diff --git a/.changeset/README.md b/.changeset/README.md new file mode 100644 index 0000000..12460a9 --- /dev/null +++ b/.changeset/README.md @@ -0,0 +1,8 @@ +# Changesets + +Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works +with multi-package repos, or single-package repos to help you version and publish your code. You can +find the full documentation for it [in the repository](https://github.com/changesets/changesets) + +We have a quick list of common questions to get you started engaging with this project in +[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) diff --git a/.changeset/config.json b/.changeset/config.json new file mode 100644 index 0000000..2be13d4 --- /dev/null +++ b/.changeset/config.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://unpkg.com/@changesets/config@3.1.1/schema.json", + "changelog": "@changesets/cli/changelog", + "commit": false, + "fixed": [], + "linked": [], + "access": "public", + "baseBranch": "main", + "updateInternalDependencies": "patch", + "ignore": [] +} diff --git a/.changeset/six-balloons-hope.md b/.changeset/six-balloons-hope.md new file mode 100644 index 0000000..9a6ed4a --- /dev/null +++ b/.changeset/six-balloons-hope.md @@ -0,0 +1,6 @@ +--- +"code-recall": patch +"code-recall-tui": patch +--- + +feat: add code recall tui diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 67f6c05..d635da4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,7 @@ on: branches: [main] jobs: - test: + ci: runs-on: ubuntu-latest steps: @@ -28,4 +28,4 @@ jobs: run: bun run build - name: Test - run: bun test + run: bun run test diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 73762e1..2de16f3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -2,12 +2,17 @@ name: Release on: push: - tags: [ v* ] + branches: [main] +concurrency: ${{ github.workflow }}-${{ github.ref }} jobs: - publish: + release: + name: Release runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write steps: - uses: actions/checkout@v4 @@ -21,9 +26,17 @@ jobs: run: bun install - name: Run tests - run: bun test + run: bun run test - - name: Publish to npm - run: bun publish --access public + - name: Build packages + run: bun run build + + - name: Create Release Pull Request or Publish + id: changesets + uses: changesets/action@v1 + with: + version: bun run version + publish: bun run release env: - NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.gitignore b/.gitignore index e33b810..8d939ba 100644 --- a/.gitignore +++ b/.gitignore @@ -1,36 +1,40 @@ -# dependencies (bun install) -node_modules - -# output -out -dist -*.tgz +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. -# code coverage -coverage -*.lcov - -# logs -logs -_.log -report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json +# Dependencies +node_modules +.pnp +.pnp.js -# dotenv environment variable files +# Local env files .env +.env.local .env.development.local .env.test.local .env.production.local -.env.local -# caches -.eslintcache -.cache -*.tsbuildinfo +# Testing +coverage + +# Turbo +.turbo + +# Vercel +.vercel + +# Build Outputs +.next/ +out/ +build +dist + -# IntelliJ based IDEs -.idea +# Debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* -# Finder (MacOS) folder config +# Misc .DS_Store +*.pem .code-recall/ \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..24d7cc6 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["tauri-apps.tauri-vscode", "rust-lang.rust-analyzer"] +} diff --git a/.vscode/settings.json b/.vscode/settings.json index 71c603b..7b46e28 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,7 @@ { - "editor.defaultFormatter": "biomejs.biome", - "editor.formatOnSave": true + "editor.defaultFormatter": "biomejs.biome", + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.organizeImports.biome": "explicit" + } } diff --git a/README.md b/README.md index f303647..dc54721 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@
-portada - +code-recall **Semantic memory for AI coding agents** @@ -11,353 +10,51 @@ Give your AI assistant persistent memory that learns from your project's history [![Bun](https://img.shields.io/badge/Bun-1.0+-black?logo=bun)](https://bun.sh) [![MCP](https://img.shields.io/badge/MCP-Compatible-green)](https://modelcontextprotocol.io) -[Features](#features) • [Installation](#installation) • [Quick Start](#quick-start) • [Tools](#mcp-tools) • [Best Practices](#best-practices) • [Architecture](#architecture) -
--- -## The Problem - -AI coding assistants are incredibly powerful, but they have a critical limitation: **they forget everything between sessions**. Every time you start a new conversation, your AI assistant has no memory of: - -- Past architectural decisions and *why* they were made -- Patterns that work well in your codebase -- Approaches that failed and should be avoided -- Project-specific rules and guardrails - -You end up repeating context, re-explaining decisions, and sometimes watching the AI make the same mistakes twice. - -### Why not just use CLAUDE.md? - -The typical solution is adding context to `.md` files. **It doesn't scale:** - -- Context window has limits — your instructions compete with actual code -- Loads everything even when you only need part of it -- No semantic search ("state management" won't find "Zustand") -- Can't learn from failures or evolve automatically - -## The Solution - -**code-recall** is an [MCP server](https://modelcontextprotocol.io) that gives AI agents persistent, semantic memory. It stores observations, decisions, and learnings in a local SQLite database with vector search capabilities, allowing your AI to: - -- **Remember** past decisions and their outcomes -- **Learn** from failures (failed approaches are boosted in future searches) -- **Follow rules** with semantic matching guardrails -- **Understand** your code structure through tree-sitter analysis - -All data stays local on your machine. No cloud, no telemetry, fully private. - ---- - -## Features +## Packages -### Semantic Memory -Store and retrieve observations using hybrid search that combines: -- **Vector similarity** (embeddings) - finds conceptually related memories -- **Full-text search** (BM25) - matches exact keywords -- **Temporal decay** - recent memories rank higher -- **Failure boost** - past failures surface prominently to prevent repeating mistakes +This monorepo contains two independent packages: -### Rules Engine -Create guardrails that are matched semantically against actions: -``` -Trigger: "adding API endpoint" -→ Must do: ["Add rate limiting", "Write integration tests"] -→ Must not: ["Skip authentication"] -→ Ask first: ["Is this a breaking change?"] -``` - -### Code Analysis -Parse TypeScript/JavaScript files with tree-sitter to extract: -- Classes, methods, and functions -- Interfaces and type aliases -- Import statements -- JSDoc documentation +### [`code-recall`](./apps/server) - MCP Server -Link memories to specific code entities for contextual recall. +[![npm](https://img.shields.io/npm/v/code-recall)](https://www.npmjs.com/package/code-recall) ---- - -## Installation - -### Prerequisites - -- **[Bun](https://bun.sh)** v1.0 or higher -- **macOS**: SQLite with extension support (via Homebrew: `brew install sqlite`) -- **Linux**: Works out of the box - -### Install from npm +The core MCP server that gives AI agents persistent, semantic memory. It stores observations, decisions, and learnings in a local SQLite database with vector search, full-text search, and a rules engine. ```bash bun install -g code-recall ``` ---- - -## Quick Start - -### 1. Add to Claude Code - ```bash claude mcp add code-recall -- bunx code-recall ``` -### 2. Restart Claude Code - -The server starts automatically when you open Claude Code. - -### 3. Start Using Memory - -Once connected, Claude can store observations, search memories, check rules, and more using the [MCP tools](#mcp-tools) below. - -### Configuration with Other MCP Clients - -Add to your MCP client configuration: - -```json -{ - "mcpServers": { - "code-recall": { - "command": "bunx", - "args": ["code-recall"] - } - } -} -``` - ---- - -## MCP Tools - -code-recall provides 8 tools that AI agents can use: - -### `store_observation` - -Store a new observation in memory with automatic conflict detection. - -| Parameter | Type | Description | -|-----------|------|-------------| -| `category` | `decision` \| `pattern` \| `warning` \| `learning` | Type of observation | -| `content` | `string` | The main content | -| `rationale` | `string?` | Why this decision was made | -| `tags` | `string[]?` | Tags for categorization | -| `file_path` | `string?` | Associated file path | - -```json -{ - "category": "decision", - "content": "Use JWT for authentication", - "rationale": "Stateless auth enables horizontal scaling", - "tags": ["auth", "architecture"] -} -``` - -### `search_memory` - -Search memories using semantic similarity. - -| Parameter | Type | Description | -|-----------|------|-------------| -| `query` | `string` | Search query | -| `limit` | `number?` | Max results (default: 10) | -| `category` | `string?` | Filter by category | -| `file_path` | `string?` | Filter by file path | - -### `get_briefing` - -Get a session start briefing with stats, warnings, and failed approaches. - -| Parameter | Type | Description | -|-----------|------|-------------| -| `focus_areas` | `string[]?` | Topics to pre-fetch context for | - -### `set_rule` - -Create a new rule/guardrail with semantic trigger matching. - -| Parameter | Type | Description | -|-----------|------|-------------| -| `trigger` | `string` | Action pattern that triggers this rule | -| `must_do` | `string[]?` | Required actions | -| `must_not` | `string[]?` | Forbidden actions | -| `ask_first` | `string[]?` | Questions to consider | - -### `check_rules` - -Check which rules apply to an action. - -| Parameter | Type | Description | -|-----------|------|-------------| -| `action` | `string` | The action you're about to take | - -### `record_outcome` - -Record whether a decision worked or failed. - -| Parameter | Type | Description | -|-----------|------|-------------| -| `memory_id` | `number` | ID of the memory | -| `outcome` | `string` | Description of what happened | -| `worked` | `boolean` | Whether it was successful | - -### `list_rules` - -List all active rules. No parameters. - -### `analyze_structure` - -Analyze a source file and extract its code structure. - -| Parameter | Type | Description | -|-----------|------|-------------| -| `file_path` | `string` | Path to the file | -| `include_types` | `string[]?` | Filter entity types | - ---- - -## Recommended Workflow - -``` -┌─────────────────────────────────────────────────────────┐ -│ SESSION START │ -│ │ │ -│ ▼ │ -│ get_briefing(focus_areas) │ -│ │ │ -└─────────────────────────┼───────────────────────────────┘ - │ -┌─────────────────────────┼───────────────────────────────┐ -│ BEFORE CHANGES │ -│ │ │ -│ ┌──────────────┴──────────────┐ │ -│ ▼ ▼ │ -│ check_rules(action) search_memory(query) │ -│ │ -└─────────────────────────────────────────────────────────┘ - │ -┌─────────────────────────┼───────────────────────────────┐ -│ AFTER DECISIONS │ -│ │ │ -│ ▼ │ -│ store_observation(category, content) │ -│ │ -└─────────────────────────────────────────────────────────┘ - │ -┌─────────────────────────┼───────────────────────────────┐ -│ AFTER IMPLEMENTATION │ -│ │ │ -│ ▼ │ -│ record_outcome(memory_id, worked) │ -│ │ -└─────────────────────────────────────────────────────────┘ -``` - ---- - -## Best Practices - -### Claude Code Skill +### [`code-recall-tui`](./apps/tui) - Terminal UI -For optimal integration with Claude Code, add our Skill to your project. [Skills](https://code.claude.com/docs/en/skills) teach Claude when and how to use code-recall automatically. +[![npm](https://img.shields.io/npm/v/code-recall-tui)](https://www.npmjs.com/package/code-recall-tui) -**Install the Skill:** +A terminal UI for browsing and exploring your code-recall database. View memories, rules, code entities, and search through everything your AI agent has learned. ```bash -# From your project root -mkdir -p .claude/skills/code-recall -curl -o .claude/skills/code-recall/SKILL.md \ - https://raw.githubusercontent.com/AbianS/code-recall/main/.claude/skills/code-recall/SKILL.md +bun install -g code-recall-tui ``` -Or create `.claude/skills/code-recall/SKILL.md` manually with [our skill template](https://github.com/AbianS/code-recall/blob/main/.claude/skills/code-recall/SKILL.md). - -### What the Skill Does - -Once installed, Claude will automatically: - -- **Session start**: Call `get_briefing` to load context and warnings -- **Before changes**: Check `search_memory` and `check_rules` for relevant past decisions -- **After decisions**: Store important choices with `store_observation` -- **After implementation**: Record outcomes with `record_outcome` - -This creates a feedback loop where Claude learns from past successes and failures in your project. - ---- - -## Architecture - -``` -code-recall/ -├── src/ -│ ├── index.ts # Entry point -│ ├── server.ts # MCP server and tools -│ ├── database/ -│ │ ├── index.ts # DatabaseManager (SQLite + sqlite-vec) -│ │ └── schema.ts # Database schema -│ ├── memory/ -│ │ ├── index.ts # MemoryManager -│ │ ├── embeddings.ts # Local embeddings (@xenova/transformers) -│ │ └── search.ts # Hybrid search implementation -│ ├── rules/ -│ │ └── index.ts # RulesEngine with semantic matching -│ └── code/ -│ ├── index.ts # Code analysis coordinator -│ ├── parser.ts # tree-sitter WASM parser -│ └── extractors/ # Language-specific extractors -├── tests/ # Comprehensive test suite -└── .code-recall/ # Data directory (auto-created) - └── memory.db # SQLite database +```bash +code-recall-tui ``` --- -## Technical Stack - -| Component | Technology | -|-----------|------------| -| **Runtime** | [Bun](https://bun.sh) | -| **Database** | SQLite + [sqlite-vec](https://github.com/asg017/sqlite-vec) | -| **Embeddings** | [@xenova/transformers](https://huggingface.co/docs/transformers.js) (all-MiniLM-L6-v2, 384d) | -| **Full-text Search** | SQLite FTS5 | -| **Code Parsing** | [web-tree-sitter](https://github.com/nickelproject/nickel/blob/main/packages/tree-sitter/README.md) | -| **Protocol** | [MCP](https://modelcontextprotocol.io) (stdio transport) | - -### Search Algorithm - -The hybrid search combines multiple signals: - -| Signal | Weight | Description | -|--------|--------|-------------| -| Vector similarity | 50% | Cosine similarity of embeddings | -| Full-text score | 30% | BM25 ranking | -| Recency | 15% | Exponential time decay | -| Failure boost | 5% | Failed decisions rank higher | - ---- - -## Development - -```bash -# Run in development mode (with watch) -bun run dev - -# Run tests -bun test - -# Run specific test file -bun test tests/memory/search.test.ts -``` +## Quick Start -### Test Coverage +1. **Install the MCP server** and add it to your AI coding agent +2. **Start coding** -- the agent will automatically store decisions, patterns, warnings, and learnings +3. **Browse your data** with the TUI to see what your agent has learned -The project includes 210+ tests covering: -- Database operations and vector search -- Embedding generation and similarity -- Hybrid search algorithm -- Rules engine semantic matching -- Code analysis and extraction -- MCP server tools +All data stays local on your machine. No cloud, no telemetry, fully private. --- @@ -371,12 +68,6 @@ Contributions are welcome! Please feel free to submit a Pull Request. 4. Push to the branch (`git push origin feature/amazing-feature`) 5. Open a Pull Request ---- - ## License MIT License - see [LICENSE](LICENSE) for details. - ---- - -

with 💖 by AbianS

diff --git a/apps/server/.gitignore b/apps/server/.gitignore new file mode 100644 index 0000000..ba79468 --- /dev/null +++ b/apps/server/.gitignore @@ -0,0 +1,34 @@ +# dependencies (bun install) +node_modules + +# output +out +dist +*.tgz + +# code coverage +coverage +*.lcov + +# logs +logs +_.log +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# caches +.eslintcache +.cache +*.tsbuildinfo + +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config +.DS_Store \ No newline at end of file diff --git a/apps/server/README.md b/apps/server/README.md new file mode 100644 index 0000000..4203205 --- /dev/null +++ b/apps/server/README.md @@ -0,0 +1,382 @@ +
+ +# code-recall + +**Semantic memory for AI coding agents** + +Give your AI assistant persistent memory that learns from your project's history. + +[![npm](https://img.shields.io/npm/v/code-recall)](https://www.npmjs.com/package/code-recall) +[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) +[![Bun](https://img.shields.io/badge/Bun-1.0+-black?logo=bun)](https://bun.sh) +[![MCP](https://img.shields.io/badge/MCP-Compatible-green)](https://modelcontextprotocol.io) + +[Features](#features) • [Installation](#installation) • [Quick Start](#quick-start) • [Tools](#mcp-tools) • [Best Practices](#best-practices) • [Architecture](#architecture) + +
+ +--- + +## The Problem + +AI coding assistants are incredibly powerful, but they have a critical limitation: **they forget everything between sessions**. Every time you start a new conversation, your AI assistant has no memory of: + +- Past architectural decisions and *why* they were made +- Patterns that work well in your codebase +- Approaches that failed and should be avoided +- Project-specific rules and guardrails + +You end up repeating context, re-explaining decisions, and sometimes watching the AI make the same mistakes twice. + +### Why not just use CLAUDE.md? + +The typical solution is adding context to `.md` files. **It doesn't scale:** + +- Context window has limits — your instructions compete with actual code +- Loads everything even when you only need part of it +- No semantic search ("state management" won't find "Zustand") +- Can't learn from failures or evolve automatically + +## The Solution + +**code-recall** is an [MCP server](https://modelcontextprotocol.io) that gives AI agents persistent, semantic memory. It stores observations, decisions, and learnings in a local SQLite database with vector search capabilities, allowing your AI to: + +- **Remember** past decisions and their outcomes +- **Learn** from failures (failed approaches are boosted in future searches) +- **Follow rules** with semantic matching guardrails +- **Understand** your code structure through tree-sitter analysis + +All data stays local on your machine. No cloud, no telemetry, fully private. + +--- + +## Features + +### Semantic Memory +Store and retrieve observations using hybrid search that combines: +- **Vector similarity** (embeddings) - finds conceptually related memories +- **Full-text search** (BM25) - matches exact keywords +- **Temporal decay** - recent memories rank higher +- **Failure boost** - past failures surface prominently to prevent repeating mistakes + +### Rules Engine +Create guardrails that are matched semantically against actions: +``` +Trigger: "adding API endpoint" +→ Must do: ["Add rate limiting", "Write integration tests"] +→ Must not: ["Skip authentication"] +→ Ask first: ["Is this a breaking change?"] +``` + +### Code Analysis +Parse TypeScript/JavaScript files with tree-sitter to extract: +- Classes, methods, and functions +- Interfaces and type aliases +- Import statements +- JSDoc documentation + +Link memories to specific code entities for contextual recall. + +--- + +## Installation + +### Prerequisites + +- **[Bun](https://bun.sh)** v1.0 or higher +- **macOS**: SQLite with extension support (via Homebrew: `brew install sqlite`) +- **Linux**: Works out of the box + +### Install from npm + +```bash +bun install -g code-recall +``` + +--- + +## Quick Start + +### 1. Add to Claude Code + +```bash +claude mcp add code-recall -- bunx code-recall +``` + +### 2. Restart Claude Code + +The server starts automatically when you open Claude Code. + +### 3. Start Using Memory + +Once connected, Claude can store observations, search memories, check rules, and more using the [MCP tools](#mcp-tools) below. + +### Configuration with Other MCP Clients + +Add to your MCP client configuration: + +```json +{ + "mcpServers": { + "code-recall": { + "command": "bunx", + "args": ["code-recall"] + } + } +} +``` + +--- + +## MCP Tools + +code-recall provides 8 tools that AI agents can use: + +### `store_observation` + +Store a new observation in memory with automatic conflict detection. + +| Parameter | Type | Description | +|-----------|------|-------------| +| `category` | `decision` \| `pattern` \| `warning` \| `learning` | Type of observation | +| `content` | `string` | The main content | +| `rationale` | `string?` | Why this decision was made | +| `tags` | `string[]?` | Tags for categorization | +| `file_path` | `string?` | Associated file path | + +```json +{ + "category": "decision", + "content": "Use JWT for authentication", + "rationale": "Stateless auth enables horizontal scaling", + "tags": ["auth", "architecture"] +} +``` + +### `search_memory` + +Search memories using semantic similarity. + +| Parameter | Type | Description | +|-----------|------|-------------| +| `query` | `string` | Search query | +| `limit` | `number?` | Max results (default: 10) | +| `category` | `string?` | Filter by category | +| `file_path` | `string?` | Filter by file path | + +### `get_briefing` + +Get a session start briefing with stats, warnings, and failed approaches. + +| Parameter | Type | Description | +|-----------|------|-------------| +| `focus_areas` | `string[]?` | Topics to pre-fetch context for | + +### `set_rule` + +Create a new rule/guardrail with semantic trigger matching. + +| Parameter | Type | Description | +|-----------|------|-------------| +| `trigger` | `string` | Action pattern that triggers this rule | +| `must_do` | `string[]?` | Required actions | +| `must_not` | `string[]?` | Forbidden actions | +| `ask_first` | `string[]?` | Questions to consider | + +### `check_rules` + +Check which rules apply to an action. + +| Parameter | Type | Description | +|-----------|------|-------------| +| `action` | `string` | The action you're about to take | + +### `record_outcome` + +Record whether a decision worked or failed. + +| Parameter | Type | Description | +|-----------|------|-------------| +| `memory_id` | `number` | ID of the memory | +| `outcome` | `string` | Description of what happened | +| `worked` | `boolean` | Whether it was successful | + +### `list_rules` + +List all active rules. No parameters. + +### `analyze_structure` + +Analyze a source file and extract its code structure. + +| Parameter | Type | Description | +|-----------|------|-------------| +| `file_path` | `string` | Path to the file | +| `include_types` | `string[]?` | Filter entity types | + +--- + +## Recommended Workflow + +``` +┌─────────────────────────────────────────────────────────┐ +│ SESSION START │ +│ │ │ +│ ▼ │ +│ get_briefing(focus_areas) │ +│ │ │ +└─────────────────────────┼───────────────────────────────┘ + │ +┌─────────────────────────┼───────────────────────────────┐ +│ BEFORE CHANGES │ +│ │ │ +│ ┌──────────────┴──────────────┐ │ +│ ▼ ▼ │ +│ check_rules(action) search_memory(query) │ +│ │ +└─────────────────────────────────────────────────────────┘ + │ +┌─────────────────────────┼───────────────────────────────┐ +│ AFTER DECISIONS │ +│ │ │ +│ ▼ │ +│ store_observation(category, content) │ +│ │ +└─────────────────────────────────────────────────────────┘ + │ +┌─────────────────────────┼───────────────────────────────┐ +│ AFTER IMPLEMENTATION │ +│ │ │ +│ ▼ │ +│ record_outcome(memory_id, worked) │ +│ │ +└─────────────────────────────────────────────────────────┘ +``` + +--- + +## Best Practices + +### Claude Code Skill + +For optimal integration with Claude Code, add our Skill to your project. [Skills](https://code.claude.com/docs/en/skills) teach Claude when and how to use code-recall automatically. + +**Install the Skill:** + +```bash +# From your project root +mkdir -p .claude/skills/code-recall +curl -o .claude/skills/code-recall/SKILL.md \ + https://raw.githubusercontent.com/AbianS/code-recall/main/.claude/skills/code-recall/SKILL.md +``` + +Or create `.claude/skills/code-recall/SKILL.md` manually with [our skill template](https://github.com/AbianS/code-recall/blob/main/.claude/skills/code-recall/SKILL.md). + +### What the Skill Does + +Once installed, Claude will automatically: + +- **Session start**: Call `get_briefing` to load context and warnings +- **Before changes**: Check `search_memory` and `check_rules` for relevant past decisions +- **After decisions**: Store important choices with `store_observation` +- **After implementation**: Record outcomes with `record_outcome` + +This creates a feedback loop where Claude learns from past successes and failures in your project. + +--- + +## Architecture + +``` +code-recall/ +├── src/ +│ ├── index.ts # Entry point +│ ├── server.ts # MCP server and tools +│ ├── database/ +│ │ ├── index.ts # DatabaseManager (SQLite + sqlite-vec) +│ │ └── schema.ts # Database schema +│ ├── memory/ +│ │ ├── index.ts # MemoryManager +│ │ ├── embeddings.ts # Local embeddings (@xenova/transformers) +│ │ └── search.ts # Hybrid search implementation +│ ├── rules/ +│ │ └── index.ts # RulesEngine with semantic matching +│ └── code/ +│ ├── index.ts # Code analysis coordinator +│ ├── parser.ts # tree-sitter WASM parser +│ └── extractors/ # Language-specific extractors +├── tests/ # Comprehensive test suite +└── .code-recall/ # Data directory (auto-created) + └── memory.db # SQLite database +``` + +--- + +## Technical Stack + +| Component | Technology | +|-----------|------------| +| **Runtime** | [Bun](https://bun.sh) | +| **Database** | SQLite + [sqlite-vec](https://github.com/asg017/sqlite-vec) | +| **Embeddings** | [@xenova/transformers](https://huggingface.co/docs/transformers.js) (all-MiniLM-L6-v2, 384d) | +| **Full-text Search** | SQLite FTS5 | +| **Code Parsing** | [web-tree-sitter](https://github.com/nickelproject/nickel/blob/main/packages/tree-sitter/README.md) | +| **Protocol** | [MCP](https://modelcontextprotocol.io) (stdio transport) | + +### Search Algorithm + +The hybrid search combines multiple signals: + +| Signal | Weight | Description | +|--------|--------|-------------| +| Vector similarity | 50% | Cosine similarity of embeddings | +| Full-text score | 30% | BM25 ranking | +| Recency | 15% | Exponential time decay | +| Failure boost | 5% | Failed decisions rank higher | + +--- + +## Development + +```bash +# Run in development mode (with watch) +bun run dev + +# Run tests +bun test + +# Run specific test file +bun test tests/memory/search.test.ts +``` + +### Test Coverage + +The project includes 210+ tests covering: +- Database operations and vector search +- Embedding generation and similarity +- Hybrid search algorithm +- Rules engine semantic matching +- Code analysis and extraction +- MCP server tools + +--- + +## Contributing + +Contributions are welcome! Please feel free to submit a Pull Request. + +1. Fork the repository +2. Create your feature branch (`git checkout -b feature/amazing-feature`) +3. Commit your changes (`git commit -m 'Add amazing feature'`) +4. Push to the branch (`git push origin feature/amazing-feature`) +5. Open a Pull Request + +--- + +## License + +MIT License - see [LICENSE](LICENSE) for details. + +--- + +

