diff --git a/v2/package-lock.json b/v2/package-lock.json index 48666cf..34bb777 100644 --- a/v2/package-lock.json +++ b/v2/package-lock.json @@ -9,10 +9,12 @@ "version": "0.1.0", "dependencies": { "@tauri-apps/api": "^2.10.1", + "@tauri-apps/plugin-updater": "^2.10.0", "@xterm/addon-canvas": "^0.7.0", "@xterm/addon-fit": "^0.11.0", "@xterm/xterm": "^6.0.0", - "marked": "^17.0.4" + "marked": "^17.0.4", + "shiki": "^4.0.1" }, "devDependencies": { "@sveltejs/vite-plugin-svelte": "^6.2.1", @@ -866,6 +868,106 @@ "win32" ] }, + "node_modules/@shikijs/core": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.0.1.tgz", + "integrity": "sha512-vWvqi9JNgz1dRL9Nvog5wtx7RuNkf7MEPl2mU/cyUUxJeH1CAr3t+81h8zO8zs7DK6cKLMoU9TvukWIDjP4Lzg==", + "license": "MIT", + "dependencies": { + "@shikijs/primitive": "4.0.1", + "@shikijs/types": "4.0.1", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4", + "hast-util-to-html": "^9.0.5" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/engine-javascript": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.0.1.tgz", + "integrity": "sha512-DJK9NiwtGYqMuKCRO4Ip0FKNDQpmaiS+K5bFjJ7DWFn4zHueDWgaUG8kAofkrnXF6zPPYYQY7J5FYVW9MbZyBg==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.0.1", + "@shikijs/vscode-textmate": "^10.0.2", + "oniguruma-to-es": "^4.3.4" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/engine-oniguruma": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.0.1.tgz", + "integrity": "sha512-oCWdCTDch3J8Kc0OZJ98KuUPC02O1VqIE3W/e2uvrHqTxYRR21RGEJMtchrgrxhsoJJCzmIciKsqG+q/yD+Cxg==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.0.1", + "@shikijs/vscode-textmate": "^10.0.2" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/langs": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.0.1.tgz", + "integrity": "sha512-v/mluaybWdnGJR4GqAR6zh8qAZohW9k+cGYT28Y7M8+jLbC0l4yG085O1A+WkseHTn+awd+P3UBymb2+MXFc8w==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.0.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/primitive": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@shikijs/primitive/-/primitive-4.0.1.tgz", + "integrity": "sha512-ns0hHZc5eWZuvuIEJz2pTx3Qecz0aRVYumVQJ8JgWY2tq/dH8WxdcVM49Fc2NsHEILNIT6vfdW9MF26RANWiTA==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.0.1", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/themes": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.0.1.tgz", + "integrity": "sha512-FW41C/D6j/yKQkzVdjrRPiJCtgeDaYRJFEyCKFCINuRJRj9WcmubhP4KQHPZ4+9eT87jruSrYPyoblNRyDFzvA==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.0.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/types": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.0.1.tgz", + "integrity": "sha512-EaygPEn57+jJ76mw+nTLvIpJMAcMPokFbrF8lufsZP7Ukk+ToJYEcswN1G0e49nUZAq7aCQtoeW219A8HK1ZOw==", + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/vscode-textmate": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", + "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", + "license": "MIT" + }, "node_modules/@sveltejs/acorn-typescript": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.9.tgz", @@ -925,6 +1027,15 @@ "url": "https://opencollective.com/tauri" } }, + "node_modules/@tauri-apps/plugin-updater": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-updater/-/plugin-updater-2.10.0.tgz", + "integrity": "sha512-ljN8jPlnT0aSn8ecYhuBib84alxfMx6Hc8vJSKMJyzGbTPFZAC44T2I1QNFZssgWKrAlofvJqCC6Rr472JWfkQ==", + "license": "MIT OR Apache-2.0", + "dependencies": { + "@tauri-apps/api": "^2.10.1" + } + }, "node_modules/@tsconfig/svelte": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/@tsconfig/svelte/-/svelte-5.0.8.tgz", @@ -939,6 +1050,24 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/hast": { + "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": "*" + } + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, "node_modules/@types/node": { "version": "24.11.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.11.0.tgz", @@ -956,6 +1085,18 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/unist": { + "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/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "license": "ISC" + }, "node_modules/@xterm/addon-canvas": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/@xterm/addon-canvas/-/addon-canvas-0.7.0.tgz", @@ -1013,6 +1154,36 @@ "node": ">= 0.4" } }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "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", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/chokidar": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", @@ -1039,6 +1210,16 @@ "node": ">=6" } }, + "node_modules/comma-separated-tokens": { + "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", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", @@ -1049,6 +1230,15 @@ "node": ">=0.10.0" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/devalue": { "version": "5.6.3", "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.3.tgz", @@ -1056,6 +1246,19 @@ "dev": true, "license": "MIT" }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/esbuild": { "version": "0.27.3", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", @@ -1148,6 +1351,52 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/hast-util-to-html": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz", + "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/is-reference": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", @@ -1187,6 +1436,116 @@ "node": ">= 20" } }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, "node_modules/mri": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", @@ -1227,6 +1586,23 @@ ], "license": "MIT" }, + "node_modules/oniguruma-parser": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.1.tgz", + "integrity": "sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==", + "license": "MIT" + }, + "node_modules/oniguruma-to-es": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.3.4.tgz", + "integrity": "sha512-3VhUGN3w2eYxnTzHn+ikMI+fp/96KoRSVK9/kMTcFqj1NRDh2IhQCKvYxDnWePKRXY/AqH+Fuiyb7VHSzBjHfA==", + "license": "MIT", + "dependencies": { + "oniguruma-parser": "^0.12.1", + "regex": "^6.0.1", + "regex-recursion": "^6.0.2" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -1276,6 +1652,16 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/property-information": { + "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", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/readdirp": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", @@ -1290,6 +1676,30 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/regex/-/regex-6.1.0.tgz", + "integrity": "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==", + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-recursion": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz", + "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-utilities": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz", + "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", + "license": "MIT" + }, "node_modules/rollup": { "version": "4.59.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", @@ -1348,6 +1758,25 @@ "node": ">=6" } }, + "node_modules/shiki": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-4.0.1.tgz", + "integrity": "sha512-EkAEhDTN5WhpoQFXFw79OHIrSAfHhlImeCdSyg4u4XvrpxKEmdo/9x/HWSowujAnUrFsGOwWiE58a6GVentMnQ==", + "license": "MIT", + "dependencies": { + "@shikijs/core": "4.0.1", + "@shikijs/engine-javascript": "4.0.1", + "@shikijs/engine-oniguruma": "4.0.1", + "@shikijs/langs": "4.0.1", + "@shikijs/themes": "4.0.1", + "@shikijs/types": "4.0.1", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -1358,6 +1787,30 @@ "node": ">=0.10.0" } }, + "node_modules/space-separated-tokens": { + "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", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/svelte": { "version": "5.53.7", "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.53.7.tgz", @@ -1427,6 +1880,16 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/typescript": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", @@ -1448,6 +1911,102 @@ "dev": true, "license": "MIT" }, + "node_modules/unist-util-is": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", + "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/vite": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", @@ -1549,6 +2108,16 @@ "integrity": "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==", "dev": true, "license": "MIT" + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } } } } diff --git a/v2/package.json b/v2/package.json index 3e459fa..69c2d40 100644 --- a/v2/package.json +++ b/v2/package.json @@ -23,9 +23,11 @@ }, "dependencies": { "@tauri-apps/api": "^2.10.1", + "@tauri-apps/plugin-updater": "^2.10.0", "@xterm/addon-canvas": "^0.7.0", "@xterm/addon-fit": "^0.11.0", "@xterm/xterm": "^6.0.0", - "marked": "^17.0.4" + "marked": "^17.0.4", + "shiki": "^4.0.1" } } diff --git a/v2/src-tauri/Cargo.lock b/v2/src-tauri/Cargo.lock index 5bb3c98..01f2bcd 100644 --- a/v2/src-tauri/Cargo.lock +++ b/v2/src-tauri/Cargo.lock @@ -87,6 +87,15 @@ version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" +dependencies = [ + "derive_arbitrary", +] + [[package]] name = "arrayvec" version = "0.7.6" @@ -243,6 +252,7 @@ dependencies = [ "tauri", "tauri-build", "tauri-plugin-log", + "tauri-plugin-updater", "uuid", ] @@ -626,6 +636,17 @@ dependencies = [ "serde_core", ] +[[package]] +name = "derive_arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "derive_more" version = "0.99.20" @@ -826,6 +847,16 @@ dependencies = [ "typeid", ] +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + [[package]] name = "fallible-iterator" version = "0.3.0" @@ -838,6 +869,12 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + [[package]] name = "fdeflate" version = "0.3.7" @@ -1493,6 +1530,22 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-rustls" +version = "0.27.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", +] + [[package]] name = "hyper-util" version = "0.1.20" @@ -1942,6 +1995,12 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + [[package]] name = "litemap" version = "0.8.1" @@ -2033,6 +2092,12 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "minisign-verify" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22f9645cb765ea72b8111f36c522475d2daa0d22c957a9826437e97534bc4e9e" + [[package]] name = "miniz_oxide" version = "0.8.9" @@ -2278,6 +2343,7 @@ checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ "bitflags 2.11.0", "block2", + "libc", "objc2", "objc2-core-foundation", ] @@ -2293,6 +2359,18 @@ dependencies = [ "objc2-core-foundation", ] +[[package]] +name = "objc2-osa-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f112d1746737b0da274ef79a23aac283376f335f4095a083a267a082f21db0c0" +dependencies = [ + "bitflags 2.11.0", + "objc2", + "objc2-app-kit", + "objc2-foundation", +] + [[package]] name = "objc2-quartz-core" version = "0.3.2" @@ -2337,12 +2415,32 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + [[package]] name = "option-ext" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +[[package]] +name = "osakit" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "732c71caeaa72c065bb69d7ea08717bd3f4863a4f451402fc9513e29dbd5261b" +dependencies = [ + "objc2", + "objc2-foundation", + "objc2-osa-kit", + "serde", + "serde_json", + "thiserror 2.0.18", +] + [[package]] name = "pango" version = "0.18.3" @@ -2965,15 +3063,20 @@ dependencies = [ "http-body", "http-body-util", "hyper", + "hyper-rustls", "hyper-util", "js-sys", "log", "percent-encoding", "pin-project-lite", + "rustls", + "rustls-pki-types", + "rustls-platform-verifier", "serde", "serde_json", "sync_wrapper", "tokio", + "tokio-rustls", "tokio-util", "tower", "tower-http", @@ -2985,6 +3088,20 @@ dependencies = [ "web-sys", ] +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + [[package]] name = "rkyv" version = "0.7.46" @@ -3053,6 +3170,92 @@ dependencies = [ "semver", ] +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags 2.11.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pki-types" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-platform-verifier" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" +dependencies = [ + "core-foundation", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki", + "security-framework", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + +[[package]] +name = "rustls-webpki" +version = "0.103.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + [[package]] name = "rustversion" version = "1.0.22" @@ -3068,6 +3271,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +dependencies = [ + "windows-sys 0.61.2", +] + [[package]] name = "schemars" version = "0.8.22" @@ -3131,6 +3343,29 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" +[[package]] +name = "security-framework" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +dependencies = [ + "bitflags 2.11.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "selectors" version = "0.24.0" @@ -3523,6 +3758,12 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "swift-rs" version = "1.0.7" @@ -3644,6 +3885,17 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +[[package]] +name = "tar" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" +dependencies = [ + "filetime", + "libc", + "xattr", +] + [[package]] name = "target-lexicon" version = "0.12.16" @@ -3803,6 +4055,39 @@ dependencies = [ "time", ] +[[package]] +name = "tauri-plugin-updater" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fe8e9bebd88fc222938ffdfbdcfa0307081423bd01e3252fc337d8bde81fc61" +dependencies = [ + "base64 0.22.1", + "dirs 6.0.0", + "flate2", + "futures-util", + "http", + "infer", + "log", + "minisign-verify", + "osakit", + "percent-encoding", + "reqwest", + "rustls", + "semver", + "serde", + "serde_json", + "tar", + "tauri", + "tauri-plugin", + "tempfile", + "thiserror 2.0.18", + "time", + "tokio", + "url", + "windows-sys 0.60.2", + "zip", +] + [[package]] name = "tauri-runtime" version = "2.10.1" @@ -3903,6 +4188,19 @@ dependencies = [ "toml 0.9.12+spec-1.1.0", ] +[[package]] +name = "tempfile" +version = "3.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82a72c767771b47409d2345987fda8628641887d5466101319899796367354a0" +dependencies = [ + "fastrand", + "getrandom 0.4.2", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + [[package]] name = "tendril" version = "0.4.3" @@ -4035,6 +4333,16 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + [[package]] name = "tokio-util" version = "0.7.18" @@ -4316,6 +4624,12 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" version = "2.5.8" @@ -4624,6 +4938,15 @@ dependencies = [ "system-deps", ] +[[package]] +name = "webpki-root-certs" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "804f18a4ac2676ffb4e8b5b5fa9ae38af06df08162314f96a68d2a363e21a8ca" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "webview2-com" version = "0.38.2" @@ -4863,6 +5186,15 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.59.0" @@ -5357,6 +5689,16 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "xattr" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" +dependencies = [ + "libc", + "rustix", +] + [[package]] name = "yoke" version = "0.8.1" @@ -5421,6 +5763,12 @@ dependencies = [ "synstructure", ] +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + [[package]] name = "zerotrie" version = "0.2.3" @@ -5454,6 +5802,18 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "zip" +version = "4.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa8cd6af31c3b31c6631b8f483848b91589021b28fffe50adada48d4f4d2ed1" +dependencies = [ + "arbitrary", + "crc32fast", + "indexmap 2.13.0", + "memchr", +] + [[package]] name = "zmij" version = "1.0.21" diff --git a/v2/src-tauri/Cargo.toml b/v2/src-tauri/Cargo.toml index f532c85..9eacd98 100644 --- a/v2/src-tauri/Cargo.toml +++ b/v2/src-tauri/Cargo.toml @@ -27,3 +27,4 @@ uuid = { version = "1", features = ["v4"] } rusqlite = { version = "0.31", features = ["bundled"] } dirs = "5" notify = { version = "6", features = ["macos_fsevent"] } +tauri-plugin-updater = "2.10.0" diff --git a/v2/src-tauri/src/ctx.rs b/v2/src-tauri/src/ctx.rs new file mode 100644 index 0000000..64c9cf2 --- /dev/null +++ b/v2/src-tauri/src/ctx.rs @@ -0,0 +1,172 @@ +// ctx — Read-only access to the Claude Code context manager database +// Database: ~/.claude-context/context.db (managed by ctx CLI tool) + +use rusqlite::{Connection, params}; +use serde::Serialize; +use std::sync::Mutex; + +#[derive(Debug, Clone, Serialize)] +pub struct CtxProject { + pub name: String, + pub description: String, + pub work_dir: Option, + pub created_at: String, +} + +#[derive(Debug, Clone, Serialize)] +pub struct CtxEntry { + pub project: String, + pub key: String, + pub value: String, + pub updated_at: String, +} + +#[derive(Debug, Clone, Serialize)] +pub struct CtxSummary { + pub project: String, + pub summary: String, + pub created_at: String, +} + +pub struct CtxDb { + conn: Mutex>, +} + +impl CtxDb { + pub fn new() -> Self { + let db_path = dirs::home_dir() + .unwrap_or_default() + .join(".claude-context") + .join("context.db"); + + let conn = if db_path.exists() { + Connection::open_with_flags( + &db_path, + rusqlite::OpenFlags::SQLITE_OPEN_READ_ONLY | rusqlite::OpenFlags::SQLITE_OPEN_NO_MUTEX, + ).ok() + } else { + None + }; + + Self { conn: Mutex::new(conn) } + } + + pub fn list_projects(&self) -> Result, String> { + let lock = self.conn.lock().unwrap(); + let conn = lock.as_ref().ok_or("ctx database not found")?; + + let mut stmt = conn + .prepare("SELECT name, description, work_dir, created_at FROM sessions ORDER BY name") + .map_err(|e| format!("ctx query failed: {e}"))?; + + let projects = stmt + .query_map([], |row| { + Ok(CtxProject { + name: row.get(0)?, + description: row.get(1)?, + work_dir: row.get(2)?, + created_at: row.get(3)?, + }) + }) + .map_err(|e| format!("ctx query failed: {e}"))? + .collect::, _>>() + .map_err(|e| format!("ctx row read failed: {e}"))?; + + Ok(projects) + } + + pub fn get_context(&self, project: &str) -> Result, String> { + let lock = self.conn.lock().unwrap(); + let conn = lock.as_ref().ok_or("ctx database not found")?; + + let mut stmt = conn + .prepare("SELECT project, key, value, updated_at FROM contexts WHERE project = ?1 ORDER BY key") + .map_err(|e| format!("ctx query failed: {e}"))?; + + let entries = stmt + .query_map(params![project], |row| { + Ok(CtxEntry { + project: row.get(0)?, + key: row.get(1)?, + value: row.get(2)?, + updated_at: row.get(3)?, + }) + }) + .map_err(|e| format!("ctx query failed: {e}"))? + .collect::, _>>() + .map_err(|e| format!("ctx row read failed: {e}"))?; + + Ok(entries) + } + + pub fn get_shared(&self) -> Result, String> { + let lock = self.conn.lock().unwrap(); + let conn = lock.as_ref().ok_or("ctx database not found")?; + + let mut stmt = conn + .prepare("SELECT key, value, updated_at FROM shared ORDER BY key") + .map_err(|e| format!("ctx query failed: {e}"))?; + + let entries = stmt + .query_map([], |row| { + Ok(CtxEntry { + project: "shared".to_string(), + key: row.get(0)?, + value: row.get(1)?, + updated_at: row.get(2)?, + }) + }) + .map_err(|e| format!("ctx query failed: {e}"))? + .collect::, _>>() + .map_err(|e| format!("ctx row read failed: {e}"))?; + + Ok(entries) + } + + pub fn get_summaries(&self, project: &str, limit: i64) -> Result, String> { + let lock = self.conn.lock().unwrap(); + let conn = lock.as_ref().ok_or("ctx database not found")?; + + let mut stmt = conn + .prepare("SELECT project, summary, created_at FROM summaries WHERE project = ?1 ORDER BY created_at DESC LIMIT ?2") + .map_err(|e| format!("ctx query failed: {e}"))?; + + let summaries = stmt + .query_map(params![project, limit], |row| { + Ok(CtxSummary { + project: row.get(0)?, + summary: row.get(1)?, + created_at: row.get(2)?, + }) + }) + .map_err(|e| format!("ctx query failed: {e}"))? + .collect::, _>>() + .map_err(|e| format!("ctx row read failed: {e}"))?; + + Ok(summaries) + } + + pub fn search(&self, query: &str) -> Result, String> { + let lock = self.conn.lock().unwrap(); + let conn = lock.as_ref().ok_or("ctx database not found")?; + + let mut stmt = conn + .prepare("SELECT project, key, value FROM contexts_fts WHERE contexts_fts MATCH ?1 LIMIT 50") + .map_err(|e| format!("ctx search failed: {e}"))?; + + let entries = stmt + .query_map(params![query], |row| { + Ok(CtxEntry { + project: row.get(0)?, + key: row.get(1)?, + value: row.get(2)?, + updated_at: String::new(), + }) + }) + .map_err(|e| format!("ctx search failed: {e}"))? + .collect::, _>>() + .map_err(|e| format!("ctx row read failed: {e}"))?; + + Ok(entries) + } +} diff --git a/v2/src-tauri/src/lib.rs b/v2/src-tauri/src/lib.rs index 6c21533..c88666b 100644 --- a/v2/src-tauri/src/lib.rs +++ b/v2/src-tauri/src/lib.rs @@ -1,10 +1,12 @@ +mod ctx; mod pty; mod sidecar; mod watcher; mod session; +use ctx::CtxDb; use pty::{PtyManager, PtyOptions}; -use session::{Session, SessionDb, LayoutState}; +use session::{Session, SessionDb, LayoutState, SshSession}; use sidecar::{AgentQueryOptions, SidecarManager}; use watcher::FileWatcherManager; use std::sync::Arc; @@ -15,6 +17,7 @@ struct AppState { sidecar_manager: Arc, session_db: Arc, file_watcher: Arc, + ctx_db: Arc, } // --- PTY commands --- @@ -149,6 +152,50 @@ fn settings_list(state: State<'_, AppState>) -> Result, St state.session_db.get_all_settings() } +// --- SSH session commands --- + +#[tauri::command] +fn ssh_session_list(state: State<'_, AppState>) -> Result, String> { + state.session_db.list_ssh_sessions() +} + +#[tauri::command] +fn ssh_session_save(state: State<'_, AppState>, session: SshSession) -> Result<(), String> { + state.session_db.save_ssh_session(&session) +} + +#[tauri::command] +fn ssh_session_delete(state: State<'_, AppState>, id: String) -> Result<(), String> { + state.session_db.delete_ssh_session(&id) +} + +// --- ctx commands --- + +#[tauri::command] +fn ctx_list_projects(state: State<'_, AppState>) -> Result, String> { + state.ctx_db.list_projects() +} + +#[tauri::command] +fn ctx_get_context(state: State<'_, AppState>, project: String) -> Result, String> { + state.ctx_db.get_context(&project) +} + +#[tauri::command] +fn ctx_get_shared(state: State<'_, AppState>) -> Result, String> { + state.ctx_db.get_shared() +} + +#[tauri::command] +fn ctx_get_summaries(state: State<'_, AppState>, project: String, limit: i64) -> Result, String> { + state.ctx_db.get_summaries(&project, limit) +} + +#[tauri::command] +fn ctx_search(state: State<'_, AppState>, query: String) -> Result, String> { + state.ctx_db.search(&query) +} + #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { let pty_manager = Arc::new(PtyManager::new()); @@ -163,12 +210,14 @@ pub fn run() { ); let file_watcher = Arc::new(FileWatcherManager::new()); + let ctx_db = Arc::new(CtxDb::new()); let app_state = AppState { pty_manager, sidecar_manager: sidecar_manager.clone(), session_db, file_watcher, + ctx_db, }; tauri::Builder::default() @@ -195,7 +244,16 @@ pub fn run() { settings_get, settings_set, settings_list, + ssh_session_list, + ssh_session_save, + ssh_session_delete, + ctx_list_projects, + ctx_get_context, + ctx_get_shared, + ctx_get_summaries, + ctx_search, ]) + .plugin(tauri_plugin_updater::Builder::new().build()) .setup(move |app| { if cfg!(debug_assertions) { app.handle().plugin( diff --git a/v2/src-tauri/src/session.rs b/v2/src-tauri/src/session.rs index df9ff87..ebbbb46 100644 --- a/v2/src-tauri/src/session.rs +++ b/v2/src-tauri/src/session.rs @@ -6,6 +6,20 @@ use serde::{Deserialize, Serialize}; use std::path::PathBuf; use std::sync::Mutex; +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SshSession { + pub id: String, + pub name: String, + pub host: String, + pub port: i32, + pub username: String, + pub key_file: String, + pub folder: String, + pub color: String, + pub created_at: i64, + pub last_used_at: i64, +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Session { pub id: String, @@ -73,6 +87,19 @@ impl SessionDb { key TEXT PRIMARY KEY, value TEXT NOT NULL ); + + CREATE TABLE IF NOT EXISTS ssh_sessions ( + id TEXT PRIMARY KEY, + name TEXT NOT NULL, + host TEXT NOT NULL, + port INTEGER NOT NULL DEFAULT 22, + username TEXT NOT NULL, + key_file TEXT DEFAULT '', + folder TEXT DEFAULT '', + color TEXT DEFAULT '#89b4fa', + created_at INTEGER NOT NULL, + last_used_at INTEGER NOT NULL + ); " ).map_err(|e| format!("Migration failed: {e}"))?; Ok(()) @@ -212,4 +239,80 @@ impl SessionDb { Ok(LayoutState { preset, pane_ids }) }).map_err(|e| format!("Layout read failed: {e}")) } + + // --- SSH session methods --- + + pub fn list_ssh_sessions(&self) -> Result, String> { + let conn = self.conn.lock().unwrap(); + let mut stmt = conn + .prepare("SELECT id, name, host, port, username, key_file, folder, color, created_at, last_used_at FROM ssh_sessions ORDER BY last_used_at DESC") + .map_err(|e| format!("SSH query prepare failed: {e}"))?; + + let sessions = stmt + .query_map([], |row| { + Ok(SshSession { + id: row.get(0)?, + name: row.get(1)?, + host: row.get(2)?, + port: row.get(3)?, + username: row.get(4)?, + key_file: row.get(5)?, + folder: row.get(6)?, + color: row.get(7)?, + created_at: row.get(8)?, + last_used_at: row.get(9)?, + }) + }) + .map_err(|e| format!("SSH query failed: {e}"))? + .collect::, _>>() + .map_err(|e| format!("SSH row read failed: {e}"))?; + + Ok(sessions) + } + + pub fn save_ssh_session(&self, session: &SshSession) -> Result<(), String> { + let conn = self.conn.lock().unwrap(); + conn.execute( + "INSERT OR REPLACE INTO ssh_sessions (id, name, host, port, username, key_file, folder, color, created_at, last_used_at) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)", + params![ + session.id, + session.name, + session.host, + session.port, + session.username, + session.key_file, + session.folder, + session.color, + session.created_at, + session.last_used_at, + ], + ).map_err(|e| format!("SSH insert failed: {e}"))?; + Ok(()) + } + + pub fn delete_ssh_session(&self, id: &str) -> Result<(), String> { + let conn = self.conn.lock().unwrap(); + conn.execute("DELETE FROM ssh_sessions WHERE id = ?1", params![id]) + .map_err(|e| format!("SSH delete failed: {e}"))?; + Ok(()) + } + + pub fn update_ssh_session(&self, session: &SshSession) -> Result<(), String> { + let conn = self.conn.lock().unwrap(); + conn.execute( + "UPDATE ssh_sessions SET name = ?1, host = ?2, port = ?3, username = ?4, key_file = ?5, folder = ?6, color = ?7, last_used_at = ?8 WHERE id = ?9", + params![ + session.name, + session.host, + session.port, + session.username, + session.key_file, + session.folder, + session.color, + session.last_used_at, + session.id, + ], + ).map_err(|e| format!("SSH update failed: {e}"))?; + Ok(()) + } } diff --git a/v2/src-tauri/tauri.conf.json b/v2/src-tauri/tauri.conf.json index c289ebf..368ef76 100644 --- a/v2/src-tauri/tauri.conf.json +++ b/v2/src-tauri/tauri.conf.json @@ -24,6 +24,15 @@ "csp": null } }, + "plugins": { + "updater": { + "endpoints": [ + "https://github.com/DexterFromLab/BTerminal/releases/latest/download/latest.json" + ], + "dialog": true, + "pubkey": "" + } + }, "bundle": { "active": true, "targets": ["deb", "appimage"], diff --git a/v2/src/App.svelte b/v2/src/App.svelte index 04d4605..3d37e91 100644 --- a/v2/src/App.svelte +++ b/v2/src/App.svelte @@ -6,8 +6,14 @@ import ToastContainer from './lib/components/Notifications/ToastContainer.svelte'; import SettingsDialog from './lib/components/Settings/SettingsDialog.svelte'; import { addPane, focusPaneByIndex, removePane, getPanes, restoreFromDb } from './lib/stores/layout.svelte'; + import { initTheme } from './lib/stores/theme.svelte'; + import { isDetachedMode, getDetachedConfig } from './lib/utils/detach'; + import TerminalPane from './lib/components/Terminal/TerminalPane.svelte'; + import AgentPane from './lib/components/Agent/AgentPane.svelte'; let settingsOpen = $state(false); + let detached = isDetachedMode(); + let detachedConfig = getDetachedConfig(); import { startAgentDispatcher, stopAgentDispatcher } from './lib/agent-dispatcher'; function newTerminal() { @@ -31,8 +37,9 @@ } onMount(() => { + initTheme(); startAgentDispatcher(); - restoreFromDb(); + if (!detached) restoreFromDb(); function handleKeydown(e: KeyboardEvent) { // Ctrl+N — new terminal @@ -80,17 +87,42 @@ }); - -
- -
- +{#if detached && detachedConfig} +
+ {#if detachedConfig.type === 'terminal' || detachedConfig.type === 'ssh'} + + {:else if detachedConfig.type === 'agent'} + + {:else} + + {/if} +
+{:else} + +
+ +
+ + settingsOpen = false} /> +{/if} - settingsOpen = false} /> diff --git a/v2/src/lib/components/Layout/PaneContainer.svelte b/v2/src/lib/components/Layout/PaneContainer.svelte index 678bfd6..51d6dcd 100644 --- a/v2/src/lib/components/Layout/PaneContainer.svelte +++ b/v2/src/lib/components/Layout/PaneContainer.svelte @@ -5,10 +5,11 @@ title: string; status?: 'idle' | 'running' | 'error' | 'done'; onClose?: () => void; + onDetach?: () => void; children: Snippet; } - let { title, status = 'idle', onClose, children }: Props = $props(); + let { title, status = 'idle', onClose, onDetach, children }: Props = $props();
@@ -18,6 +19,9 @@ {#if status !== 'idle'} {status} {/if} + {#if onDetach} + + {/if} {#if onClose} {/if} @@ -75,6 +79,18 @@ .status.error { color: var(--ctp-red); } .status.done { color: var(--ctp-green); } + .detach-btn { + background: none; + border: none; + color: var(--text-muted); + font-size: 12px; + cursor: pointer; + padding: 0 2px; + line-height: 1; + } + + .detach-btn:hover { color: var(--ctp-blue); } + .close-btn { background: none; border: none; diff --git a/v2/src/lib/components/Layout/TilingGrid.svelte b/v2/src/lib/components/Layout/TilingGrid.svelte index b89bae4..5fc2599 100644 --- a/v2/src/lib/components/Layout/TilingGrid.svelte +++ b/v2/src/lib/components/Layout/TilingGrid.svelte @@ -3,6 +3,7 @@ import TerminalPane from '../Terminal/TerminalPane.svelte'; import AgentPane from '../Agent/AgentPane.svelte'; import MarkdownPane from '../Markdown/MarkdownPane.svelte'; + import ContextPane from '../Context/ContextPane.svelte'; import { getPanes, getGridTemplate, @@ -10,9 +11,17 @@ focusPane, removePane, } from '../../stores/layout.svelte'; + import { detachPane } from '../../utils/detach'; + import { isDetachedMode } from '../../utils/detach'; let gridTemplate = $derived(getGridTemplate()); let panes = $derived(getPanes()); + let detached = isDetachedMode(); + + function handleDetach(pane: typeof panes[0]) { + detachPane(pane); + removePane(pane.id); + }
removePane(pane.id)} + onDetach={detached ? undefined : () => handleDetach(pane)} > {#if pane.type === 'terminal'} removePane(pane.id)} /> + {:else if pane.type === 'ssh'} + removePane(pane.id)} + /> + {:else if pane.type === 'context'} + removePane(pane.id)} /> {:else if pane.type === 'markdown'} import { onMount, onDestroy } from 'svelte'; - import { marked } from 'marked'; + import { marked, Renderer } from 'marked'; import { watchFile, unwatchFile, onFileChanged, type FileChangedPayload } from '../../adapters/file-bridge'; + import { getHighlighter, highlightCode, escapeHtml } from '../../utils/highlight'; interface Props { filePath: string; @@ -15,9 +16,18 @@ let error = $state(''); let unlisten: (() => void) | undefined; + const renderer = new Renderer(); + renderer.code = function({ text, lang }: { text: string; lang?: string }) { + if (lang) { + const highlighted = highlightCode(text, lang); + if (highlighted !== escapeHtml(text)) return highlighted; + } + return `
${escapeHtml(text)}
`; + }; + function renderMarkdown(source: string): void { try { - renderedHtml = marked.parse(source, { async: false }) as string; + renderedHtml = marked.parse(source, { renderer, async: false }) as string; error = ''; } catch (e) { error = `Render error: ${e}`; @@ -26,6 +36,7 @@ onMount(async () => { try { + await getHighlighter(); const content = await watchFile(paneId, filePath); renderMarkdown(content); @@ -125,6 +136,21 @@ color: var(--text-primary); } + .markdown-body :global(.shiki) { + background: var(--bg-surface) !important; + padding: 12px 14px; + border-radius: var(--border-radius); + overflow-x: auto; + font-size: 12px; + line-height: 1.5; + margin: 0.6em 0; + } + + .markdown-body :global(.shiki code) { + background: none !important; + padding: 0; + } + .markdown-body :global(blockquote) { border-left: 3px solid var(--ctp-mauve); margin: 0.5em 0; diff --git a/v2/src/lib/components/SSH/SshDialog.svelte b/v2/src/lib/components/SSH/SshDialog.svelte new file mode 100644 index 0000000..fa00248 --- /dev/null +++ b/v2/src/lib/components/SSH/SshDialog.svelte @@ -0,0 +1,281 @@ + + +{#if open} + +
+ +
+ +
+{/if} + + diff --git a/v2/src/lib/components/SSH/SshSessionList.svelte b/v2/src/lib/components/SSH/SshSessionList.svelte new file mode 100644 index 0000000..660f42e --- /dev/null +++ b/v2/src/lib/components/SSH/SshSessionList.svelte @@ -0,0 +1,263 @@ + + +
+
+

SSH

+ +
+ + {#if sessions.length === 0} +
+

No SSH sessions.

+
+ {:else} + {@const groups = grouped()} + {#each [...groups.entries()] as [folder, folderSessions] (folder)} + {#if folder} +
{folder}
+ {/if} +
    + {#each folderSessions as session (session.id)} +
  • + + + +
  • + {/each} +
+ {/each} + {/if} +
+ + { dialogOpen = false; }} + onSaved={loadSessions} +/> + + diff --git a/v2/src/lib/components/Settings/SettingsDialog.svelte b/v2/src/lib/components/Settings/SettingsDialog.svelte index 3fd5ba5..e7ec34c 100644 --- a/v2/src/lib/components/Settings/SettingsDialog.svelte +++ b/v2/src/lib/components/Settings/SettingsDialog.svelte @@ -2,6 +2,8 @@ import { onMount } from 'svelte'; import { getSetting, setSetting } from '../../adapters/settings-bridge'; import { notify } from '../../stores/notifications.svelte'; + import { getCurrentFlavor, setFlavor } from '../../stores/theme.svelte'; + import { ALL_FLAVORS, FLAVOR_LABELS, type CatppuccinFlavor } from '../../styles/themes'; interface Props { open: boolean; @@ -13,12 +15,14 @@ let defaultShell = $state(''); let defaultCwd = $state(''); let maxPanes = $state('4'); + let themeFlavor = $state('mocha'); onMount(async () => { try { defaultShell = (await getSetting('default_shell')) ?? ''; defaultCwd = (await getSetting('default_cwd')) ?? ''; maxPanes = (await getSetting('max_panes')) ?? '4'; + themeFlavor = getCurrentFlavor(); } catch { // Use defaults } @@ -29,6 +33,7 @@ if (defaultShell) await setSetting('default_shell', defaultShell); if (defaultCwd) await setSetting('default_cwd', defaultCwd); await setSetting('max_panes', maxPanes); + await setFlavor(themeFlavor); notify('success', 'Settings saved'); onClose(); } catch (e) { @@ -67,6 +72,15 @@ Maximum simultaneous panes (1-8) +