diff --git a/.gitignore b/.gitignore index df59bca..b946f9f 100644 --- a/.gitignore +++ b/.gitignore @@ -61,3 +61,6 @@ exportBackup .tago-lock.dev-ue.lock .tago-lock.dev-ue-2.lock .tago-lock.dev-1.lock + +# generated by `npm run man` and shipped via the `files` field at publish time +man/ diff --git a/README.md b/README.md index 073283f..d073068 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,8 @@ Installing the TagoIO Command Line Tools is a straightforward process. Follow th tagoio login ``` +6. **Reference (Optional)**: A man page is installed alongside the CLI. Run `man tagoio` for the full command reference. Fish users can additionally run `fish_update_completions` to enable tab-completion (fish auto-extracts flag metadata from the installed man page). + ## Command List List of commands of the CLI **Usage**: diff --git a/package-lock.json b/package-lock.json index 83667ed..15ed6ad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,8 +33,8 @@ "@types/prompts": "^2.4.9", "@types/unzipper": "^0.10.11", "@vitest/coverage-v8": "^4.1.5", - "oxfmt": "^0.46.0", - "oxlint": "1.61.0", + "oxfmt": "^0.47.0", + "oxlint": "1.62.0", "typescript": "^6.0.3", "vitest": "^4.1.5" }, @@ -104,9 +104,9 @@ } }, "node_modules/@emnapi/core": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.2.tgz", - "integrity": "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", "dev": true, "license": "MIT", "optional": true, @@ -116,9 +116,9 @@ } }, "node_modules/@emnapi/runtime": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz", - "integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", "dev": true, "license": "MIT", "optional": true, @@ -601,9 +601,9 @@ } }, "node_modules/@oxc-project/types": { - "version": "0.126.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.126.0.tgz", - "integrity": "sha512-oGfVtjAgwQVVpfBrbtk4e1XDyWHRFta6BS3GWVzrF8xYBT2VGQAk39yJS/wFSMrZqoiCU4oghT3Ch0HaHGIHcQ==", + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.127.0.tgz", + "integrity": "sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==", "dev": true, "license": "MIT", "funding": { @@ -611,9 +611,9 @@ } }, "node_modules/@oxfmt/binding-android-arm-eabi": { - "version": "0.46.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-android-arm-eabi/-/binding-android-arm-eabi-0.46.0.tgz", - "integrity": "sha512-b1doV4WRcJU+BESSlCvCjV+5CEr/T6h0frArAdV26Nir+gGNFNaylvDiiMPfF1pxeV0txZEs38ojzJaxBYg+ng==", + "version": "0.47.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-android-arm-eabi/-/binding-android-arm-eabi-0.47.0.tgz", + "integrity": "sha512-KrMQRdMi/upr81qT4ijK6X6BNp6jqpMY7FwILQnwIy9QLc3qpnhUx5rsCLGzn4ewsCQ0CNAspN2ogmP1GXLyLw==", "cpu": [ "arm" ], @@ -628,9 +628,9 @@ } }, "node_modules/@oxfmt/binding-android-arm64": { - "version": "0.46.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-android-arm64/-/binding-android-arm64-0.46.0.tgz", - "integrity": "sha512-v6+HhjsoV3GO0u2u9jLSAZrvWfTraDxKofUIQ7/ktS7tzS+epVsxdHmeM+XxuNcAY/nWxxU1Sg4JcGTNRXraBA==", + "version": "0.47.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-android-arm64/-/binding-android-arm64-0.47.0.tgz", + "integrity": "sha512-r4ixS/PeUpAFKgrpDoZ5pSkthjZzVzKd95525Aazj+aOv9H4ulK5zYHGb7wFY5n5kZxHK8TbOJUZgoEb1ohddQ==", "cpu": [ "arm64" ], @@ -645,9 +645,9 @@ } }, "node_modules/@oxfmt/binding-darwin-arm64": { - "version": "0.46.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-darwin-arm64/-/binding-darwin-arm64-0.46.0.tgz", - "integrity": "sha512-3eeooJGrqGIlI5MyryDZsAcKXSmKIgAD4yYtfRrRJzXZ0UTFZtiSveIur56YPrGMYZwT4XyVhHsMqrNwr1XeFA==", + "version": "0.47.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-darwin-arm64/-/binding-darwin-arm64-0.47.0.tgz", + "integrity": "sha512-CLWxiKpMl+195cm09CuaWEhJK0CirRkoMa07aR9+9AFPat2LfIKtwx1JqxZM0MTvcMe6+adlJNdVL6jdInvq3g==", "cpu": [ "arm64" ], @@ -662,9 +662,9 @@ } }, "node_modules/@oxfmt/binding-darwin-x64": { - "version": "0.46.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-darwin-x64/-/binding-darwin-x64-0.46.0.tgz", - "integrity": "sha512-QG8BDM0CXWbu84k2SKmCqfEddPQPFiBicwtYnLqHRWZZl57HbtOLRMac/KTq2NO4AEc4ICCBpFxJIV9zcqYfkQ==", + "version": "0.47.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-darwin-x64/-/binding-darwin-x64-0.47.0.tgz", + "integrity": "sha512-Xq5fjTYDC50faUeLSm0rZdBqoTgleXEdD7NpJdARtQIczkCJn3xNjMUSQQkUmh4CtxkKTNL68lytcOK3e/osgg==", "cpu": [ "x64" ], @@ -679,9 +679,9 @@ } }, "node_modules/@oxfmt/binding-freebsd-x64": { - "version": "0.46.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-freebsd-x64/-/binding-freebsd-x64-0.46.0.tgz", - "integrity": "sha512-9DdCqS/n2ncu/Chazvt3cpgAjAmIGQDz7hFKSrNItMApyV/Ja9mz3hD4JakIE3nS8PW9smEbPWnb389QLBY4nw==", + "version": "0.47.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-freebsd-x64/-/binding-freebsd-x64-0.47.0.tgz", + "integrity": "sha512-QOU9ZIJ52p5askcEC0QJvvr8trHAWoonul8bgISo6gYUL3s50zkqafBYcNAr9LJZQbsZtPfIWHk9+5+nUp1qJQ==", "cpu": [ "x64" ], @@ -696,9 +696,9 @@ } }, "node_modules/@oxfmt/binding-linux-arm-gnueabihf": { - "version": "0.46.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.46.0.tgz", - "integrity": "sha512-Dgs7VeE2jT0LHMhw6tPEt0xQYe54kBqHEovmWsv4FVQlegCOvlIJNx0S8n4vj8WUtpT+Z6BD2HhKJPLglLxvZg==", + "version": "0.47.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.47.0.tgz", + "integrity": "sha512-oJxDM1aBhPvz9gmElBv8UpxyiqhwfjcbrSxT5F0xtuUzY6dQI27/AQPIt3eu3Z5Yvn0kQl5R7MA3Z+MbnRvCBw==", "cpu": [ "arm" ], @@ -713,9 +713,9 @@ } }, "node_modules/@oxfmt/binding-linux-arm-musleabihf": { - "version": "0.46.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.46.0.tgz", - "integrity": "sha512-Zxn3adhTH13JKnU4xXJj8FeEfF680XjXh3gSShKl57HCMBRde2tUJTgogV/1MSHA80PJEVrDa7r66TLVq3Ia7Q==", + "version": "0.47.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.47.0.tgz", + "integrity": "sha512-g8Lh50VS4ibGz2q6v7r9UZY4D0dM16SdrFYOMzhqIoCwGcai8VMIRUAcqn1/jlCsOOzUXJ741+kCeJt0cofakQ==", "cpu": [ "arm" ], @@ -730,13 +730,16 @@ } }, "node_modules/@oxfmt/binding-linux-arm64-gnu": { - "version": "0.46.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.46.0.tgz", - "integrity": "sha512-+TWipjrgVM8D7aIdDD0tlr3teLTTvQTn7QTE5BpT10H1Fj82gfdn9X6nn2sDgx/MepuSCfSnzFNJq2paLL0OiA==", + "version": "0.47.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.47.0.tgz", + "integrity": "sha512-YrNT1vQ0asaXoRbrvYENPqmBfOQ9Xr8enPNOULeYfg44VjCcrUowFy5QZr+WawE0zyP8cH9e9Gxxg0fDEFzhcg==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -747,13 +750,16 @@ } }, "node_modules/@oxfmt/binding-linux-arm64-musl": { - "version": "0.46.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.46.0.tgz", - "integrity": "sha512-aAUPBWJ1lGwwnxZUEDLJ94+Iy6MuwJwPxUgO4sCA5mEEyDk7b+cDQ+JpX1VR150Zoyd+D49gsrUzpUK5h587Eg==", + "version": "0.47.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.47.0.tgz", + "integrity": "sha512-IxtQC/sbBi4ubbY+MdwdanRWrG9InQJVZqyMsBa5IUaQcnSg86gQme574HxXMC1p4bo4YhV99zQ+wNnGCvEgzw==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -764,13 +770,16 @@ } }, "node_modules/@oxfmt/binding-linux-ppc64-gnu": { - "version": "0.46.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.46.0.tgz", - "integrity": "sha512-ufBCJukyFX/UDrokP/r6BGDoTInnsDs7bxyzKAgMiZlt2Qu8GPJSJ6Zm6whIiJzKk0naxA8ilwmbO1LMw6Htxw==", + "version": "0.47.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.47.0.tgz", + "integrity": "sha512-EWXEhOMbWO0q6eJSbu0QLkU8cKi0ljlYLngeDs2Ocu/pm1rrLwyQiYzlFbdnMRURI4w9ndr1sI9rSbhlJ5o23Q==", "cpu": [ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -781,13 +790,16 @@ } }, "node_modules/@oxfmt/binding-linux-riscv64-gnu": { - "version": "0.46.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.46.0.tgz", - "integrity": "sha512-eqtlC2YmPqjun76R1gVfGLuKWx7NuEnLEAudZ7n6ipSKbCZTqIKSs1b5Y8K/JHZsRpLkeSmAAjig5HOIg8fQzQ==", + "version": "0.47.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.47.0.tgz", + "integrity": "sha512-tZrjS11TUiDuEpRaqdk8K9F9xETRyKXfuZKmdeW+Gj7coBnm7+8sBEfyt033EAFEQSlkniAXvBLh+Qja2ioGBQ==", "cpu": [ "riscv64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -798,13 +810,16 @@ } }, "node_modules/@oxfmt/binding-linux-riscv64-musl": { - "version": "0.46.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.46.0.tgz", - "integrity": "sha512-yccVOO2nMXkQLGgy0He3EQEwKD7NF0zEk+/OWmroznkqXyJdN6bfK0LtNnr6/14Bh3FjpYq7bP33l/VloCnxpA==", + "version": "0.47.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.47.0.tgz", + "integrity": "sha512-KBFy+2CFKUCZzYwX2ZOPQKck1vjQbz+hextuc19G4r0WRJwadfAeuQMQRQvB+Ivc8brlbOVg7et8K7E467440g==", "cpu": [ "riscv64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -815,13 +830,16 @@ } }, "node_modules/@oxfmt/binding-linux-s390x-gnu": { - "version": "0.46.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.46.0.tgz", - "integrity": "sha512-aAf7fG23OQCey6VRPj9IeCraoYtpgtx0ZyJ1CXkPyT1wjzBE7c3xtuxHe/AdHaJfVVb/SXpSk8Gl1LzyQupSqw==", + "version": "0.47.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.47.0.tgz", + "integrity": "sha512-REUPFKVGSiK99B+9eaPhluEVglzaoj/SMykNC5SUiV2RSsBfV5lWN7Y0iCIc251Wz3GaeAGZsJ/zj3gjarxdFg==", "cpu": [ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -832,13 +850,16 @@ } }, "node_modules/@oxfmt/binding-linux-x64-gnu": { - "version": "0.46.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.46.0.tgz", - "integrity": "sha512-q0JPsTMyJNjYrBvYFDz4WbVsafNZaPCZv4RnFypRotLqpKROtBZcEaXQW4eb9YmvLU3NckVemLJnzkSZSdmOxw==", + "version": "0.47.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.47.0.tgz", + "integrity": "sha512-KVftVSVEDeIfRW3TIeLe3aNI/iY4m1fu5mDwHcisKMZSCMKLkrhFsjowC7o9RoqNPxbbglm2+/6KAKBIts2t0Q==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -849,13 +870,16 @@ } }, "node_modules/@oxfmt/binding-linux-x64-musl": { - "version": "0.46.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-x64-musl/-/binding-linux-x64-musl-0.46.0.tgz", - "integrity": "sha512-7LsLY9Cw57GPkhSR+duI3mt9baRczK/DtHYSldQ4BEU92da9igBQNl4z7Vq5U9NNPsh1FmpKvv1q9WDtiUQR1A==", + "version": "0.47.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-x64-musl/-/binding-linux-x64-musl-0.47.0.tgz", + "integrity": "sha512-DTsmGEaA2860Aq5VUyDO8/MT9NFxwVL93RnRYmpMwK6DsSkThmvEpqoUDDljziEpAedMRG19SCogrNbINSbLUQ==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -866,9 +890,9 @@ } }, "node_modules/@oxfmt/binding-openharmony-arm64": { - "version": "0.46.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-openharmony-arm64/-/binding-openharmony-arm64-0.46.0.tgz", - "integrity": "sha512-lHiBOz8Duaku7JtRNLlps3j++eOaICPZSd8FCVmTDM4DFOPT71Bjn7g6iar1z7StXlKRweUKxWUs4sA+zWGDXg==", + "version": "0.47.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-openharmony-arm64/-/binding-openharmony-arm64-0.47.0.tgz", + "integrity": "sha512-8r5BDro7fLOBoq1JXHLVSs55OlrxQhEso4HVo0TcY7OXJUPYfjPoOaYL5us+yIwqyP9rQwN+rxuiNFSmaxSuOQ==", "cpu": [ "arm64" ], @@ -883,9 +907,9 @@ } }, "node_modules/@oxfmt/binding-win32-arm64-msvc": { - "version": "0.46.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.46.0.tgz", - "integrity": "sha512-/5ktYUliP89RhgC37DBH1x20U5zPSZMy3cMEcO0j3793rbHP9MWsknBwQB6eozRzWmYrh0IFM/p20EbPvDlYlg==", + "version": "0.47.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.47.0.tgz", + "integrity": "sha512-qtz/gzm8IjSPUlseZ0ofW8zyHLoZsuP5HTfcGGkWkUblB89JT8GNYH3ICqjbDsqsGqXum0/ZndXTFplSdXFIcg==", "cpu": [ "arm64" ], @@ -900,9 +924,9 @@ } }, "node_modules/@oxfmt/binding-win32-ia32-msvc": { - "version": "0.46.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.46.0.tgz", - "integrity": "sha512-3WTnoiuIr8XvV0DIY7SN+1uJSwKf4sPpcbHfobcRT9JutGcLaef/miyBB87jxd3aqH+mS0+G5lsgHuXLUwjjpQ==", + "version": "0.47.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.47.0.tgz", + "integrity": "sha512-5vIcdcIDE7nCx+MXN6sm8kbC4zajDB31E86rez4i45iHNH/2NjdKlJ720xcHTr3eeiMcttCGPHPhE1TjtBDGZw==", "cpu": [ "ia32" ], @@ -917,9 +941,9 @@ } }, "node_modules/@oxfmt/binding-win32-x64-msvc": { - "version": "0.46.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.46.0.tgz", - "integrity": "sha512-IXxiQpkYnOwNfP23vzwSfhdpxJzyiPTY7eTn6dn3DsriKddESzM8i6kfq9R7CD/PUJwCvQT22NgtygBeug3KoA==", + "version": "0.47.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.47.0.tgz", + "integrity": "sha512-Sr59Y5ms54ONBjxFeWhVlGyQcHXxcl9DxC23f6yXlRkcos7LXBLoO+KDfxexjHIOZh7cWqrWduzvUjJ+pHp8cQ==", "cpu": [ "x64" ], @@ -934,9 +958,9 @@ } }, "node_modules/@oxlint/binding-android-arm-eabi": { - "version": "1.61.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-android-arm-eabi/-/binding-android-arm-eabi-1.61.0.tgz", - "integrity": "sha512-6eZBPgiigK5txqoVgRqxbaxiom4lM8AP8CyKPPvpzKnQ3iFRFOIDc+0AapF+qsUSwjOzr5SGk4SxQDpQhkSJMQ==", + "version": "1.62.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-android-arm-eabi/-/binding-android-arm-eabi-1.62.0.tgz", + "integrity": "sha512-pKsthNECyvJh8lPTICz6VcwVy2jOqdhhsp1rlxCkhgZR47aKvXPmaRWQDv+zlXpRae4qm1MaaTnutkaOk5aofg==", "cpu": [ "arm" ], @@ -951,9 +975,9 @@ } }, "node_modules/@oxlint/binding-android-arm64": { - "version": "1.61.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-android-arm64/-/binding-android-arm64-1.61.0.tgz", - "integrity": "sha512-CkwLR69MUnyv5wjzebvbbtTSUwqLxM35CXE79bHqDIK+NtKmPEUpStTcLQRZMCo4MP0qRT6TXIQVpK0ZVScnMA==", + "version": "1.62.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-android-arm64/-/binding-android-arm64-1.62.0.tgz", + "integrity": "sha512-b1AUNViByvgmR2xJDubvLIr+dSuu3uraG7bsAoKo+xrpspPvu6RIn6Fhr2JUhobfep3jwUTy18Huco6GkwdvGQ==", "cpu": [ "arm64" ], @@ -968,9 +992,9 @@ } }, "node_modules/@oxlint/binding-darwin-arm64": { - "version": "1.61.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-darwin-arm64/-/binding-darwin-arm64-1.61.0.tgz", - "integrity": "sha512-8JbefTkbmvqkqWjmQrHke+MdpgT2UghhD/ktM4FOQSpGeCgbMToJEKdl9zwhr/YWTl92i4QI1KiTwVExpcUN8A==", + "version": "1.62.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-darwin-arm64/-/binding-darwin-arm64-1.62.0.tgz", + "integrity": "sha512-iG+Tvf70UJ6otfwFYIHk36Sjq9cpPP5YLxkoggANNRtzgi3Tj3g8q6Ybqi6AtkU3+yg9QwF7bDCkCS6bbL4PCg==", "cpu": [ "arm64" ], @@ -985,9 +1009,9 @@ } }, "node_modules/@oxlint/binding-darwin-x64": { - "version": "1.61.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-darwin-x64/-/binding-darwin-x64-1.61.0.tgz", - "integrity": "sha512-uWpoxDT47hTnDLcdEh5jVbso8rlTTu5o0zuqa9J8E0JAKmIWn7kGFEIB03Pycn2hd2vKxybPGLhjURy/9We5FQ==", + "version": "1.62.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-darwin-x64/-/binding-darwin-x64-1.62.0.tgz", + "integrity": "sha512-oOWI6YPPr5AJUx+yIDlxmuUbQjS5gZX3OH3QisawYvsZgLiQVvZtR0rPBcJTxLWqt2ClrWg0DlSrlUiG5SQNHg==", "cpu": [ "x64" ], @@ -1002,9 +1026,9 @@ } }, "node_modules/@oxlint/binding-freebsd-x64": { - "version": "1.61.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-freebsd-x64/-/binding-freebsd-x64-1.61.0.tgz", - "integrity": "sha512-K/o4hEyW7flfMel0iBVznmMBt7VIMHGdjADocHKpK1DUF9erpWnJ+BSSWd2W0c8K3mPtpph+CuHzRU6CI3l9jQ==", + "version": "1.62.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-freebsd-x64/-/binding-freebsd-x64-1.62.0.tgz", + "integrity": "sha512-dLP33T7VLCmLVv4cvjkVX+rmkcwNk2UfxmsZPNur/7BQHoQR60zJ7XLiRvNUawlzn0u8ngCa3itjEG73MAMa/w==", "cpu": [ "x64" ], @@ -1019,9 +1043,9 @@ } }, "node_modules/@oxlint/binding-linux-arm-gnueabihf": { - "version": "1.61.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.61.0.tgz", - "integrity": "sha512-P6040ZkcyweJ0Po9yEFqJCdvZnf3VNCGs1SIHgXDf8AAQNC6ID/heXQs9iSgo2FH7gKaKq32VWc59XZwL34C5Q==", + "version": "1.62.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.62.0.tgz", + "integrity": "sha512-fl//LWNks6qo9chNY60UDYyIwtp7a5cEx4Y/rHPjaarhuwqx6jtbzEpD5V5AqmdL4a6Y5D8zeXg5HF2Cr0QmSQ==", "cpu": [ "arm" ], @@ -1036,9 +1060,9 @@ } }, "node_modules/@oxlint/binding-linux-arm-musleabihf": { - "version": "1.61.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-1.61.0.tgz", - "integrity": "sha512-bwxrGCzTZkuB+THv2TQ1aTkVEfv5oz8sl+0XZZCpoYzErJD8OhPQOTA0ENPd1zJz8QsVdSzSrS2umKtPq4/JXg==", + "version": "1.62.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-1.62.0.tgz", + "integrity": "sha512-i5vkAuxvueTODV3J2dL61/TXewDHhMFKvtD156cIsk7GsdfiAu7zW7kY0NJXhKeFHeiMZIh7eFNjkPYH6J47HQ==", "cpu": [ "arm" ], @@ -1053,13 +1077,16 @@ } }, "node_modules/@oxlint/binding-linux-arm64-gnu": { - "version": "1.61.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.61.0.tgz", - "integrity": "sha512-vkhb9/wKguMkLlrm3FoJW/Xmdv31GgYAE+x8lxxQ+7HeOxXUySI0q36a3NTVIuQUdLzxCI1zzMGsk1o37FOe3w==", + "version": "1.62.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.62.0.tgz", + "integrity": "sha512-QwN19LLuIGuOjEflSeJkZmOTfBdBMlTmW8xbMf8TZhjd//cxVNYQPq75q7oKZBJc6hRx3gY7sX0Egc8cEIFZYg==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1070,13 +1097,16 @@ } }, "node_modules/@oxlint/binding-linux-arm64-musl": { - "version": "1.61.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.61.0.tgz", - "integrity": "sha512-bl1dQh8LnVqsj6oOQAcxwbuOmNJkwc4p6o//HTBZhNTzJy21TLDwAviMqUFNUxDHkPGpmdKTSN4tWTjLryP8xg==", + "version": "1.62.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.62.0.tgz", + "integrity": "sha512-8eCy3FCDuWUM5hWujAv6heMvfZPbcCOU3SdQUAkixZLu5bSzOkNfirJiLGoQFO943xceOKkiQRMQNzH++jM3WA==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -1087,13 +1117,16 @@ } }, "node_modules/@oxlint/binding-linux-ppc64-gnu": { - "version": "1.61.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.61.0.tgz", - "integrity": "sha512-QoOX6KB2IiEpyOj/HKqaxi+NQHPnOgNgnr22n9N4ANJCzXkUlj1UmeAbFb4PpqdlHIzvGDM5xZ0OKtcLq9RhiQ==", + "version": "1.62.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.62.0.tgz", + "integrity": "sha512-NjQ7K7tpTPDe9J+yq8p/s/J0E7lRCkK2uDBDqvT4XIT6f4Z0tlnr59OBg/WcrmVHER1AbrcfyxhGTXgcG8ytWg==", "cpu": [ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1104,13 +1137,16 @@ } }, "node_modules/@oxlint/binding-linux-riscv64-gnu": { - "version": "1.61.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-1.61.0.tgz", - "integrity": "sha512-1TGcTerjY6p152wCof3oKElccq3xHljS/Mucp04gV/4ATpP6nO7YNnp7opEg6SHkv2a57/b4b8Ndm9znJ1/qAw==", + "version": "1.62.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-1.62.0.tgz", + "integrity": "sha512-oKZed9gmSwze29dEt3/Wnsv6l/Ygw/FUst+8Kfpv2SGeS/glEoTGZAMQw37SVyzFV76UTHJN2snGgxK2t2+8ow==", "cpu": [ "riscv64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1121,13 +1157,16 @@ } }, "node_modules/@oxlint/binding-linux-riscv64-musl": { - "version": "1.61.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-1.61.0.tgz", - "integrity": "sha512-65wXEmZIrX2ADwC8i/qFL4EWLSbeuBpAm3suuX1vu4IQkKd+wLT/HU/BOl84kp91u2SxPkPDyQgu4yrqp8vwVA==", + "version": "1.62.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-1.62.0.tgz", + "integrity": "sha512-gBjBxQ+9lGpAYq+ELqw0w8QXsBnkZclFc7GRX2r0LnEVn3ZTEqeIKpKcGjucmp76Q53bvJD0i4qBWBhcfhSfGA==", "cpu": [ "riscv64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -1138,13 +1177,16 @@ } }, "node_modules/@oxlint/binding-linux-s390x-gnu": { - "version": "1.61.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.61.0.tgz", - "integrity": "sha512-TVvhgMvor7Qa6COeXxCJ7ENOM+lcAOGsQ0iUdPSCv2hxb9qSHLQ4XF1h50S6RE1gBOJ0WV3rNukg4JJJP1LWRA==", + "version": "1.62.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.62.0.tgz", + "integrity": "sha512-Ew2Kxs9EQ9/mbAIJ2hvocMC0wsOu6YKzStI2eFBDt+Td5O8seVC/oxgRIHqCcl5sf5ratA1nozQBAuv7tphkHg==", "cpu": [ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1155,13 +1197,16 @@ } }, "node_modules/@oxlint/binding-linux-x64-gnu": { - "version": "1.61.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.61.0.tgz", - "integrity": "sha512-SjpS5uYuFoDnDdZPwZE59ndF95AsY47R5MliuneTWR1pDm2CxGJaYXbKULI71t5TVfLQUWmrHEGRL9xvuq6dnA==", + "version": "1.62.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.62.0.tgz", + "integrity": "sha512-5z25jcAA0gfKyVwz71A0VXgaPlocPoTAxhlv/hgoK6tlCrfoNuw7haWbDHvGMfjXhdic4EqVXGRv5XsTqFnbRQ==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1172,13 +1217,16 @@ } }, "node_modules/@oxlint/binding-linux-x64-musl": { - "version": "1.61.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-x64-musl/-/binding-linux-x64-musl-1.61.0.tgz", - "integrity": "sha512-gGfAeGD4sNJGILZbc/yKcIimO9wQnPMoYp9swAaKeEtwsSQAbU+rsdQze5SBtIP6j0QDzeYd4XSSUCRCF+LIeQ==", + "version": "1.62.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-x64-musl/-/binding-linux-x64-musl-1.62.0.tgz", + "integrity": "sha512-IWpHmMB6ZDllPvqWDkG6AmXrN7JF5e/c4g/0PuURsmlK+vHoYZPB70rr4u1bn3I4LsKCSpqqfveyx6UCOC8wdg==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -1189,9 +1237,9 @@ } }, "node_modules/@oxlint/binding-openharmony-arm64": { - "version": "1.61.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-openharmony-arm64/-/binding-openharmony-arm64-1.61.0.tgz", - "integrity": "sha512-OlVT0LrG/ct33EVtWRyR+B/othwmDWeRxfi13wUdPeb3lAT5TgTcFDcfLfarZtzB4W1nWF/zICMgYdkggX2WmQ==", + "version": "1.62.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-openharmony-arm64/-/binding-openharmony-arm64-1.62.0.tgz", + "integrity": "sha512-fjlSxxrD5pA594vkyikCS9MnPRjQawW6/BLgyTYkO+73wwPlYjkcZ7LSd974l0Q2zkHQmu4DPvJFLYA7o8xrxQ==", "cpu": [ "arm64" ], @@ -1206,9 +1254,9 @@ } }, "node_modules/@oxlint/binding-win32-arm64-msvc": { - "version": "1.61.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.61.0.tgz", - "integrity": "sha512-vI//NZPJk6DToiovPtaiwD4iQ7kO1r5ReWQD0sOOyKRtP3E2f6jxin4uvwi3OvDzHA2EFfd7DcZl5dtkQh7g1w==", + "version": "1.62.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.62.0.tgz", + "integrity": "sha512-EiFXr8loNS0Ul3Gu80+9nr1T8jRmnKocqmHHg16tj5ZqTgUXyb97l2rrspVHdDluyFn9JfR4PoJFdNzw4paHww==", "cpu": [ "arm64" ], @@ -1223,9 +1271,9 @@ } }, "node_modules/@oxlint/binding-win32-ia32-msvc": { - "version": "1.61.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.61.0.tgz", - "integrity": "sha512-0ySj4/4zd2XjePs3XAQq7IigIstN4LPQZgCyigX5/ERMLjdWAJfnxcTsrtxZxuij8guJW8foXuHmhGxW0H4dDA==", + "version": "1.62.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.62.0.tgz", + "integrity": "sha512-IgOFvL73li1bFgab+hThXYA0N2Xms2kV2MvZN95cebV+fmrZ9AVui1JSxfeeqRLo3CpPxKZlzhyq4G0cnaAvIw==", "cpu": [ "ia32" ], @@ -1240,9 +1288,9 @@ } }, "node_modules/@oxlint/binding-win32-x64-msvc": { - "version": "1.61.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.61.0.tgz", - "integrity": "sha512-0xgSiyeqDLDZxXoe9CVJrOx3TUVsfyoOY7cNi03JbItNcC9WCZqrSNdrAbHONxhSPaVh/lzfnDcON1RqSUMhHw==", + "version": "1.62.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.62.0.tgz", + "integrity": "sha512-6hMpyDWQ2zGA1OXFKBrdYMUveUCO8UJhkO6JdwZPd78xIdHZNhjx+pib+4fC2Cljuhjyl0QwA2F3df/bs4Bp6A==", "cpu": [ "x64" ], @@ -1257,9 +1305,9 @@ } }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.0-rc.16", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.16.tgz", - "integrity": "sha512-rhY3k7Bsae9qQfOtph2Pm2jZEA+s8Gmjoz4hhmx70K9iMQ/ddeae+xhRQcM5IuVx5ry1+bGfkvMn7D6MJggVSA==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.17.tgz", + "integrity": "sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ==", "cpu": [ "arm64" ], @@ -1274,9 +1322,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.0-rc.16", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.16.tgz", - "integrity": "sha512-rNz0yK078yrNn3DrdgN+PKiMOW8HfQ92jQiXxwX8yW899ayV00MLVdaCNeVBhG/TbH3ouYVObo8/yrkiectkcQ==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.17.tgz", + "integrity": "sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw==", "cpu": [ "arm64" ], @@ -1291,9 +1339,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.0-rc.16", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.16.tgz", - "integrity": "sha512-r/OmdR00HmD4i79Z//xO06uEPOq5hRXdhw7nzkxQxwSavs3PSHa1ijntdpOiZ2mzOQ3fVVu8C1M19FoNM+dMUQ==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.17.tgz", + "integrity": "sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw==", "cpu": [ "x64" ], @@ -1308,9 +1356,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.0-rc.16", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.16.tgz", - "integrity": "sha512-KcRE5w8h0OnjUatG8pldyD14/CQ5Phs1oxfR+3pKDjboHRo9+MkqQaiIZlZRpsxC15paeXme/I127tUa9TXJ6g==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.17.tgz", + "integrity": "sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw==", "cpu": [ "x64" ], @@ -1325,9 +1373,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0-rc.16", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.16.tgz", - "integrity": "sha512-bT0guA1bpxEJ/ZhTRniQf7rNF8ybvXOuWbNIeLABaV5NGjx4EtOWBTSRGWFU9ZWVkPOZ+HNFP8RMcBokBiZ0Kg==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.17.tgz", + "integrity": "sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ==", "cpu": [ "arm" ], @@ -1342,13 +1390,16 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0-rc.16", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.16.tgz", - "integrity": "sha512-+tHktCHWV8BDQSjemUqm/Jl/TPk3QObCTIjmdDy/nlupcujZghmKK2962LYrqFpWu+ai01AN/REOH3NEpqvYQg==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1359,13 +1410,16 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0-rc.16", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.16.tgz", - "integrity": "sha512-3fPzdREH806oRLxpTWW1Gt4tQHs0TitZFOECB2xzCFLPKnSOy90gwA7P29cksYilFO6XVRY1kzga0cL2nRjKPg==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.17.tgz", + "integrity": "sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -1376,13 +1430,16 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.0-rc.16", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.16.tgz", - "integrity": "sha512-EKwI1tSrLs7YVw+JPJT/G2dJQ1jl9qlTTTEG0V2Ok/RdOenRfBw2PQdLPyjhIu58ocdBfP7vIRN/pvMsPxs/AQ==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==", "cpu": [ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1393,13 +1450,16 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.0-rc.16", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.16.tgz", - "integrity": "sha512-Uknladnb3Sxqu6SEcqBldQyJUpk8NleooZEc0MbRBJ4inEhRYWZX0NJu12vNf2mqAq7gsofAxHrGghiUYjhaLQ==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==", "cpu": [ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1410,13 +1470,16 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.0-rc.16", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.16.tgz", - "integrity": "sha512-FIb8+uG49sZBtLTn+zt1AJ20TqVcqWeSIyoVt0or7uAWesgKaHbiBh6OpA/k9v0LTt+PTrb1Lao133kP4uVxkg==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1427,13 +1490,16 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.0-rc.16", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.16.tgz", - "integrity": "sha512-RuERhF9/EgWxZEXYWCOaViUWHIboceK4/ivdtQ3R0T44NjLkIIlGIAVAuCddFxsZ7vnRHtNQUrt2vR2n2slB2w==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.17.tgz", + "integrity": "sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -1444,9 +1510,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.0-rc.16", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.16.tgz", - "integrity": "sha512-mXcXnvd9GpazCxeUCCnZ2+YF7nut+ZOEbE4GtaiPtyY6AkhZWbK70y1KK3j+RDhjVq5+U8FySkKRb/+w0EeUwA==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.17.tgz", + "integrity": "sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==", "cpu": [ "arm64" ], @@ -1461,9 +1527,9 @@ } }, "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.0-rc.16", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.16.tgz", - "integrity": "sha512-3Q2KQxnC8IJOLqXmUMoYwyIPZU9hzRbnHaoV3Euz+VVnjZKcY8ktnNP8T9R4/GGQtb27C/UYKABxesKWb8lsvQ==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.17.tgz", + "integrity": "sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA==", "cpu": [ "wasm32" ], @@ -1471,8 +1537,8 @@ "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "1.9.2", - "@emnapi/runtime": "1.9.2", + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", "@napi-rs/wasm-runtime": "^1.1.4" }, "engines": { @@ -1480,9 +1546,9 @@ } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.0-rc.16", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.16.tgz", - "integrity": "sha512-tj7XRemQcOcFwv7qhpUxMTBbI5mWMlE4c1Omhg5+h8GuLXzyj8HviYgR+bB2DMDgRqUE+jiDleqSCRjx4aYk/Q==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.17.tgz", + "integrity": "sha512-gUmyzBl3SPMa6hrqFUth9sVfcLBlYsbMzBx5PlexMroZStgzGqlZ26pYG89rBb45Mnia+oil6YAIFeEWGWhoZA==", "cpu": [ "arm64" ], @@ -1497,9 +1563,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0-rc.16", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.16.tgz", - "integrity": "sha512-PH5DRZT+F4f2PTXRXR8uJxnBq2po/xFtddyabTJVJs/ZYVHqXPEgNIr35IHTEa6bpa0Q8Awg+ymkTaGnKITw4g==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.17.tgz", + "integrity": "sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg==", "cpu": [ "x64" ], @@ -1514,9 +1580,9 @@ } }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.16", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.16.tgz", - "integrity": "sha512-45+YtqxLYKDWQouLKCrpIZhke+nXxhsw+qAHVzHDVwttyBlHNBVs2K25rDXrZzhpTp9w1FlAlvweV1H++fdZoA==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.17.tgz", + "integrity": "sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==", "dev": true, "license": "MIT" }, @@ -2017,9 +2083,9 @@ } }, "node_modules/es-module-lexer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", - "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", + "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", "dev": true, "license": "MIT" }, @@ -2538,6 +2604,9 @@ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2559,6 +2628,9 @@ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2580,6 +2652,9 @@ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2601,6 +2676,9 @@ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2825,9 +2903,9 @@ } }, "node_modules/oxfmt": { - "version": "0.46.0", - "resolved": "https://registry.npmjs.org/oxfmt/-/oxfmt-0.46.0.tgz", - "integrity": "sha512-CopwJOwPAjZ9p76fCvz+mSOJTw9/NY3cSksZK3VO/bUQ8UoEcketNgUuYS0UB3p+R9XnXe7wGGXUmyFxc7QxJA==", + "version": "0.47.0", + "resolved": "https://registry.npmjs.org/oxfmt/-/oxfmt-0.47.0.tgz", + "integrity": "sha512-OFbkbzxKCpooQEnRmpTDnuwTX8KHXzZTQ4Df/hz85fpS67Pl+lxPEFvUtin56HIIS0B1k4X8oIzTXRZPufA2CA==", "dev": true, "license": "MIT", "dependencies": { @@ -2843,31 +2921,31 @@ "url": "https://github.com/sponsors/Boshen" }, "optionalDependencies": { - "@oxfmt/binding-android-arm-eabi": "0.46.0", - "@oxfmt/binding-android-arm64": "0.46.0", - "@oxfmt/binding-darwin-arm64": "0.46.0", - "@oxfmt/binding-darwin-x64": "0.46.0", - "@oxfmt/binding-freebsd-x64": "0.46.0", - "@oxfmt/binding-linux-arm-gnueabihf": "0.46.0", - "@oxfmt/binding-linux-arm-musleabihf": "0.46.0", - "@oxfmt/binding-linux-arm64-gnu": "0.46.0", - "@oxfmt/binding-linux-arm64-musl": "0.46.0", - "@oxfmt/binding-linux-ppc64-gnu": "0.46.0", - "@oxfmt/binding-linux-riscv64-gnu": "0.46.0", - "@oxfmt/binding-linux-riscv64-musl": "0.46.0", - "@oxfmt/binding-linux-s390x-gnu": "0.46.0", - "@oxfmt/binding-linux-x64-gnu": "0.46.0", - "@oxfmt/binding-linux-x64-musl": "0.46.0", - "@oxfmt/binding-openharmony-arm64": "0.46.0", - "@oxfmt/binding-win32-arm64-msvc": "0.46.0", - "@oxfmt/binding-win32-ia32-msvc": "0.46.0", - "@oxfmt/binding-win32-x64-msvc": "0.46.0" + "@oxfmt/binding-android-arm-eabi": "0.47.0", + "@oxfmt/binding-android-arm64": "0.47.0", + "@oxfmt/binding-darwin-arm64": "0.47.0", + "@oxfmt/binding-darwin-x64": "0.47.0", + "@oxfmt/binding-freebsd-x64": "0.47.0", + "@oxfmt/binding-linux-arm-gnueabihf": "0.47.0", + "@oxfmt/binding-linux-arm-musleabihf": "0.47.0", + "@oxfmt/binding-linux-arm64-gnu": "0.47.0", + "@oxfmt/binding-linux-arm64-musl": "0.47.0", + "@oxfmt/binding-linux-ppc64-gnu": "0.47.0", + "@oxfmt/binding-linux-riscv64-gnu": "0.47.0", + "@oxfmt/binding-linux-riscv64-musl": "0.47.0", + "@oxfmt/binding-linux-s390x-gnu": "0.47.0", + "@oxfmt/binding-linux-x64-gnu": "0.47.0", + "@oxfmt/binding-linux-x64-musl": "0.47.0", + "@oxfmt/binding-openharmony-arm64": "0.47.0", + "@oxfmt/binding-win32-arm64-msvc": "0.47.0", + "@oxfmt/binding-win32-ia32-msvc": "0.47.0", + "@oxfmt/binding-win32-x64-msvc": "0.47.0" } }, "node_modules/oxlint": { - "version": "1.61.0", - "resolved": "https://registry.npmjs.org/oxlint/-/oxlint-1.61.0.tgz", - "integrity": "sha512-ZC0ALuhDZ6ivOFG+sy0D0pEDN49EvsId98zVlmYdkcXHsEM14m/qTNUEsUpiFiCVbpIxYtVBmmLE87nsbUHohQ==", + "version": "1.62.0", + "resolved": "https://registry.npmjs.org/oxlint/-/oxlint-1.62.0.tgz", + "integrity": "sha512-1uFkg6HakjsGIpW9wNdeW4/2LOHW9MEkoWjZUTUfQtIHyLIZPYt00w3Sg+H3lH+206FgBPHBbW5dVE5l2ExECQ==", "dev": true, "license": "MIT", "bin": { @@ -2880,25 +2958,25 @@ "url": "https://github.com/sponsors/Boshen" }, "optionalDependencies": { - "@oxlint/binding-android-arm-eabi": "1.61.0", - "@oxlint/binding-android-arm64": "1.61.0", - "@oxlint/binding-darwin-arm64": "1.61.0", - "@oxlint/binding-darwin-x64": "1.61.0", - "@oxlint/binding-freebsd-x64": "1.61.0", - "@oxlint/binding-linux-arm-gnueabihf": "1.61.0", - "@oxlint/binding-linux-arm-musleabihf": "1.61.0", - "@oxlint/binding-linux-arm64-gnu": "1.61.0", - "@oxlint/binding-linux-arm64-musl": "1.61.0", - "@oxlint/binding-linux-ppc64-gnu": "1.61.0", - "@oxlint/binding-linux-riscv64-gnu": "1.61.0", - "@oxlint/binding-linux-riscv64-musl": "1.61.0", - "@oxlint/binding-linux-s390x-gnu": "1.61.0", - "@oxlint/binding-linux-x64-gnu": "1.61.0", - "@oxlint/binding-linux-x64-musl": "1.61.0", - "@oxlint/binding-openharmony-arm64": "1.61.0", - "@oxlint/binding-win32-arm64-msvc": "1.61.0", - "@oxlint/binding-win32-ia32-msvc": "1.61.0", - "@oxlint/binding-win32-x64-msvc": "1.61.0" + "@oxlint/binding-android-arm-eabi": "1.62.0", + "@oxlint/binding-android-arm64": "1.62.0", + "@oxlint/binding-darwin-arm64": "1.62.0", + "@oxlint/binding-darwin-x64": "1.62.0", + "@oxlint/binding-freebsd-x64": "1.62.0", + "@oxlint/binding-linux-arm-gnueabihf": "1.62.0", + "@oxlint/binding-linux-arm-musleabihf": "1.62.0", + "@oxlint/binding-linux-arm64-gnu": "1.62.0", + "@oxlint/binding-linux-arm64-musl": "1.62.0", + "@oxlint/binding-linux-ppc64-gnu": "1.62.0", + "@oxlint/binding-linux-riscv64-gnu": "1.62.0", + "@oxlint/binding-linux-riscv64-musl": "1.62.0", + "@oxlint/binding-linux-s390x-gnu": "1.62.0", + "@oxlint/binding-linux-x64-gnu": "1.62.0", + "@oxlint/binding-linux-x64-musl": "1.62.0", + "@oxlint/binding-openharmony-arm64": "1.62.0", + "@oxlint/binding-win32-arm64-msvc": "1.62.0", + "@oxlint/binding-win32-ia32-msvc": "1.62.0", + "@oxlint/binding-win32-x64-msvc": "1.62.0" }, "peerDependencies": { "oxlint-tsgolint": ">=0.18.0" @@ -2943,9 +3021,9 @@ } }, "node_modules/postcss": { - "version": "8.5.10", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz", - "integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==", + "version": "8.5.12", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.12.tgz", + "integrity": "sha512-W62t/Se6rA0Az3DfCL0AqJwXuKwBeYg6nOaIgzP+xZ7N5BFCI7DYi1qs6ygUYT6rvfi6t9k65UMLJC+PHZpDAA==", "dev": true, "funding": [ { @@ -3074,14 +3152,14 @@ } }, "node_modules/rolldown": { - "version": "1.0.0-rc.16", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.16.tgz", - "integrity": "sha512-rzi5WqKzEZw3SooTt7cgm4eqIoujPIyGcJNGFL7iPEuajQw7vxMHUkXylu4/vhCkJGXsgRmxqMKXUpT6FEgl0g==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.17.tgz", + "integrity": "sha512-ZrT53oAKrtA4+YtBWPQbtPOxIbVDbxT0orcYERKd63VJTF13zPcgXTvD4843L8pcsI7M6MErt8QtON6lrB9tyA==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.126.0", - "@rolldown/pluginutils": "1.0.0-rc.16" + "@oxc-project/types": "=0.127.0", + "@rolldown/pluginutils": "1.0.0-rc.17" }, "bin": { "rolldown": "bin/cli.mjs" @@ -3090,21 +3168,21 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.0-rc.16", - "@rolldown/binding-darwin-arm64": "1.0.0-rc.16", - "@rolldown/binding-darwin-x64": "1.0.0-rc.16", - "@rolldown/binding-freebsd-x64": "1.0.0-rc.16", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.16", - "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.16", - "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.16", - "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.16", - "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.16", - "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.16", - "@rolldown/binding-linux-x64-musl": "1.0.0-rc.16", - "@rolldown/binding-openharmony-arm64": "1.0.0-rc.16", - "@rolldown/binding-wasm32-wasi": "1.0.0-rc.16", - "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.16", - "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.16" + "@rolldown/binding-android-arm64": "1.0.0-rc.17", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.17", + "@rolldown/binding-darwin-x64": "1.0.0-rc.17", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.17", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.17", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.17", + "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.17", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.17", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.17", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.17", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.17" } }, "node_modules/safe-buffer": { @@ -3278,9 +3356,9 @@ } }, "node_modules/string-width": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.0.tgz", - "integrity": "sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw==", + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.1.tgz", + "integrity": "sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==", "license": "MIT", "dependencies": { "get-east-asian-width": "^1.5.0", @@ -3452,16 +3530,16 @@ "license": "MIT" }, "node_modules/vite": { - "version": "8.0.9", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.9.tgz", - "integrity": "sha512-t7g7GVRpMXjNpa67HaVWI/8BWtdVIQPCL2WoozXXA7LBGEFK4AkkKkHx2hAQf5x1GZSlcmEDPkVLSGahxnEEZw==", + "version": "8.0.10", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.10.tgz", + "integrity": "sha512-rZuUu9j6J5uotLDs+cAA4O5H4K1SfPliUlQwqa6YEwSrWDZzP4rhm00oJR5snMewjxF5V/K3D4kctsUTsIU9Mw==", "dev": true, "license": "MIT", "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", "postcss": "^8.5.10", - "rolldown": "1.0.0-rc.16", + "rolldown": "1.0.0-rc.17", "tinyglobby": "^0.2.16" }, "bin": { diff --git a/package.json b/package.json index fd380b6..eeeef75 100644 --- a/package.json +++ b/package.json @@ -20,10 +20,13 @@ "npm": ">=10.0.0" }, "files": [ - "build" + "build", + "man" ], "scripts": { - "build": "rm -rf ./build; tsc --build; chmod +x ./build/index.js", + "man": "mkdir -p man && tsx src/lib/generate-man.ts > man/tagoio.1 && chmod 644 man/tagoio.1", + "build": "npm run man && rm -rf ./build; tsc --build; chmod +x ./build/index.js", + "prepublishOnly": "npm run man", "test": "vitest run", "test:single": "vitest --", "test:coverage": "vitest run --coverage", @@ -35,6 +38,7 @@ "bin": { "tagoio": "./build/index.js" }, + "man": "./man/tagoio.1", "author": "TagoIO LLC", "license": "ISC", "dependencies": { @@ -59,8 +63,8 @@ "@types/prompts": "^2.4.9", "@types/unzipper": "^0.10.11", "@vitest/coverage-v8": "^4.1.5", - "oxfmt": "^0.46.0", - "oxlint": "1.61.0", + "oxfmt": "^0.47.0", + "oxlint": "1.62.0", "typescript": "^6.0.3", "vitest": "^4.1.5" } diff --git a/src/index.ts b/src/index.ts index f12c6fc..9706fb0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -25,18 +25,6 @@ dotenv.config({ path: ENV_FILE_PATH, quiet: true }); const indexConfigFile = getConfigFile(); const defaultEnvironment = process.env.TAGOIO_DEFAULT || ""; -/** - * Calls functions to add all available commands to the CLI program. - * @param program - The CLI program to add commands to. - * @returns A Promise that resolves when all commands have been added. - */ -async function getAllCommands(program: Command) { - analysisCommands(program); - deviceCommands(program); - dashboardCommands(program); - profileCommands(program, defaultEnvironment); -} - /** * Returns a string with ANSI escape codes to display text in red. * @@ -49,21 +37,29 @@ function errorColor(str: string) { } /** - * Initializes the TagoIO Command Line Tools program and sets up the available commands. - * @returns {Promise} A Promise that resolves when the program has finished parsing the command line arguments. + * @description Builds the commander program with every top-level command + * (init / login / set-env / list-env) and every namespace (analysis, + * devices, dashboard, profile) registered. Returns the configured program + * without calling `program.parse()`. + * + * This is the single source of truth for the CLI's command surface. Both the + * runtime entry point (`initiateCMD`) and the man-page generator + * (`src/lib/generate-man.ts`) call it — adding a new command in this file + * automatically appears in `tagoio --help` and in `man tagoio` on the next + * `npm run man`. + * + * @param defaultEnv - Default value for the optional `[environment]` + * argument on `init` and `login`. Pass `""` for a user-agnostic build + * (e.g. man-page generation); pass the runtime selection otherwise. */ -async function initiateCMD() { - const updateLog = await updater({ name: packageJSON.name, version: packageJSON.version }); +function buildProgram(defaultEnv: string): Command { const program = new Command(); - program.exitOverride(async () => { - updateLog(); - }); program.version(packageJSON.version).description(`${kleur.bold(`TagoIO Command Line Tools - v${packageJSON.version}`)} - \tDefault Environment: ${highlightMSG(defaultEnvironment)} - \tProfile ID: ${highlightMSG(indexConfigFile?.[defaultEnvironment]?.id || "N/A")} - \tName: ${highlightMSG(indexConfigFile?.[defaultEnvironment]?.profileName || "N/A")} - \tEmail: ${highlightMSG(indexConfigFile?.[defaultEnvironment]?.email || "N/A")}`); + \tDefault Environment: ${highlightMSG(defaultEnv)} + \tProfile ID: ${highlightMSG(indexConfigFile?.[defaultEnv]?.id || "N/A")} + \tName: ${highlightMSG(indexConfigFile?.[defaultEnv]?.profileName || "N/A")} + \tEmail: ${highlightMSG(indexConfigFile?.[defaultEnv]?.email || "N/A")}`); program.configureOutput({ writeErr: (str) => process.stderr.write(`[${errorColor("ERROR")}] ${str}`), @@ -74,7 +70,7 @@ async function initiateCMD() { program .command("init") .description("create/update the config file for analysis in your current folder") - .argument("[environment]", "name of the environment.", defaultEnvironment) + .argument("[environment]", "name of the environment.", defaultEnv) .option("-t, --token ", "profile token of the environment and skip login step") .action(startConfig) .addHelpText( @@ -91,7 +87,7 @@ Example: program .command("login") .description("login to your account and store profile_token in the tago-lock.") - .argument("[environment]", "name of the environment", defaultEnvironment) + .argument("[environment]", "name of the environment", defaultEnv) .option("-u, --email ", "your TagoIO email") .option("-p, --password ", "your TagoIO password") .option("-t, --token ", "set a profile-token for the environment and skip login step") @@ -131,9 +127,31 @@ Example: $ tagoio list-env`, ); - await getAllCommands(program); + analysisCommands(program); + deviceCommands(program); + dashboardCommands(program); + profileCommands(program, defaultEnv); + return program; +} + +/** + * Initializes the TagoIO Command Line Tools program and parses argv. + */ +async function initiateCMD() { + const updateLog = await updater({ name: packageJSON.name, version: packageJSON.version }); + const program = buildProgram(defaultEnvironment); + program.exitOverride(async () => { + updateLog(); + }); program.parse(); } -initiateCMD().catch(console.error); +// Auto-run only when invoked as the CLI binary; importing this module from a +// build-time tool (e.g. the man-page generator) must NOT trigger argv parsing. +const isMainModule = import.meta.url === `file://${process.argv[1]}`; +if (isMainModule) { + initiateCMD().catch(console.error); +} + +export { buildProgram }; diff --git a/src/lib/__snapshots__/generate-man.test.ts.snap b/src/lib/__snapshots__/generate-man.test.ts.snap new file mode 100644 index 0000000..f17ec3c --- /dev/null +++ b/src/lib/__snapshots__/generate-man.test.ts.snap @@ -0,0 +1,502 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`generateManPage > walks the populated program tree and emits the expected roff document 1`] = ` +".\\" Generated by scripts/generate-man.ts. Do not edit by hand. +.TH TAGOIO 1 "" "tagoio 3.2.0" "User Commands" + +.SH NAME +tagoio \\- command\\-line tool for TagoIO + +.SH SYNOPSIS +.B tagoio +[\\fIglobal options\\fR] +\\fIcommand\\fR +[\\fIcommand options\\fR] +[\\fIarguments...\\fR] + +.SH DESCRIPTION +The TagoIO Command Line Tool is the official command\\-line +interface to TagoIO. It manages analyses, devices, dashboards, +and user profiles, and can export entire applications between +profiles \\- suitable for both interactive use and CI/CD pipelines. + +.SH GLOBAL OPTIONS +.TP +.BR \\-V , " \\-\\-version" +Output the version number. +.TP +.BR \\-h , " \\-\\-help" +Display help for command. + +.SH COMMANDS +.SS init [environment] +create/update the config file for analysis in your current folder +.TP +\\fB\\-t\\fR, \\fB\\-\\-token\\fR \\fI\\fR +profile token of the environment and skip login step +.PP +.nf + Note: If you don't store credentials in this command, you must run tagoio login + +Example: + $ tagoio init + $ tagoio init \\-t eb8a1d42\\-0f28\\-4ee7\\-9862\\-839920eb1cb0 + $ tagoio init \\-\\-env dev +.fi +.SS login [environment] +login to your account and store profile_token in the tago\\-lock. +.TP +\\fB\\-u\\fR, \\fB\\-\\-email\\fR \\fI\\fR +your TagoIO email +.TP +\\fB\\-p\\fR, \\fB\\-\\-password\\fR \\fI\\fR +your TagoIO password +.TP +\\fB\\-t\\fR, \\fB\\-\\-token\\fR \\fI\\fR +set a profile\\-token for the environment and skip login step +.PP +.nf + Note: No need to login again if you already stored credentials with tagoio init + +Example: + $ tagoio login + $ tagoio login \\-u tago@tago.io \\-p 12345678 + $ tagoio login \\-t eb8a1d42\\-0f28\\-4ee7\\-9862\\-839920eb1cb0 +.fi +.SS set\\-env [environment] +set your default environment from tagoconfig.ts +.PP +.nf +Example: + $ tagoio set\\-env + $ tagoio set\\-env dev +.fi +.SS list\\-env +list all your environment and show current default +.PP +.nf +Example: + $ tagoio list\\-env +.fi +.SS analysis\\-deploy [name] +deploy your analysis to TagoIO + Analysis must be registered in your tagoconfig.ts file first + You can register an analysis by using tagoio init +.TP +\\fB\\-\\-env\\fR, \\fB\\-\\-environment\\fR \\fI[environment]\\fR +environment from config.js +.TP +\\fB\\-s\\fR, \\fB\\-\\-silent\\fR +will not prompt to confirm the deploy +.TP +\\fB\\-\\-deno\\fR +Force build for Deno runtime (default: false) +.TP +\\fB\\-\\-node\\fR +Force build for Node.js runtime (default: false) +.TP +\\fB\\-\\-all\\fR +deploy every analysis from tagoconfig.json without prompting (default: false) +.TP +\\fB\\-t\\fR, \\fB\\-\\-token\\fR \\fI\\fR +profile token for this run (bypasses lock file, for CI/CD) +.PP +.nf +Example: + $ tagoio deploy dashboard\\-handler + $ tagoio deploy dashboard\\-handler \\-\\-deno + $ tagoio deploy dashboard\\-handler \\-\\-node + $ tagoio deploy \\-\\-all # deploy every analysis from tagoconfig.json + $ tagoio deploy \\-\\-all \\-\\-env stage # deploy all to the stage environment + $ tagoio deploy \\-\\-all \\-\\-env prod \\-t $TAGOIO_TOKEN \\-\\-silent # pipeline\\-friendly: no prompts, no lock file needed + $ tagoio deploy \\-\\-node + $ tagoio deploy \\-\\-deno +.fi +.SS analysis\\-run [name] +run your TagoIO analysis from your machine. + If name is not provided, you will be prompted to select which analysis you want to run. + + Note: Analysis will automatically be edited to run in external at TagoIO side. + To change it back to run at TagoIO, use tagoio am +.TP +\\fB\\-\\-env\\fR, \\fB\\-\\-environment\\fR \\fI[environment]\\fR +environment from config.js +.TP +\\fB\\-d\\fR, \\fB\\-\\-debug\\fR +run with \\-\\-inspector for debug +.TP +\\fB\\-c\\fR, \\fB\\-\\-clear\\fR +Will clear screen on restart +.TP +\\fB\\-\\-tsnd\\fR +run with ts\\-node\\-dev if installed globally +.TP +\\fB\\-\\-deno\\fR +Force build for Deno runtime (default: false) +.TP +\\fB\\-\\-node\\fR +Force build for Node.js runtime (default: false) +.PP +.nf +Example: + $ tagoio run dashboard\\-handler + $ tagoio run dash + $ tagoio run dashboard\\-handler \\-d + $ tagoio run dashboard\\-handler \\-d \\-c + $ tagoio run dashboard\\-handler \\-\\-deno + $ tagoio run dashboard\\-handler \\-\\-node + $ tagoio run \\-\\-deno + $ tagoio run \\-\\-node +.fi +.SS analysis\\-trigger [name] +send a signal to trigger your analysis TagoIO +.TP +\\fB\\-\\-json\\fR \\fI[JSON]\\fR +JSON to be used in scope +.TP +\\fB\\-\\-tago\\fR +pick analysis directly from TagoIO list +.TP +\\fB\\-\\-env\\fR, \\fB\\-\\-environment\\fR \\fI[environment]\\fR +environment from config.js +.PP +.nf +Example: + $ tagoio analysis\\-trigger dash + $ tagoio analysis\\-trigger dash \\-\\-json "[{"variable":"test"}]" +.fi +.SS analysis\\-console [name] +connect to your Analysis Console +.TP +\\fB\\-\\-env\\fR, \\fB\\-\\-environment\\fR \\fI[environment]\\fR +environment from config.js +.PP +.nf +Example: + $ tagoio analysis\\-console 62151835435d540010b768c4 +.fi +.SS analysis\\-duplicate [ID] +duplicate your Analysis +.TP +\\fB\\-\\-env\\fR, \\fB\\-\\-environment\\fR \\fI[environment]\\fR +environment from config.js +.TP +\\fB\\-\\-name\\fR \\fI[string]\\fR +new name for the Analysis +.PP +.nf +Example: + $ tagoio analysis\\-duplicate 62151835435d540010b768c4 \\-\\-name "Duplicated Analysis" +.fi +.SS analysis\\-mode [name] +change an analysis or group of analysis to run on tago/external + + If name is not provided, you will be prompted to select which analysis you want to update. + Analysis in external mode are displayed first. +.TP +\\fB\\-\\-env\\fR, \\fB\\-\\-environment\\fR \\fI[environment]\\fR +environment from config.js +.TP +\\fB\\-f\\fR, \\fB\\-\\-filterMode\\fR \\fI[external/tago]\\fR +show only analysis in external/tago +.TP +\\fB\\-m\\fR, \\fB\\-\\-mode\\fR \\fI[external/tago]\\fR +set as external or tago +.PP +.nf +Example: + $ tagoio analysis\\-duplicate 62151835435d540010b768c4 \\-\\-name "Duplicated Analysis" +.fi +.SS device\\-inspector [ID/Token] +connect to your Device Live Inspector +.TP +\\fB\\-\\-env\\fR \\fI[environment]\\fR +environment from config.js +.PP +.nf +Example: + $ tagoio device\\-inspector 62151835435d540010b768c4 + $ tagoio device\\-inspector 62151835435d540010b768c4 \\-\\-env dev +.fi +.SS device\\-info [ID/Token] +get information about a device and it's configuration parameters. +.TP +\\fB\\-\\-env\\fR, \\fB\\-\\-environment\\fR \\fI[environment]\\fR +environment from config.js +.TP +\\fB\\-\\-json\\fR +return json list +.TP +\\fB\\-\\-raw\\fR +get object the same as stored +.TP +\\fB\\-t\\fR, \\fB\\-\\-tokens\\fR +get tokens +.PP +.nf +Example: + $ tagoio device\\-info 62151835435d540010b768c4 +.fi +.SS device\\-list +get the list of devices. +.TP +\\fB\\-\\-env\\fR, \\fB\\-\\-environment\\fR \\fI[environment]\\fR +environment from config.js +.TP +\\fB\\-n\\fR, \\fB\\-\\-name\\fR \\fI[deviceName]\\fR +partial name of the device name +.TP +\\fB\\-k\\fR, \\fB\\-\\-tagkey\\fR \\fI[key]\\fR +tag key to filter in (default: []) +.TP +\\fB\\-v\\fR, \\fB\\-\\-tagvalue\\fR \\fI[value]\\fR +tag value to filter in (default: []) +.TP +\\fB\\-s\\fR, \\fB\\-\\-stringify\\fR +return list as text +.TP +\\fB\\-\\-tags\\fR +display tags +.TP +\\fB\\-\\-json\\fR +return json list +.TP +\\fB\\-\\-raw\\fR +get object the same as stored +.PP +.nf +Example: + $ tagoio device\\-list + $ tagoio device\\-list \\-\\-name Device \\-s + $ tagoio device\\-list \\-t device_type \\-v sensor +.fi +.SS data [ID/Token] +get data from a device. +.TP +\\fB\\-\\-env\\fR, \\fB\\-\\-environment\\fR \\fI[environment]\\fR +environment from config.js +.TP +\\fB\\-g\\fR, \\fB\\-\\-group\\fR \\fI\\fR +Filter by group +.TP +\\fB\\-\\-qty\\fR \\fI\\fR +Request a given set amount of data (default: 15) +.TP +\\fB\\-\\-start\\-date\\fR \\fI\\fR +Get data after date +.TP +\\fB\\-\\-end\\-date\\fR \\fI\\fR +Get data previous of date +.TP +\\fB\\-q\\fR, \\fB\\-\\-query\\fR \\fI[queryType]\\fR +Perform an specific query +.TP +\\fB\\-\\-json\\fR +return json list +.TP +\\fB\\-\\-stringify\\fR +return as text +.TP +\\fB\\-p\\fR, \\fB\\-\\-post\\fR \\fI\\fR +send data to the device +.TP +\\fB\\-v\\fR, \\fB\\-\\-var\\fR \\fI\\fR +Filter by variable (default: []) +.PP +.nf +Example: + $ tagoio data + $ tagoio data \\-v temperature \\-qty 1 \\-\\-json + $ tagoio data 62151835435d540010b768c4 \\-\\-post '{ "variable": "temperature", "value": 32 }' + $ tagoio data 62151835435d540010b768c4 + $ tagoio data 62151835435d540010b768c4 \\-v temperature \\-qty 1 +.fi +.SS device\\-backup [ID/Token] +backup data from a Device. Store it on TagoIO Cloud by default +.TP +\\fB\\-\\-env\\fR, \\fB\\-\\-environment\\fR \\fI[environment]\\fR +environment from config.js +.TP +\\fB\\-\\-local\\fR +store file locally +.TP +\\fB\\-\\-restore\\fR +restore a backup file +.PP +.nf +Example: + $ tagoio bkp + $ tagoio bkp 62151835435d540010b768c4 + $ tagoio bkp 62151835435d540010b768c4 \\-\\-local +.fi +.SS device\\-network [ID/Token] +change the device network and/or connector +.TP +\\fB\\-n\\fR, \\fB\\-\\-networkID\\fR \\fI\\fR +network ID +.TP +\\fB\\-c\\fR, \\fB\\-\\-connectorID\\fR \\fI[connector ID]\\fR +connector ID +.TP +\\fB\\-\\-env\\fR, \\fB\\-\\-environment\\fR \\fI[environment]\\fR +environment from config.js +.PP +.nf +Example: + $ tagoio device\\-network 62151835435d540010b768c4 \\-n 62151835435d540010b768c4 \\-c 62151835435d540010b768c4 + $ tagoio nc 62151835435d540010b768c4 \\-n 62151835435d540010b768c4 \\-c 62151835435d540010b768c4 +.fi +.SS device\\-type [ID/Token] +change the bucket type to immutable or mutable +.TP +\\fB\\-\\-env\\fR, \\fB\\-\\-environment\\fR \\fI[environment]\\fR +environment from config.js +.PP +.nf + It's Recommended to backup data before changing the type, using: + \\- tagoio bkp + Then restore the data after changing the type, using: + \\- tagoio bkp \\-\\-restore + + Example: + $ tagoio device\\-type + $ tagoio device\\-type 62151835435d540010b768c4 +.fi +.SS device\\-copy +copy data from one device to another +.TP +\\fB\\-\\-from\\fR \\fI[token/id]\\fR +token/id of the device where data will be copied from +.TP +\\fB\\-\\-to\\fR \\fI[token/id]\\fR +token/id of the device where data will be copied to +.TP +\\fB\\-\\-qty\\fR \\fI\\fR +amount of data to be copy (default: 10000) +.TP +\\fB\\-\\-env\\fR, \\fB\\-\\-environment\\fR \\fI[environment]\\fR +environment from config.js +.PP +.nf +Example: + $ tagoio device\\-copy + $ tagoio device\\-copy \\-\\-to 62151835435d540010b768c4 \\-\\-from 78151835435d540010b768c4 +.fi +.SS copy\\-tab [dashboardID] +copy a tab of a dashboard to another tab +.TP +\\fB\\-\\-from\\fR \\fI[tabID]\\fR +ID of the Tab to copy +.TP +\\fB\\-\\-to\\fR \\fI[tabID]\\fR +ID of the Tab to paste +.TP +\\fB\\-\\-env\\fR, \\fB\\-\\-environment\\fR \\fI[environment]\\fR +environment from config.js +.PP +.nf + Running this command will completely erase the target tab and replace it with a copy of the source tab. + +Example: + $ tagoio copy\\-tab + $ tagoio copy\\-tab 62151835435d540010b768c4 \\-\\-from 1688653060637 \\-\\-to 2688653060638 + $ tagoio copy\\-tab 62151835435d540010b768c4 \\-\\-env dev +.fi +.SS app\\-export +export application from one profile to another +.TP +\\fB\\-\\-from\\fR \\fI\\fR +environment exporting application +.TP +\\fB\\-\\-to\\fR \\fI\\fR +environment receiving the application +.TP +\\fB\\-\\-from\\-token\\fR \\fI\\fR +profile token of the environment +.TP +\\fB\\-\\-to\\-token\\fR \\fI\\fR +profile token of the environment +.TP +\\fB\\-e\\fR, \\fB\\-\\-entity\\fR \\fI\\fR +entities that will be exported (repeatable) (default: []) +.TP +\\fB\\-\\-setup\\fR \\fI[environment]\\fR +setup a profile to be exported +.TP +\\fB\\-\\-pick\\fR +prompt you to pick which entities to be exported +.TP +\\fB\\-\\-data\\fR \\fI[variables...]\\fR +copy device data with specified variable names (omit names to copy all) +.PP +.nf + Export your profile/environment into another profile/environment. + + Export Tags: + \\- Export Tags are a key\\-pair of tags added to the entities you want to export. By default the tag key is export_id. + \\- You can run \\-\\-setup to user the CLI to go through all your entities and setup the Export Tag for you. + \\- If targeted profile/environment already have an entity with same export tag, it will update the entity instead of creating a new one. + + Entities Export: + \\- dashboards: Export the dashboard label, blueprint devices, tabs, tags and widgets of the dashboard. + Note: To export the dashboards while preserving the relationship between Devices/Analysis, ensure they have the export_id tag or any other tag you choose. + \\- devices: Export the devices configuration. Use \\-\\-data to also copy device data: \\-\\-data copies all variables, \\-\\-data var1 var2 copies only specified variables. + If you are using device\\-tokens in Environment Variables or tags, you want to include the device in the export command. + \\- analysis: Export the analysis name, code, tags, mode and timeout settings. + \\- access: Export the access rules. + \\- run: Export sidebar buttons, sign\\-in buttons and email templates + \\- actions: Export actions. + \\- dictionaries: Export all the dictionaries slugs. + + Backup: + \\- Script will automatically create a backup under exportBackup folder inside your project. + \\- You can use the backup to restore your profile/environment in case of any issues. + +Example: + $ tagoio export + $ tagoio export \\-\\-setup dev + $ tagoio export \\-\\-from dev \\-\\-to prod + $ tagoio export \\-\\-from dev \\-\\-to prod \\-e dashboards \\-e actions \\-e analysis + $ tagoio export \\-ft cb8a1d42\\-0f28\\-4ee7\\-9862\\-839920eb1cb1 \\-tt eb8a1d42\\-0f28\\-4ee7\\-9862\\-839920eb1cb0 +.fi +.SS backup +profile backup management commands + +.SH EXIT STATUS +.TP +.B 0 +Command completed successfully. +.TP +.B 1 +Any failure. The error is printed on stderr with an [ERROR] prefix +(or as a JSON object when \\-\\-json is set). + +.SH ENVIRONMENT +.TP +.B TAGOIO_DEFAULT +Selects which environment from tagoconfig.json the CLI uses +when no \\-\\-env flag is given. Persisted by tagoio set\\-env. + +.SH FILES +.TP +.I ./tagoconfig.json +Project\\-level configuration. Created and updated by +tagoio init. +.TP +.I ./.tago-lock..lock +Per\\-environment profile token written by tagoio login. +One file per environment, kept in the current project directory. +.TP +.I ./.tagoio/personal.env +Persists the user's default environment selection +(TAGOIO_DEFAULT). Updated by tagoio set\\-env. + +.SH SEE ALSO +TagoIO documentation: \\fIhttps://help.tago.io\\fR + +Issue tracker: \\fIhttps://github.com/tago\\-io/tagoio\\-cli/issues\\fR + +.SH AUTHOR +TagoIO LLC +" +`; diff --git a/src/lib/generate-man.test.ts b/src/lib/generate-man.test.ts new file mode 100644 index 0000000..a53475d --- /dev/null +++ b/src/lib/generate-man.test.ts @@ -0,0 +1,86 @@ +import { execFileSync } from "node:child_process"; +import { mkdtempSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { describe, expect, test } from "vitest"; + +import { buildPopulatedProgram, escapeRoff, generateManPage } from "./generate-man.js"; + +/** + * @description Detects which man-page renderer is available on the host. CI + * runners typically have `groff` (Linux); macOS has `mandoc` by default. + * If neither is available, the integration test is skipped — the snapshot + * test alone still catches drift in CI. + */ +function findManRenderer(): { bin: string; args: string[] } | null { + const candidates: Array<{ bin: string; args: string[] }> = [ + { bin: "/usr/bin/mandoc", args: ["-Tutf8"] }, + { bin: "/usr/bin/groff", args: ["-mandoc", "-Tutf8"] }, + { bin: "groff", args: ["-mandoc", "-Tutf8"] }, + { bin: "mandoc", args: ["-Tutf8"] }, + ]; + for (const candidate of candidates) { + try { + execFileSync(candidate.bin, ["--version"], { stdio: "ignore" }); + return candidate; + } catch { + // try next + } + } + return null; +} + +describe("generateManPage", () => { + test("walks the populated program tree and emits the expected roff document", () => { + const program = buildPopulatedProgram(); + const roff = generateManPage("3.2.0", program.commands); + expect(roff).toMatchSnapshot(); + }); + + test("escapeRoff escapes backslashes, hyphens, and leading periods", () => { + expect(escapeRoff("plain")).toBe("plain"); + expect(escapeRoff("with\\backslash")).toBe("with\\\\backslash"); + expect(escapeRoff("--flag")).toBe("\\-\\-flag"); + expect(escapeRoff(".leading\nfine\n.line2")).toBe("\\&.leading\nfine\n\\&.line2"); + }); + + test("the generated page exposes a stable command surface (regression guard)", () => { + const program = buildPopulatedProgram(); + const roff = generateManPage("0.0.0", program.commands); + + // Sanity: a sampling of well-known commands must appear as section + // sub-headings. Locks the contract that registerAllCommands is wired in + // and the walker reaches every namespace. + expect(roff).toContain(".SS init [environment]"); + expect(roff).toContain(".SS login [environment]"); + expect(roff).toContain(".SS analysis\\-deploy [name]"); + expect(roff).toContain(".SS device\\-list"); + expect(roff).toContain(".SS copy\\-tab [dashboardID]"); + + // No "Header" placeholder leaked through. + expect(roff).not.toMatch(/\.SS [^\n]*Header/i); + + // No commander-internal `help` subcommand. + expect(roff).not.toMatch(/^\.SS help[\s\n]/m); + }); + + test("integration: the generated page renders cleanly through the system man processor", () => { + const renderer = findManRenderer(); + if (!renderer) { + // Skip on hosts without groff/mandoc. Snapshot test still gates drift. + return; + } + + const program = buildPopulatedProgram(); + const roff = generateManPage("3.2.0", program.commands); + + const dir = mkdtempSync(join(tmpdir(), "tagoio-man-")); + const path = join(dir, "tagoio.1"); + writeFileSync(path, roff, "utf8"); + + // Renderer exits non-zero on roff syntax errors (.TP without a tag, + // unclosed font escapes, etc.). We don't care about the rendered text; + // the exit code is the gate. + expect(() => execFileSync(renderer.bin, [...renderer.args, path], { stdio: "pipe" })).not.toThrow(); + }); +}); diff --git a/src/lib/generate-man.ts b/src/lib/generate-man.ts new file mode 100644 index 0000000..73f7b8a --- /dev/null +++ b/src/lib/generate-man.ts @@ -0,0 +1,266 @@ +/** + * @description Walks the live commander program tree and emits a single + * `tagoio.1` roff page to stdout. The generated page is the source of truth + * for `man tagoio` and for shell tab-completion (zsh/fish parse roff). + * + * Run via `npm run man`, which redirects stdout to `man/tagoio.1`. A vitest + * snapshot test pins the output so any flag/command change without a matching + * snapshot regen fails CI (see `scripts/generate-man.test.ts`). + * + * Roff special characters that must be escaped in user-supplied strings: + * `\` → `\\` + * `-` → `\-` (so it survives nroff dehyphenation in option names) + * `.` at line start → `\&.` (otherwise read as a control directive) + */ +import { Command, Option } from "commander"; +import { readFileSync } from "node:fs"; +import { join } from "node:path"; + +import { buildProgram } from "../index.js"; +import { MAN_CONTENT } from "./man-content.js"; + +/** Reads the package.json that sits two levels up from `src/lib`. */ +function readPackageJSON(): { name: string; version: string; description?: string } { + const path = join(import.meta.dirname, "..", "..", "package.json"); + return JSON.parse(readFileSync(path, "utf8")); +} + +/** Escapes a string for safe interpolation into roff body text. */ +function escapeRoff(input: string): string { + return input + .replaceAll("\\", "\\\\") + .replaceAll("-", "\\-") + .replaceAll(/^\./gm, "\\&."); +} + +/** Joins a list of lines into a single block, trimming trailing whitespace per line. */ +function block(...lines: string[]): string { + return `${lines.map((line) => line.replace(/[\t ]+$/u, "")).join("\n")}\n`; +} + +/** + * @description Page header (.TH) plus the static top sections. Prose lives in + * `man-content.ts` as plain English; this function wraps each value with the + * roff escapes and the right `.SH`/`.TP` markers. + */ +function buildHeader(version: string): string { + return block( + `.\\" Generated by scripts/generate-man.ts. Do not edit by hand.`, + `.TH TAGOIO 1 "" "tagoio ${version}" "User Commands"`, + "", + ".SH NAME", + escapeRoff(MAN_CONTENT.name), + "", + ".SH SYNOPSIS", + ".B tagoio", + "[\\fIglobal options\\fR]", + "\\fIcommand\\fR", + "[\\fIcommand options\\fR]", + "[\\fIarguments...\\fR]", + "", + ".SH DESCRIPTION", + escapeRoff(MAN_CONTENT.description), + "", + ".SH GLOBAL OPTIONS", + ".TP", + ".BR \\-V , \" \\-\\-version\"", + escapeRoff(MAN_CONTENT.globalVersionDesc), + ".TP", + ".BR \\-h , \" \\-\\-help\"", + escapeRoff(MAN_CONTENT.globalHelpDesc), + ); +} + +/** Trailing static sections. Prose pulled from `man-content.ts`. */ +function buildFooter(): string { + return block( + "", + ".SH EXIT STATUS", + ".TP", + ".B 0", + escapeRoff(MAN_CONTENT.exitStatusOK), + ".TP", + ".B 1", + escapeRoff(MAN_CONTENT.exitStatusFail), + "", + ".SH ENVIRONMENT", + ".TP", + ".B TAGOIO_DEFAULT", + escapeRoff(MAN_CONTENT.envTagoioDefault), + "", + ".SH FILES", + ".TP", + ".I ./tagoconfig.json", + escapeRoff(MAN_CONTENT.fileTagoconfig), + ".TP", + ".I ./.tago-lock..lock", + escapeRoff(MAN_CONTENT.fileLockfile), + ".TP", + ".I ./.tagoio/personal.env", + escapeRoff(MAN_CONTENT.filePersonalEnv), + "", + ".SH SEE ALSO", + `TagoIO documentation: \\fI${escapeRoff(MAN_CONTENT.seeAlsoDocsURL)}\\fR`, + "", + `Issue tracker: \\fI${escapeRoff(MAN_CONTENT.seeAlsoIssuesURL)}\\fR`, + "", + ".SH AUTHOR", + escapeRoff(MAN_CONTENT.author), + ); +} + +/** Returns the placeholder a command's [arg] / tokens render as in the heading. */ +function commandHeading(cmd: Command): string { + const args = cmd.registeredArguments.map((arg) => { + const name = arg.name(); + return arg.required ? `<${name}>` : `[${name}]`; + }); + const headingTokens = [cmd.name(), ...args].join(" "); + return escapeRoff(headingTokens); +} + +/** Renders a single Option as a `.TP`-prefixed roff block. */ +function renderOption(option: Option): string { + // Commander gives us a flags string like `-t, --token `. + // Split into the flag list and the optional argument placeholder. + const flagsText = option.flags; + const placeholderMatch = /\s+([<\[].+)$/u.exec(flagsText); + const placeholder = placeholderMatch ? placeholderMatch[1] : ""; + const flagsOnly = placeholder ? flagsText.slice(0, flagsText.length - placeholder.length).trim() : flagsText; + + // Render each flag in bold; placeholder in italic. + const flagTokens = flagsOnly + .split(",") + .map((flag) => `\\fB${escapeRoff(flag.trim())}\\fR`) + .join(", "); + const placeholderRendered = placeholder ? ` \\fI${escapeRoff(placeholder)}\\fR` : ""; + + const description = option.description ? escapeRoff(option.description) : ""; + const defaultText = option.defaultValue !== undefined && option.defaultValue !== "" ? ` (default: ${escapeRoff(JSON.stringify(option.defaultValue))})` : ""; + + return block(`.TP`, `${flagTokens}${placeholderRendered}`, `${description}${defaultText}` || "\\&"); +} + +/** Renders any text the command attached via `addHelpText("after", ...)` as a literal block. */ +function renderAfterText(cmd: Command): string { + // Commander 14 wires `addHelpText("after", text)` via `this.on("afterHelp", ...)`, + // so the registered listeners live on Node's EventEmitter — accessible + // through the public `listeners(eventName)` API. The Command typings don't + // expose EventEmitter members, so we cast to the minimal shape we need. + const emitter = cmd as unknown as { listeners(event: string): Array<(ctx: unknown) => void> }; + const listeners = emitter.listeners("afterHelp"); + if (listeners.length === 0) { + return ""; + } + + // Each listener writes via `context.write(str)`. We capture those writes + // by passing a stub context that appends to a buffer, then flatten. + const captured: string[] = []; + const stubContext = { + error: false, + command: cmd, + write: (str: string) => { + captured.push(str); + }, + }; + + for (const listener of listeners) { + listener(stubContext); + } + + if (captured.length === 0) { + return ""; + } + + // Render the captured text as a roff `.nf` (no-fill) block so indentation + // and line breaks survive the page layout. + const lines = captured.join("\n").split("\n").map((line) => line.trimEnd()); + // Strip leading and trailing blank lines so the block sits flush. + while (lines.length > 0 && lines[0] === "") { + lines.shift(); + } + while (lines.length > 0 && lines[lines.length - 1] === "") { + lines.pop(); + } + if (lines.length === 0) { + return ""; + } + + const out: string[] = [".PP", ".nf"]; + for (const line of lines) { + out.push(line.length === 0 ? "" : escapeRoff(line)); + } + out.push(".fi"); + return block(...out); +} + +/** Renders one command (registered top-level on `program`) as a `.SS` block. */ +function renderCommand(cmd: Command): string { + const heading = commandHeading(cmd); + const description = cmd.description() ? escapeRoff(cmd.description()) : ""; + const sections: string[] = [block(`.SS ${heading}`, description || "\\&")]; + + for (const option of cmd.options) { + sections.push(renderOption(option)); + } + + const afterText = renderAfterText(cmd); + if (afterText) { + sections.push(afterText); + } + + return sections.join(""); +} + +/** + * @description Top-level entry point. Builds the program tree, walks it, + * returns the full roff document as a string. Pure: no I/O, no env reads. + */ +function generateManPage(version: string, commands: readonly Command[]): string { + const out: string[] = [buildHeader(version), block("", ".SH COMMANDS")]; + + for (const cmd of commands) { + // Skip the empty placeholder commands like `program.command("Devices Header")` + // that the existing CLI uses as visual section dividers in --help. + // Commander parses "Foo Header" as { name: "Foo", arg:
}, so we + // check both the name and the rendered heading (name + args). + if (commandHeading(cmd).toLowerCase().includes("header")) { + continue; + } + // Skip commander's auto-generated `help` subcommand — already covered by + // GLOBAL OPTIONS (-h / --help). + if (cmd.name() === "help") { + continue; + } + out.push(renderCommand(cmd)); + } + + out.push(buildFooter()); + return out.join(""); +} + +/** Constructs a fresh program with every command registered, ready to walk. */ +function buildPopulatedProgram(): Command { + // The man-page reflects the static command surface, not any user's + // current environment; pass an empty string so commander does not bake + // a runtime value into the help output. `buildProgram` lives in + // `src/index.ts` and is the single source of truth for the CLI's command + // tree — adding a command there automatically appears in this generator's + // output on the next run. + return buildProgram(""); +} + +function main(): void { + const pkg = readPackageJSON(); + const program = buildPopulatedProgram(); + const roff = generateManPage(pkg.version, program.commands); + process.stdout.write(roff); +} + +// Run when invoked directly (so tests can `import` the helpers without side effects). +const isMain = import.meta.url === `file://${process.argv[1]}` || import.meta.url.endsWith("/src/lib/generate-man.ts"); +if (isMain) { + main(); +} + +export { buildPopulatedProgram, escapeRoff, generateManPage }; diff --git a/src/lib/man-content.ts b/src/lib/man-content.ts new file mode 100644 index 0000000..996be7c --- /dev/null +++ b/src/lib/man-content.ts @@ -0,0 +1,51 @@ +/** + * @description Plain-English text bodies for the man page. + * + * Edit prose here in normal English — no roff escapes, no font codes. The + * generator (`generate-man.ts`) wraps each value with `escapeRoff()` and + * places it under the right `.SH`/`.TP` section. + * + * Keep line breaks intentional: a literal `\n` in these strings becomes a + * line break in the rendered man page, which is how multi-paragraph entries + * stay readable in `man tagoio`. + */ +const MAN_CONTENT = { + // NAME section + name: "tagoio - command-line tool for TagoIO", + + // DESCRIPTION section + description: `The TagoIO Command Line Tool is the official command-line +interface to TagoIO. It manages analyses, devices, dashboards, +and user profiles, and can export entire applications between +profiles - suitable for both interactive use and CI/CD pipelines.`, + + // GLOBAL OPTIONS labels + globalVersionDesc: "Output the version number.", + globalHelpDesc: "Display help for command.", + + // EXIT STATUS bodies + exitStatusOK: "Command completed successfully.", + exitStatusFail: `Any failure. The error is printed on stderr with an [ERROR] prefix +(or as a JSON object when --json is set).`, + + // ENVIRONMENT body (TAGOIO_DEFAULT) + envTagoioDefault: `Selects which environment from tagoconfig.json the CLI uses +when no --env flag is given. Persisted by tagoio set-env.`, + + // FILES bodies + fileTagoconfig: `Project-level configuration. Created and updated by +tagoio init.`, + fileLockfile: `Per-environment profile token written by tagoio login. +One file per environment, kept in the current project directory.`, + filePersonalEnv: `Persists the user's default environment selection +(TAGOIO_DEFAULT). Updated by tagoio set-env.`, + + // SEE ALSO entries (URLs only — labels are in the inline structure) + seeAlsoDocsURL: "https://help.tago.io", + seeAlsoIssuesURL: "https://github.com/tago-io/tagoio-cli/issues", + + // AUTHOR + author: "TagoIO LLC", +} as const; + +export { MAN_CONTENT }; diff --git a/vitest.config.js b/vitest.config.js index eb91605..557275f 100644 --- a/vitest.config.js +++ b/vitest.config.js @@ -16,6 +16,16 @@ export default defineConfig({ "**/*.d.ts", "**/mock/**", "**/*.json", + // Entry point: integration glue, not unit-testable; runtime behaviour + // is exercised by every live invocation. + "index.ts", + // Interactive prompt-driven flows. Unit-testing each prompt branch + // would test the prompts library, not our logic. These commands are + // covered by manual smokes (see docs/pr-30-test-plan.md sections + // T-2.init and T-6.backup.restore). + "commands/start-config.ts", + "commands/profile/backup/restore.ts", + "commands/profile/export/export-setup.ts", ], thresholds: { lines: 80,