From 32c1578608ad3bab9d5fc00b2e9fce0df6d35613 Mon Sep 17 00:00:00 2001 From: Cleber Hensel Date: Thu, 23 Oct 2025 23:37:28 -0300 Subject: [PATCH] feat(cli): introduce stash system for conflict management and backups - Added a comprehensive stash system inspired by Git, allowing users to manage file conflicts during installations and updates. - Implemented new CLI commands for stashing, including `stash list`, `stash show`, `stash apply`, `stash pop`, `stash remove`, `stash diff`, `stash save`, and `stash clear`. - Enhanced install and update commands with automatic conflict detection and interactive resolution options. - Introduced `HashCalculator`, `StashLogger`, `StashManager`, `ConflictDetector`, and `ConflictResolver` for managing stashes and conflicts. - Updated dependencies: `inquirer@^9.2.0`, `diff@^5.1.0`, `@types/inquirer@^9.0.0`, `@types/diff@^5.0.0`. - Version bumped to 1.0.0 to reflect major changes. --- apps/cli/CHANGELOG.md | 48 ++++ apps/cli/STASH-SYSTEM.md | 232 +++++++++++++++ apps/cli/package.json | 2 +- apps/cli/src/adapters/copilot-adapter.ts | 2 +- apps/cli/src/commands/stash.ts | 91 +++++- .../stash/__tests__/hash-calculator.test.ts | 135 +++++++++ apps/cli/src/stash/__tests__/logger.test.ts | 118 ++++++++ apps/cli/src/stash/conflict-resolver.ts | 110 ++++++- pnpm-lock.yaml | 272 ++++++++++++++++++ 9 files changed, 1000 insertions(+), 10 deletions(-) create mode 100644 apps/cli/STASH-SYSTEM.md create mode 100644 apps/cli/src/stash/__tests__/hash-calculator.test.ts create mode 100644 apps/cli/src/stash/__tests__/logger.test.ts diff --git a/apps/cli/CHANGELOG.md b/apps/cli/CHANGELOG.md index c930686..60bf6eb 100644 --- a/apps/cli/CHANGELOG.md +++ b/apps/cli/CHANGELOG.md @@ -1,5 +1,53 @@ # Changelog +## 1.0.0 - 2025-10-23 + +### 🎉 Major Release: Stash System + +Git-inspired stash system for complete conflict management and backups. + +#### Added + +**Stash System Core**: +- HashCalculator with SHA-256 for file integrity +- StashLogger with JSONL logging +- StashManager for complete lifecycle +- ConflictDetector for automatic detection +- ConflictResolver with interactive prompts + +**CLI Commands** (8 new commands): +- `vdt stash list` - List all stashes +- `vdt stash show ` - Show details +- `vdt stash apply ` - Apply (keep) +- `vdt stash pop ` - Apply and remove +- `vdt stash remove ` - Remove stash +- `vdt stash diff ` - Show differences +- `vdt stash save [files]` - Manual stash +- `vdt stash clear` - Clear all + +**Update Command**: +- `vdt update --version ` +- `vdt update --latest` +- `vdt update --dry-run` + +**Install Enhancements**: +- Automatic conflict detection +- Interactive resolution (overwrite/stash/cancel) +- `--dry-run` flag for preview +- Stash metadata with versions + +#### Changed + +- Install now uses `force: true` after conflicts resolved +- Install shows stash info on success + +#### Dependencies + +- Added `inquirer@^9.2.0` +- Added `diff@^5.1.0` +- Added `@types/inquirer@^9.0.0` +- Added `@types/diff@^5.0.0` + ## 0.7.1 ### Patch Changes diff --git a/apps/cli/STASH-SYSTEM.md b/apps/cli/STASH-SYSTEM.md new file mode 100644 index 0000000..52698b6 --- /dev/null +++ b/apps/cli/STASH-SYSTEM.md @@ -0,0 +1,232 @@ +# Stash System + +Sistema de gestão de conflitos e backups para vibe-devtools, inspirado no `git stash`. + +## Overview + +O Stash System permite que você gerencie arquivos durante instalação/atualização de packages com controle total sobre o que sobrescrever, manter ou arquivar. + +### Features + +- ✅ Detecção automática de conflitos via SHA-256 hash +- ✅ Backup seguro com full copy (não patch) +- ✅ Comandos CLI familiares (inspirados no git stash) +- ✅ FILO ordering com renumeração automática +- ✅ Logging completo em JSONL +- ✅ Dry-run support +- ✅ Integration com install e update commands + +## Quick Start + +### Install com Detecção de Conflitos + +```bash +npx vibe-devtools install @vibe-devtools/basic +``` + +Se houver conflitos, você verá: + +``` +⚠️ Conflicts detected (3 files) + + 1. vibes/configs/constitution.md + Local: abc123... + Package: def456... + +How to resolve conflicts? + [1] Overwrite with package version + [2] Stash local and install package + [3] Cancel installation +``` + +Escolha opção 2 para criar backup automático. + +### Update com Stash + +```bash +npx vibe-devtools update @vibe-devtools/basic --latest +npx vibe-devtools update @vibe-devtools/basic --version 1.0.3 +npx vibe-devtools update @vibe-devtools/basic --dry-run +``` + +### Dry Run + +Preview mudanças sem instalar: + +```bash +npx vibe-devtools install @vibe-devtools/basic --dry-run +``` + +## Comandos Stash + +### List + +Lista todos os stashes: + +```bash +npx vibe-devtools stash list +``` + +Output: +``` +stash{0} - @vibe-devtools/basic + install • 2025-10-23 14:30 • 3 files + +stash{1} - manual + manual • 2025-10-23 15:45 • 2 files + +Total: 2 stashes +``` + +### Show + +Mostra detalhes de um stash: + +```bash +npx vibe-devtools stash show 0 +``` + +### Apply + +Aplica stash (mantém no histórico): + +```bash +npx vibe-devtools stash apply 0 +``` + +### Pop + +Aplica stash e remove do histórico: + +```bash +npx vibe-devtools stash pop 0 +``` + +### Remove + +Remove um stash: + +```bash +npx vibe-devtools stash remove 0 +``` + +### Diff + +Mostra diferenças entre stash e arquivos atuais: + +```bash +npx vibe-devtools stash diff 0 +npx vibe-devtools stash diff 0 --editor # abre no IDE +``` + +### Save + +Cria stash manual: + +```bash +npx vibe-devtools stash save file1.ts file2.ts +npx vibe-devtools stash save # prompt interativo +``` + +### Clear + +Remove todos os stashes: + +```bash +npx vibe-devtools stash clear +npx vibe-devtools stash clear --force # sem confirmação +``` + +## Architecture + +### Components + +- **HashCalculator**: SHA-256 hash calculation +- **StashLogger**: JSONL logging system +- **StashManager**: Core lifecycle management +- **ConflictDetector**: Hash-based conflict detection +- **ConflictResolver**: CLI prompts & diff display + +### Storage + +``` +~/.vibes/stash/ +├── index.json # Lista de stashes +├── stash-0/ +│ ├── metadata.json # Metadata do stash +│ └── files/ # Full copy dos arquivos +└── stash-1/ + ├── metadata.json + └── files/ +``` + +### Logging + +``` +~/.vibes/logs/stash.log +``` + +Format: JSONL (1 JSON per line) + +## Technical Details + +### Hash Algorithm + +SHA-256 via Node.js crypto (nativo) + +### Storage Strategy + +Full copy (não patch) para: +- Simplicidade e confiabilidade +- Suporte a qualquer tipo de arquivo +- Sempre funciona (não corrompe) + +### Ordering + +FILO (First In Last Out) com renumeração: +- `stash{0}` é sempre o mais recente +- Após `pop` ou `remove`, IDs são renumerados +- Igual ao `git stash` + +## Error Handling + +### Permission Denied + +Se erro de permissão em `~/.vibes/stash/`: + +```bash +sudo chown -R $USER ~/.vibes +``` + +### Stash Corrupted + +Sistema valida integridade via hash antes de aplicar. Se corrompido: + +```bash +npx vibe-devtools stash remove +``` + +### Disk Full + +Libere espaço ou: + +```bash +npx vibe-devtools stash clear +``` + +## Performance + +- Hash calculation: < 100ms (arquivos < 1MB) +- Stash creation: < 1s (< 100 arquivos) +- Stash apply: < 1s (< 100 arquivos) + +## Dependencies + +- `inquirer@^9.2.0` - CLI prompts +- `diff@^5.1.0` - Diff display + +## Compatibility + +- Node.js >= 18.0.0 +- Works on: macOS, Linux, Windows + diff --git a/apps/cli/package.json b/apps/cli/package.json index 41a4d1f..4501829 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -1,6 +1,6 @@ { "name": "vibe-devtools", - "version": "0.7.1", + "version": "1.0.0", "description": "CLI tool to install and manage vibes (agentic command packages)", "type": "module", "main": "dist/index.js", diff --git a/apps/cli/src/adapters/copilot-adapter.ts b/apps/cli/src/adapters/copilot-adapter.ts index 6d05dc3..0498a09 100644 --- a/apps/cli/src/adapters/copilot-adapter.ts +++ b/apps/cli/src/adapters/copilot-adapter.ts @@ -139,7 +139,7 @@ export class CopilotAdapter extends BaseAdapter { const promptPath = path.join(promptsDir, `${cmdName}.prompt.md`); let content = `# ${cmdName} Command Prompt\n\n`; - + if (frontmatter.description) { content += `**Description**: ${frontmatter.description}\n\n`; } diff --git a/apps/cli/src/commands/stash.ts b/apps/cli/src/commands/stash.ts index 46222b8..d4ec470 100644 --- a/apps/cli/src/commands/stash.ts +++ b/apps/cli/src/commands/stash.ts @@ -151,12 +151,95 @@ export async function stashDiffCommand(stashId: string, _options: { editor?: boo console.log(''); } -export async function stashSaveCommand(_files?: string[]): Promise { - throw new Error('Not implemented yet - will be implemented in TASK-039'); +export async function stashSaveCommand(files?: string[]): Promise { + let filesToStash: string[] = files || []; + + if (filesToStash.length === 0) { + const prompts = await import('prompts'); + const response = await prompts.default({ + type: 'text', + name: 'files', + message: 'Enter file paths to stash (comma-separated):', + validate: (value: string) => value.trim().length > 0 || 'Please enter at least one file' + }); + + if (!response.files) { + console.log(chalk.gray('Cancelled')); + return; + } + + filesToStash = response.files.split(',').map((f: string) => f.trim()); + } + + const existingFiles: string[] = []; + for (const file of filesToStash) { + const fs = await import('node:fs'); + if (fs.existsSync(file)) { + existingFiles.push(file); + } else { + console.log(chalk.yellow(`⚠️ File not found: ${file}`)); + } + } + + if (existingFiles.length === 0) { + console.log(chalk.red('No valid files to stash')); + return; + } + + const manager = new StashManager(); + const filesToStashMap = new Map( + existingFiles.map(f => [f, f]) + ); + + const stashId = await manager.create(filesToStashMap, { + reason: 'manual' + }); + + console.log(''); + console.log(chalk.green(`✓ Stash {${stashId}} created`)); + console.log(chalk.gray(` Files: ${existingFiles.length}`)); + console.log(''); + + for (const file of existingFiles) { + console.log(chalk.gray(' -'), file); + } + + console.log(''); } -export async function stashClearCommand(_options: { force?: boolean } = {}): Promise { - throw new Error('Not implemented yet - will be implemented in TASK-040'); +export async function stashClearCommand(options: { force?: boolean } = {}): Promise { + const manager = new StashManager(); + const stashes = await manager.list(); + + if (stashes.length === 0) { + console.log(chalk.gray('No stashes to clear')); + return; + } + + if (!options.force) { + console.log(''); + console.log(chalk.yellow(`⚠️ About to remove ${stashes.length} stashes`)); + console.log(''); + + const prompts = await import('prompts'); + const response = await prompts.default({ + type: 'text', + name: 'confirm', + message: 'Type "yes" to confirm:', + validate: (value: string) => value === 'yes' || 'Please type "yes" to confirm' + }); + + if (response.confirm !== 'yes') { + console.log(chalk.gray('Cancelled')); + return; + } + } + + await manager.clear(true); + + console.log(''); + console.log(chalk.green(`✓ ${stashes.length} stashes cleared`)); + console.log(''); } function formatSize(bytes: number): string { diff --git a/apps/cli/src/stash/__tests__/hash-calculator.test.ts b/apps/cli/src/stash/__tests__/hash-calculator.test.ts new file mode 100644 index 0000000..8446627 --- /dev/null +++ b/apps/cli/src/stash/__tests__/hash-calculator.test.ts @@ -0,0 +1,135 @@ +import { describe, it, expect, beforeEach, afterEach } from 'vitest'; +import { HashCalculator } from '../hash-calculator.js'; +import fs from 'node:fs/promises'; +import path from 'node:path'; +import os from 'node:os'; + +describe('HashCalculator', () => { + let hashCalculator: HashCalculator; + let tempDir: string; + + beforeEach(async () => { + hashCalculator = new HashCalculator(); + tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'hash-test-')); + }); + + afterEach(async () => { + await fs.rm(tempDir, { recursive: true, force: true }); + }); + + describe('calculateFile', () => { + it('should calculate hash for a file', async () => { + const testFile = path.join(tempDir, 'test.txt'); + await fs.writeFile(testFile, 'test content', 'utf-8'); + + const hash = await hashCalculator.calculateFile(testFile); + + expect(hash).toBeTruthy(); + expect(hash.length).toBe(64); + }); + + it('should throw error for non-existent file', async () => { + const testFile = path.join(tempDir, 'nonexistent.txt'); + + await expect(hashCalculator.calculateFile(testFile)).rejects.toThrow('File not found'); + }); + + it('should return same hash for same content', async () => { + const file1 = path.join(tempDir, 'file1.txt'); + const file2 = path.join(tempDir, 'file2.txt'); + const content = 'identical content'; + + await fs.writeFile(file1, content, 'utf-8'); + await fs.writeFile(file2, content, 'utf-8'); + + const hash1 = await hashCalculator.calculateFile(file1); + const hash2 = await hashCalculator.calculateFile(file2); + + expect(hash1).toBe(hash2); + }); + + it('should return different hash for different content', async () => { + const file1 = path.join(tempDir, 'file1.txt'); + const file2 = path.join(tempDir, 'file2.txt'); + + await fs.writeFile(file1, 'content A', 'utf-8'); + await fs.writeFile(file2, 'content B', 'utf-8'); + + const hash1 = await hashCalculator.calculateFile(file1); + const hash2 = await hashCalculator.calculateFile(file2); + + expect(hash1).not.toBe(hash2); + }); + }); + + describe('calculateDirectory', () => { + it('should calculate hashes for all files in directory', async () => { + await fs.writeFile(path.join(tempDir, 'file1.txt'), 'content 1', 'utf-8'); + await fs.writeFile(path.join(tempDir, 'file2.txt'), 'content 2', 'utf-8'); + + const hashes = await hashCalculator.calculateDirectory(tempDir); + + expect(hashes.size).toBe(2); + expect(hashes.has('file1.txt')).toBe(true); + expect(hashes.has('file2.txt')).toBe(true); + }); + + it('should handle nested directories', async () => { + const subDir = path.join(tempDir, 'subdir'); + await fs.mkdir(subDir); + await fs.writeFile(path.join(subDir, 'nested.txt'), 'nested', 'utf-8'); + await fs.writeFile(path.join(tempDir, 'root.txt'), 'root', 'utf-8'); + + const hashes = await hashCalculator.calculateDirectory(tempDir); + + expect(hashes.size).toBe(2); + expect(hashes.has('root.txt')).toBe(true); + expect(hashes.has('subdir/nested.txt')).toBe(true); + }); + + it('should throw error for non-existent directory', async () => { + await expect( + hashCalculator.calculateDirectory(path.join(tempDir, 'nonexistent')) + ).rejects.toThrow('Directory not found'); + }); + + it('should throw error if path is not a directory', async () => { + const testFile = path.join(tempDir, 'file.txt'); + await fs.writeFile(testFile, 'content', 'utf-8'); + + await expect( + hashCalculator.calculateDirectory(testFile) + ).rejects.toThrow('Path is not a directory'); + }); + }); + + describe('validate', () => { + it('should return true for matching hash', async () => { + const testFile = path.join(tempDir, 'test.txt'); + await fs.writeFile(testFile, 'content', 'utf-8'); + + const hash = await hashCalculator.calculateFile(testFile); + const isValid = await hashCalculator.validate(testFile, hash); + + expect(isValid).toBe(true); + }); + + it('should return false for non-matching hash', async () => { + const testFile = path.join(tempDir, 'test.txt'); + await fs.writeFile(testFile, 'content', 'utf-8'); + + const isValid = await hashCalculator.validate(testFile, 'wrong-hash'); + + expect(isValid).toBe(false); + }); + + it('should return false for non-existent file', async () => { + const testFile = path.join(tempDir, 'nonexistent.txt'); + + const isValid = await hashCalculator.validate(testFile, 'any-hash'); + + expect(isValid).toBe(false); + }); + }); +}); + diff --git a/apps/cli/src/stash/__tests__/logger.test.ts b/apps/cli/src/stash/__tests__/logger.test.ts new file mode 100644 index 0000000..613f419 --- /dev/null +++ b/apps/cli/src/stash/__tests__/logger.test.ts @@ -0,0 +1,118 @@ +import { describe, it, expect, beforeEach, afterEach } from 'vitest'; +import { StashLogger } from '../logger.js'; +import fs from 'node:fs/promises'; +import { existsSync } from 'node:fs'; +import path from 'node:path'; +import os from 'node:os'; + +describe('StashLogger', () => { + let logger: StashLogger; + let tempDir: string; + let logPath: string; + + beforeEach(async () => { + tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'logger-test-')); + logPath = path.join(tempDir, 'test.log'); + logger = new StashLogger(logPath); + }); + + afterEach(async () => { + await fs.rm(tempDir, { recursive: true, force: true }); + }); + + describe('log', () => { + it('should append log entry to file', async () => { + await logger.log({ + timestamp: new Date().toISOString(), + operation: 'create', + stash_id: 0, + files_count: 3, + success: true + }); + + expect(existsSync(logPath)).toBe(true); + const content = await fs.readFile(logPath, 'utf-8'); + expect(content).toContain('"operation":"create"'); + expect(content).toContain('"stash_id":0'); + }); + + it('should append multiple entries', async () => { + await logger.log({ + timestamp: new Date().toISOString(), + operation: 'create', + files_count: 1, + success: true + }); + + await logger.log({ + timestamp: new Date().toISOString(), + operation: 'apply', + stash_id: 0, + files_count: 1, + success: true + }); + + const content = await fs.readFile(logPath, 'utf-8'); + const lines = content.trim().split('\n'); + expect(lines.length).toBe(2); + }); + + it('should create log directory if not exists', async () => { + const deepPath = path.join(tempDir, 'deep', 'nested', 'test.log'); + const deepLogger = new StashLogger(deepPath); + + await deepLogger.log({ + timestamp: new Date().toISOString(), + operation: 'create', + files_count: 1, + success: true + }); + + expect(existsSync(deepPath)).toBe(true); + }); + }); + + describe('getLogs', () => { + it('should return empty array for non-existent log', async () => { + const logs = await logger.getLogs(); + expect(logs).toEqual([]); + }); + + it('should return all log entries', async () => { + await logger.log({ + timestamp: new Date().toISOString(), + operation: 'create', + files_count: 1, + success: true + }); + + await logger.log({ + timestamp: new Date().toISOString(), + operation: 'apply', + stash_id: 0, + files_count: 1, + success: true + }); + + const logs = await logger.getLogs(); + expect(logs.length).toBe(2); + expect(logs[0].operation).toBe('create'); + expect(logs[1].operation).toBe('apply'); + }); + + it('should limit results when specified', async () => { + for (let i = 0; i < 10; i++) { + await logger.log({ + timestamp: new Date().toISOString(), + operation: 'create', + files_count: 1, + success: true + }); + } + + const logs = await logger.getLogs(5); + expect(logs.length).toBe(5); + }); + }); +}); + diff --git a/apps/cli/src/stash/conflict-resolver.ts b/apps/cli/src/stash/conflict-resolver.ts index fa233da..7d67ab5 100644 --- a/apps/cli/src/stash/conflict-resolver.ts +++ b/apps/cli/src/stash/conflict-resolver.ts @@ -1,5 +1,8 @@ import prompts from 'prompts'; import chalk from 'chalk'; +import fs from 'node:fs/promises'; +import { spawn } from 'node:child_process'; +import { createTwoFilesPatch } from 'diff'; import type { Conflict } from './conflict-detector.js'; export type ConflictResolution = @@ -59,12 +62,111 @@ export class ConflictResolver { return response.resolution; } - async showDiff(_conflict: Conflict, _inline: boolean): Promise { - throw new Error('Not implemented yet - will be implemented in TASK-022'); + async showDiff(conflict: Conflict, inline: boolean): Promise { + const existingContent = await fs.readFile(conflict.destPath, 'utf-8'); + const incomingContent = await fs.readFile(conflict.sourcePath, 'utf-8'); + + const patch = createTwoFilesPatch( + conflict.destPath, + conflict.destPath, + existingContent, + incomingContent, + 'Local', + 'Package' + ); + + if (!inline) { + console.log(patch); + return; + } + + console.log(''); + console.log(chalk.bold(`Diff: ${conflict.destPath}`)); + console.log(''); + + const lines = patch.split('\n'); + for (const line of lines) { + if (line.startsWith('+') && !line.startsWith('+++')) { + console.log(chalk.green(line)); + } else if (line.startsWith('-') && !line.startsWith('---')) { + console.log(chalk.red(line)); + } else if (line.startsWith('@@')) { + console.log(chalk.cyan(line)); + } else { + console.log(chalk.gray(line)); + } + } + + console.log(''); } - async openInEditor(_conflict: Conflict): Promise { - throw new Error('Not implemented yet - will be implemented in TASK-023'); + async openInEditor(conflict: Conflict): Promise { + const editor = this.detectEditor(); + + if (!editor) { + console.log(chalk.yellow('⚠️ No editor detected')); + console.log(chalk.gray('Set EDITOR environment variable or install VSCode')); + return; + } + + const { command, args } = this.getEditorCommand(editor, conflict); + + return new Promise((resolve, reject) => { + const proc = spawn(command, args, { stdio: 'inherit' }); + + proc.on('exit', (code) => { + if (code === 0) { + resolve(); + } else { + reject(new Error(`Editor exited with code ${code}`)); + } + }); + + proc.on('error', (err) => { + reject(err); + }); + }); + } + + private detectEditor(): string | null { + if (process.env.EDITOR) { + return process.env.EDITOR; + } + + const editors = ['code', 'subl', 'vim', 'nano']; + + for (const editor of editors) { + try { + const { execSync } = require('node:child_process'); + execSync(`which ${editor}`, { stdio: 'ignore' }); + return editor; + } catch { + continue; + } + } + + return null; + } + + private getEditorCommand(editor: string, conflict: Conflict): { command: string; args: string[] } { + if (editor === 'code' || editor.endsWith('code')) { + return { + command: 'code', + args: ['--diff', conflict.destPath, conflict.sourcePath] + }; + } + + if (editor === 'subl' || editor.endsWith('sublime_text')) { + return { + command: 'subl', + args: [conflict.destPath, conflict.sourcePath] + }; + } + + return { + command: editor, + args: [conflict.destPath] + }; } private formatSize(bytes: number): string { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 98d86d9..fb78ddd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -35,6 +35,12 @@ importers: commander: specifier: ^12.0.0 version: 12.1.0 + diff: + specifier: ^5.1.0 + version: 5.2.0 + inquirer: + specifier: ^9.2.0 + version: 9.3.8(@types/node@20.19.23) ora: specifier: ^8.0.1 version: 8.2.0 @@ -42,6 +48,12 @@ importers: specifier: ^2.4.2 version: 2.4.2 devDependencies: + '@types/diff': + specifier: ^5.0.0 + version: 5.2.3 + '@types/inquirer': + specifier: ^9.0.0 + version: 9.0.9 '@types/node': specifier: ^20.0.0 version: 20.19.23 @@ -311,6 +323,10 @@ packages: '@types/node': optional: true + '@inquirer/figures@1.0.14': + resolution: {integrity: sha512-DbFgdt+9/OZYFM+19dbpXOSeAstPy884FPy1KjDu4anWwymZeOYhMY1mdFri172htv6mvc/uvIAAi7b7tvjJBQ==} + engines: {node: '>=18'} + '@jest/schemas@29.6.3': resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -449,9 +465,15 @@ packages: '@sinclair/typebox@0.27.8': resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + '@types/diff@5.2.3': + resolution: {integrity: sha512-K0Oqlrq3kQMaO2RhfrNQX5trmt+XLyom88zS0u84nnIcLvFnRUMRRHmrGny5GSM+kNO9IZLARsdQHDzkhAgmrQ==} + '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/inquirer@9.0.9': + resolution: {integrity: sha512-/mWx5136gts2Z2e5izdoRCo46lPp5TMs9R15GTSsgg/XnZyxDWVqoVU3R9lWnccKpqwsJLvRoxbCjoJtZB7DSw==} + '@types/node@12.20.55': resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} @@ -461,6 +483,9 @@ packages: '@types/prompts@2.4.9': resolution: {integrity: sha512-qTxFi6Buiu8+50/+3DGIWLHM6QuWsEKugJnnP6iv2Mc4ncxE4A/OJkjuVOA+5X0X1S/nq5VJRa8Lu+nwcvbrKA==} + '@types/through@0.0.33': + resolution: {integrity: sha512-HsJ+z3QuETzP3cswwtzt2vEIiHBk/dCcHGhbmG5X3ecnwFD/lPrMpliGXxSCg03L9AhrdwA4Oz/qfspkDW+xGQ==} + '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} @@ -500,6 +525,10 @@ packages: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} + ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -532,10 +561,16 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + better-path-resolve@1.0.0: resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} engines: {node: '>=4'} + bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + brace-expansion@1.1.12: resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} @@ -543,6 +578,9 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} @@ -573,6 +611,10 @@ packages: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} + cli-cursor@3.1.0: + resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} + engines: {node: '>=8'} + cli-cursor@5.0.0: resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} engines: {node: '>=18'} @@ -585,6 +627,14 @@ packages: resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} engines: {node: 10.* || >= 12.*} + cli-width@4.1.0: + resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} + engines: {node: '>= 12'} + + clone@1.0.4: + resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} + engines: {node: '>=0.8'} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -625,6 +675,9 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + defaults@1.0.4: + resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} + detect-indent@6.1.0: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} @@ -633,6 +686,10 @@ packages: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + diff@5.2.0: + resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} + engines: {node: '>=0.3.1'} + dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -821,6 +878,9 @@ packages: resolution: {integrity: sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==} engines: {node: '>=0.10.0'} + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -840,6 +900,10 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + inquirer@9.3.8: + resolution: {integrity: sha512-pFGGdaHrmRKMh4WoDDSowddgjT1Vkl90atobmTeSmcPGdYiwikch/m/Ef5wRaiamHejtw0cUUMMerzDUXCci2w==} + engines: {node: '>=18'} + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -852,6 +916,10 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + is-interactive@1.0.0: + resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} + engines: {node: '>=8'} + is-interactive@2.0.0: resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==} engines: {node: '>=12'} @@ -872,6 +940,10 @@ packages: resolution: {integrity: sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==} engines: {node: '>=4'} + is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + is-unicode-supported@1.3.0: resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} engines: {node: '>=12'} @@ -939,6 +1011,10 @@ packages: lodash.startcase@4.4.0: resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} + log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + log-symbols@6.0.0: resolution: {integrity: sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==} engines: {node: '>=18'} @@ -960,6 +1036,10 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + mimic-fn@4.0.0: resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} engines: {node: '>=12'} @@ -981,6 +1061,10 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + mute-stream@1.0.0: + resolution: {integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -1005,6 +1089,10 @@ packages: once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + onetime@6.0.0: resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} engines: {node: '>=12'} @@ -1017,6 +1105,10 @@ packages: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} + ora@5.4.1: + resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} + engines: {node: '>=10'} + ora@8.2.0: resolution: {integrity: sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==} engines: {node: '>=18'} @@ -1149,6 +1241,10 @@ packages: resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} engines: {node: '>=6'} + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -1157,6 +1253,10 @@ packages: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} + restore-cursor@3.1.0: + resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} + engines: {node: '>=8'} + restore-cursor@5.1.0: resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} engines: {node: '>=18'} @@ -1175,9 +1275,19 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + run-async@3.0.0: + resolution: {integrity: sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==} + engines: {node: '>=0.12.0'} + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + rxjs@7.8.2: + resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} @@ -1197,6 +1307,9 @@ packages: siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} @@ -1236,6 +1349,9 @@ packages: resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} engines: {node: '>=18'} + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -1288,6 +1404,9 @@ packages: tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + turbo-darwin-64@1.13.4: resolution: {integrity: sha512-A0eKd73R7CGnRinTiS7txkMElg+R5rKFp9HV7baDiEL4xTG1FIg/56Vm7A5RVgg8UNgG2qNnrfatJtb+dRmNdw==} cpu: [x64] @@ -1334,6 +1453,10 @@ packages: resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} engines: {node: '>=10'} + type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} @@ -1352,6 +1475,9 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + vite-node@1.6.1: resolution: {integrity: sha512-YAXkfvGtuTzwWbDSACdJSg4A4DZiAqckWe90Zapc/sEX3XvHcw1NdurM/6od8J207tSDqNbSsgdCacBgvJKFuA==} engines: {node: ^18.0.0 || >=20.0.0} @@ -1413,6 +1539,9 @@ packages: jsdom: optional: true + wcwidth@1.0.1: + resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} + webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} @@ -1433,6 +1562,10 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} @@ -1444,6 +1577,10 @@ packages: resolution: {integrity: sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==} engines: {node: '>=12.20'} + yoctocolors-cjs@2.1.3: + resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==} + engines: {node: '>=18'} + snapshots: '@babel/runtime@7.28.4': {} @@ -1721,6 +1858,8 @@ snapshots: optionalDependencies: '@types/node': 20.19.23 + '@inquirer/figures@1.0.14': {} + '@jest/schemas@29.6.3': dependencies: '@sinclair/typebox': 0.27.8 @@ -1823,8 +1962,15 @@ snapshots: '@sinclair/typebox@0.27.8': {} + '@types/diff@5.2.3': {} + '@types/estree@1.0.8': {} + '@types/inquirer@9.0.9': + dependencies: + '@types/through': 0.0.33 + rxjs: 7.8.2 + '@types/node@12.20.55': {} '@types/node@20.19.23': @@ -1836,6 +1982,10 @@ snapshots: '@types/node': 20.19.23 kleur: 3.0.3 + '@types/through@0.0.33': + dependencies: + '@types/node': 20.19.23 + '@ungap/structured-clone@1.3.0': {} '@vitest/expect@1.6.1': @@ -1886,6 +2036,10 @@ snapshots: ansi-colors@4.1.3: {} + ansi-escapes@4.3.2: + dependencies: + type-fest: 0.21.3 + ansi-regex@5.0.1: {} ansi-regex@6.2.2: {} @@ -1908,10 +2062,18 @@ snapshots: balanced-match@1.0.2: {} + base64-js@1.5.1: {} + better-path-resolve@1.0.0: dependencies: is-windows: 1.0.2 + bl@4.1.0: + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + brace-expansion@1.1.12: dependencies: balanced-match: 1.0.2 @@ -1921,6 +2083,11 @@ snapshots: dependencies: fill-range: 7.1.1 + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + cac@6.7.14: {} callsites@3.1.0: {} @@ -1950,6 +2117,10 @@ snapshots: ci-info@3.9.0: {} + cli-cursor@3.1.0: + dependencies: + restore-cursor: 3.1.0 + cli-cursor@5.0.0: dependencies: restore-cursor: 5.1.0 @@ -1962,6 +2133,10 @@ snapshots: optionalDependencies: '@colors/colors': 1.5.0 + cli-width@4.1.0: {} + + clone@1.0.4: {} + color-convert@2.0.1: dependencies: color-name: 1.1.4 @@ -1992,10 +2167,16 @@ snapshots: deep-is@0.1.4: {} + defaults@1.0.4: + dependencies: + clone: 1.0.4 + detect-indent@6.1.0: {} diff-sequences@29.6.3: {} + diff@5.2.0: {} + dir-glob@3.0.1: dependencies: path-type: 4.0.0 @@ -2242,6 +2423,8 @@ snapshots: dependencies: safer-buffer: 2.1.2 + ieee754@1.2.1: {} + ignore@5.3.2: {} import-fresh@3.3.1: @@ -2258,6 +2441,23 @@ snapshots: inherits@2.0.4: {} + inquirer@9.3.8(@types/node@20.19.23): + dependencies: + '@inquirer/external-editor': 1.0.2(@types/node@20.19.23) + '@inquirer/figures': 1.0.14 + ansi-escapes: 4.3.2 + cli-width: 4.1.0 + mute-stream: 1.0.0 + ora: 5.4.1 + run-async: 3.0.0 + rxjs: 7.8.2 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + yoctocolors-cjs: 2.1.3 + transitivePeerDependencies: + - '@types/node' + is-extglob@2.1.1: {} is-fullwidth-code-point@3.0.0: {} @@ -2266,6 +2466,8 @@ snapshots: dependencies: is-extglob: 2.1.1 + is-interactive@1.0.0: {} + is-interactive@2.0.0: {} is-number@7.0.0: {} @@ -2278,6 +2480,8 @@ snapshots: dependencies: better-path-resolve: 1.0.0 + is-unicode-supported@0.1.0: {} + is-unicode-supported@1.3.0: {} is-unicode-supported@2.1.0: {} @@ -2335,6 +2539,11 @@ snapshots: lodash.startcase@4.4.0: {} + log-symbols@4.1.0: + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + log-symbols@6.0.0: dependencies: chalk: 5.6.2 @@ -2357,6 +2566,8 @@ snapshots: braces: 3.0.3 picomatch: 2.3.1 + mimic-fn@2.1.0: {} + mimic-fn@4.0.0: {} mimic-function@5.0.1: {} @@ -2376,6 +2587,8 @@ snapshots: ms@2.1.3: {} + mute-stream@1.0.0: {} + nanoid@3.3.11: {} natural-compare@1.4.0: {} @@ -2392,6 +2605,10 @@ snapshots: dependencies: wrappy: 1.0.2 + onetime@5.1.2: + dependencies: + mimic-fn: 2.1.0 + onetime@6.0.0: dependencies: mimic-fn: 4.0.0 @@ -2409,6 +2626,18 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 + ora@5.4.1: + dependencies: + bl: 4.1.0 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-spinners: 2.9.2 + is-interactive: 1.0.0 + is-unicode-supported: 0.1.0 + log-symbols: 4.1.0 + strip-ansi: 6.0.1 + wcwidth: 1.0.1 + ora@8.2.0: dependencies: chalk: 5.6.2 @@ -2525,10 +2754,21 @@ snapshots: pify: 4.0.1 strip-bom: 3.0.0 + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + resolve-from@4.0.0: {} resolve-from@5.0.0: {} + restore-cursor@3.1.0: + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + restore-cursor@5.1.0: dependencies: onetime: 7.0.0 @@ -2568,10 +2808,18 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.52.5 fsevents: 2.3.3 + run-async@3.0.0: {} + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 + rxjs@7.8.2: + dependencies: + tslib: 2.8.1 + + safe-buffer@5.2.1: {} + safer-buffer@2.1.2: {} semver@7.7.3: {} @@ -2584,6 +2832,8 @@ snapshots: siginfo@2.0.0: {} + signal-exit@3.0.7: {} + signal-exit@4.1.0: {} sisteransi@1.0.5: {} @@ -2617,6 +2867,10 @@ snapshots: get-east-asian-width: 1.4.0 strip-ansi: 7.1.2 + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 @@ -2655,6 +2909,8 @@ snapshots: tr46@0.0.3: {} + tslib@2.8.1: {} + turbo-darwin-64@1.13.4: optional: true @@ -2690,6 +2946,8 @@ snapshots: type-fest@0.20.2: {} + type-fest@0.21.3: {} + typescript@5.9.3: {} ufo@1.6.1: {} @@ -2702,6 +2960,8 @@ snapshots: dependencies: punycode: 2.3.1 + util-deprecate@1.0.2: {} + vite-node@1.6.1(@types/node@20.19.23): dependencies: cac: 6.7.14 @@ -2763,6 +3023,10 @@ snapshots: - supports-color - terser + wcwidth@1.0.1: + dependencies: + defaults: 1.0.4 + webidl-conversions@3.0.1: {} whatwg-url@5.0.0: @@ -2781,8 +3045,16 @@ snapshots: word-wrap@1.2.5: {} + wrap-ansi@6.2.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrappy@1.0.2: {} yocto-queue@0.1.0: {} yocto-queue@1.2.1: {} + + yoctocolors-cjs@2.1.3: {}