diff --git a/package-lock.json b/package-lock.json index e8668c0..245a54c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -323,6 +323,7 @@ "version": "17.3.10", "resolved": "https://registry.npmjs.org/@angular/common/-/common-17.3.10.tgz", "integrity": "sha512-6SfD21M3LujymmZsZQIxAsV8Bj5u6He6ImZ+p2rr7FAhFxpVJyKldK8LCmJcFsBD4srpQcxEZ0iDxXvg+0ihAw==", + "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -358,6 +359,7 @@ "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-17.3.10.tgz", "integrity": "sha512-85SBphqRj3szac3FbeYgEZ+I6WaAlo5h7JX06BdjOLLiaoIwlFhLeAuG+jVekseV+95grFUxIsCMphWHi2e6hQ==", "dev": true, + "peer": true, "dependencies": { "@babel/core": "7.23.9", "@jridgewell/sourcemap-codec": "^1.4.14", @@ -430,6 +432,7 @@ "version": "17.3.10", "resolved": "https://registry.npmjs.org/@angular/core/-/core-17.3.10.tgz", "integrity": "sha512-ocEKu7X0yFCOvgJn1uZy76qjhsjKvULrO1k/BuIX0nwhp61DTGYTvCqKmwCBLM8/gvcKYH5vMKMHoQKtiSGE0A==", + "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -445,6 +448,7 @@ "version": "17.3.10", "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-17.3.10.tgz", "integrity": "sha512-LEhBDOKm2A7nRmZqsafVp6OinRDG1OYZBSqjnT1jZ+f0CRRFIXz6aJ0TMPoU6vq9SLRJ7vrGD9P/eBf2hW00NQ==", + "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -576,6 +580,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/@asciidoctor/core/-/core-3.0.4.tgz", "integrity": "sha512-41SDMi7iRRBViPe0L6VWFTe55bv6HEOJeRqMj5+E5wB1YPdUPuTucL4UAESPZM6OWmn4t/5qM5LusXomFUVwVQ==", + "peer": true, "dependencies": { "@asciidoctor/opal-runtime": "3.0.1", "unxhr": "1.2.0" @@ -626,6 +631,7 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.0.tgz", "integrity": "sha512-fQfkg0Gjkza3nf0c7/w6Xf34BW4YvzNfACRLmmb7XRLa6XHdR+K9AlJlxneFfWYf6uhOzuzZVTjF/8KfndZANw==", "dev": true, + "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.23.5", @@ -3018,6 +3024,133 @@ "node": ">=14" } }, + "node_modules/@github/copilot": { + "version": "0.0.389", + "resolved": "https://registry.npmjs.org/@github/copilot/-/copilot-0.0.389.tgz", + "integrity": "sha512-XCHMCd8fu7g9WAp+ZepXBF1ud8vdfxDG4ajstGJqHfbdz0RxQktB35R5s/vKizpYXSZogFqwjxl41qX8DypY6g==", + "license": "MIT", + "bin": { + "copilot": "npm-loader.js" + }, + "optionalDependencies": { + "@github/copilot-darwin-arm64": "0.0.389", + "@github/copilot-darwin-x64": "0.0.389", + "@github/copilot-linux-arm64": "0.0.389", + "@github/copilot-linux-x64": "0.0.389", + "@github/copilot-win32-arm64": "0.0.389", + "@github/copilot-win32-x64": "0.0.389" + } + }, + "node_modules/@github/copilot-darwin-arm64": { + "version": "0.0.389", + "resolved": "https://registry.npmjs.org/@github/copilot-darwin-arm64/-/copilot-darwin-arm64-0.0.389.tgz", + "integrity": "sha512-4Crm/C9//ZPsK+NP5E5BEjltAGuij9XkvRILvZ/mqlaiDXRncFvUtdOoV+/Of+i4Zva/1sWnc7CrS7PHGJDyFg==", + "cpu": [ + "arm64" + ], + "license": "SEE LICENSE IN LICENSE.md", + "optional": true, + "os": [ + "darwin" + ], + "bin": { + "copilot-darwin-arm64": "copilot" + } + }, + "node_modules/@github/copilot-darwin-x64": { + "version": "0.0.389", + "resolved": "https://registry.npmjs.org/@github/copilot-darwin-x64/-/copilot-darwin-x64-0.0.389.tgz", + "integrity": "sha512-w0LB+lw29UmRS9oW8ENyZhrf3S5LQ3Pz796dQY8LZybp7WxEGtQhvXN48mye9gGzOHNoHxQ2+10+OzsjC/mLUQ==", + "cpu": [ + "x64" + ], + "license": "SEE LICENSE IN LICENSE.md", + "optional": true, + "os": [ + "darwin" + ], + "bin": { + "copilot-darwin-x64": "copilot" + } + }, + "node_modules/@github/copilot-linux-arm64": { + "version": "0.0.389", + "resolved": "https://registry.npmjs.org/@github/copilot-linux-arm64/-/copilot-linux-arm64-0.0.389.tgz", + "integrity": "sha512-8QNvfs4r6nrbQrT4llu0CbJHcCJosyj+ZgLSpA+lqIiO/TiTQ48kV41uNjzTz1RmR6/qBKcz81FB7HcHXpT3xw==", + "cpu": [ + "arm64" + ], + "license": "SEE LICENSE IN LICENSE.md", + "optional": true, + "os": [ + "linux" + ], + "bin": { + "copilot-linux-arm64": "copilot" + } + }, + "node_modules/@github/copilot-linux-x64": { + "version": "0.0.389", + "resolved": "https://registry.npmjs.org/@github/copilot-linux-x64/-/copilot-linux-x64-0.0.389.tgz", + "integrity": "sha512-ls42wSzspC7sLiweoqu2zT75mqMsLWs+IZBfCqcuH1BV+C/j/XSEHsSrJxAI3TPtIsOTolPbTAa8jye1nGDxeg==", + "cpu": [ + "x64" + ], + "license": "SEE LICENSE IN LICENSE.md", + "optional": true, + "os": [ + "linux" + ], + "bin": { + "copilot-linux-x64": "copilot" + } + }, + "node_modules/@github/copilot-sdk": { + "version": "0.1.16", + "resolved": "https://registry.npmjs.org/@github/copilot-sdk/-/copilot-sdk-0.1.16.tgz", + "integrity": "sha512-yEZrrUl9w6rvKmjJpzpqovL39GzFrHxnIXOSK/bQfFwk7Ak/drmBk2gOwJqDVJcbhUm2dsoeLIfok7vtyjAxTw==", + "license": "MIT", + "dependencies": { + "@github/copilot": "^0.0.389", + "vscode-jsonrpc": "^8.2.1", + "zod": "^4.3.5" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@github/copilot-win32-arm64": { + "version": "0.0.389", + "resolved": "https://registry.npmjs.org/@github/copilot-win32-arm64/-/copilot-win32-arm64-0.0.389.tgz", + "integrity": "sha512-loniaCnrty9okQMl3EhxeeyDhnrJ/lJK0Q0r7wkLf1d/TM2swp3tsGZyIRlhDKx5lgcnCPm1m0BqauMo8Vs34g==", + "cpu": [ + "arm64" + ], + "license": "SEE LICENSE IN LICENSE.md", + "optional": true, + "os": [ + "win32" + ], + "bin": { + "copilot-win32-arm64": "copilot.exe" + } + }, + "node_modules/@github/copilot-win32-x64": { + "version": "0.0.389", + "resolved": "https://registry.npmjs.org/@github/copilot-win32-x64/-/copilot-win32-x64-0.0.389.tgz", + "integrity": "sha512-L1ZzwV/vsxnrz0WO4qLDUlXXFQQ9fOFuBGKWy6TXS7aniaxI/7mdRQR1YjIEqy+AzRw9BaXR2UUUUDk0gb1+kw==", + "cpu": [ + "x64" + ], + "license": "SEE LICENSE IN LICENSE.md", + "optional": true, + "os": [ + "win32" + ], + "bin": { + "copilot-win32-x64": "copilot.exe" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -3556,6 +3689,7 @@ "integrity": "sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@octokit/auth-token": "^6.0.0", "@octokit/graphql": "^9.0.3", @@ -5206,6 +5340,7 @@ "version": "18.19.34", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.34.tgz", "integrity": "sha512-eXF4pfBNV5DAMKGbI02NnDtWrQ40hAN558/2vvS4gMpMIxaf6JmD7YjnZbq0Q9TDSSkKBamime8ewRoomHdt4g==", + "peer": true, "dependencies": { "undici-types": "~5.26.4" } @@ -5330,6 +5465,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.12.0.tgz", "integrity": "sha512-7F91fcbuDf/d3S8o21+r3ZncGIke/+eWk0EpO21LXhDfLahriZF9CGj4fbAetEjlaBdjdSm9a6VeXbpbT6Z40Q==", "dev": true, + "peer": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "7.12.0", @@ -5363,6 +5499,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.12.0.tgz", "integrity": "sha512-dm/J2UDY3oV3TKius2OUZIFHsomQmpHtsV0FTh1WO8EKgHLQ1QCADUqscPgTpU+ih1e21FQSRjXckHn3txn6kQ==", "dev": true, + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "7.12.0", "@typescript-eslint/types": "7.12.0", @@ -5766,6 +5903,7 @@ "version": "7.4.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -5846,6 +5984,7 @@ "version": "8.12.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -6879,6 +7018,7 @@ "url": "https://github.com/sponsors/ai" } ], + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001587", "electron-to-chromium": "^1.4.668", @@ -7158,6 +7298,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "peer": true, "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -8361,15 +8502,6 @@ "url": "https://github.com/yeoman/update-notifier?sponsor=1" } }, - "node_modules/cytoscape": { - "version": "3.29.2", - "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.29.2.tgz", - "integrity": "sha512-2G1ycU28Nh7OHT9rkXRLpCDP30MKH1dXJORZuBhtEhEW7pKwgPi77ImqlCWinouyE1PNepIOGZBOrE84DG7LyQ==", - "optional": true, - "engines": { - "node": ">=0.10" - } - }, "node_modules/cytoscape-cose-bilkent": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz", @@ -8755,15 +8887,6 @@ "node": ">=12" } }, - "node_modules/d3-selection": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", - "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", - "optional": true, - "engines": { - "node": ">=12" - } - }, "node_modules/d3-shape": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", @@ -9982,6 +10105,7 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "dev": true, + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -10052,6 +10176,7 @@ "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", "dev": true, + "peer": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -10488,6 +10613,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", "dev": true, + "peer": true, "dependencies": { "array-includes": "^3.1.7", "array.prototype.findlastindex": "^1.2.3", @@ -14243,6 +14369,7 @@ "resolved": "https://registry.npmjs.org/less/-/less-4.2.0.tgz", "integrity": "sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==", "dev": true, + "peer": true, "dependencies": { "copy-anything": "^2.0.1", "parse-node-version": "^1.0.1", @@ -14668,6 +14795,7 @@ "version": "9.1.6", "resolved": "https://registry.npmjs.org/marked/-/marked-9.1.6.tgz", "integrity": "sha512-jcByLnIFkd5gSXZmjNvS1TlmRhCXZjIzHYlaGkPlLIekG55JDR2Z4va9tZwCiP+/RDERiNhMOFu01xd6O5ct1Q==", + "peer": true, "bin": { "marked": "bin/marked.js" }, @@ -18182,6 +18310,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -19097,6 +19226,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.1.tgz", "integrity": "sha512-xUXwsxNjwTQ8K3GnT4pCJm+xq3RUPQbmkYJTP5aFIfNIvbcc/4MUxgBaaRSZJ6yGJZiGSyYlM6MzwTsRk8SYCg==", "dev": true, + "peer": true, "engines": { "node": ">=12" }, @@ -19373,6 +19503,7 @@ "url": "https://github.com/sponsors/ai" } ], + "peer": true, "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.0.0", @@ -19511,6 +19642,7 @@ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.0.tgz", "integrity": "sha512-J9odKxERhCQ10OC2yb93583f6UnYutOeiV5i0zEDS7UGTdUt0u+y8erxl3lBKvwo/JHyyoEdXjwp4dke9oyZ/g==", "dev": true, + "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -20521,6 +20653,7 @@ "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "peer": true, "dependencies": { "tslib": "^2.1.0" } @@ -20602,6 +20735,7 @@ "resolved": "https://registry.npmjs.org/sass/-/sass-1.71.1.tgz", "integrity": "sha512-wovtnV2PxzteLlfNzbgm1tFXPLoZILYAMJtvoXXkD7/+1uP41eKkIt1ypWq5/q2uT94qHjXehEYfmjKOvjL9sg==", "dev": true, + "peer": true, "dependencies": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", @@ -20728,6 +20862,7 @@ "integrity": "sha512-phCkJ6pjDi9ANdhuF5ElS10GGdAKY6R1Pvt9lT3SFhOwM4T7QZE7MLpBDbNruUx/Q3gFD92/UOFringGipRqZA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@semantic-release/commit-analyzer": "^13.0.0-beta.1", "@semantic-release/error": "^4.0.0", @@ -23573,6 +23708,7 @@ "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -25057,6 +25193,7 @@ "resolved": "https://registry.npmjs.org/terser/-/terser-5.29.1.tgz", "integrity": "sha512-lZQ/fyaIGxsbGxApKmoPTODIzELy3++mXhS5hOqaAWZjQtpq/hFHAc+rm29NND1rYRxRWKcjuARNwULNXa5RtQ==", "dev": true, + "peer": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -25109,6 +25246,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -25716,6 +25854,7 @@ "version": "5.4.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -26123,6 +26262,7 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.7.tgz", "integrity": "sha512-sgnEEFTZYMui/sTlH1/XEnVNHMujOahPLGMxn1+5sIT45Xjng1Ec1K78jRP15dSmVgg5WBin9yO81j3o9OxofA==", "dev": true, + "peer": true, "dependencies": { "esbuild": "^0.19.3", "postcss": "^8.4.35", @@ -26587,6 +26727,15 @@ "node": ">=0.10.0" } }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.1.tgz", + "integrity": "sha512-kdjOSJ2lLIn7r1rtrMbbNCHjyMPfRnowdKjBQ+mGq6NAW5QY2bEZC/khaC5OR8svbbjvLEaIXkOq45e2X9BIbQ==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/watchpack": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", @@ -26637,6 +26786,7 @@ "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.90.3.tgz", "integrity": "sha512-h6uDYlWCctQRuXBs1oYpVe6sFcWedl0dpcVaTf/YF67J9bKvwJajFulMVSYKHrksMB3I/pIagRzDxwxkebuzKA==", "dev": true, + "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^1.0.5", @@ -26712,6 +26862,7 @@ "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz", "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==", "dev": true, + "peer": true, "dependencies": { "@types/bonjour": "^3.5.9", "@types/connect-history-api-fallback": "^1.3.5", @@ -26868,6 +27019,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "dev": true, + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -26889,6 +27041,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -27657,16 +27810,27 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/zod": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, "node_modules/zone.js": { "version": "0.14.6", "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.14.6.tgz", - "integrity": "sha512-vyRNFqofdaHVdWAy7v3Bzmn84a1JHWSjpuTZROT/uYn8I3p2cmo7Ro9twFmYRQDPhiYOV7QLk0hhY4JJQVqS6Q==" + "integrity": "sha512-vyRNFqofdaHVdWAy7v3Bzmn84a1JHWSjpuTZROT/uYn8I3p2cmo7Ro9twFmYRQDPhiYOV7QLk0hhY4JJQVqS6Q==", + "peer": true }, "packages/cli": { "name": "@moaw/cli", - "version": "1.5.1", + "version": "1.5.2", "license": "MIT", "dependencies": { + "@github/copilot-sdk": "^0.1.16", "asciidoctor": "^3.0.2", "browser-sync": "^3.0.2", "debug": "^4.3.4", diff --git a/packages/cli/README.md b/packages/cli/README.md index f863ea0..2aa5174 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -32,6 +32,9 @@ Commands: l, link [] Get link to target file (default: workshop.md) -r, --repo Set GitHub repo instead of fetching it from git -b, --branch Set branch name (default: current branch) + t, translate [] Translate workshop to different languages + -l, --languages Comma-separated list of target languages + -m, --model Copilot model to use (default: gpt-5.2) General options: -v, --version Show version @@ -64,3 +67,19 @@ As MOAW requires specific [frontmatter metadata in the Markdown file](../../temp ``` Note that not all AsciiDoc features are supported, and fall back to HTML generation will be used in that case. You can use the `--verbose` option to see if any unsupported feature is used. + +#### AI-Generated translations + +The `translate` command allows you to translate your workshop to different languages using GitHub Copilot CLI. + +GitHub Copilot CLI must be installed and authenticated before you can use this command (see [installation guide](https://docs.github.com/en/copilot/how-tos/set-up/install-copilot-cli)). + +You can then use AI models from Copilot to translate your workshop. For example, to translate to Spanish and French: + +```bash +moaw translate workshop.md -l es,fr +``` + +> [!NOTE] +> Translation may take some time depending on the size of your workshop and the number of target languages. +> There's a hard timeout of 30 minutes per translation request, so for very large workshops you may need to separate the translation task into multiple commands. diff --git a/packages/cli/package.json b/packages/cli/package.json index 5058be1..490f760 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -38,6 +38,7 @@ "xo": "^0.58.0" }, "dependencies": { + "@github/copilot-sdk": "^0.1.16", "asciidoctor": "^3.0.2", "browser-sync": "^3.0.2", "debug": "^4.3.4", diff --git a/packages/cli/src/cli.ts b/packages/cli/src/cli.ts index fe4f0c2..b34ef22 100644 --- a/packages/cli/src/cli.ts +++ b/packages/cli/src/cli.ts @@ -2,7 +2,7 @@ import process from 'node:process'; import debug from 'debug'; import updateNotifier, { type Package } from 'update-notifier'; import minimist from 'minimist'; -import { convert, createNew, link, serve, build } from './commands/index.js'; +import { convert, createNew, link, serve, build, translate } from './commands/index.js'; import { getPackageJson } from './util.js'; const help = `Usage: moaw [options] @@ -21,6 +21,9 @@ Commands: l, link [] Get link to target file (default: workshop.md) -r, --repo Set GitHub repo instead of fetching it from git -b, --branch Set branch name (default: current branch) + t, translate [] Translate workshop to different languages + -l, --languages Comma-separated list of target languages + -m, --model Copilot model to use (default: gpt-5.2) General options: -v, --version Show version @@ -29,7 +32,7 @@ General options: export async function run(args: string[]) { const options = minimist(args, { - string: ['host', 'attr', 'dest', 'repo', 'branch'], + string: ['host', 'attr', 'dest', 'repo', 'branch', 'languages', 'model'], boolean: ['verbose', 'version', 'help', 'open'], alias: { v: 'version', @@ -39,7 +42,9 @@ export async function run(args: string[]) { a: 'attr', d: 'dest', r: 'repo', - b: 'branch' + b: 'branch', + l: 'languages', + m: 'model' } }); @@ -112,6 +117,17 @@ export async function run(args: string[]) { break; } + case 't': + case 'translate': { + await translate({ + file: parameters[0], + languages: options.languages as string, + model: options.model as string, + verbose: Boolean(options.verbose) + }); + break; + } + default: { if (command) { console.error(`Unknown command: ${command}`); diff --git a/packages/cli/src/commands/build.ts b/packages/cli/src/commands/build.ts index 822642a..cc909f2 100644 --- a/packages/cli/src/commands/build.ts +++ b/packages/cli/src/commands/build.ts @@ -2,7 +2,7 @@ import fs from 'node:fs/promises'; import process from 'node:process'; import { dirname, parse } from 'node:path'; import createDebug from 'debug'; -import { pathExists, readJson } from '../util.js'; +import { pathExists } from '../util.js'; import { defaultWorkshopFile } from '../constants.js'; import { processFileIncludes } from '../include.js'; diff --git a/packages/cli/src/commands/index.ts b/packages/cli/src/commands/index.ts index b689144..45eb4fc 100644 --- a/packages/cli/src/commands/index.ts +++ b/packages/cli/src/commands/index.ts @@ -3,3 +3,4 @@ export * from './build.js'; export * from './serve.js'; export * from './convert.js'; export * from './link.js'; +export * from './translate.js'; diff --git a/packages/cli/src/commands/translate.ts b/packages/cli/src/commands/translate.ts new file mode 100644 index 0000000..d4ae288 --- /dev/null +++ b/packages/cli/src/commands/translate.ts @@ -0,0 +1,105 @@ +import process from 'node:process'; +import createDebug from 'debug'; +import { CopilotClient } from '@github/copilot-sdk'; +import { pathExists } from '../util.js'; +import { defaultWorkshopFile } from '../constants.js'; + +const debug = createDebug('translate'); +const translationsFolder = 'translations'; + +const translatePrompt = (file: string, languages: string) => `## Role +You are an expert translator for technical documents. Your task is to translate the provided workshop content into the specified target language while preserving the original formatting, code snippets, and technical terminology. Ensure that the translated content is complete, clear, accurate, and maintains the instructional tone of the original text. + +## Task +1. Translate the workshop file \`${file}\` in languages: \`${languages}\`. +2. Create one translated file per language. Each new translated file must be created as \`${translationsFolder}/..md\`. +3. Return the list of created files without any additional explanation. + +## Instructions +- Preserve ALL markdown, HTML and frontmatter formatting, including headings, lists, links, and code blocks. +- Update the paths in any relative links or image references to point to the correct locations in the translated file. +- Keep technical terms and code snippets unchanged. +- Keep frontmatter metadata properties names unchanged. Only translate titles and descriptions in the frontmatter. +`; + +export type TranslateOptions = { + file?: string; + languages?: string; + model?: string; + verbose?: boolean; +}; + +export async function translate(options: TranslateOptions = {}): Promise { + try { + options.file = options.file?.trim() || defaultWorkshopFile; + options.model = options.model?.trim() || 'gpt-5.2'; + debug('Options %o', options); + + const { file, model, languages } = options; + if (!languages) { + throw new Error('No target languages specified. Use the --languages option to specify target languages.'); + } + + if (!(await pathExists(file))) { + throw new Error(`File not found: ${file}`); + } + + const startTime = Date.now(); + const client = new CopilotClient(); + try { + await client.start(); + const session = await client.createSession({ model }); + const auth = await client.getAuthStatus(); + if (!auth.isAuthenticated) { + throw new Error( + 'GitHub Copilot CLI is not authenticated.\nPlease run "copilot" and use "/login" to authenticate.' + ); + } + + debug('Connected to GitHub Copilot CLI'); + console.info(`Started translation agent for file "${file}" to languages: ${languages}...`); + + session.on((event) => { + if (event.type === 'assistant.message') { + debug(`Copilot: ${event.data.content}`); + } + }); + + const response = await session.sendAndWait( + { + prompt: translatePrompt(file, languages), + attachments: [{ type: 'file', path: file }] + }, + 30 * 60 * 1000 // 30 minutes timeout + ); + + const elapsed = (Date.now() - startTime) / 1000; + const timeStr = elapsed > 60 ? `${(elapsed / 60).toFixed(1)}m` : `${elapsed.toFixed(1)}s`; + console.info(`Translation agent task completed in ${timeStr}:`); + console.log(response?.data.content); + + await session.destroy(); + debug('Copilot CLI session destroyed'); + } catch (error: unknown) { + const error_ = error as Error; + if (error_.message?.includes('ENOENT')) { + throw new Error( + `GitHub Copilot CLI is not installed.\nSee https://docs.github.com/copilot/how-tos/set-up/install-copilot-cli for installation instructions.` + ); + } + + throw error_; + } finally { + await client.stop(); + debug('Copilot CLI client stopped'); + } + + // Temp workaround to avoid process hanging + // eslint-disable-next-line unicorn/no-process-exit + process.exit(); + } catch (error: unknown) { + const error_ = error as Error; + console.error(error_.message); + process.exitCode = 1; + } +} diff --git a/packages/cli/tsconfig.json b/packages/cli/tsconfig.json index e32604c..776dad6 100644 --- a/packages/cli/tsconfig.json +++ b/packages/cli/tsconfig.json @@ -10,7 +10,8 @@ "strict": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "resolveJsonModule": true + "resolveJsonModule": true, + "skipLibCheck": true }, "include": ["./src"] }