Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7311f3eaf7 | |||
| fcbad101a4 | |||
| b6ea05948f | |||
| 495dc45c10 | |||
| e4cf30ef07 | |||
| 5655280d45 | |||
| c793db8aeb | |||
| f711c68798 | |||
| 08581776ae | |||
| af6f9fc570 | |||
| ecdef730d5 | |||
| 0f4120c1a0 | |||
| c8db4529b2 |
Generated
+263
-20
@@ -174,7 +174,7 @@
|
||||
"source-map": "0.6.1",
|
||||
"source-map-support": "^0.3.2",
|
||||
"style-loader": "^3.3.2",
|
||||
"tailwindcss": "^4.0.9",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"ts-loader": "^9.5.1",
|
||||
"ts-node": "^10.9.2",
|
||||
"tsec": "0.2.7",
|
||||
@@ -193,6 +193,19 @@
|
||||
"windows-foreground-love": "0.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@alloc/quick-lru": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
|
||||
"integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@ampproject/remapping": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz",
|
||||
@@ -6289,6 +6302,16 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/camelcase-css": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
|
||||
"integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/caniuse-api": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz",
|
||||
@@ -6370,16 +6393,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/chokidar": {
|
||||
"version": "3.5.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
|
||||
"integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
|
||||
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"anymatch": "~3.1.2",
|
||||
"braces": "~3.0.2",
|
||||
@@ -6392,6 +6410,9 @@
|
||||
"engines": {
|
||||
"node": ">= 8.10.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
@@ -7721,6 +7742,13 @@
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/didyoumean": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
|
||||
"integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/diff": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz",
|
||||
@@ -7742,6 +7770,13 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/dlv": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
|
||||
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/doctrine": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
|
||||
@@ -13303,6 +13338,16 @@
|
||||
"url": "https://github.com/chalk/supports-color?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/jiti": {
|
||||
"version": "1.21.7",
|
||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz",
|
||||
"integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"jiti": "bin/jiti.js"
|
||||
}
|
||||
},
|
||||
"node_modules/joycon": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz",
|
||||
@@ -13891,9 +13936,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/lilconfig": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz",
|
||||
"integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==",
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
|
||||
"integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -15707,6 +15752,16 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/object-hash": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
|
||||
"integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/object-inspect": {
|
||||
"version": "1.13.4",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
|
||||
@@ -16894,6 +16949,44 @@
|
||||
"postcss": "^8.4.31"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-import": {
|
||||
"version": "15.1.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
|
||||
"integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"postcss-value-parser": "^4.0.0",
|
||||
"read-cache": "^1.0.0",
|
||||
"resolve": "^1.1.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"postcss": "^8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-js": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz",
|
||||
"integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"camelcase-css": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12 || ^14 || >= 16"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/postcss/"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"postcss": "^8.4.21"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-load-config": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz",
|
||||
@@ -17854,6 +17947,26 @@
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/read-cache": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
||||
"integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"pify": "^2.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/read-cache/node_modules/pify": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
||||
"integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/read-pkg": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
|
||||
@@ -18252,18 +18365,22 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/resolve": {
|
||||
"version": "1.22.1",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
|
||||
"integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
|
||||
"version": "1.22.10",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
|
||||
"integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-core-module": "^2.9.0",
|
||||
"is-core-module": "^2.16.0",
|
||||
"path-parse": "^1.0.7",
|
||||
"supports-preserve-symlinks-flag": "^1.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"resolve": "bin/resolve"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
@@ -20449,12 +20566,125 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tailwindcss": {
|
||||
"version": "4.0.9",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.9.tgz",
|
||||
"integrity": "sha512-12laZu+fv1ONDRoNR9ipTOpUD7RN9essRVkX36sjxuRUInpN7hIiHN4lBd/SIFjbISvnXzp8h/hXzmU8SQQYhw==",
|
||||
"version": "3.4.17",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz",
|
||||
"integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@alloc/quick-lru": "^5.2.0",
|
||||
"arg": "^5.0.2",
|
||||
"chokidar": "^3.6.0",
|
||||
"didyoumean": "^1.2.2",
|
||||
"dlv": "^1.1.3",
|
||||
"fast-glob": "^3.3.2",
|
||||
"glob-parent": "^6.0.2",
|
||||
"is-glob": "^4.0.3",
|
||||
"jiti": "^1.21.6",
|
||||
"lilconfig": "^3.1.3",
|
||||
"micromatch": "^4.0.8",
|
||||
"normalize-path": "^3.0.0",
|
||||
"object-hash": "^3.0.0",
|
||||
"picocolors": "^1.1.1",
|
||||
"postcss": "^8.4.47",
|
||||
"postcss-import": "^15.1.0",
|
||||
"postcss-js": "^4.0.1",
|
||||
"postcss-load-config": "^4.0.2",
|
||||
"postcss-nested": "^6.2.0",
|
||||
"postcss-selector-parser": "^6.1.2",
|
||||
"resolve": "^1.22.8",
|
||||
"sucrase": "^3.35.0"
|
||||
},
|
||||
"bin": {
|
||||
"tailwind": "lib/cli.js",
|
||||
"tailwindcss": "lib/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tailwindcss/node_modules/arg": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
|
||||
"integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tailwindcss/node_modules/glob-parent": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
|
||||
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"is-glob": "^4.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tailwindcss/node_modules/postcss-load-config": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz",
|
||||
"integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/postcss/"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"lilconfig": "^3.0.0",
|
||||
"yaml": "^2.3.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"postcss": ">=8.0.9",
|
||||
"ts-node": ">=9.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"postcss": {
|
||||
"optional": true
|
||||
},
|
||||
"ts-node": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/tailwindcss/node_modules/postcss-nested": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz",
|
||||
"integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/postcss/"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"postcss-selector-parser": "^6.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"postcss": "^8.2.14"
|
||||
}
|
||||
},
|
||||
"node_modules/tapable": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.0.tgz",
|
||||
@@ -22730,6 +22960,19 @@
|
||||
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/yaml": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz",
|
||||
"integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"yaml": "bin.mjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs": {
|
||||
"version": "17.7.2",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
||||
|
||||
+1
-1
@@ -235,7 +235,7 @@
|
||||
"source-map": "0.6.1",
|
||||
"source-map-support": "^0.3.2",
|
||||
"style-loader": "^3.3.2",
|
||||
"tailwindcss": "^4.0.9",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"ts-loader": "^9.5.1",
|
||||
"ts-node": "^10.9.2",
|
||||
"tsec": "0.2.7",
|
||||
|
||||
Executable
+135
@@ -0,0 +1,135 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Exit on error
|
||||
set -e
|
||||
|
||||
# Check platform
|
||||
platform=$(uname)
|
||||
|
||||
if [[ "$platform" == "Darwin" ]]; then
|
||||
echo "Running on macOS. Note that the AppImage created will only work on Linux systems."
|
||||
if ! command -v docker &> /dev/null; then
|
||||
echo "Docker Desktop for Mac is not installed. Please install it from https://www.docker.com/products/docker-desktop"
|
||||
exit 1
|
||||
fi
|
||||
elif [[ "$platform" == "Linux" ]]; then
|
||||
echo "Running on Linux. Proceeding with AppImage creation..."
|
||||
else
|
||||
echo "This script is intended to run on macOS or Linux. Current platform: $platform"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Enable BuildKit
|
||||
export DOCKER_BUILDKIT=1
|
||||
|
||||
BUILD_IMAGE_NAME="void-appimage-builder"
|
||||
|
||||
# Check if Docker is running
|
||||
if ! docker info >/dev/null 2>&1; then
|
||||
echo "Docker is not running. Please start Docker first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check and install Buildx if needed
|
||||
if ! docker buildx version >/dev/null 2>&1; then
|
||||
echo "Installing Docker Buildx..."
|
||||
mkdir -p ~/.docker/cli-plugins/
|
||||
curl -SL https://github.com/docker/buildx/releases/download/v0.13.1/buildx-v0.13.1.linux-amd64 -o ~/.docker/cli-plugins/docker-buildx
|
||||
chmod +x ~/.docker/cli-plugins/docker-buildx
|
||||
fi
|
||||
|
||||
# Download appimagetool if not present
|
||||
if [ ! -f "appimagetool" ]; then
|
||||
echo "Downloading appimagetool..."
|
||||
wget -O appimagetool "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage"
|
||||
chmod +x appimagetool
|
||||
fi
|
||||
|
||||
# Delete any existing AppImage to avoid bloating the build
|
||||
rm -f Void-x86_64.AppImage
|
||||
|
||||
# Create build Dockerfile
|
||||
echo "Creating build Dockerfile..."
|
||||
cat > Dockerfile.build << 'EOF'
|
||||
# syntax=docker/dockerfile:1
|
||||
FROM ubuntu:20.04
|
||||
|
||||
# Install required dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
libfuse2 \
|
||||
libglib2.0-0 \
|
||||
libgtk-3-0 \
|
||||
libx11-xcb1 \
|
||||
libxss1 \
|
||||
libxtst6 \
|
||||
libnss3 \
|
||||
libasound2 \
|
||||
libdrm2 \
|
||||
libgbm1 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /app
|
||||
EOF
|
||||
|
||||
# Create .dockerignore file
|
||||
echo "Creating .dockerignore file..."
|
||||
cat > .dockerignore << EOF
|
||||
Dockerfile.build
|
||||
.dockerignore
|
||||
.git
|
||||
.gitignore
|
||||
.DS_Store
|
||||
*~
|
||||
*.swp
|
||||
*.swo
|
||||
*.tmp
|
||||
*.bak
|
||||
*.log
|
||||
*.err
|
||||
node_modules/
|
||||
venv/
|
||||
*.egg-info/
|
||||
*.tox/
|
||||
dist/
|
||||
EOF
|
||||
|
||||
# Build Docker image without cache
|
||||
echo "Building Docker image (no cache)..."
|
||||
docker build --no-cache -t "$BUILD_IMAGE_NAME" -f Dockerfile.build .
|
||||
|
||||
# Create AppImage using local appimagetool
|
||||
echo "Creating AppImage..."
|
||||
docker run --rm --privileged -v "$(pwd):/app" "$BUILD_IMAGE_NAME" bash -c '
|
||||
cd /app && \
|
||||
rm -rf VoidApp.AppDir && \
|
||||
mkdir -p VoidApp.AppDir/usr/bin VoidApp.AppDir/usr/lib VoidApp.AppDir/usr/share/applications && \
|
||||
find . -maxdepth 1 ! -name VoidApp.AppDir ! -name "." ! -name ".." -exec cp -r {} VoidApp.AppDir/usr/bin/ \; && \
|
||||
cp void.png VoidApp.AppDir/ && \
|
||||
echo "[Desktop Entry]" > VoidApp.AppDir/void.desktop && \
|
||||
echo "Name=Void" >> VoidApp.AppDir/void.desktop && \
|
||||
echo "Exec=void" >> VoidApp.AppDir/void.desktop && \
|
||||
echo "Icon=void" >> VoidApp.AppDir/void.desktop && \
|
||||
echo "Type=Application" >> VoidApp.AppDir/void.desktop && \
|
||||
echo "Categories=Utility;" >> VoidApp.AppDir/void.desktop && \
|
||||
echo "Comment=Void Linux Application" >> VoidApp.AppDir/void.desktop && \
|
||||
chmod +x VoidApp.AppDir/void.desktop && \
|
||||
cp VoidApp.AppDir/void.desktop VoidApp.AppDir/usr/share/applications/ && \
|
||||
echo "#!/bin/bash" > VoidApp.AppDir/AppRun && \
|
||||
echo "HERE=\$(dirname \"\$(readlink -f \"\${0}\")\")" >> VoidApp.AppDir/AppRun && \
|
||||
echo "export PATH=\${HERE}/usr/bin:\${PATH}" >> VoidApp.AppDir/AppRun && \
|
||||
echo "export LD_LIBRARY_PATH=\${HERE}/usr/lib:\${LD_LIBRARY_PATH}" >> VoidApp.AppDir/AppRun && \
|
||||
echo "exec \${HERE}/usr/bin/void --no-sandbox \"\$@\"" >> VoidApp.AppDir/AppRun && \
|
||||
chmod +x VoidApp.AppDir/AppRun && \
|
||||
chmod -R 755 VoidApp.AppDir && \
|
||||
|
||||
# Strip unneeded symbols from the binary to reduce size
|
||||
strip --strip-unneeded VoidApp.AppDir/usr/bin/void
|
||||
|
||||
ls -la VoidApp.AppDir/ && \
|
||||
ARCH=x86_64 ./appimagetool -n VoidApp.AppDir Void-x86_64.AppImage
|
||||
'
|
||||
|
||||
# Clean up
|
||||
rm -rf VoidApp.AppDir .dockerignore appimagetool
|
||||
|
||||
echo "AppImage creation complete! Your AppImage is: Void-x86_64.AppImage"
|
||||
@@ -0,0 +1,114 @@
|
||||
# Void AppImage Creation Script
|
||||
|
||||
This script automates the process of creating an AppImage for the Void Editor using Docker. It works on macOS and Linux platforms.
|
||||
## Requirements
|
||||
|
||||
* **Docker:** The script relies on Docker to build the AppImage inside a container.
|
||||
* **macOS or Linux:** The script is designed for these platforms. On macOS, it generates a Linux-compatible AppImage.
|
||||
* **Internet Connection:** Required for downloading necessary tools (like `docker-buildx` and `appimagetool` inside the Docker container).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. **Install Docker:**
|
||||
|
||||
* **macOS:** Download and install Docker Desktop from [docker.com](docker.com).
|
||||
* **Ubuntu:**
|
||||
```bash
|
||||
sudo apt install docker.io
|
||||
```
|
||||
* **Arch Linux:**
|
||||
```bash
|
||||
sudo pacman -S docker
|
||||
```
|
||||
* **Fedora:**
|
||||
```bash
|
||||
sudo dnf install docker
|
||||
```
|
||||
|
||||
2. **Set Docker User Group:**
|
||||
|
||||
Docker requires users to be part of the `docker` group to run Docker commands without `sudo`.
|
||||
|
||||
```bash
|
||||
sudo usermod -aG docker $USER
|
||||
```
|
||||
|
||||
After running this command, log out and log back in for the group changes to take effect.
|
||||
|
||||
3. **Enable and Start Docker:**
|
||||
|
||||
```bash
|
||||
sudo systemctl enable docker
|
||||
sudo systemctl start docker
|
||||
```
|
||||
|
||||
## Ubuntu Dependencies (Installed via Docker)
|
||||
|
||||
These dependencies are installed within the Docker container (Ubuntu 20.04 base). You generally don't need to install them manually:
|
||||
|
||||
* `libfuse2`
|
||||
* `libglib2.0-0`
|
||||
* `libgtk-3-0`
|
||||
* `libx11-xcb1`
|
||||
* `libxss1`
|
||||
* `libxtst6`
|
||||
* `libnss3`
|
||||
* `libasound2`
|
||||
* `libdrm2`
|
||||
* `libgbm1`
|
||||
|
||||
## Usage Instructions
|
||||
|
||||
1. **Clone or Download the Script:**
|
||||
|
||||
Save the script to your system as `create_appimage.sh`.
|
||||
|
||||
2. **Make the Script Executable:**
|
||||
|
||||
```bash
|
||||
chmod +x create_appimage.sh
|
||||
```
|
||||
|
||||
3. **Copy Required Files:**
|
||||
|
||||
Copy the following files to the directory where the app binary is being bundled (created during the build process):
|
||||
|
||||
* `create_appimage.sh`
|
||||
* `void.desktop`
|
||||
* `void.png`
|
||||
|
||||
4. **Run the Script:**
|
||||
|
||||
```bash
|
||||
./create_appimage.sh
|
||||
```
|
||||
|
||||
5. **Result:**
|
||||
|
||||
After the script completes, it will generate an AppImage named `Void-x86_64.AppImage` (or similar, depending on your architecture) in the current directory.
|
||||
|
||||
## Script Overview
|
||||
|
||||
* **Platform Check:** Checks for macOS or Linux. Exits if unsupported.
|
||||
* **Docker Checks:** Ensures Docker is installed and running.
|
||||
* **Buildx Installation:** Installs `docker buildx` if missing.
|
||||
* **`appimagetool` Download:** Downloads `appimagetool` inside the Docker container.
|
||||
* **Dockerfile Creation:** Creates a temporary `Dockerfile.build` for the Ubuntu-based environment.
|
||||
* **Docker Image Build:** Builds a Docker image and runs the build process.
|
||||
* **AppImage Creation:**
|
||||
* Creates the `VoidApp.AppDir` structure.
|
||||
* Copies binaries, resources, and the `.desktop` entry.
|
||||
* Copies `void.desktop` and `void.png`.
|
||||
* Strips unnecessary symbols from the binary.
|
||||
* Runs `appimagetool` to generate the AppImage.
|
||||
* **Cleanup:** Removes the temporary `Dockerfile.build`.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
* **Docker Not Running:** Ensure Docker is installed and running.
|
||||
* **Permission Issues:** Try running the script with `sudo` or check Docker permissions.
|
||||
* **Outdated Dependencies:** Ensure you have the minimum required versions.
|
||||
|
||||
## License
|
||||
|
||||
This script is provided "as is". It is free to use, modify, and distribute, but comes with no warranty.
|
||||
Executable
+7
@@ -0,0 +1,7 @@
|
||||
[Desktop Entry]
|
||||
Name=void
|
||||
Exec=void
|
||||
Icon=void
|
||||
Type=Application
|
||||
Categories=Utility;
|
||||
Comment=Void Linux Application
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 795 KiB |
@@ -132,6 +132,7 @@ export type StartApplyingOpts = {
|
||||
from: 'ClickApply';
|
||||
type: 'searchReplace' | 'rewrite';
|
||||
applyStr: string;
|
||||
uri: 'current' | URI;
|
||||
}
|
||||
|
||||
|
||||
@@ -1226,6 +1227,7 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
||||
|
||||
|
||||
|
||||
// throws if there's an error
|
||||
public startApplying(opts: StartApplyingOpts) {
|
||||
if (opts.type === 'rewrite') {
|
||||
const addedDiffArea = this._initializeWriteoverStream(opts)
|
||||
@@ -1448,11 +1450,18 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
||||
|
||||
|
||||
private _initializeSearchAndReplaceStream(opts: StartApplyingOpts & { from: 'ClickApply' }) {
|
||||
const { applyStr } = opts
|
||||
const { applyStr, uri: givenURI } = opts
|
||||
let uri: URI
|
||||
|
||||
if (givenURI === 'current') {
|
||||
const uri_ = this._getActiveEditorURI()
|
||||
if (!uri_) return
|
||||
uri = uri_
|
||||
}
|
||||
else {
|
||||
uri = givenURI
|
||||
}
|
||||
|
||||
const uri_ = this._getActiveEditorURI()
|
||||
if (!uri_) return
|
||||
const uri = uri_
|
||||
|
||||
// generate search/replace block text
|
||||
const originalFileCode = this._voidFileService.readModel(uri)
|
||||
|
||||
@@ -15,6 +15,14 @@ import { IVoidFileService } from '../../common/voidFileService.js';
|
||||
// this is just for ease of readability
|
||||
export const tripleTick = ['```', '```']
|
||||
|
||||
export const editToolDesc_toolDescription = `\
|
||||
A high level description of the change you'd like to make in the file. This description will be handed to a dumber, faster model that will quickly apply the change. \
|
||||
Typically the best description you can give here is a high level view of the final code you'd like to see. For example, code excerpt(s) with "// ... existing code ..." comments to help you write less. \
|
||||
However, you are allowed to describe the change using whatever text/language you like, especially if the change is better described without code. \
|
||||
Do NOT output the whole file if possible, and try to write as LITTLE as needed to describe the change.`
|
||||
|
||||
|
||||
|
||||
export const chat_systemMessage = (workspaces: string[]) => `\
|
||||
You are a coding assistant. You are given a list of instructions to follow \`INSTRUCTIONS\`, and optionally a list of relevant files \`FILES\`, and selections inside of files \`SELECTIONS\`.
|
||||
|
||||
|
||||
@@ -86,6 +86,7 @@ export const ApplyBlockHoverButtons = ({ codeStr, applyBoxId }: { codeStr: strin
|
||||
from: 'ClickApply',
|
||||
type: 'searchReplace',
|
||||
applyStr: codeStr,
|
||||
uri: 'current',
|
||||
})
|
||||
applyingURIOfApplyBoxIdRef.current[applyBoxId] = newApplyingUri ?? undefined
|
||||
rerender(c => c + 1)
|
||||
|
||||
@@ -151,7 +151,7 @@ interface VoidChatAreaProps {
|
||||
onAbort: () => void;
|
||||
isStreaming: boolean;
|
||||
isDisabled?: boolean;
|
||||
divRef?: React.RefObject<HTMLDivElement>;
|
||||
divRef?: React.RefObject<HTMLDivElement | null>;
|
||||
|
||||
// UI customization
|
||||
featureName: FeatureName;
|
||||
@@ -528,22 +528,36 @@ export const SelectedFiles = (
|
||||
}
|
||||
|
||||
|
||||
type ToolResultToComponent = { [T in ToolName]: (props: { message: ToolMessage<T> }) => React.ReactNode }
|
||||
interface ToolResultProps {
|
||||
actionTitle: string;
|
||||
actionParam: string;
|
||||
actionNumResults?: number;
|
||||
children?: React.ReactNode;
|
||||
onClick?: () => void;
|
||||
const actionTitleOfToolName: { [T in ToolName]: string } = {
|
||||
'read_file': 'Read file',
|
||||
'list_dir': 'Inspected folder',
|
||||
'pathname_search': 'Searched filename',
|
||||
'search': 'Searched',
|
||||
|
||||
'create_uri': 'Created URI',
|
||||
'delete_uri': 'Deleted URI',
|
||||
'edit': 'Edited file',
|
||||
'terminal_command': 'Ran terminal command',
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
type ToolResultToComponent = { [T in ToolName]: (props: { message: ToolMessage<T> }) => React.ReactNode }
|
||||
|
||||
const ToolResult = ({
|
||||
actionTitle,
|
||||
toolName,
|
||||
actionParam,
|
||||
actionNumResults,
|
||||
children,
|
||||
onClick,
|
||||
}: ToolResultProps) => {
|
||||
}: {
|
||||
toolName: ToolName;
|
||||
actionParam: string;
|
||||
actionNumResults?: number;
|
||||
children?: React.ReactNode;
|
||||
onClick?: () => void;
|
||||
}) => {
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
|
||||
const isDropdown = !!children
|
||||
@@ -565,7 +579,7 @@ const ToolResult = ({
|
||||
/>
|
||||
)}
|
||||
<div className="flex items-center flex-nowrap whitespace-nowrap gap-x-2">
|
||||
<span className="text-void-fg-3">{actionTitle}</span>
|
||||
<span className="text-void-fg-3">{actionTitleOfToolName[toolName]}</span>
|
||||
<span className="text-void-fg-4 text-xs italic">{actionParam}</span>
|
||||
{actionNumResults !== undefined && (
|
||||
<span className="text-void-fg-4 text-xs">
|
||||
@@ -587,18 +601,38 @@ const ToolResult = ({
|
||||
|
||||
|
||||
|
||||
const ToolError = <T extends ToolName,>({ toolName, errorMessage }: { toolName: T, errorMessage: string }) => {
|
||||
return <ToolResult
|
||||
toolName={toolName}
|
||||
actionParam={errorMessage}
|
||||
/>
|
||||
}
|
||||
|
||||
|
||||
const toolResultToComponent: ToolResultToComponent = {
|
||||
'read_file': ({ message }) => {
|
||||
|
||||
const accessor = useAccessor()
|
||||
const commandService = accessor.get('ICommandService')
|
||||
if (message.result.type === 'error') return <ToolError toolName='read_file' errorMessage={message.result.value} />
|
||||
|
||||
const { value } = message.result
|
||||
return (
|
||||
<ToolResult
|
||||
actionTitle="Read file"
|
||||
actionParam={getBasename(message.result.uri.fsPath)}
|
||||
onClick={() => { commandService.executeCommand('vscode.open', message.result.uri, { preview: true }) }}
|
||||
/>
|
||||
toolName='read_file'
|
||||
actionParam={'View file'}
|
||||
>
|
||||
<div className="text-void-fg-4 px-2 py-1 bg-black bg-opacity-20 border border-void-border-4 border-opacity-50 rounded-sm">
|
||||
<div
|
||||
className="hover:brightness-125 hover:cursor-pointer transition-all duration-200 flex items-center flex-nowrap"
|
||||
onClick={() => { commandService.executeCommand('vscode.open', value.uri, { preview: true }) }}
|
||||
>
|
||||
<svg className="w-1 h-1 opacity-60 mr-1.5 fill-current" viewBox="0 0 100 40"><rect x="0" y="15" width="100" height="10" /></svg>
|
||||
{getBasename(value.uri.fsPath)}
|
||||
</div>
|
||||
{value.hasNextPage && (<div className="italic">AI can scroll for more content...</div>)}
|
||||
</div>
|
||||
</ToolResult>
|
||||
)
|
||||
},
|
||||
'list_dir': ({ message }) => {
|
||||
@@ -607,16 +641,18 @@ const toolResultToComponent: ToolResultToComponent = {
|
||||
const explorerService = accessor.get('IExplorerService')
|
||||
// message.result.hasNextPage = true
|
||||
// message.result.itemsRemaining = 400
|
||||
if (message.result.type === 'error') return <ToolError toolName='list_dir' errorMessage={message.result.value} />
|
||||
|
||||
const { value } = message.result
|
||||
return (
|
||||
<ToolResult
|
||||
actionTitle="Inspected folder"
|
||||
actionParam={`${getBasename(message.result.rootURI.fsPath)}/`}
|
||||
actionNumResults={message.result.children?.length}
|
||||
toolName='list_dir'
|
||||
actionParam={`${getBasename(value.rootURI.fsPath)}/`}
|
||||
actionNumResults={value.children?.length}
|
||||
>
|
||||
<div className="text-void-fg-4 px-2 py-1 bg-black bg-opacity-20 border border-void-border-4 border-opacity-50 rounded-sm">
|
||||
{message.result.children?.map((child, i) => (
|
||||
<div
|
||||
key={i}
|
||||
{value.children?.map((child, i) => (
|
||||
<div key={i}
|
||||
className="hover:brightness-125 hover:cursor-pointer transition-all duration-200 flex items-center flex-nowrap"
|
||||
onClick={() => {
|
||||
commandService.executeCommand('workbench.view.explorer');
|
||||
@@ -627,11 +663,7 @@ const toolResultToComponent: ToolResultToComponent = {
|
||||
{`${child.name}${child.isDirectory ? '/' : ''}`}
|
||||
</div>
|
||||
))}
|
||||
{message.result.hasNextPage && (
|
||||
<div className="italic">
|
||||
{message.result.itemsRemaining} more items...
|
||||
</div>
|
||||
)}
|
||||
{value.hasNextPage && (<div className="italic">{value.itemsRemaining} more items...</div>)}
|
||||
</div>
|
||||
</ToolResult>
|
||||
)
|
||||
@@ -640,74 +672,162 @@ const toolResultToComponent: ToolResultToComponent = {
|
||||
|
||||
const accessor = useAccessor()
|
||||
const commandService = accessor.get('ICommandService')
|
||||
if (message.result.type === 'error') return <ToolError toolName='pathname_search' errorMessage={message.result.value} />
|
||||
|
||||
const { value } = message.result
|
||||
return (
|
||||
<ToolResult
|
||||
actionTitle="Searched filename"
|
||||
actionParam={`"${message.result.queryStr}"`}
|
||||
actionNumResults={Array.isArray(message.result.uris) ? message.result.uris.length : 0}
|
||||
toolName='pathname_search'
|
||||
actionParam={`"${value.queryStr}"`}
|
||||
actionNumResults={value.uris.length}
|
||||
>
|
||||
<div className="text-void-fg-4 px-2 py-1 bg-black bg-opacity-20 border border-void-border-4 border-opacity-50 rounded-sm">
|
||||
{Array.isArray(message.result.uris) ?
|
||||
message.result.uris.map((uri, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="hover:brightness-125 hover:cursor-pointer transition-all duration-200 flex items-center flex-nowrap"
|
||||
onClick={() => {
|
||||
commandService.executeCommand('vscode.open', uri, { preview: true })
|
||||
}}
|
||||
>
|
||||
<svg className="w-1 h-1 opacity-60 mr-1.5 fill-current" viewBox="0 0 100 40"><rect x="0" y="15" width="100" height="10" /></svg>
|
||||
{uri.fsPath.split('/').pop()}
|
||||
</div>
|
||||
)) :
|
||||
<div className="">{message.result.uris}</div>
|
||||
}
|
||||
{message.result.hasNextPage && (
|
||||
<div className="italic">
|
||||
More results available...
|
||||
{value.uris.map((uri, i) => (
|
||||
<div key={i}
|
||||
className="hover:brightness-125 hover:cursor-pointer transition-all duration-200 flex items-center flex-nowrap"
|
||||
onClick={() => { commandService.executeCommand('vscode.open', uri, { preview: true }) }}
|
||||
>
|
||||
<svg className="w-1 h-1 opacity-60 mr-1.5 fill-current" viewBox="0 0 100 40"><rect x="0" y="15" width="100" height="10" /></svg>
|
||||
{uri.fsPath.split('/').pop()}
|
||||
</div>
|
||||
)}
|
||||
))}
|
||||
{value.hasNextPage && (<div className="italic">More results available...</div>)}
|
||||
</div>
|
||||
</ToolResult>
|
||||
)
|
||||
},
|
||||
'search': ({ message }) => {
|
||||
const accessor = useAccessor()
|
||||
const commandService = accessor.get('ICommandService')
|
||||
if (message.result.type === 'error') return <ToolError toolName='search' errorMessage={message.result.value} />
|
||||
|
||||
const { value } = message.result
|
||||
return (
|
||||
<ToolResult
|
||||
toolName='search'
|
||||
actionParam={`"${value.queryStr}"`}
|
||||
actionNumResults={value.uris.length}
|
||||
>
|
||||
<div className="text-void-fg-4 px-2 py-1 bg-black bg-opacity-20 border border-void-border-4 border-opacity-50 rounded-sm">
|
||||
{value.uris.map((uri, i) => (
|
||||
<div key={i}
|
||||
className="hover:brightness-125 hover:cursor-pointer transition-all duration-200 flex items-center flex-nowrap"
|
||||
onClick={() => { commandService.executeCommand('vscode.open', uri, { preview: true }) }}
|
||||
>
|
||||
<svg className="w-1 h-1 opacity-60 mr-1.5 fill-current" viewBox="0 0 100 40"><rect x="0" y="15" width="100" height="10" /></svg>
|
||||
{uri.fsPath.split('/').pop()}
|
||||
</div>
|
||||
))}
|
||||
{value.hasNextPage && (<div className="italic">More results available...</div>)}
|
||||
</div>
|
||||
</ToolResult>
|
||||
)
|
||||
},
|
||||
|
||||
// ---
|
||||
|
||||
'create_uri': ({ message }) => {
|
||||
const accessor = useAccessor()
|
||||
const commandService = accessor.get('ICommandService')
|
||||
|
||||
if (message.result.type === 'error') return <ToolError toolName='create_uri' errorMessage={message.result.value} />
|
||||
|
||||
const { value } = message.result
|
||||
return (
|
||||
<ToolResult
|
||||
actionTitle="Searched"
|
||||
actionParam={`"${message.result.queryStr}"`}
|
||||
actionNumResults={Array.isArray(message.result.uris) ? message.result.uris.length : 0}
|
||||
toolName='create_uri'
|
||||
actionParam={getBasename(value.uri.fsPath)}
|
||||
onClick={() => { commandService.executeCommand('vscode.open', value.uri, { preview: true }) }}
|
||||
>
|
||||
<div className="text-void-fg-4 px-2 py-1 bg-black bg-opacity-20 border border-void-border-4 border-opacity-50 rounded-sm">
|
||||
{Array.isArray(message.result.uris) ?
|
||||
message.result.uris.map((uri, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="hover:brightness-125 hover:cursor-pointer transition-all duration-200 flex items-center flex-nowrap"
|
||||
onClick={() => {
|
||||
commandService.executeCommand('vscode.open', uri, { preview: true })
|
||||
}}
|
||||
>
|
||||
<svg className="w-1 h-1 opacity-60 mr-1.5 fill-current" viewBox="0 0 100 40"><rect x="0" y="15" width="100" height="10" /></svg>
|
||||
{uri.fsPath.split('/').pop()}
|
||||
</div>
|
||||
)) :
|
||||
<div className="">{message.result.uris}</div>
|
||||
}
|
||||
{message.result.hasNextPage && (
|
||||
<div className="italic">
|
||||
More results available...
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
className="hover:brightness-125 hover:cursor-pointer transition-all duration-200 flex items-center flex-nowrap"
|
||||
onClick={() => { commandService.executeCommand('vscode.open', value.uri, { preview: true }) }}
|
||||
>
|
||||
<svg className="w-1 h-1 opacity-60 mr-1.5 fill-current" viewBox="0 0 100 40"><rect x="0" y="15" width="100" height="10" /></svg>
|
||||
{value.uri.fsPath.split('/').pop()}
|
||||
</div>
|
||||
</div>
|
||||
</ToolResult>
|
||||
)
|
||||
},
|
||||
'delete_uri': ({ message }) => {
|
||||
const accessor = useAccessor()
|
||||
const commandService = accessor.get('ICommandService')
|
||||
|
||||
if (message.result.type === 'error') return <ToolError toolName='delete_uri' errorMessage={message.result.value} />
|
||||
|
||||
const { value } = message.result
|
||||
return (
|
||||
<ToolResult
|
||||
toolName='delete_uri'
|
||||
actionParam={getBasename(value.uri.fsPath) + ' (deleted)'}
|
||||
onClick={() => { commandService.executeCommand('vscode.open', value.uri, { preview: true }) }}
|
||||
>
|
||||
<div className="text-void-fg-4 px-2 py-1 bg-black bg-opacity-20 border border-void-border-4 border-opacity-50 rounded-sm">
|
||||
<div
|
||||
className="hover:brightness-125 hover:cursor-pointer transition-all duration-200 flex items-center flex-nowrap"
|
||||
onClick={() => { commandService.executeCommand('vscode.open', value.uri, { preview: true }) }}
|
||||
>
|
||||
<svg className="w-1 h-1 opacity-60 mr-1.5 fill-current" viewBox="0 0 100 40"><rect x="0" y="15" width="100" height="10" /></svg>
|
||||
{value.uri.fsPath.split('/').pop()}
|
||||
</div>
|
||||
</div>
|
||||
</ToolResult>
|
||||
)
|
||||
},
|
||||
'edit': ({ message }) => {
|
||||
const accessor = useAccessor()
|
||||
const commandService = accessor.get('ICommandService')
|
||||
|
||||
if (message.result.type === 'error') return <ToolError toolName='edit' errorMessage={message.result.value} />
|
||||
|
||||
const { value } = message.result
|
||||
return (
|
||||
<ToolResult
|
||||
toolName='edit'
|
||||
actionParam={getBasename(value.uri.fsPath)}
|
||||
onClick={() => { commandService.executeCommand('vscode.open', value.uri, { preview: true }) }}
|
||||
>
|
||||
<div className="text-void-fg-4 px-2 py-1 bg-black bg-opacity-20 border border-void-border-4 border-opacity-50 rounded-sm">
|
||||
<div
|
||||
className="hover:brightness-125 hover:cursor-pointer transition-all duration-200 flex items-center flex-nowrap"
|
||||
onClick={() => { commandService.executeCommand('vscode.open', value.uri, { preview: true }) }}
|
||||
>
|
||||
<svg className="w-1 h-1 opacity-60 mr-1.5 fill-current" viewBox="0 0 100 40"><rect x="0" y="15" width="100" height="10" /></svg>
|
||||
{value.uri.fsPath.split('/').pop()}
|
||||
</div>
|
||||
</div>
|
||||
</ToolResult>
|
||||
)
|
||||
},
|
||||
'terminal_command': ({ message }) => {
|
||||
const accessor = useAccessor()
|
||||
const commandService = accessor.get('ICommandService')
|
||||
|
||||
if (message.result.type === 'error') return <ToolError toolName='terminal_command' errorMessage={message.result.value} />
|
||||
|
||||
const { value } = message.result
|
||||
return (
|
||||
<ToolResult
|
||||
toolName='terminal_command'
|
||||
actionParam={value.command}
|
||||
>
|
||||
<div className="text-void-fg-4 px-2 py-1 bg-black bg-opacity-20 border border-void-border-4 border-opacity-50 rounded-sm">
|
||||
<div
|
||||
className="hover:brightness-125 hover:cursor-pointer transition-all duration-200 flex items-center flex-nowrap"
|
||||
// TODO!!! open terminal
|
||||
|
||||
>
|
||||
<svg className="w-1 h-1 opacity-60 mr-1.5 fill-current" viewBox="0 0 100 40"><rect x="0" y="15" width="100" height="10" /></svg>
|
||||
|
||||
<ChatMarkdownRender string={''} />
|
||||
</div>
|
||||
</div>
|
||||
</ToolResult>
|
||||
)
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/*--------------------------------------------------------------------------------------
|
||||
* Copyright 2025 Glass Devtools, Inc. All rights reserved.
|
||||
* Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information.
|
||||
*--------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Disposable } from '../../../../base/common/lifecycle.js';
|
||||
import { registerSingleton, InstantiationType } from '../../../../platform/instantiation/common/extensions.js';
|
||||
import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
|
||||
import { ITerminalService, ITerminalInstance } from '../../../../workbench/contrib/terminal/browser/terminal.js';
|
||||
import { TerminalLocation } from '../../../../platform/terminal/common/terminal.js';
|
||||
import { generateUuid } from '../../../../base/common/uuid.js';
|
||||
|
||||
export interface ITerminalToolService {
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
createNewTerminal(terminalId: string): Promise<string>;
|
||||
runCommand(command: string, terminalId?: string): Promise<void>;
|
||||
focus(terminalId: string): Promise<void>;
|
||||
}
|
||||
|
||||
export const ITerminalToolService = createDecorator<ITerminalToolService>('TerminalToolService');
|
||||
|
||||
export class TerminalToolService extends Disposable implements ITerminalToolService {
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
private terminalInstances: Record<string, ITerminalInstance> = {}
|
||||
|
||||
constructor(
|
||||
@ITerminalService private readonly terminalService: ITerminalService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
async createNewTerminal() {
|
||||
const terminalId = generateUuid();
|
||||
|
||||
this.terminalService.createTerminal({});
|
||||
const terminal = await this.terminalService.createTerminal({
|
||||
location: TerminalLocation.Editor,
|
||||
config: { name: `Void Agent (${terminalId})`, }
|
||||
});
|
||||
|
||||
this.terminalInstances[terminalId] = terminal
|
||||
return terminalId;
|
||||
}
|
||||
|
||||
async runCommand(command: string, terminalId?: string) {
|
||||
|
||||
if (!terminalId) {
|
||||
terminalId = await this.createNewTerminal();
|
||||
}
|
||||
|
||||
const terminal = this.terminalInstances[terminalId];
|
||||
if (!terminal) throw new Error(`Terminal with ID ${terminalId} does not exist`);
|
||||
|
||||
terminal.sendText(command, true);
|
||||
return;
|
||||
}
|
||||
|
||||
async focus(terminalId: string) {
|
||||
const terminal = this.terminalInstances[terminalId];
|
||||
if (!terminal) throw new Error(`That terminal was closed.`);
|
||||
|
||||
|
||||
terminal.focus(true);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
registerSingleton(ITerminalToolService, TerminalToolService, InstantiationType.Eager);
|
||||
@@ -12,12 +12,13 @@ import { URI } from '../../../../base/common/uri.js';
|
||||
import { Emitter, Event } from '../../../../base/common/event.js';
|
||||
import { IRange } from '../../../../editor/common/core/range.js';
|
||||
import { ILLMMessageService } from './llmMessageService.js';
|
||||
import { chat_userMessageContent, chat_systemMessage, chat_userMessageContentWithAllFilesToo as chat_userMessageContentWithAllFiles, chat_selectionsString } from '../browser/prompt/prompts.js';
|
||||
import { InternalToolInfo, IToolsService, ToolCallReturnType, ToolFns, ToolName, voidTools } from './toolsService.js';
|
||||
import { toLLMChatMessage } from './llmMessageTypes.js';
|
||||
import { chat_userMessageContent, chat_systemMessage, chat_userMessageContentWithAllFilesToo, chat_selectionsString } from '../browser/prompt/prompts.js';
|
||||
import { InternalToolInfo, IToolsService, ToolCallReturnType, ToolName, voidTools } from './toolsService.js';
|
||||
import { toLLMChatMessage, ToolCallType } from './llmMessageTypes.js';
|
||||
import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.js';
|
||||
import { IVoidFileService } from './voidFileService.js';
|
||||
import { generateUuid } from '../../../../base/common/uuid.js';
|
||||
import { getErrorMessage } from '../../../../base/common/errors.js';
|
||||
|
||||
|
||||
const findLastIndex = <T>(arr: T[], condition: (t: T) => boolean): number => {
|
||||
@@ -59,11 +60,9 @@ export type ToolMessage<T extends ToolName> = {
|
||||
name: T; // internal use
|
||||
params: string; // internal use
|
||||
id: string; // apis require this tool use id
|
||||
content: string; // result
|
||||
result: ToolCallReturnType[T]; // text message of result
|
||||
content: string; // give this result to LLM
|
||||
result: { type: 'success'; value: ToolCallReturnType[T], } | { type: 'error'; value: string }; // give this result to user
|
||||
}
|
||||
|
||||
|
||||
// WARNING: changing this format is a big deal!!!!!! need to migrate old format to new format on users' computers so people don't get errors.
|
||||
export type ChatMessage =
|
||||
{
|
||||
@@ -331,7 +330,7 @@ class ChatThreadService extends Disposable implements IChatThreadService {
|
||||
const instructions = userMessage
|
||||
const userMessageContent = await chat_userMessageContent(instructions, currSelns)
|
||||
const selectionsStr = await chat_selectionsString(prevSelns, currSelns, this._voidFileService)
|
||||
const userMessageFullContent = chat_userMessageContentWithAllFiles(userMessageContent, selectionsStr)
|
||||
const userMessageFullContent = chat_userMessageContentWithAllFilesToo(userMessageContent, selectionsStr)
|
||||
|
||||
const userHistoryElt: ChatMessage = { role: 'user', content: userMessageContent, displayContent: instructions, selections: currSelns, state: defaultMessageState }
|
||||
this._addMessageToThread(threadId, userHistoryElt)
|
||||
@@ -390,37 +389,44 @@ class ChatThreadService extends Disposable implements IChatThreadService {
|
||||
else {
|
||||
this._addMessageToThread(threadId, { role: 'assistant', content: fullText, reasoning: fullReasoning || null })
|
||||
this._setStreamState(threadId, { messageSoFar: undefined, reasoningSoFar: undefined }) // clear streaming message
|
||||
for (const tool of toolCalls ?? []) {
|
||||
const toolName = tool.name as ToolName
|
||||
|
||||
// 1.
|
||||
let toolResult: Awaited<ReturnType<ToolFns[ToolName]>>
|
||||
let toolResultVal: ToolCallReturnType[ToolName]
|
||||
try {
|
||||
toolResult = await this._toolsService.toolFns[toolName](tool.params)
|
||||
toolResultVal = toolResult
|
||||
} catch (error) {
|
||||
this._setStreamState(threadId, { error })
|
||||
shouldSendAnotherMessage = false
|
||||
break
|
||||
}
|
||||
// deal with the tool
|
||||
const tool: ToolCallType | undefined = toolCalls?.[0]
|
||||
if (!tool) {
|
||||
res_()
|
||||
return
|
||||
}
|
||||
const toolName = tool.name
|
||||
|
||||
// 2.
|
||||
let toolResultStr: string
|
||||
try {
|
||||
toolResultStr = this._toolsService.toolResultToString[toolName](toolResult as any) // typescript is so bad it doesn't even couple the type of ToolResult with the type of the function being called here
|
||||
} catch (error) {
|
||||
this._setStreamState(threadId, { error })
|
||||
shouldSendAnotherMessage = false
|
||||
break
|
||||
}
|
||||
|
||||
this._addMessageToThread(threadId, { role: 'tool', name: toolName, params: tool.params, id: tool.id, content: toolResultStr, result: toolResultVal, })
|
||||
// 1.
|
||||
let toolResultVal: ToolCallReturnType[typeof toolName]
|
||||
try {
|
||||
const val = await this._toolsService.toolFns[toolName](tool.params)
|
||||
toolResultVal = val
|
||||
} catch (error) {
|
||||
const errorMessage = getErrorMessage(error)
|
||||
this._addMessageToThread(threadId, { role: 'tool', name: toolName, params: tool.params, id: tool.id, content: errorMessage, result: { type: 'error', value: errorMessage }, })
|
||||
shouldSendAnotherMessage = true
|
||||
res_()
|
||||
return
|
||||
}
|
||||
|
||||
// 2.
|
||||
let toolResultStr: string
|
||||
try {
|
||||
toolResultStr = this._toolsService.toolResultToString[toolName](toolResultVal as any) // typescript is so bad it doesn't even couple the type of ToolResult with the type of the function being called here
|
||||
} catch (error) {
|
||||
// treat as irrecoverable error
|
||||
this._setStreamState(threadId, { error })
|
||||
res_()
|
||||
return
|
||||
}
|
||||
|
||||
this._addMessageToThread(threadId, { role: 'tool', name: toolName, params: tool.params, id: tool.id, content: toolResultStr, result: { type: 'success', value: toolResultVal }, })
|
||||
shouldSendAnotherMessage = true
|
||||
res_()
|
||||
}
|
||||
res_()
|
||||
|
||||
},
|
||||
onError: (error) => {
|
||||
const messageSoFar = this.streamState[threadId]?.messageSoFar ?? ''
|
||||
@@ -436,7 +442,7 @@ class ChatThreadService extends Disposable implements IChatThreadService {
|
||||
}
|
||||
}
|
||||
|
||||
agentLoop() // DO NOT AWAIT THIS, this fn should resolve when ready to clear inputs
|
||||
agentLoop() // DO NOT AWAIT THIS, add fn should resolve when we've added message (this lets us interrupt the agent loop correctly instead of waiting for it to resolve)
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,11 @@ export const errorDetails = (fullError: Error | null): string | null => {
|
||||
return null
|
||||
}
|
||||
|
||||
export const getErrorMessage: (error: unknown) => string = (error) => {
|
||||
if (error instanceof Error) return `${error.name}: ${error.message}`
|
||||
return error + ''
|
||||
}
|
||||
|
||||
|
||||
export type LLMChatMessage = {
|
||||
role: 'system' | 'user';
|
||||
@@ -60,7 +65,7 @@ export const toLLMChatMessage = (c: ChatMessage): LLMChatMessage => {
|
||||
else if (c.role === 'tool')
|
||||
return { role: c.role, id: c.id, name: c.name, params: c.params, content: c.content || '(empty output)' }
|
||||
else {
|
||||
throw 1
|
||||
throw new Error(`Role ${(c as any).role} not recognized.`)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,10 @@ import { createDecorator, IInstantiationService } from '../../../../platform/ins
|
||||
import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.js'
|
||||
import { QueryBuilder } from '../../../../workbench/services/search/common/queryBuilder.js'
|
||||
import { ISearchService } from '../../../../workbench/services/search/common/search.js'
|
||||
import { IEditCodeService } from '../browser/editCodeService.js'
|
||||
import { editToolDesc_toolDescription } from '../browser/prompt/prompts.js'
|
||||
import { IVoidFileService } from './voidFileService.js'
|
||||
// import { ITerminalToolService } from '../browser/terminalToolService.js'
|
||||
|
||||
|
||||
// tool use for AI
|
||||
@@ -29,6 +32,8 @@ const paginationHelper = {
|
||||
} as const
|
||||
|
||||
export const voidTools = {
|
||||
// --- context-gathering (read/search/list) ---
|
||||
|
||||
read_file: {
|
||||
name: 'read_file',
|
||||
description: `Returns file contents of a given URI. ${paginationHelper.desc}`,
|
||||
@@ -68,24 +73,50 @@ export const voidTools = {
|
||||
required: ['query'],
|
||||
},
|
||||
|
||||
// go_to_definition: {
|
||||
// --- editing (create/delete) ---
|
||||
|
||||
// },
|
||||
create_uri: {
|
||||
name: 'create_uri',
|
||||
description: `Creates a file or folder at the given path. To create a folder, ensure the path ends with a trailing slash. Fails gracefully if the file already exists. Missing ancestors in the path will be recursively created automatically.`,
|
||||
params: {
|
||||
uri: { type: 'string', description: undefined },
|
||||
},
|
||||
required: ['uri'],
|
||||
},
|
||||
|
||||
// go_to_usages:
|
||||
delete_uri: {
|
||||
name: 'delete_uri',
|
||||
description: `Deletes the file or folder at the given path. Fails gracefully if the file or folder does not exist.`,
|
||||
params: {
|
||||
uri: { type: 'string', description: undefined },
|
||||
params: { type: 'string', description: 'Return -r here to delete this URI and all descendants (if applicable). Default is the empty string.' }
|
||||
},
|
||||
required: ['uri', 'params'],
|
||||
},
|
||||
|
||||
// create_file: {
|
||||
// name: 'create_file',
|
||||
// description: `Creates a file at the given path. Fails gracefully if the file already exists by doing nothing.`
|
||||
// params: {
|
||||
// uri: { type: 'string', description: undefined },
|
||||
// }
|
||||
// }
|
||||
edit: { // APPLY TOOL
|
||||
name: 'edit',
|
||||
description: `Edits the contents of a file at the given URI. Fails gracefully if the file does not exist.`,
|
||||
params: {
|
||||
uri: { type: 'string', description: undefined },
|
||||
changeDescription: { type: 'string', description: editToolDesc_toolDescription }
|
||||
},
|
||||
required: ['uri', 'changeDescription'],
|
||||
},
|
||||
|
||||
terminal_command: {
|
||||
name: 'terminal_command',
|
||||
description: `Executes a terminal command.`,
|
||||
params: {
|
||||
command: { type: 'string', description: 'The terminal command to execute.' }
|
||||
},
|
||||
required: ['command'],
|
||||
},
|
||||
|
||||
|
||||
// go_to_definition
|
||||
// go_to_usages
|
||||
|
||||
// semantic_search: {
|
||||
// description: 'Searches files semantically for the given string query.',
|
||||
// // RAG
|
||||
// },
|
||||
} satisfies { [name: string]: InternalToolInfo }
|
||||
|
||||
export type ToolName = keyof typeof voidTools
|
||||
@@ -104,9 +135,13 @@ export type ToolParamsObj<T extends ToolName> = { [paramName in ToolParamNames<T
|
||||
export type ToolCallReturnType = {
|
||||
'read_file': { uri: URI, fileContents: string, hasNextPage: boolean },
|
||||
'list_dir': { rootURI: URI, children: DirectoryItem[] | null, hasNextPage: boolean, hasPrevPage: boolean, itemsRemaining: number },
|
||||
'pathname_search': { queryStr: string, uris: URI[] | string, hasNextPage: boolean },
|
||||
'search': { queryStr: string, uris: URI[] | string, hasNextPage: boolean }
|
||||
'create_file': {}
|
||||
'pathname_search': { queryStr: string, uris: URI[], hasNextPage: boolean },
|
||||
'search': { queryStr: string, uris: URI[], hasNextPage: boolean },
|
||||
// ---
|
||||
'edit': { uri: URI, changeDescription: string },
|
||||
'create_uri': { uri: URI },
|
||||
'delete_uri': { uri: URI },
|
||||
'terminal_command': { command: string },
|
||||
}
|
||||
|
||||
type DirectoryItem = {
|
||||
@@ -198,32 +233,41 @@ const validateJSON = (s: string): { [s: string]: unknown } => {
|
||||
return o
|
||||
}
|
||||
catch (e) {
|
||||
throw new Error(`Tool parameter was not a valid JSON: "${s}".`)
|
||||
throw new Error(`Tool parameter was not a string of a valid JSON: "${s}".`)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
const validateQueryStr = (queryStr: unknown) => {
|
||||
if (typeof queryStr !== 'string') throw new Error('Error calling tool: provided query must be a string.')
|
||||
return queryStr
|
||||
const validateStr = (argName: string, value: unknown) => {
|
||||
if (typeof value !== 'string') throw new Error(`Error: ${argName} must be a string.`)
|
||||
return value
|
||||
}
|
||||
|
||||
|
||||
// TODO!!!! check to make sure in workspace
|
||||
const validateURI = (uriStr: unknown) => {
|
||||
if (typeof uriStr !== 'string') throw new Error('Error calling tool: provided uri must be a string.')
|
||||
if (typeof uriStr !== 'string') throw new Error('Error: provided uri must be a string.')
|
||||
|
||||
const uri = URI.file(uriStr)
|
||||
return uri
|
||||
}
|
||||
|
||||
const validatePageNum = (pageNumberUnknown: unknown) => {
|
||||
const proposedPageNum = Number.parseInt(pageNumberUnknown + '')
|
||||
const num = Number.isInteger(proposedPageNum) ? proposedPageNum : 1
|
||||
const pageNumber = num < 1 ? 1 : num
|
||||
return pageNumber
|
||||
if (!pageNumberUnknown) return 1
|
||||
const parsedInt = Number.parseInt(pageNumberUnknown + '')
|
||||
if (!Number.isInteger(parsedInt)) throw new Error(`Page number was not an integer: "${pageNumberUnknown}".`)
|
||||
if (parsedInt < 1) throw new Error(`Specified page number must be 1 or greater: "${pageNumberUnknown}".`)
|
||||
return parsedInt
|
||||
}
|
||||
|
||||
const validateRecursiveParamStr = (paramsUnknown: unknown) => {
|
||||
if (typeof paramsUnknown !== 'string') throw new Error('Error calling tool: provided params must be a string.')
|
||||
const params = paramsUnknown
|
||||
const isRecursive = params.includes('r')
|
||||
return isRecursive
|
||||
}
|
||||
|
||||
export interface IToolsService {
|
||||
readonly _serviceBrand: undefined;
|
||||
toolFns: ToolFns;
|
||||
@@ -236,8 +280,8 @@ export class ToolsService implements IToolsService {
|
||||
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
public toolFns: ToolFns
|
||||
public toolResultToString: ToolResultToString
|
||||
public toolFns: ToolFns;
|
||||
public toolResultToString: ToolResultToString;
|
||||
|
||||
|
||||
constructor(
|
||||
@@ -246,15 +290,17 @@ export class ToolsService implements IToolsService {
|
||||
@ISearchService searchService: ISearchService,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IVoidFileService voidFileService: IVoidFileService,
|
||||
@IEditCodeService editCodeService: IEditCodeService,
|
||||
// @ITerminalToolService private readonly terminalToolService: ITerminalToolService,
|
||||
) {
|
||||
|
||||
const queryBuilder = instantiationService.createInstance(QueryBuilder);
|
||||
|
||||
this.toolFns = {
|
||||
read_file: async (s: string) => {
|
||||
read_file: async (params: string) => {
|
||||
console.log('read_file')
|
||||
|
||||
const o = validateJSON(s)
|
||||
const o = validateJSON(params)
|
||||
const { uri: uriStr, pageNumber: pageNumberUnknown } = o
|
||||
|
||||
const uri = validateURI(uriStr)
|
||||
@@ -273,25 +319,21 @@ export class ToolsService implements IToolsService {
|
||||
|
||||
return { uri, fileContents, hasNextPage }
|
||||
},
|
||||
list_dir: async (s: string) => {
|
||||
console.log('list_dir')
|
||||
const o = validateJSON(s)
|
||||
list_dir: async (params: string) => {
|
||||
const o = validateJSON(params)
|
||||
const { uri: uriStr, pageNumber: pageNumberUnknown } = o
|
||||
|
||||
const uri = validateURI(uriStr)
|
||||
const pageNumber = validatePageNum(pageNumberUnknown)
|
||||
|
||||
const dirResult = await computeDirectoryResult(fileService, uri, pageNumber)
|
||||
console.log('list_dir result:', dirResult)
|
||||
|
||||
return dirResult
|
||||
},
|
||||
pathname_search: async (s: string) => {
|
||||
console.log('pathname_search')
|
||||
const o = validateJSON(s)
|
||||
pathname_search: async (params: string) => {
|
||||
const o = validateJSON(params)
|
||||
const { query: queryUnknown, pageNumber: pageNumberUnknown } = o
|
||||
|
||||
const queryStr = validateQueryStr(queryUnknown)
|
||||
const queryStr = validateStr('query', queryUnknown)
|
||||
const pageNumber = validatePageNum(pageNumberUnknown)
|
||||
|
||||
const query = queryBuilder.file(workspaceContextService.getWorkspace().folders.map(f => f.uri), { filePattern: queryStr, })
|
||||
@@ -304,19 +346,13 @@ export class ToolsService implements IToolsService {
|
||||
.map(({ resource, results }) => resource)
|
||||
|
||||
const hasNextPage = (data.results.length - 1) - toIdx >= 1
|
||||
console.log('pathname_search result:', uris)
|
||||
|
||||
return { queryStr, uris, hasNextPage }
|
||||
},
|
||||
search: async (s: string) => {
|
||||
|
||||
|
||||
console.log('search')
|
||||
|
||||
const o = validateJSON(s)
|
||||
search: async (params: string) => {
|
||||
const o = validateJSON(params)
|
||||
const { query: queryUnknown, pageNumber: pageNumberUnknown } = o
|
||||
|
||||
const queryStr = validateQueryStr(queryUnknown)
|
||||
const queryStr = validateStr('query', queryUnknown)
|
||||
const pageNumber = validatePageNum(pageNumberUnknown)
|
||||
|
||||
const query = queryBuilder.text({ pattern: queryStr, }, workspaceContextService.getWorkspace().folders.map(f => f.uri))
|
||||
@@ -329,17 +365,62 @@ export class ToolsService implements IToolsService {
|
||||
.map(({ resource, results }) => resource)
|
||||
|
||||
const hasNextPage = (data.results.length - 1) - toIdx >= 1
|
||||
|
||||
console.log('search result:', uris)
|
||||
|
||||
return { queryStr, uris, hasNextPage }
|
||||
},
|
||||
|
||||
// ---
|
||||
|
||||
create_uri: async (params: string) => {
|
||||
const o = validateJSON(params)
|
||||
const { uri: uriStr } = o
|
||||
const uri = validateURI(uriStr)
|
||||
await fileService.createFile(uri)
|
||||
return { uri }
|
||||
},
|
||||
|
||||
delete_uri: async (params: string) => {
|
||||
const o = validateJSON(params)
|
||||
const { uri: uriStr, params: paramsStr } = o
|
||||
const uri = validateURI(uriStr)
|
||||
const isRecursive = validateRecursiveParamStr(paramsStr)
|
||||
await fileService.del(uri, { recursive: isRecursive })
|
||||
return { uri }
|
||||
},
|
||||
|
||||
edit: async (params: string) => {
|
||||
const o = validateJSON(params)
|
||||
const { uri: uriStr, changeDescription: changeDescriptionUnknown } = o
|
||||
const uri = validateURI(uriStr)
|
||||
const changeDescription = validateStr('changeDescription', changeDescriptionUnknown)
|
||||
|
||||
// const applyId = editCodeService.startApplying({ uri, applyStr: changeDescription, from: 'ClickApply', type: 'rewrite' })
|
||||
|
||||
// // TODO!!!
|
||||
|
||||
// await // await apply done before moving on
|
||||
|
||||
return { uri, changeDescription }
|
||||
},
|
||||
|
||||
terminal_command: async (s: string) => {
|
||||
const o = validateJSON(s)
|
||||
const { command: commandUnknown } = o
|
||||
const command = validateStr('command', commandUnknown)
|
||||
|
||||
// TODO!!!!
|
||||
// await // Await user confirmation and then command execution before resolving
|
||||
|
||||
|
||||
return { command }
|
||||
},
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
const nextPageStr = (hasNextPage: boolean) => hasNextPage ? '\n\n(more on next page...)' : ''
|
||||
|
||||
// given to the LLM after the call
|
||||
this.toolResultToString = {
|
||||
read_file: (result) => {
|
||||
return nextPageStr(result.hasNextPage)
|
||||
@@ -349,13 +430,25 @@ export class ToolsService implements IToolsService {
|
||||
return dirTreeStr + nextPageStr(result.hasNextPage)
|
||||
},
|
||||
pathname_search: (result) => {
|
||||
if (typeof result.uris === 'string') return result.uris
|
||||
return result.uris.map(uri => uri.fsPath).join('\n') + nextPageStr(result.hasNextPage)
|
||||
},
|
||||
search: (result) => {
|
||||
if (typeof result.uris === 'string') return result.uris
|
||||
return result.uris.map(uri => uri.fsPath).join('\n') + nextPageStr(result.hasNextPage)
|
||||
},
|
||||
// ---
|
||||
create_uri: (result) => {
|
||||
return `URI ${result.uri.fsPath} successfully created.`
|
||||
},
|
||||
delete_uri: (result) => {
|
||||
return `URI ${result.uri.fsPath} successfully deleted.`
|
||||
},
|
||||
edit: (result) => {
|
||||
return `Change successfully made ${result.uri.fsPath} successfully deleted.`
|
||||
},
|
||||
terminal_command: (result) => {
|
||||
return `Terminal command "${result.command}" successfully executed.`
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user