From 10e11245503c507f448a930ed2291e0ac89b21df Mon Sep 17 00:00:00 2001 From: root Date: Thu, 5 Mar 2026 09:27:44 +0000 Subject: [PATCH 01/28] feat: implement pass_mgr, pcexec, and safe-restart modules - Add pass_mgr Go binary with AES-256-GCM encryption - Add pcexec TypeScript tool with password sanitization - Add safe-restart module with state machine and API - Add slash command handler with cooldown support - Update README with usage documentation --- README.md | 127 ++++++++ pass_mgr/go.mod | 12 + pass_mgr/src/main.go | 498 +++++++++++++++++++++++++++++ pcexec/package.json | 21 ++ pcexec/src/index.ts | 346 ++++++++++++++++++++ pcexec/tsconfig.json | 19 ++ safe-restart/package.json | 25 ++ safe-restart/src/api.ts | 100 ++++++ safe-restart/src/index.ts | 4 + safe-restart/src/safe-restart.ts | 288 +++++++++++++++++ safe-restart/src/slash-commands.ts | 182 +++++++++++ safe-restart/src/status-manager.ts | 396 +++++++++++++++++++++++ safe-restart/tsconfig.json | 19 ++ 13 files changed, 2037 insertions(+) create mode 100644 README.md create mode 100644 pass_mgr/go.mod create mode 100644 pass_mgr/src/main.go create mode 100644 pcexec/package.json create mode 100644 pcexec/src/index.ts create mode 100644 pcexec/tsconfig.json create mode 100644 safe-restart/package.json create mode 100644 safe-restart/src/api.ts create mode 100644 safe-restart/src/index.ts create mode 100644 safe-restart/src/safe-restart.ts create mode 100644 safe-restart/src/slash-commands.ts create mode 100644 safe-restart/src/status-manager.ts create mode 100644 safe-restart/tsconfig.json diff --git a/README.md b/README.md new file mode 100644 index 0000000..11cf0dd --- /dev/null +++ b/README.md @@ -0,0 +1,127 @@ +# PaddedCell + +OpenClaw 插件:安全密码管理 + 安全执行 + 安全重启 + +## 功能模块 + +### 1. pass_mgr - 密码管理二进制 (Go) + +使用 AES-256-GCM 加密,每个 agent 基于公私钥进行加/解密。 + +```bash +# 初始化 +pass_mgr admin init [--key-path ] + +# 获取密码 +pass_mgr get [--username] + +# 生成密码 (agent 可用) +pass_mgr generate [--username ] + +# 设置密码 (仅人类) +pass_mgr set [--username ] + +# 删除密码 +pass_mgr unset + +# 轮换密码 +pass_mgr rotate +``` + +**安全特性:** +- Agent 无法执行 `set` 操作(通过环境变量检测) +- 未初始化前所有操作报错 +- Admin 密码泄露检测(监控 message/tool calling) + +### 2. pcexec - 安全执行工具 (TypeScript) + +与 OpenClaw 原生 exec 接口一致,自动处理 pass_mgr get 并脱敏输出。 + +```typescript +import { pcexec } from 'pcexec'; + +const result = await pcexec('echo $(pass_mgr get mypassword)', { + cwd: '/workspace', + timeout: 30000, +}); +// result.stdout 中密码会被替换为 ###### +``` + +### 3. safe-restart - 安全重启模块 (TypeScript) + +提供 agent 状态管理和协调重启。 + +**Agent 状态:** +- `idle` - 空闲 +- `busy` - 处理消息中 +- `focus` - 专注模式(工作流) +- `freeze` - 冻结(不接受新消息) +- `pre-freeze` - 准备冻结 +- `pre-freeze-focus` - 准备冻结(专注模式) + +**API:** +- `POST /query-restart` - 查询重启就绪状态 +- `POST /restart-result` - 报告重启结果 +- `GET /status` - 获取所有状态 + +**Slash 命令:** +``` +/padded-cell-ctrl status +/padded-cell-ctrl enable pass-mgr|safe-restart +/padded-cell-ctrl disable pass-mgr|safe-restart +``` + +## 目录结构 + +``` +PaddedCell/ +├── pass_mgr/ # Go 密码管理二进制 +│ ├── src/ +│ │ └── main.go +│ └── go.mod +├── pcexec/ # TypeScript 安全执行工具 +│ ├── src/ +│ │ └── index.ts +│ ├── package.json +│ └── tsconfig.json +├── safe-restart/ # TypeScript 安全重启模块 +│ ├── src/ +│ │ ├── index.ts +│ │ ├── status-manager.ts +│ │ ├── api.ts +│ │ ├── safe-restart.ts +│ │ └── slash-commands.ts +│ ├── package.json +│ └── tsconfig.json +├── docs/ # 文档 +├── PROJECT_PLAN.md # 项目计划 +├── AGENT_TASKS.md # 任务清单 +└── README.md +``` + +## 开发 + +```bash +# Clone +git clone https://git.hangman-lab.top/nav/PaddedCell.git +cd PaddedCell + +# Build pass_mgr (需要 Go) +cd pass_mgr +go build -o pass_mgr src/main.go + +# Build pcexec (需要 Node.js) +cd ../pcexec +npm install +npm run build + +# Build safe-restart (需要 Node.js) +cd ../safe-restart +npm install +npm run build +``` + +## 开发分支 + +- `main` - 主分支 +- `dev/zhi` - 当前开发分支 diff --git a/pass_mgr/go.mod b/pass_mgr/go.mod new file mode 100644 index 0000000..47a663c --- /dev/null +++ b/pass_mgr/go.mod @@ -0,0 +1,12 @@ +module pass_mgr + +go 1.22 + +require ( + github.com/spf13/cobra v1.8.0 +) + +require ( + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect +) diff --git a/pass_mgr/src/main.go b/pass_mgr/src/main.go new file mode 100644 index 0000000..7c196e4 --- /dev/null +++ b/pass_mgr/src/main.go @@ -0,0 +1,498 @@ +package main + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "crypto/sha256" + "encoding/base64" + "encoding/json" + "fmt" + "io" + "os" + "path/filepath" + "strings" + "time" + + "github.com/spf13/cobra" +) + +const ( + DefaultAlgorithm = "AES-256-GCM" + AdminKeyDir = ".pass_mgr" + AdminKeyFile = ".priv" + SecretsDirName = ".secrets" +) + +// EncryptedData represents the structure of encrypted password file +type EncryptedData struct { + Algorithm string `json:"algorithm"` + Nonce string `json:"nonce"` + Data string `json:"data"` + User string `json:"user,omitempty"` +} + +// Config holds admin key configuration +type Config struct { + KeyHash string `json:"key_hash"` + Algorithm string `json:"algorithm"` +} + +var ( + workspaceDir string + agentID string + username string +) + +func main() { + rootCmd := &cobra.Command{ + Use: "pass_mgr", + Short: "Password manager for OpenClaw agents", + Long: `A secure password management tool using AES-256-GCM encryption.`, + } + + // Get environment variables + workspaceDir = os.Getenv("AGENT_WORKSPACE") + agentID = os.Getenv("AGENT_ID") + + // Commands + rootCmd.AddCommand(getCmd()) + rootCmd.AddCommand(generateCmd()) + rootCmd.AddCommand(unsetCmd()) + rootCmd.AddCommand(rotateCmd()) + rootCmd.AddCommand(adminInitCmd()) + rootCmd.AddCommand(setCmd()) + + if err := rootCmd.Execute(); err != nil { + fmt.Fprintf(os.Stderr, "Error: %v\n", err) + os.Exit(1) + } +} + +func getCmd() *cobra.Command { + return &cobra.Command{ + Use: "get [key]", + Short: "Get password for a key", + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + key := args[0] + password, user, err := getPassword(key) + if err != nil { + fmt.Fprintf(os.Stderr, "Error: %v\n", err) + os.Exit(1) + } + if username { + fmt.Println(user) + } else { + fmt.Println(password) + } + }, + } +} + +func generateCmd() *cobra.Command { + var user string + cmd := &cobra.Command{ + Use: "generate [key]", + Short: "Generate a new password", + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + key := args[0] + // Check if agent is trying to set password + if os.Getenv("AGENT") != "" || os.Getenv("AGENT_WORKSPACE") != "" { + fmt.Fprintln(os.Stderr, "Error: Agents cannot set passwords. Use generate instead.") + os.Exit(1) + } + password, err := generatePassword(32) + if err != nil { + fmt.Fprintf(os.Stderr, "Error: %v\n", err) + os.Exit(1) + } + if err := setPassword(key, user, password); err != nil { + fmt.Fprintf(os.Stderr, "Error: %v\n", err) + os.Exit(1) + } + fmt.Println(password) + }, + } + cmd.Flags().StringVar(&user, "username", "", "Username associated with the password") + return cmd +} + +func unsetCmd() *cobra.Command { + return &cobra.Command{ + Use: "unset [key]", + Short: "Remove a password", + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + key := args[0] + if err := removePassword(key); err != nil { + fmt.Fprintf(os.Stderr, "Error: %v\n", err) + os.Exit(1) + } + }, + } +} + +func rotateCmd() *cobra.Command { + return &cobra.Command{ + Use: "rotate [key]", + Short: "Rotate password for a key", + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + key := args[0] + // Check if initialized + if !isInitialized() { + fmt.Fprintln(os.Stderr, "Error: pass_mgr not initialized. Run 'pass_mgr admin init' first.") + os.Exit(1) + } + + // Get current user if exists + _, user, err := getPassword(key) + if err != nil { + fmt.Fprintf(os.Stderr, "Error: %v\n", err) + os.Exit(1) + } + + // Generate new password + newPassword, err := generatePassword(32) + if err != nil { + fmt.Fprintf(os.Stderr, "Error: %v\n", err) + os.Exit(1) + } + + if err := setPassword(key, user, newPassword); err != nil { + fmt.Fprintf(os.Stderr, "Error: %v\n", err) + os.Exit(1) + } + fmt.Println(newPassword) + }, + } +} + +func adminInitCmd() *cobra.Command { + var keyPath string + cmd := &cobra.Command{ + Use: "admin init", + Short: "Initialize pass_mgr with admin key", + Run: func(cmd *cobra.Command, args []string) { + if err := initAdmin(keyPath); err != nil { + fmt.Fprintf(os.Stderr, "Error: %v\n", err) + os.Exit(1) + } + fmt.Println("pass_mgr initialized successfully") + }, + } + cmd.Flags().StringVar(&keyPath, "key-path", "", "Path to admin key file (optional)") + return cmd +} + +func setCmd() *cobra.Command { + var user string + cmd := &cobra.Command{ + Use: "set [key] [password]", + Short: "Set password (admin only)", + Args: cobra.ExactArgs(2), + Run: func(cmd *cobra.Command, args []string) { + // Check if agent is trying to set password + if os.Getenv("AGENT") != "" || os.Getenv("AGENT_WORKSPACE") != "" { + fmt.Fprintln(os.Stderr, "Error: Agents cannot set passwords. Only humans can use 'set'.") + os.Exit(1) + } + + key := args[0] + password := args[1] + + if err := setPassword(key, user, password); err != nil { + fmt.Fprintf(os.Stderr, "Error: %v\n", err) + os.Exit(1) + } + }, + } + cmd.Flags().StringVar(&user, "username", "", "Username associated with the password") + return cmd +} + +// Helper functions + +func getHomeDir() string { + home, err := os.UserHomeDir() + if err != nil { + return "." + } + return home +} + +func getAdminKeyPath() string { + return filepath.Join(getHomeDir(), AdminKeyDir, AdminKeyFile) +} + +func getConfigPath() string { + return filepath.Join(getHomeDir(), AdminKeyDir, "config.json") +} + +func isInitialized() bool { + _, err := os.Stat(getConfigPath()) + return err == nil +} + +func loadAdminKey() ([]byte, error) { + keyPath := getAdminKeyPath() + key, err := os.ReadFile(keyPath) + if err != nil { + return nil, fmt.Errorf("failed to load admin key: %w", err) + } + // Hash the key to get 32 bytes for AES-256 + hash := sha256.Sum256(key) + return hash[:], nil +} + +func initAdmin(keyPath string) error { + homeDir := getHomeDir() + adminDir := filepath.Join(homeDir, AdminKeyDir) + + // Create admin directory + if err := os.MkdirAll(adminDir, 0700); err != nil { + return fmt.Errorf("failed to create admin directory: %w", err) + } + + var key []byte + if keyPath != "" { + // Read provided key + var err error + key, err = os.ReadFile(keyPath) + if err != nil { + return fmt.Errorf("failed to read key file: %w", err) + } + } else { + // Generate new key + key = make([]byte, 32) + if _, err := rand.Read(key); err != nil { + return fmt.Errorf("failed to generate key: %w", err) + } + } + + // Save key + keyFile := filepath.Join(adminDir, AdminKeyFile) + if err := os.WriteFile(keyFile, key, 0600); err != nil { + return fmt.Errorf("failed to save key: %w", err) + } + + // Save config + config := Config{ + KeyHash: fmt.Sprintf("%x", sha256.Sum256(key)), + Algorithm: DefaultAlgorithm, + } + configData, _ := json.MarshalIndent(config, "", " ") + configPath := filepath.Join(adminDir, "config.json") + if err := os.WriteFile(configPath, configData, 0600); err != nil { + return fmt.Errorf("failed to save config: %w", err) + } + + return nil +} + +func getSecretsDir() string { + if workspaceDir != "" && agentID != "" { + return filepath.Join(workspaceDir, SecretsDirName, agentID) + } + // Fallback to home directory + return filepath.Join(getHomeDir(), SecretsDirName, "default") +} + +func getPasswordFilePath(key string) string { + return filepath.Join(getSecretsDir(), key+".gpg") +} + +func encrypt(plaintext []byte, key []byte) (*EncryptedData, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + gcm, err := cipher.NewGCM(block) + if err != nil { + return nil, err + } + + nonce := make([]byte, gcm.NonceSize()) + if _, err := io.ReadFull(rand.Reader, nonce); err != nil { + return nil, err + } + + ciphertext := gcm.Seal(nonce, nonce, plaintext, nil) + + return &EncryptedData{ + Algorithm: DefaultAlgorithm, + Nonce: base64.StdEncoding.EncodeToString(nonce), + Data: base64.StdEncoding.EncodeToString(ciphertext[gcm.NonceSize():]), + }, nil +} + +func decrypt(data *EncryptedData, key []byte) ([]byte, error) { + ciphertext, err := base64.StdEncoding.DecodeString(data.Data) + if err != nil { + return nil, err + } + + nonce, err := base64.StdEncoding.DecodeString(data.Nonce) + if err != nil { + return nil, err + } + + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + gcm, err := cipher.NewGCM(block) + if err != nil { + return nil, err + } + + plaintext, err := gcm.Open(nil, nonce, ciphertext, nil) + if err != nil { + return nil, err + } + + return plaintext, nil +} + +func setPassword(key, user, password string) error { + if !isInitialized() { + return fmt.Errorf("pass_mgr not initialized. Run 'pass_mgr admin init' first") + } + + adminKey, err := loadAdminKey() + if err != nil { + return err + } + + // Create secrets directory + secretsDir := getSecretsDir() + if err := os.MkdirAll(secretsDir, 0700); err != nil { + return fmt.Errorf("failed to create secrets directory: %w", err) + } + + // Encrypt password + data := map[string]string{ + "password": password, + "user": user, + } + plaintext, _ := json.Marshal(data) + + encrypted, err := encrypt(plaintext, adminKey) + if err != nil { + return fmt.Errorf("failed to encrypt: %w", err) + } + encrypted.User = user + + // Save to file + filePath := getPasswordFilePath(key) + fileData, _ := json.MarshalIndent(encrypted, "", " ") + if err := os.WriteFile(filePath, fileData, 0600); err != nil { + return fmt.Errorf("failed to save password: %w", err) + } + + return nil +} + +func getPassword(key string) (string, string, error) { + if !isInitialized() { + return "", "", fmt.Errorf("pass_mgr not initialized. Run 'pass_mgr admin init' first") + } + + adminKey, err := loadAdminKey() + if err != nil { + return "", "", err + } + + filePath := getPasswordFilePath(key) + fileData, err := os.ReadFile(filePath) + if err != nil { + return "", "", fmt.Errorf("password not found: %w", err) + } + + var encrypted EncryptedData + if err := json.Unmarshal(fileData, &encrypted); err != nil { + return "", "", fmt.Errorf("failed to parse password file: %w", err) + } + + plaintext, err := decrypt(&encrypted, adminKey) + if err != nil { + return "", "", fmt.Errorf("failed to decrypt: %w", err) + } + + var data map[string]string + if err := json.Unmarshal(plaintext, &data); err != nil { + return "", "", fmt.Errorf("failed to parse decrypted data: %w", err) + } + + return data["password"], data["user"], nil +} + +func removePassword(key string) error { + if !isInitialized() { + return fmt.Errorf("pass_mgr not initialized. Run 'pass_mgr admin init' first") + } + + filePath := getPasswordFilePath(key) + if err := os.Remove(filePath); err != nil { + return fmt.Errorf("failed to remove password: %w", err) + } + return nil +} + +func generatePassword(length int) (string, error) { + const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*" + password := make([]byte, length) + for i := range password { + randomByte := make([]byte, 1) + if _, err := rand.Read(randomByte); err != nil { + return "", err + } + password[i] = charset[int(randomByte[0])%len(charset)] + } + return string(password), nil +} + +// CheckForAdminLeak checks if admin password appears in message/tool calling +func CheckForAdminLeak(content string) bool { + // This is a placeholder - actual implementation should check against actual admin password + // This function should be called by the plugin to monitor messages + configPath := getConfigPath() + if _, err := os.Stat(configPath); err != nil { + return false + } + + // TODO: Implement actual leak detection + // For now, just check if content contains common patterns + return strings.Contains(content, "admin") && strings.Contains(content, "password") +} + +// ResetOnLeak resets pass_mgr to uninitialized state and logs security breach +func ResetOnLeak() error { + configPath := getConfigPath() + + // Remove config (but keep key file for potential recovery) + if err := os.Remove(configPath); err != nil { + return err + } + + // Log security breach + logPath := filepath.Join(getHomeDir(), AdminKeyDir, "security_breach.log") + logEntry := fmt.Sprintf("[%s] CRITICAL: Admin password leaked! pass_mgr reset to uninitialized state.\n", + time.Now().Format(time.RFC3339)) + + f, err := os.OpenFile(logPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600) + if err != nil { + return err + } + defer f.Close() + + if _, err := f.WriteString(logEntry); err != nil { + return err + } + + return nil +} diff --git a/pcexec/package.json b/pcexec/package.json new file mode 100644 index 0000000..f9416bf --- /dev/null +++ b/pcexec/package.json @@ -0,0 +1,21 @@ +{ + "name": "pcexec", + "version": "0.1.0", + "description": "Safe exec wrapper for OpenClaw with password sanitization", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "scripts": { + "build": "tsc", + "dev": "tsc --watch", + "test": "jest" + }, + "dependencies": { + "@types/node": "^20.0.0" + }, + "devDependencies": { + "typescript": "^5.0.0", + "jest": "^29.0.0", + "@types/jest": "^29.0.0", + "ts-jest": "^29.0.0" + } +} diff --git a/pcexec/src/index.ts b/pcexec/src/index.ts new file mode 100644 index 0000000..4df3424 --- /dev/null +++ b/pcexec/src/index.ts @@ -0,0 +1,346 @@ +import { spawn, SpawnOptions } from 'child_process'; +import { promisify } from 'util'; + +const execAsync = promisify(require('child_process').exec); + +export interface PcExecOptions { + /** Current working directory */ + cwd?: string; + /** Environment variables */ + env?: Record; + /** Timeout in milliseconds */ + timeout?: number; + /** Maximum buffer size for stdout/stderr */ + maxBuffer?: number; + /** Kill signal */ + killSignal?: NodeJS.Signals; + /** Shell to use */ + shell?: string | boolean; + /** UID to run as */ + uid?: number; + /** GID to run as */ + gid?: number; + /** Window style (Windows only) */ + windowsHide?: boolean; +} + +export interface PcExecResult { + /** Standard output */ + stdout: string; + /** Standard error */ + stderr: string; + /** Exit code */ + exitCode: number; + /** Command that was executed */ + command: string; +} + +export interface PcExecError extends Error { + /** Exit code */ + code?: number; + /** Signal that terminated the process */ + signal?: string; + /** Standard output */ + stdout: string; + /** Standard error */ + stderr: string; + /** Killed by timeout */ + killed?: boolean; +} + +/** + * Extract pass_mgr get commands from a command string + * Supports formats like: + * - $(pass_mgr get key) + * - `pass_mgr get key` + * - pass_mgr get key (direct invocation) + */ +function extractPassMgrGets(command: string): Array<{ key: string; fullMatch: string }> { + const results: Array<{ key: string; fullMatch: string }> = []; + + // Pattern for $(pass_mgr get key) or `pass_mgr get key` + const patterns = [ + /\$\(\s*pass_mgr\s+get\s+(\S+)\s*\)/g, + /`\s*pass_mgr\s+get\s+(\S+)\s*`/g, + /pass_mgr\s+get\s+(\S+)/g, + ]; + + for (const pattern of patterns) { + let match; + while ((match = pattern.exec(command)) !== null) { + results.push({ + key: match[1], + fullMatch: match[0], + }); + } + } + + return results; +} + +/** + * Execute pass_mgr get and return the password + */ +async function getPassword(key: string): Promise { + return new Promise((resolve, reject) => { + const passMgrPath = process.env.PASS_MGR_PATH || 'pass_mgr'; + const child = spawn(passMgrPath, ['get', key], { + stdio: ['ignore', 'pipe', 'pipe'], + env: { + ...process.env, + AGENT_WORKSPACE: process.env.AGENT_WORKSPACE || '', + AGENT_ID: process.env.AGENT_ID || '', + }, + }); + + let stdout = ''; + let stderr = ''; + + child.stdout.on('data', (data) => { + stdout += data.toString(); + }); + + child.stderr.on('data', (data) => { + stderr += data.toString(); + }); + + child.on('close', (code) => { + if (code !== 0) { + reject(new Error(`pass_mgr get failed: ${stderr || stdout}`)); + } else { + resolve(stdout.trim()); + } + }); + + child.on('error', (err) => { + reject(err); + }); + }); +} + +/** + * Sanitize output by replacing passwords with ###### + */ +function sanitizeOutput(output: string, passwords: string[]): string { + let sanitized = output; + for (const password of passwords) { + if (password) { + // Escape special regex characters + const escaped = password.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + const regex = new RegExp(escaped, 'g'); + sanitized = sanitized.replace(regex, '######'); + } + } + return sanitized; +} + +/** + * Replace pass_mgr get commands with actual passwords in command + */ +async function replacePassMgrGets(command: string): Promise<{ command: string; passwords: string[] }> { + const passMgrGets = extractPassMgrGets(command); + const passwords: string[] = []; + let replacedCommand = command; + + for (const { key, fullMatch } of passMgrGets) { + try { + const password = await getPassword(key); + passwords.push(password); + replacedCommand = replacedCommand.replace(fullMatch, password); + } catch (err) { + throw new Error(`Failed to get password for key '${key}': ${err}`); + } + } + + return { command: replacedCommand, passwords }; +} + +/** + * Safe exec wrapper that handles pass_mgr get commands and sanitizes output + * + * @param command - Command to execute + * @param options - Execution options + * @returns Promise resolving to execution result + */ +export async function pcexec(command: string, options: PcExecOptions = {}): Promise { + // Set up environment with workspace/agent info + const env: Record = { + ...process.env, + ...options.env, + }; + + if (process.env.AGENT_WORKSPACE) { + env.AGENT_WORKSPACE = process.env.AGENT_WORKSPACE; + } + if (process.env.AGENT_ID) { + env.AGENT_ID = process.env.AGENT_ID; + } + + // Extract and replace pass_mgr get commands + let finalCommand = command; + let passwords: string[] = []; + + try { + const result = await replacePassMgrGets(command); + finalCommand = result.command; + passwords = result.passwords; + } catch (err) { + throw err; + } + + return new Promise((resolve, reject) => { + const spawnOptions: SpawnOptions = { + cwd: options.cwd, + env, + shell: options.shell ?? true, + windowsHide: options.windowsHide, + uid: options.uid, + gid: options.gid, + }; + + // Use bash for better compatibility + const child = spawn('bash', ['-c', finalCommand], spawnOptions); + + let stdout = ''; + let stderr = ''; + let killed = false; + let timeoutId: NodeJS.Timeout | null = null; + + // Set up timeout + if (options.timeout && options.timeout > 0) { + timeoutId = setTimeout(() => { + killed = true; + child.kill(options.killSignal || 'SIGTERM'); + }, options.timeout); + } + + // Handle stdout + child.stdout?.on('data', (data) => { + stdout += data.toString(); + + // Check maxBuffer + if (options.maxBuffer && stdout.length > options.maxBuffer) { + child.kill(options.killSignal || 'SIGTERM'); + } + }); + + // Handle stderr + child.stderr?.on('data', (data) => { + stderr += data.toString(); + + // Check maxBuffer + if (options.maxBuffer && stderr.length > options.maxBuffer) { + child.kill(options.killSignal || 'SIGTERM'); + } + }); + + // Handle process close + child.on('close', (code, signal) => { + if (timeoutId) { + clearTimeout(timeoutId); + } + + // Sanitize output + const sanitizedStdout = sanitizeOutput(stdout, passwords); + const sanitizedStderr = sanitizeOutput(stderr, passwords); + + if (code === 0) { + resolve({ + stdout: sanitizedStdout, + stderr: sanitizedStderr, + exitCode: 0, + command: finalCommand, + }); + } else { + const error = new Error(`Command failed: ${command}`) as PcExecError; + error.code = code ?? undefined; + error.signal = signal ?? undefined; + error.stdout = sanitizedStdout; + error.stderr = sanitizedStderr; + error.killed = killed; + reject(error); + } + }); + + // Handle process error + child.on('error', (err) => { + if (timeoutId) { + clearTimeout(timeoutId); + } + + const error = new Error(`Failed to execute command: ${err.message}`) as PcExecError; + error.stdout = sanitizeOutput(stdout, passwords); + error.stderr = sanitizeOutput(stderr, passwords); + reject(error); + }); + }); +} + +/** + * Synchronous version of pcexec + * Note: Password sanitization is still applied + */ +export function pcexecSync(command: string, options: PcExecOptions = {}): PcExecResult { + const { execSync } = require('child_process'); + + // Set up environment + const env: Record = { + ...process.env, + ...options.env, + }; + + if (process.env.AGENT_WORKSPACE) { + env.AGENT_WORKSPACE = process.env.AGENT_WORKSPACE; + } + if (process.env.AGENT_ID) { + env.AGENT_ID = process.env.AGENT_ID; + } + + // For sync version, we need to pre-resolve passwords + // This is a limitation - passwords will be in command + const passMgrGets = extractPassMgrGets(command); + let finalCommand = command; + const passwords: string[] = []; + + // Note: In sync version, we can't async fetch passwords + // So we use the original command and rely on the user to not use pass_mgr gets in sync mode + // Or they need to resolve passwords beforehand + + const execOptions: any = { + cwd: options.cwd, + env, + shell: options.shell ?? true, + encoding: 'utf8', + windowsHide: options.windowsHide, + uid: options.uid, + gid: options.gid, + maxBuffer: options.maxBuffer, + timeout: options.timeout, + killSignal: options.killSignal, + }; + + try { + const stdout = execSync(finalCommand, execOptions); + const sanitizedStdout = sanitizeOutput(stdout.toString(), passwords); + + return { + stdout: sanitizedStdout, + stderr: '', + exitCode: 0, + command: finalCommand, + }; + } catch (err: any) { + const sanitizedStdout = sanitizeOutput(err.stdout?.toString() || '', passwords); + const sanitizedStderr = sanitizeOutput(err.stderr?.toString() || '', passwords); + + const error = new Error(`Command failed: ${command}`) as PcExecError; + error.code = err.status; + error.signal = err.signal; + error.stdout = sanitizedStdout; + error.stderr = sanitizedStderr; + throw error; + } +} + +// Default export +export default pcexec; diff --git a/pcexec/tsconfig.json b/pcexec/tsconfig.json new file mode 100644 index 0000000..2f8cd7c --- /dev/null +++ b/pcexec/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "outDir": "./dist", + "rootDir": "./src", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "resolveJsonModule": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "**/*.test.ts"] +} diff --git a/safe-restart/package.json b/safe-restart/package.json new file mode 100644 index 0000000..23fe9bd --- /dev/null +++ b/safe-restart/package.json @@ -0,0 +1,25 @@ +{ + "name": "safe-restart", + "version": "0.1.0", + "description": "Safe restart module for OpenClaw agents", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "scripts": { + "build": "tsc", + "dev": "tsc --watch", + "test": "jest" + }, + "dependencies": { + "@types/node": "^20.0.0", + "express": "^4.18.0", + "ws": "^8.14.0" + }, + "devDependencies": { + "typescript": "^5.0.0", + "@types/express": "^4.17.0", + "@types/ws": "^8.5.0", + "jest": "^29.0.0", + "@types/jest": "^29.0.0", + "ts-jest": "^29.0.0" + } +} diff --git a/safe-restart/src/api.ts b/safe-restart/src/api.ts new file mode 100644 index 0000000..eeb62c2 --- /dev/null +++ b/safe-restart/src/api.ts @@ -0,0 +1,100 @@ +import express from 'express'; +import { StatusManager } from './status-manager'; + +export interface ApiOptions { + port?: number; + statusManager: StatusManager; +} + +/** + * Creates and starts the REST API server for query-restart + */ +export function createApiServer(options: ApiOptions): express.Application { + const { port = 8765, statusManager } = options; + const app = express(); + + app.use(express.json()); + + // POST /query-restart + app.post('/query-restart', (req, res) => { + const { requesterAgentId, requesterSessionKey } = req.body; + + if (!requesterAgentId || !requesterSessionKey) { + return res.status(400).json({ + error: 'Missing required fields: requesterAgentId, requesterSessionKey', + }); + } + + const result = statusManager.queryRestart(requesterAgentId, requesterSessionKey); + + res.json({ + status: result, + timestamp: Date.now(), + }); + }); + + // POST /restart-result + app.post('/restart-result', (req, res) => { + const { status, log } = req.body; + + if (!status || !['ok', 'failed'].includes(status)) { + return res.status(400).json({ + error: 'Invalid status. Must be "ok" or "failed"', + }); + } + + statusManager.completeRestart(status === 'ok', log); + + res.json({ + success: true, + timestamp: Date.now(), + }); + }); + + // GET /status + app.get('/status', (req, res) => { + const agents = statusManager.getAllAgents(); + const global = statusManager.getGlobalStatus(); + + res.json({ + agents, + global, + timestamp: Date.now(), + }); + }); + + // GET /agent/:agentId + app.get('/agent/:agentId', (req, res) => { + const { agentId } = req.params; + const agent = statusManager.getAgent(agentId); + + if (!agent) { + return res.status(404).json({ + error: `Agent ${agentId} not found`, + }); + } + + res.json({ + agent, + timestamp: Date.now(), + }); + }); + + return app; +} + +export function startApiServer(options: ApiOptions): Promise { + const { port = 8765 } = options; + const app = createApiServer(options); + + return new Promise((resolve, reject) => { + const server = app.listen(port, () => { + console.log(`Safe-restart API server listening on port ${port}`); + resolve(); + }); + + server.on('error', (err) => { + reject(err); + }); + }); +} diff --git a/safe-restart/src/index.ts b/safe-restart/src/index.ts new file mode 100644 index 0000000..b07de73 --- /dev/null +++ b/safe-restart/src/index.ts @@ -0,0 +1,4 @@ +export { StatusManager, type AgentStatus, type GlobalStatus, type AgentState } from './status-manager'; +export { createApiServer, startApiServer } from './api'; +export { safeRestart, createSafeRestartTool, type SafeRestartOptions, type SafeRestartResult } from './safe-restart'; +export { SlashCommandHandler, type SlashCommandOptions } from './slash-commands'; diff --git a/safe-restart/src/safe-restart.ts b/safe-restart/src/safe-restart.ts new file mode 100644 index 0000000..7ddb406 --- /dev/null +++ b/safe-restart/src/safe-restart.ts @@ -0,0 +1,288 @@ +import { spawn } from 'child_process'; +import * as fs from 'fs'; +import { promisify } from 'util'; +import { StatusManager } from './status-manager'; + +const sleep = promisify(setTimeout); + +export interface SafeRestartOptions { + /** Agent ID performing the restart */ + agentId: string; + /** Session key for notifications */ + sessionKey: string; + /** API endpoint for query-restart */ + apiEndpoint?: string; + /** Rollback script path */ + rollback?: string; + /** Log file path */ + log?: string; + /** Polling interval in ms (default: 5000) */ + pollInterval?: number; + /** Maximum wait time in ms (default: 300000 = 5min) */ + maxWaitTime?: number; + /** Restart script/command */ + restartScript?: string; + /** Callback for notifications */ + onNotify?: (sessionKey: string, message: string) => Promise; +} + +export interface SafeRestartResult { + success: boolean; + message: string; + log?: string; +} + +/** + * Performs a safe restart with polling and rollback support + */ +export async function safeRestart(options: SafeRestartOptions): Promise { + const { + agentId, + sessionKey, + apiEndpoint = 'http://localhost:8765', + rollback, + log: logPath, + pollInterval = 5000, + maxWaitTime = 300000, + restartScript = 'openclaw gateway restart', + onNotify, + } = options; + + const logs: string[] = []; + const log = (msg: string) => { + const entry = `[${new Date().toISOString()}] ${msg}`; + logs.push(entry); + console.log(entry); + }; + + try { + log(`Starting safe restart. Agent: ${agentId}, Session: ${sessionKey}`); + + // Step 1: Poll query-restart until OK or timeout + const startTime = Date.now(); + let restartApproved = false; + + while (Date.now() - startTime < maxWaitTime) { + try { + const response = await fetch(`${apiEndpoint}/query-restart`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + requesterAgentId: agentId, + requesterSessionKey: sessionKey, + }), + }); + + const data = await response.json(); + + if (data.status === 'OK') { + log('All agents ready for restart'); + restartApproved = true; + break; + } else if (data.status === 'ALREADY_SCHEDULED') { + log('Restart already scheduled by another agent'); + return { + success: false, + message: 'ALREADY_SCHEDULED', + }; + } else { + log(`Waiting for agents to be ready... (${data.status})`); + } + } catch (err) { + log(`Error polling query-restart: ${err}`); + } + + await sleep(pollInterval); + } + + if (!restartApproved) { + const msg = 'Timeout waiting for agents to be ready'; + log(msg); + return { + success: false, + message: msg, + log: logs.join('\n'), + }; + } + + // Step 2: Report restart starting + log('Executing restart...'); + + // Step 3: Start restart in background process + const restartProcess = startBackgroundRestart(restartScript, logPath); + + // Wait a moment for restart to initiate + await sleep(2000); + + // Step 4: Check if gateway comes back + log('Waiting for gateway to restart...'); + await sleep(60000); // Wait 60s as specified + + // Check gateway status + const gatewayOk = await checkGatewayStatus(); + + if (gatewayOk) { + log('Gateway restarted successfully'); + + // Report success + await fetch(`${apiEndpoint}/restart-result`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + status: 'ok', + log: logPath || logs.join('\n'), + }), + }); + + // Notify resumption + if (onNotify) { + await onNotify(sessionKey, 'restart 结束了,我们继续'); + } + + return { + success: true, + message: 'Restart completed successfully', + }; + } else { + log('Gateway restart failed'); + + // Execute rollback if provided + if (rollback) { + log(`Executing rollback: ${rollback}`); + try { + await executeRollback(rollback); + log('Rollback completed'); + } catch (err) { + log(`Rollback failed: ${err}`); + } + } + + // Report failure + await fetch(`${apiEndpoint}/restart-result`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + status: 'failed', + log: logPath || logs.join('\n'), + }), + }); + + // Notify failure + if (onNotify) { + await onNotify(sessionKey, 'restart 失败,已经 rollback,请参考 log 调查。'); + } + + return { + success: false, + message: 'Restart failed', + log: logs.join('\n'), + }; + } + } catch (err) { + const errorMsg = `Unexpected error: ${err}`; + log(errorMsg); + return { + success: false, + message: errorMsg, + log: logs.join('\n'), + }; + } +} + +function startBackgroundRestart(restartScript: string, logPath?: string): void { + const script = ` +#!/bin/bash +set -e +sleep 60 +${restartScript} +openclaw gateway status +`; + + const child = spawn('bash', ['-c', script], { + detached: true, + stdio: logPath ? ['ignore', fs.openSync(logPath, 'w'), fs.openSync(logPath, 'w+')] : 'ignore', + }); + + child.unref(); +} + +async function checkGatewayStatus(): Promise { + return new Promise((resolve) => { + const child = spawn('openclaw', ['gateway', 'status'], { + timeout: 10000, + }); + + let output = ''; + child.stdout?.on('data', (data) => { + output += data.toString(); + }); + + child.on('close', (code) => { + resolve(code === 0 && output.includes('running')); + }); + + child.on('error', () => { + resolve(false); + }); + }); +} + +async function executeRollback(rollbackScript: string): Promise { + return new Promise((resolve, reject) => { + const child = spawn('bash', ['-c', rollbackScript], { + timeout: 120000, + }); + + child.on('close', (code) => { + if (code === 0) { + resolve(); + } else { + reject(new Error(`Rollback script exited with code ${code}`)); + } + }); + + child.on('error', (err) => { + reject(err); + }); + }); +} + +/** + * Safe restart tool that can be registered with OpenClaw + */ +export function createSafeRestartTool(statusManager: StatusManager) { + return { + name: 'safe_restart', + description: 'Perform a safe restart of OpenClaw gateway with agent coordination', + parameters: { + type: 'object', + properties: { + rollback: { + type: 'string', + description: 'Path to rollback script', + }, + log: { + type: 'string', + description: 'Path to log file', + }, + }, + }, + handler: async (params: { rollback?: string; log?: string }, context: { agentId: string; sessionKey: string }) => { + const result = await safeRestart({ + agentId: context.agentId, + sessionKey: context.sessionKey, + rollback: params.rollback, + log: params.log, + async onNotify(sessionKey, message) { + // This would be connected to the messaging system + console.log(`[${sessionKey}] ${message}`); + }, + }); + + return { + success: result.success, + message: result.message, + }; + }, + }; +} diff --git a/safe-restart/src/slash-commands.ts b/safe-restart/src/slash-commands.ts new file mode 100644 index 0000000..a6f9223 --- /dev/null +++ b/safe-restart/src/slash-commands.ts @@ -0,0 +1,182 @@ +import { StatusManager } from './status-manager'; + +export interface SlashCommandOptions { + statusManager: StatusManager; + /** List of authorized user IDs */ + authorizedUsers: string[]; + /** Cooldown duration in seconds */ + cooldownSeconds?: number; + /** Callback for replies */ + onReply: (message: string) => Promise; +} + +interface CommandState { + passMgrEnabled: boolean; + safeRestartEnabled: boolean; + lastToggle: { + 'pass-mgr': number; + 'safe-restart': number; + }; +} + +export class SlashCommandHandler { + private statusManager: StatusManager; + private authorizedUsers: string[]; + private cooldownMs: number; + private onReply: (message: string) => Promise; + private state: CommandState; + + constructor(options: SlashCommandOptions) { + this.statusManager = options.statusManager; + this.authorizedUsers = options.authorizedUsers; + this.cooldownMs = (options.cooldownSeconds || 10) * 1000; + this.onReply = options.onReply; + + this.state = { + passMgrEnabled: true, + safeRestartEnabled: true, + lastToggle: { + 'pass-mgr': 0, + 'safe-restart': 0, + }, + }; + } + + /** + * Handle a slash command + */ + async handle(command: string, userId: string): Promise { + // Check authorization + if (!this.authorizedUsers.includes(userId)) { + await this.onReply('❌ 无权执行此命令'); + return; + } + + const parts = command.trim().split(/\s+/); + const subcommand = parts[1]; + const feature = parts[2] as 'pass-mgr' | 'safe-restart'; + + switch (subcommand) { + case 'status': + await this.handleStatus(); + break; + case 'enable': + await this.handleEnable(feature); + break; + case 'disable': + await this.handleDisable(feature); + break; + default: + await this.onReply( + '用法:\n' + + '`/padded-cell-ctrl status` - 查看状态\n' + + '`/padded-cell-ctrl enable pass-mgr|safe-restart` - 启用功能\n' + + '`/padded-cell-ctrl disable pass-mgr|safe-restart` - 禁用功能' + ); + } + } + + private async handleStatus(): Promise { + const global = this.statusManager.getGlobalStatus(); + const agents = this.statusManager.getAllAgents(); + + const lines = [ + '**PaddedCell 状态**', + '', + `🔐 密码管理: ${this.state.passMgrEnabled ? '✅ 启用' : '❌ 禁用'}`, + `🔄 安全重启: ${this.state.safeRestartEnabled ? '✅ 启用' : '❌ 禁用'}`, + '', + '**Agent 状态:**', + ]; + + for (const agent of agents) { + const emoji = this.getStateEmoji(agent.state); + lines.push(`${emoji} ${agent.agentId}: ${agent.state}`); + } + + if (agents.length === 0) { + lines.push('(暂无 agent 注册)'); + } + + if (global.restartStatus !== 'idle') { + lines.push(''); + lines.push(`⚠️ 重启状态: ${global.restartStatus}`); + if (global.restartScheduledBy) { + lines.push(` 由 ${global.restartScheduledBy} 发起`); + } + } + + await this.onReply(lines.join('\n')); + } + + private async handleEnable(feature: 'pass-mgr' | 'safe-restart'): Promise { + if (!this.isValidFeature(feature)) { + await this.onReply('❌ 未知功能。可用选项: pass-mgr, safe-restart'); + return; + } + + if (this.isOnCooldown(feature)) { + await this.onReply('⏳ 该功能最近刚被修改过,请稍后再试'); + return; + } + + if (feature === 'pass-mgr') { + this.state.passMgrEnabled = true; + } else { + this.state.safeRestartEnabled = true; + } + + this.state.lastToggle[feature] = Date.now(); + await this.onReply(`✅ 已启用 ${feature}`); + } + + private async handleDisable(feature: 'pass-mgr' | 'safe-restart'): Promise { + if (!this.isValidFeature(feature)) { + await this.onReply('❌ 未知功能。可用选项: pass-mgr, safe-restart'); + return; + } + + if (this.isOnCooldown(feature)) { + await this.onReply('⏳ 该功能最近刚被修改过,请稍后再试'); + return; + } + + if (feature === 'pass-mgr') { + this.state.passMgrEnabled = false; + } else { + this.state.safeRestartEnabled = false; + } + + this.state.lastToggle[feature] = Date.now(); + await this.onReply(`✅ 已禁用 ${feature}`); + } + + private isValidFeature(feature: string): feature is 'pass-mgr' | 'safe-restart' { + return feature === 'pass-mgr' || feature === 'safe-restart'; + } + + private isOnCooldown(feature: 'pass-mgr' | 'safe-restart'): boolean { + const lastToggle = this.state.lastToggle[feature]; + return Date.now() - lastToggle < this.cooldownMs; + } + + private getStateEmoji(state: string): string { + switch (state) { + case 'idle': return '💤'; + case 'busy': return '⚡'; + case 'focus': return '🎯'; + case 'freeze': return '🧊'; + case 'pre-freeze': return '⏳'; + case 'pre-freeze-focus': return '📝'; + default: return '❓'; + } + } + + isPassMgrEnabled(): boolean { + return this.state.passMgrEnabled; + } + + isSafeRestartEnabled(): boolean { + return this.state.safeRestartEnabled; + } +} diff --git a/safe-restart/src/status-manager.ts b/safe-restart/src/status-manager.ts new file mode 100644 index 0000000..ee67811 --- /dev/null +++ b/safe-restart/src/status-manager.ts @@ -0,0 +1,396 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import { EventEmitter } from 'events'; + +export type AgentState = + 'idle' | + 'busy' | + 'focus' | + 'freeze' | + 'pre-freeze' | + 'pre-freeze-focus'; + +export interface AgentStatus { + agentId: string; + state: AgentState; + workflow: string | null; + activeSessions: string[]; + lastSessions: string[]; + updatedAt: number; +} + +export interface GlobalStatus { + restartScheduledBy: string | null; + restartSession: string | null; + restartStatus: 'idle' | 'waiting' | 'restarting' | 'rollback'; + updatedAt: number; +} + +export interface StatusManagerOptions { + dataDir?: string; + persistenceInterval?: number; +} + +/** + * Manages agent states and global restart status + */ +export class StatusManager extends EventEmitter { + private agents: Map = new Map(); + private global: GlobalStatus; + private dataDir: string; + private persistenceInterval: number; + private persistenceTimer: NodeJS.Timeout | null = null; + + constructor(options: StatusManagerOptions = {}) { + super(); + this.dataDir = options.dataDir || path.join(process.env.HOME || '.', '.paddedcell'); + this.persistenceInterval = options.persistenceInterval || 5000; + + this.global = { + restartScheduledBy: null, + restartSession: null, + restartStatus: 'idle', + updatedAt: Date.now(), + }; + + this.ensureDataDir(); + this.loadFromDisk(); + this.startPersistence(); + } + + private ensureDataDir(): void { + if (!fs.existsSync(this.dataDir)) { + fs.mkdirSync(this.dataDir, { recursive: true, mode: 0o700 }); + } + } + + private getAgentFilePath(agentId: string): string { + return path.join(this.dataDir, `agent_${agentId}.json`); + } + + private getGlobalFilePath(): string { + return path.join(this.dataDir, 'global.json'); + } + + private loadFromDisk(): void { + // Load global status + const globalPath = this.getGlobalFilePath(); + if (fs.existsSync(globalPath)) { + try { + const data = fs.readFileSync(globalPath, 'utf8'); + this.global = JSON.parse(data); + } catch (err) { + console.error('Failed to load global status:', err); + } + } + + // Load agent statuses + try { + const files = fs.readdirSync(this.dataDir); + for (const file of files) { + if (file.startsWith('agent_') && file.endsWith('.json')) { + try { + const data = fs.readFileSync(path.join(this.dataDir, file), 'utf8'); + const agent = JSON.parse(data) as AgentStatus; + this.agents.set(agent.agentId, agent); + } catch (err) { + console.error(`Failed to load agent status from ${file}:`, err); + } + } + } + } catch (err) { + console.error('Failed to read data directory:', err); + } + } + + private saveToDisk(): void { + // Save global status + try { + fs.writeFileSync( + this.getGlobalFilePath(), + JSON.stringify(this.global, null, 2), + { mode: 0o600 } + ); + } catch (err) { + console.error('Failed to save global status:', err); + } + + // Save agent statuses + for (const [agentId, agent] of this.agents) { + try { + fs.writeFileSync( + this.getAgentFilePath(agentId), + JSON.stringify(agent, null, 2), + { mode: 0o600 } + ); + } catch (err) { + console.error(`Failed to save agent status for ${agentId}:`, err); + } + } + } + + private startPersistence(): void { + this.persistenceTimer = setInterval(() => { + this.saveToDisk(); + }, this.persistenceInterval); + } + + stopPersistence(): void { + if (this.persistenceTimer) { + clearInterval(this.persistenceTimer); + this.persistenceTimer = null; + } + this.saveToDisk(); + } + + // Agent state management + + getOrCreateAgent(agentId: string): AgentStatus { + if (!this.agents.has(agentId)) { + const agent: AgentStatus = { + agentId, + state: 'idle', + workflow: null, + activeSessions: [], + lastSessions: [], + updatedAt: Date.now(), + }; + this.agents.set(agentId, agent); + this.emit('agentCreated', agent); + } + return this.agents.get(agentId)!; + } + + getAgent(agentId: string): AgentStatus | undefined { + return this.agents.get(agentId); + } + + getAllAgents(): AgentStatus[] { + return Array.from(this.agents.values()); + } + + onMessageStart(session: string, agentId: string): void { + const agent = this.getOrCreateAgent(agentId); + + // Don't update state for heartbeat sessions + if (this.isHeartbeatSession(session)) { + return; + } + + if (agent.state === 'idle') { + agent.state = 'busy'; + } + + if (!agent.activeSessions.includes(session)) { + agent.activeSessions.push(session); + } + + agent.updatedAt = Date.now(); + this.emit('stateChanged', agent); + } + + onMessageEnd(session: string, agentId: string): void { + const agent = this.getOrCreateAgent(agentId); + + // Remove from active sessions + agent.activeSessions = agent.activeSessions.filter(s => s !== session); + + // Add to last sessions if not already there + if (!agent.lastSessions.includes(session)) { + agent.lastSessions.unshift(session); + if (agent.lastSessions.length > 10) { + agent.lastSessions = agent.lastSessions.slice(0, 10); + } + } + + // State transitions + if (agent.activeSessions.length === 0) { + if (agent.state === 'busy') { + agent.state = 'idle'; + } else if (agent.state === 'pre-freeze' || agent.state === 'pre-freeze-focus') { + agent.state = 'freeze'; + } + } + + agent.updatedAt = Date.now(); + this.emit('stateChanged', agent); + + // Check if all agents are frozen (for restart completion) + if (agent.state === 'freeze') { + this.checkAllFrozen(); + } + } + + setWorkflow(agentId: string, workflow: string | null): void { + const agent = this.getOrCreateAgent(agentId); + agent.workflow = workflow; + + if (workflow) { + agent.state = 'focus'; + } else { + // Transition from focus to idle or busy + if (agent.activeSessions.length === 0) { + agent.state = 'idle'; + } else { + agent.state = 'busy'; + } + } + + agent.updatedAt = Date.now(); + this.emit('stateChanged', agent); + } + + isHeartbeatSession(session: string): boolean { + // Check if session is a heartbeat session + // This can be customized based on naming convention or metadata + return session.includes('heartbeat') || session.includes('poll'); + } + + // Query restart logic + + queryRestart(requesterAgentId: string, requesterSessionKey: string): 'OK' | 'NOT_READY' | 'ALREADY_SCHEDULED' { + // Check if restart is already scheduled + if (this.global.restartStatus !== 'idle') { + // If same agent is requesting, allow continuation + if (this.global.restartScheduledBy === requesterAgentId) { + return this.allAgentsFrozen() ? 'OK' : 'NOT_READY'; + } + return 'ALREADY_SCHEDULED'; + } + + // Schedule restart + this.global.restartScheduledBy = requesterAgentId; + this.global.restartSession = requesterSessionKey; + this.global.restartStatus = 'waiting'; + this.global.updatedAt = Date.now(); + + // Transition agents to freeze/pre-freeze states + for (const [agentId, agent] of this.agents) { + if (agentId === requesterAgentId) { + // Don't freeze the requester agent + continue; + } + + switch (agent.state) { + case 'idle': + agent.state = 'freeze'; + break; + case 'busy': + agent.state = 'pre-freeze'; + break; + case 'focus': + agent.state = 'pre-freeze-focus'; + // Notify agent to prepare for restart + this.emit('preparingRestart', agent); + break; + } + + agent.updatedAt = Date.now(); + this.emit('stateChanged', agent); + } + + this.saveToDisk(); + + // Check if all are frozen immediately + if (this.allAgentsFrozen()) { + return 'OK'; + } + + return 'NOT_READY'; + } + + allAgentsFrozen(): boolean { + for (const [agentId, agent] of this.agents) { + // Skip the agent that scheduled the restart + if (agentId === this.global.restartScheduledBy) { + continue; + } + if (agent.state !== 'freeze') { + return false; + } + } + return true; + } + + private checkAllFrozen(): void { + if (this.allAgentsFrozen() && this.global.restartStatus === 'waiting') { + this.emit('allFrozen'); + } + } + + // Restart completion + + completeRestart(success: boolean, log?: string): void { + if (success) { + this.global.restartStatus = 'idle'; + + // Unfreeze all agents + for (const agent of this.agents.values()) { + if (agent.state === 'freeze') { + // Restore previous state from lastSessions + agent.state = agent.activeSessions.length > 0 ? 'busy' : 'idle'; + agent.updatedAt = Date.now(); + this.emit('stateChanged', agent); + this.emit('unfrozen', agent); + } + } + + this.emit('restartCompleted'); + } else { + this.global.restartStatus = 'rollback'; + this.emit('restartFailed', log); + } + + this.global.restartScheduledBy = null; + this.global.restartSession = null; + this.global.updatedAt = Date.now(); + this.saveToDisk(); + } + + // Global status getters + + getGlobalStatus(): GlobalStatus { + return { ...this.global }; + } + + isRestartScheduled(): boolean { + return this.global.restartStatus !== 'idle'; + } + + // For focus mode: check if agent should respond + + shouldRespond(agentId: string, session: string): boolean { + const agent = this.getAgent(agentId); + if (!agent) return true; + + // In focus mode, only respond to workflow sessions + if (agent.state === 'focus' || agent.state === 'pre-freeze-focus') { + return agent.workflow !== null && session.includes(agent.workflow); + } + + // In freeze/pre-freeze states, don't accept new messages + if (agent.state === 'freeze' || agent.state === 'pre-freeze') { + return false; + } + + return true; + } + + getBusyMessage(agentId: string): string { + const agent = this.getAgent(agentId); + if (!agent) return '在忙,无法应答'; + + switch (agent.state) { + case 'focus': + case 'pre-freeze-focus': + return '当前处于专注模式,无法应答非工作流消息'; + case 'freeze': + case 'pre-freeze': + return '系统正在准备重启,请稍后再试'; + case 'busy': + return '正在处理其他消息,请稍后再试'; + default: + return '在忙,无法应答'; + } + } +} diff --git a/safe-restart/tsconfig.json b/safe-restart/tsconfig.json new file mode 100644 index 0000000..2f8cd7c --- /dev/null +++ b/safe-restart/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "outDir": "./dist", + "rootDir": "./src", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "resolveJsonModule": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "**/*.test.ts"] +} From b37ebb3db17c2870625ee484f334bf609882a902 Mon Sep 17 00:00:00 2001 From: zhi Date: Thu, 5 Mar 2026 09:38:38 +0000 Subject: [PATCH 02/28] docs: add bilingual README with language switcher - Update README.md to English version with language navigation - Add README.zh-CN.md for Simplified Chinese - Add language switcher links in both files --- README.md | 103 ++++++++++++++++++++---------------- README.zh-CN.md | 138 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 195 insertions(+), 46 deletions(-) create mode 100644 README.zh-CN.md diff --git a/README.md b/README.md index 11cf0dd..a0510a2 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,47 @@ +
+ +[English](README.md) | [简体中文](README.zh-CN.md) + +
+ # PaddedCell -OpenClaw 插件:安全密码管理 + 安全执行 + 安全重启 +OpenClaw plugin for secure password management, safe command execution, and coordinated agent restart. -## 功能模块 +## Features -### 1. pass_mgr - 密码管理二进制 (Go) +### 1. pass_mgr - Password Manager Binary (Go) -使用 AES-256-GCM 加密,每个 agent 基于公私钥进行加/解密。 +AES-256-GCM encryption, per-agent key-based encryption/decryption. ```bash -# 初始化 +# Initialize pass_mgr admin init [--key-path ] -# 获取密码 +# Get password pass_mgr get [--username] -# 生成密码 (agent 可用) +# Generate password (agent can use) pass_mgr generate [--username ] -# 设置密码 (仅人类) +# Set password (human only) pass_mgr set [--username ] -# 删除密码 +# Delete password pass_mgr unset -# 轮换密码 +# Rotate password pass_mgr rotate ``` -**安全特性:** -- Agent 无法执行 `set` 操作(通过环境变量检测) -- 未初始化前所有操作报错 -- Admin 密码泄露检测(监控 message/tool calling) +**Security Features:** +- Agents cannot execute `set` (detected via environment variables) +- All operations fail before initialization +- Admin password leak detection (monitors messages/tool calls) -### 2. pcexec - 安全执行工具 (TypeScript) +### 2. pcexec - Safe Execution Tool (TypeScript) -与 OpenClaw 原生 exec 接口一致,自动处理 pass_mgr get 并脱敏输出。 +Compatible with OpenClaw native exec interface, automatically handles `pass_mgr get` and sanitizes output. ```typescript import { pcexec } from 'pcexec'; @@ -44,47 +50,47 @@ const result = await pcexec('echo $(pass_mgr get mypassword)', { cwd: '/workspace', timeout: 30000, }); -// result.stdout 中密码会被替换为 ###### +// Passwords in result.stdout will be replaced with ###### ``` -### 3. safe-restart - 安全重启模块 (TypeScript) +### 3. safe-restart - Safe Restart Module (TypeScript) -提供 agent 状态管理和协调重启。 +Provides agent state management and coordinated restart. -**Agent 状态:** -- `idle` - 空闲 -- `busy` - 处理消息中 -- `focus` - 专注模式(工作流) -- `freeze` - 冻结(不接受新消息) -- `pre-freeze` - 准备冻结 -- `pre-freeze-focus` - 准备冻结(专注模式) +**Agent States:** +- `idle` - Idle +- `busy` - Processing messages +- `focus` - Focus mode (workflow) +- `freeze` - Frozen (not accepting new messages) +- `pre-freeze` - Preparing to freeze +- `pre-freeze-focus` - Preparing to freeze (focus mode) -**API:** -- `POST /query-restart` - 查询重启就绪状态 -- `POST /restart-result` - 报告重启结果 -- `GET /status` - 获取所有状态 +**APIs:** +- `POST /query-restart` - Query restart readiness +- `POST /restart-result` - Report restart result +- `GET /status` - Get all statuses -**Slash 命令:** +**Slash Commands:** ``` /padded-cell-ctrl status /padded-cell-ctrl enable pass-mgr|safe-restart /padded-cell-ctrl disable pass-mgr|safe-restart ``` -## 目录结构 +## Project Structure ``` PaddedCell/ -├── pass_mgr/ # Go 密码管理二进制 +├── pass_mgr/ # Go password manager binary │ ├── src/ │ │ └── main.go │ └── go.mod -├── pcexec/ # TypeScript 安全执行工具 +├── pcexec/ # TypeScript safe execution tool │ ├── src/ │ │ └── index.ts │ ├── package.json │ └── tsconfig.json -├── safe-restart/ # TypeScript 安全重启模块 +├── safe-restart/ # TypeScript safe restart module │ ├── src/ │ │ ├── index.ts │ │ ├── status-manager.ts @@ -93,35 +99,40 @@ PaddedCell/ │ │ └── slash-commands.ts │ ├── package.json │ └── tsconfig.json -├── docs/ # 文档 -├── PROJECT_PLAN.md # 项目计划 -├── AGENT_TASKS.md # 任务清单 -└── README.md +├── docs/ # Documentation +├── PROJECT_PLAN.md # Project plan +├── AGENT_TASKS.md # Task list +├── README.md # This file (English) +└── README.zh-CN.md # Chinese version ``` -## 开发 +## Development ```bash # Clone git clone https://git.hangman-lab.top/nav/PaddedCell.git cd PaddedCell -# Build pass_mgr (需要 Go) +# Build pass_mgr (requires Go) cd pass_mgr go build -o pass_mgr src/main.go -# Build pcexec (需要 Node.js) +# Build pcexec (requires Node.js) cd ../pcexec npm install npm run build -# Build safe-restart (需要 Node.js) +# Build safe-restart (requires Node.js) cd ../safe-restart npm install npm run build ``` -## 开发分支 +## Branches -- `main` - 主分支 -- `dev/zhi` - 当前开发分支 +- `main` - Main branch +- `dev/zhi` - Development branch + +## License + +MIT diff --git a/README.zh-CN.md b/README.zh-CN.md new file mode 100644 index 0000000..8cfa4ee --- /dev/null +++ b/README.zh-CN.md @@ -0,0 +1,138 @@ +
+ +[English](README.md) | [简体中文](README.zh-CN.md) + +
+ +# PaddedCell + +OpenClaw 插件:安全密码管理 + 安全执行 + 安全重启 + +## 功能模块 + +### 1. pass_mgr - 密码管理二进制 (Go) + +使用 AES-256-GCM 加密,每个 agent 基于公私钥进行加/解密。 + +```bash +# 初始化 +pass_mgr admin init [--key-path ] + +# 获取密码 +pass_mgr get [--username] + +# 生成密码 (agent 可用) +pass_mgr generate [--username ] + +# 设置密码 (仅人类) +pass_mgr set [--username ] + +# 删除密码 +pass_mgr unset + +# 轮换密码 +pass_mgr rotate +``` + +**安全特性:** +- Agent 无法执行 `set` 操作(通过环境变量检测) +- 未初始化前所有操作报错 +- Admin 密码泄露检测(监控 message/tool calling) + +### 2. pcexec - 安全执行工具 (TypeScript) + +与 OpenClaw 原生 exec 接口一致,自动处理 pass_mgr get 并脱敏输出。 + +```typescript +import { pcexec } from 'pcexec'; + +const result = await pcexec('echo $(pass_mgr get mypassword)', { + cwd: '/workspace', + timeout: 30000, +}); +// result.stdout 中密码会被替换为 ###### +``` + +### 3. safe-restart - 安全重启模块 (TypeScript) + +提供 agent 状态管理和协调重启。 + +**Agent 状态:** +- `idle` - 空闲 +- `busy` - 处理消息中 +- `focus` - 专注模式(工作流) +- `freeze` - 冻结(不接受新消息) +- `pre-freeze` - 准备冻结 +- `pre-freeze-focus` - 准备冻结(专注模式) + +**API:** +- `POST /query-restart` - 查询重启就绪状态 +- `POST /restart-result` - 报告重启结果 +- `GET /status` - 获取所有状态 + +**Slash 命令:** +``` +/padded-cell-ctrl status +/padded-cell-ctrl enable pass-mgr|safe-restart +/padded-cell-ctrl disable pass-mgr|safe-restart +``` + +## 项目结构 + +``` +PaddedCell/ +├── pass_mgr/ # Go 密码管理二进制 +│ ├── src/ +│ │ └── main.go +│ └── go.mod +├── pcexec/ # TypeScript 安全执行工具 +│ ├── src/ +│ │ └── index.ts +│ ├── package.json +│ └── tsconfig.json +├── safe-restart/ # TypeScript 安全重启模块 +│ ├── src/ +│ │ ├── index.ts +│ │ ├── status-manager.ts +│ │ ├── api.ts +│ │ ├── safe-restart.ts +│ │ └── slash-commands.ts +│ ├── package.json +│ └── tsconfig.json +├── docs/ # 文档 +├── PROJECT_PLAN.md # 项目计划 +├── AGENT_TASKS.md # 任务清单 +├── README.md # 英文版本 +└── README.zh-CN.md # 本文档 (简体中文) +``` + +## 开发 + +```bash +# Clone +git clone https://git.hangman-lab.top/nav/PaddedCell.git +cd PaddedCell + +# Build pass_mgr (需要 Go) +cd pass_mgr +go build -o pass_mgr src/main.go + +# Build pcexec (需要 Node.js) +cd ../pcexec +npm install +npm run build + +# Build safe-restart (需要 Node.js) +cd ../safe-restart +npm install +npm run build +``` + +## 分支 + +- `main` - 主分支 +- `dev/zhi` - 开发分支 + +## 许可证 + +MIT From 849effd301bdf096220386c47e50fd099853e244 Mon Sep 17 00:00:00 2001 From: zhi Date: Thu, 5 Mar 2026 09:48:40 +0000 Subject: [PATCH 03/28] feat: add install script and update project docs - Add install.mjs: unified installer with dependency check, build, install, config - Update PROJECT_PLAN.md: add section 6 for installation script requirements - Update AGENT_TASKS.md: add T-7001~T-7005 for installation tasks - Support flags: --prefix, --build-only, --skip-check, --verbose --- AGENT_TASKS.md | 83 ++++--- PROJECT_PLAN.md | 44 ++++ install.mjs | 630 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 723 insertions(+), 34 deletions(-) create mode 100755 install.mjs diff --git a/AGENT_TASKS.md b/AGENT_TASKS.md index 1891b5e..c58bb9a 100644 --- a/AGENT_TASKS.md +++ b/AGENT_TASKS.md @@ -1,4 +1,4 @@ -# PaddedCell — Agent Tasks +# PaddedCell - Agent Tasks > 任务拆分 + 依赖关系(基于 PROJECT_PLAN.md) @@ -9,98 +9,113 @@ --- ## 0. 项目准备 -- **T-0001**:确认配置项清单(路径模板、rotate 语义、admin 泄露检测范围) - - Deps: — -- **T-0002**:确定加密库与存储格式(选型与接口约束) +- **T-0001**:确认配置项清单(路径模板、rotate 语义、admin 泄露检测范围) + - Deps: - +- **T-0002**:确定加密库与存储格式(选型与接口约束) - Deps: T-0001 --- ## 1. pass_mgr 二进制 -- **T-1001**:CLI 命令规范与参数校验(get/generate/unset/rotate/admin init/set) +- **T-1001**:CLI 命令规范与参数校验(get/generate/unset/rotate/admin init/set) - Deps: T-0001 -- **T-1002**:初始化与 admin 密码存储/校验机制 +- **T-1002**:初始化与 admin 密码存储/校验机制 - Deps: T-1001, T-0002 -- **T-1003**:加/解密与存取实现(内置加密库) +- **T-1003**:加/解密与存取实现(内置加密库) - Deps: T-1001, T-0002 -- **T-1004**:generate / rotate 实现与语义落地 +- **T-1004**:generate / rotate 实现与语义落地 - Deps: T-1003 -- **T-1005**:admin-only set 实现(环境变量检测 + 禁止 agent 执行) +- **T-1005**:admin-only set 实现(环境变量检测 + 禁止 agent 执行) - Deps: T-1001 -- **T-1006**:未初始化状态阻断逻辑(所有 get/generate/set 报错) +- **T-1006**:未初始化状态阻断逻辑(所有 get/generate/set 报错) - Deps: T-1002 --- ## 2. pcexec 工具(TS) -- **T-2001**:exec 参数/行为兼容设计(与原生 exec 对齐) - - Deps: — -- **T-2002**:pass_mgr get 检测与预执行(不限 `$(...)`) +- **T-2001**:exec 参数/行为兼容设计(与原生 exec 对齐) + - Deps: - +- **T-2002**:pass_mgr get 检测与预执行(不限 `$(...)`) - Deps: T-2001, T-1001 -- **T-2003**:多密码脱敏替换(stdout/stderr) +- **T-2003**:多密码脱敏替换(stdout/stderr) - Deps: T-2002 -- **T-2004**:错误处理/退出码一致性 +- **T-2004**:错误处理/退出码一致性 - Deps: T-2001 --- ## 3. 安全重启(CalmGate 功能并入) -- **T-3001**:状态机与 session tracker(idle/busy/focus/freeze…) - - Deps: — -- **T-3002**:消息生命周期 hooks(start/end)与状态迁移 +- **T-3001**:状态机与 session tracker(idle/busy/focus/freeze…) + - Deps: - +- **T-3002**:消息生命周期 hooks(start/end)与状态迁移 - Deps: T-3001 -- **T-3003**:workflow/focus 机制与“忙碌回复” +- **T-3003**:workflow/focus 机制与"忙碌回复" - Deps: T-3001 -- **T-3004**:query-restart API(OK/NOT_READY/ALREADY_SCHEDULED) +- **T-3004**:query-restart API(OK/NOT_READY/ALREADY_SCHEDULED) - Deps: T-3001, T-3002 -- **T-3005**:safe-restart 工具(轮询/重启/rollback/log) +- **T-3005**:safe-restart 工具(轮询/重启/rollback/log) - Deps: T-3004 -- **T-3006**:重启后恢复与通知(冻结/解冻与回到工作 session) +- **T-3006**:重启后恢复与通知(冻结/解冻与回到工作 session) - Deps: T-3005 -- **T-3007**:持久化(mem+file)与恢复策略 +- **T-3007**:持久化(mem+file)与恢复策略 - Deps: T-3001 --- ## 4. 安全监控与泄露防护 -- **T-4001**:admin 密码泄露检测(message/tool calling) +- **T-4001**:admin 密码泄露检测(message/tool calling) - Deps: T-1002 -- **T-4002**:泄露触发处理(重置未初始化 + 严重漏洞日志) +- **T-4002**:泄露触发处理(重置未初始化 + 严重漏洞日志) - Deps: T-4001 --- ## 4.1 功能开关(Slash Commands) -- **T-4101**:实现 `/padded-cell-ctrl` 命令(status/enable/disable) - - Deps: — -- **T-4102**:开关状态持久化、权限限制(授权用户)与 10 秒冷却 +- **T-4101**:实现 `/padded-cell-ctrl` 命令(status/enable/disable) + - Deps: - +- **T-4102**:开关状态持久化、权限限制(授权用户)与 10 秒冷却 - Deps: T-4101 --- ## 5. 文档 & Skill 指南 -- **T-5001**:Agent 使用指南(如何用 pass_mgr/pcexec) +- **T-5001**:Agent 使用指南(如何用 pass_mgr/pcexec) - Deps: T-1001, T-2001 -- **T-5002**:Skill 文档与示例(正确使用密码相关工具) +- **T-5002**:Skill 文档与示例(正确使用密码相关工具) - Deps: T-5001 --- ## 6. 测试与验收 -- **T-6001**:pass_mgr 单测(get/generate/unset/rotate/admin init) +- **T-6001**:pass_mgr 单测(get/generate/unset/rotate/admin init) - Deps: T-1002, T-1003, T-1004, T-1005, T-1006 -- **T-6002**:pcexec 兼容性测试(参数/管道/多密码替换) +- **T-6002**:pcexec 兼容性测试(参数/管道/多密码替换) - Deps: T-2002, T-2003, T-2004 -- **T-6003**:安全重启回归(并发/冻结/rollback) +- **T-6003**:安全重启回归(并发/冻结/rollback) - Deps: T-3004, T-3005, T-3006, T-3007 -- **T-6004**:admin 泄露触发测试 +- **T-6004**:admin 泄露触发测试 - Deps: T-4002 --- +## 7. 安装脚本 +- **T-7001**:依赖检测(Node.js, Go, openclaw CLI, 平台检测) + - Deps: — +- **T-7002**:自动构建逻辑(Go + TypeScript) + - Deps: T-1001, T-2001, T-3001 +- **T-7003**:安装逻辑(二进制/模块复制、PATH 配置) + - Deps: T-7002 +- **T-7004**:初始化向导(admin 密码设置、配置生成) + - Deps: T-1002, T-7003 +- **T-7005**:安装验证与摘要输出 + - Deps: T-7004 + +--- + ## 依赖关系示意(简化) - 0.* → 1.* / 2.* / 3.* - 1.* → 4.* → 6.* - 2.* → 6.* - 3.* → 6.* - 5.* 可与 1.* / 2.* 并行,但需接口稳定 +- 7.* 依赖 1.* / 2.* / 3.* 完成(可在构建后执行) diff --git a/PROJECT_PLAN.md b/PROJECT_PLAN.md index 2284c72..0136023 100644 --- a/PROJECT_PLAN.md +++ b/PROJECT_PLAN.md @@ -244,6 +244,50 @@ Request: - 任务分配清单 - 测试用例列表 +## 6. 安装脚本 + +### 6.1 需求 +提供统一的插件安装脚本 `install.mjs`,实现以下功能: + +**检测与依赖** +- 检测系统平台 (Linux/macOS) +- 检测必要依赖 (Node.js, Go, openclaw CLI) +- 检测 openclaw 配置目录 + +**构建** +- 自动构建 pass_mgr Go 二进制 +- 自动构建 pcexec TypeScript 模块 +- 自动构建 safe-restart TypeScript 模块 + +**安装** +- 安装 pass_mgr 到系统 PATH (或 openclaw bin 目录) +- 安装 TypeScript 模块到 openclaw skills 目录 +- 创建必要的配置文件和目录 + +**配置** +- 初始化 pass_mgr admin (引导用户设置 admin 密码) +- 配置环境变量 +- 注册 safe-restart API 服务 + +**验证** +- 验证所有组件安装成功 +- 输出安装摘要和下一步操作提示 + +### 6.2 使用方式 +```bash +# 默认安装 +node install.mjs + +# 指定安装路径 +node install.mjs --prefix /usr/local + +# 仅构建不安装 +node install.mjs --build-only + +# 跳过依赖检测 +node install.mjs --skip-check +``` + --- > 更新日志:v0.1(基于当前需求整理) diff --git a/install.mjs b/install.mjs new file mode 100755 index 0000000..9365897 --- /dev/null +++ b/install.mjs @@ -0,0 +1,630 @@ +#!/usr/bin/env node + +/** + * PaddedCell Plugin Installer + * + * Usage: + * node install.mjs + * node install.mjs --prefix /usr/local + * node install.mjs --build-only + * node install.mjs --skip-check + */ + +import { execSync, spawn } from 'child_process'; +import { existsSync, mkdirSync, copyFileSync, writeFileSync, readFileSync, chmodSync } from 'fs'; +import { dirname, join, resolve } from 'path'; +import { fileURLToPath } from 'url'; +import { homedir, platform } from 'os'; +import readline from 'readline'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +// Parse arguments +const args = process.argv.slice(2); +const options = { + prefix: null, + buildOnly: args.includes('--build-only'), + skipCheck: args.includes('--skip-check'), + verbose: args.includes('--verbose') || args.includes('-v'), +}; + +// Parse --prefix value +const prefixIndex = args.indexOf('--prefix'); +if (prefixIndex !== -1 && args[prefixIndex + 1]) { + options.prefix = resolve(args[prefixIndex + 1]); +} + +// Colors for output +const colors = { + reset: '\x1b[0m', + red: '\x1b[31m', + green: '\x1b[32m', + yellow: '\x1b[33m', + blue: '\x1b[34m', + cyan: '\x1b[36m', +}; + +function log(message, color = 'reset') { + console.log(`${colors[color]}${message}${colors.reset}`); +} + +function logStep(step, message) { + log(`[${step}/7] ${message}`, 'cyan'); +} + +function logSuccess(message) { + log(` ✓ ${message}`, 'green'); +} + +function logWarning(message) { + log(` ⚠ ${message}`, 'yellow'); +} + +function logError(message) { + log(` ✗ ${message}`, 'red'); +} + +function exec(command, options = {}) { + const defaultOptions = { + cwd: __dirname, + stdio: options.silent ? 'pipe' : 'inherit', + encoding: 'utf8', + }; + return execSync(command, { ...defaultOptions, ...options }); +} + +async function prompt(question) { + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, + }); + return new Promise((resolve) => { + rl.question(question, (answer) => { + rl.close(); + resolve(answer.trim()); + }); + }); +} + +async function promptPassword(question) { + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, + }); + return new Promise((resolve) => { + // Hide password input + const stdin = process.stdin; + stdin.on('data', (char) => { + char = char.toString(); + switch (char) { + case '\n': + case '\r': + case '\u0004': + stdin.pause(); + break; + default: + process.stdout.write('*'); + break; + } + }); + + rl.question(question, (answer) => { + rl.close(); + console.log(); // New line after password + resolve(answer.trim()); + }); + }); +} + +// ============================================================================ +// Step 1: Environment Detection +// ============================================================================ + +function detectEnvironment() { + logStep(1, 'Detecting environment...'); + + const env = { + platform: platform(), + isLinux: platform() === 'linux', + isMacOS: platform() === 'darwin', + nodeVersion: null, + goVersion: null, + openclawPath: null, + openclawDir: null, + }; + + // Check Node.js + try { + const version = exec('node --version', { silent: true }).trim(); + env.nodeVersion = version; + logSuccess(`Node.js ${version}`); + } catch { + logError('Node.js not found'); + } + + // Check Go + try { + const version = exec('go version', { silent: true }).trim(); + env.goVersion = version; + logSuccess(`Go ${version}`); + } catch { + logError('Go not found'); + } + + // Check openclaw + try { + const path = exec('which openclaw', { silent: true }).trim(); + env.openclawPath = path; + logSuccess(`openclaw at ${path}`); + + // Try to find openclaw config dir + const home = homedir(); + const possibleDirs = [ + join(home, '.openclaw'), + join(home, '.config', 'openclaw'), + '/etc/openclaw', + ]; + + for (const dir of possibleDirs) { + if (existsSync(dir)) { + env.openclawDir = dir; + logSuccess(`openclaw config dir: ${dir}`); + break; + } + } + + if (!env.openclawDir) { + env.openclawDir = join(home, '.openclaw'); + logWarning(`openclaw config dir not found, will use: ${env.openclawDir}`); + } + } catch { + logWarning('openclaw CLI not found in PATH'); + env.openclawDir = join(homedir(), '.openclaw'); + } + + return env; +} + +function checkDependencies(env) { + if (options.skipCheck) { + logWarning('Skipping dependency checks'); + return true; + } + + logStep(2, 'Checking dependencies...'); + + let hasErrors = false; + + if (!env.nodeVersion) { + logError('Node.js is required. Please install Node.js 18+'); + hasErrors = true; + } else { + const majorVersion = parseInt(env.nodeVersion.slice(1).split('.')[0]); + if (majorVersion < 18) { + logError(`Node.js 18+ required, found ${env.nodeVersion}`); + hasErrors = true; + } else { + logSuccess(`Node.js version OK`); + } + } + + if (!env.goVersion) { + logError('Go is required. Please install Go 1.22+'); + hasErrors = true; + } else { + logSuccess(`Go version OK`); + } + + if (hasErrors) { + log('\nPlease install missing dependencies and try again.', 'red'); + process.exit(1); + } + + return true; +} + +// ============================================================================ +// Step 3: Build Components +// ============================================================================ + +async function buildComponents(env) { + logStep(3, 'Building components...'); + + // Build pass_mgr + log(' Building pass_mgr (Go)...', 'blue'); + try { + const passMgrDir = join(__dirname, 'pass_mgr'); + if (!existsSync(passMgrDir)) { + throw new Error('pass_mgr directory not found'); + } + + exec('go mod tidy', { cwd: passMgrDir, silent: !options.verbose }); + exec('go build -o dist/pass_mgr src/main.go', { + cwd: passMgrDir, + silent: !options.verbose + }); + + // Verify binary exists + const binaryPath = join(passMgrDir, 'dist', 'pass_mgr'); + if (!existsSync(binaryPath)) { + throw new Error('pass_mgr binary not found after build'); + } + + chmodSync(binaryPath, 0o755); + logSuccess('pass_mgr built successfully'); + } catch (err) { + logError(`Failed to build pass_mgr: ${err.message}`); + throw err; + } + + // Build pcexec + log(' Building pcexec (TypeScript)...', 'blue'); + try { + const pcexecDir = join(__dirname, 'pcexec'); + if (!existsSync(pcexecDir)) { + throw new Error('pcexec directory not found'); + } + + exec('npm install', { cwd: pcexecDir, silent: !options.verbose }); + exec('npm run build', { cwd: pcexecDir, silent: !options.verbose }); + + logSuccess('pcexec built successfully'); + } catch (err) { + logError(`Failed to build pcexec: ${err.message}`); + throw err; + } + + // Build safe-restart + log(' Building safe-restart (TypeScript)...', 'blue'); + try { + const safeRestartDir = join(__dirname, 'safe-restart'); + if (!existsSync(safeRestartDir)) { + throw new Error('safe-restart directory not found'); + } + + exec('npm install', { cwd: safeRestartDir, silent: !options.verbose }); + exec('npm run build', { cwd: safeRestartDir, silent: !options.verbose }); + + logSuccess('safe-restart built successfully'); + } catch (err) { + logError(`Failed to build safe-restart: ${err.message}`); + throw err; + } +} + +// ============================================================================ +// Step 4: Install Components +// ============================================================================ + +async function installComponents(env) { + if (options.buildOnly) { + logStep(4, 'Skipping installation (--build-only)'); + return; + } + + logStep(4, 'Installing components...'); + + // Determine install paths + const installDir = options.prefix || env.openclawDir; + const binDir = options.prefix ? join(installDir, 'bin') : join(installDir, 'bin'); + const skillsDir = join(installDir, 'skills', 'paddedcell'); + + log(` Install directory: ${installDir}`, 'blue'); + log(` Binary directory: ${binDir}`, 'blue'); + log(` Skills directory: ${skillsDir}`, 'blue'); + + // Create directories + mkdirSync(binDir, { recursive: true }); + mkdirSync(skillsDir, { recursive: true }); + + // Install pass_mgr binary + log(' Installing pass_mgr binary...', 'blue'); + const passMgrSource = join(__dirname, 'pass_mgr', 'dist', 'pass_mgr'); + const passMgrDest = join(binDir, 'pass_mgr'); + copyFileSync(passMgrSource, passMgrDest); + chmodSync(passMgrDest, 0o755); + logSuccess(`pass_mgr installed to ${passMgrDest}`); + + // Install pcexec + log(' Installing pcexec module...', 'blue'); + const pcexecSource = join(__dirname, 'pcexec'); + const pcexecDest = join(skillsDir, 'pcexec'); + copyModule(pcexecSource, pcexecDest); + logSuccess(`pcexec installed to ${pcexecDest}`); + + // Install safe-restart + log(' Installing safe-restart module...', 'blue'); + const safeRestartSource = join(__dirname, 'safe-restart'); + const safeRestartDest = join(skillsDir, 'safe-restart'); + copyModule(safeRestartSource, safeRestartDest); + logSuccess(`safe-restart installed to ${safeRestartDest}`); + + // Create skill manifest + log(' Creating skill manifest...', 'blue'); + const manifest = { + name: 'paddedcell', + version: '0.1.0', + description: 'Secure password management, safe execution, and coordinated restart', + tools: [ + { + name: 'pcexec', + entry: './pcexec/dist/index.js', + description: 'Safe exec with password sanitization', + }, + { + name: 'safe_restart', + entry: './safe-restart/dist/index.js', + description: 'Safe coordinated restart', + }, + ], + binaries: ['pass_mgr'], + installedAt: new Date().toISOString(), + }; + + writeFileSync( + join(skillsDir, 'manifest.json'), + JSON.stringify(manifest, null, 2) + ); + logSuccess('Skill manifest created'); + + // Add to PATH if needed + if (options.prefix) { + log('\n To use pass_mgr, add the following to your shell profile:', 'yellow'); + log(` export PATH="${binDir}:$PATH"`, 'cyan'); + } +} + +function copyModule(source, dest) { + mkdirSync(dest, { recursive: true }); + + const items = ['package.json', 'tsconfig.json', 'dist', 'src']; + for (const item of items) { + const srcPath = join(source, item); + const destPath = join(dest, item); + + if (!existsSync(srcPath)) continue; + + const stat = execSync(`stat -c %F "${srcPath}" 2>/dev/null || echo "file"`, { + silent: true, + cwd: __dirname + }).trim(); + + if (stat === 'directory') { + exec(`cp -r "${srcPath}" "${destPath}"`, { silent: true }); + } else { + copyFileSync(srcPath, destPath); + } + } +} + +// ============================================================================ +// Step 5: Configuration +// ============================================================================ + +async function configure(env) { + if (options.buildOnly) { + logStep(5, 'Skipping configuration (--build-only)'); + return; + } + + logStep(5, 'Configuration...'); + + const passMgrPath = options.prefix + ? join(options.prefix, 'bin', 'pass_mgr') + : join(env.openclawDir, 'bin', 'pass_mgr'); + + // Check if already initialized + const adminKeyDir = join(homedir(), '.pass_mgr'); + const configPath = join(adminKeyDir, 'config.json'); + + if (existsSync(configPath)) { + logWarning('pass_mgr already initialized'); + const reinit = await prompt(' Reinitialize? (y/N): '); + if (reinit.toLowerCase() !== 'y') { + log(' Skipping initialization'); + return; + } + } + + // Initialize pass_mgr + log(' Initializing pass_mgr...', 'blue'); + log(' Please set your admin password for pass_mgr.', 'yellow'); + + const adminPassword = await promptPassword(' Admin password: '); + if (!adminPassword) { + logWarning('Empty password, skipping initialization'); + return; + } + + const confirmPassword = await promptPassword(' Confirm password: '); + if (adminPassword !== confirmPassword) { + logError('Passwords do not match'); + return; + } + + try { + // Write password to temp file and init + const tempKeyFile = join(adminKeyDir, '.tmp_key'); + mkdirSync(adminKeyDir, { recursive: true, mode: 0o700 }); + writeFileSync(tempKeyFile, adminPassword, { mode: 0o600 }); + + exec(`${passMgrPath} admin init --key-path "${tempKeyFile}"`, { silent: !options.verbose }); + + // Remove temp file + execSync(`rm -f "${tempKeyFile}"`); + + logSuccess('pass_mgr initialized successfully'); + } catch (err) { + logError(`Failed to initialize pass_mgr: ${err.message}`); + throw err; + } + + // Create environment config + log(' Creating environment configuration...', 'blue'); + const envConfig = [ + '# PaddedCell Environment Configuration', + `export PATH="${dirname(passMgrPath)}:$PATH"`, + 'export PASS_MGR_PATH="pass_mgr"', + '', + '# PaddedCell skills', + `export PADDEDCELL_SKILLS_DIR="${join(env.openclawDir || homedir(), '.openclaw', 'skills', 'paddedcell')}"`, + ].join('\n'); + + const envFile = join(env.openclawDir || homedir(), '.openclaw', 'paddedcell.env'); + writeFileSync(envFile, envConfig); + logSuccess(`Environment config written to ${envFile}`); + + log('\n Add the following to your shell profile:', 'yellow'); + log(` source ${envFile}`, 'cyan'); +} + +// ============================================================================ +// Step 6: Verify Installation +// ============================================================================ + +async function verifyInstallation(env) { + if (options.buildOnly) { + logStep(6, 'Skipping verification (--build-only)'); + return true; + } + + logStep(6, 'Verifying installation...'); + + let allOk = true; + + // Check pass_mgr + try { + const passMgrPath = options.prefix + ? join(options.prefix, 'bin', 'pass_mgr') + : join(env.openclawDir, 'bin', 'pass_mgr'); + + if (existsSync(passMgrPath)) { + execSync(`"${passMgrPath}" --help`, { silent: true }); + logSuccess('pass_mgr is working'); + } else { + logError('pass_mgr binary not found'); + allOk = false; + } + } catch { + logError('pass_mgr test failed'); + allOk = false; + } + + // Check pcexec + const pcexecPath = join( + options.prefix || env.openclawDir, + 'skills', 'paddedcell', 'pcexec', 'dist', 'index.js' + ); + if (existsSync(pcexecPath)) { + logSuccess('pcexec module installed'); + } else { + logError('pcexec module not found'); + allOk = false; + } + + // Check safe-restart + const safeRestartPath = join( + options.prefix || env.openclawDir, + 'skills', 'paddedcell', 'safe-restart', 'dist', 'index.js' + ); + if (existsSync(safeRestartPath)) { + logSuccess('safe-restart module installed'); + } else { + logError('safe-restart module not found'); + allOk = false; + } + + return allOk; +} + +// ============================================================================ +// Step 7: Print Summary +// ============================================================================ + +function printSummary(env) { + logStep(7, 'Installation Summary'); + + const installDir = options.prefix || env.openclawDir; + + console.log(''); + log('╔════════════════════════════════════════════════════════╗', 'cyan'); + log('║ PaddedCell Installation Complete ║', 'cyan'); + log('╚════════════════════════════════════════════════════════╝', 'cyan'); + console.log(''); + + if (options.buildOnly) { + log('Build-only mode - binaries built but not installed', 'yellow'); + console.log(''); + log('Built artifacts:', 'blue'); + log(` • pass_mgr: ${join(__dirname, 'pass_mgr', 'dist', 'pass_mgr')}`, 'reset'); + log(` • pcexec: ${join(__dirname, 'pcexec', 'dist')}`, 'reset'); + log(` • safe-restart: ${join(__dirname, 'safe-restart', 'dist')}`, 'reset'); + } else { + log('Installed components:', 'blue'); + log(` • pass_mgr binary: ${join(installDir, 'bin', 'pass_mgr')}`, 'reset'); + log(` • pcexec module: ${join(installDir, 'skills', 'paddedcell', 'pcexec')}`, 'reset'); + log(` • safe-restart module: ${join(installDir, 'skills', 'paddedcell', 'safe-restart')}`, 'reset'); + console.log(''); + + log('Next steps:', 'blue'); + console.log(''); + log('1. Add to your shell profile (~/.bashrc, ~/.zshrc):', 'yellow'); + log(` source ${join(installDir, 'paddedcell.env')}`, 'cyan'); + console.log(''); + log('2. Reload your shell or run:', 'yellow'); + log(` source ${join(installDir, 'paddedcell.env')}`, 'cyan'); + console.log(''); + log('3. Test pass_mgr:', 'yellow'); + log(' pass_mgr admin init # Initialize (if not done)', 'cyan'); + log(' pass_mgr set test_key mypass # Set a test password', 'cyan'); + log(' pass_mgr get test_key # Retrieve password', 'cyan'); + } + + console.log(''); + log('For more information:', 'blue'); + log(' • Documentation: https://git.hangman-lab.top/nav/PaddedCell', 'cyan'); + log(' • Issues: https://git.hangman-lab.top/nav/PaddedCell/issues', 'cyan'); + console.log(''); +} + +// ============================================================================ +// Main +// ============================================================================ + +async function main() { + console.log(''); + log('╔════════════════════════════════════════════════════════╗', 'cyan'); + log('║ PaddedCell Plugin Installer v0.1.0 ║', 'cyan'); + log('╚════════════════════════════════════════════════════════╝', 'cyan'); + console.log(''); + + try { + const env = detectEnvironment(); + checkDependencies(env); + await buildComponents(env); + await installComponents(env); + await configure(env); + const verified = await verifyInstallation(env); + + if (!verified && !options.buildOnly) { + log('\nInstallation completed with warnings.', 'yellow'); + } + + printSummary(env); + process.exit(0); + } catch (err) { + console.log(''); + log('╔════════════════════════════════════════════════════════╗', 'red'); + log('║ Installation Failed ║', 'red'); + log('╚════════════════════════════════════════════════════════╝', 'red'); + console.log(''); + log(`Error: ${err.message}`, 'red'); + if (options.verbose) { + console.log(err.stack); + } + process.exit(1); + } +} + +main(); From 28af11cfbb3bdf563e1f97ed1a6b00fc555fd4c3 Mon Sep 17 00:00:00 2001 From: zhi Date: Thu, 5 Mar 2026 10:00:30 +0000 Subject: [PATCH 04/28] fix: resolve build errors in pass_mgr, pcexec, and safe-restart - Fix Go syntax error: use BoolVar for --username flag instead of string - Fix TypeScript type errors: filter undefined values from process.env - Fix TypeScript type error: add type assertion for fetch response - Add .gitignore to exclude node_modules and build outputs --- .gitignore | 30 + TEST_PLAN.md | 71 + pass_mgr/go.mod | 4 +- pass_mgr/go.sum | 10 + pass_mgr/src/main.go | 8 +- pcexec/package-lock.json | 3846 ++++++++++++++++++++++++ pcexec/src/index.ts | 34 +- safe-restart/package-lock.json | 4821 ++++++++++++++++++++++++++++++ safe-restart/src/safe-restart.ts | 2 +- 9 files changed, 8811 insertions(+), 15 deletions(-) create mode 100644 .gitignore create mode 100644 TEST_PLAN.md create mode 100644 pass_mgr/go.sum create mode 100644 pcexec/package-lock.json create mode 100644 safe-restart/package-lock.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8d4d900 --- /dev/null +++ b/.gitignore @@ -0,0 +1,30 @@ +# Dependencies +node_modules/ +*.log + +# Build outputs +dist/ +*.exe +*.dll +*.so +*.dylib + +# Environment +.env +.env.local + +# IDE +.vscode/ +.idea/ +*.swp +*.swo + +# OS +.DS_Store +Thumbs.db + +# Go +*.o +*.a +*.test +vendor/ diff --git a/TEST_PLAN.md b/TEST_PLAN.md new file mode 100644 index 0000000..217319e --- /dev/null +++ b/TEST_PLAN.md @@ -0,0 +1,71 @@ +# PaddedCell 测试计划 - 2026-03-05 + +## 当前状态 +- 代码已推送到 `dev/zhi` 分支 +- install.mjs 安装脚本已完成 +- 准备进行安装测试 + +## 测试步骤 + +### 1. 安装脚本测试 +```bash +cd /root/.openclaw/workspace-developer/PaddedCell +node install.mjs --verbose +``` + +### 2. 验证安装 +- [ ] pass_mgr 二进制可执行 +- [ ] pcexec 模块存在 +- [ ] safe-restart 模块存在 +- [ ] manifest.json 已创建 + +### 3. pass_mgr 功能测试 +```bash +# 初始化 +pass_mgr admin init + +# 设置测试密码 +pass_mgr set test_key test_password --username testuser + +# 获取密码 +pass_mgr get test_key + +# 获取用户名 +pass_mgr get test_key --username + +# 生成新密码 +pass_mgr generate new_key --username newuser + +# 轮换密码 +pass_mgr rotate new_key + +# 删除密码 +pass_mgr unset test_key +``` + +### 4. pcexec 功能测试 +- 测试密码脱敏功能 +- 测试多次 pass_mgr get 替换 + +### 5. safe-restart 功能测试 +- 测试状态机 +- 测试 API 接口 + +## 可能遇到的问题 + +1. **Go 依赖问题** - 需要确保 go mod tidy 能正常下载依赖 +2. **Node.js 构建问题** - npm install 可能需要较长时间 +3. **权限问题** - 二进制可能需要 chmod +x + +## 重启后计划 + +如果测试过程中需要重启 OpenClaw gateway,重启后我需要: + +1. **验证环境变量** - 检查 PATH 和 PADDEDCELL_SKILLS_DIR 是否正确设置 +2. **继续安装测试** - 重新运行 install.mjs 或验证已安装组件 +3. **功能测试** - 测试 pass_mgr/pcexec/safe-restart 是否正常工作 +4. **记录结果** - 更新此文件,记录测试通过/失败项 + +## 阻塞点 + +当前无阻塞,可以立即开始测试。 diff --git a/pass_mgr/go.mod b/pass_mgr/go.mod index 47a663c..c013613 100644 --- a/pass_mgr/go.mod +++ b/pass_mgr/go.mod @@ -2,9 +2,7 @@ module pass_mgr go 1.22 -require ( - github.com/spf13/cobra v1.8.0 -) +require github.com/spf13/cobra v1.8.0 require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect diff --git a/pass_mgr/go.sum b/pass_mgr/go.sum new file mode 100644 index 0000000..d0e8c2c --- /dev/null +++ b/pass_mgr/go.sum @@ -0,0 +1,10 @@ +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/pass_mgr/src/main.go b/pass_mgr/src/main.go index 7c196e4..213bbcd 100644 --- a/pass_mgr/src/main.go +++ b/pass_mgr/src/main.go @@ -41,7 +41,6 @@ type Config struct { var ( workspaceDir string agentID string - username string ) func main() { @@ -70,7 +69,8 @@ func main() { } func getCmd() *cobra.Command { - return &cobra.Command{ + var showUsername bool + cmd := &cobra.Command{ Use: "get [key]", Short: "Get password for a key", Args: cobra.ExactArgs(1), @@ -81,13 +81,15 @@ func getCmd() *cobra.Command { fmt.Fprintf(os.Stderr, "Error: %v\n", err) os.Exit(1) } - if username { + if showUsername { fmt.Println(user) } else { fmt.Println(password) } }, } + cmd.Flags().BoolVar(&showUsername, "username", false, "Show username instead of password") + return cmd } func generateCmd() *cobra.Command { diff --git a/pcexec/package-lock.json b/pcexec/package-lock.json new file mode 100644 index 0000000..598f765 --- /dev/null +++ b/pcexec/package-lock.json @@ -0,0 +1,3846 @@ +{ + "name": "pcexec", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "pcexec", + "version": "0.1.0", + "dependencies": { + "@types/node": "^20.0.0" + }, + "devDependencies": { + "@types/jest": "^29.0.0", + "jest": "^29.0.0", + "ts-jest": "^29.0.0", + "typescript": "^5.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", + "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", + "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", + "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", + "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "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/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.10", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.10.tgz", + "integrity": "sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "29.5.14", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.14.tgz", + "integrity": "sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "node_modules/@types/node": { + "version": "20.19.35", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.35.tgz", + "integrity": "sha512-Uarfe6J91b9HAUXxjvSOdiO2UPOKLm07Q1oh0JHxoZ1y8HoqxDAu3gVrsrOHeiio0kSsoVBt4wFrKOm0dKxVPQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/yargs": { + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" + }, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "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/baseline-browser-mapping": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", + "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "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/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001776", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001776.tgz", + "integrity": "sha512-sg01JDPzZ9jGshqKSckOQthXnYwOEP50jeVFhaSFbZcOy05TiuuaffDOfcwtCisJ9kNQuLBFibYywv2Bgm9osw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "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/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", + "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", + "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", + "dev": true, + "license": "MIT" + }, + "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==", + "dev": true, + "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==", + "dev": true, + "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/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "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/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dedent": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", + "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.307", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.307.tgz", + "integrity": "sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg==", + "dev": true, + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "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/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "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/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "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/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "license": "MIT" + }, + "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/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.36", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz", + "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", + "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "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/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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/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/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-jest": { + "version": "29.4.6", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.6.tgz", + "integrity": "sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bs-logger": "^0.2.6", + "fast-json-stable-stringify": "^2.1.0", + "handlebars": "^4.7.8", + "json5": "^2.2.3", + "lodash.memoize": "^4.1.2", + "make-error": "^1.3.6", + "semver": "^7.7.3", + "type-fest": "^4.41.0", + "yargs-parser": "^21.1.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/transform": "^29.0.0 || ^30.0.0", + "@jest/types": "^29.0.0 || ^30.0.0", + "babel-jest": "^29.0.0 || ^30.0.0", + "jest": "^29.0.0 || ^30.0.0", + "jest-util": "^29.0.0 || ^30.0.0", + "typescript": ">=4.3 <6" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/transform": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jest-util": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-jest/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "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==", + "dev": true, + "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/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.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/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "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/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "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==", + "dev": true, + "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/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "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" + } + } + } +} diff --git a/pcexec/src/index.ts b/pcexec/src/index.ts index 4df3424..ef036b8 100644 --- a/pcexec/src/index.ts +++ b/pcexec/src/index.ts @@ -164,10 +164,19 @@ async function replacePassMgrGets(command: string): Promise<{ command: string; p */ export async function pcexec(command: string, options: PcExecOptions = {}): Promise { // Set up environment with workspace/agent info - const env: Record = { - ...process.env, - ...options.env, - }; + const env: Record = {}; + + // Copy process.env, filtering out undefined values + for (const [key, value] of Object.entries(process.env)) { + if (value !== undefined) { + env[key] = value; + } + } + + // Merge options.env + if (options.env) { + Object.assign(env, options.env); + } if (process.env.AGENT_WORKSPACE) { env.AGENT_WORKSPACE = process.env.AGENT_WORKSPACE; @@ -284,10 +293,19 @@ export function pcexecSync(command: string, options: PcExecOptions = {}): PcExec const { execSync } = require('child_process'); // Set up environment - const env: Record = { - ...process.env, - ...options.env, - }; + const env: Record = {}; + + // Copy process.env, filtering out undefined values + for (const [key, value] of Object.entries(process.env)) { + if (value !== undefined) { + env[key] = value; + } + } + + // Merge options.env + if (options.env) { + Object.assign(env, options.env); + } if (process.env.AGENT_WORKSPACE) { env.AGENT_WORKSPACE = process.env.AGENT_WORKSPACE; diff --git a/safe-restart/package-lock.json b/safe-restart/package-lock.json new file mode 100644 index 0000000..c1ad2ea --- /dev/null +++ b/safe-restart/package-lock.json @@ -0,0 +1,4821 @@ +{ + "name": "safe-restart", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "safe-restart", + "version": "0.1.0", + "dependencies": { + "@types/node": "^20.0.0", + "express": "^4.18.0", + "ws": "^8.14.0" + }, + "devDependencies": { + "@types/express": "^4.17.0", + "@types/jest": "^29.0.0", + "@types/ws": "^8.5.0", + "jest": "^29.0.0", + "ts-jest": "^29.0.0", + "typescript": "^5.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/core/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==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", + "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", + "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", + "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", + "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/traverse/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==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "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/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.10", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.10.tgz", + "integrity": "sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.25", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.25.tgz", + "integrity": "sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "^1" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.8", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.8.tgz", + "integrity": "sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "29.5.14", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.14.tgz", + "integrity": "sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.19.35", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.35.tgz", + "integrity": "sha512-Uarfe6J91b9HAUXxjvSOdiO2UPOKLm07Q1oh0JHxoZ1y8HoqxDAu3gVrsrOHeiio0kSsoVBt4wFrKOm0dKxVPQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.10.tgz", + "integrity": "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "<1" + } + }, + "node_modules/@types/serve-static/node_modules/@types/send": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.6.tgz", + "integrity": "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "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/baseline-browser-mapping": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", + "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/body-parser": { + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", + "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.14.0", + "raw-body": "~2.5.3", + "type-is": "~1.6.18", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001776", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001776.tgz", + "integrity": "sha512-sg01JDPzZ9jGshqKSckOQthXnYwOEP50jeVFhaSFbZcOy05TiuuaffDOfcwtCisJ9kNQuLBFibYywv2Bgm9osw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "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/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", + "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", + "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", + "dev": true, + "license": "MIT" + }, + "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==", + "dev": true, + "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==", + "dev": true, + "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/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", + "license": "MIT" + }, + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "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/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/dedent": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", + "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.307", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.307.tgz", + "integrity": "sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg==", + "dev": true, + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/express": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", + "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "~1.20.3", + "content-disposition": "~0.5.4", + "content-type": "~1.0.4", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "~0.1.12", + "proxy-addr": "~2.0.7", + "qs": "~6.14.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "~0.19.0", + "serve-static": "~1.16.2", + "setprototypeof": "1.2.0", + "statuses": "~2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "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/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "statuses": "~2.0.2", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "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/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "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/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/istanbul-lib-source-maps/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==", + "dev": true, + "license": "MIT" + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "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/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.36", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz", + "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "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-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/qs": { + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", + "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", + "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "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": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.4.1", + "range-parser": "~1.2.1", + "statuses": "~2.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/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/serve-static": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "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/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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/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/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/ts-jest": { + "version": "29.4.6", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.6.tgz", + "integrity": "sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bs-logger": "^0.2.6", + "fast-json-stable-stringify": "^2.1.0", + "handlebars": "^4.7.8", + "json5": "^2.2.3", + "lodash.memoize": "^4.1.2", + "make-error": "^1.3.6", + "semver": "^7.7.3", + "type-fest": "^4.41.0", + "yargs-parser": "^21.1.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/transform": "^29.0.0 || ^30.0.0", + "@jest/types": "^29.0.0 || ^30.0.0", + "babel-jest": "^29.0.0 || ^30.0.0", + "jest": "^29.0.0 || ^30.0.0", + "jest-util": "^29.0.0 || ^30.0.0", + "typescript": ">=4.3 <6" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/transform": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jest-util": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-jest/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "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==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "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/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.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/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "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/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "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==", + "dev": true, + "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/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/ws": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", + "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "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" + } + } + } +} diff --git a/safe-restart/src/safe-restart.ts b/safe-restart/src/safe-restart.ts index 7ddb406..c397801 100644 --- a/safe-restart/src/safe-restart.ts +++ b/safe-restart/src/safe-restart.ts @@ -73,7 +73,7 @@ export async function safeRestart(options: SafeRestartOptions): Promise Date: Thu, 5 Mar 2026 10:01:29 +0000 Subject: [PATCH 05/28] docs: update test plan with build fix results --- TEST_PLAN.md | 75 +++++++++++++++++++++++----------------------------- 1 file changed, 33 insertions(+), 42 deletions(-) diff --git a/TEST_PLAN.md b/TEST_PLAN.md index 217319e..d6285c2 100644 --- a/TEST_PLAN.md +++ b/TEST_PLAN.md @@ -1,61 +1,50 @@ # PaddedCell 测试计划 - 2026-03-05 ## 当前状态 -- 代码已推送到 `dev/zhi` 分支 -- install.mjs 安装脚本已完成 -- 准备进行安装测试 +- 代码已推送到 `dev/zhi` 分支 (commit: 28af11c) +- 已修复构建错误 +- 安装脚本已更新 -## 测试步骤 +## 测试步骤及结果 -### 1. 安装脚本测试 +### 1. 安装脚本测试 ✅ ```bash cd /root/.openclaw/workspace-developer/PaddedCell node install.mjs --verbose ``` -### 2. 验证安装 -- [ ] pass_mgr 二进制可执行 -- [ ] pcexec 模块存在 -- [ ] safe-restart 模块存在 -- [ ] manifest.json 已创建 +**结果**: 构建成功,但安装未完成(等待用户确认安装路径) -### 3. pass_mgr 功能测试 -```bash -# 初始化 -pass_mgr admin init +### 2. 依赖安装 ✅ +- Go v1.22.2 已安装 +- Node.js v22.x 可用 -# 设置测试密码 -pass_mgr set test_key test_password --username testuser +### 3. 构建测试 ✅ +- pass_mgr Go 二进制编译成功 +- pcexec TypeScript 构建成功 +- safe-restart TypeScript 构建成功 -# 获取密码 -pass_mgr get test_key +### 4. 修复的构建错误 -# 获取用户名 -pass_mgr get test_key --username +#### pass_mgr (Go) +- **问题**: `username` string 变量用作 boolean 判断 +- **修复**: 使用 `BoolVar` 定义 `--username` flag -# 生成新密码 -pass_mgr generate new_key --username newuser +#### pcexec (TypeScript) +- **问题**: `process.env` 类型不匹配 `Record` +- **修复**: 循环复制并过滤 undefined 值 -# 轮换密码 -pass_mgr rotate new_key +#### safe-restart (TypeScript) +- **问题**: `fetch` 返回 `unknown` 类型 +- **修复**: 添加类型断言 `as { status: string }` -# 删除密码 -pass_mgr unset test_key -``` +## 下一步测试 -### 4. pcexec 功能测试 -- 测试密码脱敏功能 -- 测试多次 pass_mgr get 替换 - -### 5. safe-restart 功能测试 -- 测试状态机 -- 测试 API 接口 - -## 可能遇到的问题 - -1. **Go 依赖问题** - 需要确保 go mod tidy 能正常下载依赖 -2. **Node.js 构建问题** - npm install 可能需要较长时间 -3. **权限问题** - 二进制可能需要 chmod +x +需要完成的测试: +1. 完整安装流程测试(需要确认安装路径) +2. pass_mgr 功能测试(init/get/set/generate/rotate) +3. pcexec 密码脱敏测试 +4. safe-restart API 测试 ## 重启后计划 @@ -66,6 +55,8 @@ pass_mgr unset test_key 3. **功能测试** - 测试 pass_mgr/pcexec/safe-restart 是否正常工作 4. **记录结果** - 更新此文件,记录测试通过/失败项 -## 阻塞点 +## 当前阻塞点 -当前无阻塞,可以立即开始测试。 +**无阻塞** - 构建已通过,可以开始完整安装测试。 + +**建议**: 运行 `node install.mjs` 完成安装,然后进行功能测试。 From 21d04b17cdb01defe9bf9af4896531a1b52669f5 Mon Sep 17 00:00:00 2001 From: zhi Date: Thu, 5 Mar 2026 10:13:29 +0000 Subject: [PATCH 06/28] feat: add --uninstall support to install script - Add --uninstall flag to remove installed components - List items to be removed before confirmation - Remove pass_mgr binary, skills modules, and env config - Preserve admin key directory (warns user to remove manually) - Update PROJECT_PLAN.md with uninstall usage --- PROJECT_PLAN.md | 6 ++++ install.mjs | 87 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 92 insertions(+), 1 deletion(-) diff --git a/PROJECT_PLAN.md b/PROJECT_PLAN.md index 0136023..a994590 100644 --- a/PROJECT_PLAN.md +++ b/PROJECT_PLAN.md @@ -286,6 +286,12 @@ node install.mjs --build-only # 跳过依赖检测 node install.mjs --skip-check + +# 卸载 +node install.mjs --uninstall + +# 从指定路径卸载 +node install.mjs --uninstall --prefix /usr/local ``` --- diff --git a/install.mjs b/install.mjs index 9365897..4b64a4d 100755 --- a/install.mjs +++ b/install.mjs @@ -8,6 +8,8 @@ * node install.mjs --prefix /usr/local * node install.mjs --build-only * node install.mjs --skip-check + * node install.mjs --uninstall + * node install.mjs --uninstall --prefix /usr/local */ import { execSync, spawn } from 'child_process'; @@ -27,6 +29,7 @@ const options = { buildOnly: args.includes('--build-only'), skipCheck: args.includes('--skip-check'), verbose: args.includes('--verbose') || args.includes('-v'), + uninstall: args.includes('--uninstall'), }; // Parse --prefix value @@ -589,9 +592,84 @@ function printSummary(env) { } // ============================================================================ -// Main +// Uninstall Function // ============================================================================ +async function uninstall(env) { + logStep(1, 'Uninstalling PaddedCell...'); + + const installDir = options.prefix || env.openclawDir; + const binDir = join(installDir, 'bin'); + const skillsDir = join(installDir, 'skills', 'paddedcell'); + const envFile = join(installDir, 'paddedcell.env'); + + const itemsToRemove = []; + + // Check what exists + const passMgrBinary = join(binDir, 'pass_mgr'); + if (existsSync(passMgrBinary)) { + itemsToRemove.push(passMgrBinary); + } + + if (existsSync(skillsDir)) { + itemsToRemove.push(skillsDir); + } + + if (existsSync(envFile)) { + itemsToRemove.push(envFile); + } + + if (itemsToRemove.length === 0) { + log('No installed components found.', 'yellow'); + return; + } + + log('The following items will be removed:', 'yellow'); + for (const item of itemsToRemove) { + log(` • ${item}`, 'reset'); + } + + // Ask for confirmation + const confirm = await prompt('\nAre you sure you want to uninstall? (y/N): '); + if (confirm.toLowerCase() !== 'y') { + log('Uninstall cancelled.', 'yellow'); + return; + } + + // Perform uninstall + for (const item of itemsToRemove) { + try { + if (item === passMgrBinary || item === envFile) { + execSync(`rm -f "${item}"`, { silent: true }); + logSuccess(`Removed: ${item}`); + } else { + execSync(`rm -rf "${item}"`, { silent: true }); + logSuccess(`Removed: ${item}`); + } + } catch (err) { + logError(`Failed to remove: ${item}`); + } + } + + // Check for admin key directory + const adminKeyDir = join(homedir(), '.pass_mgr'); + if (existsSync(adminKeyDir)) { + log('\n⚠️ Admin key directory found:', 'yellow'); + log(` ${adminKeyDir}`, 'cyan'); + log(' This contains your encryption keys. Remove manually if desired.', 'yellow'); + } + + console.log(''); + log('╔════════════════════════════════════════════════════════╗', 'cyan'); + log('║ PaddedCell Uninstall Complete ║', 'cyan'); + log('╚════════════════════════════════════════════════════════╝', 'cyan'); + console.log(''); + + log('Remember to remove the following from your shell profile:', 'yellow'); + log(` source ${envFile}`, 'cyan'); + console.log(''); +} + async function main() { console.log(''); log('╔════════════════════════════════════════════════════════╗', 'cyan'); @@ -601,6 +679,13 @@ async function main() { try { const env = detectEnvironment(); + + // Handle uninstall + if (options.uninstall) { + await uninstall(env); + process.exit(0); + } + checkDependencies(env); await buildComponents(env); await installComponents(env); From 5084cfecb81ee6ccac9b6cec0899dbf1e8212799 Mon Sep 17 00:00:00 2001 From: zhi Date: Thu, 5 Mar 2026 10:28:13 +0000 Subject: [PATCH 07/28] fix: remove auto-init of pass_mgr from install script - Remove automatic pass_mgr admin init during installation - Users must manually run 'pass_mgr admin init' after install - Update install summary to show initialization as a required step - This allows non-interactive installation --- install.mjs | 77 +++++++++++++++++++---------------------------------- 1 file changed, 27 insertions(+), 50 deletions(-) diff --git a/install.mjs b/install.mjs index 4b64a4d..8700b99 100755 --- a/install.mjs +++ b/install.mjs @@ -388,15 +388,25 @@ function copyModule(source, dest) { if (!existsSync(srcPath)) continue; - const stat = execSync(`stat -c %F "${srcPath}" 2>/dev/null || echo "file"`, { - silent: true, - cwd: __dirname - }).trim(); - - if (stat === 'directory') { - exec(`cp -r "${srcPath}" "${destPath}"`, { silent: true }); - } else { - copyFileSync(srcPath, destPath); + try { + const stat = execSync(`stat -c %F "${srcPath}" 2>/dev/null || echo "file"`, { + encoding: 'utf8', + cwd: __dirname + }).trim(); + + if (stat === 'directory') { + execSync(`cp -r "${srcPath}" "${destPath}"`, { cwd: __dirname }); + } else { + copyFileSync(srcPath, destPath); + } + } catch (err) { + // Fallback: try to copy as file first, then directory + try { + copyFileSync(srcPath, destPath); + } catch { + // If file copy fails, try directory copy + execSync(`cp -r "${srcPath}" "${destPath}"`, { cwd: __dirname }); + } } } } @@ -422,45 +432,10 @@ async function configure(env) { const configPath = join(adminKeyDir, 'config.json'); if (existsSync(configPath)) { - logWarning('pass_mgr already initialized'); - const reinit = await prompt(' Reinitialize? (y/N): '); - if (reinit.toLowerCase() !== 'y') { - log(' Skipping initialization'); - return; - } - } - - // Initialize pass_mgr - log(' Initializing pass_mgr...', 'blue'); - log(' Please set your admin password for pass_mgr.', 'yellow'); - - const adminPassword = await promptPassword(' Admin password: '); - if (!adminPassword) { - logWarning('Empty password, skipping initialization'); - return; - } - - const confirmPassword = await promptPassword(' Confirm password: '); - if (adminPassword !== confirmPassword) { - logError('Passwords do not match'); - return; - } - - try { - // Write password to temp file and init - const tempKeyFile = join(adminKeyDir, '.tmp_key'); - mkdirSync(adminKeyDir, { recursive: true, mode: 0o700 }); - writeFileSync(tempKeyFile, adminPassword, { mode: 0o600 }); - - exec(`${passMgrPath} admin init --key-path "${tempKeyFile}"`, { silent: !options.verbose }); - - // Remove temp file - execSync(`rm -f "${tempKeyFile}"`); - - logSuccess('pass_mgr initialized successfully'); - } catch (err) { - logError(`Failed to initialize pass_mgr: ${err.message}`); - throw err; + logSuccess('pass_mgr already initialized'); + } else { + log(' pass_mgr not initialized yet.', 'yellow'); + log(' Run "pass_mgr admin init" manually after installation.', 'cyan'); } // Create environment config @@ -578,8 +553,10 @@ function printSummary(env) { log('2. Reload your shell or run:', 'yellow'); log(` source ${join(installDir, 'paddedcell.env')}`, 'cyan'); console.log(''); - log('3. Test pass_mgr:', 'yellow'); - log(' pass_mgr admin init # Initialize (if not done)', 'cyan'); + log('3. Initialize pass_mgr (required before first use):', 'yellow'); + log(' pass_mgr admin init', 'cyan'); + console.log(''); + log('4. Test pass_mgr:', 'yellow'); log(' pass_mgr set test_key mypass # Set a test password', 'cyan'); log(' pass_mgr get test_key # Retrieve password', 'cyan'); } From 84c9df633a7ab7229b051138073effea47677ab8 Mon Sep 17 00:00:00 2001 From: zhi Date: Thu, 5 Mar 2026 10:51:51 +0000 Subject: [PATCH 08/28] feat: require password for admin init and auto-configure plugin path - pass_mgr admin init now requires --key-path parameter - Password must be at least 6 characters long - Install script now updates OpenClaw plugins.load.paths config - Falls back to manual instructions if config file not found --- install.mjs | 38 ++++++++++++++++++++++++++++++++++++++ pass_mgr/src/main.go | 32 +++++++++++++++++--------------- 2 files changed, 55 insertions(+), 15 deletions(-) diff --git a/install.mjs b/install.mjs index 8700b99..c6bdf48 100755 --- a/install.mjs +++ b/install.mjs @@ -455,6 +455,44 @@ async function configure(env) { log('\n Add the following to your shell profile:', 'yellow'); log(` source ${envFile}`, 'cyan'); + + // Update OpenClaw plugins.load.paths configuration + log('\n Updating OpenClaw plugin configuration...', 'blue'); + const openclawConfigPath = join(env.openclawDir || homedir(), '.openclaw', 'config.json'); + + if (existsSync(openclawConfigPath)) { + try { + const configContent = readFileSync(openclawConfigPath, 'utf8'); + const config = JSON.parse(configContent); + + // Ensure plugins.load.paths exists + if (!config.plugins) { + config.plugins = {}; + } + if (!config.plugins.load) { + config.plugins.load = {}; + } + if (!config.plugins.load.paths) { + config.plugins.load.paths = []; + } + + // Add paddedcell skills path if not already present + const skillsPath = join(env.openclawDir || homedir(), '.openclaw', 'skills', 'paddedcell'); + if (!config.plugins.load.paths.includes(skillsPath)) { + config.plugins.load.paths.push(skillsPath); + writeFileSync(openclawConfigPath, JSON.stringify(config, null, 2)); + logSuccess(`Added plugin path to OpenClaw config: ${skillsPath}`); + } else { + log(' Plugin path already in OpenClaw config', 'green'); + } + } catch (err) { + logWarning(`Failed to update OpenClaw config: ${err.message}`); + } + } else { + logWarning(`OpenClaw config not found at ${openclawConfigPath}`); + log(' Please manually add the following to your OpenClaw config:', 'yellow'); + log(` plugins.load.paths: ["${join(env.openclawDir || homedir(), '.openclaw', 'skills', 'paddedcell')}"]`, 'cyan'); + } } // ============================================================================ diff --git a/pass_mgr/src/main.go b/pass_mgr/src/main.go index 213bbcd..773e31e 100644 --- a/pass_mgr/src/main.go +++ b/pass_mgr/src/main.go @@ -178,6 +178,13 @@ func adminInitCmd() *cobra.Command { Use: "admin init", Short: "Initialize pass_mgr with admin key", Run: func(cmd *cobra.Command, args []string) { + // Require --key-path parameter + if keyPath == "" { + fmt.Fprintln(os.Stderr, "Error: --key-path is required") + fmt.Fprintln(os.Stderr, "Usage: pass_mgr admin init --key-path ") + fmt.Fprintln(os.Stderr, "The key file must contain a password with at least 6 characters") + os.Exit(1) + } if err := initAdmin(keyPath); err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err) os.Exit(1) @@ -185,7 +192,7 @@ func adminInitCmd() *cobra.Command { fmt.Println("pass_mgr initialized successfully") }, } - cmd.Flags().StringVar(&keyPath, "key-path", "", "Path to admin key file (optional)") + cmd.Flags().StringVar(&keyPath, "key-path", "", "Path to admin key file (required, password must be >= 6 chars)") return cmd } @@ -258,20 +265,15 @@ func initAdmin(keyPath string) error { return fmt.Errorf("failed to create admin directory: %w", err) } - var key []byte - if keyPath != "" { - // Read provided key - var err error - key, err = os.ReadFile(keyPath) - if err != nil { - return fmt.Errorf("failed to read key file: %w", err) - } - } else { - // Generate new key - key = make([]byte, 32) - if _, err := rand.Read(key); err != nil { - return fmt.Errorf("failed to generate key: %w", err) - } + // Read provided key + key, err := os.ReadFile(keyPath) + if err != nil { + return fmt.Errorf("failed to read key file: %w", err) + } + + // Validate password length (must be >= 6 characters) + if len(key) < 6 { + return fmt.Errorf("password must be at least 6 characters long (got %d)", len(key)) } // Save key From 9ecb065b43d9ca70ecf43db6f6a1bd1941f0834d Mon Sep 17 00:00:00 2001 From: zhi Date: Thu, 5 Mar 2026 11:07:47 +0000 Subject: [PATCH 09/28] feat: interactive password input for pass_mgr admin init - Remove --key-path parameter requirement - Add interactive password prompt (hidden input like sudo) - Require password confirmation - Password must be at least 6 characters - Uses golang.org/x/term for secure password input --- pass_mgr/go.mod | 4 +- pass_mgr/go.sum | 4 ++ pass_mgr/src/main.go | 87 ++++++++++++++++++++++++++++++-------------- 3 files changed, 66 insertions(+), 29 deletions(-) diff --git a/pass_mgr/go.mod b/pass_mgr/go.mod index c013613..19e7de1 100644 --- a/pass_mgr/go.mod +++ b/pass_mgr/go.mod @@ -1,10 +1,12 @@ module pass_mgr -go 1.22 +go 1.24.0 require github.com/spf13/cobra v1.8.0 require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect + golang.org/x/sys v0.41.0 // indirect + golang.org/x/term v0.40.0 // indirect ) diff --git a/pass_mgr/go.sum b/pass_mgr/go.sum index d0e8c2c..9dfa6e5 100644 --- a/pass_mgr/go.sum +++ b/pass_mgr/go.sum @@ -6,5 +6,9 @@ github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg= +golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/pass_mgr/src/main.go b/pass_mgr/src/main.go index 773e31e..474c2a1 100644 --- a/pass_mgr/src/main.go +++ b/pass_mgr/src/main.go @@ -12,9 +12,11 @@ import ( "os" "path/filepath" "strings" + "syscall" "time" "github.com/spf13/cobra" + "golang.org/x/term" ) const ( @@ -173,27 +175,17 @@ func rotateCmd() *cobra.Command { } func adminInitCmd() *cobra.Command { - var keyPath string - cmd := &cobra.Command{ + return &cobra.Command{ Use: "admin init", Short: "Initialize pass_mgr with admin key", Run: func(cmd *cobra.Command, args []string) { - // Require --key-path parameter - if keyPath == "" { - fmt.Fprintln(os.Stderr, "Error: --key-path is required") - fmt.Fprintln(os.Stderr, "Usage: pass_mgr admin init --key-path ") - fmt.Fprintln(os.Stderr, "The key file must contain a password with at least 6 characters") - os.Exit(1) - } - if err := initAdmin(keyPath); err != nil { + if err := initAdminInteractive(); err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err) os.Exit(1) } fmt.Println("pass_mgr initialized successfully") }, } - cmd.Flags().StringVar(&keyPath, "key-path", "", "Path to admin key file (required, password must be >= 6 chars)") - return cmd } func setCmd() *cobra.Command { @@ -256,32 +248,56 @@ func loadAdminKey() ([]byte, error) { return hash[:], nil } -func initAdmin(keyPath string) error { +func initAdminInteractive() error { + fmt.Print("Enter admin password: ") + password1, err := term.ReadPassword(int(syscall.Stdin)) + if err != nil { + return fmt.Errorf("failed to read password: %w", err) + } + fmt.Println() + + // Trim whitespace/newlines + password1 = []byte(strings.TrimSpace(string(password1))) + + // Validate password length + if len(password1) < 6 { + return fmt.Errorf("password must be at least 6 characters long (got %d)", len(password1)) + } + + fmt.Print("Confirm admin password: ") + password2, err := term.ReadPassword(int(syscall.Stdin)) + if err != nil { + return fmt.Errorf("failed to read password confirmation: %w", err) + } + fmt.Println() + + // Trim whitespace/newlines + password2 = []byte(strings.TrimSpace(string(password2))) + + // Check passwords match + if string(password1) != string(password2) { + return fmt.Errorf("passwords do not match") + } + + // Save the key + return saveAdminKey(password1) +} + +func saveAdminKey(key []byte) error { homeDir := getHomeDir() adminDir := filepath.Join(homeDir, AdminKeyDir) - + // Create admin directory if err := os.MkdirAll(adminDir, 0700); err != nil { return fmt.Errorf("failed to create admin directory: %w", err) } - - // Read provided key - key, err := os.ReadFile(keyPath) - if err != nil { - return fmt.Errorf("failed to read key file: %w", err) - } - - // Validate password length (must be >= 6 characters) - if len(key) < 6 { - return fmt.Errorf("password must be at least 6 characters long (got %d)", len(key)) - } - + // Save key keyFile := filepath.Join(adminDir, AdminKeyFile) if err := os.WriteFile(keyFile, key, 0600); err != nil { return fmt.Errorf("failed to save key: %w", err) } - + // Save config config := Config{ KeyHash: fmt.Sprintf("%x", sha256.Sum256(key)), @@ -292,10 +308,25 @@ func initAdmin(keyPath string) error { if err := os.WriteFile(configPath, configData, 0600); err != nil { return fmt.Errorf("failed to save config: %w", err) } - + return nil } +func initAdmin(keyPath string) error { + // Read provided key + key, err := os.ReadFile(keyPath) + if err != nil { + return fmt.Errorf("failed to read key file: %w", err) + } + + // Validate password length (must be >= 6 characters) + if len(key) < 6 { + return fmt.Errorf("password must be at least 6 characters long (got %d)", len(key)) + } + + return saveAdminKey(key) +} + func getSecretsDir() string { if workspaceDir != "" && agentID != "" { return filepath.Join(workspaceDir, SecretsDirName, agentID) From ceb17f375bec6c8e1238b6b725250617ea7bdf3e Mon Sep 17 00:00:00 2001 From: zhi Date: Thu, 5 Mar 2026 11:13:49 +0000 Subject: [PATCH 10/28] fix: correct path construction in install script - Fix duplicate .openclaw in env file path - Use consistent installDir variable throughout - Fix skills path in OpenClaw config update - Fix fallback path in uninstall function --- install.mjs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/install.mjs b/install.mjs index c6bdf48..fea9108 100755 --- a/install.mjs +++ b/install.mjs @@ -440,16 +440,17 @@ async function configure(env) { // Create environment config log(' Creating environment configuration...', 'blue'); + const installDir = env.openclawDir || join(homedir(), '.openclaw'); const envConfig = [ '# PaddedCell Environment Configuration', `export PATH="${dirname(passMgrPath)}:$PATH"`, 'export PASS_MGR_PATH="pass_mgr"', '', '# PaddedCell skills', - `export PADDEDCELL_SKILLS_DIR="${join(env.openclawDir || homedir(), '.openclaw', 'skills', 'paddedcell')}"`, + `export PADDEDCELL_SKILLS_DIR="${join(installDir, 'skills', 'paddedcell')}"`, ].join('\n'); - const envFile = join(env.openclawDir || homedir(), '.openclaw', 'paddedcell.env'); + const envFile = join(installDir, 'paddedcell.env'); writeFileSync(envFile, envConfig); logSuccess(`Environment config written to ${envFile}`); @@ -458,7 +459,7 @@ async function configure(env) { // Update OpenClaw plugins.load.paths configuration log('\n Updating OpenClaw plugin configuration...', 'blue'); - const openclawConfigPath = join(env.openclawDir || homedir(), '.openclaw', 'config.json'); + const openclawConfigPath = join(installDir, 'config.json'); if (existsSync(openclawConfigPath)) { try { @@ -477,7 +478,7 @@ async function configure(env) { } // Add paddedcell skills path if not already present - const skillsPath = join(env.openclawDir || homedir(), '.openclaw', 'skills', 'paddedcell'); + const skillsPath = join(installDir, 'skills', 'paddedcell'); if (!config.plugins.load.paths.includes(skillsPath)) { config.plugins.load.paths.push(skillsPath); writeFileSync(openclawConfigPath, JSON.stringify(config, null, 2)); @@ -491,7 +492,7 @@ async function configure(env) { } else { logWarning(`OpenClaw config not found at ${openclawConfigPath}`); log(' Please manually add the following to your OpenClaw config:', 'yellow'); - log(` plugins.load.paths: ["${join(env.openclawDir || homedir(), '.openclaw', 'skills', 'paddedcell')}"]`, 'cyan'); + log(` plugins.load.paths: ["${join(installDir, 'skills', 'paddedcell')}"]`, 'cyan'); } } @@ -613,7 +614,7 @@ function printSummary(env) { async function uninstall(env) { logStep(1, 'Uninstalling PaddedCell...'); - const installDir = options.prefix || env.openclawDir; + const installDir = options.prefix || env.openclawDir || join(homedir(), '.openclaw'); const binDir = join(installDir, 'bin'); const skillsDir = join(installDir, 'skills', 'paddedcell'); const envFile = join(installDir, 'paddedcell.env'); From 259f9dc41840190e7e6e99b953044b78a5511780 Mon Sep 17 00:00:00 2001 From: zhi Date: Thu, 5 Mar 2026 11:16:40 +0000 Subject: [PATCH 11/28] fix: remove unused PADDEDCELL_SKILLS_DIR env variable The plugins.load.paths configuration is automatically updated, so this environment variable is not needed. --- install.mjs | 1 - 1 file changed, 1 deletion(-) diff --git a/install.mjs b/install.mjs index fea9108..9f3061f 100755 --- a/install.mjs +++ b/install.mjs @@ -447,7 +447,6 @@ async function configure(env) { 'export PASS_MGR_PATH="pass_mgr"', '', '# PaddedCell skills', - `export PADDEDCELL_SKILLS_DIR="${join(installDir, 'skills', 'paddedcell')}"`, ].join('\n'); const envFile = join(installDir, 'paddedcell.env'); From 3a495f8d6492560c4654f9e71de715d272c89b92 Mon Sep 17 00:00:00 2001 From: zhi Date: Thu, 5 Mar 2026 11:21:22 +0000 Subject: [PATCH 12/28] fix: create OpenClaw config if not exists and simplify install summary - Create ~/.openclaw/config.json if it doesn't exist - Automatically add plugin path to config - Simplify post-install steps (remove redundant 'add to profile' step) --- install.mjs | 66 ++++++++++++++++++++++++++--------------------------- 1 file changed, 32 insertions(+), 34 deletions(-) diff --git a/install.mjs b/install.mjs index 9f3061f..a1ebfa4 100755 --- a/install.mjs +++ b/install.mjs @@ -460,36 +460,37 @@ async function configure(env) { log('\n Updating OpenClaw plugin configuration...', 'blue'); const openclawConfigPath = join(installDir, 'config.json'); - if (existsSync(openclawConfigPath)) { - try { + try { + let config = {}; + + // Load existing config if present + if (existsSync(openclawConfigPath)) { const configContent = readFileSync(openclawConfigPath, 'utf8'); - const config = JSON.parse(configContent); - - // Ensure plugins.load.paths exists - if (!config.plugins) { - config.plugins = {}; - } - if (!config.plugins.load) { - config.plugins.load = {}; - } - if (!config.plugins.load.paths) { - config.plugins.load.paths = []; - } - - // Add paddedcell skills path if not already present - const skillsPath = join(installDir, 'skills', 'paddedcell'); - if (!config.plugins.load.paths.includes(skillsPath)) { - config.plugins.load.paths.push(skillsPath); - writeFileSync(openclawConfigPath, JSON.stringify(config, null, 2)); - logSuccess(`Added plugin path to OpenClaw config: ${skillsPath}`); - } else { - log(' Plugin path already in OpenClaw config', 'green'); - } - } catch (err) { - logWarning(`Failed to update OpenClaw config: ${err.message}`); + config = JSON.parse(configContent); } - } else { - logWarning(`OpenClaw config not found at ${openclawConfigPath}`); + + // Ensure plugins.load.paths exists + if (!config.plugins) { + config.plugins = {}; + } + if (!config.plugins.load) { + config.plugins.load = {}; + } + if (!config.plugins.load.paths) { + config.plugins.load.paths = []; + } + + // Add paddedcell skills path if not already present + const skillsPath = join(installDir, 'skills', 'paddedcell'); + if (!config.plugins.load.paths.includes(skillsPath)) { + config.plugins.load.paths.push(skillsPath); + writeFileSync(openclawConfigPath, JSON.stringify(config, null, 2)); + logSuccess(`Added plugin path to OpenClaw config: ${skillsPath}`); + } else { + log(' Plugin path already in OpenClaw config', 'green'); + } + } catch (err) { + logWarning(`Failed to update OpenClaw config: ${err.message}`); log(' Please manually add the following to your OpenClaw config:', 'yellow'); log(` plugins.load.paths: ["${join(installDir, 'skills', 'paddedcell')}"]`, 'cyan'); } @@ -585,16 +586,13 @@ function printSummary(env) { log('Next steps:', 'blue'); console.log(''); - log('1. Add to your shell profile (~/.bashrc, ~/.zshrc):', 'yellow'); + log('1. Reload your shell or run:', 'yellow'); log(` source ${join(installDir, 'paddedcell.env')}`, 'cyan'); console.log(''); - log('2. Reload your shell or run:', 'yellow'); - log(` source ${join(installDir, 'paddedcell.env')}`, 'cyan'); - console.log(''); - log('3. Initialize pass_mgr (required before first use):', 'yellow'); + log('2. Initialize pass_mgr (required before first use):', 'yellow'); log(' pass_mgr admin init', 'cyan'); console.log(''); - log('4. Test pass_mgr:', 'yellow'); + log('3. Test pass_mgr:', 'yellow'); log(' pass_mgr set test_key mypass # Set a test password', 'cyan'); log(' pass_mgr get test_key # Retrieve password', 'cyan'); } From 62044ab94822a66c474a962922d09d7f1188098d Mon Sep 17 00:00:00 2001 From: zhi Date: Thu, 5 Mar 2026 11:25:05 +0000 Subject: [PATCH 13/28] fix: use openclaw config command for configuration management - Use 'openclaw config get/set --json' instead of direct file manipulation - Correctly remove plugin path from OpenClaw config during uninstall - Remove pass_mgr binary during uninstall --- install.mjs | 71 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 49 insertions(+), 22 deletions(-) diff --git a/install.mjs b/install.mjs index a1ebfa4..62f85ae 100755 --- a/install.mjs +++ b/install.mjs @@ -458,33 +458,28 @@ async function configure(env) { // Update OpenClaw plugins.load.paths configuration log('\n Updating OpenClaw plugin configuration...', 'blue'); - const openclawConfigPath = join(installDir, 'config.json'); try { - let config = {}; + const skillsPath = join(installDir, 'skills', 'paddedcell'); - // Load existing config if present - if (existsSync(openclawConfigPath)) { - const configContent = readFileSync(openclawConfigPath, 'utf8'); - config = JSON.parse(configContent); - } - - // Ensure plugins.load.paths exists - if (!config.plugins) { - config.plugins = {}; - } - if (!config.plugins.load) { - config.plugins.load = {}; - } - if (!config.plugins.load.paths) { - config.plugins.load.paths = []; + // Get current plugins.load.paths using openclaw config + let currentPaths = []; + try { + const result = execSync('openclaw config get plugins.load.paths --json 2>/dev/null || echo "[]"', { + encoding: 'utf8', + cwd: __dirname + }).trim(); + currentPaths = JSON.parse(result); + } catch { + currentPaths = []; } // Add paddedcell skills path if not already present - const skillsPath = join(installDir, 'skills', 'paddedcell'); - if (!config.plugins.load.paths.includes(skillsPath)) { - config.plugins.load.paths.push(skillsPath); - writeFileSync(openclawConfigPath, JSON.stringify(config, null, 2)); + if (!currentPaths.includes(skillsPath)) { + currentPaths.push(skillsPath); + execSync(`openclaw config set plugins.load.paths --json '${JSON.stringify(currentPaths)}'`, { + cwd: __dirname + }); logSuccess(`Added plugin path to OpenClaw config: ${skillsPath}`); } else { log(' Plugin path already in OpenClaw config', 'green'); @@ -492,7 +487,7 @@ async function configure(env) { } catch (err) { logWarning(`Failed to update OpenClaw config: ${err.message}`); log(' Please manually add the following to your OpenClaw config:', 'yellow'); - log(` plugins.load.paths: ["${join(installDir, 'skills', 'paddedcell')}"]`, 'cyan'); + log(` openclaw config set plugins.load.paths --json '["${join(installDir, 'skills', 'paddedcell')}"]'`, 'cyan'); } } @@ -664,6 +659,38 @@ async function uninstall(env) { } } + // Remove plugin path from OpenClaw config + log('\n Removing plugin path from OpenClaw config...', 'blue'); + try { + const skillsPath = join(installDir, 'skills', 'paddedcell'); + + // Get current plugins.load.paths + let currentPaths = []; + try { + const result = execSync('openclaw config get plugins.load.paths --json 2>/dev/null || echo "[]"', { + encoding: 'utf8', + cwd: __dirname + }).trim(); + currentPaths = JSON.parse(result); + } catch { + currentPaths = []; + } + + // Remove paddedcell skills path + const index = currentPaths.indexOf(skillsPath); + if (index > -1) { + currentPaths.splice(index, 1); + execSync(`openclaw config set plugins.load.paths --json '${JSON.stringify(currentPaths)}'`, { + cwd: __dirname + }); + logSuccess(`Removed plugin path from OpenClaw config`); + } else { + log(' Plugin path not found in OpenClaw config', 'yellow'); + } + } catch (err) { + logWarning(`Failed to update OpenClaw config: ${err.message}`); + } + // Check for admin key directory const adminKeyDir = join(homedir(), '.pass_mgr'); if (existsSync(adminKeyDir)) { From 1c84b4d6a0b6b547fbec16659b29ee641e29fd8c Mon Sep 17 00:00:00 2001 From: zhi Date: Thu, 5 Mar 2026 11:34:19 +0000 Subject: [PATCH 14/28] refactor: remove env file creation, use full path in examples - Remove creation of paddedcell.env file - Update post-install instructions to use full pass_mgr path - Simplify to 6 steps (remove verification step) - Update uninstall to not reference env file --- install.mjs | 176 +++++++--------------------------------------------- 1 file changed, 22 insertions(+), 154 deletions(-) diff --git a/install.mjs b/install.mjs index 62f85ae..d88a895 100755 --- a/install.mjs +++ b/install.mjs @@ -12,8 +12,8 @@ * node install.mjs --uninstall --prefix /usr/local */ -import { execSync, spawn } from 'child_process'; -import { existsSync, mkdirSync, copyFileSync, writeFileSync, readFileSync, chmodSync } from 'fs'; +import { execSync } from 'child_process'; +import { existsSync, mkdirSync, copyFileSync, writeFileSync, chmodSync } from 'fs'; import { dirname, join, resolve } from 'path'; import { fileURLToPath } from 'url'; import { homedir, platform } from 'os'; @@ -53,7 +53,7 @@ function log(message, color = 'reset') { } function logStep(step, message) { - log(`[${step}/7] ${message}`, 'cyan'); + log(`[${step}/6] ${message}`, 'cyan'); } function logSuccess(message) { @@ -90,36 +90,6 @@ async function prompt(question) { }); } -async function promptPassword(question) { - const rl = readline.createInterface({ - input: process.stdin, - output: process.stdout, - }); - return new Promise((resolve) => { - // Hide password input - const stdin = process.stdin; - stdin.on('data', (char) => { - char = char.toString(); - switch (char) { - case '\n': - case '\r': - case '\u0004': - stdin.pause(); - break; - default: - process.stdout.write('*'); - break; - } - }); - - rl.question(question, (answer) => { - rl.close(); - console.log(); // New line after password - resolve(answer.trim()); - }); - }); -} - // ============================================================================ // Step 1: Environment Detection // ============================================================================ @@ -248,7 +218,6 @@ async function buildComponents(env) { silent: !options.verbose }); - // Verify binary exists const binaryPath = join(passMgrDir, 'dist', 'pass_mgr'); if (!existsSync(binaryPath)) { throw new Error('pass_mgr binary not found after build'); @@ -308,16 +277,14 @@ async function installComponents(env) { logStep(4, 'Installing components...'); - // Determine install paths const installDir = options.prefix || env.openclawDir; - const binDir = options.prefix ? join(installDir, 'bin') : join(installDir, 'bin'); + const binDir = join(installDir, 'bin'); const skillsDir = join(installDir, 'skills', 'paddedcell'); log(` Install directory: ${installDir}`, 'blue'); log(` Binary directory: ${binDir}`, 'blue'); log(` Skills directory: ${skillsDir}`, 'blue'); - // Create directories mkdirSync(binDir, { recursive: true }); mkdirSync(skillsDir, { recursive: true }); @@ -370,12 +337,6 @@ async function installComponents(env) { JSON.stringify(manifest, null, 2) ); logSuccess('Skill manifest created'); - - // Add to PATH if needed - if (options.prefix) { - log('\n To use pass_mgr, add the following to your shell profile:', 'yellow'); - log(` export PATH="${binDir}:$PATH"`, 'cyan'); - } } function copyModule(source, dest) { @@ -399,12 +360,10 @@ function copyModule(source, dest) { } else { copyFileSync(srcPath, destPath); } - } catch (err) { - // Fallback: try to copy as file first, then directory + } catch { try { copyFileSync(srcPath, destPath); } catch { - // If file copy fails, try directory copy execSync(`cp -r "${srcPath}" "${destPath}"`, { cwd: __dirname }); } } @@ -423,9 +382,8 @@ async function configure(env) { logStep(5, 'Configuration...'); - const passMgrPath = options.prefix - ? join(options.prefix, 'bin', 'pass_mgr') - : join(env.openclawDir, 'bin', 'pass_mgr'); + const installDir = env.openclawDir || join(homedir(), '.openclaw'); + const passMgrPath = join(installDir, 'bin', 'pass_mgr'); // Check if already initialized const adminKeyDir = join(homedir(), '.pass_mgr'); @@ -435,27 +393,9 @@ async function configure(env) { logSuccess('pass_mgr already initialized'); } else { log(' pass_mgr not initialized yet.', 'yellow'); - log(' Run "pass_mgr admin init" manually after installation.', 'cyan'); + log(` Run "${passMgrPath} admin init" manually after installation.`, 'cyan'); } - // Create environment config - log(' Creating environment configuration...', 'blue'); - const installDir = env.openclawDir || join(homedir(), '.openclaw'); - const envConfig = [ - '# PaddedCell Environment Configuration', - `export PATH="${dirname(passMgrPath)}:$PATH"`, - 'export PASS_MGR_PATH="pass_mgr"', - '', - '# PaddedCell skills', - ].join('\n'); - - const envFile = join(installDir, 'paddedcell.env'); - writeFileSync(envFile, envConfig); - logSuccess(`Environment config written to ${envFile}`); - - log('\n Add the following to your shell profile:', 'yellow'); - log(` source ${envFile}`, 'cyan'); - // Update OpenClaw plugins.load.paths configuration log('\n Updating OpenClaw plugin configuration...', 'blue'); @@ -492,72 +432,14 @@ async function configure(env) { } // ============================================================================ -// Step 6: Verify Installation -// ============================================================================ - -async function verifyInstallation(env) { - if (options.buildOnly) { - logStep(6, 'Skipping verification (--build-only)'); - return true; - } - - logStep(6, 'Verifying installation...'); - - let allOk = true; - - // Check pass_mgr - try { - const passMgrPath = options.prefix - ? join(options.prefix, 'bin', 'pass_mgr') - : join(env.openclawDir, 'bin', 'pass_mgr'); - - if (existsSync(passMgrPath)) { - execSync(`"${passMgrPath}" --help`, { silent: true }); - logSuccess('pass_mgr is working'); - } else { - logError('pass_mgr binary not found'); - allOk = false; - } - } catch { - logError('pass_mgr test failed'); - allOk = false; - } - - // Check pcexec - const pcexecPath = join( - options.prefix || env.openclawDir, - 'skills', 'paddedcell', 'pcexec', 'dist', 'index.js' - ); - if (existsSync(pcexecPath)) { - logSuccess('pcexec module installed'); - } else { - logError('pcexec module not found'); - allOk = false; - } - - // Check safe-restart - const safeRestartPath = join( - options.prefix || env.openclawDir, - 'skills', 'paddedcell', 'safe-restart', 'dist', 'index.js' - ); - if (existsSync(safeRestartPath)) { - logSuccess('safe-restart module installed'); - } else { - logError('safe-restart module not found'); - allOk = false; - } - - return allOk; -} - -// ============================================================================ -// Step 7: Print Summary +// Step 6: Print Summary // ============================================================================ function printSummary(env) { - logStep(7, 'Installation Summary'); + logStep(6, 'Installation Summary'); const installDir = options.prefix || env.openclawDir; + const passMgrPath = join(installDir, 'bin', 'pass_mgr'); console.log(''); log('╔════════════════════════════════════════════════════════╗', 'cyan'); @@ -574,22 +456,19 @@ function printSummary(env) { log(` • safe-restart: ${join(__dirname, 'safe-restart', 'dist')}`, 'reset'); } else { log('Installed components:', 'blue'); - log(` • pass_mgr binary: ${join(installDir, 'bin', 'pass_mgr')}`, 'reset'); + log(` • pass_mgr binary: ${passMgrPath}`, 'reset'); log(` • pcexec module: ${join(installDir, 'skills', 'paddedcell', 'pcexec')}`, 'reset'); log(` • safe-restart module: ${join(installDir, 'skills', 'paddedcell', 'safe-restart')}`, 'reset'); console.log(''); log('Next steps:', 'blue'); console.log(''); - log('1. Reload your shell or run:', 'yellow'); - log(` source ${join(installDir, 'paddedcell.env')}`, 'cyan'); + log('1. Initialize pass_mgr (required before first use):', 'yellow'); + log(` ${passMgrPath} admin init`, 'cyan'); console.log(''); - log('2. Initialize pass_mgr (required before first use):', 'yellow'); - log(' pass_mgr admin init', 'cyan'); - console.log(''); - log('3. Test pass_mgr:', 'yellow'); - log(' pass_mgr set test_key mypass # Set a test password', 'cyan'); - log(' pass_mgr get test_key # Retrieve password', 'cyan'); + log('2. Test pass_mgr:', 'yellow'); + log(` ${passMgrPath} set test_key mypass # Set a test password`, 'cyan'); + log(` ${passMgrPath} get test_key # Retrieve password`, 'cyan'); } console.log(''); @@ -609,7 +488,6 @@ async function uninstall(env) { const installDir = options.prefix || env.openclawDir || join(homedir(), '.openclaw'); const binDir = join(installDir, 'bin'); const skillsDir = join(installDir, 'skills', 'paddedcell'); - const envFile = join(installDir, 'paddedcell.env'); const itemsToRemove = []; @@ -623,10 +501,6 @@ async function uninstall(env) { itemsToRemove.push(skillsDir); } - if (existsSync(envFile)) { - itemsToRemove.push(envFile); - } - if (itemsToRemove.length === 0) { log('No installed components found.', 'yellow'); return; @@ -647,7 +521,7 @@ async function uninstall(env) { // Perform uninstall for (const item of itemsToRemove) { try { - if (item === passMgrBinary || item === envFile) { + if (item === passMgrBinary) { execSync(`rm -f "${item}"`, { silent: true }); logSuccess(`Removed: ${item}`); } else { @@ -704,12 +578,12 @@ async function uninstall(env) { log('║ PaddedCell Uninstall Complete ║', 'cyan'); log('╚════════════════════════════════════════════════════════╝', 'cyan'); console.log(''); - - log('Remember to remove the following from your shell profile:', 'yellow'); - log(` source ${envFile}`, 'cyan'); - console.log(''); } +// ============================================================================ +// Main +// ============================================================================ + async function main() { console.log(''); log('╔════════════════════════════════════════════════════════╗', 'cyan'); @@ -730,12 +604,6 @@ async function main() { await buildComponents(env); await installComponents(env); await configure(env); - const verified = await verifyInstallation(env); - - if (!verified && !options.buildOnly) { - log('\nInstallation completed with warnings.', 'yellow'); - } - printSummary(env); process.exit(0); } catch (err) { From 0daf1432a7ba84f0f814830ff755b9d34f376b7f Mon Sep 17 00:00:00 2001 From: zhi Date: Thu, 5 Mar 2026 11:49:56 +0000 Subject: [PATCH 15/28] refactor: rewrite install script to match Dirigent pattern - Plugin name changed to 'padded-cell' (in OpenClaw) - Install to ~/.openclaw/plugins/padded-cell/ instead of skills - Add plugins.entries.padded-cell configuration - Add to plugins.allow list - Use --install and --uninstall flags - Follow Dirigent's delta tracking pattern --- install.mjs | 729 ++++++++++++++++++++-------------------------------- 1 file changed, 277 insertions(+), 452 deletions(-) diff --git a/install.mjs b/install.mjs index d88a895..c2dca37 100755 --- a/install.mjs +++ b/install.mjs @@ -4,38 +4,32 @@ * PaddedCell Plugin Installer * * Usage: - * node install.mjs - * node install.mjs --prefix /usr/local - * node install.mjs --build-only - * node install.mjs --skip-check + * node install.mjs --install * node install.mjs --uninstall - * node install.mjs --uninstall --prefix /usr/local */ -import { execSync } from 'child_process'; -import { existsSync, mkdirSync, copyFileSync, writeFileSync, chmodSync } from 'fs'; +import { execSync, spawnSync } from 'child_process'; +import { existsSync, mkdirSync, copyFileSync, writeFileSync, chmodSync, readdirSync, statSync } from 'fs'; import { dirname, join, resolve } from 'path'; import { fileURLToPath } from 'url'; import { homedir, platform } from 'os'; -import readline from 'readline'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); +// Plugin configuration +const PLUGIN_NAME = 'padded-cell'; +const PLUGIN_ENTRY = `plugins.entries.${PLUGIN_NAME}`; +const PLUGIN_ALLOW_PATH = 'plugins.allow'; +const PLUGINS_LOAD_PATHS = 'plugins.load.paths'; + // Parse arguments const args = process.argv.slice(2); -const options = { - prefix: null, - buildOnly: args.includes('--build-only'), - skipCheck: args.includes('--skip-check'), - verbose: args.includes('--verbose') || args.includes('-v'), - uninstall: args.includes('--uninstall'), -}; +const mode = args.includes('--uninstall') ? 'uninstall' : (args.includes('--install') ? 'install' : null); -// Parse --prefix value -const prefixIndex = args.indexOf('--prefix'); -if (prefixIndex !== -1 && args[prefixIndex + 1]) { - options.prefix = resolve(args[prefixIndex + 1]); +if (!mode) { + console.error('Usage: install.mjs --install | --uninstall'); + process.exit(2); } // Colors for output @@ -52,177 +46,122 @@ function log(message, color = 'reset') { console.log(`${colors[color]}${message}${colors.reset}`); } -function logStep(step, message) { - log(`[${step}/6] ${message}`, 'cyan'); -} - function logSuccess(message) { - log(` ✓ ${message}`, 'green'); + log(`[${PLUGIN_NAME}] ✓ ${message}`, 'green'); } function logWarning(message) { - log(` ⚠ ${message}`, 'yellow'); + log(`[${PLUGIN_NAME}] ⚠ ${message}`, 'yellow'); } function logError(message) { - log(` ✗ ${message}`, 'red'); + log(`[${PLUGIN_NAME}] ✗ ${message}`, 'red'); } -function exec(command, options = {}) { - const defaultOptions = { - cwd: __dirname, - stdio: options.silent ? 'pipe' : 'inherit', - encoding: 'utf8', - }; - return execSync(command, { ...defaultOptions, ...options }); +function logInfo(message) { + log(`[${PLUGIN_NAME}] ${message}`, 'cyan'); } -async function prompt(question) { - const rl = readline.createInterface({ - input: process.stdin, - output: process.stdout, - }); - return new Promise((resolve) => { - rl.question(question, (answer) => { - rl.close(); - resolve(answer.trim()); - }); - }); +// Execute openclaw command +function runOpenclaw(args, { allowFail = false } = {}) { + try { + return execSync('openclaw', args, { encoding: 'utf8' }).trim(); + } catch (e) { + if (allowFail) return null; + throw e; + } +} + +// Get config value as JSON +function getJson(pathKey) { + const out = runOpenclaw(['config', 'get', pathKey, '--json'], { allowFail: true }); + if (out == null || out === '' || out === 'undefined') return undefined; + try { + return JSON.parse(out); + } catch { + return undefined; + } +} + +// Set config value as JSON +function setJson(pathKey, value) { + runOpenclaw(['config', 'set', pathKey, JSON.stringify(value), '--json']); +} + +// Unset config path +function unsetPath(pathKey) { + runOpenclaw(['config', 'unset', pathKey], { allowFail: true }); +} + +// Deep clone +function clone(v) { + if (v === undefined) return undefined; + return JSON.parse(JSON.stringify(v)); +} + +// Copy directory recursively +function copyDir(src, dest) { + mkdirSync(dest, { recursive: true }); + const entries = readdirSync(src, { withFileTypes: true }); + + for (const entry of entries) { + const srcPath = join(src, entry.name); + const destPath = join(dest, entry.name); + + if (entry.isDirectory()) { + copyDir(srcPath, destPath); + } else { + copyFileSync(srcPath, destPath); + } + } } // ============================================================================ -// Step 1: Environment Detection +// Detect Environment // ============================================================================ function detectEnvironment() { - logStep(1, 'Detecting environment...'); - const env = { - platform: platform(), - isLinux: platform() === 'linux', - isMacOS: platform() === 'darwin', + openclawDir: join(homedir(), '.openclaw'), nodeVersion: null, goVersion: null, - openclawPath: null, - openclawDir: null, }; // Check Node.js try { - const version = exec('node --version', { silent: true }).trim(); - env.nodeVersion = version; - logSuccess(`Node.js ${version}`); + env.nodeVersion = execSync('node --version', { encoding: 'utf8' }).trim(); } catch { logError('Node.js not found'); } // Check Go try { - const version = exec('go version', { silent: true }).trim(); - env.goVersion = version; - logSuccess(`Go ${version}`); + env.goVersion = execSync('go version', { encoding: 'utf8' }).trim(); } catch { logError('Go not found'); } - // Check openclaw - try { - const path = exec('which openclaw', { silent: true }).trim(); - env.openclawPath = path; - logSuccess(`openclaw at ${path}`); - - // Try to find openclaw config dir - const home = homedir(); - const possibleDirs = [ - join(home, '.openclaw'), - join(home, '.config', 'openclaw'), - '/etc/openclaw', - ]; - - for (const dir of possibleDirs) { - if (existsSync(dir)) { - env.openclawDir = dir; - logSuccess(`openclaw config dir: ${dir}`); - break; - } - } - - if (!env.openclawDir) { - env.openclawDir = join(home, '.openclaw'); - logWarning(`openclaw config dir not found, will use: ${env.openclawDir}`); - } - } catch { - logWarning('openclaw CLI not found in PATH'); - env.openclawDir = join(homedir(), '.openclaw'); - } - return env; } -function checkDependencies(env) { - if (options.skipCheck) { - logWarning('Skipping dependency checks'); - return true; - } - - logStep(2, 'Checking dependencies...'); - - let hasErrors = false; - - if (!env.nodeVersion) { - logError('Node.js is required. Please install Node.js 18+'); - hasErrors = true; - } else { - const majorVersion = parseInt(env.nodeVersion.slice(1).split('.')[0]); - if (majorVersion < 18) { - logError(`Node.js 18+ required, found ${env.nodeVersion}`); - hasErrors = true; - } else { - logSuccess(`Node.js version OK`); - } - } - - if (!env.goVersion) { - logError('Go is required. Please install Go 1.22+'); - hasErrors = true; - } else { - logSuccess(`Go version OK`); - } - - if (hasErrors) { - log('\nPlease install missing dependencies and try again.', 'red'); - process.exit(1); - } - - return true; -} - // ============================================================================ -// Step 3: Build Components +// Build Components // ============================================================================ -async function buildComponents(env) { - logStep(3, 'Building components...'); +function buildComponents(env) { + logInfo('Building components...'); // Build pass_mgr log(' Building pass_mgr (Go)...', 'blue'); try { const passMgrDir = join(__dirname, 'pass_mgr'); - if (!existsSync(passMgrDir)) { - throw new Error('pass_mgr directory not found'); - } - - exec('go mod tidy', { cwd: passMgrDir, silent: !options.verbose }); - exec('go build -o dist/pass_mgr src/main.go', { - cwd: passMgrDir, - silent: !options.verbose - }); + execSync('go mod tidy', { cwd: passMgrDir, stdio: 'inherit' }); + execSync('go build -o dist/pass_mgr src/main.go', { cwd: passMgrDir, stdio: 'inherit' }); const binaryPath = join(passMgrDir, 'dist', 'pass_mgr'); if (!existsSync(binaryPath)) { throw new Error('pass_mgr binary not found after build'); } - chmodSync(binaryPath, 0o755); logSuccess('pass_mgr built successfully'); } catch (err) { @@ -234,13 +173,8 @@ async function buildComponents(env) { log(' Building pcexec (TypeScript)...', 'blue'); try { const pcexecDir = join(__dirname, 'pcexec'); - if (!existsSync(pcexecDir)) { - throw new Error('pcexec directory not found'); - } - - exec('npm install', { cwd: pcexecDir, silent: !options.verbose }); - exec('npm run build', { cwd: pcexecDir, silent: !options.verbose }); - + execSync('npm install', { cwd: pcexecDir, stdio: 'inherit' }); + execSync('npm run build', { cwd: pcexecDir, stdio: 'inherit' }); logSuccess('pcexec built successfully'); } catch (err) { logError(`Failed to build pcexec: ${err.message}`); @@ -251,13 +185,8 @@ async function buildComponents(env) { log(' Building safe-restart (TypeScript)...', 'blue'); try { const safeRestartDir = join(__dirname, 'safe-restart'); - if (!existsSync(safeRestartDir)) { - throw new Error('safe-restart directory not found'); - } - - exec('npm install', { cwd: safeRestartDir, silent: !options.verbose }); - exec('npm run build', { cwd: safeRestartDir, silent: !options.verbose }); - + execSync('npm install', { cwd: safeRestartDir, stdio: 'inherit' }); + execSync('npm run build', { cwd: safeRestartDir, stdio: 'inherit' }); logSuccess('safe-restart built successfully'); } catch (err) { logError(`Failed to build safe-restart: ${err.message}`); @@ -266,357 +195,253 @@ async function buildComponents(env) { } // ============================================================================ -// Step 4: Install Components +// Install Plugin // ============================================================================ -async function installComponents(env) { - if (options.buildOnly) { - logStep(4, 'Skipping installation (--build-only)'); - return; - } +function installPlugin(env) { + logInfo('Installing plugin...'); - logStep(4, 'Installing components...'); - - const installDir = options.prefix || env.openclawDir; - const binDir = join(installDir, 'bin'); - const skillsDir = join(installDir, 'skills', 'paddedcell'); - - log(` Install directory: ${installDir}`, 'blue'); - log(` Binary directory: ${binDir}`, 'blue'); - log(` Skills directory: ${skillsDir}`, 'blue'); + const pluginDir = join(env.openclawDir, 'plugins', PLUGIN_NAME); + const binDir = join(env.openclawDir, 'bin'); + // Create directories + mkdirSync(pluginDir, { recursive: true }); mkdirSync(binDir, { recursive: true }); - mkdirSync(skillsDir, { recursive: true }); + + // Copy plugin files + log(' Copying plugin files...', 'blue'); + + // Copy pcexec + const pcexecSource = join(__dirname, 'pcexec'); + const pcexecDest = join(pluginDir, 'pcexec'); + copyDir(pcexecSource, pcexecDest); + logSuccess(`Installed pcexec to ${pcexecDest}`); + + // Copy safe-restart + const safeRestartSource = join(__dirname, 'safe-restart'); + const safeRestartDest = join(pluginDir, 'safe-restart'); + copyDir(safeRestartSource, safeRestartDest); + logSuccess(`Installed safe-restart to ${safeRestartDest}`); // Install pass_mgr binary - log(' Installing pass_mgr binary...', 'blue'); const passMgrSource = join(__dirname, 'pass_mgr', 'dist', 'pass_mgr'); const passMgrDest = join(binDir, 'pass_mgr'); copyFileSync(passMgrSource, passMgrDest); chmodSync(passMgrDest, 0o755); - logSuccess(`pass_mgr installed to ${passMgrDest}`); + logSuccess(`Installed pass_mgr binary to ${passMgrDest}`); - // Install pcexec - log(' Installing pcexec module...', 'blue'); - const pcexecSource = join(__dirname, 'pcexec'); - const pcexecDest = join(skillsDir, 'pcexec'); - copyModule(pcexecSource, pcexecDest); - logSuccess(`pcexec installed to ${pcexecDest}`); + return { pluginDir, passMgrPath: passMgrDest }; +} - // Install safe-restart - log(' Installing safe-restart module...', 'blue'); - const safeRestartSource = join(__dirname, 'safe-restart'); - const safeRestartDest = join(skillsDir, 'safe-restart'); - copyModule(safeRestartSource, safeRestartDest); - logSuccess(`safe-restart installed to ${safeRestartDest}`); +// ============================================================================ +// Configure OpenClaw +// ============================================================================ - // Create skill manifest - log(' Creating skill manifest...', 'blue'); - const manifest = { - name: 'paddedcell', - version: '0.1.0', - description: 'Secure password management, safe execution, and coordinated restart', - tools: [ - { - name: 'pcexec', - entry: './pcexec/dist/index.js', - description: 'Safe exec with password sanitization', - }, - { - name: 'safe_restart', - entry: './safe-restart/dist/index.js', - description: 'Safe coordinated restart', - }, - ], - binaries: ['pass_mgr'], - installedAt: new Date().toISOString(), +function configureOpenClaw(env, pluginDir, delta) { + logInfo('Configuring OpenClaw...'); + + // 1. Add plugin to plugins.allow + const allowList = getJson(PLUGIN_ALLOW_PATH) || []; + const oldAllow = clone(allowList); + + if (!allowList.includes(PLUGIN_NAME)) { + allowList.push(PLUGIN_NAME); + setJson(PLUGIN_ALLOW_PATH, allowList); + delta.added[PLUGIN_ALLOW_PATH] = PLUGIN_NAME; + delta._prev = delta._prev || {}; + delta._prev[PLUGIN_ALLOW_PATH] = oldAllow; + logSuccess(`Added '${PLUGIN_NAME}' to plugins.allow`); + } else { + log(' Already in plugins.allow', 'green'); + } + + // 2. Add plugin entry + const oldEntry = getJson(PLUGIN_ENTRY); + const newEntry = { + enabled: true, + config: { + enabled: true, + passMgrPath: join(env.openclawDir, 'bin', 'pass_mgr'), + pluginDir: pluginDir, + }, }; - - writeFileSync( - join(skillsDir, 'manifest.json'), - JSON.stringify(manifest, null, 2) - ); - logSuccess('Skill manifest created'); -} -function copyModule(source, dest) { - mkdirSync(dest, { recursive: true }); - - const items = ['package.json', 'tsconfig.json', 'dist', 'src']; - for (const item of items) { - const srcPath = join(source, item); - const destPath = join(dest, item); - - if (!existsSync(srcPath)) continue; - - try { - const stat = execSync(`stat -c %F "${srcPath}" 2>/dev/null || echo "file"`, { - encoding: 'utf8', - cwd: __dirname - }).trim(); - - if (stat === 'directory') { - execSync(`cp -r "${srcPath}" "${destPath}"`, { cwd: __dirname }); - } else { - copyFileSync(srcPath, destPath); - } - } catch { - try { - copyFileSync(srcPath, destPath); - } catch { - execSync(`cp -r "${srcPath}" "${destPath}"`, { cwd: __dirname }); - } - } - } -} - -// ============================================================================ -// Step 5: Configuration -// ============================================================================ - -async function configure(env) { - if (options.buildOnly) { - logStep(5, 'Skipping configuration (--build-only)'); - return; - } - - logStep(5, 'Configuration...'); - - const installDir = env.openclawDir || join(homedir(), '.openclaw'); - const passMgrPath = join(installDir, 'bin', 'pass_mgr'); - - // Check if already initialized - const adminKeyDir = join(homedir(), '.pass_mgr'); - const configPath = join(adminKeyDir, 'config.json'); - - if (existsSync(configPath)) { - logSuccess('pass_mgr already initialized'); + if (oldEntry === undefined) { + delta.added[PLUGIN_ENTRY] = newEntry; } else { - log(' pass_mgr not initialized yet.', 'yellow'); - log(` Run "${passMgrPath} admin init" manually after installation.`, 'cyan'); + delta.replaced[PLUGIN_ENTRY] = oldEntry; } - - // Update OpenClaw plugins.load.paths configuration - log('\n Updating OpenClaw plugin configuration...', 'blue'); - try { - const skillsPath = join(installDir, 'skills', 'paddedcell'); + // Use set for nested path + const plugins = getJson('plugins') || {}; + plugins.entries = plugins.entries || {}; + plugins.entries[PLUGIN_NAME] = newEntry; + setJson('plugins', plugins); + logSuccess(`Configured ${PLUGIN_ENTRY}`); + + // 3. Add to plugins.load.paths + const pluginsConfig = getJson('plugins') || {}; + const oldPaths = clone(pluginsConfig.load?.paths) || []; + const newPaths = clone(oldPaths); + + if (!newPaths.includes(pluginDir)) { + newPaths.push(pluginDir); + delta.added[PLUGINS_LOAD_PATHS] = pluginDir; + delta._prev = delta._prev || {}; + delta._prev[PLUGINS_LOAD_PATHS] = oldPaths; - // Get current plugins.load.paths using openclaw config - let currentPaths = []; - try { - const result = execSync('openclaw config get plugins.load.paths --json 2>/dev/null || echo "[]"', { - encoding: 'utf8', - cwd: __dirname - }).trim(); - currentPaths = JSON.parse(result); - } catch { - currentPaths = []; - } - - // Add paddedcell skills path if not already present - if (!currentPaths.includes(skillsPath)) { - currentPaths.push(skillsPath); - execSync(`openclaw config set plugins.load.paths --json '${JSON.stringify(currentPaths)}'`, { - cwd: __dirname - }); - logSuccess(`Added plugin path to OpenClaw config: ${skillsPath}`); - } else { - log(' Plugin path already in OpenClaw config', 'green'); - } - } catch (err) { - logWarning(`Failed to update OpenClaw config: ${err.message}`); - log(' Please manually add the following to your OpenClaw config:', 'yellow'); - log(` openclaw config set plugins.load.paths --json '["${join(installDir, 'skills', 'paddedcell')}"]'`, 'cyan'); - } -} - -// ============================================================================ -// Step 6: Print Summary -// ============================================================================ - -function printSummary(env) { - logStep(6, 'Installation Summary'); - - const installDir = options.prefix || env.openclawDir; - const passMgrPath = join(installDir, 'bin', 'pass_mgr'); - - console.log(''); - log('╔════════════════════════════════════════════════════════╗', 'cyan'); - log('║ PaddedCell Installation Complete ║', 'cyan'); - log('╚════════════════════════════════════════════════════════╝', 'cyan'); - console.log(''); - - if (options.buildOnly) { - log('Build-only mode - binaries built but not installed', 'yellow'); - console.log(''); - log('Built artifacts:', 'blue'); - log(` • pass_mgr: ${join(__dirname, 'pass_mgr', 'dist', 'pass_mgr')}`, 'reset'); - log(` • pcexec: ${join(__dirname, 'pcexec', 'dist')}`, 'reset'); - log(` • safe-restart: ${join(__dirname, 'safe-restart', 'dist')}`, 'reset'); + pluginsConfig.load = pluginsConfig.load || {}; + pluginsConfig.load.paths = newPaths; + setJson('plugins', pluginsConfig); + logSuccess(`Added plugin path to ${PLUGINS_LOAD_PATHS}`); } else { - log('Installed components:', 'blue'); - log(` • pass_mgr binary: ${passMgrPath}`, 'reset'); - log(` • pcexec module: ${join(installDir, 'skills', 'paddedcell', 'pcexec')}`, 'reset'); - log(` • safe-restart module: ${join(installDir, 'skills', 'paddedcell', 'safe-restart')}`, 'reset'); - console.log(''); - - log('Next steps:', 'blue'); - console.log(''); - log('1. Initialize pass_mgr (required before first use):', 'yellow'); - log(` ${passMgrPath} admin init`, 'cyan'); - console.log(''); - log('2. Test pass_mgr:', 'yellow'); - log(` ${passMgrPath} set test_key mypass # Set a test password`, 'cyan'); - log(` ${passMgrPath} get test_key # Retrieve password`, 'cyan'); + log(' Plugin path already in load.paths', 'green'); } - - console.log(''); - log('For more information:', 'blue'); - log(' • Documentation: https://git.hangman-lab.top/nav/PaddedCell', 'cyan'); - log(' • Issues: https://git.hangman-lab.top/nav/PaddedCell/issues', 'cyan'); - console.log(''); } // ============================================================================ -// Uninstall Function +// Unconfigure OpenClaw // ============================================================================ -async function uninstall(env) { - logStep(1, 'Uninstalling PaddedCell...'); +function unconfigureOpenClaw(env, delta) { + logInfo('Removing OpenClaw configuration...'); - const installDir = options.prefix || env.openclawDir || join(homedir(), '.openclaw'); - const binDir = join(installDir, 'bin'); - const skillsDir = join(installDir, 'skills', 'paddedcell'); - - const itemsToRemove = []; - - // Check what exists - const passMgrBinary = join(binDir, 'pass_mgr'); - if (existsSync(passMgrBinary)) { - itemsToRemove.push(passMgrBinary); + // 1. Remove from plugins.allow first (before removing entry) + if (delta.added?.[PLUGIN_ALLOW_PATH] !== undefined) { + const allowList = getJson(PLUGIN_ALLOW_PATH) || []; + const idx = allowList.indexOf(PLUGIN_NAME); + if (idx !== -1) { + allowList.splice(idx, 1); + setJson(PLUGIN_ALLOW_PATH, allowList); + logSuccess(`Removed '${PLUGIN_NAME}' from plugins.allow`); + } } - if (existsSync(skillsDir)) { - itemsToRemove.push(skillsDir); + // 2. Remove plugin entry + if (delta.added?.[PLUGIN_ENTRY] !== undefined || delta.replaced?.[PLUGIN_ENTRY] !== undefined) { + unsetPath(PLUGIN_ENTRY); + logSuccess(`Removed ${PLUGIN_ENTRY}`); } - if (itemsToRemove.length === 0) { - log('No installed components found.', 'yellow'); - return; + // 3. Remove from plugins.load.paths + if (delta.added?.[PLUGINS_LOAD_PATHS] !== undefined) { + const plugins = getJson('plugins') || {}; + const paths = plugins.load?.paths || []; + const pluginDir = join(env.openclawDir, 'plugins', PLUGIN_NAME); + const idx = paths.indexOf(pluginDir); + + if (idx !== -1) { + paths.splice(idx, 1); + plugins.load.paths = paths; + setJson('plugins', plugins); + logSuccess(`Removed plugin path from ${PLUGINS_LOAD_PATHS}`); + } } +} - log('The following items will be removed:', 'yellow'); - for (const item of itemsToRemove) { - log(` • ${item}`, 'reset'); - } +// ============================================================================ +// Remove Plugin Files +// ============================================================================ - // Ask for confirmation - const confirm = await prompt('\nAre you sure you want to uninstall? (y/N): '); - if (confirm.toLowerCase() !== 'y') { - log('Uninstall cancelled.', 'yellow'); - return; - } +function removePluginFiles(env) { + logInfo('Removing plugin files...'); - // Perform uninstall - for (const item of itemsToRemove) { + const pluginDir = join(env.openclawDir, 'plugins', PLUGIN_NAME); + const passMgrBinary = join(env.openclawDir, 'bin', 'pass_mgr'); + + // Remove plugin directory + if (existsSync(pluginDir)) { try { - if (item === passMgrBinary) { - execSync(`rm -f "${item}"`, { silent: true }); - logSuccess(`Removed: ${item}`); - } else { - execSync(`rm -rf "${item}"`, { silent: true }); - logSuccess(`Removed: ${item}`); - } + execSync(`rm -rf "${pluginDir}"`, { encoding: 'utf8' }); + logSuccess(`Removed ${pluginDir}`); } catch (err) { - logError(`Failed to remove: ${item}`); + logError(`Failed to remove ${pluginDir}: ${err.message}`); } } - // Remove plugin path from OpenClaw config - log('\n Removing plugin path from OpenClaw config...', 'blue'); - try { - const skillsPath = join(installDir, 'skills', 'paddedcell'); - - // Get current plugins.load.paths - let currentPaths = []; + // Remove pass_mgr binary + if (existsSync(passMgrBinary)) { try { - const result = execSync('openclaw config get plugins.load.paths --json 2>/dev/null || echo "[]"', { - encoding: 'utf8', - cwd: __dirname - }).trim(); - currentPaths = JSON.parse(result); - } catch { - currentPaths = []; + execSync(`rm -f "${passMgrBinary}"`, { encoding: 'utf8' }); + logSuccess(`Removed ${passMgrBinary}`); + } catch (err) { + logError(`Failed to remove ${passMgrBinary}: ${err.message}`); } - - // Remove paddedcell skills path - const index = currentPaths.indexOf(skillsPath); - if (index > -1) { - currentPaths.splice(index, 1); - execSync(`openclaw config set plugins.load.paths --json '${JSON.stringify(currentPaths)}'`, { - cwd: __dirname - }); - logSuccess(`Removed plugin path from OpenClaw config`); - } else { - log(' Plugin path not found in OpenClaw config', 'yellow'); - } - } catch (err) { - logWarning(`Failed to update OpenClaw config: ${err.message}`); } - - // Check for admin key directory - const adminKeyDir = join(homedir(), '.pass_mgr'); - if (existsSync(adminKeyDir)) { - log('\n⚠️ Admin key directory found:', 'yellow'); - log(` ${adminKeyDir}`, 'cyan'); - log(' This contains your encryption keys. Remove manually if desired.', 'yellow'); - } - - console.log(''); - log('╔════════════════════════════════════════════════════════╗', 'cyan'); - log('║ PaddedCell Uninstall Complete ║', 'cyan'); - log('╚════════════════════════════════════════════════════════╝', 'cyan'); - console.log(''); } // ============================================================================ // Main // ============================================================================ -async function main() { - console.log(''); - log('╔════════════════════════════════════════════════════════╗', 'cyan'); - log('║ PaddedCell Plugin Installer v0.1.0 ║', 'cyan'); - log('╚════════════════════════════════════════════════════════╝', 'cyan'); - console.log(''); +function main() { + const env = detectEnvironment(); - try { - const env = detectEnvironment(); - - // Handle uninstall - if (options.uninstall) { - await uninstall(env); - process.exit(0); + if (mode === 'install') { + logInfo('Starting installation...'); + + try { + // Build components + buildComponents(env); + + // Install plugin files + const { pluginDir, passMgrPath } = installPlugin(env); + + // Configure OpenClaw + const delta = { added: {}, replaced: {}, removed: {} }; + configureOpenClaw(env, pluginDir, delta); + + logInfo('Installation complete!'); + console.log(''); + log('Next steps:', 'cyan'); + console.log(''); + log('1. Initialize pass_mgr (required before first use):', 'yellow'); + log(` ${passMgrPath} admin init`, 'cyan'); + console.log(''); + log('2. Test pass_mgr:', 'yellow'); + log(` ${passMgrPath} set test_key mypass`, 'cyan'); + log(` ${passMgrPath} get test_key`, 'cyan'); + console.log(''); + log('3. Restart OpenClaw gateway to apply changes:', 'yellow'); + log(' openclaw gateway restart', 'cyan'); + + } catch (err) { + logError(`Installation failed: ${err.message}`); + process.exit(1); } - - checkDependencies(env); - await buildComponents(env); - await installComponents(env); - await configure(env); - printSummary(env); - process.exit(0); - } catch (err) { - console.log(''); - log('╔════════════════════════════════════════════════════════╗', 'red'); - log('║ Installation Failed ║', 'red'); - log('╚════════════════════════════════════════════════════════╝', 'red'); - console.log(''); - log(`Error: ${err.message}`, 'red'); - if (options.verbose) { - console.log(err.stack); + } else { + logInfo('Starting uninstallation...'); + + // For uninstall, we need the delta from install + // For simplicity, we'll track what we added and remove it + const delta = { + added: {}, + replaced: {}, + removed: {} + }; + + // Assume we added these during install + const pluginDir = join(env.openclawDir, 'plugins', PLUGIN_NAME); + delta.added[PLUGIN_ALLOW_PATH] = PLUGIN_NAME; + delta.added[PLUGIN_ENTRY] = { enabled: true }; + delta.added[PLUGINS_LOAD_PATHS] = pluginDir; + + try { + // Unconfigure OpenClaw + unconfigureOpenClaw(env, delta); + + // Remove plugin files + removePluginFiles(env); + + logInfo('Uninstallation complete!'); + console.log(''); + log('Restart OpenClaw gateway to apply changes:', 'yellow'); + log(' openclaw gateway restart', 'cyan'); + + } catch (err) { + logError(`Uninstallation failed: ${err.message}`); + process.exit(1); } - process.exit(1); } } From 15474eee48eb028a06f7b6a392a44e0494efe60b Mon Sep 17 00:00:00 2001 From: zhi Date: Thu, 5 Mar 2026 11:50:28 +0000 Subject: [PATCH 16/28] docs: update README with new install usage --- README.md | 38 ++++++++++++++++++-------------------- README.zh-CN.md | 38 ++++++++++++++++++-------------------- 2 files changed, 36 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index a0510a2..3f64860 100644 --- a/README.md +++ b/README.md @@ -106,32 +106,30 @@ PaddedCell/ └── README.zh-CN.md # Chinese version ``` -## Development +## Installation ```bash -# Clone -git clone https://git.hangman-lab.top/nav/PaddedCell.git -cd PaddedCell +# Install +node install.mjs --install -# Build pass_mgr (requires Go) -cd pass_mgr -go build -o pass_mgr src/main.go - -# Build pcexec (requires Node.js) -cd ../pcexec -npm install -npm run build - -# Build safe-restart (requires Node.js) -cd ../safe-restart -npm install -npm run build +# Uninstall +node install.mjs --uninstall ``` -## Branches +## Usage -- `main` - Main branch -- `dev/zhi` - Development branch +### pass_mgr + +```bash +# Initialize (required before first use) +~/.openclaw/bin/pass_mgr admin init + +# Set password +~/.openclaw/bin/pass_mgr set mykey mypassword + +# Get password +~/.openclaw/bin/pass_mgr get mykey +``` ## License diff --git a/README.zh-CN.md b/README.zh-CN.md index 8cfa4ee..6fa0ef1 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -106,32 +106,30 @@ PaddedCell/ └── README.zh-CN.md # 本文档 (简体中文) ``` -## 开发 +## 安装 ```bash -# Clone -git clone https://git.hangman-lab.top/nav/PaddedCell.git -cd PaddedCell +# 安装 +node install.mjs --install -# Build pass_mgr (需要 Go) -cd pass_mgr -go build -o pass_mgr src/main.go - -# Build pcexec (需要 Node.js) -cd ../pcexec -npm install -npm run build - -# Build safe-restart (需要 Node.js) -cd ../safe-restart -npm install -npm run build +# 卸载 +node install.mjs --uninstall ``` -## 分支 +## 使用 -- `main` - 主分支 -- `dev/zhi` - 开发分支 +### pass_mgr + +```bash +# 初始化(首次使用前必须执行) +~/.openclaw/bin/pass_mgr admin init + +# 设置密码 +~/.openclaw/bin/pass_mgr set mykey mypassword + +# 获取密码 +~/.openclaw/bin/pass_mgr get mykey +``` ## 许可证 From 7e0c4cd5e6c54164c7743e6ca65139e899bd95ba Mon Sep 17 00:00:00 2001 From: zhi Date: Thu, 5 Mar 2026 11:58:35 +0000 Subject: [PATCH 17/28] refactor: use openclaw config commands, keep plugin in place - Use 'openclaw config get/set' commands (like Dirigent) - Keep plugin in current directory, don't copy to plugins/ - Plugin path is relative to script location (__dirname) - Only copy pass_mgr binary to ~/.openclaw/bin/ - Keep 6-step install flow with all original features --- install.mjs | 644 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 379 insertions(+), 265 deletions(-) diff --git a/install.mjs b/install.mjs index c2dca37..9b50cae 100755 --- a/install.mjs +++ b/install.mjs @@ -4,32 +4,40 @@ * PaddedCell Plugin Installer * * Usage: - * node install.mjs --install + * node install.mjs + * node install.mjs --prefix /usr/local + * node install.mjs --build-only + * node install.mjs --skip-check * node install.mjs --uninstall */ -import { execSync, spawnSync } from 'child_process'; -import { existsSync, mkdirSync, copyFileSync, writeFileSync, chmodSync, readdirSync, statSync } from 'fs'; +import { execSync } from 'child_process'; +import { existsSync, mkdirSync, copyFileSync, chmodSync } from 'fs'; import { dirname, join, resolve } from 'path'; import { fileURLToPath } from 'url'; import { homedir, platform } from 'os'; +import readline from 'readline'; const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); +const __dirname = resolve(dirname(__filename)); // Plugin configuration const PLUGIN_NAME = 'padded-cell'; -const PLUGIN_ENTRY = `plugins.entries.${PLUGIN_NAME}`; -const PLUGIN_ALLOW_PATH = 'plugins.allow'; -const PLUGINS_LOAD_PATHS = 'plugins.load.paths'; // Parse arguments const args = process.argv.slice(2); -const mode = args.includes('--uninstall') ? 'uninstall' : (args.includes('--install') ? 'install' : null); +const options = { + prefix: null, + buildOnly: args.includes('--build-only'), + skipCheck: args.includes('--skip-check'), + verbose: args.includes('--verbose') || args.includes('-v'), + uninstall: args.includes('--uninstall'), +}; -if (!mode) { - console.error('Usage: install.mjs --install | --uninstall'); - process.exit(2); +// Parse --prefix value +const prefixIndex = args.indexOf('--prefix'); +if (prefixIndex !== -1 && args[prefixIndex + 1]) { + options.prefix = resolve(args[prefixIndex + 1]); } // Colors for output @@ -46,122 +54,205 @@ function log(message, color = 'reset') { console.log(`${colors[color]}${message}${colors.reset}`); } +function logStep(step, message) { + log(`[${step}/6] ${message}`, 'cyan'); +} + function logSuccess(message) { - log(`[${PLUGIN_NAME}] ✓ ${message}`, 'green'); + log(` ✓ ${message}`, 'green'); } function logWarning(message) { - log(`[${PLUGIN_NAME}] ⚠ ${message}`, 'yellow'); + log(` ⚠ ${message}`, 'yellow'); } function logError(message) { - log(`[${PLUGIN_NAME}] ✗ ${message}`, 'red'); + log(` ✗ ${message}`, 'red'); } -function logInfo(message) { - log(`[${PLUGIN_NAME}] ${message}`, 'cyan'); +function exec(command, options = {}) { + const defaultOptions = { + cwd: __dirname, + stdio: options.silent ? 'pipe' : 'inherit', + encoding: 'utf8', + }; + return execSync(command, { ...defaultOptions, ...options }); } -// Execute openclaw command -function runOpenclaw(args, { allowFail = false } = {}) { - try { - return execSync('openclaw', args, { encoding: 'utf8' }).trim(); - } catch (e) { - if (allowFail) return null; - throw e; - } -} - -// Get config value as JSON -function getJson(pathKey) { - const out = runOpenclaw(['config', 'get', pathKey, '--json'], { allowFail: true }); - if (out == null || out === '' || out === 'undefined') return undefined; +async function prompt(question) { + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, + }); + return new Promise((resolve) => { + rl.question(question, (answer) => { + rl.close(); + resolve(answer.trim()); + }); + }); +} + +// OpenClaw config helpers +function getOpenclawConfig(pathKey, defaultValue = undefined) { try { + const out = execSync(`openclaw config get ${pathKey} --json 2>/dev/null || echo "undefined"`, { + encoding: 'utf8', + cwd: __dirname + }).trim(); + if (out === 'undefined' || out === '') return defaultValue; return JSON.parse(out); } catch { - return undefined; + return defaultValue; } } -// Set config value as JSON -function setJson(pathKey, value) { - runOpenclaw(['config', 'set', pathKey, JSON.stringify(value), '--json']); +function setOpenclawConfig(pathKey, value) { + execSync(`openclaw config set ${pathKey} --json '${JSON.stringify(value)}'`, { + cwd: __dirname + }); } -// Unset config path -function unsetPath(pathKey) { - runOpenclaw(['config', 'unset', pathKey], { allowFail: true }); -} - -// Deep clone -function clone(v) { - if (v === undefined) return undefined; - return JSON.parse(JSON.stringify(v)); -} - -// Copy directory recursively -function copyDir(src, dest) { - mkdirSync(dest, { recursive: true }); - const entries = readdirSync(src, { withFileTypes: true }); - - for (const entry of entries) { - const srcPath = join(src, entry.name); - const destPath = join(dest, entry.name); - - if (entry.isDirectory()) { - copyDir(srcPath, destPath); - } else { - copyFileSync(srcPath, destPath); - } +function unsetOpenclawConfig(pathKey) { + try { + execSync(`openclaw config unset ${pathKey}`, { cwd: __dirname }); + } catch { + // Ignore errors } } // ============================================================================ -// Detect Environment +// Step 1: Environment Detection // ============================================================================ function detectEnvironment() { + logStep(1, 'Detecting environment...'); + const env = { - openclawDir: join(homedir(), '.openclaw'), + platform: platform(), + isLinux: platform() === 'linux', + isMacOS: platform() === 'darwin', nodeVersion: null, goVersion: null, + openclawPath: null, + openclawDir: null, }; // Check Node.js try { - env.nodeVersion = execSync('node --version', { encoding: 'utf8' }).trim(); + const version = exec('node --version', { silent: true }).trim(); + env.nodeVersion = version; + logSuccess(`Node.js ${version}`); } catch { logError('Node.js not found'); } // Check Go try { - env.goVersion = execSync('go version', { encoding: 'utf8' }).trim(); + const version = exec('go version', { silent: true }).trim(); + env.goVersion = version; + logSuccess(`Go ${version}`); } catch { logError('Go not found'); } + // Check openclaw + try { + const path = exec('which openclaw', { silent: true }).trim(); + env.openclawPath = path; + logSuccess(`openclaw at ${path}`); + + // Try to find openclaw config dir + const home = homedir(); + const possibleDirs = [ + join(home, '.openclaw'), + join(home, '.config', 'openclaw'), + '/etc/openclaw', + ]; + + for (const dir of possibleDirs) { + if (existsSync(dir)) { + env.openclawDir = dir; + logSuccess(`openclaw config dir: ${dir}`); + break; + } + } + + if (!env.openclawDir) { + env.openclawDir = join(home, '.openclaw'); + logWarning(`openclaw config dir not found, will use: ${env.openclawDir}`); + } + } catch { + logWarning('openclaw CLI not found in PATH'); + env.openclawDir = join(homedir(), '.openclaw'); + } + return env; } +function checkDependencies(env) { + if (options.skipCheck) { + logWarning('Skipping dependency checks'); + return true; + } + + logStep(2, 'Checking dependencies...'); + + let hasErrors = false; + + if (!env.nodeVersion) { + logError('Node.js is required. Please install Node.js 18+'); + hasErrors = true; + } else { + const majorVersion = parseInt(env.nodeVersion.slice(1).split('.')[0]); + if (majorVersion < 18) { + logError(`Node.js 18+ required, found ${env.nodeVersion}`); + hasErrors = true; + } else { + logSuccess(`Node.js version OK`); + } + } + + if (!env.goVersion) { + logError('Go is required. Please install Go 1.22+'); + hasErrors = true; + } else { + logSuccess(`Go version OK`); + } + + if (hasErrors) { + log('\nPlease install missing dependencies and try again.', 'red'); + process.exit(1); + } + + return true; +} + // ============================================================================ -// Build Components +// Step 3: Build Components // ============================================================================ -function buildComponents(env) { - logInfo('Building components...'); +async function buildComponents(env) { + logStep(3, 'Building components...'); // Build pass_mgr log(' Building pass_mgr (Go)...', 'blue'); try { const passMgrDir = join(__dirname, 'pass_mgr'); - execSync('go mod tidy', { cwd: passMgrDir, stdio: 'inherit' }); - execSync('go build -o dist/pass_mgr src/main.go', { cwd: passMgrDir, stdio: 'inherit' }); + if (!existsSync(passMgrDir)) { + throw new Error('pass_mgr directory not found'); + } + + exec('go mod tidy', { cwd: passMgrDir, silent: !options.verbose }); + exec('go build -o dist/pass_mgr src/main.go', { + cwd: passMgrDir, + silent: !options.verbose + }); const binaryPath = join(passMgrDir, 'dist', 'pass_mgr'); if (!existsSync(binaryPath)) { throw new Error('pass_mgr binary not found after build'); } + chmodSync(binaryPath, 0o755); logSuccess('pass_mgr built successfully'); } catch (err) { @@ -173,8 +264,13 @@ function buildComponents(env) { log(' Building pcexec (TypeScript)...', 'blue'); try { const pcexecDir = join(__dirname, 'pcexec'); - execSync('npm install', { cwd: pcexecDir, stdio: 'inherit' }); - execSync('npm run build', { cwd: pcexecDir, stdio: 'inherit' }); + if (!existsSync(pcexecDir)) { + throw new Error('pcexec directory not found'); + } + + exec('npm install', { cwd: pcexecDir, silent: !options.verbose }); + exec('npm run build', { cwd: pcexecDir, silent: !options.verbose }); + logSuccess('pcexec built successfully'); } catch (err) { logError(`Failed to build pcexec: ${err.message}`); @@ -185,8 +281,13 @@ function buildComponents(env) { log(' Building safe-restart (TypeScript)...', 'blue'); try { const safeRestartDir = join(__dirname, 'safe-restart'); - execSync('npm install', { cwd: safeRestartDir, stdio: 'inherit' }); - execSync('npm run build', { cwd: safeRestartDir, stdio: 'inherit' }); + if (!existsSync(safeRestartDir)) { + throw new Error('safe-restart directory not found'); + } + + exec('npm install', { cwd: safeRestartDir, silent: !options.verbose }); + exec('npm run build', { cwd: safeRestartDir, silent: !options.verbose }); + logSuccess('safe-restart built successfully'); } catch (err) { logError(`Failed to build safe-restart: ${err.message}`); @@ -195,253 +296,266 @@ function buildComponents(env) { } // ============================================================================ -// Install Plugin +// Step 4: Install Components // ============================================================================ -function installPlugin(env) { - logInfo('Installing plugin...'); +async function installComponents(env) { + if (options.buildOnly) { + logStep(4, 'Skipping installation (--build-only)'); + return null; + } - const pluginDir = join(env.openclawDir, 'plugins', PLUGIN_NAME); - const binDir = join(env.openclawDir, 'bin'); + logStep(4, 'Installing components...'); - // Create directories - mkdirSync(pluginDir, { recursive: true }); + const installDir = options.prefix || env.openclawDir; + const binDir = join(installDir, 'bin'); + + log(` Install directory: ${installDir}`, 'blue'); + log(` Binary directory: ${binDir}`, 'blue'); + log(` Plugin directory: ${__dirname}`, 'blue'); + + // Create bin directory mkdirSync(binDir, { recursive: true }); - // Copy plugin files - log(' Copying plugin files...', 'blue'); - - // Copy pcexec - const pcexecSource = join(__dirname, 'pcexec'); - const pcexecDest = join(pluginDir, 'pcexec'); - copyDir(pcexecSource, pcexecDest); - logSuccess(`Installed pcexec to ${pcexecDest}`); - - // Copy safe-restart - const safeRestartSource = join(__dirname, 'safe-restart'); - const safeRestartDest = join(pluginDir, 'safe-restart'); - copyDir(safeRestartSource, safeRestartDest); - logSuccess(`Installed safe-restart to ${safeRestartDest}`); - // Install pass_mgr binary + log(' Installing pass_mgr binary...', 'blue'); const passMgrSource = join(__dirname, 'pass_mgr', 'dist', 'pass_mgr'); const passMgrDest = join(binDir, 'pass_mgr'); copyFileSync(passMgrSource, passMgrDest); chmodSync(passMgrDest, 0o755); - logSuccess(`Installed pass_mgr binary to ${passMgrDest}`); + logSuccess(`pass_mgr installed to ${passMgrDest}`); - return { pluginDir, passMgrPath: passMgrDest }; + return { passMgrPath: passMgrDest }; } // ============================================================================ -// Configure OpenClaw +// Step 5: Configuration // ============================================================================ -function configureOpenClaw(env, pluginDir, delta) { - logInfo('Configuring OpenClaw...'); - - // 1. Add plugin to plugins.allow - const allowList = getJson(PLUGIN_ALLOW_PATH) || []; - const oldAllow = clone(allowList); - - if (!allowList.includes(PLUGIN_NAME)) { - allowList.push(PLUGIN_NAME); - setJson(PLUGIN_ALLOW_PATH, allowList); - delta.added[PLUGIN_ALLOW_PATH] = PLUGIN_NAME; - delta._prev = delta._prev || {}; - delta._prev[PLUGIN_ALLOW_PATH] = oldAllow; - logSuccess(`Added '${PLUGIN_NAME}' to plugins.allow`); - } else { - log(' Already in plugins.allow', 'green'); +async function configure(env) { + if (options.buildOnly) { + logStep(5, 'Skipping configuration (--build-only)'); + return; } - // 2. Add plugin entry - const oldEntry = getJson(PLUGIN_ENTRY); - const newEntry = { - enabled: true, - config: { + logStep(5, 'Configuration...'); + + const installDir = options.prefix || env.openclawDir; + const passMgrPath = join(installDir, 'bin', 'pass_mgr'); + + // Check if already initialized + const adminKeyDir = join(homedir(), '.pass_mgr'); + const configPath = join(adminKeyDir, 'config.json'); + + if (existsSync(configPath)) { + logSuccess('pass_mgr already initialized'); + } else { + log(' pass_mgr not initialized yet.', 'yellow'); + log(` Run "${passMgrPath} admin init" manually after installation.`, 'cyan'); + } + + // Configure OpenClaw using openclaw config commands + log('\n Configuring OpenClaw plugin...', 'blue'); + + try { + // 1. Add to plugins.allow + const allowList = getOpenclawConfig('plugins.allow', []); + if (!allowList.includes(PLUGIN_NAME)) { + allowList.push(PLUGIN_NAME); + setOpenclawConfig('plugins.allow', allowList); + logSuccess(`Added '${PLUGIN_NAME}' to plugins.allow`); + } else { + log(' Already in plugins.allow', 'green'); + } + + // 2. Add plugin entry + const existingEntry = getOpenclawConfig(`plugins.entries.${PLUGIN_NAME}`); + const pluginEntry = { enabled: true, - passMgrPath: join(env.openclawDir, 'bin', 'pass_mgr'), - pluginDir: pluginDir, - }, - }; - - if (oldEntry === undefined) { - delta.added[PLUGIN_ENTRY] = newEntry; - } else { - delta.replaced[PLUGIN_ENTRY] = oldEntry; - } - - // Use set for nested path - const plugins = getJson('plugins') || {}; - plugins.entries = plugins.entries || {}; - plugins.entries[PLUGIN_NAME] = newEntry; - setJson('plugins', plugins); - logSuccess(`Configured ${PLUGIN_ENTRY}`); - - // 3. Add to plugins.load.paths - const pluginsConfig = getJson('plugins') || {}; - const oldPaths = clone(pluginsConfig.load?.paths) || []; - const newPaths = clone(oldPaths); - - if (!newPaths.includes(pluginDir)) { - newPaths.push(pluginDir); - delta.added[PLUGINS_LOAD_PATHS] = pluginDir; - delta._prev = delta._prev || {}; - delta._prev[PLUGINS_LOAD_PATHS] = oldPaths; + config: { + enabled: true, + passMgrPath: passMgrPath, + pluginDir: __dirname, + }, + }; - pluginsConfig.load = pluginsConfig.load || {}; - pluginsConfig.load.paths = newPaths; - setJson('plugins', pluginsConfig); - logSuccess(`Added plugin path to ${PLUGINS_LOAD_PATHS}`); - } else { - log(' Plugin path already in load.paths', 'green'); + const plugins = getOpenclawConfig('plugins', {}); + plugins.entries = plugins.entries || {}; + plugins.entries[PLUGIN_NAME] = pluginEntry; + setOpenclawConfig('plugins', plugins); + + if (existingEntry) { + logSuccess(`Updated ${PLUGIN_NAME} plugin entry`); + } else { + logSuccess(`Added ${PLUGIN_NAME} plugin entry`); + } + + // 3. Add plugin path to plugins.load.paths + const currentPaths = getOpenclawConfig('plugins.load.paths', []); + if (!currentPaths.includes(__dirname)) { + currentPaths.push(__dirname); + setOpenclawConfig('plugins.load.paths', currentPaths); + logSuccess(`Added plugin path to plugins.load.paths`); + } else { + log(' Plugin path already in plugins.load.paths', 'green'); + } + } catch (err) { + logWarning(`Failed to configure OpenClaw: ${err.message}`); + log(' Please manually configure:', 'yellow'); + log(` openclaw config set plugins.allow --json '[..., "${PLUGIN_NAME}"]'`, 'cyan'); + log(` openclaw config set plugins.entries.${PLUGIN_NAME}.enabled --json 'true'`, 'cyan'); + log(` openclaw config set plugins.load.paths --json '[..., "${__dirname}"]'`, 'cyan'); } } // ============================================================================ -// Unconfigure OpenClaw +// Step 6: Print Summary // ============================================================================ -function unconfigureOpenClaw(env, delta) { - logInfo('Removing OpenClaw configuration...'); +function printSummary(env, passMgrPath) { + logStep(6, 'Installation Summary'); - // 1. Remove from plugins.allow first (before removing entry) - if (delta.added?.[PLUGIN_ALLOW_PATH] !== undefined) { - const allowList = getJson(PLUGIN_ALLOW_PATH) || []; - const idx = allowList.indexOf(PLUGIN_NAME); - if (idx !== -1) { - allowList.splice(idx, 1); - setJson(PLUGIN_ALLOW_PATH, allowList); - logSuccess(`Removed '${PLUGIN_NAME}' from plugins.allow`); - } - } + console.log(''); + log('╔════════════════════════════════════════════════════════╗', 'cyan'); + log('║ PaddedCell Installation Complete ║', 'cyan'); + log('╚════════════════════════════════════════════════════════╝', 'cyan'); + console.log(''); - // 2. Remove plugin entry - if (delta.added?.[PLUGIN_ENTRY] !== undefined || delta.replaced?.[PLUGIN_ENTRY] !== undefined) { - unsetPath(PLUGIN_ENTRY); - logSuccess(`Removed ${PLUGIN_ENTRY}`); - } - - // 3. Remove from plugins.load.paths - if (delta.added?.[PLUGINS_LOAD_PATHS] !== undefined) { - const plugins = getJson('plugins') || {}; - const paths = plugins.load?.paths || []; - const pluginDir = join(env.openclawDir, 'plugins', PLUGIN_NAME); - const idx = paths.indexOf(pluginDir); + if (options.buildOnly) { + log('Build-only mode - binaries built but not installed', 'yellow'); + console.log(''); + log('Built artifacts:', 'blue'); + log(` • pass_mgr: ${join(__dirname, 'pass_mgr', 'dist', 'pass_mgr')}`, 'reset'); + log(` • pcexec: ${join(__dirname, 'pcexec', 'dist')}`, 'reset'); + log(` • safe-restart: ${join(__dirname, 'safe-restart', 'dist')}`, 'reset'); + } else { + log('Installed components:', 'blue'); + log(` • pass_mgr binary: ${passMgrPath}`, 'reset'); + log(` • Plugin location: ${__dirname}`, 'reset'); + console.log(''); - if (idx !== -1) { - paths.splice(idx, 1); - plugins.load.paths = paths; - setJson('plugins', plugins); - logSuccess(`Removed plugin path from ${PLUGINS_LOAD_PATHS}`); - } + log('Next steps:', 'blue'); + console.log(''); + log('1. Initialize pass_mgr (required before first use):', 'yellow'); + log(` ${passMgrPath} admin init`, 'cyan'); + console.log(''); + log('2. Test pass_mgr:', 'yellow'); + log(` ${passMgrPath} set test_key mypass`, 'cyan'); + log(` ${passMgrPath} get test_key`, 'cyan'); + console.log(''); + log('3. Restart OpenClaw gateway:', 'yellow'); + log(' openclaw gateway restart', 'cyan'); } + + console.log(''); + log('For more information:', 'blue'); + log(' • Documentation: https://git.hangman-lab.top/nav/PaddedCell', 'cyan'); + console.log(''); } // ============================================================================ -// Remove Plugin Files +// Uninstall // ============================================================================ -function removePluginFiles(env) { - logInfo('Removing plugin files...'); +async function uninstall(env) { + logStep(1, 'Uninstalling PaddedCell...'); - const pluginDir = join(env.openclawDir, 'plugins', PLUGIN_NAME); - const passMgrBinary = join(env.openclawDir, 'bin', 'pass_mgr'); - - // Remove plugin directory - if (existsSync(pluginDir)) { - try { - execSync(`rm -rf "${pluginDir}"`, { encoding: 'utf8' }); - logSuccess(`Removed ${pluginDir}`); - } catch (err) { - logError(`Failed to remove ${pluginDir}: ${err.message}`); - } - } + const installDir = options.prefix || env.openclawDir || join(homedir(), '.openclaw'); + const passMgrBinary = join(installDir, 'bin', 'pass_mgr'); // Remove pass_mgr binary if (existsSync(passMgrBinary)) { try { - execSync(`rm -f "${passMgrBinary}"`, { encoding: 'utf8' }); + execSync(`rm -f "${passMgrBinary}"`, { silent: true }); logSuccess(`Removed ${passMgrBinary}`); } catch (err) { - logError(`Failed to remove ${passMgrBinary}: ${err.message}`); + logError(`Failed to remove ${passMgrBinary}`); } } + + // Remove OpenClaw configuration + log('\n Removing OpenClaw configuration...', 'blue'); + + try { + // Remove from plugins.allow + const allowList = getOpenclawConfig('plugins.allow', []); + const idx = allowList.indexOf(PLUGIN_NAME); + if (idx !== -1) { + allowList.splice(idx, 1); + setOpenclawConfig('plugins.allow', allowList); + logSuccess(`Removed '${PLUGIN_NAME}' from plugins.allow`); + } + + // Remove plugin entry + unsetOpenclawConfig(`plugins.entries.${PLUGIN_NAME}`); + logSuccess(`Removed ${PLUGIN_NAME} plugin entry`); + + // Remove from plugins.load.paths + const currentPaths = getOpenclawConfig('plugins.load.paths', []); + const pathIdx = currentPaths.indexOf(__dirname); + if (pathIdx !== -1) { + currentPaths.splice(pathIdx, 1); + setOpenclawConfig('plugins.load.paths', currentPaths); + logSuccess(`Removed plugin path from plugins.load.paths`); + } + } catch (err) { + logWarning(`Failed to update OpenClaw config: ${err.message}`); + } + + // Check for admin key directory + const adminKeyDir = join(homedir(), '.pass_mgr'); + if (existsSync(adminKeyDir)) { + log('\n⚠️ Admin key directory found:', 'yellow'); + log(` ${adminKeyDir}`, 'cyan'); + log(' This contains your encryption keys. Remove manually if desired.', 'yellow'); + } + + console.log(''); + log('╔════════════════════════════════════════════════════════╗', 'cyan'); + log('║ PaddedCell Uninstall Complete ║', 'cyan'); + log('╚════════════════════════════════════════════════════════╝', 'cyan'); + console.log(''); + log('Restart OpenClaw gateway:', 'yellow'); + log(' openclaw gateway restart', 'cyan'); } // ============================================================================ // Main // ============================================================================ -function main() { - const env = detectEnvironment(); +async function main() { + console.log(''); + log('╔════════════════════════════════════════════════════════╗', 'cyan'); + log('║ PaddedCell Plugin Installer v0.1.0 ║', 'cyan'); + log('╚════════════════════════════════════════════════════════╝', 'cyan'); + console.log(''); - if (mode === 'install') { - logInfo('Starting installation...'); - - try { - // Build components - buildComponents(env); - - // Install plugin files - const { pluginDir, passMgrPath } = installPlugin(env); - - // Configure OpenClaw - const delta = { added: {}, replaced: {}, removed: {} }; - configureOpenClaw(env, pluginDir, delta); - - logInfo('Installation complete!'); - console.log(''); - log('Next steps:', 'cyan'); - console.log(''); - log('1. Initialize pass_mgr (required before first use):', 'yellow'); - log(` ${passMgrPath} admin init`, 'cyan'); - console.log(''); - log('2. Test pass_mgr:', 'yellow'); - log(` ${passMgrPath} set test_key mypass`, 'cyan'); - log(` ${passMgrPath} get test_key`, 'cyan'); - console.log(''); - log('3. Restart OpenClaw gateway to apply changes:', 'yellow'); - log(' openclaw gateway restart', 'cyan'); - - } catch (err) { - logError(`Installation failed: ${err.message}`); - process.exit(1); + try { + const env = detectEnvironment(); + + // Handle uninstall + if (options.uninstall) { + await uninstall(env); + process.exit(0); } - } else { - logInfo('Starting uninstallation...'); - - // For uninstall, we need the delta from install - // For simplicity, we'll track what we added and remove it - const delta = { - added: {}, - replaced: {}, - removed: {} - }; - - // Assume we added these during install - const pluginDir = join(env.openclawDir, 'plugins', PLUGIN_NAME); - delta.added[PLUGIN_ALLOW_PATH] = PLUGIN_NAME; - delta.added[PLUGIN_ENTRY] = { enabled: true }; - delta.added[PLUGINS_LOAD_PATHS] = pluginDir; - - try { - // Unconfigure OpenClaw - unconfigureOpenClaw(env, delta); - - // Remove plugin files - removePluginFiles(env); - - logInfo('Uninstallation complete!'); - console.log(''); - log('Restart OpenClaw gateway to apply changes:', 'yellow'); - log(' openclaw gateway restart', 'cyan'); - - } catch (err) { - logError(`Uninstallation failed: ${err.message}`); - process.exit(1); + + checkDependencies(env); + await buildComponents(env); + const result = await installComponents(env); + await configure(env); + printSummary(env, result?.passMgrPath); + process.exit(0); + } catch (err) { + console.log(''); + log('╔════════════════════════════════════════════════════════╗', 'red'); + log('║ Installation Failed ║', 'red'); + log('╚════════════════════════════════════════════════════════╝', 'red'); + console.log(''); + log(`Error: ${err.message}`, 'red'); + if (options.verbose) { + console.log(err.stack); } + process.exit(1); } } From 08e74e38063c48206bfea5dcf899e749ff911f8a Mon Sep 17 00:00:00 2001 From: zhi Date: Thu, 5 Mar 2026 12:08:23 +0000 Subject: [PATCH 18/28] feat: add OpenClaw plugin manifest - Add openclaw.plugin.json with plugin metadata - Define tools: pcexec and safe_restart --- openclaw.plugin.json | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 openclaw.plugin.json diff --git a/openclaw.plugin.json b/openclaw.plugin.json new file mode 100644 index 0000000..162f222 --- /dev/null +++ b/openclaw.plugin.json @@ -0,0 +1,19 @@ +{ + "id": "padded-cell", + "name": "PaddedCell", + "version": "0.1.0", + "description": "Secure password management, safe execution, and coordinated restart", + "entry": "./safe-restart/dist/index.js", + "tools": [ + { + "name": "pcexec", + "entry": "./pcexec/dist/index.js", + "description": "Safe exec with password sanitization" + }, + { + "name": "safe_restart", + "entry": "./safe-restart/dist/index.js", + "description": "Safe coordinated restart" + } + ] +} From da34a3eb5e4e5610d49a6f0fafe2e101243ddffb Mon Sep 17 00:00:00 2001 From: zhi Date: Thu, 5 Mar 2026 12:09:11 +0000 Subject: [PATCH 19/28] feat: add OpenClaw plugin manifest and entry point - Add openclaw.plugin.json with proper configSchema - Add index.js as plugin entry point - Fix plugin id to 'padded-cell' to match manifest --- index.js | 21 +++++++++++++++++++++ openclaw.plugin.json | 8 +++++++- 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 index.js diff --git a/index.js b/index.js new file mode 100644 index 0000000..9fa470b --- /dev/null +++ b/index.js @@ -0,0 +1,21 @@ +// PaddedCell Plugin Entry Point +export const id = 'padded-cell'; +export const name = 'PaddedCell'; +export const version = '0.1.0'; + +// Export tools (will be loaded by OpenClaw) +export { pcexec } from './pcexec/dist/index.js'; +export { + safeRestart, + createSafeRestartTool, + StatusManager, + createApiServer, + startApiServer +} from './safe-restart/dist/index.js'; + +// Default export +export default { + id, + name, + version, +}; diff --git a/openclaw.plugin.json b/openclaw.plugin.json index 162f222..908bc6f 100644 --- a/openclaw.plugin.json +++ b/openclaw.plugin.json @@ -3,7 +3,13 @@ "name": "PaddedCell", "version": "0.1.0", "description": "Secure password management, safe execution, and coordinated restart", - "entry": "./safe-restart/dist/index.js", + "entry": "./index.js", + "configSchema": { + "type": "object", + "properties": { + "enabled": { "type": "boolean", "default": true } + } + }, "tools": [ { "name": "pcexec", From c366958a376451c8ec3dca19e19e0fe8e959ee44 Mon Sep 17 00:00:00 2001 From: zhi Date: Thu, 5 Mar 2026 12:09:42 +0000 Subject: [PATCH 20/28] fix: use PaddedCell as plugin id to match directory name - Change plugin id from 'padded-cell' to 'PaddedCell' - Update manifest and install script - OpenClaw infers plugin id from directory name --- install.mjs | 2 +- openclaw.plugin.json | 2 +- pass_mgr/go.mod | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/install.mjs b/install.mjs index 9b50cae..0b93e03 100755 --- a/install.mjs +++ b/install.mjs @@ -22,7 +22,7 @@ const __filename = fileURLToPath(import.meta.url); const __dirname = resolve(dirname(__filename)); // Plugin configuration -const PLUGIN_NAME = 'padded-cell'; +const PLUGIN_NAME = 'PaddedCell'; // Parse arguments const args = process.argv.slice(2); diff --git a/openclaw.plugin.json b/openclaw.plugin.json index 908bc6f..b7047d4 100644 --- a/openclaw.plugin.json +++ b/openclaw.plugin.json @@ -1,5 +1,5 @@ { - "id": "padded-cell", + "id": "PaddedCell", "name": "PaddedCell", "version": "0.1.0", "description": "Secure password management, safe execution, and coordinated restart", diff --git a/pass_mgr/go.mod b/pass_mgr/go.mod index 19e7de1..c2a757a 100644 --- a/pass_mgr/go.mod +++ b/pass_mgr/go.mod @@ -2,11 +2,13 @@ module pass_mgr go 1.24.0 -require github.com/spf13/cobra v1.8.0 +require ( + github.com/spf13/cobra v1.8.0 + golang.org/x/term v0.40.0 +) require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect golang.org/x/sys v0.41.0 // indirect - golang.org/x/term v0.40.0 // indirect ) From 888ed0e51ac3d87157c65c1c9da9033a65a6b288 Mon Sep 17 00:00:00 2001 From: zhi Date: Thu, 5 Mar 2026 12:10:04 +0000 Subject: [PATCH 21/28] fix: install script creates openclaw.plugin.json and index.js - Add writeFileSync import - Create manifest file during install if not exists - Create index.js entry point during install if not exists --- install.mjs | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/install.mjs b/install.mjs index 0b93e03..7e8e4db 100755 --- a/install.mjs +++ b/install.mjs @@ -12,7 +12,7 @@ */ import { execSync } from 'child_process'; -import { existsSync, mkdirSync, copyFileSync, chmodSync } from 'fs'; +import { existsSync, mkdirSync, copyFileSync, writeFileSync, chmodSync } from 'fs'; import { dirname, join, resolve } from 'path'; import { fileURLToPath } from 'url'; import { homedir, platform } from 'os'; @@ -317,6 +317,67 @@ async function installComponents(env) { // Create bin directory mkdirSync(binDir, { recursive: true }); + // Create openclaw.plugin.json if not exists + const manifestPath = join(__dirname, 'openclaw.plugin.json'); + if (!existsSync(manifestPath)) { + const manifest = { + id: PLUGIN_NAME, + name: 'PaddedCell', + version: '0.1.0', + description: 'Secure password management, safe execution, and coordinated restart', + entry: './index.js', + configSchema: { + type: 'object', + properties: { + enabled: { type: 'boolean', default: true } + } + }, + tools: [ + { + name: 'pcexec', + entry: './pcexec/dist/index.js', + description: 'Safe exec with password sanitization' + }, + { + name: 'safe_restart', + entry: './safe-restart/dist/index.js', + description: 'Safe coordinated restart' + } + ] + }; + writeFileSync(manifestPath, JSON.stringify(manifest, null, 2)); + logSuccess('Created openclaw.plugin.json'); + } + + // Create index.js if not exists + const indexPath = join(__dirname, 'index.js'); + if (!existsSync(indexPath)) { + const indexContent = `// PaddedCell Plugin Entry Point +export const id = '${PLUGIN_NAME}'; +export const name = 'PaddedCell'; +export const version = '0.1.0'; + +// Export tools (will be loaded by OpenClaw) +export { pcexec } from './pcexec/dist/index.js'; +export { + safeRestart, + createSafeRestartTool, + StatusManager, + createApiServer, + startApiServer +} from './safe-restart/dist/index.js'; + +// Default export +export default { + id, + name, + version, +}; +`; + writeFileSync(indexPath, indexContent); + logSuccess('Created index.js'); + } + // Install pass_mgr binary log(' Installing pass_mgr binary...', 'blue'); const passMgrSource = join(__dirname, 'pass_mgr', 'dist', 'pass_mgr'); From bb194ef97834b9e36ac2604e8af1184855f5d31e Mon Sep 17 00:00:00 2001 From: zhi Date: Thu, 5 Mar 2026 12:26:52 +0000 Subject: [PATCH 22/28] refactor: install to dist/padded-cell/ like Dirigent - Plugin name: padded-cell (matches dist subdirectory) - Install copies files to dist/padded-cell/ - Plugin path set to dist/padded-cell/ directory - Follows Dirigent pattern: dist// --- install.mjs | 231 ++++++++++++++++--------------------------- openclaw.plugin.json | 10 +- 2 files changed, 88 insertions(+), 153 deletions(-) diff --git a/install.mjs b/install.mjs index 7e8e4db..0a7a6fd 100755 --- a/install.mjs +++ b/install.mjs @@ -9,20 +9,21 @@ * node install.mjs --build-only * node install.mjs --skip-check * node install.mjs --uninstall + * node install.mjs --uninstall --prefix /usr/local */ import { execSync } from 'child_process'; -import { existsSync, mkdirSync, copyFileSync, writeFileSync, chmodSync } from 'fs'; +import { existsSync, mkdirSync, copyFileSync, writeFileSync, chmodSync, readdirSync, statSync } from 'fs'; import { dirname, join, resolve } from 'path'; import { fileURLToPath } from 'url'; import { homedir, platform } from 'os'; -import readline from 'readline'; const __filename = fileURLToPath(import.meta.url); const __dirname = resolve(dirname(__filename)); -// Plugin configuration -const PLUGIN_NAME = 'PaddedCell'; +// Plugin configuration - matches directory name in dist/ +const PLUGIN_NAME = 'padded-cell'; +const DIST_DIR = join(__dirname, 'dist', PLUGIN_NAME); // Parse arguments const args = process.argv.slice(2); @@ -79,19 +80,6 @@ function exec(command, options = {}) { return execSync(command, { ...defaultOptions, ...options }); } -async function prompt(question) { - const rl = readline.createInterface({ - input: process.stdin, - output: process.stdout, - }); - return new Promise((resolve) => { - rl.question(question, (answer) => { - rl.close(); - resolve(answer.trim()); - }); - }); -} - // OpenClaw config helpers function getOpenclawConfig(pathKey, defaultValue = undefined) { try { @@ -107,7 +95,7 @@ function getOpenclawConfig(pathKey, defaultValue = undefined) { } function setOpenclawConfig(pathKey, value) { - execSync(`openclaw config set ${pathKey} --json '${JSON.stringify(value)}'`, { + execSync(`openclaw config set ${pathKey} '${JSON.stringify(value)}' --json`, { cwd: __dirname }); } @@ -120,6 +108,23 @@ function unsetOpenclawConfig(pathKey) { } } +// Copy directory recursively +function copyDir(src, dest) { + mkdirSync(dest, { recursive: true }); + const entries = readdirSync(src, { withFileTypes: true }); + + for (const entry of entries) { + const srcPath = join(src, entry.name); + const destPath = join(dest, entry.name); + + if (entry.isDirectory()) { + copyDir(srcPath, destPath); + } else { + copyFileSync(srcPath, destPath); + } + } +} + // ============================================================================ // Step 1: Environment Detection // ============================================================================ @@ -129,28 +134,23 @@ function detectEnvironment() { const env = { platform: platform(), - isLinux: platform() === 'linux', - isMacOS: platform() === 'darwin', nodeVersion: null, goVersion: null, - openclawPath: null, - openclawDir: null, + openclawDir: join(homedir(), '.openclaw'), }; // Check Node.js try { - const version = exec('node --version', { silent: true }).trim(); - env.nodeVersion = version; - logSuccess(`Node.js ${version}`); + env.nodeVersion = exec('node --version', { silent: true }).trim(); + logSuccess(`Node.js ${env.nodeVersion}`); } catch { logError('Node.js not found'); } // Check Go try { - const version = exec('go version', { silent: true }).trim(); - env.goVersion = version; - logSuccess(`Go ${version}`); + env.goVersion = exec('go version', { silent: true }).trim(); + logSuccess(`Go ${env.goVersion}`); } catch { logError('Go not found'); } @@ -158,7 +158,6 @@ function detectEnvironment() { // Check openclaw try { const path = exec('which openclaw', { silent: true }).trim(); - env.openclawPath = path; logSuccess(`openclaw at ${path}`); // Try to find openclaw config dir @@ -166,7 +165,6 @@ function detectEnvironment() { const possibleDirs = [ join(home, '.openclaw'), join(home, '.config', 'openclaw'), - '/etc/openclaw', ]; for (const dir of possibleDirs) { @@ -176,14 +174,8 @@ function detectEnvironment() { break; } } - - if (!env.openclawDir) { - env.openclawDir = join(home, '.openclaw'); - logWarning(`openclaw config dir not found, will use: ${env.openclawDir}`); - } } catch { logWarning('openclaw CLI not found in PATH'); - env.openclawDir = join(homedir(), '.openclaw'); } return env; @@ -238,21 +230,13 @@ async function buildComponents(env) { log(' Building pass_mgr (Go)...', 'blue'); try { const passMgrDir = join(__dirname, 'pass_mgr'); - if (!existsSync(passMgrDir)) { - throw new Error('pass_mgr directory not found'); - } - exec('go mod tidy', { cwd: passMgrDir, silent: !options.verbose }); - exec('go build -o dist/pass_mgr src/main.go', { - cwd: passMgrDir, - silent: !options.verbose - }); + exec('go build -o dist/pass_mgr src/main.go', { cwd: passMgrDir, silent: !options.verbose }); const binaryPath = join(passMgrDir, 'dist', 'pass_mgr'); if (!existsSync(binaryPath)) { throw new Error('pass_mgr binary not found after build'); } - chmodSync(binaryPath, 0o755); logSuccess('pass_mgr built successfully'); } catch (err) { @@ -264,13 +248,8 @@ async function buildComponents(env) { log(' Building pcexec (TypeScript)...', 'blue'); try { const pcexecDir = join(__dirname, 'pcexec'); - if (!existsSync(pcexecDir)) { - throw new Error('pcexec directory not found'); - } - exec('npm install', { cwd: pcexecDir, silent: !options.verbose }); exec('npm run build', { cwd: pcexecDir, silent: !options.verbose }); - logSuccess('pcexec built successfully'); } catch (err) { logError(`Failed to build pcexec: ${err.message}`); @@ -281,13 +260,8 @@ async function buildComponents(env) { log(' Building safe-restart (TypeScript)...', 'blue'); try { const safeRestartDir = join(__dirname, 'safe-restart'); - if (!existsSync(safeRestartDir)) { - throw new Error('safe-restart directory not found'); - } - exec('npm install', { cwd: safeRestartDir, silent: !options.verbose }); exec('npm run build', { cwd: safeRestartDir, silent: !options.verbose }); - logSuccess('safe-restart built successfully'); } catch (err) { logError(`Failed to build safe-restart: ${err.message}`); @@ -312,73 +286,46 @@ async function installComponents(env) { log(` Install directory: ${installDir}`, 'blue'); log(` Binary directory: ${binDir}`, 'blue'); - log(` Plugin directory: ${__dirname}`, 'blue'); + log(` Dist directory: ${DIST_DIR}`, 'blue'); - // Create bin directory - mkdirSync(binDir, { recursive: true }); + // Create dist/padded-cell directory and copy plugin files + log(' Copying plugin files to dist/padded-cell...', 'blue'); + mkdirSync(DIST_DIR, { recursive: true }); - // Create openclaw.plugin.json if not exists - const manifestPath = join(__dirname, 'openclaw.plugin.json'); - if (!existsSync(manifestPath)) { - const manifest = { - id: PLUGIN_NAME, - name: 'PaddedCell', - version: '0.1.0', - description: 'Secure password management, safe execution, and coordinated restart', - entry: './index.js', - configSchema: { - type: 'object', - properties: { - enabled: { type: 'boolean', default: true } - } + // Copy pcexec + copyDir(join(__dirname, 'pcexec'), join(DIST_DIR, 'pcexec')); + logSuccess('Copied pcexec to dist/padded-cell/'); + + // Copy safe-restart + copyDir(join(__dirname, 'safe-restart'), join(DIST_DIR, 'safe-restart')); + logSuccess('Copied safe-restart to dist/padded-cell/'); + + // Create openclaw.plugin.json + const manifest = { + id: PLUGIN_NAME, + name: 'PaddedCell', + version: '0.1.0', + description: 'Secure password management, safe execution, and coordinated restart', + entry: './safe-restart/dist/index.js', + tools: [ + { + name: 'pcexec', + entry: './pcexec/dist/index.js', + description: 'Safe exec with password sanitization' }, - tools: [ - { - name: 'pcexec', - entry: './pcexec/dist/index.js', - description: 'Safe exec with password sanitization' - }, - { - name: 'safe_restart', - entry: './safe-restart/dist/index.js', - description: 'Safe coordinated restart' - } - ] - }; - writeFileSync(manifestPath, JSON.stringify(manifest, null, 2)); - logSuccess('Created openclaw.plugin.json'); - } + { + name: 'safe_restart', + entry: './safe-restart/dist/index.js', + description: 'Safe coordinated restart' + } + ] + }; + writeFileSync(join(DIST_DIR, 'openclaw.plugin.json'), JSON.stringify(manifest, null, 2)); + logSuccess('Created openclaw.plugin.json in dist/padded-cell/'); - // Create index.js if not exists - const indexPath = join(__dirname, 'index.js'); - if (!existsSync(indexPath)) { - const indexContent = `// PaddedCell Plugin Entry Point -export const id = '${PLUGIN_NAME}'; -export const name = 'PaddedCell'; -export const version = '0.1.0'; - -// Export tools (will be loaded by OpenClaw) -export { pcexec } from './pcexec/dist/index.js'; -export { - safeRestart, - createSafeRestartTool, - StatusManager, - createApiServer, - startApiServer -} from './safe-restart/dist/index.js'; - -// Default export -export default { - id, - name, - version, -}; -`; - writeFileSync(indexPath, indexContent); - logSuccess('Created index.js'); - } - - // Install pass_mgr binary + // Create bin directory and install pass_mgr binary + mkdirSync(binDir, { recursive: true }); + log(' Installing pass_mgr binary...', 'blue'); const passMgrSource = join(__dirname, 'pass_mgr', 'dist', 'pass_mgr'); const passMgrDest = join(binDir, 'pass_mgr'); @@ -415,7 +362,7 @@ async function configure(env) { log(` Run "${passMgrPath} admin init" manually after installation.`, 'cyan'); } - // Configure OpenClaw using openclaw config commands + // Configure OpenClaw log('\n Configuring OpenClaw plugin...', 'blue'); try { @@ -430,33 +377,24 @@ async function configure(env) { } // 2. Add plugin entry - const existingEntry = getOpenclawConfig(`plugins.entries.${PLUGIN_NAME}`); - const pluginEntry = { + const plugins = getOpenclawConfig('plugins', {}); + plugins.entries = plugins.entries || {}; + plugins.entries[PLUGIN_NAME] = { enabled: true, config: { enabled: true, passMgrPath: passMgrPath, - pluginDir: __dirname, }, }; - - const plugins = getOpenclawConfig('plugins', {}); - plugins.entries = plugins.entries || {}; - plugins.entries[PLUGIN_NAME] = pluginEntry; setOpenclawConfig('plugins', plugins); - - if (existingEntry) { - logSuccess(`Updated ${PLUGIN_NAME} plugin entry`); - } else { - logSuccess(`Added ${PLUGIN_NAME} plugin entry`); - } + logSuccess(`Configured ${PLUGIN_NAME} plugin entry`); // 3. Add plugin path to plugins.load.paths const currentPaths = getOpenclawConfig('plugins.load.paths', []); - if (!currentPaths.includes(__dirname)) { - currentPaths.push(__dirname); + if (!currentPaths.includes(DIST_DIR)) { + currentPaths.push(DIST_DIR); setOpenclawConfig('plugins.load.paths', currentPaths); - logSuccess(`Added plugin path to plugins.load.paths`); + logSuccess(`Added ${DIST_DIR} to plugins.load.paths`); } else { log(' Plugin path already in plugins.load.paths', 'green'); } @@ -464,8 +402,7 @@ async function configure(env) { logWarning(`Failed to configure OpenClaw: ${err.message}`); log(' Please manually configure:', 'yellow'); log(` openclaw config set plugins.allow --json '[..., "${PLUGIN_NAME}"]'`, 'cyan'); - log(` openclaw config set plugins.entries.${PLUGIN_NAME}.enabled --json 'true'`, 'cyan'); - log(` openclaw config set plugins.load.paths --json '[..., "${__dirname}"]'`, 'cyan'); + log(` openclaw config set plugins.load.paths --json '[..., "${DIST_DIR}"]'`, 'cyan'); } } @@ -492,7 +429,7 @@ function printSummary(env, passMgrPath) { } else { log('Installed components:', 'blue'); log(` • pass_mgr binary: ${passMgrPath}`, 'reset'); - log(` • Plugin location: ${__dirname}`, 'reset'); + log(` • Plugin files: ${DIST_DIR}`, 'reset'); console.log(''); log('Next steps:', 'blue'); @@ -509,9 +446,6 @@ function printSummary(env, passMgrPath) { } console.log(''); - log('For more information:', 'blue'); - log(' • Documentation: https://git.hangman-lab.top/nav/PaddedCell', 'cyan'); - console.log(''); } // ============================================================================ @@ -534,6 +468,16 @@ async function uninstall(env) { } } + // Remove dist/padded-cell directory + if (existsSync(DIST_DIR)) { + try { + execSync(`rm -rf "${DIST_DIR}"`, { silent: true }); + logSuccess(`Removed ${DIST_DIR}`); + } catch (err) { + logError(`Failed to remove ${DIST_DIR}`); + } + } + // Remove OpenClaw configuration log('\n Removing OpenClaw configuration...', 'blue'); @@ -553,7 +497,7 @@ async function uninstall(env) { // Remove from plugins.load.paths const currentPaths = getOpenclawConfig('plugins.load.paths', []); - const pathIdx = currentPaths.indexOf(__dirname); + const pathIdx = currentPaths.indexOf(DIST_DIR); if (pathIdx !== -1) { currentPaths.splice(pathIdx, 1); setOpenclawConfig('plugins.load.paths', currentPaths); @@ -613,9 +557,6 @@ async function main() { log('╚════════════════════════════════════════════════════════╝', 'red'); console.log(''); log(`Error: ${err.message}`, 'red'); - if (options.verbose) { - console.log(err.stack); - } process.exit(1); } } diff --git a/openclaw.plugin.json b/openclaw.plugin.json index b7047d4..162f222 100644 --- a/openclaw.plugin.json +++ b/openclaw.plugin.json @@ -1,15 +1,9 @@ { - "id": "PaddedCell", + "id": "padded-cell", "name": "PaddedCell", "version": "0.1.0", "description": "Secure password management, safe execution, and coordinated restart", - "entry": "./index.js", - "configSchema": { - "type": "object", - "properties": { - "enabled": { "type": "boolean", "default": true } - } - }, + "entry": "./safe-restart/dist/index.js", "tools": [ { "name": "pcexec", From 232b772a6ba8c51f0cf9adac2dea49b19825f3d7 Mon Sep 17 00:00:00 2001 From: zhi Date: Thu, 5 Mar 2026 12:37:29 +0000 Subject: [PATCH 23/28] fix: correct openclaw config set command syntax - Move --json flag to correct position (before value) - Add explicit encoding and error handling --- install.mjs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/install.mjs b/install.mjs index 0a7a6fd..1282356 100755 --- a/install.mjs +++ b/install.mjs @@ -95,14 +95,13 @@ function getOpenclawConfig(pathKey, defaultValue = undefined) { } function setOpenclawConfig(pathKey, value) { - execSync(`openclaw config set ${pathKey} '${JSON.stringify(value)}' --json`, { - cwd: __dirname - }); + const cmd = `openclaw config set ${pathKey} --json '${JSON.stringify(value)}'`; + execSync(cmd, { cwd: __dirname, encoding: 'utf8' }); } function unsetOpenclawConfig(pathKey) { try { - execSync(`openclaw config unset ${pathKey}`, { cwd: __dirname }); + execSync(`openclaw config unset ${pathKey}`, { cwd: __dirname, encoding: 'utf8' }); } catch { // Ignore errors } From 6454004d662975c0d3063cb2b1b31622b8d2f5d4 Mon Sep 17 00:00:00 2001 From: zhi Date: Thu, 5 Mar 2026 12:44:39 +0000 Subject: [PATCH 24/28] fix: correct OpenClaw config order - load.paths before allow - OpenClaw validates plugin exists in load.paths before allowing it in allow list - Reorder: 1) load.paths, 2) allow, 3) entries --- install.mjs | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/install.mjs b/install.mjs index 1282356..cecf888 100755 --- a/install.mjs +++ b/install.mjs @@ -95,7 +95,7 @@ function getOpenclawConfig(pathKey, defaultValue = undefined) { } function setOpenclawConfig(pathKey, value) { - const cmd = `openclaw config set ${pathKey} --json '${JSON.stringify(value)}'`; + const cmd = `openclaw config set ${pathKey} '${JSON.stringify(value)}' --json`; execSync(cmd, { cwd: __dirname, encoding: 'utf8' }); } @@ -365,7 +365,25 @@ async function configure(env) { log('\n Configuring OpenClaw plugin...', 'blue'); try { - // 1. Add to plugins.allow + // 1. Add plugin path to plugins.load.paths FIRST (required for validation) + const currentPaths = getOpenclawConfig('plugins.load.paths', []); + log(` Current paths: ${JSON.stringify(currentPaths)}`, 'blue'); + log(` DIST_DIR: ${DIST_DIR}`, 'blue'); + if (!currentPaths.includes(DIST_DIR)) { + currentPaths.push(DIST_DIR); + log(` Adding plugin path...`, 'blue'); + try { + setOpenclawConfig('plugins.load.paths', currentPaths); + logSuccess(`Added ${DIST_DIR} to plugins.load.paths`); + } catch (err) { + logError(`Failed to set paths: ${err.message}`); + throw err; + } + } else { + log(' Plugin path already in plugins.load.paths', 'green'); + } + + // 2. Add to plugins.allow (after path is set) const allowList = getOpenclawConfig('plugins.allow', []); if (!allowList.includes(PLUGIN_NAME)) { allowList.push(PLUGIN_NAME); @@ -375,7 +393,7 @@ async function configure(env) { log(' Already in plugins.allow', 'green'); } - // 2. Add plugin entry + // 3. Add plugin entry const plugins = getOpenclawConfig('plugins', {}); plugins.entries = plugins.entries || {}; plugins.entries[PLUGIN_NAME] = { @@ -387,16 +405,6 @@ async function configure(env) { }; setOpenclawConfig('plugins', plugins); logSuccess(`Configured ${PLUGIN_NAME} plugin entry`); - - // 3. Add plugin path to plugins.load.paths - const currentPaths = getOpenclawConfig('plugins.load.paths', []); - if (!currentPaths.includes(DIST_DIR)) { - currentPaths.push(DIST_DIR); - setOpenclawConfig('plugins.load.paths', currentPaths); - logSuccess(`Added ${DIST_DIR} to plugins.load.paths`); - } else { - log(' Plugin path already in plugins.load.paths', 'green'); - } } catch (err) { logWarning(`Failed to configure OpenClaw: ${err.message}`); log(' Please manually configure:', 'yellow'); From e97ce0208e16b957f36fd20a8daef9045386652d Mon Sep 17 00:00:00 2001 From: zhi Date: Thu, 5 Mar 2026 14:49:03 +0000 Subject: [PATCH 25/28] fix: add configSchema and root index.js to plugin manifest - OpenClaw requires configSchema in plugin manifest - Add root index.js as entry point (like Dirigent) - Update install script to generate correct manifest --- install.mjs | 34 ++++++++++++++++++++++++++++++++-- openclaw.plugin.json | 8 +++++++- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/install.mjs b/install.mjs index cecf888..42b63c3 100755 --- a/install.mjs +++ b/install.mjs @@ -299,13 +299,43 @@ async function installComponents(env) { copyDir(join(__dirname, 'safe-restart'), join(DIST_DIR, 'safe-restart')); logSuccess('Copied safe-restart to dist/padded-cell/'); + // Create root index.js entry point + const indexJs = `const { pcexec } = require('./pcexec/dist/index.js'); +const { + safeRestart, + createSafeRestartTool, + StatusManager, + createApiServer, + startApiServer, + SlashCommandHandler +} = require('./safe-restart/dist/index.js'); + +module.exports = { + pcexec, + safeRestart, + createSafeRestartTool, + StatusManager, + createApiServer, + startApiServer, + SlashCommandHandler, +}; +`; + writeFileSync(join(DIST_DIR, 'index.js'), indexJs); + logSuccess('Created index.js entry point'); + // Create openclaw.plugin.json const manifest = { id: PLUGIN_NAME, name: 'PaddedCell', version: '0.1.0', description: 'Secure password management, safe execution, and coordinated restart', - entry: './safe-restart/dist/index.js', + entry: './index.js', + configSchema: { + type: 'object', + properties: { + enabled: { type: 'boolean', default: true } + } + }, tools: [ { name: 'pcexec', @@ -320,7 +350,7 @@ async function installComponents(env) { ] }; writeFileSync(join(DIST_DIR, 'openclaw.plugin.json'), JSON.stringify(manifest, null, 2)); - logSuccess('Created openclaw.plugin.json in dist/padded-cell/'); + logSuccess('Created openclaw.plugin.json'); // Create bin directory and install pass_mgr binary mkdirSync(binDir, { recursive: true }); diff --git a/openclaw.plugin.json b/openclaw.plugin.json index 162f222..908bc6f 100644 --- a/openclaw.plugin.json +++ b/openclaw.plugin.json @@ -3,7 +3,13 @@ "name": "PaddedCell", "version": "0.1.0", "description": "Secure password management, safe execution, and coordinated restart", - "entry": "./safe-restart/dist/index.js", + "entry": "./index.js", + "configSchema": { + "type": "object", + "properties": { + "enabled": { "type": "boolean", "default": true } + } + }, "tools": [ { "name": "pcexec", From 858538aaad7037130f8fbf3bacaf8555c09ef72f Mon Sep 17 00:00:00 2001 From: zhi Date: Thu, 5 Mar 2026 14:51:37 +0000 Subject: [PATCH 26/28] fix: add source index.js, install script copies from source - Add index.js to project root as source - Add configSchema to openclaw.plugin.json - Install script now copies these files from source to dist/ - Ensures dist/ is reproducible from source --- index.js | 28 ++++++++++++-------------- install.mjs | 57 ++++++----------------------------------------------- 2 files changed, 19 insertions(+), 66 deletions(-) diff --git a/index.js b/index.js index 9fa470b..e5d4e86 100644 --- a/index.js +++ b/index.js @@ -1,21 +1,19 @@ -// PaddedCell Plugin Entry Point -export const id = 'padded-cell'; -export const name = 'PaddedCell'; -export const version = '0.1.0'; - -// Export tools (will be loaded by OpenClaw) -export { pcexec } from './pcexec/dist/index.js'; -export { +const { pcexec } = require('./pcexec/dist/index.js'); +const { safeRestart, createSafeRestartTool, StatusManager, createApiServer, - startApiServer -} from './safe-restart/dist/index.js'; + startApiServer, + SlashCommandHandler +} = require('./safe-restart/dist/index.js'); -// Default export -export default { - id, - name, - version, +module.exports = { + pcexec, + safeRestart, + createSafeRestartTool, + StatusManager, + createApiServer, + startApiServer, + SlashCommandHandler, }; diff --git a/install.mjs b/install.mjs index 42b63c3..cef4a01 100755 --- a/install.mjs +++ b/install.mjs @@ -299,58 +299,13 @@ async function installComponents(env) { copyDir(join(__dirname, 'safe-restart'), join(DIST_DIR, 'safe-restart')); logSuccess('Copied safe-restart to dist/padded-cell/'); - // Create root index.js entry point - const indexJs = `const { pcexec } = require('./pcexec/dist/index.js'); -const { - safeRestart, - createSafeRestartTool, - StatusManager, - createApiServer, - startApiServer, - SlashCommandHandler -} = require('./safe-restart/dist/index.js'); + // Create root index.js entry point (copy from source) + copyFileSync(join(__dirname, 'index.js'), join(DIST_DIR, 'index.js')); + logSuccess('Copied index.js entry point'); -module.exports = { - pcexec, - safeRestart, - createSafeRestartTool, - StatusManager, - createApiServer, - startApiServer, - SlashCommandHandler, -}; -`; - writeFileSync(join(DIST_DIR, 'index.js'), indexJs); - logSuccess('Created index.js entry point'); - - // Create openclaw.plugin.json - const manifest = { - id: PLUGIN_NAME, - name: 'PaddedCell', - version: '0.1.0', - description: 'Secure password management, safe execution, and coordinated restart', - entry: './index.js', - configSchema: { - type: 'object', - properties: { - enabled: { type: 'boolean', default: true } - } - }, - tools: [ - { - name: 'pcexec', - entry: './pcexec/dist/index.js', - description: 'Safe exec with password sanitization' - }, - { - name: 'safe_restart', - entry: './safe-restart/dist/index.js', - description: 'Safe coordinated restart' - } - ] - }; - writeFileSync(join(DIST_DIR, 'openclaw.plugin.json'), JSON.stringify(manifest, null, 2)); - logSuccess('Created openclaw.plugin.json'); + // Copy openclaw.plugin.json from source + copyFileSync(join(__dirname, 'openclaw.plugin.json'), join(DIST_DIR, 'openclaw.plugin.json')); + logSuccess('Copied openclaw.plugin.json'); // Create bin directory and install pass_mgr binary mkdirSync(binDir, { recursive: true }); From 27a94d1da713684c1e9763e68c03f67b48ba26a2 Mon Sep 17 00:00:00 2001 From: zhi Date: Thu, 5 Mar 2026 18:57:58 +0000 Subject: [PATCH 27/28] fix: use OpenClaw plugin SDK format with api.registerTool() - Change index.js to export init() function that receives api - Use api.registerTool() to dynamically register tools - Remove tools array from manifest (not needed for dynamic registration) - Add passMgrPath to configSchema --- index.js | 77 ++++++++++++++++++++++++++++++++++++++------ openclaw.plugin.json | 17 ++-------- 2 files changed, 70 insertions(+), 24 deletions(-) diff --git a/index.js b/index.js index e5d4e86..f264981 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,7 @@ -const { pcexec } = require('./pcexec/dist/index.js'); +// PaddedCell Plugin for OpenClaw +// Registers pcexec and safe_restart tools + +const { pcexec, pcexecSync } = require('./pcexec/dist/index.js'); const { safeRestart, createSafeRestartTool, @@ -8,12 +11,66 @@ const { SlashCommandHandler } = require('./safe-restart/dist/index.js'); -module.exports = { - pcexec, - safeRestart, - createSafeRestartTool, - StatusManager, - createApiServer, - startApiServer, - SlashCommandHandler, -}; +// Plugin initialization function +function init(api, config) { + const logger = api.logger || { info: console.log, error: console.error }; + + logger.info('PaddedCell plugin initializing...'); + + // Register pcexec tool + api.registerTool({ + name: 'pcexec', + description: 'Safe exec with password sanitization', + parameters: { + type: 'object', + properties: { + command: { type: 'string', description: 'Command to execute' }, + cwd: { type: 'string', description: 'Working directory' }, + timeout: { type: 'number', description: 'Timeout in milliseconds' }, + }, + required: ['command'], + }, + async handler(params) { + return await pcexec(params.command, { + cwd: params.cwd, + timeout: params.timeout, + }); + }, + }); + + // Register safe_restart tool + api.registerTool({ + name: 'safe_restart', + description: 'Safe coordinated restart of OpenClaw gateway', + parameters: { + type: 'object', + properties: { + rollback: { type: 'string', description: 'Rollback script path' }, + log: { type: 'string', description: 'Log file path' }, + }, + }, + async handler(params, context) { + return await safeRestart({ + agentId: context.agentId, + sessionKey: context.sessionKey, + rollback: params.rollback, + log: params.log, + }); + }, + }); + + logger.info('PaddedCell plugin initialized'); +} + +// Export for OpenClaw +module.exports = { init }; + +// Also export individual modules for direct use +module.exports.pcexec = pcexec; +module.exports.pcexecSync = pcexecSync; +module.exports.safeRestart = safeRestart; +module.exports.createSafeRestartTool = createSafeRestartTool; +module.exports.StatusManager = StatusManager; +module.exports.createApiServer = createApiServer; +module.exports.startApiServer = startApiServer; +module.exports.SlashCommandHandler = SlashCommandHandler; diff --git a/openclaw.plugin.json b/openclaw.plugin.json index 908bc6f..55875e6 100644 --- a/openclaw.plugin.json +++ b/openclaw.plugin.json @@ -7,19 +7,8 @@ "configSchema": { "type": "object", "properties": { - "enabled": { "type": "boolean", "default": true } + "enabled": { "type": "boolean", "default": true }, + "passMgrPath": { "type": "string", "default": "/root/.openclaw/bin/pass_mgr" } } - }, - "tools": [ - { - "name": "pcexec", - "entry": "./pcexec/dist/index.js", - "description": "Safe exec with password sanitization" - }, - { - "name": "safe_restart", - "entry": "./safe-restart/dist/index.js", - "description": "Safe coordinated restart" - } - ] + } } From c2fb28301c61dd378af8dd00e7d6776f80894bef Mon Sep 17 00:00:00 2001 From: zhi Date: Thu, 5 Mar 2026 19:02:53 +0000 Subject: [PATCH 28/28] fix: rename init() to register() for OpenClaw plugin API OpenClaw expects 'register' or 'activate' export, not 'init' --- index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index f264981..f96f1a4 100644 --- a/index.js +++ b/index.js @@ -11,8 +11,8 @@ const { SlashCommandHandler } = require('./safe-restart/dist/index.js'); -// Plugin initialization function -function init(api, config) { +// Plugin registration function (OpenClaw expects 'register' or 'activate') +function register(api, config) { const logger = api.logger || { info: console.log, error: console.error }; logger.info('PaddedCell plugin initializing...'); @@ -63,7 +63,7 @@ function init(api, config) { } // Export for OpenClaw -module.exports = { init }; +module.exports = { register }; // Also export individual modules for direct use module.exports.pcexec = pcexec;