diff --git a/CLAUDE.md b/CLAUDE.md index 0decf40..4229914 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -6,9 +6,9 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co Puaros is a TypeScript monorepo using pnpm workspaces. Contains two packages: -- **`@puaros/guardian`** - Code quality guardian for detecting hardcoded values, circular dependencies, framework leaks, naming violations, and architecture violations. +- **`@samiyev/guardian`** - Code quality guardian for detecting hardcoded values, circular dependencies, framework leaks, naming violations, and architecture violations. -- **`@puaros/ipuaro`** - Local AI agent for codebase operations with "infinite" context feeling. Uses lazy loading, Redis persistence, tree-sitter AST parsing, and Ollama LLM integration. +- **`@samiyev/ipuaro`** - Local AI agent for codebase operations with "infinite" context feeling. Uses lazy loading, Redis persistence, tree-sitter AST parsing, and Ollama LLM integration. The project uses Node.js 22.18.0 (see `.nvmrc`). @@ -170,7 +170,7 @@ Examples: ``` puaros/ ├── packages/ -│ ├── guardian/ # @puaros/guardian - Code quality analyzer +│ ├── guardian/ # @samiyev/guardian - Code quality analyzer │ │ ├── src/ # Source files (Clean Architecture) │ │ │ ├── domain/ # Entities, value objects │ │ │ ├── application/ # Use cases, DTOs @@ -180,7 +180,7 @@ puaros/ │ │ ├── bin/ # CLI entry point │ │ ├── tests/ # Test files │ │ └── examples/ # Usage examples -│ └── ipuaro/ # @puaros/ipuaro - Local AI agent +│ └── ipuaro/ # @samiyev/ipuaro - Local AI agent │ ├── src/ # Source files (Clean Architecture) │ │ ├── domain/ # Entities, value objects, services │ │ ├── application/ # Use cases, DTOs, mappers @@ -260,7 +260,7 @@ Guardian package (`packages/guardian/tsconfig.json`): ## Adding New Packages 1. Create `packages/new-package/` directory -2. Add `package.json` with name `@puaros/new-package` +2. Add `package.json` with name `@samiyev/new-package` 3. Create `tsconfig.json` extending `../../tsconfig.base.json` 4. Package auto-discovered via `pnpm-workspace.yaml` glob pattern @@ -412,7 +412,7 @@ npm pack --dry-run npm publish --access public # Verify -npm info @puaros/ +npm info @samiyev/ ``` ## Pipeline Checklist diff --git a/packages/ipuaro/CHANGELOG.md b/packages/ipuaro/CHANGELOG.md new file mode 100644 index 0000000..9e9cbf5 --- /dev/null +++ b/packages/ipuaro/CHANGELOG.md @@ -0,0 +1,51 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.1.0] - 2025-01-29 + +### Added + +- **Project Setup** + - package.json with all dependencies (ink, ioredis, tree-sitter, ollama, etc.) + - tsconfig.json for ESM + React JSX + - tsup.config.ts for bundling + - vitest.config.ts with 80% coverage threshold + - CLI entry point (bin/ipuaro.js) + +- **Domain Layer** + - Entities: Session, Project + - Value Objects: FileData, FileAST, FileMeta, ChatMessage, ToolCall, ToolResult, UndoEntry + - Service Interfaces: IStorage, ILLMClient, ITool, IIndexer + - Constants: supported extensions, ignore patterns, context limits + +- **Application Layer** + - IToolRegistry interface + - Placeholder structure for use cases and DTOs + +- **Shared Module** + - Config schema with Zod validation + - Config loader (default.json + .ipuaro.json) + - IpuaroError class with typed errors + - Utility functions: md5 hash, token estimation + - Result type for error handling + +- **CLI** + - Basic commands: start, init, index (placeholders) + - Commander.js integration + +- **Testing** + - 91 unit tests + - 100% code coverage + +### Notes + +This is the foundation release. The following features are planned for upcoming versions: +- 0.2.0: Redis Storage +- 0.3.0: Indexer +- 0.4.0: LLM Integration +- 0.5.0+: Tools implementation +- 0.10.0+: TUI and session management diff --git a/packages/ipuaro/README.md b/packages/ipuaro/README.md new file mode 100644 index 0000000..ded5b8d --- /dev/null +++ b/packages/ipuaro/README.md @@ -0,0 +1,130 @@ +# @samiyev/ipuaro + +Local AI agent for codebase operations with "infinite" context feeling through lazy loading. + +## Features + +- 18 LLM tools for code operations (read, edit, search, analysis, git, run) +- Redis persistence with AOF for durability +- tree-sitter AST parsing (TypeScript, JavaScript) +- Ollama LLM integration (local, private) +- File watching for live index updates +- Session and undo management +- Security (blacklist/whitelist for shell commands) +- Terminal UI with Ink/React + +## Installation + +```bash +npm install @samiyev/ipuaro +# or +pnpm add @samiyev/ipuaro +``` + +## Requirements + +- Node.js >= 20.0.0 +- Redis server (for persistence) +- Ollama (for LLM inference) + +## Quick Start + +```bash +# Start in current directory +ipuaro + +# Start in specific directory +ipuaro /path/to/project + +# With auto-apply mode +ipuaro --auto-apply + +# With custom model +ipuaro --model qwen2.5-coder:32b-instruct +``` + +## Commands + +| Command | Description | +|---------|-------------| +| `ipuaro [path]` | Start TUI in directory | +| `ipuaro init` | Create .ipuaro.json config | +| `ipuaro index` | Index project without TUI | + +## Configuration + +Create `.ipuaro.json` in your project root: + +```json +{ + "redis": { + "host": "localhost", + "port": 6379 + }, + "llm": { + "model": "qwen2.5-coder:7b-instruct", + "temperature": 0.1 + }, + "edit": { + "autoApply": false + } +} +``` + +## Architecture + +Clean Architecture with clear separation: + +``` +src/ +├── domain/ # Business logic (entities, value objects, interfaces) +├── application/ # Use cases, DTOs, orchestration +├── infrastructure/ # External implementations (Redis, Ollama, tools) +├── tui/ # Terminal UI (Ink/React components) +├── cli/ # CLI commands +└── shared/ # Cross-cutting concerns +``` + +## Tools (18 total) + +| Category | Tool | Description | +|----------|------|-------------| +| **Read** | `get_lines` | Get file lines | +| | `get_function` | Get function by name | +| | `get_class` | Get class by name | +| | `get_structure` | Get project tree | +| **Edit** | `edit_lines` | Replace lines | +| | `create_file` | Create new file | +| | `delete_file` | Delete file | +| **Search** | `find_references` | Find symbol usages | +| | `find_definition` | Find symbol definition | +| **Analysis** | `get_dependencies` | File imports | +| | `get_dependents` | Files importing this | +| | `get_complexity` | Complexity metrics | +| | `get_todos` | Find TODO/FIXME | +| **Git** | `git_status` | Repository status | +| | `git_diff` | Uncommitted changes | +| | `git_commit` | Create commit | +| **Run** | `run_command` | Execute shell command | +| | `run_tests` | Run test suite | + +## Development Status + +Currently at version **0.1.0** (Foundation). See [ROADMAP.md](./ROADMAP.md) for full development plan. + +### Completed + +- [x] 0.1.1 Project Setup +- [x] 0.1.2 Domain Value Objects +- [x] 0.1.3 Domain Services Interfaces +- [x] 0.1.4 Shared Config + +### Next + +- [ ] 0.2.0 Redis Storage +- [ ] 0.3.0 Indexer +- [ ] 0.4.0 LLM Integration + +## License + +MIT diff --git a/packages/ipuaro/TODO.md b/packages/ipuaro/TODO.md new file mode 100644 index 0000000..7cb54fa --- /dev/null +++ b/packages/ipuaro/TODO.md @@ -0,0 +1,54 @@ +# ipuaro TODO + +## In Progress + +### Version 0.2.0 - Redis Storage +- [ ] RedisClient with AOF config +- [ ] Redis schema implementation +- [ ] RedisStorage class + +## Planned + +### Version 0.3.0 - Indexer +- [ ] FileScanner with gitignore support +- [ ] ASTParser with tree-sitter +- [ ] MetaAnalyzer for complexity +- [ ] IndexBuilder for symbols +- [ ] Watchdog for file changes + +### Version 0.4.0 - LLM Integration +- [ ] OllamaClient implementation +- [ ] System prompt design +- [ ] Tool definitions (XML format) +- [ ] Response parser + +### Version 0.5.0+ - Tools +- [ ] Read tools (get_lines, get_function, get_class, get_structure) +- [ ] Edit tools (edit_lines, create_file, delete_file) +- [ ] Search tools (find_references, find_definition) +- [ ] Analysis tools (get_dependencies, get_dependents, get_complexity, get_todos) +- [ ] Git tools (git_status, git_diff, git_commit) +- [ ] Run tools (run_command, run_tests) + +### Version 0.10.0+ - Session & TUI +- [ ] Session management +- [ ] Context compression +- [ ] TUI components (StatusBar, Chat, Input, DiffView) +- [ ] Slash commands (/help, /clear, /undo, etc.) + +## Technical Debt + +_None at this time._ + +## Ideas for Future + +- Plugin system for custom tools +- Multiple LLM providers (OpenAI, Anthropic) +- IDE integration (LSP) +- Web UI option +- Parallel AST parsing +- Response caching + +--- + +**Last Updated:** 2025-01-29 diff --git a/packages/ipuaro/bin/ipuaro.js b/packages/ipuaro/bin/ipuaro.js new file mode 100644 index 0000000..ebffdb4 --- /dev/null +++ b/packages/ipuaro/bin/ipuaro.js @@ -0,0 +1,3 @@ +#!/usr/bin/env node + +import "../dist/cli/index.js" \ No newline at end of file diff --git a/packages/ipuaro/package.json b/packages/ipuaro/package.json new file mode 100644 index 0000000..2abe182 --- /dev/null +++ b/packages/ipuaro/package.json @@ -0,0 +1,80 @@ +{ + "name": "@samiyev/ipuaro", + "version": "0.1.0", + "description": "Local AI agent for codebase operations with infinite context feeling", + "author": "Fozilbek Samiyev ", + "license": "MIT", + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "bin": { + "ipuaro": "./bin/ipuaro.js" + }, + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js" + } + }, + "files": [ + "dist", + "bin" + ], + "scripts": { + "build": "tsup", + "watch": "tsup --watch", + "clean": "rm -rf dist", + "test": "vitest", + "test:run": "vitest run", + "test:coverage": "vitest run --coverage", + "test:ui": "vitest --ui", + "test:watch": "vitest --watch", + "lint": "eslint src --fix", + "format": "prettier --write src" + }, + "dependencies": { + "ink": "^4.4.1", + "ink-text-input": "^5.0.1", + "react": "^18.2.0", + "ioredis": "^5.4.1", + "tree-sitter": "^0.21.1", + "tree-sitter-typescript": "^0.21.2", + "tree-sitter-javascript": "^0.21.0", + "ollama": "^0.5.11", + "simple-git": "^3.27.0", + "chokidar": "^3.6.0", + "commander": "^11.1.0", + "zod": "^3.23.8", + "ignore": "^5.3.2" + }, + "devDependencies": { + "@types/node": "^22.10.1", + "@types/react": "^18.2.0", + "vitest": "^1.6.0", + "@vitest/coverage-v8": "^1.6.0", + "@vitest/ui": "^1.6.0", + "tsup": "^8.3.5", + "typescript": "^5.7.2" + }, + "engines": { + "node": ">=20.0.0" + }, + "keywords": [ + "ai", + "agent", + "codebase", + "llm", + "ollama", + "cli", + "terminal" + ], + "repository": { + "type": "git", + "url": "https://github.com/samiyev/puaros.git", + "directory": "packages/ipuaro" + }, + "bugs": { + "url": "https://github.com/samiyev/puaros/issues" + }, + "homepage": "https://github.com/samiyev/puaros/tree/main/packages/ipuaro#readme" +} \ No newline at end of file diff --git a/packages/ipuaro/src/application/dtos/index.ts b/packages/ipuaro/src/application/dtos/index.ts new file mode 100644 index 0000000..5df433c --- /dev/null +++ b/packages/ipuaro/src/application/dtos/index.ts @@ -0,0 +1,4 @@ +/* + * Application DTOs + * Will be implemented in version 0.10.0+ + */ diff --git a/packages/ipuaro/src/application/index.ts b/packages/ipuaro/src/application/index.ts new file mode 100644 index 0000000..30af76a --- /dev/null +++ b/packages/ipuaro/src/application/index.ts @@ -0,0 +1,10 @@ +// Application Layer exports + +// Use Cases +export * from "./use-cases/index.js" + +// DTOs +export * from "./dtos/index.js" + +// Interfaces +export * from "./interfaces/index.js" diff --git a/packages/ipuaro/src/application/interfaces/IToolRegistry.ts b/packages/ipuaro/src/application/interfaces/IToolRegistry.ts new file mode 100644 index 0000000..bb8447f --- /dev/null +++ b/packages/ipuaro/src/application/interfaces/IToolRegistry.ts @@ -0,0 +1,51 @@ +import type { ITool, ToolContext } from "../../domain/services/ITool.js" +import type { ToolResult } from "../../domain/value-objects/ToolResult.js" + +/** + * Tool registry interface. + * Manages registration and execution of tools. + */ +export interface IToolRegistry { + /** + * Register a tool. + */ + register(tool: ITool): void + + /** + * Get tool by name. + */ + get(name: string): ITool | undefined + + /** + * Get all registered tools. + */ + getAll(): ITool[] + + /** + * Get tools by category. + */ + getByCategory(category: ITool["category"]): ITool[] + + /** + * Check if tool exists. + */ + has(name: string): boolean + + /** + * Execute tool by name. + */ + execute(name: string, params: Record, ctx: ToolContext): Promise + + /** + * Get tool definitions for LLM. + */ + getToolDefinitions(): { + name: string + description: string + parameters: { + type: "object" + properties: Record + required: string[] + } + }[] +} diff --git a/packages/ipuaro/src/application/interfaces/index.ts b/packages/ipuaro/src/application/interfaces/index.ts new file mode 100644 index 0000000..aaf5915 --- /dev/null +++ b/packages/ipuaro/src/application/interfaces/index.ts @@ -0,0 +1,2 @@ +// Application Interfaces +export * from "./IToolRegistry.js" diff --git a/packages/ipuaro/src/application/use-cases/index.ts b/packages/ipuaro/src/application/use-cases/index.ts new file mode 100644 index 0000000..25ebb14 --- /dev/null +++ b/packages/ipuaro/src/application/use-cases/index.ts @@ -0,0 +1,4 @@ +/* + * Application Use Cases + * Will be implemented in version 0.10.0+ + */ diff --git a/packages/ipuaro/src/cli/index.ts b/packages/ipuaro/src/cli/index.ts new file mode 100644 index 0000000..ecf2690 --- /dev/null +++ b/packages/ipuaro/src/cli/index.ts @@ -0,0 +1,44 @@ +#!/usr/bin/env node + +import { Command } from "commander" + +const program = new Command() + +program + .name("ipuaro") + .description("Local AI agent for codebase operations with infinite context feeling") + .version("0.1.0") + +program + .command("start") + .description("Start ipuaro TUI in the current directory") + .argument("[path]", "Project path", ".") + .option("--auto-apply", "Enable auto-apply mode for edits") + .option("--model ", "Override LLM model", "qwen2.5-coder:7b-instruct") + .action((path: string, options: { autoApply?: boolean; model?: string }) => { + const model = options.model ?? "default" + const autoApply = options.autoApply ?? false + console.warn(`Starting ipuaro in ${path}...`) + console.warn(`Model: ${model}`) + console.warn(`Auto-apply: ${autoApply ? "enabled" : "disabled"}`) + console.warn("\nNot implemented yet. Coming in version 0.11.0!") + }) + +program + .command("init") + .description("Create .ipuaro.json config file") + .action(() => { + console.warn("Creating .ipuaro.json...") + console.warn("\nNot implemented yet. Coming in version 0.17.0!") + }) + +program + .command("index") + .description("Index project without starting TUI") + .argument("[path]", "Project path", ".") + .action((path: string) => { + console.warn(`Indexing ${path}...`) + console.warn("\nNot implemented yet. Coming in version 0.3.0!") + }) + +program.parse() diff --git a/packages/ipuaro/src/domain/constants/index.ts b/packages/ipuaro/src/domain/constants/index.ts new file mode 100644 index 0000000..b283bf8 --- /dev/null +++ b/packages/ipuaro/src/domain/constants/index.ts @@ -0,0 +1,48 @@ +// Domain Constants + +export const MAX_UNDO_STACK_SIZE = 10 + +export const SUPPORTED_EXTENSIONS = [ + ".ts", + ".tsx", + ".js", + ".jsx", + ".json", + ".yaml", + ".yml", +] as const + +export const BINARY_EXTENSIONS = [ + ".png", + ".jpg", + ".jpeg", + ".gif", + ".ico", + ".svg", + ".woff", + ".woff2", + ".ttf", + ".eot", + ".mp3", + ".mp4", + ".webm", + ".pdf", + ".zip", + ".tar", + ".gz", +] as const + +export const DEFAULT_IGNORE_PATTERNS = [ + "node_modules", + "dist", + "build", + ".git", + ".next", + ".nuxt", + "coverage", + ".cache", +] as const + +export const CONTEXT_WINDOW_SIZE = 128_000 + +export const CONTEXT_COMPRESSION_THRESHOLD = 0.8 diff --git a/packages/ipuaro/src/domain/entities/Project.ts b/packages/ipuaro/src/domain/entities/Project.ts new file mode 100644 index 0000000..9e12af6 --- /dev/null +++ b/packages/ipuaro/src/domain/entities/Project.ts @@ -0,0 +1,61 @@ +import { basename, dirname } from "node:path" + +/** + * Project entity representing an indexed codebase. + */ +export class Project { + readonly name: string + readonly rootPath: string + readonly createdAt: number + lastIndexedAt: number | null + fileCount: number + indexingInProgress: boolean + + constructor(rootPath: string, createdAt?: number) { + this.rootPath = rootPath + this.name = Project.generateProjectName(rootPath) + this.createdAt = createdAt ?? Date.now() + this.lastIndexedAt = null + this.fileCount = 0 + this.indexingInProgress = false + } + + /** + * Generate project name from path. + * Format: {parent-folder}-{project-folder} + */ + static generateProjectName(rootPath: string): string { + const projectFolder = basename(rootPath) + const parentFolder = basename(dirname(rootPath)) + + if (parentFolder && parentFolder !== ".") { + return `${parentFolder}-${projectFolder}` + } + return projectFolder + } + + markIndexingStarted(): void { + this.indexingInProgress = true + } + + markIndexingCompleted(fileCount: number): void { + this.indexingInProgress = false + this.lastIndexedAt = Date.now() + this.fileCount = fileCount + } + + markIndexingFailed(): void { + this.indexingInProgress = false + } + + isIndexed(): boolean { + return this.lastIndexedAt !== null + } + + getTimeSinceIndexed(): number | null { + if (this.lastIndexedAt === null) { + return null + } + return Date.now() - this.lastIndexedAt + } +} diff --git a/packages/ipuaro/src/domain/entities/Session.ts b/packages/ipuaro/src/domain/entities/Session.ts new file mode 100644 index 0000000..dc96944 --- /dev/null +++ b/packages/ipuaro/src/domain/entities/Session.ts @@ -0,0 +1,120 @@ +import type { ChatMessage } from "../value-objects/ChatMessage.js" +import type { UndoEntry } from "../value-objects/UndoEntry.js" +import { MAX_UNDO_STACK_SIZE } from "../constants/index.js" + +/** + * Session statistics. + */ +export interface SessionStats { + /** Total tokens used */ + totalTokens: number + /** Total time in milliseconds */ + totalTimeMs: number + /** Number of tool calls made */ + toolCalls: number + /** Number of edits applied */ + editsApplied: number + /** Number of edits rejected */ + editsRejected: number +} + +/** + * Context state for the session. + */ +export interface ContextState { + /** Files currently in context */ + filesInContext: string[] + /** Estimated token usage (0-1) */ + tokenUsage: number + /** Whether compression is needed */ + needsCompression: boolean +} + +/** + * Session entity representing a chat session. + */ +export class Session { + readonly id: string + readonly projectName: string + readonly createdAt: number + lastActivityAt: number + history: ChatMessage[] + context: ContextState + undoStack: UndoEntry[] + stats: SessionStats + inputHistory: string[] + + constructor(id: string, projectName: string, createdAt?: number) { + this.id = id + this.projectName = projectName + this.createdAt = createdAt ?? Date.now() + this.lastActivityAt = this.createdAt + this.history = [] + this.context = { + filesInContext: [], + tokenUsage: 0, + needsCompression: false, + } + this.undoStack = [] + this.stats = { + totalTokens: 0, + totalTimeMs: 0, + toolCalls: 0, + editsApplied: 0, + editsRejected: 0, + } + this.inputHistory = [] + } + + addMessage(message: ChatMessage): void { + this.history.push(message) + this.lastActivityAt = Date.now() + + if (message.stats) { + this.stats.totalTokens += message.stats.tokens + this.stats.totalTimeMs += message.stats.timeMs + this.stats.toolCalls += message.stats.toolCalls + } + } + + addUndoEntry(entry: UndoEntry): void { + this.undoStack.push(entry) + if (this.undoStack.length > MAX_UNDO_STACK_SIZE) { + this.undoStack.shift() + } + } + + popUndoEntry(): UndoEntry | undefined { + return this.undoStack.pop() + } + + addInputToHistory(input: string): void { + if (input.trim() && this.inputHistory[this.inputHistory.length - 1] !== input) { + this.inputHistory.push(input) + } + } + + clearHistory(): void { + this.history = [] + this.context = { + filesInContext: [], + tokenUsage: 0, + needsCompression: false, + } + } + + getSessionDurationMs(): number { + return Date.now() - this.createdAt + } + + getSessionDurationFormatted(): string { + const totalMinutes = Math.floor(this.getSessionDurationMs() / 60_000) + const hours = Math.floor(totalMinutes / 60) + const minutes = totalMinutes % 60 + + if (hours > 0) { + return `${String(hours)}h ${String(minutes)}m` + } + return `${String(minutes)}m` + } +} diff --git a/packages/ipuaro/src/domain/entities/index.ts b/packages/ipuaro/src/domain/entities/index.ts new file mode 100644 index 0000000..6187541 --- /dev/null +++ b/packages/ipuaro/src/domain/entities/index.ts @@ -0,0 +1,3 @@ +// Domain Entities +export * from "./Session.js" +export * from "./Project.js" diff --git a/packages/ipuaro/src/domain/index.ts b/packages/ipuaro/src/domain/index.ts new file mode 100644 index 0000000..2b7d118 --- /dev/null +++ b/packages/ipuaro/src/domain/index.ts @@ -0,0 +1,13 @@ +// Domain Layer exports + +// Entities +export * from "./entities/index.js" + +// Value Objects +export * from "./value-objects/index.js" + +// Service Interfaces +export * from "./services/index.js" + +// Constants +export * from "./constants/index.js" diff --git a/packages/ipuaro/src/domain/services/IIndexer.ts b/packages/ipuaro/src/domain/services/IIndexer.ts new file mode 100644 index 0000000..e33b177 --- /dev/null +++ b/packages/ipuaro/src/domain/services/IIndexer.ts @@ -0,0 +1,83 @@ +import type { FileAST } from "../value-objects/FileAST.js" +import type { FileData } from "../value-objects/FileData.js" +import type { FileMeta } from "../value-objects/FileMeta.js" +import type { DepsGraph, SymbolIndex } from "./IStorage.js" + +/** + * Progress callback for indexing operations. + */ +export interface IndexProgress { + current: number + total: number + currentFile: string + phase: "scanning" | "parsing" | "analyzing" | "indexing" +} + +/** + * Result of scanning a single file. + */ +export interface ScanResult { + path: string + type: "file" | "directory" | "symlink" + size: number + lastModified: number +} + +/** + * Indexing result statistics. + */ +export interface IndexingStats { + filesScanned: number + filesParsed: number + parseErrors: number + timeMs: number +} + +/** + * Indexer service interface (port). + * Handles project scanning, parsing, and indexing. + */ +export interface IIndexer { + /** + * Scan directory and yield file results. + */ + scan(root: string): AsyncGenerator + + /** + * Parse file content into AST. + */ + parseFile(content: string, language: "ts" | "tsx" | "js" | "jsx"): FileAST + + /** + * Analyze file and compute metadata. + */ + analyzeFile(path: string, ast: FileAST, allASTs: Map): FileMeta + + /** + * Build symbol index from all ASTs. + */ + buildSymbolIndex(asts: Map): SymbolIndex + + /** + * Build dependency graph from all ASTs. + */ + buildDepsGraph(asts: Map): DepsGraph + + /** + * Full indexing pipeline. + */ + indexProject( + root: string, + onProgress?: (progress: IndexProgress) => void, + ): Promise + + /** + * Update single file (incremental indexing). + */ + updateFile(path: string, data: FileData): Promise + + /** + * Remove file from index. + */ + removeFile(path: string): Promise +} diff --git a/packages/ipuaro/src/domain/services/ILLMClient.ts b/packages/ipuaro/src/domain/services/ILLMClient.ts new file mode 100644 index 0000000..86e6610 --- /dev/null +++ b/packages/ipuaro/src/domain/services/ILLMClient.ts @@ -0,0 +1,81 @@ +import type { ChatMessage } from "../value-objects/ChatMessage.js" +import type { ToolCall } from "../value-objects/ToolCall.js" + +/** + * Tool parameter definition for LLM. + */ +export interface ToolParameter { + name: string + type: "string" | "number" | "boolean" | "array" | "object" + description: string + required: boolean + enum?: string[] +} + +/** + * Tool definition for LLM function calling. + */ +export interface ToolDef { + name: string + description: string + parameters: ToolParameter[] +} + +/** + * Response from LLM. + */ +export interface LLMResponse { + /** Text content of the response */ + content: string + /** Tool calls parsed from response */ + toolCalls: ToolCall[] + /** Token count for this response */ + tokens: number + /** Generation time in milliseconds */ + timeMs: number + /** Whether response was truncated */ + truncated: boolean + /** Stop reason */ + stopReason: "end" | "length" | "tool_use" +} + +/** + * LLM client service interface (port). + * Abstracts the LLM provider. + */ +export interface ILLMClient { + /** + * Send messages to LLM and get response. + */ + chat(messages: ChatMessage[], tools?: ToolDef[]): Promise + + /** + * Count tokens in text. + */ + countTokens(text: string): Promise + + /** + * Check if LLM service is available. + */ + isAvailable(): Promise + + /** + * Get current model name. + */ + getModelName(): string + + /** + * Get context window size. + */ + getContextWindowSize(): number + + /** + * Pull/download model if not available locally. + */ + pullModel(model: string): Promise + + /** + * Abort current generation. + */ + abort(): void +} diff --git a/packages/ipuaro/src/domain/services/IStorage.ts b/packages/ipuaro/src/domain/services/IStorage.ts new file mode 100644 index 0000000..a8fdca5 --- /dev/null +++ b/packages/ipuaro/src/domain/services/IStorage.ts @@ -0,0 +1,65 @@ +import type { FileData } from "../value-objects/FileData.js" +import type { FileAST } from "../value-objects/FileAST.js" +import type { FileMeta } from "../value-objects/FileMeta.js" + +/** + * Symbol index mapping symbol names to their locations. + */ +export interface SymbolLocation { + path: string + line: number + type: "function" | "class" | "interface" | "type" | "variable" +} + +export type SymbolIndex = Map + +/** + * Dependencies graph for the project. + */ +export interface DepsGraph { + /** Map from file path to its imports */ + imports: Map + /** Map from file path to files that import it */ + importedBy: Map +} + +/** + * Storage service interface (port). + * Abstracts the persistence layer for project data. + */ +export interface IStorage { + // File data operations + getFile(path: string): Promise + setFile(path: string, data: FileData): Promise + deleteFile(path: string): Promise + getAllFiles(): Promise> + getFileCount(): Promise + + // AST operations + getAST(path: string): Promise + setAST(path: string, ast: FileAST): Promise + deleteAST(path: string): Promise + getAllASTs(): Promise> + + // Meta operations + getMeta(path: string): Promise + setMeta(path: string, meta: FileMeta): Promise + deleteMeta(path: string): Promise + getAllMetas(): Promise> + + // Index operations + getSymbolIndex(): Promise + setSymbolIndex(index: SymbolIndex): Promise + getDepsGraph(): Promise + setDepsGraph(graph: DepsGraph): Promise + + // Config operations + getProjectConfig(key: string): Promise + setProjectConfig(key: string, value: unknown): Promise + + // Lifecycle + connect(): Promise + disconnect(): Promise + isConnected(): boolean + clear(): Promise +} diff --git a/packages/ipuaro/src/domain/services/ITool.ts b/packages/ipuaro/src/domain/services/ITool.ts new file mode 100644 index 0000000..2fd7584 --- /dev/null +++ b/packages/ipuaro/src/domain/services/ITool.ts @@ -0,0 +1,68 @@ +import type { ToolResult } from "../value-objects/ToolResult.js" +import type { IStorage } from "./IStorage.js" + +/** + * Tool parameter schema. + */ +export interface ToolParameterSchema { + name: string + type: "string" | "number" | "boolean" | "array" | "object" + description: string + required: boolean + default?: unknown +} + +/** + * Context provided to tools during execution. + */ +export interface ToolContext { + /** Project root path */ + projectRoot: string + /** Storage service */ + storage: IStorage + /** Request user confirmation callback */ + requestConfirmation: (message: string, diff?: DiffInfo) => Promise + /** Report progress callback */ + onProgress?: (message: string) => void +} + +/** + * Diff information for confirmation dialogs. + */ +export interface DiffInfo { + filePath: string + oldLines: string[] + newLines: string[] + startLine: number +} + +/** + * Tool interface (port). + * All tools must implement this interface. + */ +export interface ITool { + /** Tool name (used in tool calls) */ + readonly name: string + + /** Human-readable description */ + readonly description: string + + /** Tool parameters schema */ + readonly parameters: ToolParameterSchema[] + + /** Whether tool requires user confirmation before execution */ + readonly requiresConfirmation: boolean + + /** Tool category */ + readonly category: "read" | "edit" | "search" | "analysis" | "git" | "run" + + /** + * Execute the tool with given parameters. + */ + execute(params: Record, ctx: ToolContext): Promise + + /** + * Validate parameters before execution. + */ + validateParams(params: Record): string | null +} diff --git a/packages/ipuaro/src/domain/services/index.ts b/packages/ipuaro/src/domain/services/index.ts new file mode 100644 index 0000000..3802656 --- /dev/null +++ b/packages/ipuaro/src/domain/services/index.ts @@ -0,0 +1,5 @@ +// Domain Service Interfaces (Ports) +export * from "./IStorage.js" +export * from "./ILLMClient.js" +export * from "./ITool.js" +export * from "./IIndexer.js" diff --git a/packages/ipuaro/src/domain/value-objects/ChatMessage.ts b/packages/ipuaro/src/domain/value-objects/ChatMessage.ts new file mode 100644 index 0000000..ec29c73 --- /dev/null +++ b/packages/ipuaro/src/domain/value-objects/ChatMessage.ts @@ -0,0 +1,79 @@ +import type { ToolCall } from "./ToolCall.js" +import type { ToolResult } from "./ToolResult.js" + +/** + * Represents a message in the chat history. + */ + +export type MessageRole = "user" | "assistant" | "tool" | "system" + +export interface MessageStats { + /** Token count for this message */ + tokens: number + /** Response generation time in ms (for assistant messages) */ + timeMs: number + /** Number of tool calls in this message */ + toolCalls: number +} + +export interface ChatMessage { + /** Message role */ + role: MessageRole + /** Message content */ + content: string + /** Timestamp when message was created */ + timestamp: number + /** Tool calls made by assistant (if any) */ + toolCalls?: ToolCall[] + /** Tool results (for tool role messages) */ + toolResults?: ToolResult[] + /** Message statistics */ + stats?: MessageStats +} + +export function createUserMessage(content: string): ChatMessage { + return { + role: "user", + content, + timestamp: Date.now(), + } +} + +export function createAssistantMessage( + content: string, + toolCalls?: ToolCall[], + stats?: MessageStats, +): ChatMessage { + return { + role: "assistant", + content, + timestamp: Date.now(), + toolCalls, + stats, + } +} + +export function createToolMessage(results: ToolResult[]): ChatMessage { + return { + role: "tool", + content: results.map((r) => formatToolResult(r)).join("\n\n"), + timestamp: Date.now(), + toolResults: results, + } +} + +export function createSystemMessage(content: string): ChatMessage { + return { + role: "system", + content, + timestamp: Date.now(), + } +} + +function formatToolResult(result: ToolResult): string { + if (result.success) { + return `[${result.callId}] Success: ${JSON.stringify(result.data)}` + } + const errorMsg = result.error ?? "Unknown error" + return `[${result.callId}] Error: ${errorMsg}` +} diff --git a/packages/ipuaro/src/domain/value-objects/FileAST.ts b/packages/ipuaro/src/domain/value-objects/FileAST.ts new file mode 100644 index 0000000..5d4f5a7 --- /dev/null +++ b/packages/ipuaro/src/domain/value-objects/FileAST.ts @@ -0,0 +1,163 @@ +/** + * Represents parsed AST information for a file. + */ + +export interface ImportInfo { + /** Import name or alias */ + name: string + /** Source module path */ + from: string + /** Line number of import statement */ + line: number + /** Import type classification */ + type: "internal" | "external" | "builtin" + /** Whether it's a default import */ + isDefault: boolean +} + +export interface ExportInfo { + /** Exported name */ + name: string + /** Line number of export */ + line: number + /** Whether it's a default export */ + isDefault: boolean + /** Export type: function, class, variable, type */ + kind: "function" | "class" | "variable" | "type" | "interface" +} + +export interface ParameterInfo { + /** Parameter name */ + name: string + /** Parameter type (if available) */ + type?: string + /** Whether it's optional */ + optional: boolean + /** Whether it has a default value */ + hasDefault: boolean +} + +export interface FunctionInfo { + /** Function name */ + name: string + /** Start line number */ + lineStart: number + /** End line number */ + lineEnd: number + /** Function parameters */ + params: ParameterInfo[] + /** Whether function is async */ + isAsync: boolean + /** Whether function is exported */ + isExported: boolean + /** Return type (if available) */ + returnType?: string +} + +export interface MethodInfo { + /** Method name */ + name: string + /** Start line number */ + lineStart: number + /** End line number */ + lineEnd: number + /** Method parameters */ + params: ParameterInfo[] + /** Whether method is async */ + isAsync: boolean + /** Method visibility */ + visibility: "public" | "private" | "protected" + /** Whether it's static */ + isStatic: boolean +} + +export interface PropertyInfo { + /** Property name */ + name: string + /** Line number */ + line: number + /** Property type (if available) */ + type?: string + /** Property visibility */ + visibility: "public" | "private" | "protected" + /** Whether it's static */ + isStatic: boolean + /** Whether it's readonly */ + isReadonly: boolean +} + +export interface ClassInfo { + /** Class name */ + name: string + /** Start line number */ + lineStart: number + /** End line number */ + lineEnd: number + /** Class methods */ + methods: MethodInfo[] + /** Class properties */ + properties: PropertyInfo[] + /** Extended class name */ + extends?: string + /** Implemented interfaces */ + implements: string[] + /** Whether class is exported */ + isExported: boolean + /** Whether class is abstract */ + isAbstract: boolean +} + +export interface InterfaceInfo { + /** Interface name */ + name: string + /** Start line number */ + lineStart: number + /** End line number */ + lineEnd: number + /** Interface properties */ + properties: PropertyInfo[] + /** Extended interfaces */ + extends: string[] + /** Whether interface is exported */ + isExported: boolean +} + +export interface TypeAliasInfo { + /** Type alias name */ + name: string + /** Line number */ + line: number + /** Whether it's exported */ + isExported: boolean +} + +export interface FileAST { + /** Import statements */ + imports: ImportInfo[] + /** Export statements */ + exports: ExportInfo[] + /** Function declarations */ + functions: FunctionInfo[] + /** Class declarations */ + classes: ClassInfo[] + /** Interface declarations */ + interfaces: InterfaceInfo[] + /** Type alias declarations */ + typeAliases: TypeAliasInfo[] + /** Whether parsing encountered errors */ + parseError: boolean + /** Parse error message if any */ + parseErrorMessage?: string +} + +export function createEmptyFileAST(): FileAST { + return { + imports: [], + exports: [], + functions: [], + classes: [], + interfaces: [], + typeAliases: [], + parseError: false, + } +} diff --git a/packages/ipuaro/src/domain/value-objects/FileData.ts b/packages/ipuaro/src/domain/value-objects/FileData.ts new file mode 100644 index 0000000..cdb787e --- /dev/null +++ b/packages/ipuaro/src/domain/value-objects/FileData.ts @@ -0,0 +1,26 @@ +/** + * Represents file content with metadata for change detection. + */ +export interface FileData { + /** File content split into lines */ + lines: string[] + /** MD5 hash for change detection */ + hash: string + /** File size in bytes */ + size: number + /** Last modification timestamp (ms) */ + lastModified: number +} + +export function createFileData( + lines: string[], + hash: string, + size: number, + lastModified: number, +): FileData { + return { lines, hash, size, lastModified } +} + +export function isFileDataEqual(a: FileData, b: FileData): boolean { + return a.hash === b.hash +} diff --git a/packages/ipuaro/src/domain/value-objects/FileMeta.ts b/packages/ipuaro/src/domain/value-objects/FileMeta.ts new file mode 100644 index 0000000..49fd6bb --- /dev/null +++ b/packages/ipuaro/src/domain/value-objects/FileMeta.ts @@ -0,0 +1,50 @@ +/** + * Represents computed metadata about a file. + */ + +export interface ComplexityMetrics { + /** Lines of code (excluding empty and comments) */ + loc: number + /** Maximum nesting depth */ + nesting: number + /** Cyclomatic complexity score */ + cyclomaticComplexity: number + /** Overall complexity score (0-100) */ + score: number +} + +export interface FileMeta { + /** Complexity metrics for the file */ + complexity: ComplexityMetrics + /** Files that this file imports (internal paths) */ + dependencies: string[] + /** Files that import this file */ + dependents: string[] + /** Whether file is a dependency hub (>5 dependents) */ + isHub: boolean + /** Whether file is an entry point (index.ts or 0 dependents) */ + isEntryPoint: boolean + /** File type classification */ + fileType: "source" | "test" | "config" | "types" | "unknown" +} + +export function createFileMeta(partial: Partial = {}): FileMeta { + return { + complexity: { + loc: 0, + nesting: 0, + cyclomaticComplexity: 1, + score: 0, + }, + dependencies: [], + dependents: [], + isHub: false, + isEntryPoint: false, + fileType: "unknown", + ...partial, + } +} + +export function isHubFile(dependentCount: number): boolean { + return dependentCount > 5 +} diff --git a/packages/ipuaro/src/domain/value-objects/ToolCall.ts b/packages/ipuaro/src/domain/value-objects/ToolCall.ts new file mode 100644 index 0000000..c3bf776 --- /dev/null +++ b/packages/ipuaro/src/domain/value-objects/ToolCall.ts @@ -0,0 +1,27 @@ +/** + * Represents a tool call from the LLM. + */ + +export interface ToolCall { + /** Unique identifier for this call */ + id: string + /** Tool name */ + name: string + /** Tool parameters */ + params: Record + /** Timestamp when call was made */ + timestamp: number +} + +export function createToolCall( + id: string, + name: string, + params: Record, +): ToolCall { + return { + id, + name, + params, + timestamp: Date.now(), + } +} diff --git a/packages/ipuaro/src/domain/value-objects/ToolResult.ts b/packages/ipuaro/src/domain/value-objects/ToolResult.ts new file mode 100644 index 0000000..0710bda --- /dev/null +++ b/packages/ipuaro/src/domain/value-objects/ToolResult.ts @@ -0,0 +1,42 @@ +/** + * Represents the result of a tool execution. + */ + +export interface ToolResult { + /** Tool call ID this result belongs to */ + callId: string + /** Whether execution was successful */ + success: boolean + /** Result data (varies by tool) */ + data?: unknown + /** Error message if failed */ + error?: string + /** Execution time in milliseconds */ + executionTimeMs: number +} + +export function createSuccessResult( + callId: string, + data: unknown, + executionTimeMs: number, +): ToolResult { + return { + callId, + success: true, + data, + executionTimeMs, + } +} + +export function createErrorResult( + callId: string, + error: string, + executionTimeMs: number, +): ToolResult { + return { + callId, + success: false, + error, + executionTimeMs, + } +} diff --git a/packages/ipuaro/src/domain/value-objects/UndoEntry.ts b/packages/ipuaro/src/domain/value-objects/UndoEntry.ts new file mode 100644 index 0000000..f44d2d0 --- /dev/null +++ b/packages/ipuaro/src/domain/value-objects/UndoEntry.ts @@ -0,0 +1,50 @@ +/** + * Represents an undo entry for file changes. + */ + +export interface UndoEntry { + /** Unique identifier */ + id: string + /** Timestamp when change was made */ + timestamp: number + /** File path that was modified */ + filePath: string + /** Content before the change */ + previousContent: string[] + /** Content after the change */ + newContent: string[] + /** Human-readable description of the change */ + description: string + /** Tool call ID that made this change */ + toolCallId?: string +} + +export function createUndoEntry( + id: string, + filePath: string, + previousContent: string[], + newContent: string[], + description: string, + toolCallId?: string, +): UndoEntry { + return { + id, + timestamp: Date.now(), + filePath, + previousContent, + newContent, + description, + toolCallId, + } +} + +export function canUndo(entry: UndoEntry, currentContent: string[]): boolean { + return arraysEqual(entry.newContent, currentContent) +} + +function arraysEqual(a: string[], b: string[]): boolean { + if (a.length !== b.length) { + return false + } + return a.every((line, i) => line === b[i]) +} diff --git a/packages/ipuaro/src/domain/value-objects/index.ts b/packages/ipuaro/src/domain/value-objects/index.ts new file mode 100644 index 0000000..a0498e3 --- /dev/null +++ b/packages/ipuaro/src/domain/value-objects/index.ts @@ -0,0 +1,8 @@ +// Domain Value Objects +export * from "./FileData.js" +export * from "./FileAST.js" +export * from "./FileMeta.js" +export * from "./ChatMessage.js" +export * from "./ToolCall.js" +export * from "./ToolResult.js" +export * from "./UndoEntry.js" diff --git a/packages/ipuaro/src/index.ts b/packages/ipuaro/src/index.ts new file mode 100644 index 0000000..583488a --- /dev/null +++ b/packages/ipuaro/src/index.ts @@ -0,0 +1,17 @@ +/** + * @puaros/ipuaro - Local AI agent for codebase operations + * + * Main entry point for the library. + */ + +// Domain exports +export * from "./domain/index.js" + +// Application exports +export * from "./application/index.js" + +// Shared exports +export * from "./shared/index.js" + +// Version +export const VERSION = "0.1.0" diff --git a/packages/ipuaro/src/shared/config/index.ts b/packages/ipuaro/src/shared/config/index.ts new file mode 100644 index 0000000..895977d --- /dev/null +++ b/packages/ipuaro/src/shared/config/index.ts @@ -0,0 +1,2 @@ +// Config module exports +export * from "./loader.js" diff --git a/packages/ipuaro/src/shared/config/loader.ts b/packages/ipuaro/src/shared/config/loader.ts new file mode 100644 index 0000000..cfed951 --- /dev/null +++ b/packages/ipuaro/src/shared/config/loader.ts @@ -0,0 +1,89 @@ +import { existsSync, readFileSync } from "node:fs" +import { join } from "node:path" +import { Config, ConfigSchema, DEFAULT_CONFIG } from "../constants/config.js" + +const CONFIG_FILE_NAME = ".ipuaro.json" +const DEFAULT_CONFIG_PATH = "config/default.json" + +/** + * Load configuration from files. + * Priority: .ipuaro.json > config/default.json > defaults + */ +export function loadConfig(projectRoot: string): Config { + const configs: Partial[] = [] + + const defaultConfigPath = join(projectRoot, DEFAULT_CONFIG_PATH) + if (existsSync(defaultConfigPath)) { + try { + const content = readFileSync(defaultConfigPath, "utf-8") + configs.push(JSON.parse(content) as Partial) + } catch { + // Ignore parse errors for default config + } + } + + const projectConfigPath = join(projectRoot, CONFIG_FILE_NAME) + if (existsSync(projectConfigPath)) { + try { + const content = readFileSync(projectConfigPath, "utf-8") + configs.push(JSON.parse(content) as Partial) + } catch { + // Ignore parse errors for project config + } + } + + if (configs.length === 0) { + return DEFAULT_CONFIG + } + + const merged = deepMerge(DEFAULT_CONFIG, ...configs) + return ConfigSchema.parse(merged) +} + +/** + * Deep merge objects. + */ +function deepMerge>(target: T, ...sources: Partial[]): T { + const result = { ...target } + + for (const source of sources) { + for (const key in source) { + const sourceValue = source[key] + const targetValue = result[key] + + if (isPlainObject(sourceValue) && isPlainObject(targetValue)) { + result[key] = deepMerge( + targetValue as Record, + sourceValue as Record, + ) as T[Extract] + } else if (sourceValue !== undefined) { + result[key] = sourceValue as T[Extract] + } + } + } + + return result +} + +function isPlainObject(value: unknown): value is Record { + return typeof value === "object" && value !== null && !Array.isArray(value) +} + +/** + * Validate configuration. + */ +export function validateConfig(config: unknown): config is Config { + const result = ConfigSchema.safeParse(config) + return result.success +} + +/** + * Get config validation errors. + */ +export function getConfigErrors(config: unknown): string[] { + const result = ConfigSchema.safeParse(config) + if (result.success) { + return [] + } + return result.error.errors.map((e) => `${e.path.join(".")}: ${e.message}`) +} diff --git a/packages/ipuaro/src/shared/constants/config.ts b/packages/ipuaro/src/shared/constants/config.ts new file mode 100644 index 0000000..5f08099 --- /dev/null +++ b/packages/ipuaro/src/shared/constants/config.ts @@ -0,0 +1,107 @@ +import { z } from "zod" + +/** + * Redis configuration schema. + */ +export const RedisConfigSchema = z.object({ + host: z.string().default("localhost"), + port: z.number().int().positive().default(6379), + db: z.number().int().min(0).max(15).default(0), + password: z.string().optional(), + keyPrefix: z.string().default("ipuaro:"), +}) + +/** + * LLM configuration schema. + */ +export const LLMConfigSchema = z.object({ + model: z.string().default("qwen2.5-coder:7b-instruct"), + contextWindow: z.number().int().positive().default(128_000), + temperature: z.number().min(0).max(2).default(0.1), + host: z.string().default("http://localhost:11434"), + timeout: z.number().int().positive().default(120_000), +}) + +/** + * Project configuration schema. + */ +export const ProjectConfigSchema = z.object({ + ignorePatterns: z + .array(z.string()) + .default(["node_modules", "dist", "build", ".git", ".next", ".nuxt", "coverage", ".cache"]), + binaryExtensions: z + .array(z.string()) + .default([ + ".png", + ".jpg", + ".jpeg", + ".gif", + ".ico", + ".svg", + ".woff", + ".woff2", + ".ttf", + ".eot", + ".mp3", + ".mp4", + ".webm", + ".pdf", + ".zip", + ".tar", + ".gz", + ]), + maxFileSize: z.number().int().positive().default(1_000_000), + supportedExtensions: z + .array(z.string()) + .default([".ts", ".tsx", ".js", ".jsx", ".json", ".yaml", ".yml"]), +}) + +/** + * Watchdog configuration schema. + */ +export const WatchdogConfigSchema = z.object({ + enabled: z.boolean().default(true), + debounceMs: z.number().int().positive().default(500), +}) + +/** + * Undo configuration schema. + */ +export const UndoConfigSchema = z.object({ + stackSize: z.number().int().positive().default(10), +}) + +/** + * Edit configuration schema. + */ +export const EditConfigSchema = z.object({ + autoApply: z.boolean().default(false), +}) + +/** + * Full configuration schema. + */ +export const ConfigSchema = z.object({ + redis: RedisConfigSchema.default({}), + llm: LLMConfigSchema.default({}), + project: ProjectConfigSchema.default({}), + watchdog: WatchdogConfigSchema.default({}), + undo: UndoConfigSchema.default({}), + edit: EditConfigSchema.default({}), +}) + +/** + * Configuration type inferred from schema. + */ +export type Config = z.infer +export type RedisConfig = z.infer +export type LLMConfig = z.infer +export type ProjectConfig = z.infer +export type WatchdogConfig = z.infer +export type UndoConfig = z.infer +export type EditConfig = z.infer + +/** + * Default configuration. + */ +export const DEFAULT_CONFIG: Config = ConfigSchema.parse({}) diff --git a/packages/ipuaro/src/shared/constants/index.ts b/packages/ipuaro/src/shared/constants/index.ts new file mode 100644 index 0000000..4215e14 --- /dev/null +++ b/packages/ipuaro/src/shared/constants/index.ts @@ -0,0 +1,3 @@ +// Shared constants +export * from "./config.js" +export * from "./messages.js" diff --git a/packages/ipuaro/src/shared/constants/messages.ts b/packages/ipuaro/src/shared/constants/messages.ts new file mode 100644 index 0000000..350214b --- /dev/null +++ b/packages/ipuaro/src/shared/constants/messages.ts @@ -0,0 +1,56 @@ +/** + * User-facing messages and labels. + */ + +export const MESSAGES = { + // Status messages + STATUS_READY: "Ready", + STATUS_THINKING: "Thinking...", + STATUS_INDEXING: "Indexing...", + STATUS_ERROR: "Error", + + // Error messages + ERROR_REDIS_UNAVAILABLE: "Redis is not available. Please start Redis server.", + ERROR_OLLAMA_UNAVAILABLE: "Ollama is not available. Please start Ollama.", + ERROR_MODEL_NOT_FOUND: "Model not found. Would you like to pull it?", + ERROR_FILE_NOT_FOUND: "File not found", + ERROR_PARSE_FAILED: "Failed to parse file", + ERROR_TOOL_FAILED: "Tool execution failed", + ERROR_COMMAND_BLACKLISTED: "Command is blacklisted for security reasons", + ERROR_PATH_OUTSIDE_PROJECT: "Path is outside project directory", + + // Confirmation messages + CONFIRM_APPLY_EDIT: "Apply this edit?", + CONFIRM_DELETE_FILE: "Delete this file?", + CONFIRM_RUN_COMMAND: "Run this command?", + CONFIRM_CREATE_FILE: "Create this file?", + CONFIRM_GIT_COMMIT: "Create this commit?", + + // Info messages + INFO_SESSION_LOADED: "Session loaded", + INFO_SESSION_CREATED: "New session created", + INFO_INDEXING_COMPLETE: "Indexing complete", + INFO_EDIT_APPLIED: "Edit applied", + INFO_EDIT_CANCELLED: "Edit cancelled", + INFO_UNDO_SUCCESS: "Change reverted", + INFO_UNDO_EMPTY: "Nothing to undo", + + // Help text + HELP_COMMANDS: `Available commands: + /help - Show this help + /clear - Clear chat history + /undo - Revert last file change + /sessions - Manage sessions + /status - Show status info + /reindex - Force reindexing + /auto-apply - Toggle auto-apply mode`, + + HELP_HOTKEYS: `Hotkeys: + Ctrl+C - Interrupt / Exit + Ctrl+D - Exit with save + Ctrl+Z - Undo last change + ↑/↓ - Navigate history + Tab - Autocomplete paths`, +} as const + +export type MessageKey = keyof typeof MESSAGES diff --git a/packages/ipuaro/src/shared/errors/IpuaroError.ts b/packages/ipuaro/src/shared/errors/IpuaroError.ts new file mode 100644 index 0000000..e4338f8 --- /dev/null +++ b/packages/ipuaro/src/shared/errors/IpuaroError.ts @@ -0,0 +1,78 @@ +/** + * Error types for ipuaro. + */ +export type ErrorType = + | "redis" + | "parse" + | "llm" + | "file" + | "command" + | "conflict" + | "validation" + | "timeout" + | "unknown" + +/** + * Base error class for ipuaro. + */ +export class IpuaroError extends Error { + readonly type: ErrorType + readonly recoverable: boolean + readonly suggestion?: string + + constructor(type: ErrorType, message: string, recoverable = true, suggestion?: string) { + super(message) + this.name = "IpuaroError" + this.type = type + this.recoverable = recoverable + this.suggestion = suggestion + } + + static redis(message: string): IpuaroError { + return new IpuaroError( + "redis", + message, + false, + "Please ensure Redis is running: redis-server", + ) + } + + static parse(message: string, filePath?: string): IpuaroError { + const msg = filePath ? `${message} in ${filePath}` : message + return new IpuaroError("parse", msg, true, "File will be skipped") + } + + static llm(message: string): IpuaroError { + return new IpuaroError( + "llm", + message, + true, + "Please ensure Ollama is running and model is available", + ) + } + + static file(message: string): IpuaroError { + return new IpuaroError("file", message, true) + } + + static command(message: string): IpuaroError { + return new IpuaroError("command", message, true) + } + + static conflict(message: string): IpuaroError { + return new IpuaroError( + "conflict", + message, + true, + "File was modified externally. Regenerate or skip.", + ) + } + + static validation(message: string): IpuaroError { + return new IpuaroError("validation", message, true) + } + + static timeout(message: string): IpuaroError { + return new IpuaroError("timeout", message, true, "Try again or increase timeout") + } +} diff --git a/packages/ipuaro/src/shared/errors/index.ts b/packages/ipuaro/src/shared/errors/index.ts new file mode 100644 index 0000000..1f5bd90 --- /dev/null +++ b/packages/ipuaro/src/shared/errors/index.ts @@ -0,0 +1,2 @@ +// Shared errors +export * from "./IpuaroError.js" diff --git a/packages/ipuaro/src/shared/index.ts b/packages/ipuaro/src/shared/index.ts new file mode 100644 index 0000000..80d3258 --- /dev/null +++ b/packages/ipuaro/src/shared/index.ts @@ -0,0 +1,6 @@ +// Shared module exports +export * from "./config/index.js" +export * from "./constants/index.js" +export * from "./errors/index.js" +export * from "./types/index.js" +export * from "./utils/index.js" diff --git a/packages/ipuaro/src/shared/types/index.ts b/packages/ipuaro/src/shared/types/index.ts new file mode 100644 index 0000000..def57d2 --- /dev/null +++ b/packages/ipuaro/src/shared/types/index.ts @@ -0,0 +1,66 @@ +/** + * Shared types for ipuaro. + */ + +/** + * Application status. + */ +export type AppStatus = "ready" | "thinking" | "indexing" | "error" + +/** + * File language type. + */ +export type FileLanguage = "ts" | "tsx" | "js" | "jsx" | "json" | "yaml" | "unknown" + +/** + * User choice for confirmations. + */ +export type ConfirmChoice = "apply" | "cancel" | "edit" + +/** + * User choice for errors. + */ +export type ErrorChoice = "retry" | "skip" | "abort" + +/** + * Project structure node. + */ +export interface ProjectNode { + name: string + type: "file" | "directory" + path: string + children?: ProjectNode[] +} + +/** + * Generic result type. + */ +export type Result = { success: true; data: T } | { success: false; error: E } + +/** + * Create success result. + */ +export function ok(data: T): Result { + return { success: true, data } +} + +/** + * Create error result. + */ +export function err(error: E): Result { + return { success: false, error } +} + +/** + * Check if result is success. + */ +export function isOk(result: Result): result is { success: true; data: T } { + return result.success +} + +/** + * Check if result is error. + */ +export function isErr(result: Result): result is { success: false; error: E } { + return !result.success +} diff --git a/packages/ipuaro/src/shared/utils/hash.ts b/packages/ipuaro/src/shared/utils/hash.ts new file mode 100644 index 0000000..cb047e8 --- /dev/null +++ b/packages/ipuaro/src/shared/utils/hash.ts @@ -0,0 +1,22 @@ +import { createHash } from "node:crypto" + +/** + * Calculate MD5 hash of content. + */ +export function md5(content: string): string { + return createHash("md5").update(content).digest("hex") +} + +/** + * Calculate MD5 hash of file lines. + */ +export function hashLines(lines: string[]): string { + return md5(lines.join("\n")) +} + +/** + * Generate short hash for IDs. + */ +export function shortHash(content: string, length = 8): string { + return md5(content).slice(0, length) +} diff --git a/packages/ipuaro/src/shared/utils/index.ts b/packages/ipuaro/src/shared/utils/index.ts new file mode 100644 index 0000000..a694882 --- /dev/null +++ b/packages/ipuaro/src/shared/utils/index.ts @@ -0,0 +1,3 @@ +// Shared utilities +export * from "./hash.js" +export * from "./tokens.js" diff --git a/packages/ipuaro/src/shared/utils/tokens.ts b/packages/ipuaro/src/shared/utils/tokens.ts new file mode 100644 index 0000000..7d0208b --- /dev/null +++ b/packages/ipuaro/src/shared/utils/tokens.ts @@ -0,0 +1,41 @@ +/** + * Simple token estimation utilities. + * Uses approximation: ~4 characters per token for English text. + */ + +const CHARS_PER_TOKEN = 4 + +/** + * Estimate token count for text. + */ +export function estimateTokens(text: string): number { + return Math.ceil(text.length / CHARS_PER_TOKEN) +} + +/** + * Estimate token count for array of strings. + */ +export function estimateTokensForLines(lines: string[]): number { + return estimateTokens(lines.join("\n")) +} + +/** + * Truncate text to approximate token limit. + */ +export function truncateToTokens(text: string, maxTokens: number): string { + const maxChars = maxTokens * CHARS_PER_TOKEN + if (text.length <= maxChars) { + return text + } + return `${text.slice(0, maxChars)}...` +} + +/** + * Format token count for display. + */ +export function formatTokenCount(tokens: number): string { + if (tokens >= 1000) { + return `${(tokens / 1000).toFixed(1)}k` + } + return tokens.toString() +} diff --git a/packages/ipuaro/tests/unit/domain/entities/Project.test.ts b/packages/ipuaro/tests/unit/domain/entities/Project.test.ts new file mode 100644 index 0000000..069ccb3 --- /dev/null +++ b/packages/ipuaro/tests/unit/domain/entities/Project.test.ts @@ -0,0 +1,106 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from "vitest" +import { Project } from "../../../../src/domain/entities/Project.js" + +describe("Project", () => { + beforeEach(() => { + vi.useFakeTimers() + vi.setSystemTime(new Date("2025-01-01T00:00:00Z")) + }) + + afterEach(() => { + vi.useRealTimers() + }) + + describe("constructor", () => { + it("should create project with generated name", () => { + const project = new Project("/home/user/projects/myapp") + + expect(project.rootPath).toBe("/home/user/projects/myapp") + expect(project.name).toBe("projects-myapp") + expect(project.createdAt).toBe(Date.now()) + expect(project.lastIndexedAt).toBeNull() + expect(project.fileCount).toBe(0) + expect(project.indexingInProgress).toBe(false) + }) + + it("should accept custom createdAt", () => { + const customTime = 1000000 + const project = new Project("/path", customTime) + + expect(project.createdAt).toBe(customTime) + }) + }) + + describe("generateProjectName", () => { + it("should generate name from parent and project folder", () => { + expect(Project.generateProjectName("/home/user/projects/myapp")).toBe("projects-myapp") + }) + + it("should handle root-level project", () => { + expect(Project.generateProjectName("/myapp")).toBe("myapp") + }) + }) + + describe("indexing lifecycle", () => { + it("should mark indexing started", () => { + const project = new Project("/path") + + project.markIndexingStarted() + + expect(project.indexingInProgress).toBe(true) + }) + + it("should mark indexing completed", () => { + const project = new Project("/path") + project.markIndexingStarted() + + project.markIndexingCompleted(100) + + expect(project.indexingInProgress).toBe(false) + expect(project.lastIndexedAt).toBe(Date.now()) + expect(project.fileCount).toBe(100) + }) + + it("should mark indexing failed", () => { + const project = new Project("/path") + project.markIndexingStarted() + + project.markIndexingFailed() + + expect(project.indexingInProgress).toBe(false) + expect(project.lastIndexedAt).toBeNull() + }) + }) + + describe("isIndexed", () => { + it("should return false when not indexed", () => { + const project = new Project("/path") + + expect(project.isIndexed()).toBe(false) + }) + + it("should return true when indexed", () => { + const project = new Project("/path") + project.markIndexingCompleted(10) + + expect(project.isIndexed()).toBe(true) + }) + }) + + describe("getTimeSinceIndexed", () => { + it("should return null when not indexed", () => { + const project = new Project("/path") + + expect(project.getTimeSinceIndexed()).toBeNull() + }) + + it("should return time since last indexed", () => { + const project = new Project("/path") + project.markIndexingCompleted(10) + + vi.advanceTimersByTime(5000) + + expect(project.getTimeSinceIndexed()).toBe(5000) + }) + }) +}) diff --git a/packages/ipuaro/tests/unit/domain/entities/Session.test.ts b/packages/ipuaro/tests/unit/domain/entities/Session.test.ts new file mode 100644 index 0000000..f0a93c4 --- /dev/null +++ b/packages/ipuaro/tests/unit/domain/entities/Session.test.ts @@ -0,0 +1,165 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from "vitest" +import { Session } from "../../../../src/domain/entities/Session.js" +import { createUserMessage } from "../../../../src/domain/value-objects/ChatMessage.js" +import type { UndoEntry } from "../../../../src/domain/value-objects/UndoEntry.js" + +describe("Session", () => { + beforeEach(() => { + vi.useFakeTimers() + vi.setSystemTime(new Date("2025-01-01T00:00:00Z")) + }) + + afterEach(() => { + vi.useRealTimers() + }) + + it("should create session with defaults", () => { + const session = new Session("session-1", "test-project") + + expect(session.id).toBe("session-1") + expect(session.projectName).toBe("test-project") + expect(session.history).toEqual([]) + expect(session.undoStack).toEqual([]) + expect(session.stats.totalTokens).toBe(0) + }) + + describe("addMessage", () => { + it("should add message to history", () => { + const session = new Session("1", "proj") + const msg = createUserMessage("Hello") + + session.addMessage(msg) + + expect(session.history).toHaveLength(1) + expect(session.history[0]).toBe(msg) + }) + + it("should update stats from message", () => { + const session = new Session("1", "proj") + const msg = { + role: "assistant" as const, + content: "Hi", + timestamp: Date.now(), + stats: { tokens: 50, timeMs: 100, toolCalls: 2 }, + } + + session.addMessage(msg) + + expect(session.stats.totalTokens).toBe(50) + expect(session.stats.totalTimeMs).toBe(100) + expect(session.stats.toolCalls).toBe(2) + }) + }) + + describe("undoStack", () => { + it("should add undo entry", () => { + const session = new Session("1", "proj") + const entry: UndoEntry = { + id: "undo-1", + timestamp: Date.now(), + filePath: "test.ts", + previousContent: ["old"], + newContent: ["new"], + description: "Edit", + } + + session.addUndoEntry(entry) + + expect(session.undoStack).toHaveLength(1) + }) + + it("should limit undo stack size", () => { + const session = new Session("1", "proj") + + for (let i = 0; i < 15; i++) { + session.addUndoEntry({ + id: `undo-${i}`, + timestamp: Date.now(), + filePath: "test.ts", + previousContent: [], + newContent: [], + description: `Edit ${i}`, + }) + } + + expect(session.undoStack).toHaveLength(10) + expect(session.undoStack[0].id).toBe("undo-5") + }) + + it("should pop undo entry", () => { + const session = new Session("1", "proj") + const entry: UndoEntry = { + id: "undo-1", + timestamp: Date.now(), + filePath: "test.ts", + previousContent: [], + newContent: [], + description: "Edit", + } + + session.addUndoEntry(entry) + const popped = session.popUndoEntry() + + expect(popped).toBe(entry) + expect(session.undoStack).toHaveLength(0) + }) + }) + + describe("inputHistory", () => { + it("should add input to history", () => { + const session = new Session("1", "proj") + + session.addInputToHistory("command 1") + session.addInputToHistory("command 2") + + expect(session.inputHistory).toEqual(["command 1", "command 2"]) + }) + + it("should not add duplicate consecutive inputs", () => { + const session = new Session("1", "proj") + + session.addInputToHistory("command") + session.addInputToHistory("command") + + expect(session.inputHistory).toHaveLength(1) + }) + + it("should not add empty inputs", () => { + const session = new Session("1", "proj") + + session.addInputToHistory("") + session.addInputToHistory(" ") + + expect(session.inputHistory).toHaveLength(0) + }) + }) + + describe("clearHistory", () => { + it("should clear history and context", () => { + const session = new Session("1", "proj") + session.addMessage(createUserMessage("Hello")) + session.context.filesInContext = ["file1.ts"] + + session.clearHistory() + + expect(session.history).toHaveLength(0) + expect(session.context.filesInContext).toHaveLength(0) + }) + }) + + describe("getSessionDurationFormatted", () => { + it("should format minutes only", () => { + const session = new Session("1", "proj") + vi.advanceTimersByTime(15 * 60 * 1000) + + expect(session.getSessionDurationFormatted()).toBe("15m") + }) + + it("should format hours and minutes", () => { + const session = new Session("1", "proj") + vi.advanceTimersByTime(90 * 60 * 1000) + + expect(session.getSessionDurationFormatted()).toBe("1h 30m") + }) + }) +}) diff --git a/packages/ipuaro/tests/unit/domain/value-objects/ChatMessage.test.ts b/packages/ipuaro/tests/unit/domain/value-objects/ChatMessage.test.ts new file mode 100644 index 0000000..da76b00 --- /dev/null +++ b/packages/ipuaro/tests/unit/domain/value-objects/ChatMessage.test.ts @@ -0,0 +1,80 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from "vitest" +import { + createUserMessage, + createAssistantMessage, + createToolMessage, + createSystemMessage, +} from "../../../../src/domain/value-objects/ChatMessage.js" + +describe("ChatMessage", () => { + beforeEach(() => { + vi.useFakeTimers() + vi.setSystemTime(new Date("2025-01-01T00:00:00Z")) + }) + + afterEach(() => { + vi.useRealTimers() + }) + + describe("createUserMessage", () => { + it("should create user message", () => { + const msg = createUserMessage("Hello") + + expect(msg.role).toBe("user") + expect(msg.content).toBe("Hello") + expect(msg.timestamp).toBe(Date.now()) + }) + }) + + describe("createAssistantMessage", () => { + it("should create assistant message without tool calls", () => { + const msg = createAssistantMessage("Response") + + expect(msg.role).toBe("assistant") + expect(msg.content).toBe("Response") + expect(msg.toolCalls).toBeUndefined() + }) + + it("should create assistant message with tool calls", () => { + const toolCalls = [ + { id: "1", name: "get_lines", params: {}, timestamp: Date.now() }, + ] + const stats = { tokens: 100, timeMs: 500, toolCalls: 1 } + const msg = createAssistantMessage("Response", toolCalls, stats) + + expect(msg.toolCalls).toEqual(toolCalls) + expect(msg.stats).toEqual(stats) + }) + }) + + describe("createToolMessage", () => { + it("should create tool message with results", () => { + const results = [ + { callId: "1", success: true, data: "data", executionTimeMs: 10 }, + ] + const msg = createToolMessage(results) + + expect(msg.role).toBe("tool") + expect(msg.toolResults).toEqual(results) + expect(msg.content).toContain("[1] Success") + }) + + it("should format error results", () => { + const results = [ + { callId: "2", success: false, error: "Not found", executionTimeMs: 5 }, + ] + const msg = createToolMessage(results) + + expect(msg.content).toContain("[2] Error: Not found") + }) + }) + + describe("createSystemMessage", () => { + it("should create system message", () => { + const msg = createSystemMessage("System prompt") + + expect(msg.role).toBe("system") + expect(msg.content).toBe("System prompt") + }) + }) +}) diff --git a/packages/ipuaro/tests/unit/domain/value-objects/FileAST.test.ts b/packages/ipuaro/tests/unit/domain/value-objects/FileAST.test.ts new file mode 100644 index 0000000..bb758a9 --- /dev/null +++ b/packages/ipuaro/tests/unit/domain/value-objects/FileAST.test.ts @@ -0,0 +1,19 @@ +import { describe, it, expect } from "vitest" +import { createEmptyFileAST } from "../../../../src/domain/value-objects/FileAST.js" + +describe("FileAST", () => { + describe("createEmptyFileAST", () => { + it("should create empty AST with all arrays empty", () => { + const ast = createEmptyFileAST() + + expect(ast.imports).toEqual([]) + expect(ast.exports).toEqual([]) + expect(ast.functions).toEqual([]) + expect(ast.classes).toEqual([]) + expect(ast.interfaces).toEqual([]) + expect(ast.typeAliases).toEqual([]) + expect(ast.parseError).toBe(false) + expect(ast.parseErrorMessage).toBeUndefined() + }) + }) +}) diff --git a/packages/ipuaro/tests/unit/domain/value-objects/FileData.test.ts b/packages/ipuaro/tests/unit/domain/value-objects/FileData.test.ts new file mode 100644 index 0000000..97b9a52 --- /dev/null +++ b/packages/ipuaro/tests/unit/domain/value-objects/FileData.test.ts @@ -0,0 +1,39 @@ +import { describe, it, expect } from "vitest" +import { + createFileData, + isFileDataEqual, +} from "../../../../src/domain/value-objects/FileData.js" + +describe("FileData", () => { + describe("createFileData", () => { + it("should create FileData with all fields", () => { + const lines = ["line1", "line2"] + const hash = "abc123" + const size = 100 + const lastModified = Date.now() + + const result = createFileData(lines, hash, size, lastModified) + + expect(result.lines).toEqual(lines) + expect(result.hash).toBe(hash) + expect(result.size).toBe(size) + expect(result.lastModified).toBe(lastModified) + }) + }) + + describe("isFileDataEqual", () => { + it("should return true for equal hashes", () => { + const a = createFileData(["a"], "hash1", 1, 1) + const b = createFileData(["b"], "hash1", 2, 2) + + expect(isFileDataEqual(a, b)).toBe(true) + }) + + it("should return false for different hashes", () => { + const a = createFileData(["a"], "hash1", 1, 1) + const b = createFileData(["a"], "hash2", 1, 1) + + expect(isFileDataEqual(a, b)).toBe(false) + }) + }) +}) diff --git a/packages/ipuaro/tests/unit/domain/value-objects/FileMeta.test.ts b/packages/ipuaro/tests/unit/domain/value-objects/FileMeta.test.ts new file mode 100644 index 0000000..eb9376e --- /dev/null +++ b/packages/ipuaro/tests/unit/domain/value-objects/FileMeta.test.ts @@ -0,0 +1,48 @@ +import { describe, it, expect } from "vitest" +import { + createFileMeta, + isHubFile, +} from "../../../../src/domain/value-objects/FileMeta.js" + +describe("FileMeta", () => { + describe("createFileMeta", () => { + it("should create FileMeta with defaults", () => { + const meta = createFileMeta() + + expect(meta.complexity.loc).toBe(0) + expect(meta.complexity.nesting).toBe(0) + expect(meta.complexity.cyclomaticComplexity).toBe(1) + expect(meta.complexity.score).toBe(0) + expect(meta.dependencies).toEqual([]) + expect(meta.dependents).toEqual([]) + expect(meta.isHub).toBe(false) + expect(meta.isEntryPoint).toBe(false) + expect(meta.fileType).toBe("unknown") + }) + + it("should merge partial values", () => { + const meta = createFileMeta({ + isHub: true, + fileType: "source", + dependencies: ["dep1.ts"], + }) + + expect(meta.isHub).toBe(true) + expect(meta.fileType).toBe("source") + expect(meta.dependencies).toEqual(["dep1.ts"]) + expect(meta.dependents).toEqual([]) + }) + }) + + describe("isHubFile", () => { + it("should return true for >5 dependents", () => { + expect(isHubFile(6)).toBe(true) + expect(isHubFile(10)).toBe(true) + }) + + it("should return false for <=5 dependents", () => { + expect(isHubFile(5)).toBe(false) + expect(isHubFile(0)).toBe(false) + }) + }) +}) diff --git a/packages/ipuaro/tests/unit/domain/value-objects/ToolCall.test.ts b/packages/ipuaro/tests/unit/domain/value-objects/ToolCall.test.ts new file mode 100644 index 0000000..c94668b --- /dev/null +++ b/packages/ipuaro/tests/unit/domain/value-objects/ToolCall.test.ts @@ -0,0 +1,31 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from "vitest" +import { createToolCall } from "../../../../src/domain/value-objects/ToolCall.js" + +describe("ToolCall", () => { + beforeEach(() => { + vi.useFakeTimers() + vi.setSystemTime(new Date("2025-01-01T00:00:00Z")) + }) + + afterEach(() => { + vi.useRealTimers() + }) + + describe("createToolCall", () => { + it("should create tool call with all fields", () => { + const params = { path: "test.ts", line: 10 } + const call = createToolCall("call-1", "get_lines", params) + + expect(call.id).toBe("call-1") + expect(call.name).toBe("get_lines") + expect(call.params).toEqual(params) + expect(call.timestamp).toBe(Date.now()) + }) + + it("should handle empty params", () => { + const call = createToolCall("call-2", "git_status", {}) + + expect(call.params).toEqual({}) + }) + }) +}) diff --git a/packages/ipuaro/tests/unit/domain/value-objects/ToolResult.test.ts b/packages/ipuaro/tests/unit/domain/value-objects/ToolResult.test.ts new file mode 100644 index 0000000..04919f4 --- /dev/null +++ b/packages/ipuaro/tests/unit/domain/value-objects/ToolResult.test.ts @@ -0,0 +1,32 @@ +import { describe, it, expect } from "vitest" +import { + createSuccessResult, + createErrorResult, +} from "../../../../src/domain/value-objects/ToolResult.js" + +describe("ToolResult", () => { + describe("createSuccessResult", () => { + it("should create success result", () => { + const data = { lines: ["line1", "line2"] } + const result = createSuccessResult("call-1", data, 50) + + expect(result.callId).toBe("call-1") + expect(result.success).toBe(true) + expect(result.data).toEqual(data) + expect(result.executionTimeMs).toBe(50) + expect(result.error).toBeUndefined() + }) + }) + + describe("createErrorResult", () => { + it("should create error result", () => { + const result = createErrorResult("call-2", "File not found", 10) + + expect(result.callId).toBe("call-2") + expect(result.success).toBe(false) + expect(result.error).toBe("File not found") + expect(result.executionTimeMs).toBe(10) + expect(result.data).toBeUndefined() + }) + }) +}) diff --git a/packages/ipuaro/tests/unit/domain/value-objects/UndoEntry.test.ts b/packages/ipuaro/tests/unit/domain/value-objects/UndoEntry.test.ts new file mode 100644 index 0000000..81df792 --- /dev/null +++ b/packages/ipuaro/tests/unit/domain/value-objects/UndoEntry.test.ts @@ -0,0 +1,87 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from "vitest" +import { + createUndoEntry, + canUndo, +} from "../../../../src/domain/value-objects/UndoEntry.js" + +describe("UndoEntry", () => { + beforeEach(() => { + vi.useFakeTimers() + vi.setSystemTime(new Date("2025-01-01T00:00:00Z")) + }) + + afterEach(() => { + vi.useRealTimers() + }) + + describe("createUndoEntry", () => { + it("should create undo entry with all fields", () => { + const entry = createUndoEntry( + "undo-1", + "test.ts", + ["old line"], + ["new line"], + "Edit line 1" + ) + + expect(entry.id).toBe("undo-1") + expect(entry.filePath).toBe("test.ts") + expect(entry.previousContent).toEqual(["old line"]) + expect(entry.newContent).toEqual(["new line"]) + expect(entry.description).toBe("Edit line 1") + expect(entry.timestamp).toBe(Date.now()) + expect(entry.toolCallId).toBeUndefined() + }) + + it("should create undo entry with toolCallId", () => { + const entry = createUndoEntry( + "undo-2", + "test.ts", + [], + [], + "Create file", + "tool-123" + ) + + expect(entry.toolCallId).toBe("tool-123") + }) + }) + + describe("canUndo", () => { + it("should return true when current content matches newContent", () => { + const entry = createUndoEntry( + "undo-1", + "test.ts", + ["old"], + ["new"], + "Edit" + ) + + expect(canUndo(entry, ["new"])).toBe(true) + }) + + it("should return false when content differs", () => { + const entry = createUndoEntry( + "undo-1", + "test.ts", + ["old"], + ["new"], + "Edit" + ) + + expect(canUndo(entry, ["modified"])).toBe(false) + }) + + it("should return false when length differs", () => { + const entry = createUndoEntry( + "undo-1", + "test.ts", + ["old"], + ["new"], + "Edit" + ) + + expect(canUndo(entry, ["new", "extra"])).toBe(false) + }) + }) +}) diff --git a/packages/ipuaro/tests/unit/shared/config/loader.test.ts b/packages/ipuaro/tests/unit/shared/config/loader.test.ts new file mode 100644 index 0000000..3263477 --- /dev/null +++ b/packages/ipuaro/tests/unit/shared/config/loader.test.ts @@ -0,0 +1,80 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from "vitest" +import { loadConfig, validateConfig, getConfigErrors } from "../../../../src/shared/config/loader.js" +import { DEFAULT_CONFIG } from "../../../../src/shared/constants/config.js" +import * as fs from "node:fs" + +vi.mock("node:fs") + +describe("config loader", () => { + beforeEach(() => { + vi.resetAllMocks() + }) + + afterEach(() => { + vi.restoreAllMocks() + }) + + describe("loadConfig", () => { + it("should return default config when no files exist", () => { + vi.mocked(fs.existsSync).mockReturnValue(false) + + const config = loadConfig("/project") + + expect(config).toEqual(DEFAULT_CONFIG) + }) + + it("should merge project config with defaults", () => { + vi.mocked(fs.existsSync).mockImplementation((path) => { + return path === "/project/.ipuaro.json" + }) + vi.mocked(fs.readFileSync).mockReturnValue( + JSON.stringify({ llm: { model: "custom-model" } }) + ) + + const config = loadConfig("/project") + + expect(config.llm.model).toBe("custom-model") + expect(config.redis.host).toBe("localhost") + }) + + it("should handle invalid JSON gracefully", () => { + vi.mocked(fs.existsSync).mockReturnValue(true) + vi.mocked(fs.readFileSync).mockReturnValue("invalid json") + + const config = loadConfig("/project") + + expect(config).toEqual(DEFAULT_CONFIG) + }) + }) + + describe("validateConfig", () => { + it("should return true for valid config", () => { + expect(validateConfig(DEFAULT_CONFIG)).toBe(true) + }) + + it("should return true for partial valid config", () => { + expect(validateConfig({ redis: { host: "redis.local" } })).toBe(true) + }) + + it("should return false for invalid config", () => { + expect(validateConfig({ redis: { port: "not a number" } })).toBe(false) + }) + }) + + describe("getConfigErrors", () => { + it("should return empty array for valid config", () => { + const errors = getConfigErrors(DEFAULT_CONFIG) + + expect(errors).toHaveLength(0) + }) + + it("should return errors for invalid config", () => { + const errors = getConfigErrors({ + redis: { port: "invalid" }, + }) + + expect(errors.length).toBeGreaterThan(0) + expect(errors[0]).toContain("redis.port") + }) + }) +}) diff --git a/packages/ipuaro/tests/unit/shared/constants/messages.test.ts b/packages/ipuaro/tests/unit/shared/constants/messages.test.ts new file mode 100644 index 0000000..22bf3ab --- /dev/null +++ b/packages/ipuaro/tests/unit/shared/constants/messages.test.ts @@ -0,0 +1,48 @@ +import { describe, it, expect } from "vitest" +import { MESSAGES } from "../../../../src/shared/constants/messages.js" + +describe("MESSAGES", () => { + it("should have status messages", () => { + expect(MESSAGES.STATUS_READY).toBe("Ready") + expect(MESSAGES.STATUS_THINKING).toBe("Thinking...") + expect(MESSAGES.STATUS_INDEXING).toBe("Indexing...") + expect(MESSAGES.STATUS_ERROR).toBe("Error") + }) + + it("should have error messages", () => { + expect(MESSAGES.ERROR_REDIS_UNAVAILABLE).toContain("Redis") + expect(MESSAGES.ERROR_OLLAMA_UNAVAILABLE).toContain("Ollama") + expect(MESSAGES.ERROR_MODEL_NOT_FOUND).toContain("Model") + expect(MESSAGES.ERROR_FILE_NOT_FOUND).toBe("File not found") + expect(MESSAGES.ERROR_PARSE_FAILED).toContain("parse") + expect(MESSAGES.ERROR_TOOL_FAILED).toContain("Tool") + expect(MESSAGES.ERROR_COMMAND_BLACKLISTED).toContain("blacklisted") + expect(MESSAGES.ERROR_PATH_OUTSIDE_PROJECT).toContain("outside") + }) + + it("should have confirmation messages", () => { + expect(MESSAGES.CONFIRM_APPLY_EDIT).toContain("Apply") + expect(MESSAGES.CONFIRM_DELETE_FILE).toContain("Delete") + expect(MESSAGES.CONFIRM_RUN_COMMAND).toContain("Run") + expect(MESSAGES.CONFIRM_CREATE_FILE).toContain("Create") + expect(MESSAGES.CONFIRM_GIT_COMMIT).toContain("commit") + }) + + it("should have info messages", () => { + expect(MESSAGES.INFO_SESSION_LOADED).toContain("loaded") + expect(MESSAGES.INFO_SESSION_CREATED).toContain("created") + expect(MESSAGES.INFO_INDEXING_COMPLETE).toContain("complete") + expect(MESSAGES.INFO_EDIT_APPLIED).toContain("applied") + expect(MESSAGES.INFO_EDIT_CANCELLED).toContain("cancelled") + expect(MESSAGES.INFO_UNDO_SUCCESS).toContain("reverted") + expect(MESSAGES.INFO_UNDO_EMPTY).toContain("Nothing") + }) + + it("should have help text", () => { + expect(MESSAGES.HELP_COMMANDS).toContain("/help") + expect(MESSAGES.HELP_COMMANDS).toContain("/clear") + expect(MESSAGES.HELP_COMMANDS).toContain("/undo") + expect(MESSAGES.HELP_HOTKEYS).toContain("Ctrl+C") + expect(MESSAGES.HELP_HOTKEYS).toContain("Ctrl+D") + }) +}) diff --git a/packages/ipuaro/tests/unit/shared/errors/IpuaroError.test.ts b/packages/ipuaro/tests/unit/shared/errors/IpuaroError.test.ts new file mode 100644 index 0000000..108c7e4 --- /dev/null +++ b/packages/ipuaro/tests/unit/shared/errors/IpuaroError.test.ts @@ -0,0 +1,86 @@ +import { describe, it, expect } from "vitest" +import { IpuaroError } from "../../../../src/shared/errors/IpuaroError.js" + +describe("IpuaroError", () => { + describe("constructor", () => { + it("should create error with all fields", () => { + const error = new IpuaroError("file", "Not found", true, "Check path") + + expect(error.name).toBe("IpuaroError") + expect(error.type).toBe("file") + expect(error.message).toBe("Not found") + expect(error.recoverable).toBe(true) + expect(error.suggestion).toBe("Check path") + }) + + it("should default recoverable to true", () => { + const error = new IpuaroError("parse", "Parse failed") + + expect(error.recoverable).toBe(true) + }) + }) + + describe("static factories", () => { + it("should create redis error", () => { + const error = IpuaroError.redis("Connection failed") + + expect(error.type).toBe("redis") + expect(error.recoverable).toBe(false) + expect(error.suggestion).toContain("Redis") + }) + + it("should create parse error", () => { + const error = IpuaroError.parse("Syntax error", "test.ts") + + expect(error.type).toBe("parse") + expect(error.message).toContain("test.ts") + expect(error.recoverable).toBe(true) + }) + + it("should create parse error without file", () => { + const error = IpuaroError.parse("Syntax error") + + expect(error.message).toBe("Syntax error") + }) + + it("should create llm error", () => { + const error = IpuaroError.llm("Timeout") + + expect(error.type).toBe("llm") + expect(error.recoverable).toBe(true) + expect(error.suggestion).toContain("Ollama") + }) + + it("should create file error", () => { + const error = IpuaroError.file("Not found") + + expect(error.type).toBe("file") + }) + + it("should create command error", () => { + const error = IpuaroError.command("Blacklisted") + + expect(error.type).toBe("command") + }) + + it("should create conflict error", () => { + const error = IpuaroError.conflict("File changed") + + expect(error.type).toBe("conflict") + expect(error.suggestion).toContain("Regenerate") + }) + + it("should create validation error", () => { + const error = IpuaroError.validation("Invalid param") + + expect(error.type).toBe("validation") + }) + + it("should create timeout error", () => { + const error = IpuaroError.timeout("Request timeout") + + expect(error.type).toBe("timeout") + expect(error.suggestion).toContain("timeout") + }) + }) +}) diff --git a/packages/ipuaro/tests/unit/shared/types/index.test.ts b/packages/ipuaro/tests/unit/shared/types/index.test.ts new file mode 100644 index 0000000..98b6d27 --- /dev/null +++ b/packages/ipuaro/tests/unit/shared/types/index.test.ts @@ -0,0 +1,51 @@ +import { describe, it, expect } from "vitest" +import { ok, err, isOk, isErr, type Result } from "../../../../src/shared/types/index.js" + +describe("Result type", () => { + describe("ok", () => { + it("should create success result", () => { + const result = ok("data") + + expect(result.success).toBe(true) + expect(result.data).toBe("data") + }) + }) + + describe("err", () => { + it("should create error result", () => { + const error = new Error("failed") + const result = err(error) + + expect(result.success).toBe(false) + expect(result.error).toBe(error) + }) + }) + + describe("isOk", () => { + it("should return true for success", () => { + const result: Result = ok("data") + + expect(isOk(result)).toBe(true) + }) + + it("should return false for error", () => { + const result: Result = err(new Error("fail")) + + expect(isOk(result)).toBe(false) + }) + }) + + describe("isErr", () => { + it("should return true for error", () => { + const result: Result = err(new Error("fail")) + + expect(isErr(result)).toBe(true) + }) + + it("should return false for success", () => { + const result: Result = ok("data") + + expect(isErr(result)).toBe(false) + }) + }) +}) diff --git a/packages/ipuaro/tests/unit/shared/utils/hash.test.ts b/packages/ipuaro/tests/unit/shared/utils/hash.test.ts new file mode 100644 index 0000000..5d3f991 --- /dev/null +++ b/packages/ipuaro/tests/unit/shared/utils/hash.test.ts @@ -0,0 +1,56 @@ +import { describe, it, expect } from "vitest" +import { md5, hashLines, shortHash } from "../../../../src/shared/utils/hash.js" + +describe("hash utils", () => { + describe("md5", () => { + it("should return consistent hash for same input", () => { + const hash1 = md5("hello") + const hash2 = md5("hello") + + expect(hash1).toBe(hash2) + }) + + it("should return different hash for different input", () => { + const hash1 = md5("hello") + const hash2 = md5("world") + + expect(hash1).not.toBe(hash2) + }) + + it("should return 32 character hex string", () => { + const hash = md5("test") + + expect(hash).toHaveLength(32) + expect(hash).toMatch(/^[a-f0-9]+$/) + }) + }) + + describe("hashLines", () => { + it("should hash joined lines", () => { + const lines = ["line1", "line2", "line3"] + const hash = hashLines(lines) + + expect(hash).toBe(md5("line1\nline2\nline3")) + }) + + it("should handle empty array", () => { + const hash = hashLines([]) + + expect(hash).toBe(md5("")) + }) + }) + + describe("shortHash", () => { + it("should return truncated hash", () => { + const hash = shortHash("test") + + expect(hash).toHaveLength(8) + }) + + it("should accept custom length", () => { + const hash = shortHash("test", 12) + + expect(hash).toHaveLength(12) + }) + }) +}) diff --git a/packages/ipuaro/tests/unit/shared/utils/tokens.test.ts b/packages/ipuaro/tests/unit/shared/utils/tokens.test.ts new file mode 100644 index 0000000..3cb1f8c --- /dev/null +++ b/packages/ipuaro/tests/unit/shared/utils/tokens.test.ts @@ -0,0 +1,61 @@ +import { describe, it, expect } from "vitest" +import { + estimateTokens, + estimateTokensForLines, + truncateToTokens, + formatTokenCount, +} from "../../../../src/shared/utils/tokens.js" + +describe("tokens utils", () => { + describe("estimateTokens", () => { + it("should estimate ~4 chars per token", () => { + expect(estimateTokens("")).toBe(0) + expect(estimateTokens("test")).toBe(1) + expect(estimateTokens("12345678")).toBe(2) + }) + + it("should round up", () => { + expect(estimateTokens("12345")).toBe(2) + }) + }) + + describe("estimateTokensForLines", () => { + it("should estimate tokens for array of lines", () => { + const lines = ["line1", "line2"] + const expected = estimateTokens("line1\nline2") + + expect(estimateTokensForLines(lines)).toBe(expected) + }) + + it("should handle empty array", () => { + expect(estimateTokensForLines([])).toBe(0) + }) + }) + + describe("truncateToTokens", () => { + it("should not truncate short text", () => { + const text = "short" + expect(truncateToTokens(text, 10)).toBe(text) + }) + + it("should truncate long text", () => { + const text = "a".repeat(100) + const result = truncateToTokens(text, 10) + + expect(result).toBe("a".repeat(40) + "...") + }) + }) + + describe("formatTokenCount", () => { + it("should format small numbers as-is", () => { + expect(formatTokenCount(500)).toBe("500") + expect(formatTokenCount(999)).toBe("999") + }) + + it("should format thousands with k suffix", () => { + expect(formatTokenCount(1000)).toBe("1.0k") + expect(formatTokenCount(1500)).toBe("1.5k") + expect(formatTokenCount(12345)).toBe("12.3k") + }) + }) +}) diff --git a/packages/ipuaro/tsconfig.json b/packages/ipuaro/tsconfig.json new file mode 100644 index 0000000..3a21b1c --- /dev/null +++ b/packages/ipuaro/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "module": "nodenext", + "moduleResolution": "nodenext", + "target": "ES2023", + "outDir": "./dist", + "rootDir": "./src", + "jsx": "react-jsx", + "jsxImportSource": "react", + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "strict": true, + "skipLibCheck": true, + "esModuleInterop": true, + "resolvePackageJsonExports": true, + "forceConsistentCasingInFileNames": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "tests"] +} \ No newline at end of file diff --git a/packages/ipuaro/tsup.config.ts b/packages/ipuaro/tsup.config.ts new file mode 100644 index 0000000..286ecb9 --- /dev/null +++ b/packages/ipuaro/tsup.config.ts @@ -0,0 +1,19 @@ +import { defineConfig } from "tsup" + +export default defineConfig({ + entry: ["src/index.ts", "src/cli/index.ts"], + format: ["esm"], + dts: true, + clean: true, + sourcemap: true, + splitting: false, + treeshake: true, + external: [ + "tree-sitter", + "tree-sitter-typescript", + "tree-sitter-javascript", + ], + esbuildOptions(options) { + options.jsx = "automatic" + }, +}) diff --git a/packages/ipuaro/vitest.config.ts b/packages/ipuaro/vitest.config.ts new file mode 100644 index 0000000..9f954c9 --- /dev/null +++ b/packages/ipuaro/vitest.config.ts @@ -0,0 +1,25 @@ +import { defineConfig } from "vitest/config" + +export default defineConfig({ + test: { + globals: true, + environment: "node", + include: ["tests/**/*.test.ts"], + coverage: { + provider: "v8", + reporter: ["text", "html", "lcov"], + include: ["src/**/*.ts", "src/**/*.tsx"], + exclude: [ + "src/**/*.d.ts", + "src/**/index.ts", + "src/**/*.test.ts", + ], + thresholds: { + lines: 80, + functions: 80, + branches: 80, + statements: 80, + }, + }, + }, +}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6306f62..cdcedfa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -133,8 +133,80 @@ importers: specifier: ^4.0.10 version: 4.0.13(@types/node@22.19.1)(@vitest/ui@4.0.13)(terser@5.44.1)(tsx@4.20.6) + packages/ipuaro: + dependencies: + chokidar: + specifier: ^3.6.0 + version: 3.6.0 + commander: + specifier: ^11.1.0 + version: 11.1.0 + ignore: + specifier: ^5.3.2 + version: 5.3.2 + ink: + specifier: ^4.4.1 + version: 4.4.1(@types/react@18.3.27)(react@18.3.1) + ink-text-input: + specifier: ^5.0.1 + version: 5.0.1(ink@4.4.1(@types/react@18.3.27)(react@18.3.1))(react@18.3.1) + ioredis: + specifier: ^5.4.1 + version: 5.8.2 + ollama: + specifier: ^0.5.11 + version: 0.5.18 + react: + specifier: ^18.2.0 + version: 18.3.1 + simple-git: + specifier: ^3.27.0 + version: 3.30.0 + tree-sitter: + specifier: ^0.21.1 + version: 0.21.1 + tree-sitter-javascript: + specifier: ^0.21.0 + version: 0.21.4(tree-sitter@0.21.1) + tree-sitter-typescript: + specifier: ^0.21.2 + version: 0.21.2(tree-sitter@0.21.1) + zod: + specifier: ^3.23.8 + version: 3.25.76 + devDependencies: + '@types/node': + specifier: ^22.10.1 + version: 22.19.1 + '@types/react': + specifier: ^18.2.0 + version: 18.3.27 + '@vitest/coverage-v8': + specifier: ^1.6.0 + version: 1.6.1(vitest@1.6.1) + '@vitest/ui': + specifier: ^1.6.0 + version: 1.6.1(vitest@1.6.1) + tsup: + specifier: ^8.3.5 + version: 8.5.1(postcss@8.5.6)(tsx@4.20.6)(typescript@5.9.3) + typescript: + specifier: ^5.7.2 + version: 5.9.3 + vitest: + specifier: ^1.6.0 + version: 1.6.1(@types/node@22.19.1)(@vitest/ui@1.6.1)(terser@5.44.1) + packages: + '@alcalzone/ansi-tokenize@0.1.3': + resolution: {integrity: sha512-3yWxPTq3UQ/FY9p1ErPxIyfT64elWaMvM9lIHnaqpyft63tkxodF5aUElYHrdisWve5cETkh1+KBw1yJuW0aRw==} + engines: {node: '>=14.13.1'} + + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + '@angular-devkit/core@19.2.17': resolution: {integrity: sha512-Ah008x2RJkd0F+NLKqIpA34/vUGwjlprRCkvddjDopAWRzYn6xCkz1Tqwuhn0nR1Dy47wTLKYD999TYl5ONOAQ==} engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} @@ -361,162 +433,456 @@ packages: '@emnapi/wasi-threads@1.1.0': resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} + '@esbuild/aix-ppc64@0.21.5': + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + '@esbuild/aix-ppc64@0.25.12': resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.27.0': + resolution: {integrity: sha512-KuZrd2hRjz01y5JK9mEBSD3Vj3mbCvemhT466rSuJYeE/hjuBrHfjjcjMdTm/sz7au+++sdbJZJmuBwQLuw68A==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.21.5': + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm64@0.25.12': resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} engines: {node: '>=18'} cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.27.0': + resolution: {integrity: sha512-CC3vt4+1xZrs97/PKDkl0yN7w8edvU2vZvAFGD16n9F0Cvniy5qvzRXjfO1l94efczkkQE6g1x0i73Qf5uthOQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.21.5': + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + '@esbuild/android-arm@0.25.12': resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} engines: {node: '>=18'} cpu: [arm] os: [android] + '@esbuild/android-arm@0.27.0': + resolution: {integrity: sha512-j67aezrPNYWJEOHUNLPj9maeJte7uSMM6gMoxfPC9hOg8N02JuQi/T7ewumf4tNvJadFkvLZMlAq73b9uwdMyQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.21.5': + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + '@esbuild/android-x64@0.25.12': resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} engines: {node: '>=18'} cpu: [x64] os: [android] + '@esbuild/android-x64@0.27.0': + resolution: {integrity: sha512-wurMkF1nmQajBO1+0CJmcN17U4BP6GqNSROP8t0X/Jiw2ltYGLHpEksp9MpoBqkrFR3kv2/te6Sha26k3+yZ9Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.21.5': + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-arm64@0.25.12': resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.27.0': + resolution: {integrity: sha512-uJOQKYCcHhg07DL7i8MzjvS2LaP7W7Pn/7uA0B5S1EnqAirJtbyw4yC5jQ5qcFjHK9l6o/MX9QisBg12kNkdHg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.21.5': + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + '@esbuild/darwin-x64@0.25.12': resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} engines: {node: '>=18'} cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.27.0': + resolution: {integrity: sha512-8mG6arH3yB/4ZXiEnXof5MK72dE6zM9cDvUcPtxhUZsDjESl9JipZYW60C3JGreKCEP+p8P/72r69m4AZGJd5g==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.21.5': + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-arm64@0.25.12': resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.27.0': + resolution: {integrity: sha512-9FHtyO988CwNMMOE3YIeci+UV+x5Zy8fI2qHNpsEtSF83YPBmE8UWmfYAQg6Ux7Gsmd4FejZqnEUZCMGaNQHQw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.21.5': + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + '@esbuild/freebsd-x64@0.25.12': resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.27.0': + resolution: {integrity: sha512-zCMeMXI4HS/tXvJz8vWGexpZj2YVtRAihHLk1imZj4efx1BQzN76YFeKqlDr3bUWI26wHwLWPd3rwh6pe4EV7g==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.21.5': + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm64@0.25.12': resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} engines: {node: '>=18'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.27.0': + resolution: {integrity: sha512-AS18v0V+vZiLJyi/4LphvBE+OIX682Pu7ZYNsdUHyUKSoRwdnOsMf6FDekwoAFKej14WAkOef3zAORJgAtXnlQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.21.5': + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + '@esbuild/linux-arm@0.25.12': resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} engines: {node: '>=18'} cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.27.0': + resolution: {integrity: sha512-t76XLQDpxgmq2cNXKTVEB7O7YMb42atj2Re2Haf45HkaUpjM2J0UuJZDuaGbPbamzZ7bawyGFUkodL+zcE+jvQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.21.5': + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-ia32@0.25.12': resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} engines: {node: '>=18'} cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.27.0': + resolution: {integrity: sha512-Mz1jxqm/kfgKkc/KLHC5qIujMvnnarD9ra1cEcrs7qshTUSksPihGrWHVG5+osAIQ68577Zpww7SGapmzSt4Nw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.21.5': + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-loong64@0.25.12': resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} engines: {node: '>=18'} cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.27.0': + resolution: {integrity: sha512-QbEREjdJeIreIAbdG2hLU1yXm1uu+LTdzoq1KCo4G4pFOLlvIspBm36QrQOar9LFduavoWX2msNFAAAY9j4BDg==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.21.5': + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-mips64el@0.25.12': resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.27.0': + resolution: {integrity: sha512-sJz3zRNe4tO2wxvDpH/HYJilb6+2YJxo/ZNbVdtFiKDufzWq4JmKAiHy9iGoLjAV7r/W32VgaHGkk35cUXlNOg==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.21.5': + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-ppc64@0.25.12': resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.27.0': + resolution: {integrity: sha512-z9N10FBD0DCS2dmSABDBb5TLAyF1/ydVb+N4pi88T45efQ/w4ohr/F/QYCkxDPnkhkp6AIpIcQKQ8F0ANoA2JA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.21.5': + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-riscv64@0.25.12': resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.27.0': + resolution: {integrity: sha512-pQdyAIZ0BWIC5GyvVFn5awDiO14TkT/19FTmFcPdDec94KJ1uZcmFs21Fo8auMXzD4Tt+diXu1LW1gHus9fhFQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.21.5': + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-s390x@0.25.12': resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} engines: {node: '>=18'} cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.27.0': + resolution: {integrity: sha512-hPlRWR4eIDDEci953RI1BLZitgi5uqcsjKMxwYfmi4LcwyWo2IcRP+lThVnKjNtk90pLS8nKdroXYOqW+QQH+w==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.21.5': + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + '@esbuild/linux-x64@0.25.12': resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} engines: {node: '>=18'} cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.27.0': + resolution: {integrity: sha512-1hBWx4OUJE2cab++aVZ7pObD6s+DK4mPGpemtnAORBvb5l/g5xFGk0vc0PjSkrDs0XaXj9yyob3d14XqvnQ4gw==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/netbsd-arm64@0.25.12': resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-arm64@0.27.0': + resolution: {integrity: sha512-6m0sfQfxfQfy1qRuecMkJlf1cIzTOgyaeXaiVaaki8/v+WB+U4hc6ik15ZW6TAllRlg/WuQXxWj1jx6C+dfy3w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.21.5': + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + '@esbuild/netbsd-x64@0.25.12': resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.27.0': + resolution: {integrity: sha512-xbbOdfn06FtcJ9d0ShxxvSn2iUsGd/lgPIO2V3VZIPDbEaIj1/3nBBe1AwuEZKXVXkMmpr6LUAgMkLD/4D2PPA==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + '@esbuild/openbsd-arm64@0.25.12': resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-arm64@0.27.0': + resolution: {integrity: sha512-fWgqR8uNbCQ/GGv0yhzttj6sU/9Z5/Sv/VGU3F5OuXK6J6SlriONKrQ7tNlwBrJZXRYk5jUhuWvF7GYzGguBZQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.21.5': + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + '@esbuild/openbsd-x64@0.25.12': resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.27.0': + resolution: {integrity: sha512-aCwlRdSNMNxkGGqQajMUza6uXzR/U0dIl1QmLjPtRbLOx3Gy3otfFu/VjATy4yQzo9yFDGTxYDo1FfAD9oRD2A==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/openharmony-arm64@0.25.12': resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] + '@esbuild/openharmony-arm64@0.27.0': + resolution: {integrity: sha512-nyvsBccxNAsNYz2jVFYwEGuRRomqZ149A39SHWk4hV0jWxKM0hjBPm3AmdxcbHiFLbBSwG6SbpIcUbXjgyECfA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.21.5': + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + '@esbuild/sunos-x64@0.25.12': resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} engines: {node: '>=18'} cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.27.0': + resolution: {integrity: sha512-Q1KY1iJafM+UX6CFEL+F4HRTgygmEW568YMqDA5UV97AuZSm21b7SXIrRJDwXWPzr8MGr75fUZPV67FdtMHlHA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.21.5': + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-arm64@0.25.12': resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} engines: {node: '>=18'} cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.27.0': + resolution: {integrity: sha512-W1eyGNi6d+8kOmZIwi/EDjrL9nxQIQ0MiGqe/AWc6+IaHloxHSGoeRgDRKHFISThLmsewZ5nHFvGFWdBYlgKPg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.21.5': + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-ia32@0.25.12': resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} engines: {node: '>=18'} cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.27.0': + resolution: {integrity: sha512-30z1aKL9h22kQhilnYkORFYt+3wp7yZsHWus+wSKAJR8JtdfI76LJ4SBdMsCopTR3z/ORqVu5L1vtnHZWVj4cQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.21.5': + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + '@esbuild/win32-x64@0.25.12': resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} engines: {node: '>=18'} cpu: [x64] os: [win32] + '@esbuild/win32-x64@0.27.0': + resolution: {integrity: sha512-aIitBcjQeyOhMTImhLZmtxfdOcuNRpwlPNmlFKPcHQYPhEssw75Cl1TSXJXpMkzaua9FUetx/4OQKq7eJul5Cg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@eslint-community/eslint-utils@4.9.0': resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -714,6 +1080,9 @@ packages: '@types/node': optional: true + '@ioredis/commands@1.4.0': + resolution: {integrity: sha512-aFT2yemJJo+TZCmieA7qnYGQooOS7QfNmYrzGtsYd3g9j5iDP8AimYYAesf79ohjbLG12XxC4nG5DyEnC88AsQ==} + '@isaacs/balanced-match@4.0.1': resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} engines: {node: 20 || >=22} @@ -788,6 +1157,10 @@ packages: node-notifier: optional: true + '@jest/schemas@29.6.3': + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/schemas@30.0.5': resolution: {integrity: sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} @@ -1092,6 +1465,9 @@ packages: resolution: {integrity: sha512-iA7E+uXuiEydOwv8glEYM4tCHnl8C7wTgLxg+3upHhH/iSSnefWfoRqrJwVBhwxPg4MDoypVI7Oal7bX7/ne+w==} engines: {node: '>=20.0.0'} + '@sinclair/typebox@0.27.8': + resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + '@sinclair/typebox@0.34.41': resolution: {integrity: sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==} @@ -1210,12 +1586,18 @@ packages: '@types/node@22.19.1': resolution: {integrity: sha512-LCCV0HdSZZZb34qifBsyWlUmok6W7ouER+oQIGBScS8EsZsQbrtFTUrDX4hOl+CS6p7cnNC4td+qrSVGSCTUfQ==} + '@types/prop-types@15.7.15': + resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==} + '@types/qs@6.14.0': resolution: {integrity: sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==} '@types/range-parser@1.2.7': resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} + '@types/react@18.3.27': + resolution: {integrity: sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==} + '@types/send@0.17.6': resolution: {integrity: sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==} @@ -1401,6 +1783,11 @@ packages: cpu: [x64] os: [win32] + '@vitest/coverage-v8@1.6.1': + resolution: {integrity: sha512-6YeRZwuO4oTGKxD3bijok756oktHSIm3eczVVzNe3scqzuhLwltIF3S9ZL/vwOVIpURmU6SnZhziXXAfw8/Qlw==} + peerDependencies: + vitest: 1.6.1 + '@vitest/coverage-v8@4.0.13': resolution: {integrity: sha512-w77N6bmtJ3CFnL/YHiYotwW/JI3oDlR3K38WEIqegRfdMSScaYxwYKB/0jSNpOTZzUjQkG8HHEz4sdWQMWpQ5g==} peerDependencies: @@ -1410,6 +1797,9 @@ packages: '@vitest/browser': optional: true + '@vitest/expect@1.6.1': + resolution: {integrity: sha512-jXL+9+ZNIJKruofqXuuTClf44eSpcHlgj3CiuNihUF3Ioujtmc0zIa3UJOW5RjDK1YLBJZnWBlPuqhYycLioog==} + '@vitest/expect@4.0.13': resolution: {integrity: sha512-zYtcnNIBm6yS7Gpr7nFTmq8ncowlMdOJkWLqYvhr/zweY6tFbDkDi8BPPOeHxEtK1rSI69H7Fd4+1sqvEGli6w==} @@ -1427,20 +1817,37 @@ packages: '@vitest/pretty-format@4.0.13': resolution: {integrity: sha512-ooqfze8URWbI2ozOeLDMh8YZxWDpGXoeY3VOgcDnsUxN0jPyPWSUvjPQWqDGCBks+opWlN1E4oP1UYl3C/2EQA==} + '@vitest/runner@1.6.1': + resolution: {integrity: sha512-3nSnYXkVkf3mXFfE7vVyPmi3Sazhb/2cfZGGs0JRzFsPFvAMBEcrweV1V1GsrstdXeKCTXlJbvnQwGWgEIHmOA==} + '@vitest/runner@4.0.13': resolution: {integrity: sha512-9IKlAru58wcVaWy7hz6qWPb2QzJTKt+IOVKjAx5vb5rzEFPTL6H4/R9BMvjZ2ppkxKgTrFONEJFtzvnyEpiT+A==} + '@vitest/snapshot@1.6.1': + resolution: {integrity: sha512-WvidQuWAzU2p95u8GAKlRMqMyN1yOJkGHnx3M1PL9Raf7AQ1kwLKg04ADlCa3+OXUZE7BceOhVZiuWAbzCKcUQ==} + '@vitest/snapshot@4.0.13': resolution: {integrity: sha512-hb7Usvyika1huG6G6l191qu1urNPsq1iFc2hmdzQY3F5/rTgqQnwwplyf8zoYHkpt7H6rw5UfIw6i/3qf9oSxQ==} + '@vitest/spy@1.6.1': + resolution: {integrity: sha512-MGcMmpGkZebsMZhbQKkAf9CX5zGvjkBTqf8Zx3ApYWXr3wG+QvEu2eXWfnIIWYSJExIp4V9FCKDEeygzkYrXMw==} + '@vitest/spy@4.0.13': resolution: {integrity: sha512-hSu+m4se0lDV5yVIcNWqjuncrmBgwaXa2utFLIrBkQCQkt+pSwyZTPFQAZiiF/63j8jYa8uAeUZ3RSfcdWaYWw==} + '@vitest/ui@1.6.1': + resolution: {integrity: sha512-xa57bCPGuzEFqGjPs3vVLyqareG8DX0uMkr5U/v5vLv5/ZUrBrPL7gzxzTJedEyZxFMfsozwTIbbYfEQVo3kgg==} + peerDependencies: + vitest: 1.6.1 + '@vitest/ui@4.0.13': resolution: {integrity: sha512-MFV6GhTflgBj194+vowTB2iLI5niMZhqiW7/NV7U4AfWbX/IAtsq4zA+gzCLyGzpsQUdJlX26hrQ1vuWShq2BQ==} peerDependencies: vitest: 4.0.13 + '@vitest/utils@1.6.1': + resolution: {integrity: sha512-jOrrUvXM4Av9ZWiG1EajNto0u96kWAhJ1LmPmJhXXQx/32MecEKd10pOLYgS2BQx1TgkGhloPU1ArDW2vvaY6g==} + '@vitest/utils@4.0.13': resolution: {integrity: sha512-ydozWyQ4LZuu8rLp47xFUWis5VOKMdHjXCWhs1LuJsTNKww+pTHQNK4e0assIB9K80TxFyskENL6vCu3j34EYA==} @@ -1555,6 +1962,10 @@ packages: resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} engines: {node: '>=8'} + ansi-escapes@6.2.1: + resolution: {integrity: sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==} + engines: {node: '>=14.16'} + ansi-escapes@7.2.0: resolution: {integrity: sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw==} engines: {node: '>=18'} @@ -1583,6 +1994,9 @@ packages: resolution: {integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==} engines: {node: '>=14'} + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} @@ -1602,6 +2016,9 @@ packages: asap@2.0.6: resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} + assertion-error@1.1.0: + resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} + assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} @@ -1616,6 +2033,10 @@ packages: asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + auto-bind@5.0.1: + resolution: {integrity: sha512-ooviqdwwgfIfNmDwo94wlshcdzfO64XV0Cg6oDsDYBJfITDz1EngD2z7DkbvCWn+XIMsIqW27sEVF6qcpJrRcg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + babel-jest@30.2.0: resolution: {integrity: sha512-0YiBEOxWqKkSQWL9nNGGEgndoeL0ZpWrbLMNL5u/Kaxrli3Eaxlt3ZtIDktEvXt4L/R9r3ODr2zKwGM/2BjxVw==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} @@ -1651,6 +2072,10 @@ packages: resolution: {integrity: sha512-a28v2eWrrRWPpJSzxc+mKwm0ZtVx/G8SepdQZDArnXYU/XS+IF6mp8aB/4E+hH1tyGCoDo3KlUCdlSxGDsRkAw==} hasBin: true + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + binaryextensions@6.11.0: resolution: {integrity: sha512-sXnYK/Ij80TO3lcqZVV2YgfKN5QjUWIRk/XSm2J/4bd/lPko3lvk0O4ZppH6m+6hB2/GTu+ptNwVFe1xh+QLQw==} engines: {node: '>=4'} @@ -1689,6 +2114,16 @@ packages: buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + bundle-require@5.1.0: + resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + peerDependencies: + esbuild: '>=0.18' + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} @@ -1712,6 +2147,10 @@ packages: caniuse-lite@1.0.30001756: resolution: {integrity: sha512-4HnCNKbMLkLdhJz3TToeVWHSnfJvPaq6vu/eRP0Ahub/07n484XHhBF5AJoSGHdVrS8tKFauUQz8Bp9P7LVx7A==} + chai@4.5.0: + resolution: {integrity: sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==} + engines: {node: '>=4'} + chai@6.2.1: resolution: {integrity: sha512-p4Z49OGG5W/WBCPSS/dH3jQ73kD6tiMmUM+bckNK6Jr5JHMG3k9bg/BvKR8lKmtVBKmOiuVaV2ws8s9oSbwysg==} engines: {node: '>=18'} @@ -1731,6 +2170,13 @@ packages: chardet@2.1.1: resolution: {integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==} + check-error@1.0.3: + resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} + + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + chokidar@4.0.3: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} @@ -1739,6 +2185,10 @@ packages: resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} engines: {node: '>=6.0'} + ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + ci-info@4.3.1: resolution: {integrity: sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==} engines: {node: '>=8'} @@ -1746,10 +2196,18 @@ packages: cjs-module-lexer@2.1.1: resolution: {integrity: sha512-+CmxIZ/L2vNcEfvNtLdU0ZQ6mbq3FZnwAP2PPTiKP+1QOoKwlKlPgb8UKV0Dds7QVaMnHm+FwSft2VB0s/SLjQ==} + cli-boxes@3.0.0: + resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==} + engines: {node: '>=10'} + cli-cursor@3.1.0: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} engines: {node: '>=8'} + cli-cursor@4.0.0: + resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + cli-spinners@2.9.2: resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} engines: {node: '>=6'} @@ -1758,6 +2216,10 @@ packages: resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} engines: {node: 10.* || >= 12.*} + cli-truncate@3.1.0: + resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + cli-width@4.1.0: resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} engines: {node: '>= 12'} @@ -1770,10 +2232,18 @@ packages: resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} engines: {node: '>=0.8'} + cluster-key-slot@1.1.2: + resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} + engines: {node: '>=0.10.0'} + co@4.6.0: resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + code-excerpt@4.0.0: + resolution: {integrity: sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + collect-v8-coverage@1.0.3: resolution: {integrity: sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==} @@ -1788,6 +2258,10 @@ packages: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} + commander@11.1.0: + resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} + engines: {node: '>=16'} + commander@12.1.0: resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} engines: {node: '>=18'} @@ -1809,6 +2283,9 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + consola@3.4.2: resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} engines: {node: ^14.18.0 || >=16.10.0} @@ -1816,6 +2293,10 @@ packages: convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + convert-to-spaces@2.0.1: + resolution: {integrity: sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + cookiejar@2.1.4: resolution: {integrity: sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==} @@ -1838,6 +2319,9 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -1855,6 +2339,10 @@ packages: babel-plugin-macros: optional: true + deep-eql@4.1.4: + resolution: {integrity: sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==} + engines: {node: '>=6'} + deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} @@ -1869,6 +2357,10 @@ packages: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} + denque@2.1.0: + resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} + engines: {node: '>=0.10'} + detect-newline@3.1.0: resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} engines: {node: '>=8'} @@ -1876,6 +2368,10 @@ packages: dezalgo@1.0.4: resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==} + diff-sequences@29.6.3: + resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + diff@4.0.2: resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} engines: {node: '>=0.3.1'} @@ -1934,11 +2430,21 @@ packages: resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} engines: {node: '>= 0.4'} + esbuild@0.21.5: + resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} + engines: {node: '>=12'} + hasBin: true + esbuild@0.25.12: resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} engines: {node: '>=18'} hasBin: true + esbuild@0.27.0: + resolution: {integrity: sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA==} + engines: {node: '>=18'} + hasBin: true + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -2037,6 +2543,10 @@ packages: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} + execa@8.0.1: + resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} + engines: {node: '>=16.17'} + exit-x@0.2.2: resolution: {integrity: sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==} engines: {node: '>= 0.8.0'} @@ -2109,6 +2619,9 @@ packages: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} + fix-dts-default-cjs-exports@1.0.1: + resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==} + flat-cache@4.0.1: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} @@ -2161,6 +2674,9 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} + get-func-name@2.0.2: + resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} + get-intrinsic@1.3.0: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} @@ -2177,6 +2693,10 @@ packages: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} + get-stream@8.0.1: + resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} + engines: {node: '>=16'} + get-tsconfig@4.13.0: resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} @@ -2250,6 +2770,10 @@ packages: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} + human-signals@5.0.0: + resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} + engines: {node: '>=16.17.0'} + iconv-lite@0.7.0: resolution: {integrity: sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==} engines: {node: '>=0.10.0'} @@ -2278,6 +2802,10 @@ packages: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} + indent-string@5.0.0: + resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} + engines: {node: '>=12'} + inflight@1.0.6: resolution: {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. @@ -2285,9 +2813,41 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + ink-text-input@5.0.1: + resolution: {integrity: sha512-crnsYJalG4EhneOFnr/q+Kzw1RgmXI2KsBaLFE6mpiIKxAtJLUnvygOF2IUKO8z4nwkSkveGRBMd81RoYdRSag==} + engines: {node: '>=14.16'} + peerDependencies: + ink: ^4.0.0 + react: ^18.0.0 + + ink@4.4.1: + resolution: {integrity: sha512-rXckvqPBB0Krifk5rn/5LvQGmyXwCUpBfmTwbkQNBY9JY8RSl3b8OftBNEYxg4+SWUhEKcPifgope28uL9inlA==} + engines: {node: '>=14.16'} + peerDependencies: + '@types/react': '>=18.0.0' + react: '>=18.0.0' + react-devtools-core: ^4.19.1 + peerDependenciesMeta: + '@types/react': + optional: true + react-devtools-core: + optional: true + + ioredis@5.8.2: + resolution: {integrity: sha512-C6uC+kleiIMmjViJINWk80sOQw5lEzse1ZmvD+S/s8p8CWapftSaC+kocGTx6xrbrJ4WmYQGC08ffHLr6ToR6Q==} + engines: {node: '>=12.22.0'} + is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-ci@3.0.1: + resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==} + hasBin: true + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -2296,6 +2856,10 @@ packages: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} + is-fullwidth-code-point@4.0.0: + resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} + engines: {node: '>=12'} + is-generator-fn@2.1.0: resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} engines: {node: '>=6'} @@ -2308,6 +2872,9 @@ packages: resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} engines: {node: '>=8'} + is-lower-case@2.0.2: + resolution: {integrity: sha512-bVcMJy4X5Og6VZfdOZstSexlEy20Sr0k/p/b2IlQJlfdKAQuMpiv5w2Ccxb8sKdRUNAG1PnHVHjFSdRDVS6NlQ==} + is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} @@ -2316,10 +2883,17 @@ packages: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} + is-stream@3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + is-unicode-supported@0.1.0: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} + is-upper-case@2.0.2: + resolution: {integrity: sha512-44pxmxAvnnAOwBg4tHPnkfvgjPwbc5QIsSstNU+YcJ1ovxVzCWpSGosPJOZh/a1tdl81fbgnLc9LLv+x2ywbPQ==} + isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -2490,6 +3064,10 @@ packages: node-notifier: optional: true + joycon@3.1.1: + resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} + engines: {node: '>=10'} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -2546,6 +3124,10 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} + lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} @@ -2553,10 +3135,18 @@ packages: resolution: {integrity: sha512-v5xlu8eHD1+6r8EHTg6hfmO97LN8ugKtiXcy5e6oN72iD2r6u0RPfLl6fxM+7Wnh2ZRq15o0russMst44WauPA==} engines: {node: '>=13.2.0'} + load-tsconfig@0.2.5: + resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + loader-runner@4.3.1: resolution: {integrity: sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==} engines: {node: '>=6.11.5'} + local-pkg@0.5.1: + resolution: {integrity: sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==} + engines: {node: '>=14'} + locate-path@5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} @@ -2565,6 +3155,12 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} + lodash.defaults@4.2.0: + resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} + + lodash.isarguments@3.1.0: + resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==} + lodash.memoize@4.1.2: resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} @@ -2581,6 +3177,13 @@ packages: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} engines: {node: '>=10'} + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + loupe@2.3.7: + resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} + lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} @@ -2597,6 +3200,9 @@ packages: magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + magicast@0.3.5: + resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==} + magicast@0.5.1: resolution: {integrity: sha512-xrHS24IxaLrvuo613F719wvOIv9xPHFWQHuvGUBmPnCA/3MQxKI3b+r7n1jAoDHmsbC5bRhTZYR77invLAxVnw==} @@ -2650,6 +3256,10 @@ packages: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} + mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + minimatch@10.1.1: resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} engines: {node: 20 || >=22} @@ -2668,6 +3278,9 @@ packages: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} + mlly@1.8.0: + resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} + mrmime@2.0.1: resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} engines: {node: '>=10'} @@ -2679,6 +3292,9 @@ packages: resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} engines: {node: ^18.17.0 || >=20.5.0} + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -2723,10 +3339,21 @@ packages: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} engines: {node: '>=8'} + npm-run-path@5.3.0: + resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + object-inspect@1.13.4: resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} engines: {node: '>= 0.4'} + ollama@0.5.18: + resolution: {integrity: sha512-lTFqTf9bo7Cd3hpF6CviBe/DEhewjoZYd9N/uCe7O20qYTvGqrNOFOBDj3lbZgFWHUgDv5EeyusYxsZSLS8nvg==} + once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -2734,6 +3361,10 @@ packages: 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'} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -2750,6 +3381,10 @@ packages: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} + p-limit@5.0.0: + resolution: {integrity: sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==} + engines: {node: '>=18'} + p-locate@4.1.0: resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} engines: {node: '>=8'} @@ -2777,6 +3412,10 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} + patch-console@2.0.0: + resolution: {integrity: sha512-0YNdUceMdaQwoKce1gatDScmMo5pu/tfABfnzEqeG0gtTmd7mh/WcwgUjtAeOU7N8nFFlbQBnFK2gXW5fGvmMA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -2789,6 +3428,10 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + path-scurry@1.11.1: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} @@ -2804,9 +3447,15 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} + pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + pathval@1.1.1: + resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -2830,6 +3479,9 @@ packages: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + pluralize@2.0.0: resolution: {integrity: sha512-TqNZzQCD4S42De9IfnnBvILN7HAW7riLqsCyp8lgjXeysyPlX5HhqKAcJHHHb9XskE4/a+7VGC9zzx8Ls0jOAw==} @@ -2837,6 +3489,24 @@ packages: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} engines: {node: '>=4'} + postcss-load-config@6.0.1: + resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} + engines: {node: '>= 18'} + peerDependencies: + jiti: '>=1.21.0' + postcss: '>=8.0.9' + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + jiti: + optional: true + postcss: + optional: true + tsx: + optional: true + yaml: + optional: true + postcss@8.5.6: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} @@ -2854,6 +3524,10 @@ packages: engines: {node: '>=14'} hasBin: true + pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + pretty-format@30.2.0: resolution: {integrity: sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} @@ -2881,14 +3555,36 @@ packages: react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + react-reconciler@0.29.2: + resolution: {integrity: sha512-zZQqIiYgDCTP/f1N/mAR10nJGrPD2ZR+jDSEsKWJHYC7Cm2wodlwbR3upZRdC3cjIjSlTLNVyO7Iu0Yy7t2AYg==} + engines: {node: '>=0.10.0'} + peerDependencies: + react: ^18.3.1 + + react@18.3.1: + resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} + engines: {node: '>=0.10.0'} + readable-stream@3.6.2: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + readdirp@4.1.2: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} + redis-errors@1.2.0: + resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==} + engines: {node: '>=4'} + + redis-parser@3.0.0: + resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==} + engines: {node: '>=4'} + reflect-metadata@0.2.2: resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} @@ -2919,6 +3615,10 @@ packages: resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} engines: {node: '>=8'} + restore-cursor@4.0.0: + resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + reusify@1.1.0: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -2940,6 +3640,9 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + scheduler@0.23.2: + resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} + schema-utils@3.3.0: resolution: {integrity: sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==} engines: {node: '>= 10.13.0'} @@ -2997,6 +3700,10 @@ packages: simple-git@3.30.0: resolution: {integrity: sha512-q6lxyDsCmEal/MEGhP1aVyQ3oxnagGlBDOVSIB4XUVLl1iZh0Pah6ebC9V4xBap/RfgP2WlI8EKs0WS0rMEJHg==} + sirv@2.0.4: + resolution: {integrity: sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==} + engines: {node: '>= 10'} + sirv@3.0.2: resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} engines: {node: '>=18'} @@ -3009,6 +3716,14 @@ packages: resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} engines: {node: '>=10'} + slice-ansi@5.0.0: + resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} + engines: {node: '>=12'} + + slice-ansi@6.0.0: + resolution: {integrity: sha512-6bn4hRfkTvDfUoEQYkERg0BVF1D0vrX9HEkMl08uDiNWvVvjylLHvZFZWkDo6wjT8tUctbYl1nCOuE66ZTaUtA==} + engines: {node: '>=14.16'} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -3041,6 +3756,9 @@ packages: stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + standard-as-callback@2.1.0: + resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} + std-env@3.10.0: resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} @@ -3079,10 +3797,17 @@ packages: resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} engines: {node: '>=6'} + strip-final-newline@3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} + strip-literal@2.1.1: + resolution: {integrity: sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q==} + strtok3@10.3.4: resolution: {integrity: sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg==} engines: {node: '>=18'} @@ -3090,6 +3815,11 @@ packages: structured-source@4.0.0: resolution: {integrity: sha512-qGzRFNJDjFieQkl/sVOI2dUjHKRyL9dAJi2gCPGJLbJHBIkyOHxjuocpIEfbLioX+qSJpvbYdT49/YCdMznKxA==} + sucrase@3.35.1: + resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + superagent@10.2.3: resolution: {integrity: sha512-y/hkYGeXAj7wUMjxRbB21g/l6aAEituGXM9Rwl4o20+SX3e8YOSV6BxFXl+dL3Uk0mjSL3kCbNkwURm8/gEDig==} engines: {node: '>=14.18.0'} @@ -3162,6 +3892,13 @@ packages: resolution: {integrity: sha512-tXJwSr9355kFJI3lbCkPpUH5cP8/M0GGy2xLO34aZCjMXBaK3SoPnZwr/oWmo1FdCnELcs4npdCIOFtq9W3ruQ==} engines: {node: '>=4'} + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} @@ -3172,10 +3909,18 @@ packages: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} + tinypool@0.8.4: + resolution: {integrity: sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==} + engines: {node: '>=14.0.0'} + tinyrainbow@3.0.3: resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} engines: {node: '>=14.0.0'} + tinyspy@2.2.1: + resolution: {integrity: sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==} + engines: {node: '>=14.0.0'} + tmpl@1.0.5: resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} @@ -3191,6 +3936,19 @@ packages: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} + tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + + tree-sitter-javascript@0.21.4: + resolution: {integrity: sha512-Lrk8yahebwrwc1sWJE9xPcz1OnnqiEV7Dh5fbN6EN3wNAdu9r06HpTqLqDwUUbnG4EB46Sfk+FJFAOldfoKLOw==} + peerDependencies: + tree-sitter: ^0.21.1 + tree_sitter: '*' + peerDependenciesMeta: + tree_sitter: + optional: true + tree-sitter-javascript@0.23.1: resolution: {integrity: sha512-/bnhbrTD9frUYHQTiYnPcxyHORIw157ERBa6dqzaKxvR/x3PC4Yzd+D1pZIMS6zNg2v3a8BZ0oK7jHqsQo9fWA==} peerDependencies: @@ -3199,6 +3957,15 @@ packages: tree-sitter: optional: true + tree-sitter-typescript@0.21.2: + resolution: {integrity: sha512-/RyNK41ZpkA8PuPZimR6pGLvNR1p0ibRUJwwQn4qAjyyLEIQD/BNlwS3NSxWtGsAWZe9gZ44VK1mWx2+eQVldg==} + peerDependencies: + tree-sitter: ^0.21.0 + tree_sitter: '*' + peerDependenciesMeta: + tree_sitter: + optional: true + tree-sitter-typescript@0.23.2: resolution: {integrity: sha512-e04JUUKxTT53/x3Uq1zIL45DoYKVfHH4CZqwgZhPg5qYROl5nQjV+85ruFzFGZxu+QeFVbRTPDRnqL9UbU4VeA==} peerDependencies: @@ -3216,6 +3983,9 @@ packages: peerDependencies: typescript: '>=4.8.4' + ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + ts-jest@29.4.5: resolution: {integrity: sha512-HO3GyiWn2qvTQA4kTgjDcXiMwYQt68a1Y8+JuLRVpdIzm+UOLSHgl/XqR4c6nzJkq5rOkjc02O2I7P7l/Yof0Q==} engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0} @@ -3275,6 +4045,25 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tsup@8.5.1: + resolution: {integrity: sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + '@microsoft/api-extractor': ^7.36.0 + '@swc/core': ^1 + postcss: ^8.4.12 + typescript: '>=4.5.0' + peerDependenciesMeta: + '@microsoft/api-extractor': + optional: true + '@swc/core': + optional: true + postcss: + optional: true + typescript: + optional: true + tsx@4.20.6: resolution: {integrity: sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==} engines: {node: '>=18.0.0'} @@ -3288,10 +4077,22 @@ packages: resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} engines: {node: '>=4'} + type-detect@4.1.0: + resolution: {integrity: sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==} + engines: {node: '>=4'} + + type-fest@0.12.0: + resolution: {integrity: sha512-53RyidyjvkGpnWPMF9bQgFtWp+Sl8O2Rp13VavmJgfAP9WWG6q6TkrKU8iyJdnwnfgHI6k2hTlgqH4aSdjoTbg==} + engines: {node: '>=10'} + type-fest@0.21.3: resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} engines: {node: '>=10'} + type-fest@3.13.1: + resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} + engines: {node: '>=14.16'} + type-fest@4.41.0: resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} engines: {node: '>=16'} @@ -3308,6 +4109,9 @@ packages: engines: {node: '>=14.17'} hasBin: true + ufo@1.6.1: + resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} + uglify-js@3.19.3: resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==} engines: {node: '>=0.8.0'} @@ -3358,6 +4162,42 @@ packages: resolution: {integrity: sha512-Ck0EJbAGxHwprkzFO966t4/5QkRuzh+/I1RxhLgUKKwEn+Cd8NwM60mE3AqBZg5gYODoXW0EFsQvbZjRlvdqbg==} engines: {node: '>=4'} + vite-node@1.6.1: + resolution: {integrity: sha512-YAXkfvGtuTzwWbDSACdJSg4A4DZiAqckWe90Zapc/sEX3XvHcw1NdurM/6od8J207tSDqNbSsgdCacBgvJKFuA==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + + vite@5.4.21: + resolution: {integrity: sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + vite@7.2.4: resolution: {integrity: sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3398,6 +4238,31 @@ packages: yaml: optional: true + vitest@1.6.1: + resolution: {integrity: sha512-Ljb1cnSJSivGN0LqXd/zmDbWEM0RNNg2t1QW/XUhYl/qPqyu7CsqeWtqQXHVaJsecLPuDoak2oJcZN2QoRIOag==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/node': ^18.0.0 || >=20.0.0 + '@vitest/browser': 1.6.1 + '@vitest/ui': 1.6.1 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + vitest@4.0.13: resolution: {integrity: sha512-QSD4I0fN6uZQfftryIXuqvqgBxTvJ3ZNkF6RWECd82YGAYAfhcppBLFXzXJHQAAhVFyYEuFTrq6h0hQqjB7jIQ==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} @@ -3463,6 +4328,9 @@ packages: webpack-cli: optional: true + whatwg-fetch@3.6.20: + resolution: {integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==} + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -3473,6 +4341,10 @@ packages: engines: {node: '>=8'} hasBin: true + widest-line@4.0.1: + resolution: {integrity: sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==} + engines: {node: '>=12'} + word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} @@ -3499,6 +4371,18 @@ packages: resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + ws@8.18.3: + resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} + 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 + y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -3522,12 +4406,32 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + yocto-queue@1.2.2: + resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==} + engines: {node: '>=12.20'} + yoctocolors-cjs@2.1.3: resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==} engines: {node: '>=18'} + yoga-wasm-web@0.3.3: + resolution: {integrity: sha512-N+d4UJSJbt/R3wqY7Coqs5pcV0aUj2j9IaQ3rNj9bVCLld8tTGKRa2USARjnvZJWVx1NDmQev8EknoczaOQDOA==} + + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + snapshots: + '@alcalzone/ansi-tokenize@0.1.3': + dependencies: + ansi-styles: 6.2.3 + is-fullwidth-code-point: 4.0.0 + + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + '@angular-devkit/core@19.2.17(chokidar@4.0.3)': dependencies: ajv: 8.17.1 @@ -3804,84 +4708,231 @@ snapshots: tslib: 2.8.1 optional: true + '@esbuild/aix-ppc64@0.21.5': + optional: true + '@esbuild/aix-ppc64@0.25.12': optional: true + '@esbuild/aix-ppc64@0.27.0': + optional: true + + '@esbuild/android-arm64@0.21.5': + optional: true + '@esbuild/android-arm64@0.25.12': optional: true + '@esbuild/android-arm64@0.27.0': + optional: true + + '@esbuild/android-arm@0.21.5': + optional: true + '@esbuild/android-arm@0.25.12': optional: true + '@esbuild/android-arm@0.27.0': + optional: true + + '@esbuild/android-x64@0.21.5': + optional: true + '@esbuild/android-x64@0.25.12': optional: true + '@esbuild/android-x64@0.27.0': + optional: true + + '@esbuild/darwin-arm64@0.21.5': + optional: true + '@esbuild/darwin-arm64@0.25.12': optional: true + '@esbuild/darwin-arm64@0.27.0': + optional: true + + '@esbuild/darwin-x64@0.21.5': + optional: true + '@esbuild/darwin-x64@0.25.12': optional: true + '@esbuild/darwin-x64@0.27.0': + optional: true + + '@esbuild/freebsd-arm64@0.21.5': + optional: true + '@esbuild/freebsd-arm64@0.25.12': optional: true + '@esbuild/freebsd-arm64@0.27.0': + optional: true + + '@esbuild/freebsd-x64@0.21.5': + optional: true + '@esbuild/freebsd-x64@0.25.12': optional: true + '@esbuild/freebsd-x64@0.27.0': + optional: true + + '@esbuild/linux-arm64@0.21.5': + optional: true + '@esbuild/linux-arm64@0.25.12': optional: true + '@esbuild/linux-arm64@0.27.0': + optional: true + + '@esbuild/linux-arm@0.21.5': + optional: true + '@esbuild/linux-arm@0.25.12': optional: true + '@esbuild/linux-arm@0.27.0': + optional: true + + '@esbuild/linux-ia32@0.21.5': + optional: true + '@esbuild/linux-ia32@0.25.12': optional: true + '@esbuild/linux-ia32@0.27.0': + optional: true + + '@esbuild/linux-loong64@0.21.5': + optional: true + '@esbuild/linux-loong64@0.25.12': optional: true + '@esbuild/linux-loong64@0.27.0': + optional: true + + '@esbuild/linux-mips64el@0.21.5': + optional: true + '@esbuild/linux-mips64el@0.25.12': optional: true + '@esbuild/linux-mips64el@0.27.0': + optional: true + + '@esbuild/linux-ppc64@0.21.5': + optional: true + '@esbuild/linux-ppc64@0.25.12': optional: true + '@esbuild/linux-ppc64@0.27.0': + optional: true + + '@esbuild/linux-riscv64@0.21.5': + optional: true + '@esbuild/linux-riscv64@0.25.12': optional: true + '@esbuild/linux-riscv64@0.27.0': + optional: true + + '@esbuild/linux-s390x@0.21.5': + optional: true + '@esbuild/linux-s390x@0.25.12': optional: true + '@esbuild/linux-s390x@0.27.0': + optional: true + + '@esbuild/linux-x64@0.21.5': + optional: true + '@esbuild/linux-x64@0.25.12': optional: true + '@esbuild/linux-x64@0.27.0': + optional: true + '@esbuild/netbsd-arm64@0.25.12': optional: true + '@esbuild/netbsd-arm64@0.27.0': + optional: true + + '@esbuild/netbsd-x64@0.21.5': + optional: true + '@esbuild/netbsd-x64@0.25.12': optional: true + '@esbuild/netbsd-x64@0.27.0': + optional: true + '@esbuild/openbsd-arm64@0.25.12': optional: true + '@esbuild/openbsd-arm64@0.27.0': + optional: true + + '@esbuild/openbsd-x64@0.21.5': + optional: true + '@esbuild/openbsd-x64@0.25.12': optional: true + '@esbuild/openbsd-x64@0.27.0': + optional: true + '@esbuild/openharmony-arm64@0.25.12': optional: true + '@esbuild/openharmony-arm64@0.27.0': + optional: true + + '@esbuild/sunos-x64@0.21.5': + optional: true + '@esbuild/sunos-x64@0.25.12': optional: true + '@esbuild/sunos-x64@0.27.0': + optional: true + + '@esbuild/win32-arm64@0.21.5': + optional: true + '@esbuild/win32-arm64@0.25.12': optional: true + '@esbuild/win32-arm64@0.27.0': + optional: true + + '@esbuild/win32-ia32@0.21.5': + optional: true + '@esbuild/win32-ia32@0.25.12': optional: true + '@esbuild/win32-ia32@0.27.0': + optional: true + + '@esbuild/win32-x64@0.21.5': + optional: true + '@esbuild/win32-x64@0.25.12': optional: true + '@esbuild/win32-x64@0.27.0': + optional: true + '@eslint-community/eslint-utils@4.9.0(eslint@9.39.1)': dependencies: eslint: 9.39.1 @@ -4079,6 +5130,8 @@ snapshots: optionalDependencies: '@types/node': 22.19.1 + '@ioredis/commands@1.4.0': {} + '@isaacs/balanced-match@4.0.1': {} '@isaacs/brace-expansion@5.0.0': @@ -4222,6 +5275,10 @@ snapshots: transitivePeerDependencies: - supports-color + '@jest/schemas@29.6.3': + dependencies: + '@sinclair/typebox': 0.27.8 + '@jest/schemas@30.0.5': dependencies: '@sinclair/typebox': 0.34.41 @@ -4553,6 +5610,8 @@ snapshots: '@secretlint/types@11.2.5': {} + '@sinclair/typebox@0.27.8': {} + '@sinclair/typebox@0.34.41': {} '@sinonjs/commons@3.0.1': @@ -4708,10 +5767,17 @@ snapshots: dependencies: undici-types: 6.21.0 + '@types/prop-types@15.7.15': {} + '@types/qs@6.14.0': {} '@types/range-parser@1.2.7': {} + '@types/react@18.3.27': + dependencies: + '@types/prop-types': 15.7.15 + csstype: 3.2.3 + '@types/send@0.17.6': dependencies: '@types/mime': 1.3.5 @@ -4905,6 +5971,25 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true + '@vitest/coverage-v8@1.6.1(vitest@1.6.1)': + dependencies: + '@ampproject/remapping': 2.3.0 + '@bcoe/v8-coverage': 0.2.3 + debug: 4.4.3 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 5.0.6 + istanbul-reports: 3.2.0 + magic-string: 0.30.21 + magicast: 0.3.5 + picocolors: 1.1.1 + std-env: 3.10.0 + strip-literal: 2.1.1 + test-exclude: 6.0.0 + vitest: 1.6.1(@types/node@22.19.1)(@vitest/ui@1.6.1)(terser@5.44.1) + transitivePeerDependencies: + - supports-color + '@vitest/coverage-v8@4.0.13(vitest@4.0.13)': dependencies: '@bcoe/v8-coverage': 1.0.2 @@ -4922,6 +6007,12 @@ snapshots: transitivePeerDependencies: - supports-color + '@vitest/expect@1.6.1': + dependencies: + '@vitest/spy': 1.6.1 + '@vitest/utils': 1.6.1 + chai: 4.5.0 + '@vitest/expect@4.0.13': dependencies: '@standard-schema/spec': 1.0.0 @@ -4943,19 +6034,46 @@ snapshots: dependencies: tinyrainbow: 3.0.3 + '@vitest/runner@1.6.1': + dependencies: + '@vitest/utils': 1.6.1 + p-limit: 5.0.0 + pathe: 1.1.2 + '@vitest/runner@4.0.13': dependencies: '@vitest/utils': 4.0.13 pathe: 2.0.3 + '@vitest/snapshot@1.6.1': + dependencies: + magic-string: 0.30.21 + pathe: 1.1.2 + pretty-format: 29.7.0 + '@vitest/snapshot@4.0.13': dependencies: '@vitest/pretty-format': 4.0.13 magic-string: 0.30.21 pathe: 2.0.3 + '@vitest/spy@1.6.1': + dependencies: + tinyspy: 2.2.1 + '@vitest/spy@4.0.13': {} + '@vitest/ui@1.6.1(vitest@1.6.1)': + dependencies: + '@vitest/utils': 1.6.1 + fast-glob: 3.3.3 + fflate: 0.8.2 + flatted: 3.3.3 + pathe: 1.1.2 + picocolors: 1.1.1 + sirv: 2.0.4 + vitest: 1.6.1(@types/node@22.19.1)(@vitest/ui@1.6.1)(terser@5.44.1) + '@vitest/ui@4.0.13(vitest@4.0.13)': dependencies: '@vitest/utils': 4.0.13 @@ -4967,6 +6085,13 @@ snapshots: tinyrainbow: 3.0.3 vitest: 4.0.13(@types/node@22.19.1)(@vitest/ui@4.0.13)(terser@5.44.1)(tsx@4.20.6) + '@vitest/utils@1.6.1': + dependencies: + diff-sequences: 29.6.3 + estree-walker: 3.0.3 + loupe: 2.3.7 + pretty-format: 29.7.0 + '@vitest/utils@4.0.13': dependencies: '@vitest/pretty-format': 4.0.13 @@ -5103,6 +6228,8 @@ snapshots: dependencies: type-fest: 0.21.3 + ansi-escapes@6.2.1: {} + ansi-escapes@7.2.0: dependencies: environment: 1.1.0 @@ -5121,6 +6248,8 @@ snapshots: ansis@4.2.0: {} + any-promise@1.3.0: {} + anymatch@3.1.3: dependencies: normalize-path: 3.0.0 @@ -5138,6 +6267,8 @@ snapshots: asap@2.0.6: {} + assertion-error@1.1.0: {} + assertion-error@2.0.1: {} ast-v8-to-istanbul@0.3.8: @@ -5150,6 +6281,8 @@ snapshots: asynckit@0.4.0: {} + auto-bind@5.0.1: {} + babel-jest@30.2.0(@babel/core@7.28.5): dependencies: '@babel/core': 7.28.5 @@ -5208,6 +6341,8 @@ snapshots: baseline-browser-mapping@2.8.31: {} + binary-extensions@2.3.0: {} + binaryextensions@6.11.0: dependencies: editions: 6.22.0 @@ -5256,6 +6391,13 @@ snapshots: base64-js: 1.5.1 ieee754: 1.2.1 + bundle-require@5.1.0(esbuild@0.27.0): + dependencies: + esbuild: 0.27.0 + load-tsconfig: 0.2.5 + + cac@6.7.14: {} + call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 @@ -5274,6 +6416,16 @@ snapshots: caniuse-lite@1.0.30001756: {} + chai@4.5.0: + dependencies: + assertion-error: 1.1.0 + check-error: 1.0.3 + deep-eql: 4.1.4 + get-func-name: 2.0.2 + loupe: 2.3.7 + pathval: 1.1.1 + type-detect: 4.1.0 + chai@6.2.1: {} chalk@4.1.2: @@ -5287,20 +6439,44 @@ snapshots: chardet@2.1.1: {} + check-error@1.0.3: + dependencies: + get-func-name: 2.0.2 + + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + chokidar@4.0.3: dependencies: readdirp: 4.1.2 chrome-trace-event@1.0.4: {} + ci-info@3.9.0: {} + ci-info@4.3.1: {} cjs-module-lexer@2.1.1: {} + cli-boxes@3.0.0: {} + cli-cursor@3.1.0: dependencies: restore-cursor: 3.1.0 + cli-cursor@4.0.0: + dependencies: + restore-cursor: 4.0.0 + cli-spinners@2.9.2: {} cli-table3@0.6.5: @@ -5309,6 +6485,11 @@ snapshots: optionalDependencies: '@colors/colors': 1.5.0 + cli-truncate@3.1.0: + dependencies: + slice-ansi: 5.0.0 + string-width: 5.1.2 + cli-width@4.1.0: {} cliui@8.0.1: @@ -5319,8 +6500,14 @@ snapshots: clone@1.0.4: {} + cluster-key-slot@1.1.2: {} + co@4.6.0: {} + code-excerpt@4.0.0: + dependencies: + convert-to-spaces: 2.0.1 + collect-v8-coverage@1.0.3: {} color-convert@2.0.1: @@ -5333,6 +6520,8 @@ snapshots: dependencies: delayed-stream: 1.0.0 + commander@11.1.0: {} + commander@12.1.0: {} commander@2.20.3: {} @@ -5349,10 +6538,14 @@ snapshots: concat-map@0.0.1: {} + confbox@0.1.8: {} + consola@3.4.2: {} convert-source-map@2.0.0: {} + convert-to-spaces@2.0.1: {} + cookiejar@2.1.4: {} core-util-is@1.0.3: {} @@ -5374,12 +6567,18 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + csstype@3.2.3: {} + debug@4.4.3: dependencies: ms: 2.1.3 dedent@1.7.0: {} + deep-eql@4.1.4: + dependencies: + type-detect: 4.1.0 + deep-is@0.1.4: {} deepmerge@4.3.1: {} @@ -5390,6 +6589,8 @@ snapshots: delayed-stream@1.0.0: {} + denque@2.1.0: {} + detect-newline@3.1.0: {} dezalgo@1.0.4: @@ -5397,6 +6598,8 @@ snapshots: asap: 2.0.6 wrappy: 1.0.2 + diff-sequences@29.6.3: {} + diff@4.0.2: {} dunder-proto@1.0.1: @@ -5447,6 +6650,32 @@ snapshots: has-tostringtag: 1.0.2 hasown: 2.0.2 + esbuild@0.21.5: + optionalDependencies: + '@esbuild/aix-ppc64': 0.21.5 + '@esbuild/android-arm': 0.21.5 + '@esbuild/android-arm64': 0.21.5 + '@esbuild/android-x64': 0.21.5 + '@esbuild/darwin-arm64': 0.21.5 + '@esbuild/darwin-x64': 0.21.5 + '@esbuild/freebsd-arm64': 0.21.5 + '@esbuild/freebsd-x64': 0.21.5 + '@esbuild/linux-arm': 0.21.5 + '@esbuild/linux-arm64': 0.21.5 + '@esbuild/linux-ia32': 0.21.5 + '@esbuild/linux-loong64': 0.21.5 + '@esbuild/linux-mips64el': 0.21.5 + '@esbuild/linux-ppc64': 0.21.5 + '@esbuild/linux-riscv64': 0.21.5 + '@esbuild/linux-s390x': 0.21.5 + '@esbuild/linux-x64': 0.21.5 + '@esbuild/netbsd-x64': 0.21.5 + '@esbuild/openbsd-x64': 0.21.5 + '@esbuild/sunos-x64': 0.21.5 + '@esbuild/win32-arm64': 0.21.5 + '@esbuild/win32-ia32': 0.21.5 + '@esbuild/win32-x64': 0.21.5 + esbuild@0.25.12: optionalDependencies: '@esbuild/aix-ppc64': 0.25.12 @@ -5476,6 +6705,35 @@ snapshots: '@esbuild/win32-ia32': 0.25.12 '@esbuild/win32-x64': 0.25.12 + esbuild@0.27.0: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.0 + '@esbuild/android-arm': 0.27.0 + '@esbuild/android-arm64': 0.27.0 + '@esbuild/android-x64': 0.27.0 + '@esbuild/darwin-arm64': 0.27.0 + '@esbuild/darwin-x64': 0.27.0 + '@esbuild/freebsd-arm64': 0.27.0 + '@esbuild/freebsd-x64': 0.27.0 + '@esbuild/linux-arm': 0.27.0 + '@esbuild/linux-arm64': 0.27.0 + '@esbuild/linux-ia32': 0.27.0 + '@esbuild/linux-loong64': 0.27.0 + '@esbuild/linux-mips64el': 0.27.0 + '@esbuild/linux-ppc64': 0.27.0 + '@esbuild/linux-riscv64': 0.27.0 + '@esbuild/linux-s390x': 0.27.0 + '@esbuild/linux-x64': 0.27.0 + '@esbuild/netbsd-arm64': 0.27.0 + '@esbuild/netbsd-x64': 0.27.0 + '@esbuild/openbsd-arm64': 0.27.0 + '@esbuild/openbsd-x64': 0.27.0 + '@esbuild/openharmony-arm64': 0.27.0 + '@esbuild/sunos-x64': 0.27.0 + '@esbuild/win32-arm64': 0.27.0 + '@esbuild/win32-ia32': 0.27.0 + '@esbuild/win32-x64': 0.27.0 + escalade@3.2.0: {} escape-string-regexp@2.0.0: {} @@ -5589,6 +6847,18 @@ snapshots: signal-exit: 3.0.7 strip-final-newline: 2.0.0 + execa@8.0.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 8.0.1 + human-signals: 5.0.0 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.3.0 + onetime: 6.0.0 + signal-exit: 4.1.0 + strip-final-newline: 3.0.0 + exit-x@0.2.2: {} expect-type@1.2.2: {} @@ -5663,6 +6933,12 @@ snapshots: locate-path: 6.0.0 path-exists: 4.0.0 + fix-dts-default-cjs-exports@1.0.1: + dependencies: + magic-string: 0.30.21 + mlly: 1.8.0 + rollup: 4.53.3 + flat-cache@4.0.1: dependencies: flatted: 3.3.3 @@ -5725,6 +7001,8 @@ snapshots: get-caller-file@2.0.5: {} + get-func-name@2.0.2: {} + get-intrinsic@1.3.0: dependencies: call-bind-apply-helpers: 1.0.2 @@ -5747,6 +7025,8 @@ snapshots: get-stream@6.0.1: {} + get-stream@8.0.1: {} + get-tsconfig@4.13.0: dependencies: resolve-pkg-maps: 1.0.0 @@ -5823,6 +7103,8 @@ snapshots: human-signals@2.1.0: {} + human-signals@5.0.0: {} + iconv-lite@0.7.0: dependencies: safer-buffer: 2.1.2 @@ -5845,6 +7127,8 @@ snapshots: imurmurhash@0.1.4: {} + indent-string@5.0.0: {} + inflight@1.0.6: dependencies: once: 1.4.0 @@ -5852,12 +7136,77 @@ snapshots: inherits@2.0.4: {} + ink-text-input@5.0.1(ink@4.4.1(@types/react@18.3.27)(react@18.3.1))(react@18.3.1): + dependencies: + chalk: 5.6.2 + ink: 4.4.1(@types/react@18.3.27)(react@18.3.1) + react: 18.3.1 + type-fest: 3.13.1 + + ink@4.4.1(@types/react@18.3.27)(react@18.3.1): + dependencies: + '@alcalzone/ansi-tokenize': 0.1.3 + ansi-escapes: 6.2.1 + auto-bind: 5.0.1 + chalk: 5.6.2 + cli-boxes: 3.0.0 + cli-cursor: 4.0.0 + cli-truncate: 3.1.0 + code-excerpt: 4.0.0 + indent-string: 5.0.0 + is-ci: 3.0.1 + is-lower-case: 2.0.2 + is-upper-case: 2.0.2 + lodash: 4.17.21 + patch-console: 2.0.0 + react: 18.3.1 + react-reconciler: 0.29.2(react@18.3.1) + scheduler: 0.23.2 + signal-exit: 3.0.7 + slice-ansi: 6.0.0 + stack-utils: 2.0.6 + string-width: 5.1.2 + type-fest: 0.12.0 + widest-line: 4.0.1 + wrap-ansi: 8.1.0 + ws: 8.18.3 + yoga-wasm-web: 0.3.3 + optionalDependencies: + '@types/react': 18.3.27 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + ioredis@5.8.2: + dependencies: + '@ioredis/commands': 1.4.0 + cluster-key-slot: 1.1.2 + debug: 4.4.3 + denque: 2.1.0 + lodash.defaults: 4.2.0 + lodash.isarguments: 3.1.0 + redis-errors: 1.2.0 + redis-parser: 3.0.0 + standard-as-callback: 2.1.0 + transitivePeerDependencies: + - supports-color + is-arrayish@0.2.1: {} + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + + is-ci@3.0.1: + dependencies: + ci-info: 3.9.0 + is-extglob@2.1.1: {} is-fullwidth-code-point@3.0.0: {} + is-fullwidth-code-point@4.0.0: {} + is-generator-fn@2.1.0: {} is-glob@4.0.3: @@ -5866,12 +7215,22 @@ snapshots: is-interactive@1.0.0: {} + is-lower-case@2.0.2: + dependencies: + tslib: 2.8.1 + is-number@7.0.0: {} is-stream@2.0.1: {} + is-stream@3.0.0: {} + is-unicode-supported@0.1.0: {} + is-upper-case@2.0.2: + dependencies: + tslib: 2.8.1 + isexe@2.0.0: {} istanbul-lib-coverage@3.2.2: {} @@ -6241,6 +7600,8 @@ snapshots: - supports-color - ts-node + joycon@3.1.1: {} + js-tokens@4.0.0: {} js-tokens@9.0.1: {} @@ -6287,12 +7648,21 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + lilconfig@3.1.3: {} + lines-and-columns@1.2.4: {} load-esm@1.0.3: {} + load-tsconfig@0.2.5: {} + loader-runner@4.3.1: {} + local-pkg@0.5.1: + dependencies: + mlly: 1.8.0 + pkg-types: 1.3.1 + locate-path@5.0.0: dependencies: p-locate: 4.1.0 @@ -6301,6 +7671,10 @@ snapshots: dependencies: p-locate: 5.0.0 + lodash.defaults@4.2.0: {} + + lodash.isarguments@3.1.0: {} + lodash.memoize@4.1.2: {} lodash.merge@4.6.2: {} @@ -6314,6 +7688,14 @@ snapshots: chalk: 4.1.2 is-unicode-supported: 0.1.0 + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + loupe@2.3.7: + dependencies: + get-func-name: 2.0.2 + lru-cache@10.4.3: {} lru-cache@11.2.2: {} @@ -6330,6 +7712,12 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 + magicast@0.3.5: + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + source-map-js: 1.2.1 + magicast@0.5.1: dependencies: '@babel/parser': 7.28.5 @@ -6373,6 +7761,8 @@ snapshots: mimic-fn@2.1.0: {} + mimic-fn@4.0.0: {} + minimatch@10.1.1: dependencies: '@isaacs/brace-expansion': 5.0.0 @@ -6389,12 +7779,25 @@ snapshots: minipass@7.1.2: {} + mlly@1.8.0: + dependencies: + acorn: 8.15.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.1 + mrmime@2.0.1: {} ms@2.1.3: {} mute-stream@2.0.0: {} + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + nanoid@3.3.11: {} napi-postinstall@0.3.4: {} @@ -6423,8 +7826,18 @@ snapshots: dependencies: path-key: 3.1.1 + npm-run-path@5.3.0: + dependencies: + path-key: 4.0.0 + + object-assign@4.1.1: {} + object-inspect@1.13.4: {} + ollama@0.5.18: + dependencies: + whatwg-fetch: 3.6.20 + once@1.4.0: dependencies: wrappy: 1.0.2 @@ -6433,6 +7846,10 @@ snapshots: dependencies: mimic-fn: 2.1.0 + onetime@6.0.0: + dependencies: + mimic-fn: 4.0.0 + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -6462,6 +7879,10 @@ snapshots: dependencies: yocto-queue: 0.1.0 + p-limit@5.0.0: + dependencies: + yocto-queue: 1.2.2 + p-locate@4.1.0: dependencies: p-limit: 2.3.0 @@ -6487,12 +7908,16 @@ snapshots: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 + patch-console@2.0.0: {} + path-exists@4.0.0: {} path-is-absolute@1.0.1: {} path-key@3.1.1: {} + path-key@4.0.0: {} + path-scurry@1.11.1: dependencies: lru-cache: 10.4.3 @@ -6507,8 +7932,12 @@ snapshots: path-type@4.0.0: {} + pathe@1.1.2: {} + pathe@2.0.3: {} + pathval@1.1.1: {} + picocolors@1.1.1: {} picomatch@2.3.1: {} @@ -6523,10 +7952,23 @@ snapshots: dependencies: find-up: 4.1.0 + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.8.0 + pathe: 2.0.3 + pluralize@2.0.0: {} pluralize@8.0.0: {} + postcss-load-config@6.0.1(postcss@8.5.6)(tsx@4.20.6): + dependencies: + lilconfig: 3.1.3 + optionalDependencies: + postcss: 8.5.6 + tsx: 4.20.6 + postcss@8.5.6: dependencies: nanoid: 3.3.11 @@ -6541,6 +7983,12 @@ snapshots: prettier@3.6.2: {} + pretty-format@29.7.0: + dependencies: + '@jest/schemas': 29.6.3 + ansi-styles: 5.2.0 + react-is: 18.3.1 + pretty-format@30.2.0: dependencies: '@jest/schemas': 30.0.5 @@ -6572,14 +8020,34 @@ snapshots: react-is@18.3.1: {} + react-reconciler@0.29.2(react@18.3.1): + dependencies: + loose-envify: 1.4.0 + react: 18.3.1 + scheduler: 0.23.2 + + react@18.3.1: + dependencies: + loose-envify: 1.4.0 + readable-stream@3.6.2: dependencies: inherits: 2.0.4 string_decoder: 1.3.0 util-deprecate: 1.0.2 + readdirp@3.6.0: + dependencies: + picomatch: 2.3.1 + readdirp@4.1.2: {} + redis-errors@1.2.0: {} + + redis-parser@3.0.0: + dependencies: + redis-errors: 1.2.0 + reflect-metadata@0.2.2: {} require-directory@2.1.1: {} @@ -6601,6 +8069,11 @@ snapshots: onetime: 5.1.2 signal-exit: 3.0.7 + restore-cursor@4.0.0: + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + reusify@1.1.0: {} rollup@4.53.3: @@ -6643,6 +8116,10 @@ snapshots: safer-buffer@2.1.2: {} + scheduler@0.23.2: + dependencies: + loose-envify: 1.4.0 + schema-utils@3.3.0: dependencies: '@types/json-schema': 7.0.15 @@ -6712,6 +8189,12 @@ snapshots: transitivePeerDependencies: - supports-color + sirv@2.0.4: + dependencies: + '@polka/url': 1.0.0-next.29 + mrmime: 2.0.1 + totalist: 3.0.1 + sirv@3.0.2: dependencies: '@polka/url': 1.0.0-next.29 @@ -6726,6 +8209,16 @@ snapshots: astral-regex: 2.0.0 is-fullwidth-code-point: 3.0.0 + slice-ansi@5.0.0: + dependencies: + ansi-styles: 6.2.3 + is-fullwidth-code-point: 4.0.0 + + slice-ansi@6.0.0: + dependencies: + ansi-styles: 6.2.3 + is-fullwidth-code-point: 4.0.0 + source-map-js@1.2.1: {} source-map-support@0.5.13: @@ -6752,6 +8245,8 @@ snapshots: stackback@0.0.2: {} + standard-as-callback@2.1.0: {} + std-env@3.10.0: {} string-length@4.0.2: @@ -6789,8 +8284,14 @@ snapshots: strip-final-newline@2.0.0: {} + strip-final-newline@3.0.0: {} + strip-json-comments@3.1.1: {} + strip-literal@2.1.1: + dependencies: + js-tokens: 9.0.1 + strtok3@10.3.4: dependencies: '@tokenizer/token': 0.3.0 @@ -6799,6 +8300,16 @@ snapshots: dependencies: boundary: 2.0.0 + sucrase@3.35.1: + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + commander: 4.1.1 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.7 + tinyglobby: 0.2.15 + ts-interface-checker: 0.1.13 + superagent@10.2.3: dependencies: component-emitter: 1.3.1 @@ -6882,6 +8393,14 @@ snapshots: dependencies: editions: 6.22.0 + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + tinybench@2.9.0: {} tinyexec@0.3.2: {} @@ -6891,8 +8410,12 @@ snapshots: fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 + tinypool@0.8.4: {} + tinyrainbow@3.0.3: {} + tinyspy@2.2.1: {} + tmpl@1.0.5: {} to-regex-range@5.0.1: @@ -6907,6 +8430,14 @@ snapshots: totalist@3.0.1: {} + tree-kill@1.2.2: {} + + tree-sitter-javascript@0.21.4(tree-sitter@0.21.1): + dependencies: + node-addon-api: 8.5.0 + node-gyp-build: 4.8.4 + tree-sitter: 0.21.1 + tree-sitter-javascript@0.23.1(tree-sitter@0.21.1): dependencies: node-addon-api: 8.5.0 @@ -6914,6 +8445,12 @@ snapshots: optionalDependencies: tree-sitter: 0.21.1 + tree-sitter-typescript@0.21.2(tree-sitter@0.21.1): + dependencies: + node-addon-api: 8.5.0 + node-gyp-build: 4.8.4 + tree-sitter: 0.21.1 + tree-sitter-typescript@0.23.2(tree-sitter@0.21.1): dependencies: node-addon-api: 8.5.0 @@ -6931,6 +8468,8 @@ snapshots: dependencies: typescript: 5.9.3 + ts-interface-checker@0.1.13: {} + ts-jest@29.4.5(@babel/core@7.28.5)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.5))(jest-util@30.2.0)(jest@30.2.0(@types/node@22.19.1)(ts-node@10.9.2(@types/node@22.19.1)(typescript@5.9.3)))(typescript@5.9.3): dependencies: bs-logger: 0.2.6 @@ -6994,6 +8533,34 @@ snapshots: tslib@2.8.1: {} + tsup@8.5.1(postcss@8.5.6)(tsx@4.20.6)(typescript@5.9.3): + dependencies: + bundle-require: 5.1.0(esbuild@0.27.0) + cac: 6.7.14 + chokidar: 4.0.3 + consola: 3.4.2 + debug: 4.4.3 + esbuild: 0.27.0 + fix-dts-default-cjs-exports: 1.0.1 + joycon: 3.1.1 + picocolors: 1.1.1 + postcss-load-config: 6.0.1(postcss@8.5.6)(tsx@4.20.6) + resolve-from: 5.0.0 + rollup: 4.53.3 + source-map: 0.7.6 + sucrase: 3.35.1 + tinyexec: 0.3.2 + tinyglobby: 0.2.15 + tree-kill: 1.2.2 + optionalDependencies: + postcss: 8.5.6 + typescript: 5.9.3 + transitivePeerDependencies: + - jiti + - supports-color + - tsx + - yaml + tsx@4.20.6: dependencies: esbuild: 0.25.12 @@ -7007,8 +8574,14 @@ snapshots: type-detect@4.0.8: {} + type-detect@4.1.0: {} + + type-fest@0.12.0: {} + type-fest@0.21.3: {} + type-fest@3.13.1: {} + type-fest@4.41.0: {} typescript-eslint@8.47.0(eslint@9.39.1)(typescript@5.9.3): @@ -7024,6 +8597,8 @@ snapshots: typescript@5.9.3: {} + ufo@1.6.1: {} + uglify-js@3.19.3: optional: true @@ -7085,6 +8660,34 @@ snapshots: version-range@4.15.0: {} + vite-node@1.6.1(@types/node@22.19.1)(terser@5.44.1): + dependencies: + cac: 6.7.14 + debug: 4.4.3 + pathe: 1.1.2 + picocolors: 1.1.1 + vite: 5.4.21(@types/node@22.19.1)(terser@5.44.1) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + + vite@5.4.21(@types/node@22.19.1)(terser@5.44.1): + dependencies: + esbuild: 0.21.5 + postcss: 8.5.6 + rollup: 4.53.3 + optionalDependencies: + '@types/node': 22.19.1 + fsevents: 2.3.3 + terser: 5.44.1 + vite@7.2.4(@types/node@22.19.1)(terser@5.44.1)(tsx@4.20.6): dependencies: esbuild: 0.25.12 @@ -7099,6 +8702,41 @@ snapshots: terser: 5.44.1 tsx: 4.20.6 + vitest@1.6.1(@types/node@22.19.1)(@vitest/ui@1.6.1)(terser@5.44.1): + dependencies: + '@vitest/expect': 1.6.1 + '@vitest/runner': 1.6.1 + '@vitest/snapshot': 1.6.1 + '@vitest/spy': 1.6.1 + '@vitest/utils': 1.6.1 + acorn-walk: 8.3.4 + chai: 4.5.0 + debug: 4.4.3 + execa: 8.0.1 + local-pkg: 0.5.1 + magic-string: 0.30.21 + pathe: 1.1.2 + picocolors: 1.1.1 + std-env: 3.10.0 + strip-literal: 2.1.1 + tinybench: 2.9.0 + tinypool: 0.8.4 + vite: 5.4.21(@types/node@22.19.1)(terser@5.44.1) + vite-node: 1.6.1(@types/node@22.19.1)(terser@5.44.1) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 22.19.1 + '@vitest/ui': 1.6.1(vitest@1.6.1) + transitivePeerDependencies: + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + vitest@4.0.13(@types/node@22.19.1)(@vitest/ui@4.0.13)(terser@5.44.1)(tsx@4.20.6): dependencies: '@vitest/expect': 4.0.13 @@ -7187,6 +8825,8 @@ snapshots: - esbuild - uglify-js + whatwg-fetch@3.6.20: {} + which@2.0.2: dependencies: isexe: 2.0.0 @@ -7196,6 +8836,10 @@ snapshots: siginfo: 2.0.0 stackback: 0.0.2 + widest-line@4.0.1: + dependencies: + string-width: 5.1.2 + word-wrap@1.2.5: {} wordwrap@1.0.0: {} @@ -7225,6 +8869,8 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 4.1.0 + ws@8.18.3: {} + y18n@5.0.8: {} yallist@3.1.1: {} @@ -7245,4 +8891,10 @@ snapshots: yocto-queue@0.1.0: {} + yocto-queue@1.2.2: {} + yoctocolors-cjs@2.1.3: {} + + yoga-wasm-web@0.3.3: {} + + zod@3.25.76: {}