fix: resolve npm audit vulnerabilities in prismjs dependency (#37)
* Cleanup: Remove unused components and update configuration - Remove RepoStatusButton component (unused) - Remove git.ts library file (unused) - Update ExecutionModeModal with improvements - Update page.tsx with enhancements - Update env.js configuration - Update scripts router with improvements - Update .env.example with new variables * fix: resolve npm audit vulnerabilities in prismjs dependency - Add overrides to force prismjs@^1.30.0 across all dependencies - Update refractor to latest version (5.0.0) - Resolves 3 moderate severity vulnerabilities in prismjs DOM Clobbering - All npm audit vulnerabilities now resolved (0 vulnerabilities found)
This commit is contained in:
committed by
GitHub
parent
a2f830a0a1
commit
ab7e46cbc0
@@ -1,7 +1,6 @@
|
||||
# When adding additional environment variables, the schema in "/src/env.js"
|
||||
# should be updated accordingly.
|
||||
|
||||
ORIGINAL_REPO_URL="https://github.com/michelroegl-brunner/PVEScriptslocal"
|
||||
REPO_URL="https://github.com/community-scripts/ProxmoxVE"
|
||||
REPO_BRANCH="main"
|
||||
SCRIPTS_DIRECTORY="scripts"
|
||||
|
||||
406
package-lock.json
generated
406
package-lock.json
generated
@@ -15,7 +15,6 @@
|
||||
"@trpc/server": "^11.0.0",
|
||||
"@types/react-syntax-highlighter": "^15.5.13",
|
||||
"@types/ws": "^8.18.1",
|
||||
"@xterm/addon-attach": "^0.11.0",
|
||||
"@xterm/addon-fit": "^0.10.0",
|
||||
"@xterm/addon-web-links": "^0.11.0",
|
||||
"@xterm/xterm": "^5.5.0",
|
||||
@@ -25,12 +24,11 @@
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-syntax-highlighter": "^15.6.6",
|
||||
"refractor": "^5.0.0",
|
||||
"server-only": "^0.0.1",
|
||||
"simple-git": "^3.28.0",
|
||||
"strip-ansi": "^7.1.2",
|
||||
"superjson": "^2.2.1",
|
||||
"ws": "^8.18.3",
|
||||
"xterm": "^5.3.0",
|
||||
"zod": "^3.24.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -1706,21 +1704,6 @@
|
||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@kwsites/file-exists": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz",
|
||||
"integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@kwsites/promise-deferred": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz",
|
||||
"integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@napi-rs/wasm-runtime": {
|
||||
"version": "0.2.12",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz",
|
||||
@@ -2856,12 +2839,12 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/hast": {
|
||||
"version": "2.3.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz",
|
||||
"integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==",
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz",
|
||||
"integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/unist": "^2"
|
||||
"@types/unist": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/json-schema": {
|
||||
@@ -2887,6 +2870,12 @@
|
||||
"undici-types": "~7.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/prismjs": {
|
||||
"version": "1.26.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.5.tgz",
|
||||
"integrity": "sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "19.1.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.12.tgz",
|
||||
@@ -2916,9 +2905,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/unist": {
|
||||
"version": "2.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz",
|
||||
"integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==",
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz",
|
||||
"integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/ws": {
|
||||
@@ -3692,15 +3681,6 @@
|
||||
"url": "https://opencollective.com/vitest"
|
||||
}
|
||||
},
|
||||
"node_modules/@xterm/addon-attach": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@xterm/addon-attach/-/addon-attach-0.11.0.tgz",
|
||||
"integrity": "sha512-JboCN0QAY6ZLY/SSB/Zl2cQ5zW1Eh4X3fH7BnuR1NB7xGRhzbqU2Npmpiw/3zFlxDaU88vtKzok44JKi2L2V2Q==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@xterm/xterm": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@xterm/addon-fit": {
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@xterm/addon-fit/-/addon-fit-0.10.0.tgz",
|
||||
@@ -4324,9 +4304,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/character-entities": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz",
|
||||
"integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==",
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz",
|
||||
"integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
@@ -4334,9 +4314,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/character-entities-legacy": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz",
|
||||
"integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==",
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz",
|
||||
"integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
@@ -4344,9 +4324,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/character-reference-invalid": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz",
|
||||
"integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==",
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz",
|
||||
"integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
@@ -4425,9 +4405,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/comma-separated-tokens": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz",
|
||||
"integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==",
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz",
|
||||
"integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
@@ -4584,6 +4564,7 @@
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
|
||||
"integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
@@ -4604,6 +4585,19 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/decode-named-character-reference": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.2.0.tgz",
|
||||
"integrity": "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"character-entities": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/decompress-response": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
|
||||
@@ -6039,26 +6033,29 @@
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-parse-selector": {
|
||||
"version": "2.2.5",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz",
|
||||
"integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==",
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz",
|
||||
"integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/hast": "^3.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hastscript": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz",
|
||||
"integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==",
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz",
|
||||
"integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/hast": "^2.0.0",
|
||||
"comma-separated-tokens": "^1.0.0",
|
||||
"hast-util-parse-selector": "^2.0.0",
|
||||
"property-information": "^5.0.0",
|
||||
"space-separated-tokens": "^1.0.0"
|
||||
"@types/hast": "^3.0.0",
|
||||
"comma-separated-tokens": "^2.0.0",
|
||||
"hast-util-parse-selector": "^4.0.0",
|
||||
"property-information": "^7.0.0",
|
||||
"space-separated-tokens": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
@@ -6236,9 +6233,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/is-alphabetical": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz",
|
||||
"integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==",
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz",
|
||||
"integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
@@ -6246,13 +6243,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/is-alphanumerical": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz",
|
||||
"integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==",
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz",
|
||||
"integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-alphabetical": "^1.0.0",
|
||||
"is-decimal": "^1.0.0"
|
||||
"is-alphabetical": "^2.0.0",
|
||||
"is-decimal": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
@@ -6425,9 +6422,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/is-decimal": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz",
|
||||
"integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==",
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz",
|
||||
"integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
@@ -6503,9 +6500,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/is-hexadecimal": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz",
|
||||
"integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==",
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz",
|
||||
"integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
@@ -7513,6 +7510,7 @@
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/nan": {
|
||||
@@ -7917,23 +7915,30 @@
|
||||
}
|
||||
},
|
||||
"node_modules/parse-entities": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz",
|
||||
"integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==",
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz",
|
||||
"integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"character-entities": "^1.0.0",
|
||||
"character-entities-legacy": "^1.0.0",
|
||||
"character-reference-invalid": "^1.0.0",
|
||||
"is-alphanumerical": "^1.0.0",
|
||||
"is-decimal": "^1.0.0",
|
||||
"is-hexadecimal": "^1.0.0"
|
||||
"@types/unist": "^2.0.0",
|
||||
"character-entities-legacy": "^3.0.0",
|
||||
"character-reference-invalid": "^2.0.0",
|
||||
"decode-named-character-reference": "^1.0.0",
|
||||
"is-alphanumerical": "^2.0.0",
|
||||
"is-decimal": "^2.0.0",
|
||||
"is-hexadecimal": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/parse-entities/node_modules/@types/unist": {
|
||||
"version": "2.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz",
|
||||
"integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/parse5": {
|
||||
"version": "7.3.0",
|
||||
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz",
|
||||
@@ -8271,13 +8276,10 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/property-information": {
|
||||
"version": "5.6.0",
|
||||
"resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz",
|
||||
"integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==",
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz",
|
||||
"integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"xtend": "^4.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
@@ -8404,6 +8406,188 @@
|
||||
"react": ">= 0.14.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-syntax-highlighter/node_modules/@types/hast": {
|
||||
"version": "2.3.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz",
|
||||
"integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/unist": "^2"
|
||||
}
|
||||
},
|
||||
"node_modules/react-syntax-highlighter/node_modules/@types/unist": {
|
||||
"version": "2.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz",
|
||||
"integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/react-syntax-highlighter/node_modules/character-entities": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz",
|
||||
"integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/react-syntax-highlighter/node_modules/character-entities-legacy": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz",
|
||||
"integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/react-syntax-highlighter/node_modules/character-reference-invalid": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz",
|
||||
"integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/react-syntax-highlighter/node_modules/comma-separated-tokens": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz",
|
||||
"integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/react-syntax-highlighter/node_modules/hast-util-parse-selector": {
|
||||
"version": "2.2.5",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz",
|
||||
"integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/react-syntax-highlighter/node_modules/hastscript": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz",
|
||||
"integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/hast": "^2.0.0",
|
||||
"comma-separated-tokens": "^1.0.0",
|
||||
"hast-util-parse-selector": "^2.0.0",
|
||||
"property-information": "^5.0.0",
|
||||
"space-separated-tokens": "^1.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/react-syntax-highlighter/node_modules/is-alphabetical": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz",
|
||||
"integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/react-syntax-highlighter/node_modules/is-alphanumerical": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz",
|
||||
"integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-alphabetical": "^1.0.0",
|
||||
"is-decimal": "^1.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/react-syntax-highlighter/node_modules/is-decimal": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz",
|
||||
"integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/react-syntax-highlighter/node_modules/is-hexadecimal": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz",
|
||||
"integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/react-syntax-highlighter/node_modules/parse-entities": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz",
|
||||
"integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"character-entities": "^1.0.0",
|
||||
"character-entities-legacy": "^1.0.0",
|
||||
"character-reference-invalid": "^1.0.0",
|
||||
"is-alphanumerical": "^1.0.0",
|
||||
"is-decimal": "^1.0.0",
|
||||
"is-hexadecimal": "^1.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/react-syntax-highlighter/node_modules/property-information": {
|
||||
"version": "5.6.0",
|
||||
"resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz",
|
||||
"integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"xtend": "^4.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/react-syntax-highlighter/node_modules/refractor": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/refractor/-/refractor-3.6.0.tgz",
|
||||
"integrity": "sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"hastscript": "^6.0.0",
|
||||
"parse-entities": "^2.0.0",
|
||||
"prismjs": "~1.27.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/react-syntax-highlighter/node_modules/space-separated-tokens": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz",
|
||||
"integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/readable-stream": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
||||
@@ -8456,29 +8640,21 @@
|
||||
}
|
||||
},
|
||||
"node_modules/refractor": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/refractor/-/refractor-3.6.0.tgz",
|
||||
"integrity": "sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==",
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/refractor/-/refractor-5.0.0.tgz",
|
||||
"integrity": "sha512-QXOrHQF5jOpjjLfiNk5GFnWhRXvxjUVnlFxkeDmewR5sXkr3iM46Zo+CnRR8B+MDVqkULW4EcLVcRBNOPXHosw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"hastscript": "^6.0.0",
|
||||
"parse-entities": "^2.0.0",
|
||||
"prismjs": "~1.27.0"
|
||||
"@types/hast": "^3.0.0",
|
||||
"@types/prismjs": "^1.0.0",
|
||||
"hastscript": "^9.0.0",
|
||||
"parse-entities": "^4.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/refractor/node_modules/prismjs": {
|
||||
"version": "1.27.0",
|
||||
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.27.0.tgz",
|
||||
"integrity": "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/regexp.prototype.flags": {
|
||||
"version": "1.5.4",
|
||||
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz",
|
||||
@@ -9010,21 +9186,6 @@
|
||||
"simple-concat": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/simple-git": {
|
||||
"version": "3.28.0",
|
||||
"resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.28.0.tgz",
|
||||
"integrity": "sha512-Rs/vQRwsn1ILH1oBUy8NucJlXmnnLeLCfcvbSehkPzbv3wwoFWIdtfd6Ndo6ZPhlPsCZ60CPI4rxurnwAa+a2w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@kwsites/file-exists": "^1.1.1",
|
||||
"@kwsites/promise-deferred": "^1.1.1",
|
||||
"debug": "^4.4.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/steveukx/git-js?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/simple-swizzle": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
|
||||
@@ -9060,9 +9221,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/space-separated-tokens": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz",
|
||||
"integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==",
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz",
|
||||
"integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
@@ -10567,13 +10728,6 @@
|
||||
"node": ">=0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/xterm": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/xterm/-/xterm-5.3.0.tgz",
|
||||
"integrity": "sha512-8QqjlekLUFTrU6x7xck1MsPzPA571K5zNqWm0M0oroYEWVOptZ0+ubQSkQ3uxIEhcIHRujJy6emDWX4A7qyFzg==",
|
||||
"deprecated": "This package is now deprecated. Move to @xterm/xterm instead.",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/yallist": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
||||
|
||||
17
package.json
17
package.json
@@ -29,23 +29,21 @@
|
||||
"@trpc/server": "^11.0.0",
|
||||
"@types/react-syntax-highlighter": "^15.5.13",
|
||||
"@types/ws": "^8.18.1",
|
||||
"@xterm/addon-attach": "^0.11.0",
|
||||
"@xterm/addon-fit": "^0.10.0",
|
||||
"@xterm/addon-web-links": "^0.11.0",
|
||||
"@xterm/xterm": "^5.5.0",
|
||||
"better-sqlite3": "^9.6.0",
|
||||
"next": "^15.5.3",
|
||||
"node-pty": "^1.0.0",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-syntax-highlighter": "^15.6.6",
|
||||
"refractor": "^5.0.0",
|
||||
"server-only": "^0.0.1",
|
||||
"simple-git": "^3.28.0",
|
||||
"strip-ansi": "^7.1.2",
|
||||
"superjson": "^2.2.1",
|
||||
"ws": "^8.18.3",
|
||||
"xterm": "^5.3.0",
|
||||
"zod": "^3.24.2",
|
||||
"better-sqlite3": "^9.6.0"
|
||||
"zod": "^3.24.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/eslintrc": "^3.3.1",
|
||||
@@ -53,6 +51,7 @@
|
||||
"@testing-library/jest-dom": "^6.8.0",
|
||||
"@testing-library/react": "^16.3.0",
|
||||
"@testing-library/user-event": "^14.6.1",
|
||||
"@types/better-sqlite3": "^7.6.8",
|
||||
"@types/node": "^24.3.1",
|
||||
"@types/react": "^19.0.0",
|
||||
"@types/react-dom": "^19.0.0",
|
||||
@@ -68,11 +67,13 @@
|
||||
"tailwindcss": "^4.0.15",
|
||||
"typescript": "^5.8.2",
|
||||
"typescript-eslint": "^8.27.0",
|
||||
"vitest": "^3.2.4",
|
||||
"@types/better-sqlite3": "^7.6.8"
|
||||
"vitest": "^3.2.4"
|
||||
},
|
||||
"ct3aMetadata": {
|
||||
"initVersion": "7.39.3"
|
||||
},
|
||||
"packageManager": "npm@10.9.3"
|
||||
"packageManager": "npm@10.9.3",
|
||||
"overrides": {
|
||||
"prismjs": "^1.30.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,11 +79,9 @@ export function ExecutionModeModal({ isOpen, onClose, onExecute, scriptName }: E
|
||||
<div className="p-6">
|
||||
<div className="mb-6">
|
||||
<h3 className="text-lg font-medium text-gray-900 mb-2">
|
||||
How would you like to execute "{scriptName}"?
|
||||
Where would you like to execute "{scriptName}"?
|
||||
</h3>
|
||||
<p className="text-gray-600 text-sm">
|
||||
Choose between local execution or running the script on a remote server via SSH.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
{error && (
|
||||
@@ -103,42 +101,7 @@ export function ExecutionModeModal({ isOpen, onClose, onExecute, scriptName }: E
|
||||
|
||||
{/* Execution Mode Selection */}
|
||||
<div className="space-y-4 mb-6">
|
||||
{/* Local Execution */}
|
||||
<div
|
||||
className={`border rounded-lg p-4 cursor-pointer transition-colors ${
|
||||
selectedMode === 'local'
|
||||
? 'border-blue-500 bg-blue-50'
|
||||
: 'border-gray-200 hover:border-gray-300'
|
||||
}`}
|
||||
onClick={() => handleModeChange('local')}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<input
|
||||
type="radio"
|
||||
id="local"
|
||||
name="executionMode"
|
||||
value="local"
|
||||
checked={selectedMode === 'local'}
|
||||
onChange={() => handleModeChange('local')}
|
||||
className="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300"
|
||||
/>
|
||||
<label htmlFor="local" className="ml-3 flex-1 cursor-pointer">
|
||||
<div className="flex items-center">
|
||||
<div className="flex-shrink-0">
|
||||
<div className="w-10 h-10 bg-green-100 rounded-full flex items-center justify-center">
|
||||
<svg className="w-6 h-6 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div className="ml-3">
|
||||
<h4 className="text-sm font-medium text-gray-900">Local Execution</h4>
|
||||
<p className="text-sm text-gray-500">Run the script on this server</p>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{/* SSH Execution */}
|
||||
<div
|
||||
|
||||
@@ -1,185 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { api } from '~/trpc/react';
|
||||
|
||||
export function RepoStatusButton() {
|
||||
const [isUpdating, setIsUpdating] = useState(false);
|
||||
const [updateMessage, setUpdateMessage] = useState<string | null>(null);
|
||||
const [updateSteps, setUpdateSteps] = useState<string[]>([]);
|
||||
const [showSteps, setShowSteps] = useState(false);
|
||||
|
||||
// Query repository status
|
||||
const { data: repoStatus, refetch: refetchStatus } = api.scripts.getRepoStatus.useQuery();
|
||||
|
||||
// Full update mutation
|
||||
const fullUpdateMutation = api.scripts.fullUpdateRepo.useMutation({
|
||||
onSuccess: (data) => {
|
||||
setIsUpdating(false);
|
||||
setUpdateMessage(data.message);
|
||||
setUpdateSteps(data.steps);
|
||||
setShowSteps(true);
|
||||
|
||||
if (data.success) {
|
||||
// Refetch status after successful update
|
||||
setTimeout(() => {
|
||||
void refetchStatus();
|
||||
}, 1000);
|
||||
|
||||
// Clear message after 5 seconds for success
|
||||
setTimeout(() => {
|
||||
setUpdateMessage(null);
|
||||
setShowSteps(false);
|
||||
}, 5000);
|
||||
} else {
|
||||
// Clear message after 10 seconds for errors
|
||||
setTimeout(() => {
|
||||
setUpdateMessage(null);
|
||||
setShowSteps(false);
|
||||
}, 10000);
|
||||
}
|
||||
},
|
||||
onError: (error) => {
|
||||
setIsUpdating(false);
|
||||
setUpdateMessage(`Error: ${error.message}`);
|
||||
setUpdateSteps([`❌ ${error.message}`]);
|
||||
setShowSteps(true);
|
||||
setTimeout(() => {
|
||||
setUpdateMessage(null);
|
||||
setShowSteps(false);
|
||||
}, 10000);
|
||||
},
|
||||
});
|
||||
|
||||
const handleFullUpdate = async () => {
|
||||
setIsUpdating(true);
|
||||
setUpdateMessage(null);
|
||||
setUpdateSteps([]);
|
||||
setShowSteps(false);
|
||||
fullUpdateMutation.mutate();
|
||||
};
|
||||
|
||||
const getStatusColor = () => {
|
||||
if (!repoStatus?.isRepo) return 'text-gray-500';
|
||||
if (repoStatus.isBehind) return 'text-orange-500';
|
||||
return 'text-green-500';
|
||||
};
|
||||
|
||||
const getStatusIcon = () => {
|
||||
if (!repoStatus?.isRepo) return '❓';
|
||||
if (repoStatus.isBehind) return '⚠️';
|
||||
return '✅';
|
||||
};
|
||||
|
||||
const getStatusText = () => {
|
||||
if (!repoStatus?.isRepo) return 'Not a git repository';
|
||||
if (repoStatus.isBehind) return 'Updates available';
|
||||
return 'Up to date';
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col space-y-4">
|
||||
{/* Status Display */}
|
||||
<div className="flex items-center justify-between bg-white rounded-lg shadow-sm border p-4">
|
||||
<div className="flex items-center space-x-3">
|
||||
<div className="flex items-center space-x-2">
|
||||
<span className="text-2xl">{getStatusIcon()}</span>
|
||||
<div>
|
||||
<div className={`font-medium ${getStatusColor()}`}>
|
||||
Repository Status: {getStatusText()}
|
||||
</div>
|
||||
{repoStatus?.isRepo && (
|
||||
<div className="text-sm text-gray-500">
|
||||
Branch: {repoStatus.branch ?? 'unknown'} |
|
||||
Last commit: {repoStatus.lastCommit ? repoStatus.lastCommit.substring(0, 8) : 'unknown'}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center space-x-3">
|
||||
{repoStatus?.isBehind && (
|
||||
<button
|
||||
onClick={handleFullUpdate}
|
||||
disabled={isUpdating}
|
||||
className={`flex items-center space-x-2 px-4 py-2 rounded-lg font-medium transition-colors ${
|
||||
isUpdating
|
||||
? 'bg-gray-400 text-white cursor-not-allowed'
|
||||
: 'bg-orange-600 text-white hover:bg-orange-700'
|
||||
}`}
|
||||
>
|
||||
{isUpdating ? (
|
||||
<>
|
||||
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white"></div>
|
||||
<span>Updating...</span>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
||||
</svg>
|
||||
<span>Update Repository</span>
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
)}
|
||||
|
||||
<button
|
||||
onClick={() => refetchStatus()}
|
||||
className="flex items-center space-x-2 px-3 py-2 text-gray-600 hover:text-gray-800 hover:bg-gray-100 rounded-lg transition-colors"
|
||||
title="Refresh status"
|
||||
>
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Update Message */}
|
||||
{updateMessage && (
|
||||
<div className={`p-4 rounded-lg ${
|
||||
updateMessage.includes('Error') || updateMessage.includes('Failed')
|
||||
? 'bg-red-100 text-red-700 border border-red-200'
|
||||
: 'bg-green-100 text-green-700 border border-green-200'
|
||||
}`}>
|
||||
<div className="font-medium mb-2">{updateMessage}</div>
|
||||
{showSteps && updateSteps.length > 0 && (
|
||||
<div className="mt-3">
|
||||
<button
|
||||
onClick={() => setShowSteps(!showSteps)}
|
||||
className="text-sm font-medium hover:underline"
|
||||
>
|
||||
{showSteps ? 'Hide' : 'Show'} update steps
|
||||
</button>
|
||||
{showSteps && (
|
||||
<div className="mt-2 space-y-1">
|
||||
{updateSteps.map((step, index) => (
|
||||
<div key={index} className="text-sm font-mono">
|
||||
{step}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Update Steps (always show when updating) */}
|
||||
{isUpdating && updateSteps.length > 0 && (
|
||||
<div className="bg-blue-50 border border-blue-200 rounded-lg p-4">
|
||||
<div className="font-medium text-blue-800 mb-2">Update Progress:</div>
|
||||
<div className="space-y-1">
|
||||
{updateSteps.map((step, index) => (
|
||||
<div key={index} className="text-sm font-mono text-blue-700">
|
||||
{step}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -33,6 +33,14 @@ export default function Home() {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Controls */}
|
||||
<div className="mb-8">
|
||||
<div className="flex items-left pr-4 mb-6">
|
||||
<SettingsButton />
|
||||
<ResyncButton />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Tab Navigation */}
|
||||
<div className="mb-8">
|
||||
<div className="border-b border-gray-200">
|
||||
@@ -61,13 +69,7 @@ export default function Home() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Controls */}
|
||||
<div className="mb-8">
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<SettingsButton />
|
||||
<ResyncButton />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{/* Running Script Terminal */}
|
||||
{runningScript && (
|
||||
|
||||
@@ -13,7 +13,7 @@ export const env = createEnv({
|
||||
.default("development"),
|
||||
// Repository Configuration
|
||||
REPO_URL: z.string().url().optional(),
|
||||
ORIGINAL_REPO_URL: z.string().url().optional(),
|
||||
|
||||
REPO_BRANCH: z.string().default("main"),
|
||||
SCRIPTS_DIRECTORY: z.string().default("scripts"),
|
||||
JSON_FOLDER: z.string().default("json"),
|
||||
@@ -42,7 +42,7 @@ export const env = createEnv({
|
||||
NODE_ENV: process.env.NODE_ENV,
|
||||
// Repository Configuration
|
||||
REPO_URL: process.env.REPO_URL,
|
||||
ORIGINAL_REPO_URL: process.env.ORIGINAL_REPO_URL,
|
||||
|
||||
REPO_BRANCH: process.env.REPO_BRANCH,
|
||||
SCRIPTS_DIRECTORY: process.env.SCRIPTS_DIRECTORY,
|
||||
JSON_FOLDER: process.env.JSON_FOLDER,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { z } from "zod";
|
||||
import { createTRPCRouter, publicProcedure } from "~/server/api/trpc";
|
||||
import { scriptManager } from "~/server/lib/scripts";
|
||||
import { gitManager } from "~/server/lib/git";
|
||||
import { githubJsonService } from "~/server/services/githubJsonService";
|
||||
import { localScriptsService } from "~/server/services/localScripts";
|
||||
import { scriptDownloaderService } from "~/server/services/scriptDownloader";
|
||||
@@ -27,26 +26,6 @@ export const scriptsRouter = createTRPCRouter({
|
||||
};
|
||||
}),
|
||||
|
||||
// Get repository status
|
||||
getRepoStatus: publicProcedure
|
||||
.query(async () => {
|
||||
const status = await gitManager.getStatus();
|
||||
return status;
|
||||
}),
|
||||
|
||||
// Update repository
|
||||
updateRepo: publicProcedure
|
||||
.mutation(async () => {
|
||||
const result = await gitManager.pullUpdates();
|
||||
return result;
|
||||
}),
|
||||
|
||||
// Full update repository (git pull, npm install, build)
|
||||
fullUpdateRepo: publicProcedure
|
||||
.mutation(async () => {
|
||||
const result = await gitManager.fullUpdate();
|
||||
return result;
|
||||
}),
|
||||
|
||||
// Get script content for viewing
|
||||
getScriptContent: publicProcedure
|
||||
|
||||
@@ -1,258 +0,0 @@
|
||||
import { simpleGit, type SimpleGit } from 'simple-git';
|
||||
import { env } from '~/env.js';
|
||||
import { join } from 'path';
|
||||
import { exec } from 'child_process';
|
||||
import { promisify } from 'util';
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
|
||||
export class GitManager {
|
||||
private git: SimpleGit;
|
||||
private repoPath: string;
|
||||
private scriptsDir: string | null = null;
|
||||
|
||||
constructor() {
|
||||
this.repoPath = process.cwd();
|
||||
this.git = simpleGit(this.repoPath);
|
||||
}
|
||||
|
||||
private initializeConfig() {
|
||||
this.scriptsDir ??= join(this.repoPath, env.SCRIPTS_DIRECTORY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the repository is behind the remote
|
||||
*/
|
||||
async isBehindRemote(): Promise<boolean> {
|
||||
try {
|
||||
if (!env.ORIGINAL_REPO_URL) {
|
||||
return false; // No remote configured
|
||||
}
|
||||
|
||||
// Fetch latest changes without merging
|
||||
await this.git.fetch();
|
||||
|
||||
// Check if local branch is behind remote
|
||||
const status = await this.git.status();
|
||||
const behind = status.behind > 0;
|
||||
|
||||
return behind;
|
||||
} catch (error) {
|
||||
console.error('Error checking repo status:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull updates from remote repository
|
||||
*/
|
||||
async pullUpdates(): Promise<{ success: boolean; message: string }> {
|
||||
try {
|
||||
if (!env.ORIGINAL_REPO_URL) {
|
||||
return { success: false, message: 'No remote repository configured' };
|
||||
}
|
||||
|
||||
// Check if we're in a git repository
|
||||
const isRepo = await this.git.checkIsRepo();
|
||||
if (!isRepo) {
|
||||
// Clone the repository if it doesn't exist
|
||||
return await this.cloneRepository();
|
||||
}
|
||||
|
||||
// Pull latest changes
|
||||
const result = await this.git.pull(env.REPO_BRANCH);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: `Successfully pulled updates. ${result.summary.changes} changes, ${result.summary.insertions} insertions, ${result.summary.deletions} deletions`
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error pulling updates:', error);
|
||||
return {
|
||||
success: false,
|
||||
message: `Failed to pull updates: ${error instanceof Error ? error.message : 'Unknown error'}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Full update process: git pull, npm install, and restart server
|
||||
*/
|
||||
async fullUpdate(): Promise<{ success: boolean; message: string; steps: string[] }> {
|
||||
const steps: string[] = [];
|
||||
|
||||
try {
|
||||
if (!env.ORIGINAL_REPO_URL) {
|
||||
return {
|
||||
success: false,
|
||||
message: 'No remote repository configured',
|
||||
steps: ['❌ No remote repository configured']
|
||||
};
|
||||
}
|
||||
|
||||
// Step 1: Git pull
|
||||
steps.push('🔄 Pulling latest changes from repository...');
|
||||
const pullResult = await this.pullUpdates();
|
||||
if (!pullResult.success) {
|
||||
return {
|
||||
success: false,
|
||||
message: pullResult.message,
|
||||
steps: [...steps, `❌ ${pullResult.message}`]
|
||||
};
|
||||
}
|
||||
steps.push(`✅ ${pullResult.message}`);
|
||||
|
||||
// Step 2: npm install
|
||||
steps.push('📦 Installing/updating dependencies...');
|
||||
try {
|
||||
const { stderr } = await execAsync('npm install', { cwd: this.repoPath });
|
||||
if (stderr && !stderr.includes('npm WARN')) {
|
||||
console.warn('npm install warnings:', stderr);
|
||||
}
|
||||
steps.push('✅ Dependencies updated successfully');
|
||||
} catch (error) {
|
||||
const errorMsg = `Failed to install dependencies: ${error instanceof Error ? error.message : 'Unknown error'}`;
|
||||
steps.push(`❌ ${errorMsg}`);
|
||||
return {
|
||||
success: false,
|
||||
message: errorMsg,
|
||||
steps
|
||||
};
|
||||
}
|
||||
|
||||
// Step 3: Build the application
|
||||
steps.push('🔨 Building application...');
|
||||
try {
|
||||
const { stderr } = await execAsync('npm run build', { cwd: this.repoPath });
|
||||
if (stderr && !stderr.includes('npm WARN')) {
|
||||
console.warn('npm build warnings:', stderr);
|
||||
}
|
||||
steps.push('✅ Application built successfully');
|
||||
} catch (error) {
|
||||
const errorMsg = `Failed to build application: ${error instanceof Error ? error.message : 'Unknown error'}`;
|
||||
steps.push(`❌ ${errorMsg}`);
|
||||
return {
|
||||
success: false,
|
||||
message: errorMsg,
|
||||
steps
|
||||
};
|
||||
}
|
||||
|
||||
// Step 4: Restart server (this will be handled by the process manager)
|
||||
steps.push('🔄 Server restart required - please restart manually or use a process manager');
|
||||
steps.push('✅ Update process completed successfully');
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: 'Repository updated successfully. Please restart the server to apply changes.',
|
||||
steps
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
const errorMsg = `Update failed: ${error instanceof Error ? error.message : 'Unknown error'}`;
|
||||
steps.push(`❌ ${errorMsg}`);
|
||||
return {
|
||||
success: false,
|
||||
message: errorMsg,
|
||||
steps
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone the repository if it doesn't exist
|
||||
*/
|
||||
private async cloneRepository(): Promise<{ success: boolean; message: string }> {
|
||||
try {
|
||||
if (!env.ORIGINAL_REPO_URL) {
|
||||
return { success: false, message: 'No repository URL configured' };
|
||||
}
|
||||
|
||||
|
||||
// Clone the repository
|
||||
await this.git.clone(env.ORIGINAL_REPO_URL, this.repoPath, [
|
||||
'--branch', env.REPO_BRANCH,
|
||||
'--single-branch',
|
||||
'--depth', '1'
|
||||
]);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: `Successfully cloned repository from ${env.ORIGINAL_REPO_URL}`
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error cloning repository:', error);
|
||||
return {
|
||||
success: false,
|
||||
message: `Failed to clone repository: ${error instanceof Error ? error.message : 'Unknown error'}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize repository on startup if needed
|
||||
*/
|
||||
async initializeRepository(): Promise<void> {
|
||||
try {
|
||||
if (!env.ORIGINAL_REPO_URL) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isRepo = await this.git.checkIsRepo();
|
||||
if (!isRepo) {
|
||||
const result = await this.cloneRepository();
|
||||
if (result.success) {
|
||||
} else {
|
||||
}
|
||||
} else {
|
||||
const behind = await this.isBehindRemote();
|
||||
if (behind) {
|
||||
const result = await this.pullUpdates();
|
||||
if (result.success) {
|
||||
} else {
|
||||
}
|
||||
} else {
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error initializing repository:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get repository status information
|
||||
*/
|
||||
async getStatus(): Promise<{
|
||||
isRepo: boolean;
|
||||
isBehind: boolean;
|
||||
lastCommit?: string;
|
||||
branch?: string;
|
||||
}> {
|
||||
try {
|
||||
const isRepo = await this.git.checkIsRepo();
|
||||
if (!isRepo) {
|
||||
return { isRepo: false, isBehind: false };
|
||||
}
|
||||
|
||||
const isBehind = await this.isBehindRemote();
|
||||
const log = await this.git.log({ maxCount: 1 });
|
||||
const status = await this.git.status();
|
||||
|
||||
return {
|
||||
isRepo: true,
|
||||
isBehind,
|
||||
lastCommit: log.latest?.hash ?? undefined,
|
||||
branch: status.current ?? undefined
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error getting repository status:', error);
|
||||
return { isRepo: false, isBehind: false };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Export singleton instance
|
||||
export const gitManager = new GitManager();
|
||||
|
||||
// Initialize repository on module load
|
||||
gitManager.initializeRepository().catch(console.error);
|
||||
Reference in New Issue
Block a user