From ab2d9e7bbe7ec24c261a741fa178f43fa4549260 Mon Sep 17 00:00:00 2001 From: Yuchen07569 <296913685+Yuchen07569@users.noreply.github.com> Date: Thu, 13 Aug 2026 14:19:55 +0800 Subject: [PATCH 1/5] Add agent-night-watch extension - fix: make Skill preflight portable - feat: publish Agent Night Watch extension and skill --- extensions/agent-night-watch/.gitignore | 4 + extensions/agent-night-watch/CHANGELOG.md | 10 + extensions/agent-night-watch/README.md | 33 + .../agent-night-watch/assets/coffee-off.png | Bin 0 -> 30240 bytes .../agent-night-watch/assets/coffee-off.svg | 7 + .../agent-night-watch/assets/coffee-on.png | Bin 0 -> 38785 bytes .../agent-night-watch/assets/coffee-on.svg | 9 + .../assets/night-watch-guard.sh | 53 + extensions/agent-night-watch/eslint.config.js | 3 + .../agent-night-watch/package-lock.json | 4026 +++++++++++++++++ extensions/agent-night-watch/package.json | 53 + .../src/night-watch-menu.tsx | 133 + .../agent-night-watch/src/night-watch.ts | 429 ++ extensions/agent-night-watch/src/status.ts | 71 + .../src/toggle-night-watch.ts | 35 + .../agent-night-watch/tests/status.test.ts | 136 + extensions/agent-night-watch/tsconfig.json | 17 + 17 files changed, 5019 insertions(+) create mode 100644 extensions/agent-night-watch/.gitignore create mode 100644 extensions/agent-night-watch/CHANGELOG.md create mode 100644 extensions/agent-night-watch/README.md create mode 100644 extensions/agent-night-watch/assets/coffee-off.png create mode 100644 extensions/agent-night-watch/assets/coffee-off.svg create mode 100644 extensions/agent-night-watch/assets/coffee-on.png create mode 100644 extensions/agent-night-watch/assets/coffee-on.svg create mode 100755 extensions/agent-night-watch/assets/night-watch-guard.sh create mode 100644 extensions/agent-night-watch/eslint.config.js create mode 100644 extensions/agent-night-watch/package-lock.json create mode 100644 extensions/agent-night-watch/package.json create mode 100644 extensions/agent-night-watch/src/night-watch-menu.tsx create mode 100644 extensions/agent-night-watch/src/night-watch.ts create mode 100644 extensions/agent-night-watch/src/status.ts create mode 100644 extensions/agent-night-watch/src/toggle-night-watch.ts create mode 100644 extensions/agent-night-watch/tests/status.test.ts create mode 100644 extensions/agent-night-watch/tsconfig.json diff --git a/extensions/agent-night-watch/.gitignore b/extensions/agent-night-watch/.gitignore new file mode 100644 index 00000000000..94510244f15 --- /dev/null +++ b/extensions/agent-night-watch/.gitignore @@ -0,0 +1,4 @@ +node_modules/ +dist/ +.DS_Store +*.log diff --git a/extensions/agent-night-watch/CHANGELOG.md b/extensions/agent-night-watch/CHANGELOG.md new file mode 100644 index 00000000000..131d5a7cf54 --- /dev/null +++ b/extensions/agent-night-watch/CHANGELOG.md @@ -0,0 +1,10 @@ +# Changelog + +## [Initial Version] - {PR_MERGE_DATE} + +- Add a menu-bar coffee cup for closed-lid awake status. +- Add a manual toggle command suitable for a user-assigned hotkey. +- Read `SleepDisabled` as the source of truth and distinguish owned sessions + from external sleep-disabled state. +- Require administrator authorization on enable and verify normal sleep on + disable. diff --git a/extensions/agent-night-watch/README.md b/extensions/agent-night-watch/README.md new file mode 100644 index 00000000000..153c8e4dfaf --- /dev/null +++ b/extensions/agent-night-watch/README.md @@ -0,0 +1,33 @@ +# Agent Night Watch + +Keep local agents running when a MacBook lid is closed, using a coffee-cup +switch in the Raycast menu bar. + +- Empty cup: normal closed-lid sleep. +- Steaming cup: Agent Night Watch is active. +- Enabling asks for macOS administrator authorization every time. +- Disabling an owned session does not ask again. +- The display can still turn off according to macOS settings. + +Unlike Coffee and other `caffeinate` wrappers, Agent Night Watch controls the +closed-lid `SleepDisabled` setting and reads it back before reporting success. + +## Setup + +1. Enable **Night Watch Menu Bar** to keep the coffee cup visible. +2. Optionally assign `⌥S` to **Toggle Night Watch** in Raycast Settings. +3. Click **Enable Agent Night Watch** and approve the macOS dialog. +4. Click **Disable Agent Night Watch** when the job finishes. + +## Safety + +Closed-lid work can increase heat and battery use. Keep the MacBook on a hard, +ventilated surface. This extension does not add a timer or battery cutoff, so +you remain responsible for turning it off. + +If sleep was disabled by another tool, Agent Night Watch will not claim that +session. The menu offers a separately confirmed, administrator-authorized +recovery action. + +No password is stored. No privileged helper, sudoers rule, analytics, or +network request is used. diff --git a/extensions/agent-night-watch/assets/coffee-off.png b/extensions/agent-night-watch/assets/coffee-off.png new file mode 100644 index 0000000000000000000000000000000000000000..5552e675b6f9ddda4a2b244f253241efb701257f GIT binary patch literal 30240 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 Jv8mgm{{vRqA1eR= literal 0 HcmV?d00001 diff --git a/extensions/agent-night-watch/assets/coffee-off.svg b/extensions/agent-night-watch/assets/coffee-off.svg new file mode 100644 index 00000000000..95d4c5e618d --- /dev/null +++ b/extensions/agent-night-watch/assets/coffee-off.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/extensions/agent-night-watch/assets/coffee-on.png b/extensions/agent-night-watch/assets/coffee-on.png new file mode 100644 index 0000000000000000000000000000000000000000..3d2e42bfc7171d7e901e6525915320d4b1d25a58 GIT binary patch literal 38785 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 + + + + + + + + diff --git a/extensions/agent-night-watch/assets/night-watch-guard.sh b/extensions/agent-night-watch/assets/night-watch-guard.sh new file mode 100755 index 00000000000..a09cab9d80c --- /dev/null +++ b/extensions/agent-night-watch/assets/night-watch-guard.sh @@ -0,0 +1,53 @@ +#!/bin/sh + +set -u +umask 077 + +SESSION_DIR="${1:-}" +case "$SESSION_DIR" in + */com.yuchen.agent-night-watch/session.*) ;; + *) exit 64 ;; +esac + +READY_FILE="$SESSION_DIR/ready" +STOP_FILE="$SESSION_DIR/stop" +STOPPED_FILE="$SESSION_DIR/stopped" +REASON_FILE="$SESSION_DIR/reason" +ORIGINAL_FILE="$SESSION_DIR/original" + +sleep_is_disabled() { + /usr/bin/pmset -g | /usr/bin/grep -Eq '^[[:space:]]*SleepDisabled[[:space:]]+1[[:space:]]*$' +} + +original_state=0 +if sleep_is_disabled; then + original_state=1 +fi + +cleanup() { + cleanup_status=$? + trap - EXIT HUP INT TERM + /usr/bin/pmset -a disablesleep "$original_state" >/dev/null 2>&1 || true + /bin/rm -f "$READY_FILE" + /usr/bin/touch "$STOPPED_FILE" + exit "$cleanup_status" +} + +trap cleanup EXIT HUP INT TERM + +/bin/echo "$original_state" > "$ORIGINAL_FILE" +/usr/bin/pmset -a disablesleep 1 >/dev/null +sleep_is_disabled || exit 1 +/usr/bin/touch "$READY_FILE" + +while [ ! -e "$STOP_FILE" ]; do + if ! sleep_is_disabled; then + /bin/echo external-change > "$REASON_FILE" + exit 0 + fi + /bin/sleep 1 +done + +if [ ! -s "$REASON_FILE" ]; then + /bin/echo manual > "$REASON_FILE" +fi diff --git a/extensions/agent-night-watch/eslint.config.js b/extensions/agent-night-watch/eslint.config.js new file mode 100644 index 00000000000..ad5ba569b73 --- /dev/null +++ b/extensions/agent-night-watch/eslint.config.js @@ -0,0 +1,3 @@ +import raycastConfig from "@raycast/eslint-config"; + +export default [...raycastConfig]; diff --git a/extensions/agent-night-watch/package-lock.json b/extensions/agent-night-watch/package-lock.json new file mode 100644 index 00000000000..b15a12edbd0 --- /dev/null +++ b/extensions/agent-night-watch/package-lock.json @@ -0,0 +1,4026 @@ +{ + "name": "agent-night-watch", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "agent-night-watch", + "license": "MIT", + "dependencies": { + "@raycast/api": "^1.104.24", + "react": "^19.0.0" + }, + "devDependencies": { + "@raycast/eslint-config": "^2.2.0", + "@types/node": "^22.18.0", + "@types/react": "^19.1.0", + "eslint": "^9.34.0", + "prettier": "^3.6.2", + "typescript": "^5.9.2", + "vitest": "^3.2.4" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", + "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.10.1.tgz", + "integrity": "sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.5" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.6.tgz", + "integrity": "sha512-l2Ul9PrHsPCKcEY/ac7VgFj9D80C7S68sOKc618SyHDPK36s1XcFebXY0iTzUVn4Yq+YbwvSnDmCz9yxjX+QrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.14.0", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.3.0", + "minimatch": "^3.1.5", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.5", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.5.tgz", + "integrity": "sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@inquirer/ansi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz", + "integrity": "sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/checkbox": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.2.tgz", + "integrity": "sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==", + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/confirm": { + "version": "5.1.21", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.21.tgz", + "integrity": "sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/core": { + "version": "10.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.2.tgz", + "integrity": "sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==", + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^1.0.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "cli-width": "^4.1.0", + "mute-stream": "^2.0.0", + "signal-exit": "^4.1.0", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/core/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@inquirer/editor": { + "version": "4.2.23", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.23.tgz", + "integrity": "sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/external-editor": "^1.0.3", + "@inquirer/type": "^3.0.10" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/expand": { + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.23.tgz", + "integrity": "sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/external-editor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz", + "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==", + "license": "MIT", + "dependencies": { + "chardet": "^2.1.1", + "iconv-lite": "^0.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/figures": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.15.tgz", + "integrity": "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/input": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.3.1.tgz", + "integrity": "sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/number": { + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.23.tgz", + "integrity": "sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/password": { + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.23.tgz", + "integrity": "sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==", + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/prompts": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.10.1.tgz", + "integrity": "sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==", + "license": "MIT", + "dependencies": { + "@inquirer/checkbox": "^4.3.2", + "@inquirer/confirm": "^5.1.21", + "@inquirer/editor": "^4.2.23", + "@inquirer/expand": "^4.0.23", + "@inquirer/input": "^4.3.1", + "@inquirer/number": "^3.0.23", + "@inquirer/password": "^4.0.23", + "@inquirer/rawlist": "^4.1.11", + "@inquirer/search": "^3.2.2", + "@inquirer/select": "^4.4.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/rawlist": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.11.tgz", + "integrity": "sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/search": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.2.2.tgz", + "integrity": "sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/select": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.4.2.tgz", + "integrity": "sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==", + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/type": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.10.tgz", + "integrity": "sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@napi-rs/lzma-linux-x64-gnu": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.5.1.tgz", + "integrity": "sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^22.20 || ^24.12 || >=25" + } + }, + "node_modules/@oclif/core": { + "version": "4.13.3", + "resolved": "https://registry.npmjs.org/@oclif/core/-/core-4.13.3.tgz", + "integrity": "sha512-wBp2igI2KVwq2ZmpnfmGtOROo7aXZIr3OEtAS16g1wHFBqyEuswL+9K50NJWJvlpAmxd+4dVj/ycawXESU3wQQ==", + "license": "MIT", + "dependencies": { + "ansi-escapes": "^4.3.2", + "ansis": "^3.17.0", + "clean-stack": "^3.0.1", + "cli-spinners": "^2.9.2", + "debug": "^4.4.3", + "ejs": "^3.1.10", + "get-package-type": "^0.1.0", + "indent-string": "^4.0.0", + "is-wsl": "^2.2.0", + "lilconfig": "^3.1.3", + "minimatch": "^10.2.5", + "semver": "^7.8.1", + "string-width": "^4.2.3", + "supports-color": "^8", + "tinyglobby": "^0.2.17", + "widest-line": "^3.1.0", + "wordwrap": "^1.0.0", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@oclif/plugin-autocomplete": { + "version": "3.2.56", + "resolved": "https://registry.npmjs.org/@oclif/plugin-autocomplete/-/plugin-autocomplete-3.2.56.tgz", + "integrity": "sha512-P96b6RZvQatlJ6pX6sgIFOQhgX2tFVhgSfw53GT/MajecCQNFGVqagJKo2CfcPsacDpuFuPRT6zji8h1oaqtrA==", + "license": "MIT", + "dependencies": { + "@oclif/core": "^4", + "ansis": "^3.16.0", + "debug": "^4.4.1", + "ejs": "^3.1.10" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@oclif/plugin-help": { + "version": "6.2.58", + "resolved": "https://registry.npmjs.org/@oclif/plugin-help/-/plugin-help-6.2.58.tgz", + "integrity": "sha512-DAYMXZrTWRMLTbpX+rT+ibAmKrZ6IVNGn+fgAGjMoeNlqlSY94eJHocgmqChMwsdWp3H3x+jFmPJiYQt/ifr3Q==", + "license": "MIT", + "dependencies": { + "@oclif/core": "^4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@oclif/plugin-not-found": { + "version": "3.2.93", + "resolved": "https://registry.npmjs.org/@oclif/plugin-not-found/-/plugin-not-found-3.2.93.tgz", + "integrity": "sha512-KBizxn+kgTPWLUCo/vDz/oDdEA5Ll5H6x0jJhl05B56yHwgQp46ZxwXmtBsxvvgrmMqJEtFUw2Qrq+nTHWWv4g==", + "license": "MIT", + "dependencies": { + "@inquirer/prompts": "^7.10.1", + "@oclif/core": "^4.13.3", + "ansis": "^3.17.0", + "fast-levenshtein": "^3.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@raycast/api": { + "version": "1.104.24", + "resolved": "https://registry.npmjs.org/@raycast/api/-/api-1.104.24.tgz", + "integrity": "sha512-Jppfyi1T7wcGXZFxpzXuvNAKUPQ+BQkKC0N3rJBz1epp/z22SH9aLA23YZRk/ickGwEm6DI/7OY7Jin8dD53Sg==", + "license": "MIT", + "dependencies": { + "@oclif/core": "^4.8.4", + "@oclif/plugin-autocomplete": "^3.2.40", + "@oclif/plugin-help": "^6.2.37", + "@oclif/plugin-not-found": "^3.2.74", + "@types/node": "22.19.17", + "@types/react": "19.0.10", + "esbuild": "^0.27.3", + "react": "19.0.0" + }, + "bin": { + "ray": "bin/run.js" + }, + "engines": { + "node": ">=22.22.2" + }, + "peerDependencies": { + "@types/node": "22.19.17", + "@types/react": "19.0.10", + "react-devtools": "6.1.1" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@types/react": { + "optional": true + }, + "react-devtools": { + "optional": true + } + } + }, + "node_modules/@raycast/api/node_modules/@types/node": { + "version": "22.19.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.17.tgz", + "integrity": "sha512-wGdMcf+vPYM6jikpS/qhg6WiqSV/OhG+jeeHT/KlVqxYfD40iYJf9/AE1uQxVWFvU7MipKRkRv8NSHiCGgPr8Q==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@raycast/api/node_modules/@types/react": { + "version": "19.0.10", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.10.tgz", + "integrity": "sha512-JuRQ9KXLEjaUNjTWpzuR231Z2WpIwczOkBEIvbHNCzQefFIT0L8IqE6NV6ULLyC1SI/i234JnDoMkfg+RjQj2g==", + "license": "MIT", + "dependencies": { + "csstype": "^3.0.2" + } + }, + "node_modules/@raycast/api/node_modules/react": { + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz", + "integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@raycast/eslint-config": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@raycast/eslint-config/-/eslint-config-2.2.0.tgz", + "integrity": "sha512-uS/UDvM+3HfABgYhLYnIv0y+IVu+rGiZZIMwQsO5EGrcf2/TX/yioTzfezAQqhdszW4ViCuHbv8BddIagDKZvQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint/js": "^9.39.4", + "@raycast/eslint-plugin": "^2.2.0", + "eslint-config-prettier": "^10.1.8", + "globals": "^17.7.0", + "typescript-eslint": "^8.62.0" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "prettier": ">=2", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@raycast/eslint-plugin": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@raycast/eslint-plugin/-/eslint-plugin-2.2.0.tgz", + "integrity": "sha512-ixO3PoRAEAZZcSQeRPvvDS/vs09D47tXdyXrs7hctoxxPtweXgJ6I24kjCD5GuuuQS5hGTiuL+Uy6hIg6a/a4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/utils": "^8.62.0" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.4.tgz", + "integrity": "sha512-RrPokAb7dmbxFoeO3TloqHyOjgye8RkBhSqmp4aJMIex4c9r46ZstPnleDQOq1t46VOVjwIuwNogIqbodV1Vvg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.4.tgz", + "integrity": "sha512-JKuJc+pnpks2pjy7L/N3v/cAkZxYlnmuZoD840ldbMI5KDbC4iO9NKwPKYdjYFCMAIIlBzYSFHxIJVYzRo2/8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.4.tgz", + "integrity": "sha512-krw5uS2STmvJ02x0uTXHbqQNuz+9eZ1iw+qXk9dmW2gvV4jV7O2hEoOnuhFrpOPiel1mBFtqbxYZZtC46hXLOw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.4.tgz", + "integrity": "sha512-wsTxtgApb4PrOsNJIm0FZ1h3WvCC+k9uxLJ4ad75hgoS4NiRes2SoJFlDAyMwiUY8IssDqGcHbXuN0sx1tfF1A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.4.tgz", + "integrity": "sha512-GUOnQlyZe3yAXhWOtOMsn5Qkrv5E5mZXa0thbARWi5Ei2szlVXJFQhddZ4HbAzh8q92w5twp+CQvs/eFanz9YQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.4.tgz", + "integrity": "sha512-/Y7f3QuxjzPKsjA/rfEDa3+0vXqyjmJ50Ln8dPpCmWkKTrUoWHG1cWhTqaAMLob2m2nESWuC7yGrREz019Ztqg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.4.tgz", + "integrity": "sha512-81wiiX3v7aqy+T+bT61TJ78yJjRquqFFTTbAPt08imfQQzkPIW8t6aJbkTagtCCrXMNc9D66+geqlK7ydLPNqA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.4.tgz", + "integrity": "sha512-9kmDIvNZqdoHOBZgNtpTBeLWYO/LVipM3H/j62P8848/l/VPEQL6N3uxU9pvP1oZAsXyC2MEnFP3ovRjo7WYNQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.4.tgz", + "integrity": "sha512-CcnXHWnXg69g+DX5VWL3FHts3qMRN2uVEHX+BZvGLdd07/gXkn3ePjYtO1LDJvxkGKVHMclKBRa1QUTH+6toYQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.4.tgz", + "integrity": "sha512-iFOibiHnTRuhrWLlRsOQFdZJJIa7S8OwkneJr4ocALP16u5yk6lWLINFwhHaEqBFMsKDUZofLkGos7+CPzGB3g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.4.tgz", + "integrity": "sha512-XnWYMI7euHlb5a871xPja+Gm7DRCFU+FGRrtS2sMq9N8FvqtpagUy6gD4YOemC5MRk9xbh8+jYMEJbigFQwsgA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.4.tgz", + "integrity": "sha512-qGDAlO0U8xedCcsdRm9oaoQY8DAx/QT7uIxJWhCdx0ceIWX783UC9QSYkdpzAe29wNiVfp24+bZdQmn49o45SQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.4.tgz", + "integrity": "sha512-ru4H6ezD7ysA5EiEK6qkkaEb4modH8CTej6kUy/gQi20u3kB3G7Zn8snXXkeJSCOFKG/rbPPtM/+9Wgas1961w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.4.tgz", + "integrity": "sha512-2W4MO5WQVJnbJaZdvDb9rhBDuFU1nKIepPFpJUBsTh2k1YY2g+ODViaWuyOAjQ5cOP7NvrvLzt3wvHOoiAvc7w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.4.tgz", + "integrity": "sha512-+fxjfuoAmVMCYV5QyjoIpu0cp5DOiOTeqYFk1AVaxGr+/ravWLX89XfQmptsoWcaVy/TGf2hexzbUOrCQIL1CQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.4.tgz", + "integrity": "sha512-jTn8JfHGL4djjFxPuM06LmNUJDsst2jeVlsd9OmIH6zc5sC9K6rIuO4YajXatLUpBmBKl6b35ro1QZocLi+tcA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.4.tgz", + "integrity": "sha512-oCJCJL4pXsoDcP2QZ+JVlPTIRc6266zsIaeJJsWImmF7HO0W8nb6HuSgZlMWxJwaPf8ehbSw8yo0EUw925hKsA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.4.tgz", + "integrity": "sha512-W69hukhZ3KKNRCaMIEzKvcFye42hh0FE1+YoYaf5+Ikacuftoco6yO/xouz0hc5d5W/s3yBro5jRiuEE/Q5vUw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.4.tgz", + "integrity": "sha512-qiXbGG2jkjXhzXpsFZSR2Xpb8DN/UaxYsbb/STbuR/6fpaDgRmmaq1B/LmtF2wQFOFOSsK2jdE0RZ3a0zHn4QA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.4.tgz", + "integrity": "sha512-nWeM//hxv8mIo6jD7Hu4o48DVmV9pbV6gsKaWU+4NFyqHoPKwrkRiZGLKUhOBk8qNmDmpwFtPKg80Bo/Tn4xiQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.4.tgz", + "integrity": "sha512-s62SQ/vgsRSvMwDkOEfTqfgASF0f26ZNaQuTA6Aok5lrikf89yI2W0gFHvZb2Jpgc6N8JnOKZgCK2iciO3CsxQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.4.tgz", + "integrity": "sha512-J6wGf8TVGbXJq+HH+ttTvrcfNKPbuZecV6KT1B8I18BC5IURUh5kl4Yl5OEP5eFIUoI5BWxCsyYMhFsDx8kekw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.4.tgz", + "integrity": "sha512-zmfrQd/0wu6oJs8Vq8KwY/YtsKSsLtKe/HwAP4Wqy8LhWjeT55fHRAkOhYQ12wI3ayS4Tt12d5CDRD7N96SAYQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.4.tgz", + "integrity": "sha512-qPzHqdj9rfUD+w79dtE07zi/kFwKyCJqplp5K5ygeLTp7jLpAoc16OAH39HSmRC9UpozaecsleI8uAdEj6v2yw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.4.tgz", + "integrity": "sha512-zD6NdeWEByGE9QF9vCrlJ5YQB4oq9q91kPZS37Jwj5hOkvR1lTBSpsKhKDw4IJtbQ35LsTS1HD9DZYGKIshU1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.20.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.1.tgz", + "integrity": "sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/react": { + "version": "19.2.18", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.18.tgz", + "integrity": "sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.67.0.tgz", + "integrity": "sha512-Un7Heoyj65NREbKAyIrFxeM143NZpExWmy1Nep4DLeQOeLlTeumPjoNKnBrU5D5moWXbPJgRa5Uwcdu0faVNGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.67.0", + "@typescript-eslint/type-utils": "8.67.0", + "@typescript-eslint/utils": "8.67.0", + "@typescript-eslint/visitor-keys": "8.67.0", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.67.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.6.tgz", + "integrity": "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.67.0.tgz", + "integrity": "sha512-fUBfTuuEulWqX6V8+O3PtScV01tzYYRUDTAirHFKoRAt7nOzoGiPt0M/bB47wWNy0coOOcgEwAMUtBpykMxl6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.67.0", + "@typescript-eslint/types": "8.67.0", + "@typescript-eslint/typescript-estree": "8.67.0", + "@typescript-eslint/visitor-keys": "8.67.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.67.0.tgz", + "integrity": "sha512-cvE8c7ulYeXN9fYuszhCeCsbzyVEXuhrRCybnBre7TUmqb5nRmBfQAwCj0O3WJFDeyAZt4VYv51vMCC9LHSdYw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.67.0", + "@typescript-eslint/types": "^8.67.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.67.0.tgz", + "integrity": "sha512-EgvsleTwS4E+WzzSvem8fAUubLwatMNF1B5hHSLQxcvs7q2dtRhGyujHwLJSYlG41niJ7GP24Aha2+0mb1b2kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.67.0", + "@typescript-eslint/visitor-keys": "8.67.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.67.0.tgz", + "integrity": "sha512-vV+LUSv5njUWsknE71fqKTlXUva+R76SaeORd6Zojcunk/6DvKFXONU3BrAs2H49mbygUXt6gbYunzwqNwlhdg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.67.0.tgz", + "integrity": "sha512-aVWDXbRmdXO9siTfX4ditQI1T9+zVcNazT48EJCD0v40/9RIFoUgZ05CmGEq9H2gixRpjUn/iplwvlcvutJW/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.67.0", + "@typescript-eslint/typescript-estree": "8.67.0", + "@typescript-eslint/utils": "8.67.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.67.0.tgz", + "integrity": "sha512-sBtgslww8nsMYUjhdPBiSyUqSzT8uR6g93A2QXnQC8+cGdjz0CyaOdqHDRJb1AtORbZCNUJBBeFA/tNR2uQmww==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.67.0.tgz", + "integrity": "sha512-EKQBCE9yNlRJYm7jdTW5AhDacDUmSwQb0FAJAmK2EKYrNXIsa2vxcSZx6PvJ/dEdI6lS+Y9W+EXckLj0iPFGcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.67.0", + "@typescript-eslint/tsconfig-utils": "8.67.0", + "@typescript-eslint/types": "8.67.0", + "@typescript-eslint/visitor-keys": "8.67.0", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.67.0.tgz", + "integrity": "sha512-U9D1FdwEWBwok3hxxSdhclMb0twvt9QnjIQ0VfQ1AiX2epnpSgv2ubVDsayOFyY8K6FX+AQ7E0FKWVG3iKsj1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.67.0", + "@typescript-eslint/types": "8.67.0", + "@typescript-eslint/typescript-estree": "8.67.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.67.0.tgz", + "integrity": "sha512-fkv8dHRDqfGtTHuJeebdrQ7cX6Ad4WAS00rgHh9UGvMycF1mjBfsxry1XsLIFhWZ6Judlh6UdzK+TYlbpCXgnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.67.0", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@vitest/expect": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.7.tgz", + "integrity": "sha512-E8eBXaKibuvH2pSZErOjdVb5vF4PbKYcrnluBTYxEk1l/VhhwZg1kZQsdtjq+CsF5CFydf2Rdkz7jDHKSisi3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/spy": "3.2.7", + "@vitest/utils": "3.2.7", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.7.tgz", + "integrity": "sha512-Trr0hYO9CM3Wj6ksWHRhK9IZpIY6wTMO5u/MqXurMxT57sWBaOPEtP3Oq60ihZuh5JsiagKfz95OcxdEP6dBrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "3.2.7", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.17" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.7.tgz", + "integrity": "sha512-KUHlwqVu0sRlhCdyPdQ/wBoTfRahjUky1MubOmYw9fWfIZy1gNoHpuaaQBPAaMaVYdQYHJLurzj8ECCj5OwTqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.7.tgz", + "integrity": "sha512-sB9y4ovltoQP+WaUPwmSxO9WIg9Ig694Di5PalVPsYHklAdE027mehpWF2SQSVq+k6sFgaivbTjTJwZLSHbedA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "3.2.7", + "pathe": "^2.0.3", + "strip-literal": "^3.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.7.tgz", + "integrity": "sha512-7C+MwShwtBSI5Buwoyg3s/iY1eHL9PKAf+O1wVh/TdnjXUtkoL/9YQtre90i4MtNXM6edP1wJ2zOBpfCyhIS7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.7", + "magic-string": "^0.30.17", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.7.tgz", + "integrity": "sha512-Q2eQGI6d2L/hBtZ0qNuKcAGid68XK6cv1xsoaIma6PaJhHPoqcEJhYpXZ/5myCMqkNgtP6UKuBhbc0nHKnrkuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^4.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.7.tgz", + "integrity": "sha512-x6BDOd7dyo3PFLY3I9/HJ25X/6OurhGXk2/B9gOZNPF7XDVjeBK4k01lQE5uvDpbuheErh91qYuE1E2OEjK3Rw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.7", + "loupe": "^3.1.4", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/acorn": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", + "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ansis": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/ansis/-/ansis-3.17.0.tgz", + "integrity": "sha512-0qWUglt9JEqLFr3w1I1pbrChn1grhaiAR2ocX1PP/flRmxgtwTzPFFFnfIlD6aMOLQZgSuCRlidD70lvx8yhzg==", + "license": "ISC", + "engines": { + "node": ">=14" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chai": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chardet": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.2.0.tgz", + "integrity": "sha512-rddelWYNPRrXq6PtNEN2S3f6t9ILzvqaN5pVgi4kqt9jHQaXIial9PznB5iSPVlQSLNaaH22ItWz3EJtQ10+OA==", + "license": "MIT" + }, + "node_modules/check-error": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", + "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "node_modules/clean-stack": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-3.0.1.tgz", + "integrity": "sha512-lR9wNiMRcVQjSB3a7xXGLuz4cr4wJuuXlaAEbRutGowQTmlp7R72/DOgN21e8jdwblMWl9UOJMJXarX94pzKdg==", + "license": "MIT", + "dependencies": { + "escape-string-regexp": "4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "license": "ISC", + "engines": { + "node": ">= 12" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "license": "Apache-2.0", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.39.5", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.5.tgz", + "integrity": "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.2", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.6", + "@eslint/js": "9.39.5", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.5", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-config-prettier": { + "version": "10.1.8", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", + "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "funding": { + "url": "https://opencollective.com/eslint-config-prettier" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expect-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", + "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-3.0.0.tgz", + "integrity": "sha512-hKKNajm46uNmTlhHSyZkmToAc56uZJwYq7yrciZjqOxnlfQwERDQJmHPUp7m1m9wx8vgOe8IaCKZ5Kv2k1DdCQ==", + "license": "MIT", + "dependencies": { + "fastest-levenshtein": "^1.0.7" + } + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "license": "MIT", + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/filelist": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.6.tgz", + "integrity": "sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==", + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz", + "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.4.tgz", + "integrity": "sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "17.10.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.10.0.tgz", + "integrity": "sha512-V0kztuWST2k8A/VbxAY8+L+7+Rgo3fyA24IHRLrZp7HOzJjV0gHSaZUjK9lpP/IrBSNite2tZ1prhRkinRu1CA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/iconv-lite": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz", + "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jake": { + "version": "10.9.4", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", + "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", + "license": "Apache-2.0", + "dependencies": { + "async": "^3.2.6", + "filelist": "^1.0.4", + "picocolors": "^1.1.1" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", + "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/mute-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", + "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.18", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", + "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/optionator/node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.26", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", + "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.17", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.9.6", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.6.tgz", + "integrity": "sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/react": { + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz", + "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/rollup": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.4.tgz", + "integrity": "sha512-RXOqwaPsBGjMNMa4sQjDjHieHEZDFoj/Rdr46l2MU5DfEs16wHJPC2RPTPHWhNl+M3aI472LLqFkFKut4SblOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@napi-rs/lzma-linux-x64-gnu": "1.5.1", + "@rollup/rollup-android-arm-eabi": "4.62.4", + "@rollup/rollup-android-arm64": "4.62.4", + "@rollup/rollup-darwin-arm64": "4.62.4", + "@rollup/rollup-darwin-x64": "4.62.4", + "@rollup/rollup-freebsd-arm64": "4.62.4", + "@rollup/rollup-freebsd-x64": "4.62.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.62.4", + "@rollup/rollup-linux-arm-musleabihf": "4.62.4", + "@rollup/rollup-linux-arm64-gnu": "4.62.4", + "@rollup/rollup-linux-arm64-musl": "4.62.4", + "@rollup/rollup-linux-loong64-gnu": "4.62.4", + "@rollup/rollup-linux-loong64-musl": "4.62.4", + "@rollup/rollup-linux-ppc64-gnu": "4.62.4", + "@rollup/rollup-linux-ppc64-musl": "4.62.4", + "@rollup/rollup-linux-riscv64-gnu": "4.62.4", + "@rollup/rollup-linux-riscv64-musl": "4.62.4", + "@rollup/rollup-linux-s390x-gnu": "4.62.4", + "@rollup/rollup-linux-x64-gnu": "4.62.4", + "@rollup/rollup-linux-x64-musl": "4.62.4", + "@rollup/rollup-openbsd-x64": "4.62.4", + "@rollup/rollup-openharmony-arm64": "4.62.4", + "@rollup/rollup-win32-arm64-msvc": "4.62.4", + "@rollup/rollup-win32-ia32-msvc": "4.62.4", + "@rollup/rollup-win32-x64-gnu": "4.62.4", + "@rollup/rollup-win32-x64-msvc": "4.62.4", + "fsevents": "~2.3.2" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-literal": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz", + "integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^9.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinypool": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/tinyrainbow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", + "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.4.tgz", + "integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.67.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.67.0.tgz", + "integrity": "sha512-S2udFs8tCKEKffuJ4TB1idGUZiXdCPGi3IPBGWXarbLQ5UPXORV8QEVzJ4gCRduURMb5EkpNCdjbk0eDIuI8Yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.67.0", + "@typescript-eslint/parser": "8.67.0", + "@typescript-eslint/typescript-estree": "8.67.0", + "@typescript-eslint/utils": "8.67.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "license": "MIT" + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/vite": { + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.6.tgz", + "integrity": "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0 || ^0.28.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", + "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.4.1", + "es-module-lexer": "^1.7.0", + "pathe": "^2.0.3", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vitest": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.7.tgz", + "integrity": "sha512-KrxIJ62Fd89gfysR4WotlgZABiz2dqFPgqGzX7s+CwsqLFomRH7777ZcrOD6+WVAh7khPQP41A+BKbpcJFrdEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/expect": "3.2.7", + "@vitest/mocker": "3.2.7", + "@vitest/pretty-format": "^3.2.7", + "@vitest/runner": "3.2.7", + "@vitest/snapshot": "3.2.7", + "@vitest/spy": "3.2.7", + "@vitest/utils": "3.2.7", + "chai": "^5.2.0", + "debug": "^4.4.1", + "expect-type": "^1.2.1", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "picomatch": "^4.0.2", + "std-env": "^3.9.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.14", + "tinypool": "^1.1.1", + "tinyrainbow": "^2.0.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", + "vite-node": "3.2.4", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@vitest/browser": "3.2.7", + "@vitest/ui": "3.2.7", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "license": "MIT", + "dependencies": { + "string-width": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yoctocolors-cjs": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz", + "integrity": "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/extensions/agent-night-watch/package.json b/extensions/agent-night-watch/package.json new file mode 100644 index 00000000000..2333c858f52 --- /dev/null +++ b/extensions/agent-night-watch/package.json @@ -0,0 +1,53 @@ +{ + "$schema": "https://www.raycast.com/schemas/extension.json", + "type": "module", + "name": "agent-night-watch", + "title": "Agent Night Watch", + "description": "Manually control closed-lid sleep from the Raycast menu bar", + "icon": "coffee-on.png", + "author": "yhu575361", + "license": "MIT", + "scripts": { + "build": "ray build -e dist", + "dev": "ray develop", + "fix-lint": "ray lint --fix", + "lint": "ray lint", + "publish": "npx @raycast/api@latest publish", + "test": "vitest run && /bin/sh -n assets/night-watch-guard.sh" + }, + "platforms": ["macOS"], + "categories": ["System"], + "keywords": ["agent", "awake", "closed lid", "clamshell", "coffee", "sleep"], + "dependencies": { + "@raycast/api": "^1.104.24", + "react": "^19.0.0" + }, + "devDependencies": { + "@raycast/eslint-config": "^2.2.0", + "@types/node": "^22.18.0", + "@types/react": "^19.1.0", + "eslint": "^9.34.0", + "prettier": "^3.6.2", + "typescript": "^5.9.2", + "vitest": "^3.2.4" + }, + "commands": [ + { + "name": "toggle-night-watch", + "title": "Toggle Night Watch", + "subtitle": "Agent Night Watch", + "description": "Manually enable or disable closed-lid awake mode", + "icon": "coffee-on.png", + "mode": "no-view" + }, + { + "name": "night-watch-menu", + "title": "Night Watch Menu Bar", + "subtitle": "Agent Night Watch", + "description": "Show and control closed-lid awake status in the menu bar", + "icon": "coffee-off.png", + "mode": "menu-bar", + "interval": "1m" + } + ] +} diff --git a/extensions/agent-night-watch/src/night-watch-menu.tsx b/extensions/agent-night-watch/src/night-watch-menu.tsx new file mode 100644 index 00000000000..47c27e38950 --- /dev/null +++ b/extensions/agent-night-watch/src/night-watch-menu.tsx @@ -0,0 +1,133 @@ +import { + Alert, + Color, + Icon, + MenuBarExtra, + Toast, + confirmAlert, + showToast, +} from "@raycast/api"; +import { useCallback, useEffect, useState } from "react"; +import { + NightWatchError, + forceRestoreSleep, + getNightWatchStatus, + startNightWatch, + stopNightWatch, +} from "./night-watch"; +import { NightWatchStatus } from "./status"; + +const OFF_ICON = { source: "coffee-off.png", tintColor: Color.PrimaryText }; +const ON_ICON = { source: "coffee-on.png", tintColor: Color.PrimaryText }; + +export default function Command() { + const [status, setStatus] = useState(); + const [isLoading, setIsLoading] = useState(true); + + const refresh = useCallback(async () => { + try { + setStatus(await getNightWatchStatus()); + } finally { + setIsLoading(false); + } + }, []); + + useEffect(() => { + void refresh(); + }, [refresh]); + + const run = useCallback( + async (operation: () => Promise, successTitle: string) => { + setIsLoading(true); + try { + await operation(); + await showToast({ style: Toast.Style.Success, title: successTitle }); + } catch (error) { + await showToast({ + style: Toast.Style.Failure, + title: "Action Not Completed", + message: + error instanceof NightWatchError ? error.message : String(error), + }); + } finally { + await refresh(); + } + }, + [refresh], + ); + + const isOn = status?.sleepDisabled ?? false; + const isTransitioning = + status?.kind === "starting" || status?.kind === "stopping"; + const tooltip = status + ? `Agent Night Watch: ${status.message}` + : "Reading Agent Night Watch status"; + + return ( + + + + + {status?.kind === "off" ? ( + + void run(startNightWatch, "☕ Agent Night Watch Enabled") + } + /> + ) : null} + + {status?.kind === "on-owned" ? ( + + void run(stopNightWatch, "Agent Night Watch Disabled") + } + /> + ) : null} + + {status?.kind === "on-external" ? ( + { + const confirmed = await confirmAlert({ + title: "Restore Normal System Sleep?", + message: + "The current sleep-disabled state is not owned by Agent Night Watch. Continuing runs pmset disablesleep 0 and may override another tool.", + primaryAction: { + title: "Restore Normal Sleep", + style: Alert.ActionStyle.Destructive, + }, + }); + if (confirmed) + await run(forceRestoreSleep, "Normal System Sleep Restored"); + }} + /> + ) : null} + + {isTransitioning ? ( + + ) : null} + + + void refresh()} + /> + + ); +} diff --git a/extensions/agent-night-watch/src/night-watch.ts b/extensions/agent-night-watch/src/night-watch.ts new file mode 100644 index 00000000000..d0d94277742 --- /dev/null +++ b/extensions/agent-night-watch/src/night-watch.ts @@ -0,0 +1,429 @@ +import { environment } from "@raycast/api"; +import { execFile, spawn } from "node:child_process"; +import { homedir } from "node:os"; +import path from "node:path"; +import { + closeSync, + copyFileSync, + existsSync, + mkdirSync, + mkdtempSync, + openSync, + readFileSync, + rmSync, + statSync, + writeFileSync, +} from "node:fs"; +import { promisify } from "node:util"; +import { + NightWatchStatus, + SessionPhase, + classifyNightWatchStatus, + parseSleepDisabled, + isAuthorizationCanceled, + statusMessage, +} from "./status"; + +const execFileAsync = promisify(execFile); +const CACHE_DIR = path.join( + homedir(), + "Library", + "Caches", + "com.yuchen.agent-night-watch", +); +const STATE_FILE = path.join(CACHE_DIR, "session.json"); +const LEGACY_STATE_FILE = path.join(CACHE_DIR, "session"); +const LOCK_DIR = path.join(CACHE_DIR, "toggle.lock"); +const SESSION_PREFIX = path.join(CACHE_DIR, "session."); +const START_TIMEOUT_MS = 120_000; +const STOP_TIMEOUT_MS = 8_000; + +interface SessionState { + version: 2; + launcherPid: number; + sessionDir: string; + startedAt: string; + phase: SessionPhase; +} + +export class NightWatchError extends Error { + constructor(message: string) { + super(message); + this.name = "NightWatchError"; + } +} + +function delay(milliseconds: number): Promise { + return new Promise((resolve) => setTimeout(resolve, milliseconds)); +} + +function shellQuote(value: string): string { + return `'${value.replaceAll("'", `'\\''`)}'`; +} + +function appleScriptQuote(value: string): string { + return value.replaceAll("\\", "\\\\").replaceAll('"', '\\"'); +} + +function installGuardScript(sessionDir: string): string { + const source = path.join(environment.assetsPath, "night-watch-guard.sh"); + const target = path.join(sessionDir, "night-watch-guard.sh"); + copyFileSync(source, target); + return target; +} + +function ensureCacheDirectory(): void { + mkdirSync(CACHE_DIR, { recursive: true, mode: 0o700 }); +} + +function isSessionDirectory(candidate: string): boolean { + return ( + path.dirname(candidate) === CACHE_DIR && + path.basename(candidate).startsWith("session.") + ); +} + +function removeSessionFiles(sessionDir?: string): void { + rmSync(STATE_FILE, { force: true }); + if (sessionDir && isSessionDirectory(sessionDir)) { + rmSync(sessionDir, { recursive: true, force: true }); + } +} + +function readSessionState(): SessionState | undefined { + try { + const state = JSON.parse( + readFileSync(STATE_FILE, "utf8"), + ) as Partial; + if ( + state.version !== 2 || + !Number.isInteger(state.launcherPid) || + (state.launcherPid ?? 0) <= 1 || + typeof state.sessionDir !== "string" || + !isSessionDirectory(state.sessionDir) || + typeof state.startedAt !== "string" || + !["starting", "running", "stopping"].includes(state.phase ?? "") + ) { + return undefined; + } + return state as SessionState; + } catch { + return undefined; + } +} + +function writeSessionState(state: SessionState): void { + ensureCacheDirectory(); + writeFileSync(STATE_FILE, `${JSON.stringify(state, null, 2)}\n`, { + mode: 0o600, + }); +} + +function isProcessAlive(pid: number): boolean { + try { + process.kill(pid, 0); + return true; + } catch { + return false; + } +} + +async function processMatchesSession(state: SessionState): Promise { + if (!isProcessAlive(state.launcherPid)) return false; + try { + const { stdout } = await execFileAsync("/bin/ps", [ + "-ww", + "-p", + String(state.launcherPid), + "-o", + "command=", + ]); + return stdout.includes("osascript") && stdout.includes(state.sessionDir); + } catch { + return false; + } +} + +async function sleepIsDisabled(): Promise { + const { stdout } = await execFileAsync("/usr/bin/pmset", ["-g"]); + return parseSleepDisabled(stdout); +} + +function cleanLegacyStateIfSafe(disabled: boolean): void { + if (disabled || !existsSync(LEGACY_STATE_FILE)) return; + try { + const [pidText, sessionDir] = readFileSync(LEGACY_STATE_FILE, "utf8") + .trim() + .split("\n"); + const pid = Number(pidText); + if (Number.isInteger(pid) && pid > 1 && isProcessAlive(pid)) return; + rmSync(LEGACY_STATE_FILE, { force: true }); + if (sessionDir && isSessionDirectory(sessionDir)) { + rmSync(sessionDir, { recursive: true, force: true }); + } + } catch { + // A malformed legacy cache is non-authoritative and can be left alone. + } +} + +export async function getNightWatchStatus(): Promise { + ensureCacheDirectory(); + const disabled = await sleepIsDisabled(); + cleanLegacyStateIfSafe(disabled); + const state = readSessionState(); + + if (!state) { + if (existsSync(STATE_FILE)) removeSessionFiles(); + const kind = classifyNightWatchStatus({ + sleepDisabled: disabled, + statePresent: false, + processMatches: false, + ready: false, + stopped: false, + stopRequested: false, + }); + return { kind, sleepDisabled: disabled, message: statusMessage(kind) }; + } + + const processMatches = await processMatchesSession(state); + const ready = existsSync(path.join(state.sessionDir, "ready")); + const stopped = existsSync(path.join(state.sessionDir, "stopped")); + const stopRequested = existsSync(path.join(state.sessionDir, "stop")); + + const kind = classifyNightWatchStatus({ + sleepDisabled: disabled, + statePresent: true, + processMatches, + ready, + stopped, + stopRequested, + phase: state.phase, + }); + + if (kind === "on-owned" && state.phase !== "running") { + writeSessionState({ ...state, phase: "running" }); + } + if (kind === "off" || kind === "on-external") { + removeSessionFiles(state.sessionDir); + } + return { kind, sleepDisabled: disabled, message: statusMessage(kind) }; +} + +async function acquireLock(): Promise<() => void> { + ensureCacheDirectory(); + for (let attempt = 0; attempt < 50; attempt += 1) { + try { + mkdirSync(LOCK_DIR, { mode: 0o700 }); + writeFileSync(path.join(LOCK_DIR, "owner"), `${process.pid}\n`, { + mode: 0o600, + }); + return () => rmSync(LOCK_DIR, { recursive: true, force: true }); + } catch { + try { + if (Date.now() - statSync(LOCK_DIR).mtimeMs > 180_000) { + rmSync(LOCK_DIR, { recursive: true, force: true }); + continue; + } + } catch { + continue; + } + await delay(100); + } + } + throw new NightWatchError( + "Another Night Watch toggle is still running. Try again shortly.", + ); +} + +async function withToggleLock(operation: () => Promise): Promise { + const release = await acquireLock(); + try { + return await operation(); + } finally { + release(); + } +} + +function readLogTail(logPath: string): string { + try { + const lines = readFileSync(logPath, "utf8").trim().split("\n"); + return lines.at(-1) ?? ""; + } catch { + return ""; + } +} + +async function startNightWatchUnlocked(): Promise { + const current = await getNightWatchStatus(); + if (current.kind === "on-owned") return; + if (current.kind === "starting" || current.kind === "stopping") { + throw new NightWatchError( + "Night Watch is already changing state. Try again shortly.", + ); + } + if (current.kind === "on-external") { + throw new NightWatchError( + "Sleep is already disabled by another tool. Use the coffee-cup menu to review it.", + ); + } + + const sessionDir = mkdtempSync(SESSION_PREFIX); + const logPath = path.join(sessionDir, "guard.log"); + const logFd = openSync(logPath, "a", 0o600); + const guardPath = installGuardScript(sessionDir); + const rootCommand = `/bin/sh ${shellQuote(guardPath)} ${shellQuote(sessionDir)}`; + const script = `with timeout of 2147483647 seconds\n do shell script "${appleScriptQuote(rootCommand)}" with administrator privileges\nend timeout`; + const child = spawn("/usr/bin/osascript", ["-e", script], { + detached: true, + stdio: ["ignore", logFd, logFd], + }); + closeSync(logFd); + + if (!child.pid) { + removeSessionFiles(sessionDir); + throw new NightWatchError( + "Could not start the administrator authorization process.", + ); + } + child.unref(); + + const state: SessionState = { + version: 2, + launcherPid: child.pid, + sessionDir, + startedAt: new Date().toISOString(), + phase: "starting", + }; + writeSessionState(state); + + const startedAt = Date.now(); + while (Date.now() - startedAt < START_TIMEOUT_MS) { + if ( + existsSync(path.join(sessionDir, "ready")) && + (await sleepIsDisabled()) + ) { + writeSessionState({ ...state, phase: "running" }); + return; + } + if (!isProcessAlive(child.pid)) break; + await delay(100); + } + + if (isProcessAlive(child.pid)) { + try { + process.kill(child.pid, "SIGTERM"); + } catch { + // The authorization process may have exited between checks. + } + } + for (let attempt = 0; attempt < 50 && (await sleepIsDisabled()); attempt += 1) + await delay(100); + + const errorTail = readLogTail(logPath); + if (!(await sleepIsDisabled())) removeSessionFiles(sessionDir); + if (isAuthorizationCanceled(errorTail)) { + throw new NightWatchError( + "Not enabled: administrator authorization was canceled.", + ); + } + throw new NightWatchError( + errorTail + ? `Not enabled: ${errorTail}` + : "Not enabled: administrator authorization was not granted.", + ); +} + +async function stopNightWatchUnlocked(): Promise { + const current = await getNightWatchStatus(); + if (current.kind === "off") return; + if (current.kind === "on-external") { + throw new NightWatchError( + "This state was not created by Agent Night Watch. Use Restore Normal Sleep from the menu.", + ); + } + if (current.kind === "starting") { + throw new NightWatchError( + "Administrator authorization is still open. Complete or cancel it first.", + ); + } + + const state = readSessionState(); + if (!state) + throw new NightWatchError( + "The owned Night Watch session was not found. System state was not changed.", + ); + writeSessionState({ ...state, phase: "stopping" }); + writeFileSync(path.join(state.sessionDir, "reason"), "manual\n", { + mode: 0o600, + }); + writeFileSync(path.join(state.sessionDir, "stop"), "\n", { mode: 0o600 }); + + const startedAt = Date.now(); + while (Date.now() - startedAt < STOP_TIMEOUT_MS) { + const disabled = await sleepIsDisabled(); + if (!disabled && existsSync(path.join(state.sessionDir, "stopped"))) { + removeSessionFiles(state.sessionDir); + return; + } + await delay(100); + } + + if (!(await sleepIsDisabled())) { + removeSessionFiles(state.sessionDir); + return; + } + throw new NightWatchError( + "Night Watch did not stop: sleep is still disabled. Use the coffee-cup menu to recover.", + ); +} + +export async function startNightWatch(): Promise { + await withToggleLock(startNightWatchUnlocked); +} + +export async function stopNightWatch(): Promise { + await withToggleLock(stopNightWatchUnlocked); +} + +export async function toggleNightWatch(): Promise<"on" | "off"> { + return withToggleLock(async () => { + const current = await getNightWatchStatus(); + if (current.kind === "off") { + await startNightWatchUnlocked(); + return "on"; + } + if (current.kind === "on-owned") { + await stopNightWatchUnlocked(); + return "off"; + } + if (current.kind === "on-external") { + throw new NightWatchError( + "Sleep is disabled by another tool or leftover state. Review it from the coffee-cup menu.", + ); + } + throw new NightWatchError( + "Night Watch is already changing state. Try again shortly.", + ); + }); +} + +export async function forceRestoreSleep(): Promise { + await withToggleLock(async () => { + const command = "/usr/bin/pmset -a disablesleep 0"; + const script = `do shell script "${appleScriptQuote(command)}" with administrator privileges`; + try { + await execFileAsync("/usr/bin/osascript", ["-e", script]); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + if (isAuthorizationCanceled(message)) + throw new NightWatchError("Restore canceled."); + throw new NightWatchError(`Restore failed: ${message}`); + } + if (await sleepIsDisabled()) + throw new NightWatchError( + "The administrator command completed, but sleep is still disabled.", + ); + const state = readSessionState(); + removeSessionFiles(state?.sessionDir); + }); +} diff --git a/extensions/agent-night-watch/src/status.ts b/extensions/agent-night-watch/src/status.ts new file mode 100644 index 00000000000..a6e6486753f --- /dev/null +++ b/extensions/agent-night-watch/src/status.ts @@ -0,0 +1,71 @@ +export type StatusKind = + "off" | "starting" | "on-owned" | "stopping" | "on-external"; +export type SessionPhase = "starting" | "running" | "stopping"; + +export interface NightWatchStatus { + kind: StatusKind; + sleepDisabled: boolean; + message: string; +} + +export interface StatusSnapshot { + sleepDisabled: boolean; + statePresent: boolean; + processMatches: boolean; + ready: boolean; + stopped: boolean; + stopRequested: boolean; + phase?: SessionPhase; +} + +export function parseSleepDisabled(pmsetOutput: string): boolean { + return /^\s*SleepDisabled\s+1\s*$/m.test(pmsetOutput); +} + +export function classifyNightWatchStatus(snapshot: StatusSnapshot): StatusKind { + if (!snapshot.statePresent) { + return snapshot.sleepDisabled ? "on-external" : "off"; + } + + if (!snapshot.sleepDisabled) { + return snapshot.phase === "starting" && + snapshot.processMatches && + !snapshot.stopped + ? "starting" + : "off"; + } + + if (snapshot.processMatches && snapshot.ready) { + return snapshot.phase === "stopping" || snapshot.stopRequested + ? "stopping" + : "on-owned"; + } + + if ( + snapshot.processMatches && + snapshot.phase === "starting" && + !snapshot.stopped + ) { + return "starting"; + } + return "on-external"; +} + +export function statusMessage(kind: StatusKind): string { + switch (kind) { + case "off": + return "Off — closing the lid will sleep normally"; + case "starting": + return "Waiting for administrator authorization"; + case "on-owned": + return "On — agents keep running with the lid closed"; + case "stopping": + return "Restoring normal sleep"; + case "on-external": + return "Sleep is disabled by another tool or leftover state"; + } +} + +export function isAuthorizationCanceled(message: string): boolean { + return /User canceled|用户取消|-128/.test(message); +} diff --git a/extensions/agent-night-watch/src/toggle-night-watch.ts b/extensions/agent-night-watch/src/toggle-night-watch.ts new file mode 100644 index 00000000000..4eff01ec720 --- /dev/null +++ b/extensions/agent-night-watch/src/toggle-night-watch.ts @@ -0,0 +1,35 @@ +import { LaunchType, Toast, launchCommand, showToast } from "@raycast/api"; +import { NightWatchError, toggleNightWatch } from "./night-watch"; + +export default async function Command() { + const toast = await showToast({ + style: Toast.Style.Animated, + title: "Toggling Agent Night Watch…", + }); + try { + const result = await toggleNightWatch(); + toast.style = Toast.Style.Success; + toast.title = + result === "on" + ? "☕ Agent Night Watch Enabled" + : "Agent Night Watch Disabled"; + toast.message = + result === "on" + ? "Agents keep running with the lid closed; the display may still turn off." + : "Closing the lid now restores normal sleep."; + } catch (error) { + toast.style = Toast.Style.Failure; + toast.title = "Could Not Toggle Agent Night Watch"; + toast.message = + error instanceof NightWatchError ? error.message : String(error); + } finally { + try { + await launchCommand({ + name: "night-watch-menu", + type: LaunchType.Background, + }); + } catch { + // The menu command may not have been enabled yet during first-time setup. + } + } +} diff --git a/extensions/agent-night-watch/tests/status.test.ts b/extensions/agent-night-watch/tests/status.test.ts new file mode 100644 index 00000000000..10ae911f702 --- /dev/null +++ b/extensions/agent-night-watch/tests/status.test.ts @@ -0,0 +1,136 @@ +import { describe, expect, it } from "vitest"; +import { + classifyNightWatchStatus, + isAuthorizationCanceled, + parseSleepDisabled, + statusMessage, +} from "../src/status"; + +describe("parseSleepDisabled", () => { + it("detects an enabled system-wide setting", () => { + expect(parseSleepDisabled("System-wide power settings:\n SleepDisabled\t\t1\n")).toBe(true); + }); + + it("detects a disabled system-wide setting", () => { + expect(parseSleepDisabled("System-wide power settings:\n SleepDisabled\t\t0\n")).toBe(false); + }); + + it("does not confuse unrelated values with SleepDisabled", () => { + expect(parseSleepDisabled(" sleep 1 (sleep prevented by powerd)\n")).toBe(false); + }); +}); + +describe("statusMessage", () => { + it("provides a message for every lifecycle state", () => { + for (const kind of ["off", "starting", "on-owned", "stopping", "on-external"] as const) { + expect(statusMessage(kind)).not.toHaveLength(0); + } + }); +}); + +describe("isAuthorizationCanceled", () => { + it("recognizes macOS cancellation responses without treating other failures as cancellation", () => { + expect(isAuthorizationCanceled("execution error: User canceled. (-128)")).toBe(true); + expect(isAuthorizationCanceled("用户取消了授权 (-128)")).toBe(true); + expect(isAuthorizationCanceled("pmset exited with status 1")).toBe(false); + }); +}); + +describe("classifyNightWatchStatus", () => { + const base = { + sleepDisabled: false, + statePresent: false, + processMatches: false, + ready: false, + stopped: false, + stopRequested: false, + }; + + it("treats pmset as authoritative without an owned session", () => { + expect(classifyNightWatchStatus(base)).toBe("off"); + expect( + classifyNightWatchStatus({ ...base, sleepDisabled: true }), + ).toBe("on-external"); + }); + + it("recognizes an owned running session", () => { + expect( + classifyNightWatchStatus({ + ...base, + sleepDisabled: true, + statePresent: true, + processMatches: true, + ready: true, + phase: "running", + }), + ).toBe("on-owned"); + }); + + it("recognizes starting and stopping transitions", () => { + expect( + classifyNightWatchStatus({ + ...base, + statePresent: true, + processMatches: true, + phase: "starting", + }), + ).toBe("starting"); + expect( + classifyNightWatchStatus({ + ...base, + sleepDisabled: true, + statePresent: true, + processMatches: true, + ready: true, + stopRequested: true, + phase: "stopping", + }), + ).toBe("stopping"); + }); + + it("keeps a stopping session visible until pmset confirms normal sleep", () => { + expect( + classifyNightWatchStatus({ + ...base, + sleepDisabled: true, + statePresent: true, + processMatches: true, + ready: true, + phase: "stopping", + }), + ).toBe("stopping"); + }); + + it("does not claim ownership before the privileged guard is ready", () => { + expect( + classifyNightWatchStatus({ + ...base, + sleepDisabled: true, + statePresent: true, + processMatches: true, + ready: false, + phase: "starting", + }), + ).toBe("starting"); + }); + + it("does not trust a stale PID or stale cache", () => { + expect( + classifyNightWatchStatus({ + ...base, + sleepDisabled: true, + statePresent: true, + ready: true, + phase: "running", + }), + ).toBe("on-external"); + expect( + classifyNightWatchStatus({ + ...base, + statePresent: true, + ready: true, + phase: "running", + }), + ).toBe("off"); + }); +}); diff --git a/extensions/agent-night-watch/tsconfig.json b/extensions/agent-night-watch/tsconfig.json new file mode 100644 index 00000000000..6435f5ad756 --- /dev/null +++ b/extensions/agent-night-watch/tsconfig.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "compilerOptions": { + "lib": ["ES2023"], + "module": "ESNext", + "target": "ES2022", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "moduleResolution": "Bundler", + "resolveJsonModule": true, + "jsx": "react-jsx", + "noEmit": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "tests/**/*.ts"] +} From 86b642b551424d56656465290902865edd74c2d6 Mon Sep 17 00:00:00 2001 From: Yuchen07569 <296913685+Yuchen07569@users.noreply.github.com> Date: Thu, 13 Aug 2026 14:54:31 +0800 Subject: [PATCH 2/5] fix: recover abandoned toggle locks --- extensions/agent-night-watch/CHANGELOG.md | 6 +++ .../agent-night-watch/src/night-watch.ts | 40 +++++++++++++++---- .../agent-night-watch/src/toggle-lock.ts | 30 ++++++++++++++ .../tests/toggle-lock.test.ts | 30 ++++++++++++++ 4 files changed, 99 insertions(+), 7 deletions(-) create mode 100644 extensions/agent-night-watch/src/toggle-lock.ts create mode 100644 extensions/agent-night-watch/tests/toggle-lock.test.ts diff --git a/extensions/agent-night-watch/CHANGELOG.md b/extensions/agent-night-watch/CHANGELOG.md index 131d5a7cf54..d3ac2dd531c 100644 --- a/extensions/agent-night-watch/CHANGELOG.md +++ b/extensions/agent-night-watch/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [Fixed Lock Recovery] - {PR_MERGE_DATE} + +- Fixed an abandoned toggle lock that could block both the hotkey and menu from + disabling Night Watch. +- Added token-checked lock release and prompt stale-lock recovery. + ## [Initial Version] - {PR_MERGE_DATE} - Add a menu-bar coffee cup for closed-lid awake status. diff --git a/extensions/agent-night-watch/src/night-watch.ts b/extensions/agent-night-watch/src/night-watch.ts index d0d94277742..73803f01adb 100644 --- a/extensions/agent-night-watch/src/night-watch.ts +++ b/extensions/agent-night-watch/src/night-watch.ts @@ -1,5 +1,6 @@ import { environment } from "@raycast/api"; import { execFile, spawn } from "node:child_process"; +import { randomUUID } from "node:crypto"; import { homedir } from "node:os"; import path from "node:path"; import { @@ -23,6 +24,12 @@ import { isAuthorizationCanceled, statusMessage, } from "./status"; +import { + LOCK_STALE_AFTER_MS, + lockLeaseExpired, + parseLockOwnerToken, + serializeLockOwner, +} from "./toggle-lock"; const execFileAsync = promisify(execFile); const CACHE_DIR = path.join( @@ -211,16 +218,35 @@ export async function getNightWatchStatus(): Promise { async function acquireLock(): Promise<() => void> { ensureCacheDirectory(); - for (let attempt = 0; attempt < 50; attempt += 1) { + const token = randomUUID(); + const ownerPath = path.join(LOCK_DIR, "owner"); + for (let attempt = 0; attempt < 70; attempt += 1) { try { mkdirSync(LOCK_DIR, { mode: 0o700 }); - writeFileSync(path.join(LOCK_DIR, "owner"), `${process.pid}\n`, { - mode: 0o600, - }); - return () => rmSync(LOCK_DIR, { recursive: true, force: true }); + writeFileSync( + ownerPath, + serializeLockOwner({ + version: 1, + pid: process.pid, + token, + acquiredAt: new Date().toISOString(), + }), + { mode: 0o600 }, + ); + return () => { + try { + if (parseLockOwnerToken(readFileSync(ownerPath, "utf8")) === token) + rmSync(LOCK_DIR, { recursive: true, force: true }); + } catch { + // A newer operation may already own the lock. + } + }; } catch { try { - if (Date.now() - statSync(LOCK_DIR).mtimeMs > 180_000) { + const lockModifiedAt = existsSync(ownerPath) + ? statSync(ownerPath).mtimeMs + : statSync(LOCK_DIR).mtimeMs; + if (lockLeaseExpired(lockModifiedAt)) { rmSync(LOCK_DIR, { recursive: true, force: true }); continue; } @@ -231,7 +257,7 @@ async function acquireLock(): Promise<() => void> { } } throw new NightWatchError( - "Another Night Watch toggle is still running. Try again shortly.", + `Another Night Watch toggle is still running. Try again in ${Math.ceil(LOCK_STALE_AFTER_MS / 1000)} seconds.`, ); } diff --git a/extensions/agent-night-watch/src/toggle-lock.ts b/extensions/agent-night-watch/src/toggle-lock.ts new file mode 100644 index 00000000000..fbc1f0a85f4 --- /dev/null +++ b/extensions/agent-night-watch/src/toggle-lock.ts @@ -0,0 +1,30 @@ +export const LOCK_STALE_AFTER_MS = 5_000; + +interface LockOwner { + version: 1; + pid: number; + token: string; + acquiredAt: string; +} + +export function serializeLockOwner(owner: LockOwner): string { + return `${JSON.stringify(owner)}\n`; +} + +export function parseLockOwnerToken(contents: string): string | undefined { + try { + const parsed = JSON.parse(contents) as Partial; + return parsed.version === 1 && typeof parsed.token === "string" + ? parsed.token + : undefined; + } catch { + return undefined; + } +} + +export function lockLeaseExpired( + modifiedAtMs: number, + nowMs = Date.now(), +): boolean { + return nowMs - modifiedAtMs >= LOCK_STALE_AFTER_MS; +} diff --git a/extensions/agent-night-watch/tests/toggle-lock.test.ts b/extensions/agent-night-watch/tests/toggle-lock.test.ts new file mode 100644 index 00000000000..04c724e6613 --- /dev/null +++ b/extensions/agent-night-watch/tests/toggle-lock.test.ts @@ -0,0 +1,30 @@ +import { describe, expect, it } from "vitest"; +import { + LOCK_STALE_AFTER_MS, + lockLeaseExpired, + parseLockOwnerToken, + serializeLockOwner, +} from "../src/toggle-lock"; + +describe("toggle lock lease", () => { + it("round-trips the unique owner token", () => { + const contents = serializeLockOwner({ + version: 1, + pid: 42, + token: "operation-a", + acquiredAt: "2026-08-13T00:00:00.000Z", + }); + + expect(parseLockOwnerToken(contents)).toBe("operation-a"); + }); + + it("does not trust the legacy long-lived Raycast backend PID format", () => { + expect(parseLockOwnerToken("69240\n")).toBeUndefined(); + }); + + it("reclaims an abandoned lease promptly but not an active lease", () => { + const now = 100_000; + expect(lockLeaseExpired(now - LOCK_STALE_AFTER_MS + 1, now)).toBe(false); + expect(lockLeaseExpired(now - LOCK_STALE_AFTER_MS, now)).toBe(true); + }); +}); From ef0d155969e47afda9fab5746778adb75c08443e Mon Sep 17 00:00:00 2001 From: Yuchen07569 <296913685+Yuchen07569@users.noreply.github.com> Date: Thu, 13 Aug 2026 15:03:17 +0800 Subject: [PATCH 3/5] fix: keep menu-bar icon synchronized --- extensions/agent-night-watch/CHANGELOG.md | 7 +++++++ .../agent-night-watch/src/night-watch-menu.tsx | 3 +++ .../agent-night-watch/tests/menu-refresh.test.ts | 16 ++++++++++++++++ 3 files changed, 26 insertions(+) create mode 100644 extensions/agent-night-watch/tests/menu-refresh.test.ts diff --git a/extensions/agent-night-watch/CHANGELOG.md b/extensions/agent-night-watch/CHANGELOG.md index d3ac2dd531c..64e0d949100 100644 --- a/extensions/agent-night-watch/CHANGELOG.md +++ b/extensions/agent-night-watch/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [Fixed Live Menu Status] - {PR_MERGE_DATE} + +- Fixed the steaming menu-bar icon remaining visible after normal sleep had + already been restored. +- Added live `SleepDisabled` calibration while Raycast keeps the menu command + loaded. + ## [Fixed Lock Recovery] - {PR_MERGE_DATE} - Fixed an abandoned toggle lock that could block both the hotkey and menu from diff --git a/extensions/agent-night-watch/src/night-watch-menu.tsx b/extensions/agent-night-watch/src/night-watch-menu.tsx index 47c27e38950..2aa4859cc72 100644 --- a/extensions/agent-night-watch/src/night-watch-menu.tsx +++ b/extensions/agent-night-watch/src/night-watch-menu.tsx @@ -19,6 +19,7 @@ import { NightWatchStatus } from "./status"; const OFF_ICON = { source: "coffee-off.png", tintColor: Color.PrimaryText }; const ON_ICON = { source: "coffee-on.png", tintColor: Color.PrimaryText }; +const LIVE_STATUS_INTERVAL_MS = 2_000; export default function Command() { const [status, setStatus] = useState(); @@ -34,6 +35,8 @@ export default function Command() { useEffect(() => { void refresh(); + const interval = setInterval(() => void refresh(), LIVE_STATUS_INTERVAL_MS); + return () => clearInterval(interval); }, [refresh]); const run = useCallback( diff --git a/extensions/agent-night-watch/tests/menu-refresh.test.ts b/extensions/agent-night-watch/tests/menu-refresh.test.ts new file mode 100644 index 00000000000..332eb79a0cb --- /dev/null +++ b/extensions/agent-night-watch/tests/menu-refresh.test.ts @@ -0,0 +1,16 @@ +import { describe, expect, it } from "vitest"; +import { readFileSync } from "node:fs"; +import path from "node:path"; + +describe("menu-bar status refresh", () => { + it("keeps a loaded Raycast menu command synchronized with system truth", () => { + const source = readFileSync( + path.join(process.cwd(), "src", "night-watch-menu.tsx"), + "utf8", + ); + + expect(source).toContain("LIVE_STATUS_INTERVAL_MS = 2_000"); + expect(source).toContain("setInterval(() => void refresh()"); + expect(source).toContain("clearInterval(interval)"); + }); +}); From 5c2e6d700a75217c35ffd34a62b39a9741fb5849 Mon Sep 17 00:00:00 2001 From: Yuchen07569 <296913685+Yuchen07569@users.noreply.github.com> Date: Thu, 13 Aug 2026 15:32:09 +0800 Subject: [PATCH 4/5] Update agent-night-watch extension - fix: allow repeated menu bar toggles - feat: toggle directly from menu bar cup --- extensions/agent-night-watch/CHANGELOG.md | 8 + extensions/agent-night-watch/README.md | 11 +- .../agent-night-watch/src/menu-bar-click.ts | 32 +++ .../src/night-watch-menu.tsx | 193 ++++++++++-------- .../tests/menu-bar-click.test.ts | 71 +++++++ .../tests/menu-refresh.test.ts | 16 -- 6 files changed, 226 insertions(+), 105 deletions(-) create mode 100644 extensions/agent-night-watch/src/menu-bar-click.ts create mode 100644 extensions/agent-night-watch/tests/menu-bar-click.test.ts delete mode 100644 extensions/agent-night-watch/tests/menu-refresh.test.ts diff --git a/extensions/agent-night-watch/CHANGELOG.md b/extensions/agent-night-watch/CHANGELOG.md index 64e0d949100..545f976b814 100644 --- a/extensions/agent-night-watch/CHANGELOG.md +++ b/extensions/agent-night-watch/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [Direct Coffee-Cup Toggle] - {PR_MERGE_DATE} + +- Click the coffee cup once to toggle Night Watch directly in normal states. +- Keep external ownership and transition states behind a safe recovery menu. +- Remove continuous two-second polling and redraw after completed operations. +- Release duplicate-mount suppression after one second so later clicks are not + mistaken for the previous background refresh. + ## [Fixed Live Menu Status] - {PR_MERGE_DATE} - Fixed the steaming menu-bar icon remaining visible after normal sleep had diff --git a/extensions/agent-night-watch/README.md b/extensions/agent-night-watch/README.md index 153c8e4dfaf..a9e20775e05 100644 --- a/extensions/agent-night-watch/README.md +++ b/extensions/agent-night-watch/README.md @@ -5,6 +5,7 @@ switch in the Raycast menu bar. - Empty cup: normal closed-lid sleep. - Steaming cup: Agent Night Watch is active. +- Click the cup once to toggle directly during normal operation. - Enabling asks for macOS administrator authorization every time. - Disabling an owned session does not ask again. - The display can still turn off according to macOS settings. @@ -14,10 +15,10 @@ closed-lid `SleepDisabled` setting and reads it back before reporting success. ## Setup -1. Enable **Night Watch Menu Bar** to keep the coffee cup visible. +1. Run **Night Watch Menu Bar** once to keep the coffee cup visible. 2. Optionally assign `⌥S` to **Toggle Night Watch** in Raycast Settings. -3. Click **Enable Agent Night Watch** and approve the macOS dialog. -4. Click **Disable Agent Night Watch** when the job finishes. +3. Click the coffee cup and approve the macOS dialog to enable it. +4. Click the coffee cup again to disable it when the job finishes. ## Safety @@ -26,8 +27,8 @@ ventilated surface. This extension does not add a timer or battery cutoff, so you remain responsible for turning it off. If sleep was disabled by another tool, Agent Night Watch will not claim that -session. The menu offers a separately confirmed, administrator-authorized -recovery action. +session. In that exceptional state, clicking the cup opens a separately +confirmed, administrator-authorized recovery menu instead of toggling directly. No password is stored. No privileged helper, sudoers rule, analytics, or network request is used. diff --git a/extensions/agent-night-watch/src/menu-bar-click.ts b/extensions/agent-night-watch/src/menu-bar-click.ts new file mode 100644 index 00000000000..38ee362c189 --- /dev/null +++ b/extensions/agent-night-watch/src/menu-bar-click.ts @@ -0,0 +1,32 @@ +import { StatusKind } from "./status"; + +export function createSingleFlight(dedupeWindowMs = 1_000) { + let current: Promise | undefined; + let resetTimer: ReturnType | undefined; + return (operation: () => Promise): Promise => { + if (!current) { + current = operation(); + const scheduleReset = () => { + if (resetTimer) clearTimeout(resetTimer); + resetTimer = setTimeout(() => { + current = undefined; + resetTimer = undefined; + }, dedupeWindowMs); + }; + void current.then(scheduleReset, scheduleReset); + } + return current; + }; +} + +export function shouldToggleFromMenuBar( + launchType: string, + alreadyActivated: boolean, + statusKind: StatusKind, +): boolean { + return ( + launchType === "userInitiated" && + alreadyActivated && + (statusKind === "off" || statusKind === "on-owned") + ); +} diff --git a/extensions/agent-night-watch/src/night-watch-menu.tsx b/extensions/agent-night-watch/src/night-watch-menu.tsx index 2aa4859cc72..1bfa2dbcbb2 100644 --- a/extensions/agent-night-watch/src/night-watch-menu.tsx +++ b/extensions/agent-night-watch/src/night-watch-menu.tsx @@ -2,9 +2,11 @@ import { Alert, Color, Icon, + LocalStorage, MenuBarExtra, Toast, confirmAlert, + environment, showToast, } from "@raycast/api"; import { useCallback, useEffect, useState } from "react"; @@ -12,58 +14,117 @@ import { NightWatchError, forceRestoreSleep, getNightWatchStatus, - startNightWatch, - stopNightWatch, + toggleNightWatch, } from "./night-watch"; import { NightWatchStatus } from "./status"; +import { createSingleFlight, shouldToggleFromMenuBar } from "./menu-bar-click"; const OFF_ICON = { source: "coffee-off.png", tintColor: Color.PrimaryText }; const ON_ICON = { source: "coffee-on.png", tintColor: Color.PrimaryText }; -const LIVE_STATUS_INTERVAL_MS = 2_000; +const ACTIVATED_KEY = "menu-bar-direct-toggle-activated-v1"; +const runLaunchOnce = createSingleFlight(); + +async function showToggleSuccess(result: "on" | "off"): Promise { + await showToast({ + style: Toast.Style.Success, + title: + result === "on" + ? "☕ Agent Night Watch Enabled" + : "Agent Night Watch Disabled", + }); +} + +async function showActionFailure(error: unknown): Promise { + await showToast({ + style: Toast.Style.Failure, + title: "Action Not Completed", + message: error instanceof NightWatchError ? error.message : String(error), + }); +} export default function Command() { const [status, setStatus] = useState(); const [isLoading, setIsLoading] = useState(true); const refresh = useCallback(async () => { - try { - setStatus(await getNightWatchStatus()); - } finally { - setIsLoading(false); - } + const nextStatus = await getNightWatchStatus(); + setStatus(nextStatus); + return nextStatus; }, []); useEffect(() => { - void refresh(); - const interval = setInterval(() => void refresh(), LIVE_STATUS_INTERVAL_MS); - return () => clearInterval(interval); - }, [refresh]); + let cancelled = false; - const run = useCallback( - async (operation: () => Promise, successTitle: string) => { - setIsLoading(true); - try { - await operation(); - await showToast({ style: Toast.Style.Success, title: successTitle }); - } catch (error) { - await showToast({ - style: Toast.Style.Failure, - title: "Action Not Completed", - message: - error instanceof NightWatchError ? error.message : String(error), - }); - } finally { - await refresh(); + const executeLaunch = async (): Promise => { + let current = await getNightWatchStatus(); + const alreadyActivated = + (await LocalStorage.getItem(ACTIVATED_KEY)) === true; + if (!alreadyActivated) { + await LocalStorage.setItem(ACTIVATED_KEY, true); + } else if ( + shouldToggleFromMenuBar( + environment.launchType, + alreadyActivated, + current.kind, + ) + ) { + const result = await toggleNightWatch(); + await showToggleSuccess(result); + current = await getNightWatchStatus(); } - }, - [refresh], - ); + return current; + }; + + setIsLoading(true); + void runLaunchOnce(executeLaunch) + .then((current) => { + if (!cancelled) setStatus(current); + }) + .catch(async (error) => { + await showActionFailure(error); + if (!cancelled) setStatus(await getNightWatchStatus()); + }) + .finally(() => { + if (!cancelled) setIsLoading(false); + }); + + return () => { + cancelled = true; + }; + }, []); + + const restoreExternalState = useCallback(async () => { + const confirmed = await confirmAlert({ + title: "Restore Normal System Sleep?", + message: + "The current sleep-disabled state is not owned by Agent Night Watch. Continuing runs pmset disablesleep 0 and may override another tool.", + primaryAction: { + title: "Restore Normal Sleep", + style: Alert.ActionStyle.Destructive, + }, + }); + if (!confirmed) return; + + setIsLoading(true); + try { + await forceRestoreSleep(); + await showToast({ + style: Toast.Style.Success, + title: "Normal System Sleep Restored", + }); + } catch (error) { + await showActionFailure(error); + } finally { + await refresh(); + setIsLoading(false); + } + }, [refresh]); const isOn = status?.sleepDisabled ?? false; const isTransitioning = status?.kind === "starting" || status?.kind === "stopping"; const tooltip = status - ? `Agent Night Watch: ${status.message}` + ? `Agent Night Watch: ${status.message}. Click to toggle.` : "Reading Agent Night Watch status"; return ( @@ -72,65 +133,29 @@ export default function Command() { isLoading={isLoading || isTransitioning} tooltip={tooltip} > - - - - {status?.kind === "off" ? ( - - void run(startNightWatch, "☕ Agent Night Watch Enabled") - } - /> - ) : null} - - {status?.kind === "on-owned" ? ( - - void run(stopNightWatch, "Agent Night Watch Disabled") - } - /> - ) : null} - {status?.kind === "on-external" ? ( - { - const confirmed = await confirmAlert({ - title: "Restore Normal System Sleep?", - message: - "The current sleep-disabled state is not owned by Agent Night Watch. Continuing runs pmset disablesleep 0 and may override another tool.", - primaryAction: { - title: "Restore Normal Sleep", - style: Alert.ActionStyle.Destructive, - }, - }); - if (confirmed) - await run(forceRestoreSleep, "Normal System Sleep Restored"); - }} - /> + <> + + void restoreExternalState()} + /> + void refresh()} + /> + ) : null} {isTransitioning ? ( ) : null} - - - void refresh()} - /> ); } diff --git a/extensions/agent-night-watch/tests/menu-bar-click.test.ts b/extensions/agent-night-watch/tests/menu-bar-click.test.ts new file mode 100644 index 00000000000..3432da6124b --- /dev/null +++ b/extensions/agent-night-watch/tests/menu-bar-click.test.ts @@ -0,0 +1,71 @@ +import { describe, expect, it, vi } from "vitest"; +import { + createSingleFlight, + shouldToggleFromMenuBar, +} from "../src/menu-bar-click"; + +describe("menu-bar launch single flight", () => { + it("shares one operation across repeated React effect mounts", async () => { + const runOnce = createSingleFlight(); + let calls = 0; + const operation = async () => { + calls += 1; + return 42; + }; + + const [first, second] = await Promise.all([ + runOnce(operation), + runOnce(operation), + ]); + + expect(first).toBe(42); + expect(second).toBe(42); + expect(calls).toBe(1); + }); + + it("allows a later menu-bar click after the dedupe window", async () => { + vi.useFakeTimers(); + const runOnce = createSingleFlight(); + let calls = 0; + const operation = async () => { + calls += 1; + return calls; + }; + + try { + expect(await runOnce(operation)).toBe(1); + expect(await runOnce(operation)).toBe(1); + await vi.advanceTimersByTimeAsync(1_000); + expect(await runOnce(operation)).toBe(2); + expect(calls).toBe(2); + } finally { + vi.useRealTimers(); + } + }); +}); + +describe("direct menu-bar toggle", () => { + it("toggles normal states on a user click", () => { + expect(shouldToggleFromMenuBar("userInitiated", true, "off")).toBe(true); + expect(shouldToggleFromMenuBar("userInitiated", true, "on-owned")).toBe( + true, + ); + }); + + it("does not toggle during first activation or background refresh", () => { + expect(shouldToggleFromMenuBar("userInitiated", false, "off")).toBe(false); + expect(shouldToggleFromMenuBar("background", true, "off")).toBe(false); + }); + + it("keeps exceptional states behind the recovery menu", () => { + expect( + shouldToggleFromMenuBar("userInitiated", true, "on-external"), + ).toBe(false); + expect(shouldToggleFromMenuBar("userInitiated", true, "starting")).toBe( + false, + ); + expect(shouldToggleFromMenuBar("userInitiated", true, "stopping")).toBe( + false, + ); + }); +}); diff --git a/extensions/agent-night-watch/tests/menu-refresh.test.ts b/extensions/agent-night-watch/tests/menu-refresh.test.ts deleted file mode 100644 index 332eb79a0cb..00000000000 --- a/extensions/agent-night-watch/tests/menu-refresh.test.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { readFileSync } from "node:fs"; -import path from "node:path"; - -describe("menu-bar status refresh", () => { - it("keeps a loaded Raycast menu command synchronized with system truth", () => { - const source = readFileSync( - path.join(process.cwd(), "src", "night-watch-menu.tsx"), - "utf8", - ); - - expect(source).toContain("LIVE_STATUS_INTERVAL_MS = 2_000"); - expect(source).toContain("setInterval(() => void refresh()"); - expect(source).toContain("clearInterval(interval)"); - }); -}); From a6403f10265112748803c063d4ca06dfd46e379c Mon Sep 17 00:00:00 2001 From: Yuchen07569 <296913685+Yuchen07569@users.noreply.github.com> Date: Thu, 13 Aug 2026 16:25:43 +0800 Subject: [PATCH 5/5] fix: harden privileged guard execution --- extensions/agent-night-watch/CHANGELOG.md | 10 ++ extensions/agent-night-watch/README.md | 3 +- .../assets/night-watch-guard.sh | 53 --------- extensions/agent-night-watch/package.json | 2 +- .../agent-night-watch/src/night-watch.ts | 73 +++++------- .../src/privileged-command.ts | 49 ++++++++ extensions/agent-night-watch/src/status.ts | 21 +--- .../tests/privileged-command.test.ts | 106 ++++++++++++++++++ .../agent-night-watch/tests/status.test.ts | 14 +-- 9 files changed, 201 insertions(+), 130 deletions(-) delete mode 100755 extensions/agent-night-watch/assets/night-watch-guard.sh create mode 100644 extensions/agent-night-watch/src/privileged-command.ts create mode 100644 extensions/agent-night-watch/tests/privileged-command.test.ts diff --git a/extensions/agent-night-watch/CHANGELOG.md b/extensions/agent-night-watch/CHANGELOG.md index 545f976b814..2fe9aad6fba 100644 --- a/extensions/agent-night-watch/CHANGELOG.md +++ b/extensions/agent-night-watch/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## [Hardened Privileged Guard] - {PR_MERGE_DATE} + +- Embed the fixed guard program into the authorization command before showing + the password dialog instead of executing a user-writable script pathname. +- Make the privileged process read-only toward user session paths and restrict + its executable allowlist to absolute `pmset`, `grep`, and `sleep` paths. +- Use `pmset -g` and verified launcher identity for readiness and ownership. +- Add adversarial regression coverage for path replacement, symlink writes, + shell injection, and privileged command allowlisting. + ## [Direct Coffee-Cup Toggle] - {PR_MERGE_DATE} - Click the coffee cup once to toggle Night Watch directly in normal states. diff --git a/extensions/agent-night-watch/README.md b/extensions/agent-night-watch/README.md index a9e20775e05..63ecebf9b76 100644 --- a/extensions/agent-night-watch/README.md +++ b/extensions/agent-night-watch/README.md @@ -31,4 +31,5 @@ session. In that exceptional state, clicking the cup opens a separately confirmed, administrator-authorized recovery menu instead of toggling directly. No password is stored. No privileged helper, sudoers rule, analytics, or -network request is used. +network request is used. The fixed privileged guard is embedded before the +authorization dialog and never executes or writes a user-controlled path. diff --git a/extensions/agent-night-watch/assets/night-watch-guard.sh b/extensions/agent-night-watch/assets/night-watch-guard.sh deleted file mode 100755 index a09cab9d80c..00000000000 --- a/extensions/agent-night-watch/assets/night-watch-guard.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/sh - -set -u -umask 077 - -SESSION_DIR="${1:-}" -case "$SESSION_DIR" in - */com.yuchen.agent-night-watch/session.*) ;; - *) exit 64 ;; -esac - -READY_FILE="$SESSION_DIR/ready" -STOP_FILE="$SESSION_DIR/stop" -STOPPED_FILE="$SESSION_DIR/stopped" -REASON_FILE="$SESSION_DIR/reason" -ORIGINAL_FILE="$SESSION_DIR/original" - -sleep_is_disabled() { - /usr/bin/pmset -g | /usr/bin/grep -Eq '^[[:space:]]*SleepDisabled[[:space:]]+1[[:space:]]*$' -} - -original_state=0 -if sleep_is_disabled; then - original_state=1 -fi - -cleanup() { - cleanup_status=$? - trap - EXIT HUP INT TERM - /usr/bin/pmset -a disablesleep "$original_state" >/dev/null 2>&1 || true - /bin/rm -f "$READY_FILE" - /usr/bin/touch "$STOPPED_FILE" - exit "$cleanup_status" -} - -trap cleanup EXIT HUP INT TERM - -/bin/echo "$original_state" > "$ORIGINAL_FILE" -/usr/bin/pmset -a disablesleep 1 >/dev/null -sleep_is_disabled || exit 1 -/usr/bin/touch "$READY_FILE" - -while [ ! -e "$STOP_FILE" ]; do - if ! sleep_is_disabled; then - /bin/echo external-change > "$REASON_FILE" - exit 0 - fi - /bin/sleep 1 -done - -if [ ! -s "$REASON_FILE" ]; then - /bin/echo manual > "$REASON_FILE" -fi diff --git a/extensions/agent-night-watch/package.json b/extensions/agent-night-watch/package.json index 2333c858f52..3bc88e4c4a9 100644 --- a/extensions/agent-night-watch/package.json +++ b/extensions/agent-night-watch/package.json @@ -13,7 +13,7 @@ "fix-lint": "ray lint --fix", "lint": "ray lint", "publish": "npx @raycast/api@latest publish", - "test": "vitest run && /bin/sh -n assets/night-watch-guard.sh" + "test": "vitest run" }, "platforms": ["macOS"], "categories": ["System"], diff --git a/extensions/agent-night-watch/src/night-watch.ts b/extensions/agent-night-watch/src/night-watch.ts index 73803f01adb..eb50a4a22dc 100644 --- a/extensions/agent-night-watch/src/night-watch.ts +++ b/extensions/agent-night-watch/src/night-watch.ts @@ -1,11 +1,9 @@ -import { environment } from "@raycast/api"; import { execFile, spawn } from "node:child_process"; import { randomUUID } from "node:crypto"; import { homedir } from "node:os"; import path from "node:path"; import { closeSync, - copyFileSync, existsSync, mkdirSync, mkdtempSync, @@ -24,6 +22,11 @@ import { isAuthorizationCanceled, statusMessage, } from "./status"; +import { + appleScriptQuote, + buildAdministratorAppleScript, + buildPrivilegedGuardCommand, +} from "./privileged-command"; import { LOCK_STALE_AFTER_MS, lockLeaseExpired, @@ -46,7 +49,7 @@ const START_TIMEOUT_MS = 120_000; const STOP_TIMEOUT_MS = 8_000; interface SessionState { - version: 2; + version: 3; launcherPid: number; sessionDir: string; startedAt: string; @@ -64,21 +67,6 @@ function delay(milliseconds: number): Promise { return new Promise((resolve) => setTimeout(resolve, milliseconds)); } -function shellQuote(value: string): string { - return `'${value.replaceAll("'", `'\\''`)}'`; -} - -function appleScriptQuote(value: string): string { - return value.replaceAll("\\", "\\\\").replaceAll('"', '\\"'); -} - -function installGuardScript(sessionDir: string): string { - const source = path.join(environment.assetsPath, "night-watch-guard.sh"); - const target = path.join(sessionDir, "night-watch-guard.sh"); - copyFileSync(source, target); - return target; -} - function ensureCacheDirectory(): void { mkdirSync(CACHE_DIR, { recursive: true, mode: 0o700 }); } @@ -103,7 +91,7 @@ function readSessionState(): SessionState | undefined { readFileSync(STATE_FILE, "utf8"), ) as Partial; if ( - state.version !== 2 || + state.version !== 3 || !Number.isInteger(state.launcherPid) || (state.launcherPid ?? 0) <= 1 || typeof state.sessionDir !== "string" || @@ -185,25 +173,15 @@ export async function getNightWatchStatus(): Promise { sleepDisabled: disabled, statePresent: false, processMatches: false, - ready: false, - stopped: false, - stopRequested: false, }); return { kind, sleepDisabled: disabled, message: statusMessage(kind) }; } const processMatches = await processMatchesSession(state); - const ready = existsSync(path.join(state.sessionDir, "ready")); - const stopped = existsSync(path.join(state.sessionDir, "stopped")); - const stopRequested = existsSync(path.join(state.sessionDir, "stop")); - const kind = classifyNightWatchStatus({ sleepDisabled: disabled, statePresent: true, processMatches, - ready, - stopped, - stopRequested, phase: state.phase, }); @@ -279,6 +257,16 @@ function readLogTail(logPath: string): string { } } +function requestStop(sessionDir: string): void { + const stopPath = path.join(sessionDir, "stop"); + try { + const stopFd = openSync(stopPath, "wx", 0o600); + closeSync(stopFd); + } catch (error) { + if (!existsSync(stopPath)) throw error; + } +} + async function startNightWatchUnlocked(): Promise { const current = await getNightWatchStatus(); if (current.kind === "on-owned") return; @@ -295,10 +283,9 @@ async function startNightWatchUnlocked(): Promise { const sessionDir = mkdtempSync(SESSION_PREFIX); const logPath = path.join(sessionDir, "guard.log"); - const logFd = openSync(logPath, "a", 0o600); - const guardPath = installGuardScript(sessionDir); - const rootCommand = `/bin/sh ${shellQuote(guardPath)} ${shellQuote(sessionDir)}`; - const script = `with timeout of 2147483647 seconds\n do shell script "${appleScriptQuote(rootCommand)}" with administrator privileges\nend timeout`; + const logFd = openSync(logPath, "wx", 0o600); + const rootCommand = buildPrivilegedGuardCommand(sessionDir); + const script = buildAdministratorAppleScript(rootCommand); const child = spawn("/usr/bin/osascript", ["-e", script], { detached: true, stdio: ["ignore", logFd, logFd], @@ -314,7 +301,7 @@ async function startNightWatchUnlocked(): Promise { child.unref(); const state: SessionState = { - version: 2, + version: 3, launcherPid: child.pid, sessionDir, startedAt: new Date().toISOString(), @@ -324,10 +311,7 @@ async function startNightWatchUnlocked(): Promise { const startedAt = Date.now(); while (Date.now() - startedAt < START_TIMEOUT_MS) { - if ( - existsSync(path.join(sessionDir, "ready")) && - (await sleepIsDisabled()) - ) { + if ((await sleepIsDisabled()) && isProcessAlive(child.pid)) { writeSessionState({ ...state, phase: "running" }); return; } @@ -335,6 +319,10 @@ async function startNightWatchUnlocked(): Promise { await delay(100); } + requestStop(sessionDir); + for (let attempt = 0; attempt < 50 && (await sleepIsDisabled()); attempt += 1) + await delay(100); + if (isProcessAlive(child.pid)) { try { process.kill(child.pid, "SIGTERM"); @@ -342,8 +330,6 @@ async function startNightWatchUnlocked(): Promise { // The authorization process may have exited between checks. } } - for (let attempt = 0; attempt < 50 && (await sleepIsDisabled()); attempt += 1) - await delay(100); const errorTail = readLogTail(logPath); if (!(await sleepIsDisabled())) removeSessionFiles(sessionDir); @@ -379,15 +365,12 @@ async function stopNightWatchUnlocked(): Promise { "The owned Night Watch session was not found. System state was not changed.", ); writeSessionState({ ...state, phase: "stopping" }); - writeFileSync(path.join(state.sessionDir, "reason"), "manual\n", { - mode: 0o600, - }); - writeFileSync(path.join(state.sessionDir, "stop"), "\n", { mode: 0o600 }); + requestStop(state.sessionDir); const startedAt = Date.now(); while (Date.now() - startedAt < STOP_TIMEOUT_MS) { const disabled = await sleepIsDisabled(); - if (!disabled && existsSync(path.join(state.sessionDir, "stopped"))) { + if (!disabled) { removeSessionFiles(state.sessionDir); return; } diff --git a/extensions/agent-night-watch/src/privileged-command.ts b/extensions/agent-night-watch/src/privileged-command.ts new file mode 100644 index 00000000000..0a21f837a41 --- /dev/null +++ b/extensions/agent-night-watch/src/privileged-command.ts @@ -0,0 +1,49 @@ +import path from "node:path"; + +export const PRIVILEGED_GUARD_PROGRAM = String.raw`set -u +STOP_FILE="$1" + +sleep_is_disabled() { + /usr/bin/pmset -g | /usr/bin/grep -Eq '^[[:space:]]*SleepDisabled[[:space:]]+1[[:space:]]*$' +} + +original_state=0 +if sleep_is_disabled; then + original_state=1 +fi + +restore_original_state() { + cleanup_status=$? + trap - EXIT HUP INT TERM + /usr/bin/pmset -a disablesleep "$original_state" >/dev/null 2>&1 || true + exit "$cleanup_status" +} + +trap restore_original_state EXIT HUP INT TERM + +/usr/bin/pmset -a disablesleep 1 >/dev/null +sleep_is_disabled || exit 1 + +while [ ! -e "$STOP_FILE" ]; do + if ! sleep_is_disabled; then + exit 0 + fi + /bin/sleep 1 +done`; + +function shellQuote(value: string): string { + return `'${value.replaceAll("'", `'\\''`)}'`; +} + +export function appleScriptQuote(value: string): string { + return value.replaceAll("\\", "\\\\").replaceAll('"', '\\"'); +} + +export function buildPrivilegedGuardCommand(sessionDir: string): string { + const stopFile = path.join(sessionDir, "stop"); + return `/bin/sh -c ${shellQuote(PRIVILEGED_GUARD_PROGRAM)} agent-night-watch ${shellQuote(stopFile)}`; +} + +export function buildAdministratorAppleScript(rootCommand: string): string { + return `with timeout of 2147483647 seconds\n do shell script "${appleScriptQuote(rootCommand)}" with administrator privileges\nend timeout`; +} diff --git a/extensions/agent-night-watch/src/status.ts b/extensions/agent-night-watch/src/status.ts index a6e6486753f..6f4b51d3bfb 100644 --- a/extensions/agent-night-watch/src/status.ts +++ b/extensions/agent-night-watch/src/status.ts @@ -12,9 +12,6 @@ export interface StatusSnapshot { sleepDisabled: boolean; statePresent: boolean; processMatches: boolean; - ready: boolean; - stopped: boolean; - stopRequested: boolean; phase?: SessionPhase; } @@ -28,25 +25,13 @@ export function classifyNightWatchStatus(snapshot: StatusSnapshot): StatusKind { } if (!snapshot.sleepDisabled) { - return snapshot.phase === "starting" && - snapshot.processMatches && - !snapshot.stopped + return snapshot.phase === "starting" && snapshot.processMatches ? "starting" : "off"; } - if (snapshot.processMatches && snapshot.ready) { - return snapshot.phase === "stopping" || snapshot.stopRequested - ? "stopping" - : "on-owned"; - } - - if ( - snapshot.processMatches && - snapshot.phase === "starting" && - !snapshot.stopped - ) { - return "starting"; + if (snapshot.processMatches) { + return snapshot.phase === "stopping" ? "stopping" : "on-owned"; } return "on-external"; } diff --git a/extensions/agent-night-watch/tests/privileged-command.test.ts b/extensions/agent-night-watch/tests/privileged-command.test.ts new file mode 100644 index 00000000000..436314640a5 --- /dev/null +++ b/extensions/agent-night-watch/tests/privileged-command.test.ts @@ -0,0 +1,106 @@ +import { spawnSync } from "node:child_process"; +import { + chmodSync, + mkdtempSync, + readFileSync, + rmSync, + symlinkSync, + writeFileSync, +} from "node:fs"; +import { tmpdir } from "node:os"; +import path from "node:path"; +import { describe, expect, it } from "vitest"; +import { + PRIVILEGED_GUARD_PROGRAM, + buildAdministratorAppleScript, + buildPrivilegedGuardCommand, +} from "../src/privileged-command"; + +describe("privileged guard command", () => { + it("is valid POSIX shell embedded before authorization", () => { + const result = spawnSync("/bin/sh", ["-n", "-c", PRIVILEGED_GUARD_PROGRAM]); + expect(result.status).toBe(0); + expect(result.stderr.toString()).toBe(""); + }); + + it("never executes or writes a user-controlled path as root", () => { + expect(PRIVILEGED_GUARD_PROGRAM).toContain('STOP_FILE="$1"'); + expect(PRIVILEGED_GUARD_PROGRAM).toContain( + 'while [ ! -e "$STOP_FILE" ]; do', + ); + expect(PRIVILEGED_GUARD_PROGRAM).not.toMatch( + /\b(?:rm|touch|chmod|chown|cp|mv|install)\b/, + ); + expect(PRIVILEGED_GUARD_PROGRAM).not.toMatch( + /(?:>|>>)[^\n]*\$STOP_FILE/, + ); + expect( + [...PRIVILEGED_GUARD_PROGRAM.matchAll(/\/(?:usr\/bin|bin)\/[a-z]+/g)] + .map(([command]) => command) + .filter((command, index, commands) => commands.indexOf(command) === index) + .sort(), + ).toEqual(["/bin/sleep", "/usr/bin/grep", "/usr/bin/pmset"]); + expect(PRIVILEGED_GUARD_PROGRAM.match(/\$STOP_FILE/g)).toHaveLength(1); + }); + + it("passes an adversarial stop path as one quoted argument", () => { + const sessionDir = "/tmp/session.'; /usr/bin/id; echo '"; + const command = buildPrivilegedGuardCommand(sessionDir); + + expect(command).not.toContain("night-watch-guard.sh"); + expect(command).toContain("agent-night-watch '/tmp/session.'\\'';"); + expect(spawnSync("/bin/sh", ["-n", "-c", command]).status).toBe(0); + }); + + it("does not modify a symlink target while observing a stop signal", () => { + const directory = mkdtempSync(path.join(tmpdir(), "night-watch-guard-")); + const statePath = path.join(directory, "sleep-state"); + const targetPath = path.join(directory, "protected-target"); + const stopPath = path.join(directory, "stop"); + const mockPmsetPath = path.join(directory, "pmset"); + writeFileSync(statePath, "0\n"); + writeFileSync(targetPath, "unchanged\n"); + symlinkSync(targetPath, stopPath); + writeFileSync( + mockPmsetPath, + `#!/bin/sh +if [ "\${1:-}" = "-g" ]; then + state=$(/bin/cat '${statePath}') + /bin/echo " SleepDisabled $state" + exit 0 +fi +/bin/echo "\${3:-0}" > '${statePath}' +`, + ); + chmodSync(mockPmsetPath, 0o700); + + try { + const simulatedProgram = PRIVILEGED_GUARD_PROGRAM.replaceAll( + "/usr/bin/pmset", + mockPmsetPath, + ); + const result = spawnSync("/bin/sh", [ + "-c", + simulatedProgram, + "agent-night-watch", + stopPath, + ]); + + expect(result.status).toBe(0); + expect(readFileSync(targetPath, "utf8")).toBe("unchanged\n"); + expect(readFileSync(statePath, "utf8")).toBe("0\n"); + } finally { + rmSync(directory, { recursive: true, force: true }); + } + }); + + it("escapes the complete command before handing it to AppleScript", () => { + const script = buildAdministratorAppleScript( + buildPrivilegedGuardCommand("/tmp/session.test"), + ); + + expect(script).toContain("with administrator privileges"); + expect(script).toContain("with timeout of 2147483647 seconds"); + expect(script).not.toContain("night-watch-guard.sh"); + }); +}); diff --git a/extensions/agent-night-watch/tests/status.test.ts b/extensions/agent-night-watch/tests/status.test.ts index 10ae911f702..c32e9ad74bb 100644 --- a/extensions/agent-night-watch/tests/status.test.ts +++ b/extensions/agent-night-watch/tests/status.test.ts @@ -41,9 +41,6 @@ describe("classifyNightWatchStatus", () => { sleepDisabled: false, statePresent: false, processMatches: false, - ready: false, - stopped: false, - stopRequested: false, }; it("treats pmset as authoritative without an owned session", () => { @@ -60,7 +57,6 @@ describe("classifyNightWatchStatus", () => { sleepDisabled: true, statePresent: true, processMatches: true, - ready: true, phase: "running", }), ).toBe("on-owned"); @@ -81,8 +77,6 @@ describe("classifyNightWatchStatus", () => { sleepDisabled: true, statePresent: true, processMatches: true, - ready: true, - stopRequested: true, phase: "stopping", }), ).toBe("stopping"); @@ -95,23 +89,21 @@ describe("classifyNightWatchStatus", () => { sleepDisabled: true, statePresent: true, processMatches: true, - ready: true, phase: "stopping", }), ).toBe("stopping"); }); - it("does not claim ownership before the privileged guard is ready", () => { + it("uses pmset truth to recognize the privileged guard after authorization", () => { expect( classifyNightWatchStatus({ ...base, sleepDisabled: true, statePresent: true, processMatches: true, - ready: false, phase: "starting", }), - ).toBe("starting"); + ).toBe("on-owned"); }); it("does not trust a stale PID or stale cache", () => { @@ -120,7 +112,6 @@ describe("classifyNightWatchStatus", () => { ...base, sleepDisabled: true, statePresent: true, - ready: true, phase: "running", }), ).toBe("on-external"); @@ -128,7 +119,6 @@ describe("classifyNightWatchStatus", () => { classifyNightWatchStatus({ ...base, statePresent: true, - ready: true, phase: "running", }), ).toBe("off");