Support for isomorphic-git as an alternative git backend, part 1 (#5229) * Initial version of git adapter for alternate backend. Only clone is implemented. * Regenerate package-lock.json * Clarify comments in config.yaml regarding git backend options --------- Co-authored-by: Sanitised <sanitised@users.noreply.github.com> Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>

3db508a75936a42b7259675f9f5fc33edb35b366

Sanitised <bakeriesvader@gmail.com>

Signed
6 files changed, +565 -6Ignore whitespace
default/config.yaml+7 -0
@@ -250,6 +250,13 @@ extensions:
250250 speechToText: Xenova/whisper-small
251251 textToSpeech: Xenova/speecht5_tts
252252
253+# Git backend for plugin/extension repository operations.
254+# - Use "auto" to prefer system git, falling back to the integrated backend
255+# - Use "system" to force system backend
256+# - Use "builtin" to force integrated backend
257+git:
258+ backend: auto
259+
253260# Additional model tokenizers can be downloaded on demand.
254261# Disabling will fallback to another locally available tokenizer.
255262enableDownloadableTokenizers: true
package-lock.json+409 -1
@@ -72,6 +72,7 @@
7272 "ip-regex": "^5.0.0",
7373 "ipaddr.js": "^2.2.0",
7474 "is-docker": "^3.0.0",
75+ "isomorphic-git": "^1.36.3",
7576 "localforage": "^1.10.0",
7677 "lodash": "^4.17.21",
7778 "mime-types": "^3.0.2",
@@ -2982,12 +2983,33 @@
29822983 "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz",
29832984 "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg=="
29842985 },
2986+ "node_modules/async-lock": {
2987+ "version": "1.4.1",
2988+ "resolved": "https://registry.npmjs.org/async-lock/-/async-lock-1.4.1.tgz",
2989+ "integrity": "sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ==",
2990+ "license": "MIT"
2991+ },
29852992 "node_modules/asynckit": {
29862993 "version": "0.4.0",
29872994 "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
29882995 "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
29892996 "license": "MIT"
29902997 },
2998+ "node_modules/available-typed-arrays": {
2999+ "version": "1.0.7",
3000+ "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
3001+ "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
3002+ "license": "MIT",
3003+ "dependencies": {
3004+ "possible-typed-array-names": "^1.0.0"
3005+ },
3006+ "engines": {
3007+ "node": ">= 0.4"
3008+ },
3009+ "funding": {
3010+ "url": "https://github.com/sponsors/ljharb"
3011+ }
3012+ },
29913013 "node_modules/await-to-js": {
29923014 "version": "3.0.0",
29933015 "resolved": "https://registry.npmjs.org/await-to-js/-/await-to-js-3.0.0.tgz",
@@ -3334,6 +3356,24 @@
33343356 "node": ">=8"
33353357 }
33363358 },
3359+ "node_modules/call-bind": {
3360+ "version": "1.0.8",
3361+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz",
3362+ "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==",
3363+ "license": "MIT",
3364+ "dependencies": {
3365+ "call-bind-apply-helpers": "^1.0.0",
3366+ "es-define-property": "^1.0.0",
3367+ "get-intrinsic": "^1.2.4",
3368+ "set-function-length": "^1.2.2"
3369+ },
3370+ "engines": {
3371+ "node": ">= 0.4"
3372+ },
3373+ "funding": {
3374+ "url": "https://github.com/sponsors/ljharb"
3375+ }
3376+ },
33373377 "node_modules/call-bind-apply-helpers": {
33383378 "version": "1.0.2",
33393379 "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
@@ -3484,6 +3524,12 @@
34843524 "node": ">=6.0"
34853525 }
34863526 },
3527+ "node_modules/clean-git-ref": {
3528+ "version": "2.0.1",
3529+ "resolved": "https://registry.npmjs.org/clean-git-ref/-/clean-git-ref-2.0.1.tgz",
3530+ "integrity": "sha512-bLSptAy2P0s6hU4PzuIMKmMJJSE6gLXGH1cntDu7bWJUksvuM+7ReOK61mozULErYvP6a15rnYl0zFDef+pyPw==",
3531+ "license": "Apache-2.0"
3532+ },
34873533 "node_modules/cliui": {
34883534 "version": "8.0.1",
34893535 "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
@@ -4109,6 +4155,23 @@
41094155 "node": ">=10"
41104156 }
41114157 },
4158+ "node_modules/define-data-property": {
4159+ "version": "1.1.4",
4160+ "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
4161+ "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
4162+ "license": "MIT",
4163+ "dependencies": {
4164+ "es-define-property": "^1.0.0",
4165+ "es-errors": "^1.3.0",
4166+ "gopd": "^1.0.1"
4167+ },
4168+ "engines": {
4169+ "node": ">= 0.4"
4170+ },
4171+ "funding": {
4172+ "url": "https://github.com/sponsors/ljharb"
4173+ }
4174+ },
41124175 "node_modules/define-lazy-prop": {
41134176 "version": "3.0.0",
41144177 "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz",
@@ -4169,6 +4232,12 @@
41694232 "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==",
41704233 "license": "Apache-2.0"
41714234 },
4235+ "node_modules/diff3": {
4236+ "version": "0.0.3",
4237+ "resolved": "https://registry.npmjs.org/diff3/-/diff3-0.0.3.tgz",
4238+ "integrity": "sha512-iSq8ngPOt0K53A6eVr4d5Kn6GNrM2nQZtC740pzIriHtn4pOQ2lyzEXQMBeVcWERN0ye7fhBsk9PbLLQOnUx/g==",
4239+ "license": "MIT"
4240+ },
41724241 "node_modules/digest-fetch": {
41734242 "version": "1.3.0",
41744243 "resolved": "https://registry.npmjs.org/digest-fetch/-/digest-fetch-1.3.0.tgz",
@@ -5149,6 +5218,21 @@
51495218 }
51505219 }
51515220 },
5221+ "node_modules/for-each": {
5222+ "version": "0.3.5",
5223+ "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
5224+ "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==",
5225+ "license": "MIT",
5226+ "dependencies": {
5227+ "is-callable": "^1.2.7"
5228+ },
5229+ "engines": {
5230+ "node": ">= 0.4"
5231+ },
5232+ "funding": {
5233+ "url": "https://github.com/sponsors/ljharb"
5234+ }
5235+ },
51525236 "node_modules/foreground-child": {
51535237 "version": "3.1.1",
51545238 "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz",
@@ -5574,6 +5658,18 @@
55745658 "node": ">=8"
55755659 }
55765660 },
5661+ "node_modules/has-property-descriptors": {
5662+ "version": "1.0.2",
5663+ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
5664+ "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
5665+ "license": "MIT",
5666+ "dependencies": {
5667+ "es-define-property": "^1.0.0"
5668+ },
5669+ "funding": {
5670+ "url": "https://github.com/sponsors/ljharb"
5671+ }
5672+ },
55775673 "node_modules/has-symbols": {
55785674 "version": "1.1.0",
55795675 "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
@@ -5827,7 +5923,6 @@
58275923 "version": "5.2.4",
58285924 "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
58295925 "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
5830- "dev": true,
58315926 "license": "MIT",
58325927 "engines": {
58335928 "node": ">= 4"
@@ -5955,6 +6050,18 @@
59556050 "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
59566051 "license": "MIT"
59576052 },
6053+ "node_modules/is-callable": {
6054+ "version": "1.2.7",
6055+ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
6056+ "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
6057+ "license": "MIT",
6058+ "engines": {
6059+ "node": ">= 0.4"
6060+ },
6061+ "funding": {
6062+ "url": "https://github.com/sponsors/ljharb"
6063+ }
6064+ },
59586065 "node_modules/is-docker": {
59596066 "version": "3.0.0",
59606067 "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz",
@@ -6057,6 +6164,21 @@
60576164 "url": "https://github.com/sponsors/sindresorhus"
60586165 }
60596166 },
6167+ "node_modules/is-typed-array": {
6168+ "version": "1.1.15",
6169+ "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz",
6170+ "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==",
6171+ "license": "MIT",
6172+ "dependencies": {
6173+ "which-typed-array": "^1.1.16"
6174+ },
6175+ "engines": {
6176+ "node": ">= 0.4"
6177+ },
6178+ "funding": {
6179+ "url": "https://github.com/sponsors/ljharb"
6180+ }
6181+ },
60606182 "node_modules/is-wsl": {
60616183 "version": "3.1.0",
60626184 "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz",
@@ -6114,6 +6236,88 @@
61146236 }
61156237 }
61166238 },
6239+ "node_modules/isomorphic-git": {
6240+ "version": "1.37.2",
6241+ "resolved": "https://registry.npmjs.org/isomorphic-git/-/isomorphic-git-1.37.2.tgz",
6242+ "integrity": "sha512-HCQBBKmXIMPdHgYGstSBNp6MNmVcMQBbUqJF8xfywFmlpNseO4KKex59YlXqNxhRxmv3fUZwvNWvMyOdc1VvhA==",
6243+ "license": "MIT",
6244+ "dependencies": {
6245+ "async-lock": "^1.4.1",
6246+ "clean-git-ref": "^2.0.1",
6247+ "crc-32": "^1.2.0",
6248+ "diff3": "0.0.3",
6249+ "ignore": "^5.1.4",
6250+ "minimisted": "^2.0.0",
6251+ "pako": "^1.0.10",
6252+ "pify": "^4.0.1",
6253+ "readable-stream": "^4.0.0",
6254+ "sha.js": "^2.4.12",
6255+ "simple-get": "^4.0.1"
6256+ },
6257+ "bin": {
6258+ "isogit": "cli.cjs"
6259+ },
6260+ "engines": {
6261+ "node": ">=14.17"
6262+ }
6263+ },
6264+ "node_modules/isomorphic-git/node_modules/crc-32": {
6265+ "version": "1.2.2",
6266+ "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz",
6267+ "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==",
6268+ "license": "Apache-2.0",
6269+ "bin": {
6270+ "crc32": "bin/crc32.njs"
6271+ },
6272+ "engines": {
6273+ "node": ">=0.8"
6274+ }
6275+ },
6276+ "node_modules/isomorphic-git/node_modules/readable-stream": {
6277+ "version": "4.7.0",
6278+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz",
6279+ "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==",
6280+ "license": "MIT",
6281+ "dependencies": {
6282+ "abort-controller": "^3.0.0",
6283+ "buffer": "^6.0.3",
6284+ "events": "^3.3.0",
6285+ "process": "^0.11.10",
6286+ "string_decoder": "^1.3.0"
6287+ },
6288+ "engines": {
6289+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
6290+ }
6291+ },
6292+ "node_modules/isomorphic-git/node_modules/safe-buffer": {
6293+ "version": "5.2.1",
6294+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
6295+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
6296+ "funding": [
6297+ {
6298+ "type": "github",
6299+ "url": "https://github.com/sponsors/feross"
6300+ },
6301+ {
6302+ "type": "patreon",
6303+ "url": "https://www.patreon.com/feross"
6304+ },
6305+ {
6306+ "type": "consulting",
6307+ "url": "https://feross.org/support"
6308+ }
6309+ ],
6310+ "license": "MIT"
6311+ },
6312+ "node_modules/isomorphic-git/node_modules/string_decoder": {
6313+ "version": "1.3.0",
6314+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
6315+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
6316+ "license": "MIT",
6317+ "dependencies": {
6318+ "safe-buffer": "~5.2.0"
6319+ }
6320+ },
61176321 "node_modules/jackspeak": {
61186322 "version": "3.4.3",
61196323 "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
@@ -6611,6 +6815,15 @@
66116815 "url": "https://github.com/sponsors/ljharb"
66126816 }
66136817 },
6818+ "node_modules/minimisted": {
6819+ "version": "2.0.1",
6820+ "resolved": "https://registry.npmjs.org/minimisted/-/minimisted-2.0.1.tgz",
6821+ "integrity": "sha512-1oPjfuLQa2caorJUM8HV8lGgWCc0qqAO1MNv/k05G4qslmsndV/5WdNZrqCiyqiz3wohia2Ij2B7w2Dr7/IyrA==",
6822+ "license": "MIT",
6823+ "dependencies": {
6824+ "minimist": "^1.2.5"
6825+ }
6826+ },
66146827 "node_modules/minipass": {
66156828 "version": "7.1.2",
66166829 "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
@@ -7297,6 +7510,15 @@
72977510 "url": "https://github.com/sponsors/jonschlinkert"
72987511 }
72997512 },
7513+ "node_modules/pify": {
7514+ "version": "4.0.1",
7515+ "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
7516+ "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
7517+ "license": "MIT",
7518+ "engines": {
7519+ "node": ">=6"
7520+ }
7521+ },
73007522 "node_modules/platform": {
73017523 "version": "1.3.6",
73027524 "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz",
@@ -7327,6 +7549,15 @@
73277549 "node": ">=14.19.0"
73287550 }
73297551 },
7552+ "node_modules/possible-typed-array-names": {
7553+ "version": "1.1.0",
7554+ "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
7555+ "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==",
7556+ "license": "MIT",
7557+ "engines": {
7558+ "node": ">= 0.4"
7559+ }
7560+ },
73307561 "node_modules/prelude-ls": {
73317562 "version": "1.2.1",
73327563 "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -8005,12 +8236,69 @@
80058236 "node": ">= 0.8.0"
80068237 }
80078238 },
8239+ "node_modules/set-function-length": {
8240+ "version": "1.2.2",
8241+ "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
8242+ "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
8243+ "license": "MIT",
8244+ "dependencies": {
8245+ "define-data-property": "^1.1.4",
8246+ "es-errors": "^1.3.0",
8247+ "function-bind": "^1.1.2",
8248+ "get-intrinsic": "^1.2.4",
8249+ "gopd": "^1.0.1",
8250+ "has-property-descriptors": "^1.0.2"
8251+ },
8252+ "engines": {
8253+ "node": ">= 0.4"
8254+ }
8255+ },
80088256 "node_modules/setprototypeof": {
80098257 "version": "1.2.0",
80108258 "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
80118259 "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
80128260 "license": "ISC"
80138261 },
8262+ "node_modules/sha.js": {
8263+ "version": "2.4.12",
8264+ "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz",
8265+ "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==",
8266+ "license": "(MIT AND BSD-3-Clause)",
8267+ "dependencies": {
8268+ "inherits": "^2.0.4",
8269+ "safe-buffer": "^5.2.1",
8270+ "to-buffer": "^1.2.0"
8271+ },
8272+ "bin": {
8273+ "sha.js": "bin.js"
8274+ },
8275+ "engines": {
8276+ "node": ">= 0.10"
8277+ },
8278+ "funding": {
8279+ "url": "https://github.com/sponsors/ljharb"
8280+ }
8281+ },
8282+ "node_modules/sha.js/node_modules/safe-buffer": {
8283+ "version": "5.2.1",
8284+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
8285+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
8286+ "funding": [
8287+ {
8288+ "type": "github",
8289+ "url": "https://github.com/sponsors/feross"
8290+ },
8291+ {
8292+ "type": "patreon",
8293+ "url": "https://www.patreon.com/feross"
8294+ },
8295+ {
8296+ "type": "consulting",
8297+ "url": "https://feross.org/support"
8298+ }
8299+ ],
8300+ "license": "MIT"
8301+ },
80148302 "node_modules/shebang-command": {
80158303 "version": "2.0.0",
80168304 "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -8181,6 +8469,51 @@
81818469 "regenerator-runtime": "^0.13.3"
81828470 }
81838471 },
8472+ "node_modules/simple-concat": {
8473+ "version": "1.0.1",
8474+ "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
8475+ "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
8476+ "funding": [
8477+ {
8478+ "type": "github",
8479+ "url": "https://github.com/sponsors/feross"
8480+ },
8481+ {
8482+ "type": "patreon",
8483+ "url": "https://www.patreon.com/feross"
8484+ },
8485+ {
8486+ "type": "consulting",
8487+ "url": "https://feross.org/support"
8488+ }
8489+ ],
8490+ "license": "MIT"
8491+ },
8492+ "node_modules/simple-get": {
8493+ "version": "4.0.1",
8494+ "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
8495+ "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
8496+ "funding": [
8497+ {
8498+ "type": "github",
8499+ "url": "https://github.com/sponsors/feross"
8500+ },
8501+ {
8502+ "type": "patreon",
8503+ "url": "https://www.patreon.com/feross"
8504+ },
8505+ {
8506+ "type": "consulting",
8507+ "url": "https://feross.org/support"
8508+ }
8509+ ],
8510+ "license": "MIT",
8511+ "dependencies": {
8512+ "decompress-response": "^6.0.0",
8513+ "once": "^1.3.1",
8514+ "simple-concat": "^1.0.0"
8515+ }
8516+ },
81848517 "node_modules/simple-git": {
81858518 "version": "3.28.0",
81868519 "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.28.0.tgz",
@@ -8605,6 +8938,46 @@
86058938 "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==",
86068939 "license": "MIT"
86078940 },
8941+ "node_modules/to-buffer": {
8942+ "version": "1.2.2",
8943+ "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz",
8944+ "integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==",
8945+ "license": "MIT",
8946+ "dependencies": {
8947+ "isarray": "^2.0.5",
8948+ "safe-buffer": "^5.2.1",
8949+ "typed-array-buffer": "^1.0.3"
8950+ },
8951+ "engines": {
8952+ "node": ">= 0.4"
8953+ }
8954+ },
8955+ "node_modules/to-buffer/node_modules/isarray": {
8956+ "version": "2.0.5",
8957+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
8958+ "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
8959+ "license": "MIT"
8960+ },
8961+ "node_modules/to-buffer/node_modules/safe-buffer": {
8962+ "version": "5.2.1",
8963+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
8964+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
8965+ "funding": [
8966+ {
8967+ "type": "github",
8968+ "url": "https://github.com/sponsors/feross"
8969+ },
8970+ {
8971+ "type": "patreon",
8972+ "url": "https://www.patreon.com/feross"
8973+ },
8974+ {
8975+ "type": "consulting",
8976+ "url": "https://feross.org/support"
8977+ }
8978+ ],
8979+ "license": "MIT"
8980+ },
86088981 "node_modules/to-regex-range": {
86098982 "version": "5.0.1",
86108983 "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -8753,6 +9126,20 @@
87539126 "node": ">= 0.6"
87549127 }
87559128 },
9129+ "node_modules/typed-array-buffer": {
9130+ "version": "1.0.3",
9131+ "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
9132+ "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==",
9133+ "license": "MIT",
9134+ "dependencies": {
9135+ "call-bound": "^1.0.3",
9136+ "es-errors": "^1.3.0",
9137+ "is-typed-array": "^1.1.14"
9138+ },
9139+ "engines": {
9140+ "node": ">= 0.4"
9141+ }
9142+ },
87569143 "node_modules/typedarray": {
87579144 "version": "0.0.6",
87589145 "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
@@ -9101,6 +9488,27 @@
91019488 "node": ">= 8"
91029489 }
91039490 },
9491+ "node_modules/which-typed-array": {
9492+ "version": "1.1.20",
9493+ "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz",
9494+ "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==",
9495+ "license": "MIT",
9496+ "dependencies": {
9497+ "available-typed-arrays": "^1.0.7",
9498+ "call-bind": "^1.0.8",
9499+ "call-bound": "^1.0.4",
9500+ "for-each": "^0.3.5",
9501+ "get-proto": "^1.0.1",
9502+ "gopd": "^1.2.0",
9503+ "has-tostringtag": "^1.0.2"
9504+ },
9505+ "engines": {
9506+ "node": ">= 0.4"
9507+ },
9508+ "funding": {
9509+ "url": "https://github.com/sponsors/ljharb"
9510+ }
9511+ },
91049512 "node_modules/wordwrap": {
91059513 "version": "1.0.0",
91069514 "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
package.json+1 -0
@@ -61,6 +61,7 @@
6161 "ip-matching": "^2.1.2",
6262 "ip-regex": "^5.0.0",
6363 "ipaddr.js": "^2.2.0",
64+ "isomorphic-git": "^1.36.3",
6465 "is-docker": "^3.0.0",
6566 "localforage": "^1.10.0",
6667 "lodash": "^4.17.21",
plugins.js+3 -1
@@ -9,11 +9,13 @@ import process from 'node:process';
99import { fileURLToPath } from 'node:url';
1010
1111import { default as git, CheckRepoActions } from 'simple-git';
12+import { createGitClient } from './src/git/client.js';
1213import { color } from './src/util.js';
1314
1415const __dirname = import.meta.dirname ?? path.dirname(fileURLToPath(import.meta.url));
1516process.chdir(__dirname);
1617const pluginsPath = './plugins';
18+const gitBackend = process.env.SILLYTAVERN_GIT_BACKEND || 'auto';
1719
1820const command = process.argv[2];
1921
@@ -87,7 +89,7 @@ async function installPlugin(pluginName) {
8789 return console.log(color.yellow(`Directory already exists at ${pluginPath}`));
8890 }
8991
9092 await gitcreateGitClient({ backend: gitBackend }).clone(pluginName, pluginPath, { '--depth': 1 });
9193 console.log(`Plugin ${color.green(pluginName)} installed to ${color.cyan(pluginPath)}`);
9294 } catch (error) {
9395 console.error(color.red(`Failed to install plugin ${pluginName}`), error);
src/endpoints/extensions.js+7 -4
@@ -6,6 +6,10 @@ import sanitize from 'sanitize-filename';
66import { CheckRepoActions, default as simpleGit } from 'simple-git';
77
88import { PUBLIC_DIRECTORIES } from '../constants.js';
9+import { getConfigValue } from '../util.js';
10+import { createGitClient } from '../git/client.js';
11+
12+const gitBackend = getConfigValue('git.backend', 'auto');
913
1014/**
1115 * @type {Partial<import('simple-git').SimpleGitOptions>}
@@ -76,8 +80,7 @@ router.post('/install', async (request, response) => {
7680 }
7781
7882 try {
79- // No timeout for cloning, as it may take a while depending on the repo size
83+ const git = createGitClient({ backend: gitBackend });
80- const git = simpleGit();
8184
8285 // make sure the third-party directory exists
8386 if (!fs.existsSync(path.join(request.user.directories.extensions))) {
@@ -102,9 +105,9 @@ router.post('/install', async (request, response) => {
102105 return response.status(409).send(`Directory already exists at ${extensionPath}`);
103106 }
104107
105108 const cloneOptions = { '--depth': 1 };
106109 if (branch) {
107110 cloneOptions['--.branch'] = branch;
108111 }
109112 await git.clone(url, extensionPath, cloneOptions);
110113 console.info(`Extension has been cloned to ${extensionPath} from ${url} at ${branch || '(default)'} branch`);
src/git/client.js+138 -0
@@ -0,0 +1,138 @@
1+import fs from 'node:fs';
2+
3+import { sync as commandExistsSync } from 'command-exists';
4+import git from 'isomorphic-git';
5+import http from 'isomorphic-git/http/node';
6+import simpleGit from 'simple-git';
7+
8+/** @type {{ AUTO: 'auto', SYSTEM: 'system', BUILTIN: 'builtin' }} */
9+export const GIT_BACKENDS = {
10+ AUTO: 'auto',
11+ SYSTEM: 'system',
12+ BUILTIN: 'builtin',
13+};
14+
15+/**
16+ * @param {string | undefined | null} preferredBackend
17+ * @returns {'system' | 'builtin'}
18+ */
19+function resolveBackend(preferredBackend) {
20+ const normalized = typeof preferredBackend === 'string' ? preferredBackend.trim().toLowerCase() : GIT_BACKENDS.AUTO;
21+ const backend = normalized === GIT_BACKENDS.SYSTEM
22+ ? GIT_BACKENDS.SYSTEM
23+ : normalized === GIT_BACKENDS.BUILTIN
24+ ? GIT_BACKENDS.BUILTIN
25+ : GIT_BACKENDS.AUTO;
26+ const systemGitAvailable = commandExistsSync('git');
27+
28+ if (backend === GIT_BACKENDS.SYSTEM && !systemGitAvailable) {
29+ throw new Error('System git backend is configured, but no git binary was found in PATH.');
30+ }
31+
32+ if (backend === GIT_BACKENDS.SYSTEM || (backend === GIT_BACKENDS.AUTO && systemGitAvailable)) {
33+ return GIT_BACKENDS.SYSTEM;
34+ }
35+
36+ return GIT_BACKENDS.BUILTIN;
37+}
38+
39+/**
40+ * @typedef {object} GitCloneOptions
41+ * @property {number} [depth]
42+ * @property {string} [branch]
43+ */
44+
45+const SUPPORTED_CLONE_OPTIONS = new Set(['depth', 'branch']);
46+
47+/**
48+ * @param {GitCloneOptions} [options]
49+ * @returns {{ depth?: number, branch?: string }}
50+ */
51+function normalizeCloneOptions(options = {}) {
52+ for (const key of Object.keys(options)) {
53+ if (!SUPPORTED_CLONE_OPTIONS.has(key)) {
54+ throw new Error(`Unsupported clone option: ${key}`);
55+ }
56+ }
57+ return { depth: options.depth, branch: options.branch };
58+}
59+
60+/**
61+ * @typedef {object} GitClient
62+ * @property {'system' | 'builtin'} backend
63+ * @property {(url: string, localPath: string, options?: GitCloneOptions) => Promise<void>} clone
64+ */
65+
66+/**
67+ * @param {{ backend?: string }} [options]
68+ * @returns {GitClient}
69+ */
70+export function createGitClient(options = {}) {
71+ const backend = resolveBackend(options.backend);
72+ if (backend === GIT_BACKENDS.SYSTEM) {
73+ return new SimpleGitClient();
74+ }
75+
76+ return new IsomorphicGitClient();
77+}
78+
79+/**
80+ * @implements {GitClient}
81+ */
82+class SimpleGitClient {
83+ constructor() {
84+ this.backend = GIT_BACKENDS.SYSTEM;
85+ this.git = simpleGit();
86+ }
87+
88+ /**
89+ * @param {string} url
90+ * @param {string} localPath
91+ * @param {GitCloneOptions} [options]
92+ * @returns {Promise<void>}
93+ */
94+ async clone(url, localPath, options = {}) {
95+ const { depth, branch } = normalizeCloneOptions(options);
96+ /** @type {Record<string, any>} */
97+ const cloneOptions = {};
98+
99+ if (depth !== undefined) {
100+ cloneOptions['--depth'] = depth;
101+ }
102+
103+ if (branch) {
104+ cloneOptions['--branch'] = branch;
105+ }
106+
107+ await this.git.clone(url, localPath, cloneOptions);
108+ }
109+}
110+
111+/**
112+ * @implements {GitClient}
113+ */
114+class IsomorphicGitClient {
115+ constructor() {
116+ this.backend = GIT_BACKENDS.BUILTIN;
117+ }
118+
119+ /**
120+ * @param {string} url
121+ * @param {string} localPath
122+ * @param {GitCloneOptions} [options]
123+ * @returns {Promise<void>}
124+ */
125+ async clone(url, localPath, options = {}) {
126+ const { depth, branch } = normalizeCloneOptions(options);
127+
128+ await git.clone({
129+ fs,
130+ http,
131+ dir: localPath,
132+ url,
133+ depth,
134+ ref: branch,
135+ singleBranch: depth !== undefined || Boolean(branch),
136+ });
137+ }
138+}