with 💖 by AbianS

diff --git a/apps/server/package.json b/apps/server/package.json new file mode 100644 index 0000000..cfab747 --- /dev/null +++ b/apps/server/package.json @@ -0,0 +1,60 @@ +{ + "name": "code-recall", + "version": "1.0.0", + "description": "Ultra-fast MCP server for semantic memory and code analysis", + "module": "src/index.ts", + "type": "module", + "bin": { + "code-recall": "src/index.ts" + }, + "files": [ + "src", + "README.md", + "LICENSE" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/AbianS/code-recall.git" + }, + "keywords": [ + "mcp", + "memory", + "ai", + "coding-agent", + "semantic-search", + "sqlite", + "bun" + ], + "author": "AbianS", + "license": "MIT", + "bugs": { + "url": "https://github.com/AbianS/code-recall/issues" + }, + "homepage": "https://github.com/AbianS/code-recall#readme", + "engines": { + "bun": ">=1.0.0" + }, + "scripts": { + "start": "bun --bun run src/index.ts", + "dev": "bun --bun --watch run src/index.ts", + "build": "bun --bun build src/index.ts --outdir dist --target bun", + "test": "bun --bun test", + "lint": "biome check src tests", + "lint:fix": "biome check --write src tests" + }, + "dependencies": { + "@modelcontextprotocol/sdk": "1.25.2", + "@xenova/transformers": "2.17.2", + "sqlite-vec": "0.1.7-alpha.2", + "tree-sitter-javascript": "0.25.0", + "tree-sitter-typescript": "0.23.2", + "web-tree-sitter": "0.26.3", + "zod": "3.25.76" + }, + "devDependencies": { + "@types/bun": "1.3.6" + }, + "peerDependencies": { + "typescript": "5.9.3" + } +} diff --git a/src/code/extractors/javascript.ts b/apps/server/src/code/extractors/javascript.ts similarity index 100% rename from src/code/extractors/javascript.ts rename to apps/server/src/code/extractors/javascript.ts diff --git a/src/code/extractors/typescript.ts b/apps/server/src/code/extractors/typescript.ts similarity index 100% rename from src/code/extractors/typescript.ts rename to apps/server/src/code/extractors/typescript.ts diff --git a/src/code/index.ts b/apps/server/src/code/index.ts similarity index 100% rename from src/code/index.ts rename to apps/server/src/code/index.ts diff --git a/src/code/parser.ts b/apps/server/src/code/parser.ts similarity index 100% rename from src/code/parser.ts rename to apps/server/src/code/parser.ts diff --git a/src/code/types.ts b/apps/server/src/code/types.ts similarity index 100% rename from src/code/types.ts rename to apps/server/src/code/types.ts diff --git a/src/database/index.ts b/apps/server/src/database/index.ts similarity index 100% rename from src/database/index.ts rename to apps/server/src/database/index.ts diff --git a/src/database/migrations/0001_initial.ts b/apps/server/src/database/migrations/0001_initial.ts similarity index 100% rename from src/database/migrations/0001_initial.ts rename to apps/server/src/database/migrations/0001_initial.ts diff --git a/src/database/migrations/index.ts b/apps/server/src/database/migrations/index.ts similarity index 100% rename from src/database/migrations/index.ts rename to apps/server/src/database/migrations/index.ts diff --git a/src/database/migrations/types.ts b/apps/server/src/database/migrations/types.ts similarity index 100% rename from src/database/migrations/types.ts rename to apps/server/src/database/migrations/types.ts diff --git a/src/database/migrations/utils.ts b/apps/server/src/database/migrations/utils.ts similarity index 100% rename from src/database/migrations/utils.ts rename to apps/server/src/database/migrations/utils.ts diff --git a/src/database/schema.ts b/apps/server/src/database/schema.ts similarity index 100% rename from src/database/schema.ts rename to apps/server/src/database/schema.ts diff --git a/src/index.ts b/apps/server/src/index.ts old mode 100644 new mode 100755 similarity index 100% rename from src/index.ts rename to apps/server/src/index.ts diff --git a/src/memory/embeddings.ts b/apps/server/src/memory/embeddings.ts similarity index 100% rename from src/memory/embeddings.ts rename to apps/server/src/memory/embeddings.ts diff --git a/src/memory/index.ts b/apps/server/src/memory/index.ts similarity index 100% rename from src/memory/index.ts rename to apps/server/src/memory/index.ts diff --git a/src/memory/search.ts b/apps/server/src/memory/search.ts similarity index 100% rename from src/memory/search.ts rename to apps/server/src/memory/search.ts diff --git a/src/rules/index.ts b/apps/server/src/rules/index.ts similarity index 100% rename from src/rules/index.ts rename to apps/server/src/rules/index.ts diff --git a/src/server.ts b/apps/server/src/server.ts similarity index 100% rename from src/server.ts rename to apps/server/src/server.ts diff --git a/tests/code/analyzer.test.ts b/apps/server/tests/code/analyzer.test.ts similarity index 100% rename from tests/code/analyzer.test.ts rename to apps/server/tests/code/analyzer.test.ts diff --git a/tests/code/javascript.test.ts b/apps/server/tests/code/javascript.test.ts similarity index 100% rename from tests/code/javascript.test.ts rename to apps/server/tests/code/javascript.test.ts diff --git a/tests/code/parser.test.ts b/apps/server/tests/code/parser.test.ts similarity index 100% rename from tests/code/parser.test.ts rename to apps/server/tests/code/parser.test.ts diff --git a/tests/code/typescript.test.ts b/apps/server/tests/code/typescript.test.ts similarity index 100% rename from tests/code/typescript.test.ts rename to apps/server/tests/code/typescript.test.ts diff --git a/tests/database/entities.test.ts b/apps/server/tests/database/entities.test.ts similarity index 100% rename from tests/database/entities.test.ts rename to apps/server/tests/database/entities.test.ts diff --git a/tests/database/manager.test.ts b/apps/server/tests/database/manager.test.ts similarity index 100% rename from tests/database/manager.test.ts rename to apps/server/tests/database/manager.test.ts diff --git a/tests/database/migrations.test.ts b/apps/server/tests/database/migrations.test.ts similarity index 100% rename from tests/database/migrations.test.ts rename to apps/server/tests/database/migrations.test.ts diff --git a/tests/database/vectors.test.ts b/apps/server/tests/database/vectors.test.ts similarity index 100% rename from tests/database/vectors.test.ts rename to apps/server/tests/database/vectors.test.ts diff --git a/tests/memory/embeddings.test.ts b/apps/server/tests/memory/embeddings.test.ts similarity index 100% rename from tests/memory/embeddings.test.ts rename to apps/server/tests/memory/embeddings.test.ts diff --git a/tests/memory/manager.test.ts b/apps/server/tests/memory/manager.test.ts similarity index 100% rename from tests/memory/manager.test.ts rename to apps/server/tests/memory/manager.test.ts diff --git a/tests/memory/search.test.ts b/apps/server/tests/memory/search.test.ts similarity index 100% rename from tests/memory/search.test.ts rename to apps/server/tests/memory/search.test.ts diff --git a/tests/rules/engine.test.ts b/apps/server/tests/rules/engine.test.ts similarity index 100% rename from tests/rules/engine.test.ts rename to apps/server/tests/rules/engine.test.ts diff --git a/tests/server/tools.test.ts b/apps/server/tests/server/tools.test.ts similarity index 100% rename from tests/server/tools.test.ts rename to apps/server/tests/server/tools.test.ts diff --git a/tests/setup.ts b/apps/server/tests/setup.ts similarity index 100% rename from tests/setup.ts rename to apps/server/tests/setup.ts diff --git a/tsconfig.json b/apps/server/tsconfig.json similarity index 100% rename from tsconfig.json rename to apps/server/tsconfig.json diff --git a/apps/tui/README.md b/apps/tui/README.md new file mode 100644 index 0000000..38cd497 --- /dev/null +++ b/apps/tui/README.md @@ -0,0 +1,127 @@ +
+ +# code-recall-tui + +**Terminal UI for browsing your code-recall database** + +Explore memories, rules, code entities, and search through everything your AI agent has learned. + +[![npm](https://img.shields.io/npm/v/code-recall-tui)](https://www.npmjs.com/package/code-recall-tui) +[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) +[![Bun](https://img.shields.io/badge/Bun-1.0+-black?logo=bun)](https://bun.sh) + +
+ +--- + +## Installation + +```bash +bun install -g code-recall-tui +``` + +## Usage + +Run from the root of a project that has a `.code-recall/memory.db` file: + +```bash +code-recall-tui +``` + +Or specify a project path: + +```bash +code-recall-tui --project /path/to/your/project +``` + +You can also set the project path via environment variable: + +```bash +CODE_RECALL_PROJECT_PATH=/path/to/project code-recall-tui +``` + +--- + +## Screens + +### Dashboard + +Overview of your code-recall data at a glance: +- Total memories, rules, failed decisions, and warnings +- Category breakdown (decisions, patterns, warnings, learnings) +- Recent activity feed +- Failed approaches panel + +### Memories + +Browse all stored memories with category filtering: +- Filter by: All, Decisions, Patterns, Warnings, Learnings +- Navigate tabs with `[` and `]` +- Press Enter to view full memory details + +### Memory Detail + +Full view of a single memory including: +- Category and outcome status +- Content, rationale, and context +- Tags, file path, and recorded outcome + +### Rules + +Browse all active rules/guardrails with their trigger patterns and constraint counts. + +### Rule Detail + +Full view of a rule showing: +- Trigger pattern +- Must Do constraints +- Must Not constraints +- Ask First questions + +### Code Entities + +Browse analyzed source files and their extracted code structure: +- Split view: file list + entity details +- Color-coded entity types (classes, functions, interfaces, etc.) +- Signatures and line ranges + +### Search + +Full-text search across all memories using SQLite FTS5. + +--- + +## Keyboard Shortcuts + +| Key | Action | +|-----|--------| +| `1` | Go to Dashboard | +| `2` | Go to Memories | +| `3` | Go to Rules | +| `4` | Go to Code Entities | +| `/` | Go to Search | +| `Escape` | Go back | +| `Enter` | Select / Open detail | +| `Tab` | Toggle panel focus (where applicable) | +| `[` / `]` | Switch tabs (Memories screen) | +| `q` | Quit | + +--- + +## Requirements + +- **[Bun](https://bun.sh)** v1.0 or higher +- An existing `.code-recall/memory.db` database (created by the [code-recall](https://www.npmjs.com/package/code-recall) MCP server) +- **macOS**: SQLite with extension support (via Homebrew: `brew install sqlite`) + +--- + +## How It Works + +`code-recall-tui` opens your `.code-recall/memory.db` database in **read-only mode** -- it never modifies your data. It's a standalone viewer that is completely independent from the code-recall MCP server. + +--- + +## License + +MIT License - see [LICENSE](../../LICENSE) for details. diff --git a/apps/tui/package.json b/apps/tui/package.json new file mode 100644 index 0000000..0143f88 --- /dev/null +++ b/apps/tui/package.json @@ -0,0 +1,54 @@ +{ + "name": "code-recall-tui", + "version": "1.0.0", + "description": "Terminal UI for browsing code-recall memories, rules, and code entities", + "type": "module", + "main": "dist/index.js", + "bin": { + "code-recall-tui": "dist/index.js" + }, + "files": [ + "dist" + ], + "scripts": { + "start": "bun run src/index.ts", + "dev": "bun --watch run src/index.ts", + "build": "bun build src/index.ts --outdir dist --target bun", + "lint": "biome check src", + "lint:fix": "biome check --write src" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/AbianS/code-recall.git", + "directory": "apps/tui" + }, + "keywords": [ + "code-recall", + "tui", + "terminal", + "cli", + "memory", + "ai", + "mcp", + "sqlite", + "bun" + ], + "author": "AbianS", + "license": "MIT", + "bugs": { + "url": "https://github.com/AbianS/code-recall/issues" + }, + "homepage": "https://github.com/AbianS/code-recall/tree/main/apps/tui#readme", + "engines": { + "bun": ">=1.0.0" + }, + "dependencies": { + "@opentui/core": "0.1.75" + }, + "devDependencies": { + "@types/bun": "1.3.6" + }, + "peerDependencies": { + "typescript": "5.9.3" + } +} diff --git a/apps/tui/src/app.ts b/apps/tui/src/app.ts new file mode 100644 index 0000000..2d15f0d --- /dev/null +++ b/apps/tui/src/app.ts @@ -0,0 +1,200 @@ +import type { CliRenderer, KeyEvent } from "@opentui/core"; +import { BoxRenderable } from "@opentui/core"; +import { createHeader } from "./components/header.ts"; +import { createStatusBar } from "./components/status-bar.ts"; +import type { DataStore } from "./data/store.ts"; +import { DashboardScreen } from "./screens/dashboard.ts"; +import { EntitiesScreen } from "./screens/entities.ts"; +import { MemoriesScreen } from "./screens/memories.ts"; +import { MemoryDetailScreen } from "./screens/memory-detail.ts"; +import { RuleDetailScreen } from "./screens/rule-detail.ts"; +import { RulesScreen } from "./screens/rules.ts"; +import { SearchScreen } from "./screens/search.ts"; +import { BG_PRIMARY } from "./theme.ts"; +import type { + AppContext, + NavigateParams, + Screen, + ScreenEntry, + ScreenName, +} from "./types.ts"; + +const SCREEN_LABELS: Record = { + dashboard: "Dashboard", + memories: "Memories", + "memory-detail": "Memory Detail", + rules: "Rules", + "rule-detail": "Rule Detail", + entities: "Code Entities", + search: "Search", +}; + +const SCREEN_HINTS: Partial> = { + "memory-detail": "Esc:Back j/k:Scroll", + "rule-detail": "Esc:Back j/k:Scroll", +}; + +export class App implements AppContext { + renderer: CliRenderer; + store: DataStore; + + private header: ReturnType; + private statusBar: ReturnType; + private contentArea: BoxRenderable; + private currentScreen: Screen | null = null; + private history: ScreenEntry[] = []; + + constructor(renderer: CliRenderer, store: DataStore, projectPath: string) { + this.renderer = renderer; + this.store = store; + + // Build persistent layout frame + const root = new BoxRenderable(renderer, { + id: "root", + width: "100%", + height: "100%", + flexDirection: "column", + backgroundColor: BG_PRIMARY, + }); + + this.header = createHeader(renderer, projectPath); + this.contentArea = new BoxRenderable(renderer, { + id: "content-area", + flexGrow: 1, + width: "100%", + flexDirection: "column", + backgroundColor: BG_PRIMARY, + }); + this.statusBar = createStatusBar(renderer); + + root.add(this.header.renderable); + root.add(this.contentArea); + root.add(this.statusBar.renderable); + + renderer.root.add(root); + + // Global keyboard handler + renderer.keyInput.on("keypress", (key: KeyEvent) => { + this.handleGlobalKey(key); + }); + } + + start() { + this.navigateTo("dashboard"); + } + + navigateTo(name: ScreenName, params?: NavigateParams) { + // Push current to history (but not if going back) + if (this.currentScreen) { + this.history.push({ + name: this.currentScreen.name, + }); + if (this.history.length > 10) { + this.history.shift(); + } + } + + this.switchScreen(name, params); + } + + goBack() { + const prev = this.history.pop(); + if (prev) { + this.switchScreen(prev.name, prev.params); + } + } + + private switchScreen(name: ScreenName, params?: NavigateParams) { + // Destroy current screen + if (this.currentScreen) { + this.currentScreen.destroy(); + this.currentScreen = null; + } + + // Clear content area children + for (const child of this.contentArea.getChildren()) { + child.destroy(); + } + const screen = this.createScreen(name, params); + this.currentScreen = screen; + + // Mount + screen.mount(this.contentArea); + + // Update chrome + this.header.update(SCREEN_LABELS[name] ?? name); + this.statusBar.update(SCREEN_HINTS[name]); + } + + private createScreen(name: ScreenName, params?: NavigateParams): Screen { + switch (name) { + case "dashboard": + return new DashboardScreen(this); + case "memories": + return new MemoriesScreen(this, params); + case "memory-detail": + return new MemoryDetailScreen(this, params!); + case "rules": + return new RulesScreen(this); + case "rule-detail": + return new RuleDetailScreen(this, params!); + case "entities": + return new EntitiesScreen(this); + case "search": + return new SearchScreen(this, params); + default: + return new DashboardScreen(this); + } + } + + private handleGlobalKey(key: KeyEvent) { + // Let the current screen handle it first + if (this.currentScreen?.onKeypress?.(key)) { + return; + } + + // Don't process global shortcuts when an input is focused + if ( + this.renderer.currentFocusedRenderable && + "placeholder" in this.renderer.currentFocusedRenderable + ) { + return; + } + + switch (key.name) { + case "1": + if (this.currentScreen?.name !== "dashboard") { + this.navigateTo("dashboard"); + } + break; + case "2": + if (this.currentScreen?.name !== "memories") { + this.navigateTo("memories"); + } + break; + case "3": + if (this.currentScreen?.name !== "rules") { + this.navigateTo("rules"); + } + break; + case "4": + if (this.currentScreen?.name !== "entities") { + this.navigateTo("entities"); + } + break; + case "/": + if (this.currentScreen?.name !== "search") { + this.navigateTo("search"); + } + break; + case "q": + this.store.close(); + this.renderer.destroy(); + process.exit(0); + break; + case "escape": + this.goBack(); + break; + } + } +} diff --git a/apps/tui/src/components/category-badge.ts b/apps/tui/src/components/category-badge.ts new file mode 100644 index 0000000..ff31372 --- /dev/null +++ b/apps/tui/src/components/category-badge.ts @@ -0,0 +1,10 @@ +import { CATEGORY_COLORS, CATEGORY_ICONS, FG_SECONDARY } from "../theme.ts"; + +export function categoryLabel(category: string): string { + const icon = CATEGORY_ICONS[category] ?? "\u25cb"; + return `${icon} ${category.toUpperCase()}`; +} + +export function categoryColor(category: string): string { + return CATEGORY_COLORS[category] ?? FG_SECONDARY; +} diff --git a/apps/tui/src/components/empty-state.ts b/apps/tui/src/components/empty-state.ts new file mode 100644 index 0000000..a01676b --- /dev/null +++ b/apps/tui/src/components/empty-state.ts @@ -0,0 +1,22 @@ +import type { CliRenderer } from "@opentui/core"; +import { BoxRenderable, TextRenderable } from "@opentui/core"; +import { FG_MUTED } from "../theme.ts"; + +export function createEmptyState(renderer: CliRenderer, message: string) { + const box = new BoxRenderable(renderer, { + id: "empty-state", + width: "100%", + flexGrow: 1, + justifyContent: "center", + alignItems: "center", + }); + + const text = new TextRenderable(renderer, { + content: message, + fg: FG_MUTED, + attributes: 4, // ITALIC + }); + + box.add(text); + return box; +} diff --git a/apps/tui/src/components/header.ts b/apps/tui/src/components/header.ts new file mode 100644 index 0000000..28649da --- /dev/null +++ b/apps/tui/src/components/header.ts @@ -0,0 +1,59 @@ +import type { CliRenderer } from "@opentui/core"; +import { BoxRenderable, TextRenderable } from "@opentui/core"; +import { + BG_SECONDARY, + COLOR_ACCENT, + COLOR_BORDER, + FG_PRIMARY, + FG_SECONDARY, +} from "../theme.ts"; + +export function createHeader(renderer: CliRenderer, projectPath: string) { + const container = new BoxRenderable(renderer, { + id: "header", + height: 3, + width: "100%", + flexDirection: "row", + justifyContent: "space-between", + alignItems: "center", + backgroundColor: BG_SECONDARY, + border: true, + borderStyle: "heavy", + borderColor: COLOR_BORDER, + paddingLeft: 1, + paddingRight: 1, + }); + + const title = new TextRenderable(renderer, { + id: "header-title", + content: " code-recall ", + fg: COLOR_ACCENT, + attributes: 1, // BOLD + }); + + const breadcrumb = new TextRenderable(renderer, { + id: "header-breadcrumb", + content: "Dashboard", + fg: FG_PRIMARY, + }); + + const truncatedPath = + projectPath.length > 40 ? `...${projectPath.slice(-37)}` : projectPath; + const path = new TextRenderable(renderer, { + id: "header-path", + content: truncatedPath, + fg: FG_SECONDARY, + attributes: 4, // ITALIC + }); + + container.add(title); + container.add(breadcrumb); + container.add(path); + + return { + renderable: container, + update(screenName: string) { + breadcrumb.content = screenName; + }, + }; +} diff --git a/apps/tui/src/components/memory-card.ts b/apps/tui/src/components/memory-card.ts new file mode 100644 index 0000000..ae89344 --- /dev/null +++ b/apps/tui/src/components/memory-card.ts @@ -0,0 +1,29 @@ +import type { MemoryRow } from "../types.ts"; +import { categoryLabel } from "./category-badge.ts"; +import { outcomeLabel } from "./outcome-badge.ts"; + +export function formatMemoryOption(memory: MemoryRow) { + const badge = categoryLabel(memory.category); + const content = + memory.content.length > 60 + ? `${memory.content.slice(0, 57)}...` + : memory.content; + + const parts: string[] = []; + if (memory.tags) { + try { + const tags = JSON.parse(memory.tags) as string[]; + if (tags.length > 0) parts.push(`Tags: ${tags.join(", ")}`); + } catch {} + } + if (memory.file_path) { + parts.push(`File: ${memory.file_path}`); + } + parts.push(outcomeLabel(memory.worked)); + + return { + name: `[${badge}] ${content}`, + description: parts.join(" | "), + value: memory.id, + }; +} diff --git a/apps/tui/src/components/outcome-badge.ts b/apps/tui/src/components/outcome-badge.ts new file mode 100644 index 0000000..2f95cd7 --- /dev/null +++ b/apps/tui/src/components/outcome-badge.ts @@ -0,0 +1,18 @@ +import { + COLOR_FAILURE, + COLOR_PENDING, + COLOR_SUCCESS, + OUTCOME_ICONS, +} from "../theme.ts"; + +export function outcomeLabel(worked: number | null): string { + if (worked === 1) return `${OUTCOME_ICONS.worked} WORKED`; + if (worked === 0) return `${OUTCOME_ICONS.failed} FAILED`; + return `${OUTCOME_ICONS.pending} PENDING`; +} + +export function outcomeColor(worked: number | null): string { + if (worked === 1) return COLOR_SUCCESS; + if (worked === 0) return COLOR_FAILURE; + return COLOR_PENDING; +} diff --git a/apps/tui/src/components/rule-card.ts b/apps/tui/src/components/rule-card.ts new file mode 100644 index 0000000..85ad45e --- /dev/null +++ b/apps/tui/src/components/rule-card.ts @@ -0,0 +1,28 @@ +import type { RuleRow } from "../types.ts"; + +function parseJsonArray(raw: string | null): string[] { + if (!raw) return []; + try { + const parsed = JSON.parse(raw); + return Array.isArray(parsed) ? parsed : []; + } catch { + return []; + } +} + +export function formatRuleOption(rule: RuleRow) { + const mustDo = parseJsonArray(rule.must_do); + const mustNot = parseJsonArray(rule.must_not); + const askFirst = parseJsonArray(rule.ask_first); + + const parts: string[] = []; + if (mustDo.length > 0) parts.push(`+ ${mustDo.length} must-do`); + if (mustNot.length > 0) parts.push(`- ${mustNot.length} must-not`); + if (askFirst.length > 0) parts.push(`? ${askFirst.length} ask-first`); + + return { + name: `"${rule.trigger}"`, + description: parts.join(" | ") || "No constraints defined", + value: rule.id, + }; +} diff --git a/apps/tui/src/components/stat-box.ts b/apps/tui/src/components/stat-box.ts new file mode 100644 index 0000000..b71b753 --- /dev/null +++ b/apps/tui/src/components/stat-box.ts @@ -0,0 +1,44 @@ +import type { CliRenderer } from "@opentui/core"; +import { BoxRenderable, TextRenderable } from "@opentui/core"; +import { + BG_SECONDARY, + COLOR_BORDER, + FG_SECONDARY, + PANEL_BORDER, +} from "../theme.ts"; + +export function createStatBox( + renderer: CliRenderer, + opts: { value: number; label: string; color: string }, +) { + const box = new BoxRenderable(renderer, { + id: `stat-${opts.label.toLowerCase().replace(/\s+/g, "-")}`, + flexGrow: 1, + height: 6, + flexDirection: "column", + justifyContent: "center", + alignItems: "center", + backgroundColor: BG_SECONDARY, + border: true, + borderStyle: PANEL_BORDER, + borderColor: COLOR_BORDER, + paddingLeft: 1, + paddingRight: 1, + }); + + const value = new TextRenderable(renderer, { + content: String(opts.value), + fg: opts.color, + attributes: 1, // BOLD + }); + + const label = new TextRenderable(renderer, { + content: opts.label, + fg: FG_SECONDARY, + }); + + box.add(value); + box.add(label); + + return box; +} diff --git a/apps/tui/src/components/status-bar.ts b/apps/tui/src/components/status-bar.ts new file mode 100644 index 0000000..553ebb4 --- /dev/null +++ b/apps/tui/src/components/status-bar.ts @@ -0,0 +1,34 @@ +import type { CliRenderer } from "@opentui/core"; +import { BoxRenderable, TextRenderable } from "@opentui/core"; +import { BG_TERTIARY, FG_SECONDARY } from "../theme.ts"; + +const DEFAULT_HINTS = + "1:Dashboard 2:Memories 3:Rules 4:Entities /:Search q:Quit"; + +export function createStatusBar(renderer: CliRenderer) { + const container = new BoxRenderable(renderer, { + id: "status-bar", + height: 1, + width: "100%", + flexDirection: "row", + alignItems: "center", + backgroundColor: BG_TERTIARY, + paddingLeft: 1, + paddingRight: 1, + }); + + const hints = new TextRenderable(renderer, { + id: "status-hints", + content: DEFAULT_HINTS, + fg: FG_SECONDARY, + }); + + container.add(hints); + + return { + renderable: container, + update(text?: string) { + hints.content = text ?? DEFAULT_HINTS; + }, + }; +} diff --git a/apps/tui/src/data/store.ts b/apps/tui/src/data/store.ts new file mode 100644 index 0000000..9de5ecb --- /dev/null +++ b/apps/tui/src/data/store.ts @@ -0,0 +1,199 @@ +import { Database } from "bun:sqlite"; +import { existsSync } from "node:fs"; +import { join } from "node:path"; +import type { CodeEntityRow, MemoryRow, RuleRow, Stats } from "../types.ts"; + +const HOMEBREW_SQLITE_PATHS = [ + "/opt/homebrew/opt/sqlite/lib/libsqlite3.dylib", + "/usr/local/opt/sqlite/lib/libsqlite3.dylib", +]; + +let sqliteConfigured = false; + +function configureSQLite(): void { + if (sqliteConfigured) return; + if (process.platform === "darwin") { + const path = HOMEBREW_SQLITE_PATHS.find((p) => existsSync(p)); + if (path) { + Database.setCustomSQLite(path); + } + } + sqliteConfigured = true; +} + +export class DataStore { + private db: Database; + readonly dbPath: string; + + constructor(projectPath: string) { + configureSQLite(); + this.dbPath = join(projectPath, ".code-recall", "memory.db"); + if (!existsSync(this.dbPath)) { + throw new Error( + `No code-recall database found at ${this.dbPath}\nRun the code-recall MCP server first to initialize the database.`, + ); + } + this.db = new Database(this.dbPath, { readonly: true }); + } + + // --- Memories --- + + getRecentMemories(limit = 50): MemoryRow[] { + return this.db + .query( + "SELECT * FROM memories WHERE archived = 0 ORDER BY created_at DESC LIMIT ?", + ) + .all(limit) as MemoryRow[]; + } + + getMemoriesByCategory(category: string, limit = 50): MemoryRow[] { + return this.db + .query( + "SELECT * FROM memories WHERE category = ? AND archived = 0 ORDER BY created_at DESC LIMIT ?", + ) + .all(category, limit) as MemoryRow[]; + } + + getMemoryById(id: number): MemoryRow | null { + return ( + (this.db + .query("SELECT * FROM memories WHERE id = ?") + .get(id) as MemoryRow | null) ?? null + ); + } + + getFailedMemories(limit = 20): MemoryRow[] { + return this.db + .query( + "SELECT * FROM memories WHERE worked = 0 AND archived = 0 ORDER BY updated_at DESC LIMIT ?", + ) + .all(limit) as MemoryRow[]; + } + + getPinnedMemories(): MemoryRow[] { + return this.db + .query( + "SELECT * FROM memories WHERE pinned = 1 AND archived = 0 ORDER BY created_at DESC", + ) + .all() as MemoryRow[]; + } + + searchByFullText(query: string, limit = 20): MemoryRow[] { + return this.db + .query( + `SELECT m.* FROM memories m + JOIN memories_fts fts ON m.id = fts.rowid + WHERE memories_fts MATCH ? AND m.archived = 0 + ORDER BY rank + LIMIT ?`, + ) + .all(query, limit) as MemoryRow[]; + } + + getMemoriesByFilePath(filePath: string): MemoryRow[] { + return this.db + .query( + "SELECT * FROM memories WHERE file_path = ? AND archived = 0 ORDER BY created_at DESC", + ) + .all(filePath) as MemoryRow[]; + } + + // --- Rules --- + + getActiveRules(): RuleRow[] { + return this.db + .query("SELECT * FROM rules WHERE active = 1 ORDER BY created_at DESC") + .all() as RuleRow[]; + } + + getRuleById(id: number): RuleRow | null { + return ( + (this.db + .query("SELECT * FROM rules WHERE id = ?") + .get(id) as RuleRow | null) ?? null + ); + } + + // --- Code Entities --- + + getCodeEntitiesByFile(filePath: string): CodeEntityRow[] { + return this.db + .query( + "SELECT * FROM code_entities WHERE file_path = ? ORDER BY start_line ASC", + ) + .all(filePath) as CodeEntityRow[]; + } + + getDistinctEntityFiles(): string[] { + const rows = this.db + .query( + "SELECT DISTINCT file_path FROM code_entities ORDER BY file_path ASC", + ) + .all() as Array<{ file_path: string }>; + return rows.map((r) => r.file_path); + } + + // --- Stats --- + + getStats(): Stats { + const total = ( + this.db + .query("SELECT COUNT(*) as count FROM memories WHERE archived = 0") + .get() as { count: number } + ).count; + + const categories = this.db + .query( + "SELECT category, COUNT(*) as count FROM memories WHERE archived = 0 GROUP BY category", + ) + .all() as Array<{ category: string; count: number }>; + + const byCategory: Record = {}; + for (const row of categories) { + byCategory[row.category] = row.count; + } + + const totalRules = ( + this.db + .query("SELECT COUNT(*) as count FROM rules WHERE active = 1") + .get() as { count: number } + ).count; + + const recentDecisions = ( + this.db + .query( + "SELECT COUNT(*) as count FROM memories WHERE category = 'decision' AND archived = 0 AND created_at >= datetime('now', '-7 days')", + ) + .get() as { count: number } + ).count; + + const failedDecisions = ( + this.db + .query( + "SELECT COUNT(*) as count FROM memories WHERE worked = 0 AND archived = 0", + ) + .get() as { count: number } + ).count; + + const totalWarnings = ( + this.db + .query( + "SELECT COUNT(*) as count FROM memories WHERE category = 'warning' AND archived = 0", + ) + .get() as { count: number } + ).count; + + return { + totalMemories: total, + byCategory, + totalRules, + recentDecisions, + failedDecisions, + totalWarnings, + }; + } + + close(): void { + this.db.close(); + } +} diff --git a/apps/tui/src/index.ts b/apps/tui/src/index.ts new file mode 100644 index 0000000..49a2029 --- /dev/null +++ b/apps/tui/src/index.ts @@ -0,0 +1,61 @@ +#!/usr/bin/env bun +import { existsSync } from "node:fs"; +import { resolve } from "node:path"; +import { createCliRenderer } from "@opentui/core"; +import { App } from "./app.ts"; +import { DataStore } from "./data/store.ts"; + +function getProjectPath(): string { + // Check CLI args + const args = process.argv.slice(2); + const projectIdx = args.indexOf("--project"); + if (projectIdx >= 0 && args[projectIdx + 1]) { + return resolve(args[projectIdx + 1]!); + } + + // Check env var + if (process.env.CODE_RECALL_PROJECT_PATH) { + return resolve(process.env.CODE_RECALL_PROJECT_PATH); + } + + // Default to cwd + return process.cwd(); +} + +async function main() { + const projectPath = getProjectPath(); + const dbPath = `${projectPath}/.code-recall/memory.db`; + + if (!existsSync(dbPath)) { + console.error( + `\n Error: No code-recall database found.\n\n` + + ` Looked at: ${dbPath}\n\n` + + ` Run the code-recall MCP server first to initialize the database,\n` + + ` or specify a project path:\n\n` + + ` code-recall-tui --project /path/to/project\n`, + ); + process.exit(1); + } + + let store: DataStore; + try { + store = new DataStore(projectPath); + } catch (err) { + console.error( + `\n Error: Could not open database.\n ${err instanceof Error ? err.message : err}\n`, + ); + process.exit(1); + } + + const renderer = await createCliRenderer({ + exitOnCtrlC: true, + }); + + const app = new App(renderer, store, projectPath); + app.start(); +} + +main().catch((err) => { + console.error("Fatal error:", err); + process.exit(1); +}); diff --git a/apps/tui/src/screens/dashboard.ts b/apps/tui/src/screens/dashboard.ts new file mode 100644 index 0000000..a2cc209 --- /dev/null +++ b/apps/tui/src/screens/dashboard.ts @@ -0,0 +1,229 @@ +import type { KeyEvent } from "@opentui/core"; +import { BoxRenderable, SelectRenderable, TextRenderable } from "@opentui/core"; +import { categoryColor } from "../components/category-badge.ts"; +import { createEmptyState } from "../components/empty-state.ts"; +import { formatMemoryOption } from "../components/memory-card.ts"; +import { createStatBox } from "../components/stat-box.ts"; +import { + BG_SECONDARY, + BG_TERTIARY, + CATEGORY_ICONS, + COLOR_ACCENT, + COLOR_BORDER, + COLOR_FAILURE, + COLOR_WARNING, + FG_MUTED, + FG_PRIMARY, + FG_SECONDARY, + PANEL_BORDER, +} from "../theme.ts"; +import type { AppContext, Screen } from "../types.ts"; + +export class DashboardScreen implements Screen { + readonly name = "dashboard" as const; + private container: BoxRenderable | null = null; + private recentSelect: SelectRenderable | null = null; + private ctx: AppContext; + + constructor(ctx: AppContext) { + this.ctx = ctx; + } + + mount(contentArea: BoxRenderable) { + const { renderer, store } = this.ctx; + const stats = store.getStats(); + const recentMemories = store.getRecentMemories(10); + const failedMemories = store.getFailedMemories(5); + + this.container = new BoxRenderable(renderer, { + id: "dashboard", + width: "100%", + flexGrow: 1, + flexDirection: "column", + gap: 1, + padding: 1, + }); + + // --- Stats row --- + const statsRow = new BoxRenderable(renderer, { + id: "stats-row", + width: "100%", + height: 6, + flexDirection: "row", + gap: 1, + }); + + statsRow.add( + createStatBox(renderer, { + value: stats.totalMemories, + label: "Memories", + color: COLOR_ACCENT, + }), + ); + statsRow.add( + createStatBox(renderer, { + value: stats.totalRules, + label: "Rules", + color: COLOR_ACCENT, + }), + ); + statsRow.add( + createStatBox(renderer, { + value: stats.failedDecisions, + label: "Failed", + color: COLOR_FAILURE, + }), + ); + statsRow.add( + createStatBox(renderer, { + value: stats.totalWarnings, + label: "Warnings", + color: COLOR_WARNING, + }), + ); + + this.container.add(statsRow); + + // --- Middle row: categories + recent --- + const middleRow = new BoxRenderable(renderer, { + id: "middle-row", + width: "100%", + flexGrow: 1, + flexDirection: "row", + gap: 1, + }); + + // Category breakdown panel + const categoryPanel = new BoxRenderable(renderer, { + id: "category-panel", + width: "35%", + flexDirection: "column", + border: true, + borderStyle: PANEL_BORDER, + borderColor: COLOR_BORDER, + title: " Categories ", + titleAlignment: "left", + padding: 1, + gap: 1, + backgroundColor: BG_SECONDARY, + }); + + for (const cat of ["decision", "pattern", "warning", "learning"]) { + const count = stats.byCategory[cat] ?? 0; + const icon = CATEGORY_ICONS[cat] ?? ""; + const row = new BoxRenderable(renderer, { + flexDirection: "row", + justifyContent: "space-between", + width: "100%", + }); + row.add( + new TextRenderable(renderer, { + content: `${icon} ${cat.charAt(0).toUpperCase() + cat.slice(1)}`, + fg: categoryColor(cat), + }), + ); + row.add( + new TextRenderable(renderer, { + content: String(count), + fg: FG_PRIMARY, + attributes: 1, + }), + ); + categoryPanel.add(row); + } + + middleRow.add(categoryPanel); + + // Recent activity panel + const recentPanel = new BoxRenderable(renderer, { + id: "recent-panel", + flexGrow: 1, + flexDirection: "column", + border: true, + borderStyle: PANEL_BORDER, + borderColor: COLOR_BORDER, + title: " Recent Activity ", + titleAlignment: "left", + backgroundColor: BG_SECONDARY, + }); + + if (recentMemories.length === 0) { + recentPanel.add( + createEmptyState(renderer, "No memories yet. Start using code-recall!"), + ); + } else { + this.recentSelect = new SelectRenderable(renderer, { + id: "recent-select", + options: recentMemories.map(formatMemoryOption), + backgroundColor: BG_SECONDARY, + focusedBackgroundColor: BG_SECONDARY, + selectedBackgroundColor: BG_TERTIARY, + selectedTextColor: FG_PRIMARY, + textColor: FG_SECONDARY, + descriptionColor: FG_MUTED, + selectedDescriptionColor: FG_SECONDARY, + showDescription: true, + flexGrow: 1, + width: "100%", + }); + + this.recentSelect.on("itemSelected", () => { + const opt = this.recentSelect?.getSelectedOption(); + if (opt?.value != null) { + this.ctx.navigateTo("memory-detail", { memoryId: opt.value }); + } + }); + + recentPanel.add(this.recentSelect); + this.recentSelect.focus(); + } + + middleRow.add(recentPanel); + this.container.add(middleRow); + + // --- Failed approaches panel --- + if (failedMemories.length > 0) { + const failedPanel = new BoxRenderable(renderer, { + id: "failed-panel", + width: "100%", + height: Math.min(failedMemories.length + 3, 8), + flexDirection: "column", + border: true, + borderStyle: PANEL_BORDER, + borderColor: COLOR_FAILURE, + title: " Failed Approaches ", + titleAlignment: "left", + backgroundColor: BG_SECONDARY, + padding: 1, + gap: 0, + }); + + for (const mem of failedMemories) { + const content = + mem.content.length > 80 + ? `${mem.content.slice(0, 77)}...` + : mem.content; + failedPanel.add( + new TextRenderable(renderer, { + content: `\u2717 ${content}`, + fg: COLOR_FAILURE, + }), + ); + } + + this.container.add(failedPanel); + } + + contentArea.add(this.container); + } + + onKeypress(_key: KeyEvent): boolean { + return false; + } + + destroy() { + this.container?.destroy(); + this.container = null; + this.recentSelect = null; + } +} diff --git a/apps/tui/src/screens/entities.ts b/apps/tui/src/screens/entities.ts new file mode 100644 index 0000000..245801f --- /dev/null +++ b/apps/tui/src/screens/entities.ts @@ -0,0 +1,288 @@ +import type { KeyEvent } from "@opentui/core"; +import { + BoxRenderable, + ScrollBoxRenderable, + SelectRenderable, + TextRenderable, +} from "@opentui/core"; +import { createEmptyState } from "../components/empty-state.ts"; +import { + BG_SECONDARY, + BG_TERTIARY, + COLOR_ACCENT, + COLOR_BORDER, + COLOR_DECISION, + COLOR_LEARNING, + COLOR_PATTERN, + COLOR_WARNING, + FG_MUTED, + FG_PRIMARY, + FG_SECONDARY, + PANEL_BORDER, +} from "../theme.ts"; +import type { AppContext, Screen } from "../types.ts"; + +const ENTITY_TYPE_COLORS: Record = { + class: COLOR_DECISION, + interface: COLOR_DECISION, + type: COLOR_LEARNING, + function: COLOR_PATTERN, + method: COLOR_PATTERN, + variable: COLOR_WARNING, + import: FG_MUTED, +}; + +export class EntitiesScreen implements Screen { + readonly name = "entities" as const; + private container: BoxRenderable | null = null; + private fileSelect: SelectRenderable | null = null; + private entityPanel: BoxRenderable | null = null; + private ctx: AppContext; + private files: string[] = []; + private focusOnEntities = false; + + constructor(ctx: AppContext) { + this.ctx = ctx; + } + + mount(contentArea: BoxRenderable) { + const { renderer, store } = this.ctx; + this.files = store.getDistinctEntityFiles(); + + this.container = new BoxRenderable(renderer, { + id: "entities-screen", + width: "100%", + flexGrow: 1, + flexDirection: "column", + padding: 1, + gap: 1, + }); + + // Header + const headerRow = new BoxRenderable(renderer, { + width: "100%", + flexDirection: "row", + justifyContent: "space-between", + }); + headerRow.add( + new TextRenderable(renderer, { + content: "Analyzed Files", + fg: FG_PRIMARY, + attributes: 1, + }), + ); + headerRow.add( + new TextRenderable(renderer, { + content: `${this.files.length} files`, + fg: FG_MUTED, + }), + ); + this.container.add(headerRow); + + if (this.files.length === 0) { + this.container.add( + createEmptyState( + renderer, + "No code entities analyzed yet. Use analyze_structure via MCP.", + ), + ); + contentArea.add(this.container); + return; + } + + // Split view + const splitRow = new BoxRenderable(renderer, { + id: "split-row", + width: "100%", + flexGrow: 1, + flexDirection: "row", + gap: 1, + }); + + // File list (left) + const filePanel = new BoxRenderable(renderer, { + id: "file-panel", + width: "35%", + flexDirection: "column", + border: true, + borderStyle: PANEL_BORDER, + borderColor: COLOR_BORDER, + title: " Files ", + titleAlignment: "left", + backgroundColor: BG_SECONDARY, + }); + + this.fileSelect = new SelectRenderable(renderer, { + id: "file-select", + options: this.files.map((f) => ({ + name: shortenPath(f), + description: "", + value: f, + })), + backgroundColor: BG_SECONDARY, + focusedBackgroundColor: BG_SECONDARY, + selectedBackgroundColor: BG_TERTIARY, + selectedTextColor: COLOR_ACCENT, + textColor: FG_SECONDARY, + showDescription: false, + showScrollIndicator: true, + flexGrow: 1, + width: "100%", + }); + + this.fileSelect.on("selectionChanged", () => { + this.loadEntities(); + }); + + filePanel.add(this.fileSelect); + splitRow.add(filePanel); + + // Entity panel (right) + this.entityPanel = new BoxRenderable(renderer, { + id: "entity-panel", + flexGrow: 1, + flexDirection: "column", + border: true, + borderStyle: PANEL_BORDER, + borderColor: COLOR_BORDER, + title: " Entities ", + titleAlignment: "left", + backgroundColor: BG_SECONDARY, + }); + + splitRow.add(this.entityPanel); + this.container.add(splitRow); + + // Load first file + this.loadEntities(); + this.fileSelect.focus(); + + contentArea.add(this.container); + } + + private loadEntities() { + const opt = this.fileSelect?.getSelectedOption(); + if (!opt?.value || !this.entityPanel) return; + + const { renderer, store } = this.ctx; + const filePath = opt.value as string; + const entities = store.getCodeEntitiesByFile(filePath); + + // Clear entity panel + for (const child of this.entityPanel.getChildren()) { + child.destroy(); + } + + // Update panel title + this.entityPanel.title = ` ${shortenPath(filePath)} `; + + if (entities.length === 0) { + this.entityPanel.add( + createEmptyState(renderer, "No entities in this file."), + ); + return; + } + + const scrollBox = new ScrollBoxRenderable(renderer, { + id: "entity-scroll", + flexGrow: 1, + width: "100%", + scrollY: true, + backgroundColor: BG_SECONDARY, + contentOptions: { + flexDirection: "column", + gap: 0, + width: "100%", + }, + }); + + for (const entity of entities) { + const row = new BoxRenderable(renderer, { + width: "100%", + flexDirection: "row", + gap: 1, + paddingLeft: 1, + }); + + const typeColor = ENTITY_TYPE_COLORS[entity.entity_type] ?? FG_SECONDARY; + row.add( + new TextRenderable(renderer, { + content: `[${entity.entity_type}]`.padEnd(12), + fg: typeColor, + attributes: 1, + }), + ); + + const displayName = entity.qualified_name || entity.name; + row.add( + new TextRenderable(renderer, { + content: displayName, + fg: FG_PRIMARY, + }), + ); + + row.add( + new TextRenderable(renderer, { + content: `L${entity.start_line}-${entity.end_line}`, + fg: FG_MUTED, + }), + ); + + scrollBox.add(row); + + if (entity.signature) { + const sigRow = new BoxRenderable(renderer, { + width: "100%", + paddingLeft: 14, + }); + sigRow.add( + new TextRenderable(renderer, { + content: + entity.signature.length > 70 + ? `${entity.signature.slice(0, 67)}...` + : entity.signature, + fg: FG_MUTED, + attributes: 4, + }), + ); + scrollBox.add(sigRow); + } + } + + this.entityPanel.add(scrollBox); + } + + onKeypress(key: KeyEvent): boolean { + if (key.name === "tab" && this.fileSelect) { + if (this.focusOnEntities) { + this.fileSelect.focus(); + this.focusOnEntities = false; + } else { + // Find the scrollbox in entity panel and focus it + const children = this.entityPanel?.getChildren() ?? []; + for (const child of children) { + if ("scrollBy" in child) { + child.focus(); + this.focusOnEntities = true; + break; + } + } + } + return true; + } + return false; + } + + destroy() { + this.container?.destroy(); + this.container = null; + this.fileSelect = null; + this.entityPanel = null; + } +} + +function shortenPath(filePath: string): string { + const parts = filePath.split("/"); + if (parts.length <= 3) return filePath; + return `.../${parts.slice(-3).join("/")}`; +} diff --git a/apps/tui/src/screens/memories.ts b/apps/tui/src/screens/memories.ts new file mode 100644 index 0000000..a5fabad --- /dev/null +++ b/apps/tui/src/screens/memories.ts @@ -0,0 +1,195 @@ +import type { KeyEvent } from "@opentui/core"; +import { + BoxRenderable, + SelectRenderable, + TabSelectRenderable, + TextRenderable, +} from "@opentui/core"; +import { formatMemoryOption } from "../components/memory-card.ts"; +import { + BG_PRIMARY, + BG_SECONDARY, + BG_TERTIARY, + COLOR_ACCENT, + COLOR_BORDER, + FG_MUTED, + FG_PRIMARY, + FG_SECONDARY, + PANEL_BORDER, +} from "../theme.ts"; +import type { + AppContext, + MemoryRow, + NavigateParams, + Screen, +} from "../types.ts"; + +const TABS = [ + { name: "All", description: "", value: "all" }, + { name: "Decisions", description: "", value: "decision" }, + { name: "Patterns", description: "", value: "pattern" }, + { name: "Warnings", description: "", value: "warning" }, + { name: "Learnings", description: "", value: "learning" }, +]; + +export class MemoriesScreen implements Screen { + readonly name = "memories" as const; + private container: BoxRenderable | null = null; + private tabSelect: TabSelectRenderable | null = null; + private memorySelect: SelectRenderable | null = null; + private countText: TextRenderable | null = null; + private emptyState: BoxRenderable | null = null; + private ctx: AppContext; + private initialCategory: string | undefined; + + constructor(ctx: AppContext, params?: NavigateParams) { + this.ctx = ctx; + this.initialCategory = params?.category; + } + + mount(contentArea: BoxRenderable) { + const { renderer } = this.ctx; + + this.container = new BoxRenderable(renderer, { + id: "memories-screen", + width: "100%", + flexGrow: 1, + flexDirection: "column", + padding: 1, + gap: 1, + }); + + // Tab bar + const tabRow = new BoxRenderable(renderer, { + id: "tab-row", + width: "100%", + height: 3, + flexDirection: "row", + alignItems: "center", + gap: 1, + }); + + this.tabSelect = new TabSelectRenderable(renderer, { + id: "memory-tabs", + options: TABS, + height: 1, + flexGrow: 1, + backgroundColor: BG_PRIMARY, + textColor: FG_SECONDARY, + selectedBackgroundColor: COLOR_ACCENT, + selectedTextColor: "#ffffff", + focusedBackgroundColor: BG_PRIMARY, + focusedTextColor: FG_PRIMARY, + showDescription: false, + wrapSelection: true, + }); + + this.countText = new TextRenderable(renderer, { + id: "memory-count", + content: "", + fg: FG_MUTED, + }); + + tabRow.add(this.tabSelect); + tabRow.add(this.countText); + this.container.add(tabRow); + + // Memory list container + const listPanel = new BoxRenderable(renderer, { + id: "memory-list-panel", + flexGrow: 1, + width: "100%", + border: true, + borderStyle: PANEL_BORDER, + borderColor: COLOR_BORDER, + backgroundColor: BG_SECONDARY, + }); + + this.memorySelect = new SelectRenderable(renderer, { + id: "memory-select", + options: [], + backgroundColor: BG_SECONDARY, + focusedBackgroundColor: BG_SECONDARY, + selectedBackgroundColor: BG_TERTIARY, + selectedTextColor: FG_PRIMARY, + textColor: FG_SECONDARY, + descriptionColor: FG_MUTED, + selectedDescriptionColor: FG_SECONDARY, + showDescription: true, + showScrollIndicator: true, + flexGrow: 1, + width: "100%", + }); + + this.memorySelect.on("itemSelected", () => { + const opt = this.memorySelect?.getSelectedOption(); + if (opt?.value != null) { + this.ctx.navigateTo("memory-detail", { memoryId: opt.value }); + } + }); + + listPanel.add(this.memorySelect); + this.container.add(listPanel); + + // Tab change handler + this.tabSelect.on("selectionChanged", () => { + this.loadMemories(); + }); + + // Set initial tab + if (this.initialCategory) { + const idx = TABS.findIndex((t) => t.value === this.initialCategory); + if (idx >= 0) { + this.tabSelect.setSelectedIndex(idx); + } + } + + // Load initial data + this.loadMemories(); + this.memorySelect.focus(); + + contentArea.add(this.container); + } + + private loadMemories() { + const tab = this.tabSelect?.getSelectedOption(); + const category = tab?.value; + + let memories: MemoryRow[]; + if (!category || category === "all") { + memories = this.ctx.store.getRecentMemories(100); + } else { + memories = this.ctx.store.getMemoriesByCategory(category, 100); + } + + const options = memories.map(formatMemoryOption); + if (this.memorySelect) { + this.memorySelect.options = options; + this.memorySelect.setSelectedIndex(0); + } + + if (this.countText) { + this.countText.content = `${memories.length} memories`; + } + } + + onKeypress(key: KeyEvent): boolean { + if (key.name === "[" || key.name === "]") { + if (this.tabSelect) { + if (key.name === "[") this.tabSelect.moveLeft(); + else this.tabSelect.moveRight(); + return true; + } + } + return false; + } + + destroy() { + this.container?.destroy(); + this.container = null; + this.tabSelect = null; + this.memorySelect = null; + this.countText = null; + this.emptyState = null; + } +} diff --git a/apps/tui/src/screens/memory-detail.ts b/apps/tui/src/screens/memory-detail.ts new file mode 100644 index 0000000..cb99997 --- /dev/null +++ b/apps/tui/src/screens/memory-detail.ts @@ -0,0 +1,241 @@ +import type { KeyEvent } from "@opentui/core"; +import { + BoxRenderable, + ScrollBoxRenderable, + TextRenderable, +} from "@opentui/core"; +import { categoryColor, categoryLabel } from "../components/category-badge.ts"; +import { outcomeColor, outcomeLabel } from "../components/outcome-badge.ts"; +import { + BG_PRIMARY, + BG_SECONDARY, + COLOR_ACCENT, + COLOR_BORDER, + FG_MUTED, + FG_PRIMARY, + FG_SECONDARY, + PANEL_BORDER, +} from "../theme.ts"; +import type { AppContext, NavigateParams, Screen } from "../types.ts"; + +export class MemoryDetailScreen implements Screen { + readonly name = "memory-detail" as const; + private scrollBox: ScrollBoxRenderable | null = null; + private ctx: AppContext; + private memoryId: number; + + constructor(ctx: AppContext, params: NavigateParams) { + this.ctx = ctx; + this.memoryId = params.memoryId!; + } + + mount(contentArea: BoxRenderable) { + const { renderer, store } = this.ctx; + const memory = store.getMemoryById(this.memoryId); + + if (!memory) { + const errBox = new BoxRenderable(renderer, { + width: "100%", + flexGrow: 1, + justifyContent: "center", + alignItems: "center", + }); + errBox.add( + new TextRenderable(renderer, { + content: `Memory #${this.memoryId} not found`, + fg: FG_MUTED, + }), + ); + contentArea.add(errBox); + return; + } + + this.scrollBox = new ScrollBoxRenderable(renderer, { + id: "memory-detail-scroll", + width: "100%", + flexGrow: 1, + scrollY: true, + padding: 1, + backgroundColor: BG_PRIMARY, + contentOptions: { + flexDirection: "column", + gap: 1, + width: "100%", + }, + }); + + // --- Header row: category + outcome --- + const headerRow = new BoxRenderable(renderer, { + id: "detail-header", + width: "100%", + flexDirection: "row", + justifyContent: "space-between", + alignItems: "center", + }); + + headerRow.add( + new TextRenderable(renderer, { + content: `Memory #${memory.id} ${categoryLabel(memory.category)}`, + fg: categoryColor(memory.category), + attributes: 1, + }), + ); + + headerRow.add( + new TextRenderable(renderer, { + content: outcomeLabel(memory.worked), + fg: outcomeColor(memory.worked), + attributes: 1, + }), + ); + + this.scrollBox.add(headerRow); + + // --- Dates --- + const dateRow = new BoxRenderable(renderer, { + width: "100%", + flexDirection: "row", + gap: 4, + }); + dateRow.add( + new TextRenderable(renderer, { + content: `Created: ${formatDate(memory.created_at)}`, + fg: FG_MUTED, + }), + ); + dateRow.add( + new TextRenderable(renderer, { + content: `Updated: ${formatDate(memory.updated_at)}`, + fg: FG_MUTED, + }), + ); + this.scrollBox.add(dateRow); + + // --- Content panel --- + this.scrollBox.add(createPanel(renderer, "Content", memory.content)); + + // --- Rationale panel --- + if (memory.rationale) { + this.scrollBox.add(createPanel(renderer, "Rationale", memory.rationale)); + } + + // --- Context panel --- + if (memory.context) { + this.scrollBox.add(createPanel(renderer, "Context", memory.context)); + } + + // --- Tags --- + if (memory.tags) { + try { + const tags = JSON.parse(memory.tags) as string[]; + if (tags.length > 0) { + const tagsRow = new BoxRenderable(renderer, { + width: "100%", + flexDirection: "row", + gap: 1, + }); + tagsRow.add( + new TextRenderable(renderer, { + content: "Tags:", + fg: FG_SECONDARY, + attributes: 1, + }), + ); + tagsRow.add( + new TextRenderable(renderer, { + content: tags.join(", "), + fg: COLOR_ACCENT, + }), + ); + this.scrollBox.add(tagsRow); + } + } catch {} + } + + // --- File path --- + if (memory.file_path) { + const fileRow = new BoxRenderable(renderer, { + width: "100%", + flexDirection: "row", + gap: 1, + }); + fileRow.add( + new TextRenderable(renderer, { + content: "File:", + fg: FG_SECONDARY, + attributes: 1, + }), + ); + fileRow.add( + new TextRenderable(renderer, { + content: memory.file_path, + fg: FG_PRIMARY, + }), + ); + this.scrollBox.add(fileRow); + } + + // --- Outcome panel --- + if (memory.outcome) { + this.scrollBox.add(createPanel(renderer, "Outcome", memory.outcome)); + } + + this.scrollBox.focus(); + contentArea.add(this.scrollBox); + } + + onKeypress(key: KeyEvent): boolean { + if (key.name === "escape") { + this.ctx.goBack(); + return true; + } + return false; + } + + destroy() { + this.scrollBox?.destroy(); + this.scrollBox = null; + } +} + +function createPanel( + renderer: import("@opentui/core").CliRenderer, + title: string, + content: string, +) { + const panel = new BoxRenderable(renderer, { + width: "100%", + flexDirection: "column", + border: true, + borderStyle: PANEL_BORDER, + borderColor: COLOR_BORDER, + title: ` ${title} `, + titleAlignment: "left", + backgroundColor: BG_SECONDARY, + padding: 1, + }); + + panel.add( + new TextRenderable(renderer, { + content, + fg: FG_PRIMARY, + }), + ); + + return panel; +} + +function formatDate(iso: string): string { + try { + const d = new Date(iso); + return d.toLocaleString("en-US", { + year: "numeric", + month: "short", + day: "numeric", + hour: "2-digit", + minute: "2-digit", + }); + } catch { + return iso; + } +} diff --git a/apps/tui/src/screens/rule-detail.ts b/apps/tui/src/screens/rule-detail.ts new file mode 100644 index 0000000..12dd754 --- /dev/null +++ b/apps/tui/src/screens/rule-detail.ts @@ -0,0 +1,209 @@ +import type { KeyEvent } from "@opentui/core"; +import { + BoxRenderable, + ScrollBoxRenderable, + TextRenderable, +} from "@opentui/core"; +import { + BG_PRIMARY, + BG_SECONDARY, + COLOR_ACCENT, + COLOR_BORDER, + COLOR_FAILURE, + COLOR_SUCCESS, + COLOR_WARNING, + FG_MUTED, + PANEL_BORDER, +} from "../theme.ts"; +import type { AppContext, NavigateParams, Screen } from "../types.ts"; + +function parseJsonArray(raw: string | null): string[] { + if (!raw) return []; + try { + const parsed = JSON.parse(raw); + return Array.isArray(parsed) ? parsed : []; + } catch { + return []; + } +} + +export class RuleDetailScreen implements Screen { + readonly name = "rule-detail" as const; + private scrollBox: ScrollBoxRenderable | null = null; + private ctx: AppContext; + private ruleId: number; + + constructor(ctx: AppContext, params: NavigateParams) { + this.ctx = ctx; + this.ruleId = params.ruleId!; + } + + mount(contentArea: BoxRenderable) { + const { renderer, store } = this.ctx; + const rule = store.getRuleById(this.ruleId); + + if (!rule) { + const errBox = new BoxRenderable(renderer, { + width: "100%", + flexGrow: 1, + justifyContent: "center", + alignItems: "center", + }); + errBox.add( + new TextRenderable(renderer, { + content: `Rule #${this.ruleId} not found`, + fg: FG_MUTED, + }), + ); + contentArea.add(errBox); + return; + } + + this.scrollBox = new ScrollBoxRenderable(renderer, { + id: "rule-detail-scroll", + width: "100%", + flexGrow: 1, + scrollY: true, + padding: 1, + backgroundColor: BG_PRIMARY, + contentOptions: { + flexDirection: "column", + gap: 1, + width: "100%", + }, + }); + + // Trigger + this.scrollBox.add( + new TextRenderable(renderer, { + content: `Rule #${rule.id}`, + fg: FG_MUTED, + }), + ); + this.scrollBox.add( + new TextRenderable(renderer, { + content: `"${rule.trigger}"`, + fg: COLOR_ACCENT, + attributes: 1, + }), + ); + + // Date + this.scrollBox.add( + new TextRenderable(renderer, { + content: `Created: ${formatDate(rule.created_at)}`, + fg: FG_MUTED, + }), + ); + + const mustDo = parseJsonArray(rule.must_do); + const mustNot = parseJsonArray(rule.must_not); + const askFirst = parseJsonArray(rule.ask_first); + + // Must Do + if (mustDo.length > 0) { + this.scrollBox.add( + createConstraintPanel(renderer, "Must Do", mustDo, "+", COLOR_SUCCESS), + ); + } + + // Must Not + if (mustNot.length > 0) { + this.scrollBox.add( + createConstraintPanel( + renderer, + "Must Not", + mustNot, + "-", + COLOR_FAILURE, + ), + ); + } + + // Ask First + if (askFirst.length > 0) { + this.scrollBox.add( + createConstraintPanel( + renderer, + "Ask First", + askFirst, + "?", + COLOR_WARNING, + ), + ); + } + + if (mustDo.length === 0 && mustNot.length === 0 && askFirst.length === 0) { + this.scrollBox.add( + new TextRenderable(renderer, { + content: "No constraints defined for this rule.", + fg: FG_MUTED, + attributes: 4, + }), + ); + } + + this.scrollBox.focus(); + contentArea.add(this.scrollBox); + } + + onKeypress(key: KeyEvent): boolean { + if (key.name === "escape") { + this.ctx.goBack(); + return true; + } + return false; + } + + destroy() { + this.scrollBox?.destroy(); + this.scrollBox = null; + } +} + +function createConstraintPanel( + renderer: import("@opentui/core").CliRenderer, + title: string, + items: string[], + prefix: string, + color: string, +) { + const panel = new BoxRenderable(renderer, { + width: "100%", + flexDirection: "column", + border: true, + borderStyle: PANEL_BORDER, + borderColor: COLOR_BORDER, + title: ` ${title} `, + titleAlignment: "left", + backgroundColor: BG_SECONDARY, + padding: 1, + gap: 0, + }); + + for (const item of items) { + panel.add( + new TextRenderable(renderer, { + content: ` ${prefix} ${item}`, + fg: color, + }), + ); + } + + return panel; +} + +function formatDate(iso: string): string { + try { + const d = new Date(iso); + return d.toLocaleString("en-US", { + year: "numeric", + month: "short", + day: "numeric", + hour: "2-digit", + minute: "2-digit", + }); + } catch { + return iso; + } +} diff --git a/apps/tui/src/screens/rules.ts b/apps/tui/src/screens/rules.ts new file mode 100644 index 0000000..5275dca --- /dev/null +++ b/apps/tui/src/screens/rules.ts @@ -0,0 +1,119 @@ +import type { KeyEvent } from "@opentui/core"; +import { BoxRenderable, SelectRenderable, TextRenderable } from "@opentui/core"; +import { createEmptyState } from "../components/empty-state.ts"; +import { formatRuleOption } from "../components/rule-card.ts"; +import { + BG_SECONDARY, + BG_TERTIARY, + COLOR_BORDER, + FG_MUTED, + FG_PRIMARY, + FG_SECONDARY, + PANEL_BORDER, +} from "../theme.ts"; +import type { AppContext, Screen } from "../types.ts"; + +export class RulesScreen implements Screen { + readonly name = "rules" as const; + private container: BoxRenderable | null = null; + private ruleSelect: SelectRenderable | null = null; + private ctx: AppContext; + + constructor(ctx: AppContext) { + this.ctx = ctx; + } + + mount(contentArea: BoxRenderable) { + const { renderer, store } = this.ctx; + const rules = store.getActiveRules(); + + this.container = new BoxRenderable(renderer, { + id: "rules-screen", + width: "100%", + flexGrow: 1, + flexDirection: "column", + padding: 1, + gap: 1, + }); + + // Header + const headerRow = new BoxRenderable(renderer, { + width: "100%", + flexDirection: "row", + justifyContent: "space-between", + alignItems: "center", + }); + + headerRow.add( + new TextRenderable(renderer, { + content: "Active Guardrails", + fg: FG_PRIMARY, + attributes: 1, + }), + ); + + headerRow.add( + new TextRenderable(renderer, { + content: `${rules.length} rules`, + fg: FG_MUTED, + }), + ); + + this.container.add(headerRow); + + // Rule list + const listPanel = new BoxRenderable(renderer, { + id: "rule-list-panel", + flexGrow: 1, + width: "100%", + border: true, + borderStyle: PANEL_BORDER, + borderColor: COLOR_BORDER, + backgroundColor: BG_SECONDARY, + }); + + if (rules.length === 0) { + listPanel.add(createEmptyState(renderer, "No rules defined yet.")); + } else { + this.ruleSelect = new SelectRenderable(renderer, { + id: "rule-select", + options: rules.map(formatRuleOption), + backgroundColor: BG_SECONDARY, + focusedBackgroundColor: BG_SECONDARY, + selectedBackgroundColor: BG_TERTIARY, + selectedTextColor: FG_PRIMARY, + textColor: FG_SECONDARY, + descriptionColor: FG_MUTED, + selectedDescriptionColor: FG_SECONDARY, + showDescription: true, + showScrollIndicator: true, + flexGrow: 1, + width: "100%", + itemSpacing: 1, + }); + + this.ruleSelect.on("itemSelected", () => { + const opt = this.ruleSelect?.getSelectedOption(); + if (opt?.value != null) { + this.ctx.navigateTo("rule-detail", { ruleId: opt.value }); + } + }); + + listPanel.add(this.ruleSelect); + this.ruleSelect.focus(); + } + + this.container.add(listPanel); + contentArea.add(this.container); + } + + onKeypress(_key: KeyEvent): boolean { + return false; + } + + destroy() { + this.container?.destroy(); + this.container = null; + this.ruleSelect = null; + } +} diff --git a/apps/tui/src/screens/search.ts b/apps/tui/src/screens/search.ts new file mode 100644 index 0000000..9c21fc7 --- /dev/null +++ b/apps/tui/src/screens/search.ts @@ -0,0 +1,213 @@ +import { + BoxRenderable, + InputRenderable, + KeyEvent, + SelectRenderable, + TextRenderable, +} from "@opentui/core"; +import { createEmptyState } from "../components/empty-state.ts"; +import { formatMemoryOption } from "../components/memory-card.ts"; +import { + BG_SECONDARY, + BG_TERTIARY, + COLOR_ACCENT, + COLOR_BORDER, + FG_MUTED, + FG_PRIMARY, + FG_SECONDARY, + PANEL_BORDER, +} from "../theme.ts"; +import type { AppContext, NavigateParams, Screen } from "../types.ts"; + +export class SearchScreen implements Screen { + readonly name = "search" as const; + private container: BoxRenderable | null = null; + private input: InputRenderable | null = null; + private resultSelect: SelectRenderable | null = null; + private resultCount: TextRenderable | null = null; + private emptyBox: BoxRenderable | null = null; + private resultsPanel: BoxRenderable | null = null; + private ctx: AppContext; + private inputFocused = true; + + constructor(ctx: AppContext, _params?: NavigateParams) { + this.ctx = ctx; + } + + mount(contentArea: BoxRenderable) { + const { renderer } = this.ctx; + + this.container = new BoxRenderable(renderer, { + id: "search-screen", + width: "100%", + flexGrow: 1, + flexDirection: "column", + padding: 1, + gap: 1, + }); + + // Search input bar + const searchBar = new BoxRenderable(renderer, { + id: "search-bar", + width: "100%", + height: 3, + flexDirection: "row", + alignItems: "center", + border: true, + borderStyle: PANEL_BORDER, + borderColor: COLOR_ACCENT, + title: " Search ", + titleAlignment: "left", + backgroundColor: BG_SECONDARY, + paddingLeft: 1, + paddingRight: 1, + }); + + this.input = new InputRenderable(renderer, { + id: "search-input", + placeholder: "Type a query and press Enter...", + backgroundColor: BG_SECONDARY, + focusedBackgroundColor: BG_SECONDARY, + textColor: FG_PRIMARY, + width: "100%", + }); + + this.input.on("enter", () => { + this.executeSearch(); + }); + + searchBar.add(this.input); + this.container.add(searchBar); + + // Results area + this.resultsPanel = new BoxRenderable(renderer, { + id: "results-panel", + flexGrow: 1, + width: "100%", + flexDirection: "column", + border: true, + borderStyle: PANEL_BORDER, + borderColor: COLOR_BORDER, + backgroundColor: BG_SECONDARY, + }); + + this.resultCount = new TextRenderable(renderer, { + id: "result-count", + content: "", + fg: FG_MUTED, + paddingLeft: 1, + }); + this.resultsPanel.add(this.resultCount); + + this.emptyBox = createEmptyState( + renderer, + "Type a query above and press Enter to search memories.", + ); + this.resultsPanel.add(this.emptyBox); + + this.container.add(this.resultsPanel); + this.input.focus(); + + contentArea.add(this.container); + } + + private executeSearch() { + const query = this.input?.value?.trim(); + if (!query || !this.resultsPanel) return; + + const { renderer, store } = this.ctx; + + try { + const results = store.searchByFullText(query, 30); + + // Remove old results + if (this.resultSelect) { + this.resultSelect.destroy(); + this.resultSelect = null; + } + if (this.emptyBox) { + this.emptyBox.destroy(); + this.emptyBox = null; + } + + if (this.resultCount) { + this.resultCount.content = ` ${results.length} result${results.length !== 1 ? "s" : ""} for "${query}"`; + } + + if (results.length === 0) { + this.emptyBox = createEmptyState( + renderer, + "No results found. Try a different query.", + ); + this.resultsPanel.add(this.emptyBox); + return; + } + + this.resultSelect = new SelectRenderable(renderer, { + id: "result-select", + options: results.map(formatMemoryOption), + backgroundColor: BG_SECONDARY, + focusedBackgroundColor: BG_SECONDARY, + selectedBackgroundColor: BG_TERTIARY, + selectedTextColor: FG_PRIMARY, + textColor: FG_SECONDARY, + descriptionColor: FG_MUTED, + selectedDescriptionColor: FG_SECONDARY, + showDescription: true, + showScrollIndicator: true, + flexGrow: 1, + width: "100%", + }); + + this.resultSelect.on("itemSelected", () => { + const opt = this.resultSelect?.getSelectedOption(); + if (opt?.value != null) { + this.ctx.navigateTo("memory-detail", { memoryId: opt.value }); + } + }); + + this.resultsPanel.add(this.resultSelect); + + // Focus the results + this.resultSelect.focus(); + this.inputFocused = false; + } catch { + if (this.resultCount) { + this.resultCount.content = ` Search error. Try simpler terms (avoid special characters).`; + } + } + } + + onKeypress(key: KeyEvent): boolean { + if (key.name === "tab") { + if (this.inputFocused && this.resultSelect) { + this.resultSelect.focus(); + this.inputFocused = false; + } else if (this.input) { + this.input.focus(); + this.inputFocused = true; + } + return true; + } + if (key.name === "escape") { + if (!this.inputFocused && this.input) { + this.input.focus(); + this.inputFocused = true; + return true; + } + this.ctx.goBack(); + return true; + } + return false; + } + + destroy() { + this.container?.destroy(); + this.container = null; + this.input = null; + this.resultSelect = null; + this.resultCount = null; + this.emptyBox = null; + this.resultsPanel = null; + } +} diff --git a/apps/tui/src/theme.ts b/apps/tui/src/theme.ts new file mode 100644 index 0000000..9f112f1 --- /dev/null +++ b/apps/tui/src/theme.ts @@ -0,0 +1,52 @@ +// Background colors +export const BG_PRIMARY = "#0d1117"; +export const BG_SECONDARY = "#161b22"; +export const BG_TERTIARY = "#21262d"; +export const BG_HOVER = "#30363d"; + +// Text colors +export const FG_PRIMARY = "#e6edf3"; +export const FG_SECONDARY = "#8b949e"; +export const FG_MUTED = "#484f58"; + +// Category colors +export const COLOR_DECISION = "#58a6ff"; +export const COLOR_PATTERN = "#3fb950"; +export const COLOR_WARNING = "#d29922"; +export const COLOR_LEARNING = "#bc8cff"; + +// Outcome colors +export const COLOR_SUCCESS = "#3fb950"; +export const COLOR_FAILURE = "#f85149"; +export const COLOR_PENDING = "#8b949e"; + +// Accent & borders +export const COLOR_ACCENT = "#58a6ff"; +export const COLOR_BORDER = "#30363d"; +export const COLOR_BORDER_FOCUS = "#58a6ff"; + +// Category color lookup +export const CATEGORY_COLORS: Record = { + decision: COLOR_DECISION, + pattern: COLOR_PATTERN, + warning: COLOR_WARNING, + learning: COLOR_LEARNING, +}; + +// Category icons +export const CATEGORY_ICONS: Record = { + decision: "\u25cf", + pattern: "\u25a0", + warning: "\u25b2", + learning: "\u2605", +}; + +// Outcome icons +export const OUTCOME_ICONS: Record = { + worked: "\u2713", + failed: "\u2717", + pending: "\u25cb", +}; + +// Border style +export const PANEL_BORDER = "rounded" as const; diff --git a/apps/tui/src/types.ts b/apps/tui/src/types.ts new file mode 100644 index 0000000..0c13f11 --- /dev/null +++ b/apps/tui/src/types.ts @@ -0,0 +1,89 @@ +import type { BoxRenderable, CliRenderer, KeyEvent } from "@opentui/core"; +import type { DataStore } from "./data/store.ts"; + +export type ScreenName = + | "dashboard" + | "memories" + | "memory-detail" + | "rules" + | "rule-detail" + | "entities" + | "search"; + +export interface Screen { + readonly name: ScreenName; + mount(container: BoxRenderable): void; + destroy(): void; + onKeypress?(key: KeyEvent): boolean; +} + +export interface NavigateParams { + memoryId?: number; + ruleId?: number; + category?: string; + filePath?: string; + searchQuery?: string; +} + +export interface ScreenEntry { + name: ScreenName; + params?: NavigateParams; +} + +export interface AppContext { + renderer: CliRenderer; + store: DataStore; + navigateTo(screen: ScreenName, params?: NavigateParams): void; + goBack(): void; +} + +// Database row types (standalone, no server dependency) +export interface MemoryRow { + id: number; + category: "decision" | "pattern" | "warning" | "learning"; + content: string; + rationale: string | null; + context: string | null; + tags: string | null; + file_path: string | null; + outcome: string | null; + worked: number | null; + pinned: number; + archived: number; + created_at: string; + updated_at: string; +} + +export interface RuleRow { + id: number; + trigger: string; + must_do: string | null; + must_not: string | null; + ask_first: string | null; + active: number; + created_at: string; + updated_at: string; +} + +export interface CodeEntityRow { + id: number; + file_path: string; + entity_type: string; + name: string; + qualified_name: string | null; + signature: string | null; + docstring: string | null; + start_line: number; + end_line: number; + file_hash: string; + created_at: string; +} + +export interface Stats { + totalMemories: number; + byCategory: Record; + totalRules: number; + recentDecisions: number; + failedDecisions: number; + totalWarnings: number; +} diff --git a/apps/tui/tsconfig.json b/apps/tui/tsconfig.json new file mode 100644 index 0000000..12f643d --- /dev/null +++ b/apps/tui/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "lib": ["ESNext"], + "target": "ESNext", + "module": "Preserve", + "moduleDetection": "force", + "allowJs": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "noEmit": true, + "strict": true, + "skipLibCheck": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedIndexedAccess": true, + "noImplicitOverride": true, + "noUnusedLocals": false, + "noUnusedParameters": false, + "noPropertyAccessFromIndexSignature": false + } +} diff --git a/biome.json b/biome.json index 233c05e..553be08 100644 --- a/biome.json +++ b/biome.json @@ -5,6 +5,12 @@ "clientKind": "git", "useIgnoreFile": true }, + "css": { + "parser": { + "cssModules": false, + "tailwindDirectives": true + } + }, "files": { "ignoreUnknown": false }, @@ -22,7 +28,8 @@ "recommended": true, "style": { "useTemplate": "off", - "noNonNullAssertion": "off" + "noNonNullAssertion": "off", + "useImportType": "off" }, "correctness": { "noUnusedPrivateClassMembers": "off" diff --git a/bun.lock b/bun.lock index db60576..d3048c1 100644 --- a/bun.lock +++ b/bun.lock @@ -3,7 +3,20 @@ "configVersion": 1, "workspaces": { "": { + "name": "code-recall-monorepo", + "devDependencies": { + "@biomejs/biome": "2.3.11", + "@changesets/cli": "2.29.8", + "turbo": "2.7.4", + "typescript": "5.9.3", + }, + }, + "apps/server": { "name": "code-recall", + "version": "1.0.0", + "bin": { + "code-recall": "src/index.ts", + }, "dependencies": { "@modelcontextprotocol/sdk": "1.25.2", "@xenova/transformers": "2.17.2", @@ -14,15 +27,32 @@ "zod": "3.25.76", }, "devDependencies": { - "@biomejs/biome": "2.3.11", - "@types/bun": "1.2.15", + "@types/bun": "1.3.6", + }, + "peerDependencies": { + "typescript": "5.9.3", + }, + }, + "apps/tui": { + "name": "code-recall-tui", + "version": "1.0.0", + "bin": { + "code-recall-tui": "src/index.ts", + }, + "dependencies": { + "@opentui/core": "0.1.75", + }, + "devDependencies": { + "@types/bun": "1.3.6", }, "peerDependencies": { - "typescript": "5", + "typescript": "5.9.3", }, }, }, "packages": { + "@babel/runtime": ["@babel/runtime@7.28.6", "", {}, "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA=="], + "@biomejs/biome": ["@biomejs/biome@2.3.11", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.3.11", "@biomejs/cli-darwin-x64": "2.3.11", "@biomejs/cli-linux-arm64": "2.3.11", "@biomejs/cli-linux-arm64-musl": "2.3.11", "@biomejs/cli-linux-x64": "2.3.11", "@biomejs/cli-linux-x64-musl": "2.3.11", "@biomejs/cli-win32-arm64": "2.3.11", "@biomejs/cli-win32-x64": "2.3.11" }, "bin": { "biome": "bin/biome" } }, "sha512-/zt+6qazBWguPG6+eWmiELqO+9jRsMZ/DBU3lfuU2ngtIQYzymocHhKiZRyrbra4aCOoyTg/BmY+6WH5mv9xmQ=="], "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.3.11", "", { "os": "darwin", "cpu": "arm64" }, "sha512-/uXXkBcPKVQY7rc9Ys2CrlirBJYbpESEDme7RKiBD6MmqR2w3j0+ZZXRIL2xiaNPsIMMNhP1YnA+jRRxoOAFrA=="], @@ -41,12 +71,130 @@ "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.3.11", "", { "os": "win32", "cpu": "x64" }, "sha512-43VrG813EW+b5+YbDbz31uUsheX+qFKCpXeY9kfdAx+ww3naKxeVkTD9zLIWxUPfJquANMHrmW3wbe/037G0Qg=="], - "@hono/node-server": ["@hono/node-server@1.19.8", "", { "peerDependencies": { "hono": "^4" } }, "sha512-0/g2lIOPzX8f3vzW1ggQgvG5mjtFBDBHFAzI5SFAi2DzSqS9luJwqg9T6O/gKYLi+inS7eNxBeIFkkghIPvrMA=="], + "@changesets/apply-release-plan": ["@changesets/apply-release-plan@7.0.14", "", { "dependencies": { "@changesets/config": "^3.1.2", "@changesets/get-version-range-type": "^0.4.0", "@changesets/git": "^3.0.4", "@changesets/should-skip-package": "^0.1.2", "@changesets/types": "^6.1.0", "@manypkg/get-packages": "^1.1.3", "detect-indent": "^6.0.0", "fs-extra": "^7.0.1", "lodash.startcase": "^4.4.0", "outdent": "^0.5.0", "prettier": "^2.7.1", "resolve-from": "^5.0.0", "semver": "^7.5.3" } }, "sha512-ddBvf9PHdy2YY0OUiEl3TV78mH9sckndJR14QAt87KLEbIov81XO0q0QAmvooBxXlqRRP8I9B7XOzZwQG7JkWA=="], + + "@changesets/assemble-release-plan": ["@changesets/assemble-release-plan@6.0.9", "", { "dependencies": { "@changesets/errors": "^0.2.0", "@changesets/get-dependents-graph": "^2.1.3", "@changesets/should-skip-package": "^0.1.2", "@changesets/types": "^6.1.0", "@manypkg/get-packages": "^1.1.3", "semver": "^7.5.3" } }, "sha512-tPgeeqCHIwNo8sypKlS3gOPmsS3wP0zHt67JDuL20P4QcXiw/O4Hl7oXiuLnP9yg+rXLQ2sScdV1Kkzde61iSQ=="], + + "@changesets/changelog-git": ["@changesets/changelog-git@0.2.1", "", { "dependencies": { "@changesets/types": "^6.1.0" } }, "sha512-x/xEleCFLH28c3bQeQIyeZf8lFXyDFVn1SgcBiR2Tw/r4IAWlk1fzxCEZ6NxQAjF2Nwtczoen3OA2qR+UawQ8Q=="], + + "@changesets/cli": ["@changesets/cli@2.29.8", "", { "dependencies": { "@changesets/apply-release-plan": "^7.0.14", "@changesets/assemble-release-plan": "^6.0.9", "@changesets/changelog-git": "^0.2.1", "@changesets/config": "^3.1.2", "@changesets/errors": "^0.2.0", "@changesets/get-dependents-graph": "^2.1.3", "@changesets/get-release-plan": "^4.0.14", "@changesets/git": "^3.0.4", "@changesets/logger": "^0.1.1", "@changesets/pre": "^2.0.2", "@changesets/read": "^0.6.6", "@changesets/should-skip-package": "^0.1.2", "@changesets/types": "^6.1.0", "@changesets/write": "^0.4.0", "@inquirer/external-editor": "^1.0.2", "@manypkg/get-packages": "^1.1.3", "ansi-colors": "^4.1.3", "ci-info": "^3.7.0", "enquirer": "^2.4.1", "fs-extra": "^7.0.1", "mri": "^1.2.0", "p-limit": "^2.2.0", "package-manager-detector": "^0.2.0", "picocolors": "^1.1.0", "resolve-from": "^5.0.0", "semver": "^7.5.3", "spawndamnit": "^3.0.1", "term-size": "^2.1.0" }, "bin": { "changeset": "bin.js" } }, "sha512-1weuGZpP63YWUYjay/E84qqwcnt5yJMM0tep10Up7Q5cS/DGe2IZ0Uj3HNMxGhCINZuR7aO9WBMdKnPit5ZDPA=="], + + "@changesets/config": ["@changesets/config@3.1.2", "", { "dependencies": { "@changesets/errors": "^0.2.0", "@changesets/get-dependents-graph": "^2.1.3", "@changesets/logger": "^0.1.1", "@changesets/types": "^6.1.0", "@manypkg/get-packages": "^1.1.3", "fs-extra": "^7.0.1", "micromatch": "^4.0.8" } }, "sha512-CYiRhA4bWKemdYi/uwImjPxqWNpqGPNbEBdX1BdONALFIDK7MCUj6FPkzD+z9gJcvDFUQJn9aDVf4UG7OT6Kog=="], + + "@changesets/errors": ["@changesets/errors@0.2.0", "", { "dependencies": { "extendable-error": "^0.1.5" } }, "sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow=="], + + "@changesets/get-dependents-graph": ["@changesets/get-dependents-graph@2.1.3", "", { "dependencies": { "@changesets/types": "^6.1.0", "@manypkg/get-packages": "^1.1.3", "picocolors": "^1.1.0", "semver": "^7.5.3" } }, "sha512-gphr+v0mv2I3Oxt19VdWRRUxq3sseyUpX9DaHpTUmLj92Y10AGy+XOtV+kbM6L/fDcpx7/ISDFK6T8A/P3lOdQ=="], + + "@changesets/get-release-plan": ["@changesets/get-release-plan@4.0.14", "", { "dependencies": { "@changesets/assemble-release-plan": "^6.0.9", "@changesets/config": "^3.1.2", "@changesets/pre": "^2.0.2", "@changesets/read": "^0.6.6", "@changesets/types": "^6.1.0", "@manypkg/get-packages": "^1.1.3" } }, "sha512-yjZMHpUHgl4Xl5gRlolVuxDkm4HgSJqT93Ri1Uz8kGrQb+5iJ8dkXJ20M2j/Y4iV5QzS2c5SeTxVSKX+2eMI0g=="], + + "@changesets/get-version-range-type": ["@changesets/get-version-range-type@0.4.0", "", {}, "sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ=="], + + "@changesets/git": ["@changesets/git@3.0.4", "", { "dependencies": { "@changesets/errors": "^0.2.0", "@manypkg/get-packages": "^1.1.3", "is-subdir": "^1.1.1", "micromatch": "^4.0.8", "spawndamnit": "^3.0.1" } }, "sha512-BXANzRFkX+XcC1q/d27NKvlJ1yf7PSAgi8JG6dt8EfbHFHi4neau7mufcSca5zRhwOL8j9s6EqsxmT+s+/E6Sw=="], + + "@changesets/logger": ["@changesets/logger@0.1.1", "", { "dependencies": { "picocolors": "^1.1.0" } }, "sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg=="], + + "@changesets/parse": ["@changesets/parse@0.4.2", "", { "dependencies": { "@changesets/types": "^6.1.0", "js-yaml": "^4.1.1" } }, "sha512-Uo5MC5mfg4OM0jU3up66fmSn6/NE9INK+8/Vn/7sMVcdWg46zfbvvUSjD9EMonVqPi9fbrJH9SXHn48Tr1f2yA=="], + + "@changesets/pre": ["@changesets/pre@2.0.2", "", { "dependencies": { "@changesets/errors": "^0.2.0", "@changesets/types": "^6.1.0", "@manypkg/get-packages": "^1.1.3", "fs-extra": "^7.0.1" } }, "sha512-HaL/gEyFVvkf9KFg6484wR9s0qjAXlZ8qWPDkTyKF6+zqjBe/I2mygg3MbpZ++hdi0ToqNUF8cjj7fBy0dg8Ug=="], + + "@changesets/read": ["@changesets/read@0.6.6", "", { "dependencies": { "@changesets/git": "^3.0.4", "@changesets/logger": "^0.1.1", "@changesets/parse": "^0.4.2", "@changesets/types": "^6.1.0", "fs-extra": "^7.0.1", "p-filter": "^2.1.0", "picocolors": "^1.1.0" } }, "sha512-P5QaN9hJSQQKJShzzpBT13FzOSPyHbqdoIBUd2DJdgvnECCyO6LmAOWSV+O8se2TaZJVwSXjL+v9yhb+a9JeJg=="], + + "@changesets/should-skip-package": ["@changesets/should-skip-package@0.1.2", "", { "dependencies": { "@changesets/types": "^6.1.0", "@manypkg/get-packages": "^1.1.3" } }, "sha512-qAK/WrqWLNCP22UDdBTMPH5f41elVDlsNyat180A33dWxuUDyNpg6fPi/FyTZwRriVjg0L8gnjJn2F9XAoF0qw=="], + + "@changesets/types": ["@changesets/types@6.1.0", "", {}, "sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA=="], + + "@changesets/write": ["@changesets/write@0.4.0", "", { "dependencies": { "@changesets/types": "^6.1.0", "fs-extra": "^7.0.1", "human-id": "^4.1.1", "prettier": "^2.7.1" } }, "sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q=="], + + "@dimforge/rapier2d-simd-compat": ["@dimforge/rapier2d-simd-compat@0.17.3", "", {}, "sha512-bijvwWz6NHsNj5e5i1vtd3dU2pDhthSaTUZSh14DUGGKJfw8eMnlWZsxwHBxB/a3AXVNDjL9abuHw1k9FGR+jg=="], + + "@hono/node-server": ["@hono/node-server@1.19.9", "", { "peerDependencies": { "hono": "^4" } }, "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw=="], "@huggingface/jinja": ["@huggingface/jinja@0.2.2", "", {}, "sha512-/KPde26khDUIPkTGU82jdtTW9UAuvUTumCAbFs/7giR0SxsvZC4hru51PBvpijH6BVkHcROcvZM/lpy5h1jRRA=="], + "@inquirer/external-editor": ["@inquirer/external-editor@1.0.3", "", { "dependencies": { "chardet": "^2.1.1", "iconv-lite": "^0.7.0" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA=="], + + "@jimp/core": ["@jimp/core@1.6.0", "", { "dependencies": { "@jimp/file-ops": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "await-to-js": "^3.0.0", "exif-parser": "^0.1.12", "file-type": "^16.0.0", "mime": "3" } }, "sha512-EQQlKU3s9QfdJqiSrZWNTxBs3rKXgO2W+GxNXDtwchF3a4IqxDheFX1ti+Env9hdJXDiYLp2jTRjlxhPthsk8w=="], + + "@jimp/diff": ["@jimp/diff@1.6.0", "", { "dependencies": { "@jimp/plugin-resize": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "pixelmatch": "^5.3.0" } }, "sha512-+yUAQ5gvRC5D1WHYxjBHZI7JBRusGGSLf8AmPRPCenTzh4PA+wZ1xv2+cYqQwTfQHU5tXYOhA0xDytfHUf1Zyw=="], + + "@jimp/file-ops": ["@jimp/file-ops@1.6.0", "", {}, "sha512-Dx/bVDmgnRe1AlniRpCKrGRm5YvGmUwbDzt+MAkgmLGf+jvBT75hmMEZ003n9HQI/aPnm/YKnXjg/hOpzNCpHQ=="], + + "@jimp/js-bmp": ["@jimp/js-bmp@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "bmp-ts": "^1.0.9" } }, "sha512-FU6Q5PC/e3yzLyBDXupR3SnL3htU7S3KEs4e6rjDP6gNEOXRFsWs6YD3hXuXd50jd8ummy+q2WSwuGkr8wi+Gw=="], + + "@jimp/js-gif": ["@jimp/js-gif@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "gifwrap": "^0.10.1", "omggif": "^1.0.10" } }, "sha512-N9CZPHOrJTsAUoWkWZstLPpwT5AwJ0wge+47+ix3++SdSL/H2QzyMqxbcDYNFe4MoI5MIhATfb0/dl/wmX221g=="], + + "@jimp/js-jpeg": ["@jimp/js-jpeg@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "jpeg-js": "^0.4.4" } }, "sha512-6vgFDqeusblf5Pok6B2DUiMXplH8RhIKAryj1yn+007SIAQ0khM1Uptxmpku/0MfbClx2r7pnJv9gWpAEJdMVA=="], + + "@jimp/js-png": ["@jimp/js-png@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "pngjs": "^7.0.0" } }, "sha512-AbQHScy3hDDgMRNfG0tPjL88AV6qKAILGReIa3ATpW5QFjBKpisvUaOqhzJ7Reic1oawx3Riyv152gaPfqsBVg=="], + + "@jimp/js-tiff": ["@jimp/js-tiff@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "utif2": "^4.1.0" } }, "sha512-zhReR8/7KO+adijj3h0ZQUOiun3mXUv79zYEAKvE0O+rP7EhgtKvWJOZfRzdZSNv0Pu1rKtgM72qgtwe2tFvyw=="], + + "@jimp/plugin-blit": ["@jimp/plugin-blit@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-M+uRWl1csi7qilnSK8uxK4RJMSuVeBiO1AY0+7APnfUbQNZm6hCe0CCFv1Iyw1D/Dhb8ph8fQgm5mwM0eSxgVA=="], + + "@jimp/plugin-blur": ["@jimp/plugin-blur@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/utils": "1.6.0" } }, "sha512-zrM7iic1OTwUCb0g/rN5y+UnmdEsT3IfuCXCJJNs8SZzP0MkZ1eTvuwK9ZidCuMo4+J3xkzCidRwYXB5CyGZTw=="], + + "@jimp/plugin-circle": ["@jimp/plugin-circle@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "zod": "^3.23.8" } }, "sha512-xt1Gp+LtdMKAXfDp3HNaG30SPZW6AQ7dtAtTnoRKorRi+5yCJjKqXRgkewS5bvj8DEh87Ko1ydJfzqS3P2tdWw=="], + + "@jimp/plugin-color": ["@jimp/plugin-color@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "tinycolor2": "^1.6.0", "zod": "^3.23.8" } }, "sha512-J5q8IVCpkBsxIXM+45XOXTrsyfblyMZg3a9eAo0P7VPH4+CrvyNQwaYatbAIamSIN1YzxmO3DkIZXzRjFSz1SA=="], + + "@jimp/plugin-contain": ["@jimp/plugin-contain@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/plugin-blit": "1.6.0", "@jimp/plugin-resize": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-oN/n+Vdq/Qg9bB4yOBOxtY9IPAtEfES8J1n9Ddx+XhGBYT1/QTU/JYkGaAkIGoPnyYvmLEDqMz2SGihqlpqfzQ=="], + + "@jimp/plugin-cover": ["@jimp/plugin-cover@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/plugin-crop": "1.6.0", "@jimp/plugin-resize": "1.6.0", "@jimp/types": "1.6.0", "zod": "^3.23.8" } }, "sha512-Iow0h6yqSC269YUJ8HC3Q/MpCi2V55sMlbkkTTx4zPvd8mWZlC0ykrNDeAy9IJegrQ7v5E99rJwmQu25lygKLA=="], + + "@jimp/plugin-crop": ["@jimp/plugin-crop@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-KqZkEhvs+21USdySCUDI+GFa393eDIzbi1smBqkUPTE+pRwSWMAf01D5OC3ZWB+xZsNla93BDS9iCkLHA8wang=="], + + "@jimp/plugin-displace": ["@jimp/plugin-displace@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-4Y10X9qwr5F+Bo5ME356XSACEF55485j5nGdiyJ9hYzjQP9nGgxNJaZ4SAOqpd+k5sFaIeD7SQ0Occ26uIng5Q=="], + + "@jimp/plugin-dither": ["@jimp/plugin-dither@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0" } }, "sha512-600d1RxY0pKwgyU0tgMahLNKsqEcxGdbgXadCiVCoGd6V6glyCvkNrnnwC0n5aJ56Htkj88PToSdF88tNVZEEQ=="], + + "@jimp/plugin-fisheye": ["@jimp/plugin-fisheye@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-E5QHKWSCBFtpgZarlmN3Q6+rTQxjirFqo44ohoTjzYVrDI6B6beXNnPIThJgPr0Y9GwfzgyarKvQuQuqCnnfbA=="], + + "@jimp/plugin-flip": ["@jimp/plugin-flip@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "zod": "^3.23.8" } }, "sha512-/+rJVDuBIVOgwoyVkBjUFHtP+wmW0r+r5OQ2GpatQofToPVbJw1DdYWXlwviSx7hvixTWLKVgRWQ5Dw862emDg=="], + + "@jimp/plugin-hash": ["@jimp/plugin-hash@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/js-bmp": "1.6.0", "@jimp/js-jpeg": "1.6.0", "@jimp/js-png": "1.6.0", "@jimp/js-tiff": "1.6.0", "@jimp/plugin-color": "1.6.0", "@jimp/plugin-resize": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "any-base": "^1.1.0" } }, "sha512-wWzl0kTpDJgYVbZdajTf+4NBSKvmI3bRI8q6EH9CVeIHps9VWVsUvEyb7rpbcwVLWYuzDtP2R0lTT6WeBNQH9Q=="], + + "@jimp/plugin-mask": ["@jimp/plugin-mask@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "zod": "^3.23.8" } }, "sha512-Cwy7ExSJMZszvkad8NV8o/Z92X2kFUFM8mcDAhNVxU0Q6tA0op2UKRJY51eoK8r6eds/qak3FQkXakvNabdLnA=="], + + "@jimp/plugin-print": ["@jimp/plugin-print@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/js-jpeg": "1.6.0", "@jimp/js-png": "1.6.0", "@jimp/plugin-blit": "1.6.0", "@jimp/types": "1.6.0", "parse-bmfont-ascii": "^1.0.6", "parse-bmfont-binary": "^1.0.6", "parse-bmfont-xml": "^1.1.6", "simple-xml-to-json": "^1.2.2", "zod": "^3.23.8" } }, "sha512-zarTIJi8fjoGMSI/M3Xh5yY9T65p03XJmPsuNet19K/Q7mwRU6EV2pfj+28++2PV2NJ+htDF5uecAlnGyxFN2A=="], + + "@jimp/plugin-quantize": ["@jimp/plugin-quantize@1.6.0", "", { "dependencies": { "image-q": "^4.0.0", "zod": "^3.23.8" } }, "sha512-EmzZ/s9StYQwbpG6rUGBCisc3f64JIhSH+ncTJd+iFGtGo0YvSeMdAd+zqgiHpfZoOL54dNavZNjF4otK+mvlg=="], + + "@jimp/plugin-resize": ["@jimp/plugin-resize@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/types": "1.6.0", "zod": "^3.23.8" } }, "sha512-uSUD1mqXN9i1SGSz5ov3keRZ7S9L32/mAQG08wUwZiEi5FpbV0K8A8l1zkazAIZi9IJzLlTauRNU41Mi8IF9fA=="], + + "@jimp/plugin-rotate": ["@jimp/plugin-rotate@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/plugin-crop": "1.6.0", "@jimp/plugin-resize": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-JagdjBLnUZGSG4xjCLkIpQOZZ3Mjbg8aGCCi4G69qR+OjNpOeGI7N2EQlfK/WE8BEHOW5vdjSyglNqcYbQBWRw=="], + + "@jimp/plugin-threshold": ["@jimp/plugin-threshold@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/plugin-color": "1.6.0", "@jimp/plugin-hash": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0", "zod": "^3.23.8" } }, "sha512-M59m5dzLoHOVWdM41O8z9SyySzcDn43xHseOH0HavjsfQsT56GGCC4QzU1banJidbUrePhzoEdS42uFE8Fei8w=="], + + "@jimp/types": ["@jimp/types@1.6.0", "", { "dependencies": { "zod": "^3.23.8" } }, "sha512-7UfRsiKo5GZTAATxm2qQ7jqmUXP0DxTArztllTcYdyw6Xi5oT4RaoXynVtCD4UyLK5gJgkZJcwonoijrhYFKfg=="], + + "@jimp/utils": ["@jimp/utils@1.6.0", "", { "dependencies": { "@jimp/types": "1.6.0", "tinycolor2": "^1.6.0" } }, "sha512-gqFTGEosKbOkYF/WFj26jMHOI5OH2jeP1MmC/zbK6BF6VJBf8rIC5898dPfSzZEbSA0wbbV5slbntWVc5PKLFA=="], + + "@manypkg/find-root": ["@manypkg/find-root@1.1.0", "", { "dependencies": { "@babel/runtime": "^7.5.5", "@types/node": "^12.7.1", "find-up": "^4.1.0", "fs-extra": "^8.1.0" } }, "sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA=="], + + "@manypkg/get-packages": ["@manypkg/get-packages@1.1.3", "", { "dependencies": { "@babel/runtime": "^7.5.5", "@changesets/types": "^4.0.1", "@manypkg/find-root": "^1.1.0", "fs-extra": "^8.1.0", "globby": "^11.0.0", "read-yaml-file": "^1.1.0" } }, "sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A=="], + "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.25.2", "", { "dependencies": { "@hono/node-server": "^1.19.7", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "jose": "^6.1.1", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.0" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-LZFeo4F9M5qOhC/Uc1aQSrBHxMrvxett+9KLHt7OhcExtoiRN9DKgbZffMP/nxjutWDQpfMDfP3nkHI4X9ijww=="], + "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], + + "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], + + "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], + + "@opentui/core": ["@opentui/core@0.1.75", "", { "dependencies": { "bun-ffi-structs": "0.1.2", "diff": "8.0.2", "jimp": "1.6.0", "marked": "17.0.1", "yoga-layout": "3.2.1" }, "optionalDependencies": { "@dimforge/rapier2d-simd-compat": "^0.17.3", "@opentui/core-darwin-arm64": "0.1.75", "@opentui/core-darwin-x64": "0.1.75", "@opentui/core-linux-arm64": "0.1.75", "@opentui/core-linux-x64": "0.1.75", "@opentui/core-win32-arm64": "0.1.75", "@opentui/core-win32-x64": "0.1.75", "bun-webgpu": "0.1.4", "planck": "^1.4.2", "three": "0.177.0" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-8ARRZxSG+BXkJmEVtM2DQ4se7DAF1ZCKD07d+AklgTr2mxCzmdxxPbOwRzboSQ6FM7qGuTVPVbV4O2W9DpUmoA=="], + + "@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.1.75", "", { "os": "darwin", "cpu": "arm64" }, "sha512-gGaGZjkFpqcXJk6321JzhRl66pM2VxBlI470L8W4DQUW4S6iDT1R9L7awSzGB4Cn9toUl7DTV8BemaXZYXV4SA=="], + + "@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.1.75", "", { "os": "darwin", "cpu": "x64" }, "sha512-tPlvqQI0whZ76amHydpJs5kN+QeWAIcFbI8RAtlAo9baj2EbxTDC+JGwgb9Fnt0/YQx831humbtaNDhV2Jt1bw=="], + + "@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.1.75", "", { "os": "linux", "cpu": "arm64" }, "sha512-nVxIQ4Hqf84uBergDpWiVzU6pzpjy6tqBHRQpySxZ2flkJ/U6/aMEizVrQ1jcgIdxZtvqWDETZhzxhG0yDx+cw=="], + + "@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.1.75", "", { "os": "linux", "cpu": "x64" }, "sha512-1CnApef4kxA+ORyLfbuCLgZfEjp4wr3HjFnt7FAfOb73kIZH82cb7JYixeqRyy9eOcKfKqxLmBYy3o8IDkc4Rg=="], + + "@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.1.75", "", { "os": "win32", "cpu": "arm64" }, "sha512-j0UB95nmkYGNzmOrs6GqaddO1S90R0YC6IhbKnbKBdjchFPNVLz9JpexAs6MBDXPZwdKAywMxtwG2h3aTJtxng=="], + + "@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.1.75", "", { "os": "win32", "cpu": "x64" }, "sha512-ESpVZVGewe3JkB2TwrG3VRbkxT909iPdtvgNT7xTCIYH2VB4jqZomJfvERPTE0tvqAZJm19mHECzJFI8asSJgQ=="], + "@protobufjs/aspromise": ["@protobufjs/aspromise@1.1.2", "", {}, "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="], "@protobufjs/base64": ["@protobufjs/base64@1.1.2", "", {}, "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="], @@ -67,20 +215,38 @@ "@protobufjs/utf8": ["@protobufjs/utf8@1.1.0", "", {}, "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="], - "@types/bun": ["@types/bun@1.2.15", "", { "dependencies": { "bun-types": "1.2.15" } }, "sha512-U1ljPdBEphF0nw1MIk0hI7kPg7dFdPyM7EenHsp6W5loNHl7zqy6JQf/RKCgnUn2KDzUpkBwHPnEJEjII594bA=="], + "@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="], + + "@types/bun": ["@types/bun@1.3.6", "", { "dependencies": { "bun-types": "1.3.6" } }, "sha512-uWCv6FO/8LcpREhenN1d1b6fcspAB+cefwD7uti8C8VffIv0Um08TKMn98FynpTiU38+y2dUO55T11NgDt8VAA=="], "@types/long": ["@types/long@4.0.2", "", {}, "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA=="], "@types/node": ["@types/node@25.0.8", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-powIePYMmC3ibL0UJ2i2s0WIbq6cg6UyVFQxSCpaPxxzAaziRfimGivjdF943sSGV6RADVbk0Nvlm5P/FB44Zg=="], + "@webgpu/types": ["@webgpu/types@0.1.69", "", {}, "sha512-RPmm6kgRbI8e98zSD3RVACvnuktIja5+yLgDAkTmxLr90BEwdTXRQWNLF3ETTTyH/8mKhznZuN5AveXYFEsMGQ=="], + "@xenova/transformers": ["@xenova/transformers@2.17.2", "", { "dependencies": { "@huggingface/jinja": "^0.2.2", "onnxruntime-web": "1.14.0", "sharp": "^0.32.0" }, "optionalDependencies": { "onnxruntime-node": "1.14.0" } }, "sha512-lZmHqzrVIkSvZdKZEx7IYY51TK0WDrC8eR0c5IMnBsO8di8are1zzw8BlLhyO2TklZKLN5UffNGs1IJwT6oOqQ=="], + "abort-controller": ["abort-controller@3.0.0", "", { "dependencies": { "event-target-shim": "^5.0.0" } }, "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg=="], + "accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], "ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="], "ajv-formats": ["ajv-formats@3.0.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="], + "ansi-colors": ["ansi-colors@4.1.3", "", {}, "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw=="], + + "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "any-base": ["any-base@1.1.0", "", {}, "sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg=="], + + "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], + + "array-union": ["array-union@2.1.0", "", {}, "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw=="], + + "await-to-js": ["await-to-js@3.0.0", "", {}, "sha512-zJAaP9zxTcvTHRlejau3ZOY4V7SRpiByf3/dxx2uyKxxor19tpmpV2QRsTKikckwhaPmr2dVpxxMr7jOCYVp5g=="], + "b4a": ["b4a@1.7.3", "", { "peerDependencies": { "react-native-b4a": "*" }, "optionalPeers": ["react-native-b4a"] }, "sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q=="], "bare-events": ["bare-events@2.8.2", "", { "peerDependencies": { "bare-abort-controller": "*" }, "optionalPeers": ["bare-abort-controller"] }, "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ=="], @@ -97,13 +263,31 @@ "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], + "better-path-resolve": ["better-path-resolve@1.0.0", "", { "dependencies": { "is-windows": "^1.0.0" } }, "sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g=="], + "bl": ["bl@4.1.0", "", { "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="], + "bmp-ts": ["bmp-ts@1.0.9", "", {}, "sha512-cTEHk2jLrPyi+12M3dhpEbnnPOsaZuq7C45ylbbQIiWgDFZq4UVYPEY5mlqjvsj/6gJv9qX5sa+ebDzLXT28Vw=="], + "body-parser": ["body-parser@2.2.2", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.3", "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.1", "raw-body": "^3.0.1", "type-is": "^2.0.1" } }, "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA=="], + "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], + "buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], - "bun-types": ["bun-types@1.2.15", "", { "dependencies": { "@types/node": "*" } }, "sha512-NarRIaS+iOaQU1JPfyKhZm4AsUOrwUOqRNHY0XxI8GI8jYxiLXLcdjYMG9UKS+fwWasc1uw1htV9AX24dD+p4w=="], + "bun-ffi-structs": ["bun-ffi-structs@0.1.2", "", { "peerDependencies": { "typescript": "^5" } }, "sha512-Lh1oQAYHDcnesJauieA4UNkWGXY9hYck7OA5IaRwE3Bp6K2F2pJSNYqq+hIy7P3uOvo3km3oxS8304g5gDMl/w=="], + + "bun-types": ["bun-types@1.3.6", "", { "dependencies": { "@types/node": "*" } }, "sha512-OlFwHcnNV99r//9v5IIOgQ9Uk37gZqrNMCcqEaExdkVq3Avwqok1bJFmvGMCkCE0FqzdY8VMOZpfpR3lwI+CsQ=="], + + "bun-webgpu": ["bun-webgpu@0.1.4", "", { "dependencies": { "@webgpu/types": "^0.1.60" }, "optionalDependencies": { "bun-webgpu-darwin-arm64": "^0.1.4", "bun-webgpu-darwin-x64": "^0.1.4", "bun-webgpu-linux-x64": "^0.1.4", "bun-webgpu-win32-x64": "^0.1.4" } }, "sha512-Kw+HoXl1PMWJTh9wvh63SSRofTA8vYBFCw0XEP1V1fFdQEDhI8Sgf73sdndE/oDpN/7CMx0Yv/q8FCvO39ROMQ=="], + + "bun-webgpu-darwin-arm64": ["bun-webgpu-darwin-arm64@0.1.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-eDgLN9teKTfmvrCqgwwmWNsNszxYs7IZdCqk0S1DCarvMhr4wcajoSBlA/nQA0/owwLduPTS8xxCnQp4/N/gDg=="], + + "bun-webgpu-darwin-x64": ["bun-webgpu-darwin-x64@0.1.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-X+PjwJUWenUmdQBP8EtdItMyieQ6Nlpn+BH518oaouDiSnWj5+b0Y7DNDZJq7Ezom4EaxmqL/uGYZK3aCQ7CXg=="], + + "bun-webgpu-linux-x64": ["bun-webgpu-linux-x64@0.1.4", "", { "os": "linux", "cpu": "x64" }, "sha512-zMLs2YIGB+/jxrYFXaFhVKX/GBt05UTF45lc9srcHc9JXGjEj+12CIo1CHLTAWatXMTqt0Jsu6ukWEoWVT/ayA=="], + + "bun-webgpu-win32-x64": ["bun-webgpu-win32-x64@0.1.4", "", { "os": "win32", "cpu": "x64" }, "sha512-Z5yAK28xrcm8Wb5k7TZ8FJKpOI/r+aVCRdlHYAqI2SDJFN3nD4mJs900X6kNVmG/xFzb5yOuKVYWGg+6ZXWbyA=="], "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], @@ -111,8 +295,16 @@ "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], + "chardet": ["chardet@2.1.1", "", {}, "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ=="], + "chownr": ["chownr@1.1.4", "", {}, "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="], + "ci-info": ["ci-info@3.9.0", "", {}, "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ=="], + + "code-recall": ["code-recall@workspace:apps/server"], + + "code-recall-tui": ["code-recall-tui@workspace:apps/tui"], + "color": ["color@4.2.3", "", { "dependencies": { "color-convert": "^2.0.1", "color-string": "^1.9.0" } }, "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A=="], "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], @@ -141,8 +333,14 @@ "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], + "detect-indent": ["detect-indent@6.1.0", "", {}, "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA=="], + "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], + "diff": ["diff@8.0.2", "", {}, "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg=="], + + "dir-glob": ["dir-glob@3.0.1", "", { "dependencies": { "path-type": "^4.0.0" } }, "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA=="], + "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], @@ -151,6 +349,8 @@ "end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="], + "enquirer": ["enquirer@2.4.1", "", { "dependencies": { "ansi-colors": "^4.1.1", "strip-ansi": "^6.0.1" } }, "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ=="], + "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], @@ -159,28 +359,48 @@ "escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="], + "esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="], + "etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="], + "event-target-shim": ["event-target-shim@5.0.1", "", {}, "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="], + + "events": ["events@3.3.0", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="], + "events-universal": ["events-universal@1.0.1", "", { "dependencies": { "bare-events": "^2.7.0" } }, "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw=="], "eventsource": ["eventsource@3.0.7", "", { "dependencies": { "eventsource-parser": "^3.0.1" } }, "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA=="], "eventsource-parser": ["eventsource-parser@3.0.6", "", {}, "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg=="], + "exif-parser": ["exif-parser@0.1.12", "", {}, "sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw=="], + "expand-template": ["expand-template@2.0.3", "", {}, "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg=="], "express": ["express@5.2.1", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw=="], "express-rate-limit": ["express-rate-limit@7.5.1", "", { "peerDependencies": { "express": ">= 4.11" } }, "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw=="], + "extendable-error": ["extendable-error@0.1.7", "", {}, "sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg=="], + "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], "fast-fifo": ["fast-fifo@1.3.2", "", {}, "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ=="], + "fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], + "fast-uri": ["fast-uri@3.1.0", "", {}, "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA=="], + "fastq": ["fastq@1.20.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw=="], + + "file-type": ["file-type@16.5.4", "", { "dependencies": { "readable-web-to-node-stream": "^3.0.0", "strtok3": "^6.2.4", "token-types": "^4.1.1" } }, "sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw=="], + + "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], + "finalhandler": ["finalhandler@2.1.1", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA=="], + "find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], + "flatbuffers": ["flatbuffers@1.12.0", "", {}, "sha512-c7CZADjRcl6j0PlvFy0ZqXQ67qSEZfrVPynmnL+2zPc+NtMvrF8Y0QceMo7QqnSPc7+uWjUIAbvCQ5WIKlMVdQ=="], "forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="], @@ -189,16 +409,26 @@ "fs-constants": ["fs-constants@1.0.0", "", {}, "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="], + "fs-extra": ["fs-extra@7.0.1", "", { "dependencies": { "graceful-fs": "^4.1.2", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw=="], + "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], + "gifwrap": ["gifwrap@0.10.1", "", { "dependencies": { "image-q": "^4.0.0", "omggif": "^1.0.10" } }, "sha512-2760b1vpJHNmLzZ/ubTtNnEx5WApN/PYWJvXvgS+tL1egTTthayFYIQQNi136FLEDcN/IyEY2EcGpIITD6eYUw=="], + "github-from-package": ["github-from-package@0.0.0", "", {}, "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw=="], + "glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + + "globby": ["globby@11.1.0", "", { "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", "fast-glob": "^3.2.9", "ignore": "^5.2.0", "merge2": "^1.4.1", "slash": "^3.0.0" } }, "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g=="], + "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], + "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + "guid-typescript": ["guid-typescript@1.0.9", "", {}, "sha512-Y8T4vYhEfwJOTbouREvG+3XDsjr8E3kIr7uf+JZ0BYloFsttiHU0WfvANVsR7TxNUJa/WpCnw/Ino/p+DeBhBQ=="], "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], @@ -209,10 +439,16 @@ "http-errors": ["http-errors@2.0.1", "", { "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", "setprototypeof": "~1.2.0", "statuses": "~2.0.2", "toidentifier": "~1.0.1" } }, "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ=="], + "human-id": ["human-id@4.1.3", "", { "bin": { "human-id": "dist/cli.js" } }, "sha512-tsYlhAYpjCKa//8rXZ9DqKEawhPoSytweBC2eNvcaDK+57RZLHGqNs3PZTQO6yekLFSuvA6AlnAfrw1uBvtb+Q=="], + "iconv-lite": ["iconv-lite@0.7.2", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="], "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], + + "image-q": ["image-q@4.0.0", "", { "dependencies": { "@types/node": "16.9.1" } }, "sha512-PfJGVgIfKQJuq3s0tTDOKtztksibuUEbJQIYT3by6wctQo+Rdlh7ef4evJ5NCdxY4CfMbvFkocEwbl4BF8RlJw=="], + "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], "ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="], @@ -221,24 +457,54 @@ "is-arrayish": ["is-arrayish@0.3.4", "", {}, "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA=="], + "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], + + "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], + + "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], + "is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="], + "is-subdir": ["is-subdir@1.2.0", "", { "dependencies": { "better-path-resolve": "1.0.0" } }, "sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw=="], + + "is-windows": ["is-windows@1.0.2", "", {}, "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA=="], + "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + "jimp": ["jimp@1.6.0", "", { "dependencies": { "@jimp/core": "1.6.0", "@jimp/diff": "1.6.0", "@jimp/js-bmp": "1.6.0", "@jimp/js-gif": "1.6.0", "@jimp/js-jpeg": "1.6.0", "@jimp/js-png": "1.6.0", "@jimp/js-tiff": "1.6.0", "@jimp/plugin-blit": "1.6.0", "@jimp/plugin-blur": "1.6.0", "@jimp/plugin-circle": "1.6.0", "@jimp/plugin-color": "1.6.0", "@jimp/plugin-contain": "1.6.0", "@jimp/plugin-cover": "1.6.0", "@jimp/plugin-crop": "1.6.0", "@jimp/plugin-displace": "1.6.0", "@jimp/plugin-dither": "1.6.0", "@jimp/plugin-fisheye": "1.6.0", "@jimp/plugin-flip": "1.6.0", "@jimp/plugin-hash": "1.6.0", "@jimp/plugin-mask": "1.6.0", "@jimp/plugin-print": "1.6.0", "@jimp/plugin-quantize": "1.6.0", "@jimp/plugin-resize": "1.6.0", "@jimp/plugin-rotate": "1.6.0", "@jimp/plugin-threshold": "1.6.0", "@jimp/types": "1.6.0", "@jimp/utils": "1.6.0" } }, "sha512-YcwCHw1kiqEeI5xRpDlPPBGL2EOpBKLwO4yIBJcXWHPj5PnA5urGq0jbyhM5KoNpypQ6VboSoxc9D8HyfvngSg=="], + "jose": ["jose@6.1.3", "", {}, "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ=="], + "jpeg-js": ["jpeg-js@0.4.4", "", {}, "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg=="], + + "js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="], + "json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], "json-schema-typed": ["json-schema-typed@8.0.2", "", {}, "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA=="], + "jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="], + + "locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], + + "lodash.startcase": ["lodash.startcase@4.4.0", "", {}, "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg=="], + "long": ["long@4.0.0", "", {}, "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA=="], + "marked": ["marked@17.0.1", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-boeBdiS0ghpWcSwoNm/jJBwdpFaMnZWRzjA6SkUMYb40SVaN1x7mmfGKp0jvexGcx+7y2La5zRZsYFZI6Qpypg=="], + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], "media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], "merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="], + "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], + + "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], + + "mime": ["mime@3.0.0", "", { "bin": { "mime": "cli.js" } }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="], + "mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], "mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="], @@ -249,6 +515,8 @@ "mkdirp-classic": ["mkdirp-classic@0.5.3", "", {}, "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="], + "mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="], + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], "napi-build-utils": ["napi-build-utils@2.0.0", "", {}, "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA=="], @@ -265,6 +533,8 @@ "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], + "omggif": ["omggif@1.0.10", "", {}, "sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw=="], + "on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="], "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], @@ -277,18 +547,62 @@ "onnxruntime-web": ["onnxruntime-web@1.14.0", "", { "dependencies": { "flatbuffers": "^1.12.0", "guid-typescript": "^1.0.9", "long": "^4.0.0", "onnx-proto": "^4.0.4", "onnxruntime-common": "~1.14.0", "platform": "^1.3.6" } }, "sha512-Kcqf43UMfW8mCydVGcX9OMXI2VN17c0p6XvR7IPSZzBf/6lteBzXHvcEVWDPmCKuGombl997HgLqj91F11DzXw=="], + "outdent": ["outdent@0.5.0", "", {}, "sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q=="], + + "p-filter": ["p-filter@2.1.0", "", { "dependencies": { "p-map": "^2.0.0" } }, "sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw=="], + + "p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], + + "p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], + + "p-map": ["p-map@2.1.0", "", {}, "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw=="], + + "p-try": ["p-try@2.2.0", "", {}, "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="], + + "package-manager-detector": ["package-manager-detector@0.2.11", "", { "dependencies": { "quansync": "^0.2.7" } }, "sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ=="], + + "pako": ["pako@1.0.11", "", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="], + + "parse-bmfont-ascii": ["parse-bmfont-ascii@1.0.6", "", {}, "sha512-U4RrVsUFCleIOBsIGYOMKjn9PavsGOXxbvYGtMOEfnId0SVNsgehXh1DxUdVPLoxd5mvcEtvmKs2Mmf0Mpa1ZA=="], + + "parse-bmfont-binary": ["parse-bmfont-binary@1.0.6", "", {}, "sha512-GxmsRea0wdGdYthjuUeWTMWPqm2+FAd4GI8vCvhgJsFnoGhTrLhXDDupwTo7rXVAgaLIGoVHDZS9p/5XbSqeWA=="], + + "parse-bmfont-xml": ["parse-bmfont-xml@1.1.6", "", { "dependencies": { "xml-parse-from-string": "^1.0.0", "xml2js": "^0.5.0" } }, "sha512-0cEliVMZEhrFDwMh4SxIyVJpqYoOWDJ9P895tFuS+XuNzI5UBmBk5U5O4KuJdTnZpSBI4LFA2+ZiJaiwfSwlMA=="], + "parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="], + "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], "path-to-regexp": ["path-to-regexp@8.3.0", "", {}, "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA=="], + "path-type": ["path-type@4.0.0", "", {}, "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="], + + "peek-readable": ["peek-readable@4.1.0", "", {}, "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg=="], + + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + + "picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + + "pify": ["pify@4.0.1", "", {}, "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="], + + "pixelmatch": ["pixelmatch@5.3.0", "", { "dependencies": { "pngjs": "^6.0.0" }, "bin": { "pixelmatch": "bin/pixelmatch" } }, "sha512-o8mkY4E/+LNUf6LzX96ht6k6CEDi65k9G2rjMtBe9Oo+VPKSvl+0GKHuH/AlG+GA5LPG/i5hrekkxUc3s2HU+Q=="], + "pkce-challenge": ["pkce-challenge@5.0.1", "", {}, "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ=="], + "planck": ["planck@1.4.2", "", { "peerDependencies": { "stage-js": "^1.0.0-alpha.12" } }, "sha512-mNbhnV3g8X2rwGxzcesjmN8BDA6qfXgQxXVMkWau9MCRlQY0RLNEkyHlVp6yFy/X6qrzAXyNONCnZ1cGDLrNew=="], + "platform": ["platform@1.3.6", "", {}, "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg=="], + "pngjs": ["pngjs@7.0.0", "", {}, "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow=="], + "prebuild-install": ["prebuild-install@7.1.3", "", { "dependencies": { "detect-libc": "^2.0.0", "expand-template": "^2.0.3", "github-from-package": "0.0.0", "minimist": "^1.2.3", "mkdirp-classic": "^0.5.3", "napi-build-utils": "^2.0.0", "node-abi": "^3.3.0", "pump": "^3.0.0", "rc": "^1.2.7", "simple-get": "^4.0.0", "tar-fs": "^2.0.0", "tunnel-agent": "^0.6.0" }, "bin": { "prebuild-install": "bin.js" } }, "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug=="], + "prettier": ["prettier@2.8.8", "", { "bin": { "prettier": "bin-prettier.js" } }, "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q=="], + + "process": ["process@0.11.10", "", {}, "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A=="], + "protobufjs": ["protobufjs@6.11.4", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/long": "^4.0.1", "@types/node": ">=13.7.0", "long": "^4.0.0" }, "bin": { "pbjs": "bin/pbjs", "pbts": "bin/pbts" } }, "sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw=="], "proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="], @@ -297,22 +611,38 @@ "qs": ["qs@6.14.1", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ=="], + "quansync": ["quansync@0.2.11", "", {}, "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA=="], + + "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], + "range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], "raw-body": ["raw-body@3.0.2", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" } }, "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA=="], "rc": ["rc@1.2.8", "", { "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" }, "bin": { "rc": "./cli.js" } }, "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw=="], + "read-yaml-file": ["read-yaml-file@1.1.0", "", { "dependencies": { "graceful-fs": "^4.1.5", "js-yaml": "^3.6.1", "pify": "^4.0.1", "strip-bom": "^3.0.0" } }, "sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA=="], + "readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], + "readable-web-to-node-stream": ["readable-web-to-node-stream@3.0.4", "", { "dependencies": { "readable-stream": "^4.7.0" } }, "sha512-9nX56alTf5bwXQ3ZDipHJhusu9NTQJ/CVPtb/XHAJCXihZeitfJvIRS4GqQ/mfIoOE3IelHMrpayVrosdHBuLw=="], + "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], + "resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="], + + "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], + "router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="], + "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], + "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], + "sax": ["sax@1.4.4", "", {}, "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw=="], + "semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], "send": ["send@1.2.1", "", { "dependencies": { "debug": "^4.4.3", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.1", "mime-types": "^3.0.2", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.2" } }, "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ=="], @@ -335,12 +665,22 @@ "side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="], + "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], + "simple-concat": ["simple-concat@1.0.1", "", {}, "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q=="], "simple-get": ["simple-get@4.0.1", "", { "dependencies": { "decompress-response": "^6.0.0", "once": "^1.3.1", "simple-concat": "^1.0.0" } }, "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA=="], "simple-swizzle": ["simple-swizzle@0.2.4", "", { "dependencies": { "is-arrayish": "^0.3.1" } }, "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw=="], + "simple-xml-to-json": ["simple-xml-to-json@1.2.3", "", {}, "sha512-kWJDCr9EWtZ+/EYYM5MareWj2cRnZGF93YDNpH4jQiHB+hBIZnfPFSQiVMzZOdk+zXWqTZ/9fTeQNu2DqeiudA=="], + + "slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], + + "spawndamnit": ["spawndamnit@3.0.1", "", { "dependencies": { "cross-spawn": "^7.0.5", "signal-exit": "^4.0.1" } }, "sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg=="], + + "sprintf-js": ["sprintf-js@1.0.3", "", {}, "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="], + "sqlite-vec": ["sqlite-vec@0.1.7-alpha.2", "", { "optionalDependencies": { "sqlite-vec-darwin-arm64": "0.1.7-alpha.2", "sqlite-vec-darwin-x64": "0.1.7-alpha.2", "sqlite-vec-linux-arm64": "0.1.7-alpha.2", "sqlite-vec-linux-x64": "0.1.7-alpha.2", "sqlite-vec-windows-x64": "0.1.7-alpha.2" } }, "sha512-rNgRCv+4V4Ed3yc33Qr+nNmjhtrMnnHzXfLVPeGb28Dx5mmDL3Ngw/Wk8vhCGjj76+oC6gnkmMG8y73BZWGBwQ=="], "sqlite-vec-darwin-arm64": ["sqlite-vec-darwin-arm64@0.1.7-alpha.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-raIATOqFYkeCHhb/t3r7W7Cf2lVYdf4J3ogJ6GFc8PQEgHCPEsi+bYnm2JT84MzLfTlSTIdxr4/NKv+zF7oLPw=="], @@ -353,36 +693,72 @@ "sqlite-vec-windows-x64": ["sqlite-vec-windows-x64@0.1.7-alpha.2", "", { "os": "win32", "cpu": "x64" }, "sha512-TRP6hTjAcwvQ6xpCZvjP00pdlda8J38ArFy1lMYhtQWXiIBmWnhMaMbq4kaeCYwvTTddfidatRS+TJrwIKB/oQ=="], + "stage-js": ["stage-js@1.0.0-alpha.18", "", {}, "sha512-Mh+pbkfxA6NXlDrcutP8vp1Zg04pDRcC8D39UXKZzEcQeBPOZ4SRUSkIsF26aoODUZ4CSQRY7shXc1Avb0wZKA=="], + "statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], "streamx": ["streamx@2.23.0", "", { "dependencies": { "events-universal": "^1.0.0", "fast-fifo": "^1.3.2", "text-decoder": "^1.1.0" } }, "sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg=="], "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], + "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "strip-bom": ["strip-bom@3.0.0", "", {}, "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA=="], + "strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="], + "strtok3": ["strtok3@6.3.0", "", { "dependencies": { "@tokenizer/token": "^0.3.0", "peek-readable": "^4.1.0" } }, "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw=="], + "tar-fs": ["tar-fs@3.1.1", "", { "dependencies": { "pump": "^3.0.0", "tar-stream": "^3.1.5" }, "optionalDependencies": { "bare-fs": "^4.0.1", "bare-path": "^3.0.0" } }, "sha512-LZA0oaPOc2fVo82Txf3gw+AkEd38szODlptMYejQUhndHMLQ9M059uXR+AfS7DNo0NpINvSqDsvyaCrBVkptWg=="], "tar-stream": ["tar-stream@3.1.7", "", { "dependencies": { "b4a": "^1.6.4", "fast-fifo": "^1.2.0", "streamx": "^2.15.0" } }, "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ=="], + "term-size": ["term-size@2.2.1", "", {}, "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg=="], + "text-decoder": ["text-decoder@1.2.3", "", { "dependencies": { "b4a": "^1.6.4" } }, "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA=="], + "three": ["three@0.177.0", "", {}, "sha512-EiXv5/qWAaGI+Vz2A+JfavwYCMdGjxVsrn3oBwllUoqYeaBO75J63ZfyaQKoiLrqNHoTlUc6PFgMXnS0kI45zg=="], + + "tinycolor2": ["tinycolor2@1.6.0", "", {}, "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw=="], + + "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], + "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], + "token-types": ["token-types@4.2.1", "", { "dependencies": { "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ=="], + "tree-sitter-javascript": ["tree-sitter-javascript@0.25.0", "", { "dependencies": { "node-addon-api": "^8.3.1", "node-gyp-build": "^4.8.4" }, "peerDependencies": { "tree-sitter": "^0.25.0" }, "optionalPeers": ["tree-sitter"] }, "sha512-1fCbmzAskZkxcZzN41sFZ2br2iqTYP3tKls1b/HKGNPQUVOpsUxpmGxdN/wMqAk3jYZnYBR1dd/y/0avMeU7dw=="], "tree-sitter-typescript": ["tree-sitter-typescript@0.23.2", "", { "dependencies": { "node-addon-api": "^8.2.2", "node-gyp-build": "^4.8.2", "tree-sitter-javascript": "^0.23.1" }, "peerDependencies": { "tree-sitter": "^0.21.0" }, "optionalPeers": ["tree-sitter"] }, "sha512-e04JUUKxTT53/x3Uq1zIL45DoYKVfHH4CZqwgZhPg5qYROl5nQjV+85ruFzFGZxu+QeFVbRTPDRnqL9UbU4VeA=="], "tunnel-agent": ["tunnel-agent@0.6.0", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w=="], + "turbo": ["turbo@2.7.4", "", { "optionalDependencies": { "turbo-darwin-64": "2.7.4", "turbo-darwin-arm64": "2.7.4", "turbo-linux-64": "2.7.4", "turbo-linux-arm64": "2.7.4", "turbo-windows-64": "2.7.4", "turbo-windows-arm64": "2.7.4" }, "bin": { "turbo": "bin/turbo" } }, "sha512-bkO4AddmDishzJB2ze7aYYPaejMoJVfS0XnaR6RCdXFOY8JGJfQE+l9fKiV7uDPa5Ut44gmOWJL3894CIMeH9g=="], + + "turbo-darwin-64": ["turbo-darwin-64@2.7.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-xDR30ltfkSsRfGzABBckvl1nz1cZ3ssTujvdj+TPwOweeDRvZ0e06t5DS0rmRBvyKpgGs42K/EK6Mn2qLlFY9A=="], + + "turbo-darwin-arm64": ["turbo-darwin-arm64@2.7.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-P7sjqXtOL/+nYWPvcDGWhi8wf8M8mZHHB8XEzw2VX7VJrS8IGHyJHGD1AYfDvhAEcr7pnk3gGifz3/xyhI655w=="], + + "turbo-linux-64": ["turbo-linux-64@2.7.4", "", { "os": "linux", "cpu": "x64" }, "sha512-GofFOxRO/IhG8BcPyMSSB3Y2+oKQotsaYbHxL9yD6JPb20/o35eo+zUSyazOtilAwDHnak5dorAJFoFU8MIg2A=="], + + "turbo-linux-arm64": ["turbo-linux-arm64@2.7.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-+RQKgNjksVPxYAyAgmDV7w/1qj++qca+nSNTAOKGOfJiDtSvRKoci89oftJ6anGs00uamLKVEQ712TI/tfNAIw=="], + + "turbo-windows-64": ["turbo-windows-64@2.7.4", "", { "os": "win32", "cpu": "x64" }, "sha512-rfak1+g+ON3czs1mDYsCS4X74ZmK6gOgRQTXjDICtzvR4o61paqtgAYtNPofcVsMWeF4wvCajSeoAkkeAnQ1kg=="], + + "turbo-windows-arm64": ["turbo-windows-arm64@2.7.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-1ZgBNjNRbDu/fPeqXuX9i26x3CJ/Y1gcwUpQ+Vp7kN9Un6RZ9kzs164f/knrjcu5E+szCRexVjRSJay1k5jApA=="], + "type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="], "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + "universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="], + "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], + "utif2": ["utif2@4.1.0", "", { "dependencies": { "pako": "^1.0.11" } }, "sha512-+oknB9FHrJ7oW7A2WZYajOcv4FcDR4CfoGB0dPNfxbi4GO05RRnFmt5oa23+9w32EanrYcSJWspUiJkLMs+37w=="], + "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], @@ -393,16 +769,44 @@ "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], + "xml-parse-from-string": ["xml-parse-from-string@1.0.1", "", {}, "sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g=="], + + "xml2js": ["xml2js@0.5.0", "", { "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" } }, "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA=="], + + "xmlbuilder": ["xmlbuilder@11.0.1", "", {}, "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="], + + "yoga-layout": ["yoga-layout@3.2.1", "", {}, "sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ=="], + "zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], "zod-to-json-schema": ["zod-to-json-schema@3.25.1", "", { "peerDependencies": { "zod": "^3.25 || ^4" } }, "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA=="], + "@manypkg/find-root/@types/node": ["@types/node@12.20.55", "", {}, "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ=="], + + "@manypkg/find-root/fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="], + + "@manypkg/get-packages/@changesets/types": ["@changesets/types@4.1.0", "", {}, "sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw=="], + + "@manypkg/get-packages/fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="], + + "image-q/@types/node": ["@types/node@16.9.1", "", {}, "sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g=="], + + "pixelmatch/pngjs": ["pngjs@6.0.0", "", {}, "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg=="], + "prebuild-install/tar-fs": ["tar-fs@2.1.4", "", { "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", "pump": "^3.0.0", "tar-stream": "^2.1.4" } }, "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ=="], + "read-yaml-file/js-yaml": ["js-yaml@3.14.2", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg=="], + + "readable-web-to-node-stream/readable-stream": ["readable-stream@4.7.0", "", { "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", "events": "^3.3.0", "process": "^0.11.10", "string_decoder": "^1.3.0" } }, "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg=="], + "sharp/node-addon-api": ["node-addon-api@6.1.0", "", {}, "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA=="], "tree-sitter-typescript/tree-sitter-javascript": ["tree-sitter-javascript@0.23.1", "", { "dependencies": { "node-addon-api": "^8.2.2", "node-gyp-build": "^4.8.2" }, "peerDependencies": { "tree-sitter": "^0.21.1" }, "optionalPeers": ["tree-sitter"] }, "sha512-/bnhbrTD9frUYHQTiYnPcxyHORIw157ERBa6dqzaKxvR/x3PC4Yzd+D1pZIMS6zNg2v3a8BZ0oK7jHqsQo9fWA=="], "prebuild-install/tar-fs/tar-stream": ["tar-stream@2.2.0", "", { "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", "fs-constants": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.1.1" } }, "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ=="], + + "read-yaml-file/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], + + "readable-web-to-node-stream/readable-stream/buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="], } } diff --git a/package.json b/package.json index 1b69863..cbe344d 100644 --- a/package.json +++ b/package.json @@ -1,61 +1,27 @@ { - "name": "code-recall", - "version": "1.0.0", - "description": "Ultra-fast MCP server for semantic memory and code analysis", - "module": "src/index.ts", - "type": "module", - "bin": { - "code-recall": "src/index.ts" - }, - "files": [ - "src", - "README.md", - "LICENSE" - ], - "repository": { - "type": "git", - "url": "git+https://github.com/AbianS/code-recall.git" - }, - "keywords": [ - "mcp", - "memory", - "ai", - "coding-agent", - "semantic-search", - "sqlite", - "bun" - ], - "author": "AbianS", - "license": "MIT", - "bugs": { - "url": "https://github.com/AbianS/code-recall/issues" - }, - "homepage": "https://github.com/AbianS/code-recall#readme", - "engines": { - "bun": ">=1.0.0" - }, + "name": "code-recall-monorepo", + "private": true, "scripts": { - "start": "bun run src/index.ts", - "dev": "bun --watch run src/index.ts", - "build": "bun build src/index.ts --outdir dist --target bun", - "test": "bun test", - "lint": "biome check src tests", - "lint:fix": "biome check --write src tests" - }, - "dependencies": { - "@modelcontextprotocol/sdk": "1.25.2", - "@xenova/transformers": "2.17.2", - "sqlite-vec": "0.1.7-alpha.2", - "tree-sitter-javascript": "0.25.0", - "tree-sitter-typescript": "0.23.2", - "web-tree-sitter": "0.26.3", - "zod": "3.25.76" + "build": "bun --bun turbo run build", + "dev": "bun --bun turbo run dev", + "test": "bun --bun turbo run test", + "lint": "turbo run lint", + "lint:fix": "turbo run lint:fix", + "changeset": "changeset", + "version": "changeset version", + "release": "bun --bun turbo run build && changeset publish" }, "devDependencies": { "@biomejs/biome": "2.3.11", - "@types/bun": "1.2.15" + "@changesets/cli": "2.29.8", + "turbo": "2.7.4", + "typescript": "5.9.3" + }, + "engines": { + "bun": ">=1.0.0" }, - "peerDependencies": { - "typescript": "5" - } + "packageManager": "bun@1.3.5", + "workspaces": [ + "apps/*" + ] } diff --git a/turbo.json b/turbo.json new file mode 100644 index 0000000..03f960a --- /dev/null +++ b/turbo.json @@ -0,0 +1,31 @@ +{ + "$schema": "https://turborepo.dev/schema.json", + "ui": "tui", + "tasks": { + "build": { + "dependsOn": ["^build"], + "inputs": ["$TURBO_DEFAULT$", ".env*"], + "outputs": ["dist/**"] + }, + "test": { + "dependsOn": ["^build"], + "inputs": ["$TURBO_DEFAULT$", "src/**", "tests/**"], + "outputs": [] + }, + "lint": { + "inputs": ["$TURBO_DEFAULT$", "src/**", "tests/**"], + "outputs": [] + }, + "lint:fix": { + "inputs": ["$TURBO_DEFAULT$", "src/**", "tests/**"], + "outputs": [] + }, + "check-types": { + "dependsOn": ["^check-types"] + }, + "dev": { + "cache": false, + "persistent": true + } + } +}