diff --git a/.env.example b/.env.example
new file mode 100644
index 0000000..593fb0a
--- /dev/null
+++ b/.env.example
@@ -0,0 +1,3 @@
+AWS_REGION=your-region-here
+AWS_ACCESS_KEY_ID=your-access-key-here
+AWS_SECRET_ACCESS_KEY=your-secret-key-here
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index c6bba59..a4b416e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,74 +1,47 @@
-# Logs
-logs
-*.log
+# Environment variables
+.env
+.env.*
+!.env.example
+
+# Python
+__pycache__/
+*.py[cod]
+*$py.class
+*.so
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+
+# Node
+node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
-lerna-debug.log*
.pnpm-debug.log*
-# Diagnostic reports (https://nodejs.org/api/report.html)
-report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
-
-# Runtime data
-pids
-*.pid
-*.seed
-*.pid.lock
-
-# Directory for instrumented libs generated by jscoverage/JSCover
-lib-cov
-
-# Coverage directory used by tools like istanbul
-coverage
-*.lcov
-
-# nyc test coverage
-.nyc_output
-
-# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
-.grunt
-
-# Bower dependency directory (https://bower.io/)
-bower_components
-
-# node-waf configuration
-.lock-wscript
-
-# Compiled binary addons (https://nodejs.org/api/addons.html)
-build/Release
-
-# Dependency directories
-node_modules/
-jspm_packages/
-
-# Snowpack dependency directory (https://snowpack.dev/)
-web_modules/
-
-# TypeScript cache
-*.tsbuildinfo
-
-# Optional npm cache directory
-.npm
-
-# Optional eslint cache
-.eslintcache
-
-# Optional stylelint cache
-.stylelintcache
-
-# Microbundle cache
-.rpt2_cache/
-.rts2_cache_cjs/
-.rts2_cache_es/
-.rts2_cache_umd/
-
-# Optional REPL history
-.node_repl_history
-
-# Output of 'npm pack'
-*.tgz
+# IDE
+.idea/
+.vscode/
+*.swp
+*.swo
+# Project specific
+chunks.json
+summary_cache.json
+*-FINAL-REPORT.txt
# Yarn Integrity file
.yarn-integrity
@@ -128,3 +101,17 @@ dist
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
+
+# Test files
+test.html
+test.ts
+test.js
+test.d.ts
+test.js.map
+parallel-report.txt
+quantum-deep-research-report.txt
+quantum-parallel-report.txt
+deepresearch-report.txt
+
+mcp-webresearch-original
+TURTLE-SOUP.txt
diff --git a/README.md b/README.md
index 35dd7ab..4cd4bbc 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,46 @@
-# MCP Web Research Server
+# MCP Deep Web Research Server (v0.3.0)
-A Model Context Protocol (MCP) server for web research.
+[](https://nodejs.org/)
+[](https://www.typescriptlang.org/)
+[](https://opensource.org/licenses/MIT)
-Bring real-time info into Claude and easily research any topic.
+A Model Context Protocol (MCP) server for advanced web research.
+
+## Latest Changes
+
+- Added visit_page tool for direct webpage content extraction
+- Optimized performance to work within MCP timeout limits
+ * Reduced default maxDepth and maxBranching parameters
+ * Improved page loading efficiency
+ * Added timeout checks throughout the process
+ * Enhanced error handling for timeouts
+
+> This project is a fork of [mcp-webresearch](https://github.com/mzxrai/mcp-webresearch) by [mzxrai](https://github.com/mzxrai), enhanced with additional features for deep web research capabilities. We're grateful to the original creators for their foundational work.
+
+Bring real-time info into Claude with intelligent search queuing, enhanced content extraction, and deep research capabilities.
## Features
-- Google search integration
-- Webpage content extraction
-- Research session tracking (list of visited pages, search queries, etc.)
-- Screenshot capture
+- Intelligent Search Queue System
+ - Batch search operations with rate limiting
+ - Queue management with progress tracking
+ - Error recovery and automatic retries
+ - Search result deduplication
+
+- Enhanced Content Extraction
+ - TF-IDF based relevance scoring
+ - Keyword proximity analysis
+ - Content section weighting
+ - Readability scoring
+ - Improved HTML structure parsing
+ - Structured data extraction
+ - Better content cleaning and formatting
+
+- Core Features
+ - Google search integration
+ - Webpage content extraction
+ - Research session tracking
+ - Markdown conversion with improved formatting
## Prerequisites
@@ -18,42 +49,133 @@ Bring real-time info into Claude and easily research any topic.
## Installation
-First, ensure you've downloaded and installed the [Claude Desktop app](https://claude.ai/download) and you have npm installed.
+### Global Installation (Recommended)
+
+```bash
+# Install globally using npm
+npm install -g mcp-deepwebresearch
+
+# Or using yarn
+yarn global add mcp-deepwebresearch
-Next, add this entry to your `claude_desktop_config.json` (on Mac, found at `~/Library/Application\ Support/Claude/claude_desktop_config.json`):
+# Or using pnpm
+pnpm add -g mcp-deepwebresearch
+```
+
+### Local Project Installation
+
+```bash
+# Using npm
+npm install mcp-deepwebresearch
+
+# Using yarn
+yarn add mcp-deepwebresearch
+
+# Using pnpm
+pnpm add mcp-deepwebresearch
+```
+### Claude Desktop Integration
+
+After installing the package, add this entry to your `claude_desktop_config.json`:
+
+#### Windows
```json
{
"mcpServers": {
- "webresearch": {
- "command": "npx",
- "args": ["-y", "@mzxrai/mcp-webresearch@latest"]
+ "deepwebresearch": {
+ "command": "mcp-deepwebresearch",
+ "args": []
}
}
}
```
+Location: `%APPDATA%\Claude\claude_desktop_config.json`
-This config allows Claude Desktop to automatically start the web research MCP server when needed.
+#### macOS
+```json
+{
+ "mcpServers": {
+ "deepwebresearch": {
+ "command": "mcp-deepwebresearch",
+ "args": []
+ }
+ }
+}
+```
+Location: `~/Library/Application Support/Claude/claude_desktop_config.json`
-## Usage
+This config allows Claude Desktop to automatically start the web research MCP server when needed.
-Simply start a chat with Claude and send a prompt that would benefit from web research. If you'd like a prebuilt prompt customized for deeper web research, you can use the `agentic-research` prompt that we provide through this package. Access that prompt in Claude Desktop by clicking the Paperclip icon in the chat input and then selecting `Choose an integration` → `webresearch` → `agentic-research`.
+### First-time Setup
-
+After installation, run this command to install required browser dependencies:
+```bash
+npx playwright install chromium
+```
-### Tools
+## Usage
-1. `search_google`
- - Performs Google searches and extracts results
- - Arguments: `{ query: string }`
+Simply start a chat with Claude and send a prompt that would benefit from web research. If you'd like a prebuilt prompt customized for deeper web research, you can use the `agentic-research` prompt that we provide through this package. Access that prompt in Claude Desktop by clicking the Paperclip icon in the chat input and then selecting `Choose an integration` → `deepwebresearch` → `agentic-research`.
-2. `visit_page`
- - Visits a webpage and extracts its content
- - Arguments: `{ url: string, takeScreenshot?: boolean }`
+### Tools
-3. `take_screenshot`
- - Takes a screenshot of the current page
- - No arguments required
+1. `deep_research`
+ - Performs comprehensive research with content analysis
+ - Arguments:
+ ```typescript
+ {
+ topic: string;
+ maxDepth?: number; // default: 2
+ maxBranching?: number; // default: 3
+ timeout?: number; // default: 55000 (55 seconds)
+ minRelevanceScore?: number; // default: 0.7
+ }
+ ```
+ - Returns:
+ ```typescript
+ {
+ findings: {
+ mainTopics: Array<{name: string, importance: number}>;
+ keyInsights: Array<{text: string, confidence: number}>;
+ sources: Array<{url: string, credibilityScore: number}>;
+ };
+ progress: {
+ completedSteps: number;
+ totalSteps: number;
+ processedUrls: number;
+ };
+ timing: {
+ started: string;
+ completed?: string;
+ duration?: number;
+ operations?: {
+ parallelSearch?: number;
+ deduplication?: number;
+ topResultsProcessing?: number;
+ remainingResultsProcessing?: number;
+ total?: number;
+ };
+ };
+ }
+ ```
+
+2. `parallel_search`
+ - Performs multiple Google searches in parallel with intelligent queuing
+ - Arguments: `{ queries: string[], maxParallel?: number }`
+ - Note: maxParallel is limited to 5 to ensure reliable performance
+
+3. `visit_page`
+ - Visit a webpage and extract its content
+ - Arguments: `{ url: string }`
+ - Returns:
+ ```typescript
+ {
+ url: string;
+ title: string;
+ content: string; // Markdown formatted content
+ }
+ ```
### Prompts
@@ -65,39 +187,54 @@ A guided research prompt that helps Claude conduct thorough web research. The pr
- Keep you informed and let you guide the research interactively
- Always cite sources with URLs
-### Resources
+## Configuration Options
-We expose two things as MCP resources: (1) captured webpage screenshots, and (2) the research session.
+The server can be configured through environment variables:
-#### Screenshots
+- `MAX_PARALLEL_SEARCHES`: Maximum number of concurrent searches (default: 5)
+- `SEARCH_DELAY_MS`: Delay between searches in milliseconds (default: 200)
+- `MAX_RETRIES`: Number of retry attempts for failed requests (default: 3)
+- `TIMEOUT_MS`: Request timeout in milliseconds (default: 55000)
+- `LOG_LEVEL`: Logging level (default: 'info')
-When you take a screenshot, it's saved as an MCP resource. You can access captured screenshots in Claude Desktop via the Paperclip icon.
+## Error Handling
-#### Research Session
+### Common Issues
-The server maintains a research session that includes:
-- Search queries
-- Visited pages
-- Extracted content
-- Screenshots
-- Timestamps
+1. Rate Limiting
+ - Symptom: "Too many requests" error
+ - Solution: Increase `SEARCH_DELAY_MS` or decrease `MAX_PARALLEL_SEARCHES`
-### Suggestions
+2. Network Timeouts
+ - Symptom: "Request timed out" error
+ - Solution: Ensure requests complete within the 60-second MCP timeout
-For the best results, if you choose not to use the `agentic-research` prompt when doing your research, it may be helpful to suggest high-quality sources for Claude to use when researching general topics. For example, you could prompt `news today from reuters or AP` instead of `news today`.
+3. Browser Issues
+ - Symptom: "Browser failed to launch" error
+ - Solution: Ensure Playwright is properly installed (`npx playwright install`)
-## Problems
+### Debugging
-This is very much pre-alpha code. And it is also AIGC, so expect bugs.
+This is beta software. If you run into issues:
-If you run into issues, it may be helpful to check Claude Desktop's MCP logs:
+1. Check Claude Desktop's MCP logs:
+ ```bash
+ # On macOS
+ tail -n 20 -f ~/Library/Logs/Claude/mcp*.log
+
+ # On Windows
+ Get-Content -Path "$env:APPDATA\Claude\logs\mcp*.log" -Tail 20 -Wait
+ ```
-```bash
-tail -n 20 -f ~/Library/Logs/Claude/mcp*.log
-```
+2. Enable debug logging:
+ ```bash
+ export LOG_LEVEL=debug
+ ```
## Development
+### Setup
+
```bash
# Install dependencies
pnpm install
@@ -112,6 +249,56 @@ pnpm watch
pnpm dev
```
+### Testing
+
+```bash
+# Run all tests
+pnpm test
+
+# Run tests in watch mode
+pnpm test:watch
+
+# Run tests with coverage
+pnpm test:coverage
+```
+
+### Code Quality
+
+```bash
+# Run linter
+pnpm lint
+
+# Fix linting issues
+pnpm lint:fix
+
+# Type check
+pnpm type-check
+```
+
+## Contributing
+
+1. Fork the repository
+2. Create your feature branch (`git checkout -b feature/amazing-feature`)
+3. Commit your changes (`git commit -m 'Add some amazing feature'`)
+4. Push to the branch (`git push origin feature/amazing-feature`)
+5. Open a Pull Request
+
+### Coding Standards
+
+- Follow TypeScript best practices
+- Maintain test coverage above 80%
+- Document new features and APIs
+- Update CHANGELOG.md for significant changes
+- Follow semantic versioning
+
+### Performance Considerations
+
+- Use batch operations where possible
+- Implement proper error handling and retries
+- Consider memory usage with large datasets
+- Cache results when appropriate
+- Use streaming for large content
+
## Requirements
- Node.js >= 18
@@ -120,12 +307,17 @@ pnpm dev
## Verified Platforms
- [x] macOS
+- [x] Windows
- [ ] Linux
## License
MIT
+## Credits
+
+This project builds upon the excellent work of [mcp-webresearch](https://github.com/mzxrai/mcp-webresearch) by [mzxrai](https://github.com/mzxrai). The original codebase provided the foundation for our enhanced features and capabilities.
+
## Author
-[mzxrai](https://github.com/mzxrai)
\ No newline at end of file
+[qpd-v](https://github.com/qpd-v)
\ No newline at end of file
diff --git a/chunk_document.py b/chunk_document.py
new file mode 100644
index 0000000..9040671
--- /dev/null
+++ b/chunk_document.py
@@ -0,0 +1,25 @@
+from typing import List
+import json
+
+def main():
+ print("Requesting file chunking from claude-chunks MCP server...")
+
+ # This will be replaced by the actual MCP tool call result
+ print("Please use the following MCP tool call:")
+ print("""
+
+claude-chunks
+chunk_file
+
+{
+ "filePath": "amazon bedrock aws user guide.txt",
+ "maxTokens": 4000,
+ "overlapTokens": 200
+}
+
+
+""")
+ print("\nAfter getting the chunks, save them to chunks.json and then run summarize_report.py")
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/deepresearch-report.txt b/deepresearch-report.txt
new file mode 100644
index 0000000..21e910c
--- /dev/null
+++ b/deepresearch-report.txt
@@ -0,0 +1,48 @@
+Deep Research Report on LLM News
+
+Main Topics:
+1. **Label** - Importance: 107.33
+2. **2409** - Importance: 74.82
+3. **17515** - Importance: 52.37
+4. **Arxiv** - Importance: 50.68
+5. **Toggle** - Importance: 48.63
+6. **Https** - Importance: 31.00
+7. **Org** - Importance: 5.52
+
+Key Insights:
+1. **Computer Science > Artificial Intelligence**
+ - arXiv:2409.17515 (cs) [Submitted on 26 Sep 2024 (v1), last revised 30 Oct 2024 (v3)]
+ - Title: From News to Forecast: Integrating Event Analysis in LLM-Based Time Series Forecasting with Reflection
+ - Authors: Xinlei Wang, Maike Feng, Jing Qiu, Jinjin Gu
+
+2. **LLM & Generative AI News**
+ - Meta’s big, expensive AI bet hinges on giving its models away for free
+ - Generative AI could soon decimate the call center industry, says CEO
+ - 5 Pro enters public preview on Vertex AI
+
+3. **Co-LLM Project**
+ - Co-LLM trains a general-purpose LLM to collaborate with expert models
+ - Used data like the BioASQ medical set to couple a base LLM with expert LLMs
+
+Sources:
+1. [Computer Science > Artificial Intelligence](https://arxiv.org/abs/2409.17515)
+2. [May 2024 Top LLM & Generative AI News, Research, & Open-Source Tools](https://odsc.medium.com/may-2024-top-llm-generative-ai-news-research-open-source-tools-0ad7f0b28f31)
+3. [LLMs for innovation and technology intelligence: news categorization and trend signal detection](https://medium.com/mapegy-tech/llms-for-innovation-and-technology-intelligence-news-categorization-and-trend-signal-detection-ec4171627937)
+4. [Enhancing LLM collaboration for smarter, more efficient solutions](https://news.mit.edu/2024/enhancing-llm-collaboration-smarter-more-efficient-solutions-0916)
+5. [LLMs develop their own understanding of reality as their language abilities improve](https://news.mit.edu/2024/llms-develop-own-understanding-of-reality-as-language-abilities-improve-0814)
+6. [Brain News Topics Analysis with LLM](https://braincompany.co/bntallm.html)
+7. [From News to Forecast: Integrating Event Analysis in LLM-Based Time Series Forecasting with Reflection | OpenReview](https://openreview.net/forum?id=tj8nsfxi5r&referrer=%5Bthe%20profile%20of%20Jinjin%20Gu%5D(%2Fprofile%3Fid%3D~Jinjin_Gu1))
+8. [LLMs aren’t always bad at writing news headlines](https://sixcolors.com/post/2025/01/llms-arent-always-bad-at-writing-news-headlines/)
+9. [Things we learned about LLMs in 2024 | Hacker News](https://news.ycombinator.com/item?id=42560558)
+10. [News](https://www.infoq.com/llms/news/)
+11. [AI and LLM News Articles (2023) - Health Research Alliance](https://www.healthra.org/resources/ai-and-llm-news-articles-2023/)
+12. [What’s Currently Happening in LLMs? (Q2 2024)](https://www.startus-insights.com/innovators-guide/llm-news-brief/)
+13. [Thomson Reuters CoCounsel Tests Custom LLM from OpenAI, Broadening its Multi-Model Product Strategy](https://www.prnewswire.com/news-releases/thomson-reuters-cocounsel-tests-custom-llm-from-openai-broadening-its-multi-model-product-strategy-302314877.html)
+14. [Can AI Hold Consistent Values? Stanford Researchers Probe LLM Consistency and Bias](https://hai.stanford.edu/news/can-ai-hold-consistent-values-stanford-researchers-probe-llm-consistency-and-bias)
+15. [We Built a News Site Powered by LLMs and Public Data: Here’s What We Learned](https://generative-ai-newsroom.com/we-built-a-news-site-powered-by-llms-and-public-data-heres-what-we-learned-aba6c52a7ee4)
+16. [Extracting Structured Insights from Financial News: An Augmented LLM Driven Approach](https://arxiv.org/html/2407.15788v1)
+17. [What would you like to report?](https://dl.acm.org/doi/10.1145/3677052.3698642)
+18. [An Exploration of Large Language Models for Verification of News Headlines](https://ieeexplore.ieee.org/document/10411561/)
+19. [AI and Large Language Models (LLM) - Health Research Alliance](https://www.healthra.org/communities/ai-and-large-language-models/)
+20. [Can Language Models Really Understand? Study Uncovers Limits in AI Logic - Neuroscience News](https://neurosciencenews.com/llm-ai-logic-27987/)
+21. [NVIDIA LLM News](https://www.nvidia.com/en-us/deep-learning-ai/large-language-model-news/)
\ No newline at end of file
diff --git a/document_processor.py b/document_processor.py
new file mode 100644
index 0000000..3ac80b3
--- /dev/null
+++ b/document_processor.py
@@ -0,0 +1,691 @@
+import os
+import json
+import re
+import time
+import glob
+import math
+import hashlib
+from typing import List, Dict, Tuple
+from datetime import datetime
+import boto3
+from dotenv import load_dotenv
+from concurrent.futures import ThreadPoolExecutor, as_completed, wait, FIRST_COMPLETED
+from tqdm import tqdm
+from botocore.exceptions import ClientError
+from rate_tracker import RateTracker, RateTrackerConfig
+
+# Load environment variables
+load_dotenv()
+
+class Cache:
+ def __init__(self, cache_file: str = 'summary_cache.json'):
+ self.cache_file = cache_file
+ self.cache = self._load_cache()
+
+ def _load_cache(self) -> Dict:
+ if os.path.exists(self.cache_file):
+ try:
+ with open(self.cache_file, 'r') as f:
+ return json.load(f)
+ except:
+ return {}
+ return {}
+
+ def _save_cache(self):
+ with open(self.cache_file, 'w') as f:
+ json.dump(self.cache, f)
+
+ def get(self, key: str) -> str:
+ return self.cache.get(key)
+
+ def set(self, key: str, value: str):
+ self.cache[key] = value
+ self._save_cache()
+
+class DocumentChunker:
+ def __init__(self, target_chunk_size: int = 6000):
+ self.target_chunk_size = target_chunk_size
+ self.header_pattern = re.compile(r'^(?:#{1,6}|\d+\.)\s+.+$', re.MULTILINE)
+
+ def split_into_sections(self, text: str) -> List[str]:
+ sections = []
+ current_section = []
+
+ for line in text.split('\n'):
+ if self.header_pattern.match(line) and len('\n'.join(current_section).split()) > self.target_chunk_size // 2:
+ if current_section:
+ sections.append('\n'.join(current_section))
+ current_section = [line]
+ else:
+ current_section.append(line)
+
+ if current_section:
+ sections.append('\n'.join(current_section))
+
+ return sections
+
+ def optimize_chunks(self, sections: List[str]) -> List[str]:
+ optimized_chunks = []
+ current_chunk = []
+ current_size = 0
+
+ for section in sections:
+ section_size = len(section.split())
+
+ if section_size > self.target_chunk_size:
+ sentences = re.split(r'(?<=[.!?])\s+', section)
+ temp_chunk = []
+ temp_size = 0
+
+ for sentence in sentences:
+ sentence_size = len(sentence.split())
+ if temp_size + sentence_size <= self.target_chunk_size:
+ temp_chunk.append(sentence)
+ temp_size += sentence_size
+ else:
+ if temp_chunk:
+ optimized_chunks.append(' '.join(temp_chunk))
+ temp_chunk = [sentence]
+ temp_size = sentence_size
+
+ if temp_chunk:
+ optimized_chunks.append(' '.join(temp_chunk))
+
+ elif current_size + section_size <= self.target_chunk_size:
+ current_chunk.append(section)
+ current_size += section_size
+ else:
+ if current_chunk:
+ optimized_chunks.append('\n\n'.join(current_chunk))
+ current_chunk = [section]
+ current_size = section_size
+
+ if current_chunk:
+ optimized_chunks.append('\n\n'.join(current_chunk))
+
+ return optimized_chunks
+
+ def chunk_document(self, text: str) -> List[str]:
+ sections = self.split_into_sections(text)
+ chunks = self.optimize_chunks(sections)
+ return chunks
+
+class BedrockSummarizer:
+ def __init__(self, topic: str, max_workers: int = 4):
+ self.topic = topic
+ self.bedrock = boto3.client(
+ service_name='bedrock-runtime',
+ region_name=os.getenv('AWS_REGION'),
+ aws_access_key_id=os.getenv('AWS_ACCESS_KEY_ID'),
+ aws_secret_access_key=os.getenv('AWS_SECRET_ACCESS_KEY')
+ )
+ self.model_id = "anthropic.claude-3-5-sonnet-20241022-v2:0"
+ self.max_tokens = 4000
+ self.temperature = 0.7
+ self.max_workers = max_workers
+ self.cache = Cache()
+ self.rate_tracker = RateTracker(RateTrackerConfig(
+ requestsPerMinute=50, # AWS Bedrock limit
+ tokensPerMinute=400000, # AWS Bedrock limit
+ maxTokensPerRequest=4000
+ ))
+
+ def get_cache_key(self, content: str, task: str) -> str:
+ content_hash = hashlib.md5(content.encode()).hexdigest()
+ return f"{content_hash}_{task}"
+
+ def wait_for_rate_limit(self, estimated_tokens: int):
+ wait_time = self.rate_tracker.get_wait_time(estimated_tokens)
+ if wait_time > 0:
+ status = self.rate_tracker.get_rate_limit_status()
+ print(f"[RATE] Waiting {wait_time}ms for capacity")
+ print(f"[RATE] Requests: {status['requestsUsed']}/{self.rate_tracker.config['requestsPerMinute']}")
+ print(f"[RATE] Tokens: {status['tokensUsed']}/{self.rate_tracker.config['tokensPerMinute']}")
+ print(f"[RATE] Next reset in: {math.ceil((status['nextReset'] - time.time()) * 1000)}ms")
+ time.sleep(wait_time / 1000) # Convert ms to seconds
+
+ def determine_analysis_tasks(self, content: str) -> Dict[str, str]:
+ """Analyze content to determine appropriate analysis tasks."""
+ prompt = f"""Analyze this content about {self.topic} and create a comprehensive analysis plan. The analysis should follow a clear narrative structure with the following sections:
+
+ 1. Executive Summary
+ - Brief overview of key findings and main points
+ - High-level insights and conclusions
+ - Critical takeaways for readers
+
+ 2. Main Analysis Sections (3-4 key areas)
+ - Each section should have a clear focus
+ - Include supporting evidence and examples
+ - Build a coherent narrative flow
+
+ 3. Supporting Analysis
+ - Technical details and implementation specifics
+ - Market or domain-specific considerations
+ - Risk and opportunity analysis
+
+ 4. Future Implications
+ - Long-term impact and consequences
+ - Emerging trends and developments
+ - Recommendations and next steps
+
+ Format your response as a JSON object where each key represents a section name and its value describes what should be analyzed. The sections should flow logically and build upon each other.
+
+ Example format:
+ {{
+ "executive_summary": "comprehensive overview of key findings and critical insights",
+ "technical_foundation": "detailed analysis of core technologies and methodologies",
+ "market_dynamics": "examination of market forces, competition, and opportunities",
+ "implementation_strategy": "practical considerations and execution framework",
+ "future_outlook": "long-term implications and strategic recommendations"
+ }}
+
+ Content for analysis:
+ {content[:2000]}
+
+ Create a structure that tells a cohesive story while maintaining analytical rigor.
+ """
+
+ response = self.invoke_model_with_retry({
+ "anthropic_version": "bedrock-2023-05-31",
+ "max_tokens": 4000,
+ "messages": [{"role": "user", "content": prompt}],
+ "temperature": 0.7
+ })
+
+ try:
+ # Extract JSON from response
+ json_str = response[response.find('{'):response.rfind('}')+1]
+ tasks = json.loads(json_str)
+ return tasks
+ except:
+ # Fallback to default tasks if JSON parsing fails
+ return {
+ "overview": f"main aspects and key concepts of {self.topic}",
+ "analysis": f"detailed analysis of important elements in {self.topic}",
+ "implications": f"effects and implications of {self.topic}",
+ "future": f"future trends and developments in {self.topic}"
+ }
+
+ def create_prompt(self, content: str, task: str, is_final: bool = False) -> dict:
+ if is_final:
+ prompt = f"""Create a comprehensive final analysis about {self.topic} focusing on {task}.
+ Use these previous summaries to create a well-structured narrative that flows naturally:
+
+ {content}
+
+ Guidelines for the analysis:
+ 1. Start with a clear introductory paragraph that sets the context
+ 2. Develop your main points using a mix of:
+ - Well-crafted paragraphs that explain key concepts
+ - Specific examples and evidence to support claims
+ - Selective use of bullet points for lists or features
+ 3. Use clear transitions between major points
+ 4. Include relevant data or metrics where appropriate
+ 5. End with a strong concluding paragraph that synthesizes the main insights
+
+ Focus on creating a cohesive narrative that a reader can follow easily. Avoid excessive bullet points or lists unless absolutely necessary. Each major point should flow naturally into the next."""
+ else:
+ prompt = f"""Analyze this portion of content about {self.topic}, focusing on {task}.
+ Create a well-structured analysis that will contribute to the larger narrative:
+
+ {content}
+
+ Guidelines for analysis:
+ 1. Begin with a clear topic sentence that connects to the main theme
+ 2. Develop your analysis using:
+ - Well-written paragraphs that explain concepts
+ - Specific examples from the content
+ - Data or evidence when available
+ 3. Make connections between different points
+ 4. Highlight particularly significant findings
+ 5. End with a summary that ties back to the main focus
+
+ Write in a clear, engaging style that maintains analytical rigor while being accessible to readers.
+ Use paragraphs as your primary structure, with lists only when they truly add value."""
+
+ return {
+ "anthropic_version": "bedrock-2023-05-31",
+ "max_tokens": self.max_tokens,
+ "messages": [{"role": "user", "content": prompt}],
+ "temperature": self.temperature
+ }
+
+ def invoke_model_with_retry(self, prompt: dict, max_retries: int = 5, timeout: int = 30) -> str:
+ retry_count = 0
+ base_delay = 1
+
+ # Estimate token usage
+ prompt_tokens = len(prompt['messages'][0]['content'].split())
+ max_response_tokens = prompt.get('max_tokens', 4000)
+ estimated_total_tokens = prompt_tokens + max_response_tokens
+
+ print(f"[TOKENS] Estimated input tokens: {prompt_tokens}")
+ print(f"[TOKENS] Maximum response tokens: {max_response_tokens}")
+ print(f"[TOKENS] Estimated total tokens: {estimated_total_tokens}")
+
+ while retry_count < max_retries:
+ try:
+ print("[API] Checking rate limits...")
+ self.wait_for_rate_limit(estimated_total_tokens)
+ print(f"[API] Sending request to Bedrock (timeout: {timeout}s)...")
+
+ # Set a timeout for the API call
+ start_time = time.time()
+ try:
+ response = self.bedrock.invoke_model(
+ modelId=self.model_id,
+ body=json.dumps(prompt)
+ )
+
+ # Check if we exceeded the timeout
+ if time.time() - start_time > timeout:
+ print(f"[TIMEOUT] API call exceeded {timeout} seconds")
+ raise TimeoutError(f"API call timed out after {timeout} seconds")
+
+ print("[API] Reading response from Bedrock...")
+ response_data = response.get('body').read()
+ print(f"[DEBUG] Raw response size: {len(response_data)} bytes")
+
+ try:
+ response_body = json.loads(response_data)
+ print("[DEBUG] Response structure:", json.dumps(response_body, indent=2)[:500] + "...")
+
+ if 'content' not in response_body:
+ print("[ERROR] Missing 'content' in response")
+ print("[DEBUG] Full response:", response_body)
+ raise ValueError("Invalid response structure - missing 'content'")
+
+ if not response_body['content'] or not isinstance(response_body['content'], list):
+ print("[ERROR] Invalid 'content' structure in response")
+ print("[DEBUG] Content value:", response_body['content'])
+ raise ValueError("Invalid content structure")
+
+ if 'text' not in response_body['content'][0]:
+ print("[ERROR] Missing 'text' in content")
+ print("[DEBUG] Content object:", response_body['content'][0])
+ raise ValueError("Invalid content structure - missing 'text'")
+
+ response_text = response_body['content'][0]['text']
+
+ # Record actual token usage
+ actual_response_tokens = len(response_text.split())
+ actual_total_tokens = prompt_tokens + actual_response_tokens
+ print(f"[TOKENS] Actual response tokens: {actual_response_tokens}")
+ print(f"[TOKENS] Actual total tokens: {actual_total_tokens}")
+ self.rate_tracker.record_usage(actual_total_tokens)
+
+ print("[OK] Successfully processed API response")
+ return response_text
+
+ except json.JSONDecodeError as e:
+ print("[ERROR] Failed to parse JSON response")
+ print(f"[DEBUG] JSON Error: {str(e)}")
+ print("[DEBUG] Raw response:", response_data)
+ raise
+
+ except Exception as e:
+ print(f"[ERROR] API call failed: {str(e)}")
+ print("[DEBUG] Error type:", type(e).__name__)
+ raise
+ except (ClientError, TimeoutError) as e:
+ retry_count += 1
+ if retry_count == max_retries:
+ print(f"[ERROR] Failed after {max_retries} retries: {str(e)}")
+ return ""
+
+ if isinstance(e, ClientError):
+ error_code = e.response['Error']['Code']
+ if error_code in ['ThrottlingException', 'ServiceUnavailableException']:
+ delay = base_delay * (2 ** retry_count)
+ print(f"[WARN] Rate limited, attempt {retry_count}/{max_retries}")
+ print(f"[WAIT] Waiting {delay} seconds before retry")
+ time.sleep(delay)
+ else:
+ print(f"[ERROR] Bedrock API error: {error_code} - {str(e)}")
+ return ""
+ else: # TimeoutError
+ delay = base_delay * (2 ** retry_count)
+ print(f"[RETRY] Request timed out, attempt {retry_count}/{max_retries}")
+ print(f"[WAIT] Waiting {delay} seconds before retry")
+ time.sleep(delay)
+
+ except Exception as e:
+ print(f"[ERROR] Unexpected error: {str(e)}")
+ print("[DEBUG] Error type:", type(e).__name__)
+ print("[DEBUG] Error details:", str(e))
+ return ""
+
+ def process_chunk(self, args: Tuple[str, str, int, int]) -> Tuple[int, str]:
+ chunk, task, chunk_idx, total_chunks = args
+ start_time = time.time()
+ print(f"\n[INFO] Processing chunk {chunk_idx + 1}/{total_chunks}")
+ print(f"[INFO] Task: {task}")
+ print(f"[INFO] Chunk size: {len(chunk.split())} words")
+
+ cache_key = self.get_cache_key(chunk, task)
+ cached_result = self.cache.get(cache_key)
+ if cached_result:
+ print(f"[CACHE] Using cached result for chunk {chunk_idx + 1}")
+ print(f"[PROGRESS] Status: Retrieved from cache")
+ return chunk_idx, cached_result
+
+ print(f"[API] Creating prompt for chunk {chunk_idx + 1}")
+ prompt = self.create_prompt(chunk, task)
+ prompt_tokens = len(prompt['messages'][0]['content'].split())
+ print(f"[API] Prompt size: {prompt_tokens} tokens")
+
+ print(f"[API] Calling Bedrock API for chunk {chunk_idx + 1}")
+ result = self.invoke_model_with_retry(prompt)
+
+ elapsed_time = time.time() - start_time
+ if result:
+ result_tokens = len(result.split())
+ print(f"[OK] Successfully processed chunk {chunk_idx + 1} in {elapsed_time:.1f}s")
+ print(f"[INFO] Response size: {result_tokens} tokens")
+ print(f"[CACHE] Caching result for chunk {chunk_idx + 1}")
+ self.cache.set(cache_key, result)
+ print(f"[PROGRESS] Status: Completed successfully")
+ else:
+ print(f"[ERROR] Failed to process chunk {chunk_idx + 1} after {elapsed_time:.1f}s")
+ print(f"[PROGRESS] Status: Failed")
+
+ return chunk_idx, result
+
+ def process_chunks_for_task(self, chunks: List[str], task: str, timeout: int = 600) -> List[str]:
+ """Process chunks with timeout and better progress tracking."""
+ print(f"\nProcessing {len(chunks)} chunks for task: {task}")
+ chunk_results = [None] * len(chunks)
+ start_time = time.time()
+
+ with ThreadPoolExecutor(max_workers=self.max_workers) as executor:
+ print(f"Using {self.max_workers} parallel workers")
+
+ # Submit all tasks and track them
+ futures_to_index = {
+ executor.submit(self.process_chunk, (chunk, task, i, len(chunks))): i
+ for i, chunk in enumerate(chunks)
+ }
+
+ pending = set(futures_to_index.keys())
+ completed_chunks = 0
+
+ while pending:
+ # Check overall timeout
+ if time.time() - start_time > timeout:
+ print(f"\n[TIMEOUT] Task processing exceeded {timeout} seconds")
+ print(f"[STATUS] Completed {completed_chunks}/{len(chunks)} chunks")
+ break
+
+ # Wait for the next chunk to complete with a timeout
+ done, pending = wait(pending, timeout=30, return_when=FIRST_COMPLETED)
+
+ # Process completed chunks
+ for future in done:
+ try:
+ idx, result = future.result(timeout=1)
+ if result:
+ chunk_results[idx] = result
+ completed_chunks += 1
+ print(f"[OK] Chunk {idx + 1}/{len(chunks)} processed ({completed_chunks} total complete)")
+ print(f"[PROGRESS] {completed_chunks}/{len(chunks)} chunks completed")
+ print(f"[TIME] Elapsed: {int(time.time() - start_time)}s")
+ else:
+ print(f"[FAIL] Failed to process chunk {idx + 1}/{len(chunks)}")
+ except Exception as e:
+ print(f"[ERROR] Error processing chunk {futures_to_index[future] + 1}: {str(e)}")
+ continue
+
+ # Print status update for remaining chunks
+ if pending:
+ remaining_time = timeout - (time.time() - start_time)
+ print(f"\n[STATUS] {len(pending)} chunks remaining")
+ print(f"[TIME] Timeout in {int(remaining_time)}s")
+
+ # Cancel any remaining futures
+ for future in pending:
+ future.cancel()
+ print(f"[CANCEL] Cancelled chunk {futures_to_index[future] + 1}")
+
+ successful_chunks = [r for r in chunk_results if r is not None]
+ print(f"\nTask {task}: {len(successful_chunks)}/{len(chunks)} chunks processed successfully")
+ return successful_chunks
+
+ def process_content(self, chunks: List[str], task_timeout: int = 900) -> Dict[str, str]:
+ """Process content with task-level timeouts and progress tracking."""
+ print("\nAnalyzing content to determine appropriate tasks...")
+ tasks = self.determine_analysis_tasks(chunks[0])
+ print(f"\nIdentified {len(tasks)} analysis tasks:")
+ for task_name, task_desc in tasks.items():
+ print(f"- {task_name}: {task_desc}")
+
+ results = {}
+ print("\nInitializing parallel task processing...")
+ start_time = time.time()
+
+ with ThreadPoolExecutor(max_workers=len(tasks)) as executor:
+ # Submit all tasks with chunk-level timeout of 600s
+ future_to_task = {
+ executor.submit(self.process_chunks_for_task, chunks, task_desc, 600): task_name
+ for task_name, task_desc in tasks.items()
+ }
+
+ pending = set(future_to_task.keys())
+ completed_tasks = 0
+
+ while pending:
+ # Check overall timeout
+ elapsed = time.time() - start_time
+ if elapsed > task_timeout:
+ print(f"\n[TIMEOUT] Overall processing exceeded {task_timeout} seconds")
+ print(f"[STATUS] Completed {completed_tasks}/{len(tasks)} tasks")
+ break
+
+ # Wait for the next task to complete
+ try:
+ done, pending = wait(pending, timeout=30, return_when=FIRST_COMPLETED)
+
+ # Process completed tasks
+ for future in done:
+ task_name = future_to_task[future]
+ try:
+ print(f"\n[TASK] Processing {task_name} ({completed_tasks + 1}/{len(tasks)})")
+ chunk_summaries = future.result(timeout=30)
+
+ if chunk_summaries:
+ print(f"[INFO] Creating final summary for {task_name}")
+ print(f"[INFO] Processing {len(chunk_summaries)} chunk summaries")
+ results[task_name] = self.create_final_summary(chunk_summaries, tasks[task_name])
+ print(f"[OK] Summary completed for {task_name}")
+ else:
+ print(f"[WARN] No valid summaries generated for {task_name}")
+ results[task_name] = f"Error: No valid summaries generated for {task_name}"
+
+ completed_tasks += 1
+ elapsed = time.time() - start_time
+ print(f"[PROGRESS] {completed_tasks}/{len(tasks)} tasks completed")
+ print(f"[TIME] Total elapsed: {int(elapsed)}s")
+
+ except Exception as e:
+ print(f"[ERROR] Error processing task {task_name}: {str(e)}")
+ print(f"[DEBUG] Error type: {type(e).__name__}")
+ results[task_name] = f"Error processing task: {str(e)}"
+ completed_tasks += 1
+
+ # Print status for remaining tasks
+ if pending:
+ remaining_time = task_timeout - elapsed
+ print(f"\n[STATUS] {len(pending)} tasks remaining")
+ print(f"[TIME] Overall timeout in {int(remaining_time)}s")
+ print("[TASKS] Remaining:", ", ".join(future_to_task[f] for f in pending))
+
+ except Exception as e:
+ print(f"[ERROR] Error in task processing loop: {str(e)}")
+ print("[DEBUG] Error type:", type(e).__name__)
+ continue
+
+ # Cancel any remaining tasks
+ for future in pending:
+ future.cancel()
+ task_name = future_to_task[future]
+ print(f"[CANCEL] Cancelled task: {task_name}")
+ if task_name not in results:
+ results[task_name] = "Error: Task cancelled due to timeout"
+
+ print(f"\n[COMPLETE] Processed {completed_tasks}/{len(tasks)} tasks")
+ print(f"[TIME] Total processing time: {int(time.time() - start_time)}s")
+
+ return results, tasks
+
+ def create_final_summary(self, chunk_summaries: List[str], task: str) -> str:
+ print(f"\nCreating final summary for task: {task}")
+ print(f"Combining {len(chunk_summaries)} chunk summaries...")
+ combined_summaries = "\n\n".join(chunk_summaries)
+
+ cache_key = self.get_cache_key(combined_summaries, f"final_{task}")
+ cached_result = self.cache.get(cache_key)
+ if cached_result:
+ print("[CACHE] Using cached summary")
+ return cached_result
+
+ print("[INFO] Generating new summary...")
+ prompt = self.create_prompt(combined_summaries, task, is_final=True)
+ result = self.invoke_model_with_retry(prompt)
+
+ if result:
+ print("[OK] Summary generated successfully")
+ print("[INFO] Caching result for future use...")
+ self.cache.set(cache_key, result)
+ else:
+ print("[ERROR] Failed to generate summary")
+
+ return result
+
+def main():
+ import sys
+ if len(sys.argv) < 2:
+ print("Usage: python document_processor.py ")
+ sys.exit(1)
+
+ topic = sys.argv[1]
+ # Find the most recent summary file for the topic
+ summary_pattern = f"*{topic.lower().replace(' ', '-')}*summary.txt"
+ input_file = max(glob.glob(summary_pattern), key=os.path.getctime)
+ if not input_file:
+ print(f"Error: No summary file found matching pattern: {summary_pattern}")
+ sys.exit(1)
+
+ # Check for required environment variables
+ required_env_vars = ['AWS_REGION', 'AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY']
+ missing_vars = [var for var in required_env_vars if not os.getenv(var)]
+ if missing_vars:
+ print("Error: Missing required environment variables:", missing_vars)
+ print("Please set these variables in your .env file")
+ sys.exit(1)
+
+ # Initialize chunker and summarizer
+ chunker = DocumentChunker(target_chunk_size=6000)
+ summarizer = BedrockSummarizer(topic, max_workers=4)
+
+ # Read and chunk the document
+ print("Reading and chunking document...")
+ with open(input_file, 'r', encoding='utf-8') as f:
+ content = f.read()
+
+ chunks = chunker.chunk_document(content)
+ print(f"Document split into {len(chunks)} chunks")
+
+ # Save chunks for inspection if needed
+ with open('chunks.json', 'w', encoding='utf-8') as f:
+ json.dump({'chunks': chunks}, f, indent=2)
+ print("Chunks saved to chunks.json")
+
+ # Process chunks
+ results, tasks = summarizer.process_content(chunks)
+
+ # Generate final report with improved structure
+ sections = []
+
+ # Add report header with metadata
+ report_header = f"""# {topic} Analysis
+Generated using AWS Bedrock Claude 3.5 Sonnet
+Date: {datetime.now().strftime('%B %d, %Y')}
+
+---"""
+ sections.append(report_header)
+
+ # Add executive summary section
+ if "executive_summary" in results:
+ sections.append(f"""## Executive Summary
+
+{results['executive_summary']}
+
+---""")
+ else:
+ # Create a synthetic executive summary from other sections
+ summary_content = []
+ for task_name, result in results.items():
+ # Take first paragraph from each section
+ first_para = result.split('\n\n')[0] if result else ""
+ if first_para:
+ summary_content.append(first_para)
+
+ sections.append(f"""## Executive Summary
+
+{' '.join(summary_content[:2])}
+
+---""")
+
+ # Add main content sections with transitions
+ main_sections = []
+ previous_section = None
+ for task_name, task_desc in tasks.items():
+ if task_name != "executive_summary": # Skip executive summary as it's already added
+ section_content = results[task_name]
+
+ # Add transition from previous section if applicable
+ transition = ""
+ if previous_section:
+ transition = f"Building on the {previous_section} discussed above, we now turn our attention to {task_name}.\n\n"
+
+ # Add section with description and content
+ # Handle task_desc which could be a string or dict value
+ description = task_desc
+ if isinstance(task_desc, dict):
+ description = task_desc.get(task_name, '')
+
+ formatted_desc = description.capitalize() if isinstance(description, str) else ''
+
+ main_sections.append(f"""## {task_name.title()}
+_{formatted_desc}_
+
+{transition}{section_content}
+
+---""")
+ previous_section = task_name
+
+ # Add main sections to report
+ sections.extend(main_sections)
+
+ # Add recommendations section
+ sections.append("""## Next Steps and Recommendations
+
+Based on the comprehensive analysis presented above, consider the following key recommendations:
+
+1. Review and prioritize the insights from each section
+2. Evaluate the implications for your specific context
+3. Develop an action plan based on the findings
+4. Monitor ongoing developments in this rapidly evolving field
+
+For detailed information about any aspect of this analysis, refer to the relevant sections above.""")
+
+ # Combine all sections into final report
+ final_report = f"{chr(10).join(sections)}"
+
+ # Write final report
+ output_file = f"{topic.lower().replace(' ', '-')}-FINAL-REPORT.txt"
+ with open(output_file, 'w', encoding='utf-8') as f:
+ f.write(final_report)
+ print(f"\nFinal report has been generated: {output_file}")
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/improvements-plan.txt b/improvements-plan.txt
new file mode 100644
index 0000000..e16d29d
--- /dev/null
+++ b/improvements-plan.txt
@@ -0,0 +1,85 @@
+# MCP-WebResearch Improvements Plan
+
+## Phase 1: High Priority Improvements
+
+### 1. Intelligent Search Queue System [IN PROGRESS]
+Implementation Steps:
+1. Create SearchQueue class to manage search operations
+ - Add queue data structure for pending searches
+ - Implement rate limiting with exponential backoff
+ - Add progress tracking and status reporting
+ - Handle error recovery and retries
+
+2. Add new tool endpoints:
+ - batch_search: Queue multiple searches
+ - get_queue_status: Check search queue progress
+ - cancel_search: Cancel pending searches
+
+3. Enhance search results aggregation:
+ - Implement result deduplication
+ - Add result sorting options
+ - Improve error handling and recovery
+
+4. Add queue persistence:
+ - Save queue state between sessions
+ - Handle interrupted searches
+ - Implement queue recovery
+
+Testing Criteria:
+- Queue should handle at least 50 searches without triggering anti-bot measures
+- Rate limiting should adapt to Google's response patterns
+- Progress updates should be accurate and timely
+- Results should be properly aggregated and deduplicated
+
+### 2. Enhanced Content Extraction & Relevance Scoring [IN PROGRESS]
+Implementation Steps:
+1. Improve content relevance scoring:
+ - Implement TF-IDF scoring
+ - Add keyword proximity analysis
+ - Add content section weighting
+ - Implement readability scoring
+
+2. Enhance content extraction:
+ - Improve HTML structure parsing
+ - Add support for common content patterns
+ - Implement better content cleaning
+ - Add structured data extraction
+
+3. Add content summarization:
+ - Implement extractive summarization
+ - Add key points extraction
+ - Generate section summaries
+ - Preserve important metadata
+
+4. Improve markdown conversion:
+ - Enhance formatting preservation
+ - Better handle tables and lists
+ - Improve code block handling
+ - Better preserve document structure
+
+Testing Criteria:
+- Content relevance scores should align with human judgment
+- Extracted content should be clean and well-formatted
+- Structured data should be accurately identified
+- Summaries should capture key information
+- Markdown output should be consistently formatted
+
+## Implementation Notes:
+- Each feature will be implemented incrementally
+- Testing will be done after each major component
+- Code reviews required before merging
+- Performance benchmarks will be maintained
+
+## Status Tracking:
+[ ] Feature 1 Started
+[ ] Feature 1 Tested
+[ ] Feature 1 Complete
+[ ] Feature 2 Started
+[ ] Feature 2 Tested
+[ ] Feature 2 Complete
+
+## Dependencies to Add:
+- tf-idf-search (for relevance scoring)
+- readability (for content analysis)
+- html-to-md (for improved markdown conversion)
+- rate-limiter-flexible (for queue management)
\ No newline at end of file
diff --git a/index.ts b/index.ts
index d78079c..43c6676 100644
--- a/index.ts
+++ b/index.ts
@@ -25,6 +25,11 @@ import type { Node } from "turndown";
import * as fs from 'fs';
import * as path from 'path';
import * as os from 'os';
+import { ParallelSearch } from './src/parallel-search.js';
+import { ParallelSearchResult } from './src/types.js';
+
+// Initialize parallel search instance
+const parallelSearch = new ParallelSearch();
// Initialize temp directory for screenshots
const SCREENSHOTS_DIR = fs.mkdtempSync(path.join(os.tmpdir(), 'mcp-screenshots-'));
@@ -141,6 +146,35 @@ const TOOLS: Tool[] = [
required: ["query"],
},
},
+ {
+ name: "parallel_search",
+ description: "Perform multiple Google searches in parallel",
+ inputSchema: {
+ type: "object",
+ properties: {
+ queries: {
+ type: "array",
+ items: { type: "string" },
+ description: "Array of search queries to execute in parallel"
+ },
+ maxParallel: {
+ type: "number",
+ description: "Maximum number of parallel searches (default: 10, max: 10)",
+ minimum: 1,
+ maximum: 10
+ },
+ outputDir: {
+ type: "string",
+ description: "Directory to save search results (default: search-results)"
+ },
+ includeTimings: {
+ type: "boolean",
+ description: "Include execution time information in results (default: false)"
+ }
+ },
+ required: ["queries"]
+ },
+ },
{
name: "visit_page",
description: "Visit a webpage and extract its content",
@@ -1112,6 +1146,98 @@ server.setRequestHandler(CallToolRequestSchema, async (request): Promise !r.error)
+ .forEach(result => {
+ result.results.forEach(searchResult => {
+ addResult({
+ url: searchResult.url,
+ title: searchResult.title,
+ content: searchResult.snippet,
+ timestamp: new Date().toISOString(),
+ });
+ });
+ });
+
+ return {
+ content: [{
+ type: "text",
+ text: JSON.stringify({
+ summary: {
+ ...searchResult.summary,
+ outputDirectory: options.outputDir,
+ ...(includeTimings ? {
+ totalExecutionTime: totalTime,
+ averageExecutionTime: Math.round(totalTime / queries.length)
+ } : {})
+ },
+ results: searchResult.results.map(r => ({
+ searchId: r.searchId,
+ query: r.query,
+ status: r.error ? 'failed' : 'success',
+ resultCount: r.results.length,
+ error: r.error,
+ results: r.results,
+ ...(includeTimings ? { executionTime: r.executionTime } : {})
+ }))
+ }, null, 2)
+ }]
+ };
+ } catch (error) {
+ return {
+ content: [{
+ type: "text",
+ text: `Failed to execute parallel search: ${(error as Error).message}`
+ }],
+ isError: true
+ };
+ }
+ }
+
// Handle unknown tool requests
default:
throw new McpError(
diff --git a/package.json b/package.json
index 264eb18..620b4c6 100644
--- a/package.json
+++ b/package.json
@@ -1,44 +1,70 @@
{
- "name": "@mzxrai/mcp-webresearch",
- "version": "0.1.7",
- "description": "MCP server for web research",
- "license": "MIT",
- "author": "mzxrai",
- "homepage": "https://github.com/mzxrai/mcp-webresearch",
- "bugs": "https://github.com/mzxrai/mcp-webresearch/issues",
+ "name": "mcp-deepwebresearch",
+ "version": "0.3.0",
+ "description": "MCP Web Research Server with Deep Research capabilities",
+ "main": "dist/index.js",
"type": "module",
- "bin": {
- "mcp-server-webresearch": "dist/index.js"
+ "bin": "./dist/index.js",
+ "engines": {
+ "node": ">=18"
},
- "files": [
- "dist"
- ],
"scripts": {
- "build": "tsc && shx chmod +x dist/*.js",
- "prepare": "pnpm run build",
- "postinstall": "playwright install chromium",
- "watch": "tsc --watch",
- "dev": "tsx watch index.ts"
- },
- "publishConfig": {
- "access": "public"
+ "build": "tsc",
+ "postbuild": "node -e \"if (process.platform !== 'win32') require('fs').chmodSync('dist/index.js', '755')\"",
+ "start": "node dist/index.js",
+ "dev": "ts-node-esm src/index.ts",
+ "watch": "tsc -w",
+ "test": "jest",
+ "lint": "eslint src/**/*.ts",
+ "clean": "rimraf dist"
},
"keywords": [
"mcp",
- "model-context-protocol",
- "web-research",
- "ai",
- "web-scraping"
+ "research",
+ "web",
+ "search",
+ "analysis"
+ ],
+ "author": "Kenneth ",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/mcpnfo/mcp-deepwebresearch.git"
+ },
+ "bugs": {
+ "url": "https://github.com/mcpnfo/mcp-deepwebresearch/issues"
+ },
+ "homepage": "https://github.com/mcpnfo/mcp-deepwebresearch#readme",
+ "bin": {
+ "mcp-deepwebresearch": "./dist/index.js"
+ },
+ "files": [
+ "dist",
+ "README.md",
+ "LICENSE"
],
+ "license": "MIT",
"dependencies": {
- "@modelcontextprotocol/sdk": "1.0.1",
- "playwright": "^1.49.0",
- "turndown": "^7.1.2"
+ "@modelcontextprotocol/sdk": "^1.1.1",
+ "@types/turndown": "^5.0.5",
+ "cheerio": "^1.0.0",
+ "html-to-md": "^0.8.6",
+ "natural": "^8.0.0",
+ "playwright": "^1.40.0",
+ "rate-limiter-flexible": "^5.0.0",
+ "readability": "^0.1.0",
+ "turndown": "^7.2.0"
},
"devDependencies": {
- "shx": "^0.3.4",
- "tsx": "^4.19.2",
- "typescript": "^5.6.2",
- "@types/turndown": "^5.0.4"
+ "@types/cheerio": "^0.22.35",
+ "@types/jest": "^29.5.0",
+ "@types/node": "^20.0.0",
+ "@typescript-eslint/eslint-plugin": "^6.0.0",
+ "@typescript-eslint/parser": "^6.0.0",
+ "eslint": "^8.0.0",
+ "jest": "^29.0.0",
+ "rimraf": "^5.0.0",
+ "ts-jest": "^29.0.0",
+ "ts-node": "^10.0.0",
+ "typescript": "^5.0.0"
}
}
\ No newline at end of file
diff --git a/parallel-report.txt b/parallel-report.txt
new file mode 100644
index 0000000..7be8524
--- /dev/null
+++ b/parallel-report.txt
@@ -0,0 +1,94 @@
+TURTLE SOUP RESEARCH REPORT
+
+Historical Evolution:
+- Indigenous Origins: Prevalent in tropical coastal regions among indigenous cultures for centuries
+- Colonial Spread: Knowledge of turtle soup preparation spread through colonial networks
+ * Seafaring nations brought the practice from tropical regions to Europe
+ * Initially considered an aristocratic luxury in Europe
+ * British Empire played key role in spreading the dish to Asia
+- First Royal Taste: British royal family first tried turtle soup in 1728
+- Peak Popularity: Mid-1800s to early 1900s
+ * Served at prestigious venues from the Ritz to the Titanic
+ * Commercially manufactured and canned as "Clear Green Turtle Soup"
+ * Featured at White House events from George Washington to Abraham Lincoln
+
+Presidential and Royal Connections:
+- William Howard Taft: Had a dedicated chef for "Taft Terrapin Soup" (whole turtle with four pounds of veal)
+ * Insisted on serving it with champagne for important visitors
+- Queen Victoria: Initially disliked turtle soup, comparing it to "insects and Tories"
+ * Later became a fan, with Hatfield House providing £800 worth of turtle for a three-day visit
+- Other Presidential Connections:
+ * George Washington and John Adams served it at the White House
+ * Abraham Lincoln offered terrapin hors d'oeuvres at his second inauguration
+
+Cultural Impact and Social Significance:
+- Symbol of Status:
+ * Evolved from aristocratic luxury to middle-class aspiration
+ * Used to demonstrate wealth and sophistication
+ * Featured at elaborate "turtle frolics" and society events
+- Regional Variations:
+ * Philadelphia Style: Unique preparation with sherry added just before serving
+ * New Orleans Style: Thick, buttery, dark brown preparation
+ * Asian Variations: Often prepared with medicinal herbs
+ * Singapore: Symbol of prosperity and cultural heritage
+
+The "Turtle King" Phenomenon:
+- Liverpool-based merchant became known as the "Turtle King"
+- Specialized in importing live and processed turtles
+- Primary supplier to British aristocracy
+- Focused mainly on green turtle species
+
+Culinary Characteristics:
+- Preparation Methods:
+ * Broth becomes extremely gelatinous when cooled
+ * Turtle meat itself has no characteristic taste
+ * Flavor depends entirely on seasoning
+ * Often served with sherry or champagne
+- Mock Turtle Soup:
+ * Created as an alternative for those who couldn't afford real turtle
+ * Made with calf's head and feet for similar gelatinous texture
+ * Became popular in its own right
+
+Historical Medicinal Uses:
+- Traditional Beliefs:
+ * Christopher Columbus (1498) reported use of turtle blood for treating leprosy
+ * Sailors believed it prevented scurvy (later proved incorrect)
+ * Various cultures attributed healing properties to turtle soup
+- Modern Nutritional Understanding:
+ * High protein content
+ * Rich in vitamins A, B1, B2, and B6
+ * Contains minerals like phosphorous and zinc
+ * Approximately 335 calories per 2-cup serving
+
+Conservation Impact and Modern Status:
+- Historical Decimation:
+ * Caribbean populations severely depleted by 18th century
+ * Commercial hunting led to near extinction of some species
+ * Mass production for canning further threatened populations
+- Legal Protection:
+ * 1973 Endangered Species Act prohibited turtle hunting in U.S. waters
+ * Modern fines up to $20,000 for interfering with sea turtles
+ * Current fine of $750 for even touching Hawaiian green turtles
+- Contemporary Availability:
+ * Few restaurants still serve authentic turtle soup
+ * Mostly limited to specific regions (New Orleans, Philadelphia)
+ * Some Asian countries continue traditional preparation
+ * Farm-raised turtles now primary source where legal
+
+Social Clubs and Traditions:
+- Hoboken Turtle Club:
+ * One of America's oldest social clubs
+ * Motto: "Dum vivimus vivamus" (While we live, let us live)
+ * Centered around turtle soup consumption
+- Philadelphia Legacy:
+ * Continues through establishments like:
+ - Sansom Street Oyster House
+ - The Union League
+ - Pearl's Oyster Bar in Reading Terminal Market
+
+Legacy and Modern Perspective:
+- Represents significant shift in conservation attitudes
+- Symbol of changing cultural values
+- Reminder of historical impact on marine species
+- Example of how culinary trends can affect wildlife populations
+- Demonstrates evolution from luxury item to protected species
\ No newline at end of file
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 2d9f8d5..b3d8050 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -9,563 +9,4656 @@ importers:
.:
dependencies:
'@modelcontextprotocol/sdk':
- specifier: 1.0.1
- version: 1.0.1
+ specifier: ^1.1.1
+ version: 1.1.1
+ '@types/turndown':
+ specifier: ^5.0.5
+ version: 5.0.5
+ cheerio:
+ specifier: ^1.0.0
+ version: 1.0.0
+ html-to-md:
+ specifier: ^0.8.6
+ version: 0.8.6
+ natural:
+ specifier: ^8.0.0
+ version: 8.0.1
playwright:
- specifier: ^1.49.0
+ specifier: ^1.40.0
version: 1.49.0
+ rate-limiter-flexible:
+ specifier: ^5.0.0
+ version: 5.0.4
+ readability:
+ specifier: ^0.1.0
+ version: 0.1.0
turndown:
- specifier: ^7.1.2
+ specifier: ^7.2.0
version: 7.2.0
devDependencies:
- '@types/turndown':
- specifier: ^5.0.4
- version: 5.0.5
- shx:
- specifier: ^0.3.4
- version: 0.3.4
- tsx:
- specifier: ^4.19.2
- version: 4.19.2
+ '@types/cheerio':
+ specifier: ^0.22.35
+ version: 0.22.35
+ '@types/jest':
+ specifier: ^29.5.0
+ version: 29.5.14
+ '@types/node':
+ specifier: ^20.0.0
+ version: 20.17.12
+ '@typescript-eslint/eslint-plugin':
+ specifier: ^6.0.0
+ version: 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1)(typescript@5.7.2)
+ '@typescript-eslint/parser':
+ specifier: ^6.0.0
+ version: 6.21.0(eslint@8.57.1)(typescript@5.7.2)
+ eslint:
+ specifier: ^8.0.0
+ version: 8.57.1
+ jest:
+ specifier: ^29.0.0
+ version: 29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@types/node@20.17.12)(typescript@5.7.2))
+ rimraf:
+ specifier: ^5.0.0
+ version: 5.0.10
+ ts-jest:
+ specifier: ^29.0.0
+ version: 29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@types/node@20.17.12)(typescript@5.7.2)))(typescript@5.7.2)
+ ts-node:
+ specifier: ^10.0.0
+ version: 10.9.2(@types/node@20.17.12)(typescript@5.7.2)
typescript:
- specifier: ^5.6.2
+ specifier: ^5.0.0
version: 5.7.2
packages:
- '@esbuild/aix-ppc64@0.23.1':
- resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==}
- engines: {node: '>=18'}
- cpu: [ppc64]
- os: [aix]
+ '@ampproject/remapping@2.3.0':
+ resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
+ engines: {node: '>=6.0.0'}
- '@esbuild/android-arm64@0.23.1':
- resolution: {integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [android]
+ '@asamuzakjp/css-color@2.8.2':
+ resolution: {integrity: sha512-RtWv9jFN2/bLExuZgFFZ0I3pWWeezAHGgrmjqGGWclATl1aDe3yhCUaI0Ilkp6OCk9zX7+FjvDasEX8Q9Rxc5w==}
- '@esbuild/android-arm@0.23.1':
- resolution: {integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==}
- engines: {node: '>=18'}
- cpu: [arm]
- os: [android]
+ '@babel/code-frame@7.26.2':
+ resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==}
+ engines: {node: '>=6.9.0'}
- '@esbuild/android-x64@0.23.1':
- resolution: {integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [android]
+ '@babel/compat-data@7.26.5':
+ resolution: {integrity: sha512-XvcZi1KWf88RVbF9wn8MN6tYFloU5qX8KjuF3E1PVBmJ9eypXfs4GRiJwLuTZL0iSnJUKn1BFPa5BPZZJyFzPg==}
+ engines: {node: '>=6.9.0'}
- '@esbuild/darwin-arm64@0.23.1':
- resolution: {integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [darwin]
+ '@babel/core@7.26.0':
+ resolution: {integrity: sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==}
+ engines: {node: '>=6.9.0'}
- '@esbuild/darwin-x64@0.23.1':
- resolution: {integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [darwin]
+ '@babel/generator@7.26.5':
+ resolution: {integrity: sha512-2caSP6fN9I7HOe6nqhtft7V4g7/V/gfDsC3Ag4W7kEzzvRGKqiv0pu0HogPiZ3KaVSoNDhUws6IJjDjpfmYIXw==}
+ engines: {node: '>=6.9.0'}
- '@esbuild/freebsd-arm64@0.23.1':
- resolution: {integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [freebsd]
+ '@babel/helper-compilation-targets@7.26.5':
+ resolution: {integrity: sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==}
+ engines: {node: '>=6.9.0'}
- '@esbuild/freebsd-x64@0.23.1':
- resolution: {integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [freebsd]
+ '@babel/helper-module-imports@7.25.9':
+ resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==}
+ engines: {node: '>=6.9.0'}
- '@esbuild/linux-arm64@0.23.1':
- resolution: {integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [linux]
+ '@babel/helper-module-transforms@7.26.0':
+ resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
- '@esbuild/linux-arm@0.23.1':
- resolution: {integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==}
- engines: {node: '>=18'}
- cpu: [arm]
- os: [linux]
+ '@babel/helper-plugin-utils@7.26.5':
+ resolution: {integrity: sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==}
+ engines: {node: '>=6.9.0'}
- '@esbuild/linux-ia32@0.23.1':
- resolution: {integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==}
- engines: {node: '>=18'}
- cpu: [ia32]
- os: [linux]
+ '@babel/helper-string-parser@7.25.9':
+ resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==}
+ engines: {node: '>=6.9.0'}
- '@esbuild/linux-loong64@0.23.1':
- resolution: {integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==}
- engines: {node: '>=18'}
- cpu: [loong64]
- os: [linux]
+ '@babel/helper-validator-identifier@7.25.9':
+ resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==}
+ engines: {node: '>=6.9.0'}
- '@esbuild/linux-mips64el@0.23.1':
- resolution: {integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==}
- engines: {node: '>=18'}
- cpu: [mips64el]
- os: [linux]
+ '@babel/helper-validator-option@7.25.9':
+ resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==}
+ engines: {node: '>=6.9.0'}
- '@esbuild/linux-ppc64@0.23.1':
- resolution: {integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==}
- engines: {node: '>=18'}
- cpu: [ppc64]
- os: [linux]
+ '@babel/helpers@7.26.0':
+ resolution: {integrity: sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==}
+ engines: {node: '>=6.9.0'}
- '@esbuild/linux-riscv64@0.23.1':
- resolution: {integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==}
- engines: {node: '>=18'}
- cpu: [riscv64]
- os: [linux]
+ '@babel/parser@7.26.5':
+ resolution: {integrity: sha512-SRJ4jYmXRqV1/Xc+TIVG84WjHBXKlxO9sHQnA2Pf12QQEAp1LOh6kDzNHXcUnbH1QI0FDoPPVOt+vyUDucxpaw==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
- '@esbuild/linux-s390x@0.23.1':
- resolution: {integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==}
+ '@babel/plugin-syntax-async-generators@7.8.4':
+ resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-bigint@7.8.3':
+ resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-class-properties@7.12.13':
+ resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-class-static-block@7.14.5':
+ resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-import-attributes@7.26.0':
+ resolution: {integrity: sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-import-meta@7.10.4':
+ resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-json-strings@7.8.3':
+ resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-jsx@7.25.9':
+ resolution: {integrity: sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-logical-assignment-operators@7.10.4':
+ resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3':
+ resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-numeric-separator@7.10.4':
+ resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-object-rest-spread@7.8.3':
+ resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-optional-catch-binding@7.8.3':
+ resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-optional-chaining@7.8.3':
+ resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-private-property-in-object@7.14.5':
+ resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-top-level-await@7.14.5':
+ resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-syntax-typescript@7.25.9':
+ resolution: {integrity: sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/template@7.25.9':
+ resolution: {integrity: sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/traverse@7.26.5':
+ resolution: {integrity: sha512-rkOSPOw+AXbgtwUga3U4u8RpoK9FEFWBNAlTpcnkLFjL5CT+oyHNuUUC/xx6XefEJ16r38r8Bc/lfp6rYuHeJQ==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/types@7.26.5':
+ resolution: {integrity: sha512-L6mZmwFDK6Cjh1nRCLXpa6no13ZIioJDz7mdkzHv399pThrTa/k0nUlNaenOeh2kWu/iaOQYElEpKPUswUa9Vg==}
+ engines: {node: '>=6.9.0'}
+
+ '@bcoe/v8-coverage@0.2.3':
+ resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
+
+ '@cspotcode/source-map-support@0.8.1':
+ resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
+ engines: {node: '>=12'}
+
+ '@csstools/color-helpers@5.0.1':
+ resolution: {integrity: sha512-MKtmkA0BX87PKaO1NFRTFH+UnkgnmySQOvNxJubsadusqPEC2aJ9MOQiMceZJJ6oitUl/i0L6u0M1IrmAOmgBA==}
engines: {node: '>=18'}
- cpu: [s390x]
- os: [linux]
- '@esbuild/linux-x64@0.23.1':
- resolution: {integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==}
+ '@csstools/css-calc@2.1.1':
+ resolution: {integrity: sha512-rL7kaUnTkL9K+Cvo2pnCieqNpTKgQzy5f+N+5Iuko9HAoasP+xgprVh7KN/MaJVvVL1l0EzQq2MoqBHKSrDrag==}
engines: {node: '>=18'}
- cpu: [x64]
- os: [linux]
+ peerDependencies:
+ '@csstools/css-parser-algorithms': ^3.0.4
+ '@csstools/css-tokenizer': ^3.0.3
- '@esbuild/netbsd-x64@0.23.1':
- resolution: {integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==}
+ '@csstools/css-color-parser@3.0.7':
+ resolution: {integrity: sha512-nkMp2mTICw32uE5NN+EsJ4f5N+IGFeCFu4bGpiKgb2Pq/7J/MpyLBeQ5ry4KKtRFZaYs6sTmcMYrSRIyj5DFKA==}
engines: {node: '>=18'}
- cpu: [x64]
- os: [netbsd]
+ peerDependencies:
+ '@csstools/css-parser-algorithms': ^3.0.4
+ '@csstools/css-tokenizer': ^3.0.3
- '@esbuild/openbsd-arm64@0.23.1':
- resolution: {integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==}
+ '@csstools/css-parser-algorithms@3.0.4':
+ resolution: {integrity: sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A==}
engines: {node: '>=18'}
- cpu: [arm64]
- os: [openbsd]
+ peerDependencies:
+ '@csstools/css-tokenizer': ^3.0.3
- '@esbuild/openbsd-x64@0.23.1':
- resolution: {integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==}
+ '@csstools/css-tokenizer@3.0.3':
+ resolution: {integrity: sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==}
engines: {node: '>=18'}
- cpu: [x64]
- os: [openbsd]
- '@esbuild/sunos-x64@0.23.1':
- resolution: {integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [sunos]
+ '@eslint-community/eslint-utils@4.4.1':
+ resolution: {integrity: sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
+
+ '@eslint-community/regexpp@4.12.1':
+ resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==}
+ engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
+
+ '@eslint/eslintrc@2.1.4':
+ resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
+ '@eslint/js@8.57.1':
+ resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
+ '@humanwhocodes/config-array@0.13.0':
+ resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==}
+ engines: {node: '>=10.10.0'}
+ deprecated: Use @eslint/config-array instead
+
+ '@humanwhocodes/module-importer@1.0.1':
+ resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
+ engines: {node: '>=12.22'}
+
+ '@humanwhocodes/object-schema@2.0.3':
+ resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==}
+ deprecated: Use @eslint/object-schema instead
+
+ '@isaacs/cliui@8.0.2':
+ resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
+ engines: {node: '>=12'}
+
+ '@istanbuljs/load-nyc-config@1.1.0':
+ resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==}
+ engines: {node: '>=8'}
+
+ '@istanbuljs/schema@0.1.3':
+ resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==}
+ engines: {node: '>=8'}
+
+ '@jest/console@29.7.0':
+ resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jest/core@29.7.0':
+ resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ peerDependencies:
+ node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
+ peerDependenciesMeta:
+ node-notifier:
+ optional: true
+
+ '@jest/environment@29.7.0':
+ resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jest/expect-utils@29.7.0':
+ resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jest/expect@29.7.0':
+ resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jest/fake-timers@29.7.0':
+ resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jest/globals@29.7.0':
+ resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jest/reporters@29.7.0':
+ resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ peerDependencies:
+ node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
+ peerDependenciesMeta:
+ node-notifier:
+ optional: true
+
+ '@jest/schemas@29.6.3':
+ resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jest/source-map@29.6.3':
+ resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jest/test-result@29.7.0':
+ resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jest/test-sequencer@29.7.0':
+ resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jest/transform@29.7.0':
+ resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jest/types@29.6.3':
+ resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ '@jridgewell/gen-mapping@0.3.8':
+ resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==}
+ engines: {node: '>=6.0.0'}
+
+ '@jridgewell/resolve-uri@3.1.2':
+ resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
+ engines: {node: '>=6.0.0'}
+
+ '@jridgewell/set-array@1.2.1':
+ resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==}
+ engines: {node: '>=6.0.0'}
+
+ '@jridgewell/sourcemap-codec@1.5.0':
+ resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}
+
+ '@jridgewell/trace-mapping@0.3.25':
+ resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
+
+ '@jridgewell/trace-mapping@0.3.9':
+ resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
- '@esbuild/win32-arm64@0.23.1':
- resolution: {integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [win32]
+ '@mixmark-io/domino@2.2.0':
+ resolution: {integrity: sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==}
- '@esbuild/win32-ia32@0.23.1':
- resolution: {integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==}
+ '@modelcontextprotocol/sdk@1.1.1':
+ resolution: {integrity: sha512-siCApQgBn3U8R93TdumLtezRyRIlrA/a63GrTRO1jP31fRyOohpu0iPLvXzsyptxmy7B8GDxr8+r+Phu6mHgzg==}
engines: {node: '>=18'}
- cpu: [ia32]
- os: [win32]
- '@esbuild/win32-x64@0.23.1':
- resolution: {integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [win32]
+ '@mongodb-js/saslprep@1.1.9':
+ resolution: {integrity: sha512-tVkljjeEaAhCqTzajSdgbQ6gE6f3oneVwa3iXR6csiEwXXOFsiC6Uh9iAjAhXPtqa/XMDHWjjeNH/77m/Yq2dw==}
- '@mixmark-io/domino@2.2.0':
- resolution: {integrity: sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==}
+ '@nodelib/fs.scandir@2.1.5':
+ resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
+ engines: {node: '>= 8'}
- '@modelcontextprotocol/sdk@1.0.1':
- resolution: {integrity: sha512-slLdFaxQJ9AlRg+hw28iiTtGvShAOgOKXcD0F91nUcRYiOMuS9ZBYjcdNZRXW9G5JQ511GRTdUy1zQVZDpJ+4w==}
+ '@nodelib/fs.stat@2.0.5':
+ resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
+ engines: {node: '>= 8'}
- '@types/turndown@5.0.5':
- resolution: {integrity: sha512-TL2IgGgc7B5j78rIccBtlYAnkuv8nUQqhQc+DSYV5j9Be9XOcm/SKOVRuA47xAVI3680Tk9B1d8flK2GWT2+4w==}
+ '@nodelib/fs.walk@1.2.8':
+ resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
+ engines: {node: '>= 8'}
- balanced-match@1.0.2:
- resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+ '@pkgjs/parseargs@0.11.0':
+ resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
+ engines: {node: '>=14'}
- brace-expansion@1.1.11:
- resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
+ '@redis/bloom@1.2.0':
+ resolution: {integrity: sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==}
+ peerDependencies:
+ '@redis/client': ^1.0.0
- bytes@3.1.2:
- resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
- engines: {node: '>= 0.8'}
+ '@redis/client@1.6.0':
+ resolution: {integrity: sha512-aR0uffYI700OEEH4gYnitAnv3vzVGXCFvYfdpu/CJKvk4pHfLPEy/JSZyrpQ+15WhXe1yJRXLtfQ84s4mEXnPg==}
+ engines: {node: '>=14'}
- concat-map@0.0.1:
- resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
+ '@redis/graph@1.1.1':
+ resolution: {integrity: sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw==}
+ peerDependencies:
+ '@redis/client': ^1.0.0
- content-type@1.0.5:
- resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
- engines: {node: '>= 0.6'}
+ '@redis/json@1.0.7':
+ resolution: {integrity: sha512-6UyXfjVaTBTJtKNG4/9Z8PSpKE6XgSyEb8iwaqDcy+uKrd/DGYHTWkUdnQDyzm727V7p21WUMhsqz5oy65kPcQ==}
+ peerDependencies:
+ '@redis/client': ^1.0.0
- depd@2.0.0:
- resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
- engines: {node: '>= 0.8'}
+ '@redis/search@1.2.0':
+ resolution: {integrity: sha512-tYoDBbtqOVigEDMAcTGsRlMycIIjwMCgD8eR2t0NANeQmgK/lvxNAvYyb6bZDD4frHRhIHkJu2TBRvB0ERkOmw==}
+ peerDependencies:
+ '@redis/client': ^1.0.0
- esbuild@0.23.1:
- resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==}
- engines: {node: '>=18'}
- hasBin: true
+ '@redis/time-series@1.1.0':
+ resolution: {integrity: sha512-c1Q99M5ljsIuc4YdaCwfUEXsofakb9c8+Zse2qxTadu8TalLXuAESzLvFAvNVbkmSlvlzIQOLpBCmWI9wTOt+g==}
+ peerDependencies:
+ '@redis/client': ^1.0.0
- fs.realpath@1.0.0:
- resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
+ '@sinclair/typebox@0.27.8':
+ resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==}
- fsevents@2.3.2:
- resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
- engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
- os: [darwin]
+ '@sinonjs/commons@3.0.1':
+ resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==}
- fsevents@2.3.3:
- resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
- engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
- os: [darwin]
+ '@sinonjs/fake-timers@10.3.0':
+ resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==}
- function-bind@1.1.2:
- resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
+ '@tsconfig/node10@1.0.11':
+ resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==}
- get-tsconfig@4.8.1:
- resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==}
+ '@tsconfig/node12@1.0.11':
+ resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==}
- glob@7.2.3:
- resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
- deprecated: Glob versions prior to v9 are no longer supported
+ '@tsconfig/node14@1.0.3':
+ resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==}
- hasown@2.0.2:
- resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
- engines: {node: '>= 0.4'}
+ '@tsconfig/node16@1.0.4':
+ resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==}
- http-errors@2.0.0:
- resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
- engines: {node: '>= 0.8'}
+ '@types/babel__core@7.20.5':
+ resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
- iconv-lite@0.6.3:
- resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
- engines: {node: '>=0.10.0'}
+ '@types/babel__generator@7.6.8':
+ resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==}
- inflight@1.0.6:
- resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
- deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
+ '@types/babel__template@7.4.4':
+ resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==}
- inherits@2.0.4:
- resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
+ '@types/babel__traverse@7.20.6':
+ resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==}
- interpret@1.4.0:
- resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==}
- engines: {node: '>= 0.10'}
+ '@types/cheerio@0.22.35':
+ resolution: {integrity: sha512-yD57BchKRvTV+JD53UZ6PD8KWY5g5rvvMLRnZR3EQBCZXiDT/HR+pKpMzFGlWNhFrXlo7VPZXtKvIEwZkAWOIA==}
- is-core-module@2.15.1:
- resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==}
- engines: {node: '>= 0.4'}
+ '@types/graceful-fs@4.1.9':
+ resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==}
- minimatch@3.1.2:
- resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
+ '@types/istanbul-lib-coverage@2.0.6':
+ resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==}
- minimist@1.2.8:
- resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
+ '@types/istanbul-lib-report@3.0.3':
+ resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==}
- once@1.4.0:
- resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
+ '@types/istanbul-reports@3.0.4':
+ resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==}
- path-is-absolute@1.0.1:
- resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
- engines: {node: '>=0.10.0'}
+ '@types/jest@29.5.14':
+ resolution: {integrity: sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==}
- path-parse@1.0.7:
- resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
+ '@types/json-schema@7.0.15':
+ resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
- playwright-core@1.49.0:
- resolution: {integrity: sha512-R+3KKTQF3npy5GTiKH/T+kdhoJfJojjHESR1YEWhYuEKRVfVaxH3+4+GvXE5xyCngCxhxnykk0Vlah9v8fs3jA==}
- engines: {node: '>=18'}
- hasBin: true
+ '@types/node@20.17.12':
+ resolution: {integrity: sha512-vo/wmBgMIiEA23A/knMfn/cf37VnuF52nZh5ZoW0GWt4e4sxNquibrMRJ7UQsA06+MBx9r/H1jsI9grYjQCQlw==}
- playwright@1.49.0:
- resolution: {integrity: sha512-eKpmys0UFDnfNb3vfsf8Vx2LEOtflgRebl0Im2eQQnYMA4Aqd+Zw8bEOB+7ZKvN76901mRnqdsiOGKxzVTbi7A==}
- engines: {node: '>=18'}
- hasBin: true
+ '@types/semver@7.5.8':
+ resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==}
- raw-body@3.0.0:
- resolution: {integrity: sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==}
- engines: {node: '>= 0.8'}
+ '@types/stack-utils@2.0.3':
+ resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==}
- rechoir@0.6.2:
- resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==}
- engines: {node: '>= 0.10'}
+ '@types/turndown@5.0.5':
+ resolution: {integrity: sha512-TL2IgGgc7B5j78rIccBtlYAnkuv8nUQqhQc+DSYV5j9Be9XOcm/SKOVRuA47xAVI3680Tk9B1d8flK2GWT2+4w==}
- resolve-pkg-maps@1.0.0:
- resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
+ '@types/webidl-conversions@7.0.3':
+ resolution: {integrity: sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==}
- resolve@1.22.8:
- resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==}
- hasBin: true
+ '@types/whatwg-url@11.0.5':
+ resolution: {integrity: sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==}
- safer-buffer@2.1.2:
- resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
+ '@types/yargs-parser@21.0.3':
+ resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==}
- setprototypeof@1.2.0:
- resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
+ '@types/yargs@17.0.33':
+ resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==}
- shelljs@0.8.5:
- resolution: {integrity: sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==}
- engines: {node: '>=4'}
- hasBin: true
+ '@typescript-eslint/eslint-plugin@6.21.0':
+ resolution: {integrity: sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==}
+ engines: {node: ^16.0.0 || >=18.0.0}
+ peerDependencies:
+ '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha
+ eslint: ^7.0.0 || ^8.0.0
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@typescript-eslint/parser@6.21.0':
+ resolution: {integrity: sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==}
+ engines: {node: ^16.0.0 || >=18.0.0}
+ peerDependencies:
+ eslint: ^7.0.0 || ^8.0.0
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@typescript-eslint/scope-manager@6.21.0':
+ resolution: {integrity: sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==}
+ engines: {node: ^16.0.0 || >=18.0.0}
+
+ '@typescript-eslint/type-utils@6.21.0':
+ resolution: {integrity: sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==}
+ engines: {node: ^16.0.0 || >=18.0.0}
+ peerDependencies:
+ eslint: ^7.0.0 || ^8.0.0
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ '@typescript-eslint/types@6.21.0':
+ resolution: {integrity: sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==}
+ engines: {node: ^16.0.0 || >=18.0.0}
+
+ '@typescript-eslint/typescript-estree@6.21.0':
+ resolution: {integrity: sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==}
+ engines: {node: ^16.0.0 || >=18.0.0}
+ peerDependencies:
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
- shx@0.3.4:
- resolution: {integrity: sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==}
- engines: {node: '>=6'}
- hasBin: true
+ '@typescript-eslint/utils@6.21.0':
+ resolution: {integrity: sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==}
+ engines: {node: ^16.0.0 || >=18.0.0}
+ peerDependencies:
+ eslint: ^7.0.0 || ^8.0.0
- statuses@2.0.1:
- resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==}
- engines: {node: '>= 0.8'}
+ '@typescript-eslint/visitor-keys@6.21.0':
+ resolution: {integrity: sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==}
+ engines: {node: ^16.0.0 || >=18.0.0}
- supports-preserve-symlinks-flag@1.0.0:
- resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
- engines: {node: '>= 0.4'}
+ '@ungap/structured-clone@1.2.1':
+ resolution: {integrity: sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA==}
- toidentifier@1.0.1:
- resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
- engines: {node: '>=0.6'}
+ acorn-jsx@5.3.2:
+ resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
+ peerDependencies:
+ acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
- tsx@4.19.2:
- resolution: {integrity: sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==}
- engines: {node: '>=18.0.0'}
+ acorn-walk@8.3.4:
+ resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==}
+ engines: {node: '>=0.4.0'}
+
+ acorn@8.14.0:
+ resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==}
+ engines: {node: '>=0.4.0'}
hasBin: true
- turndown@7.2.0:
- resolution: {integrity: sha512-eCZGBN4nNNqM9Owkv9HAtWRYfLA4h909E/WGAWWBpmB275ehNhZyk87/Tpvjbp0jjNl9XwCsbe6bm6CqFsgD+A==}
+ afinn-165-financialmarketnews@3.0.0:
+ resolution: {integrity: sha512-0g9A1S3ZomFIGDTzZ0t6xmv4AuokBvBmpes8htiyHpH7N4xDmvSQL6UxL/Zcs2ypRb3VwgCscaD8Q3zEawKYhw==}
- typescript@5.7.2:
- resolution: {integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==}
- engines: {node: '>=14.17'}
- hasBin: true
+ afinn-165@1.0.4:
+ resolution: {integrity: sha512-7+Wlx3BImrK0HiG6y3lU4xX7SpBPSSu8T9iguPMlaueRFxjbYwAQrp9lqZUuFikqKbd/en8lVREILvP2J80uJA==}
- unpipe@1.0.0:
- resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
- engines: {node: '>= 0.8'}
+ agent-base@7.1.3:
+ resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==}
+ engines: {node: '>= 14'}
- wrappy@1.0.2:
- resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
+ ajv@6.12.6:
+ resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
- zod@3.23.8:
- resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==}
+ ansi-escapes@4.3.2:
+ resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==}
+ engines: {node: '>=8'}
-snapshots:
+ ansi-regex@5.0.1:
+ resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
+ engines: {node: '>=8'}
- '@esbuild/aix-ppc64@0.23.1':
- optional: true
+ ansi-regex@6.1.0:
+ resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==}
+ engines: {node: '>=12'}
- '@esbuild/android-arm64@0.23.1':
- optional: true
+ ansi-styles@4.3.0:
+ resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
+ engines: {node: '>=8'}
- '@esbuild/android-arm@0.23.1':
- optional: true
+ ansi-styles@5.2.0:
+ resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==}
+ engines: {node: '>=10'}
- '@esbuild/android-x64@0.23.1':
- optional: true
+ ansi-styles@6.2.1:
+ resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
+ engines: {node: '>=12'}
- '@esbuild/darwin-arm64@0.23.1':
- optional: true
+ anymatch@3.1.3:
+ resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
+ engines: {node: '>= 8'}
- '@esbuild/darwin-x64@0.23.1':
- optional: true
+ apparatus@0.0.10:
+ resolution: {integrity: sha512-KLy/ugo33KZA7nugtQ7O0E1c8kQ52N3IvD/XgIh4w/Nr28ypfkwDfA67F1ev4N1m5D+BOk1+b2dEJDfpj/VvZg==}
+ engines: {node: '>=0.2.6'}
- '@esbuild/freebsd-arm64@0.23.1':
- optional: true
+ arg@4.1.3:
+ resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
- '@esbuild/freebsd-x64@0.23.1':
- optional: true
+ argparse@1.0.10:
+ resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
- '@esbuild/linux-arm64@0.23.1':
- optional: true
+ argparse@2.0.1:
+ resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
- '@esbuild/linux-arm@0.23.1':
- optional: true
+ array-union@2.1.0:
+ resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
+ engines: {node: '>=8'}
- '@esbuild/linux-ia32@0.23.1':
- optional: true
+ async@2.6.4:
+ resolution: {integrity: sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==}
- '@esbuild/linux-loong64@0.23.1':
- optional: true
+ async@3.2.6:
+ resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==}
- '@esbuild/linux-mips64el@0.23.1':
- optional: true
+ asynckit@0.4.0:
+ resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
- '@esbuild/linux-ppc64@0.23.1':
- optional: true
+ babel-jest@29.7.0:
+ resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ peerDependencies:
+ '@babel/core': ^7.8.0
- '@esbuild/linux-riscv64@0.23.1':
- optional: true
+ babel-plugin-istanbul@6.1.1:
+ resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==}
+ engines: {node: '>=8'}
- '@esbuild/linux-s390x@0.23.1':
- optional: true
+ babel-plugin-jest-hoist@29.6.3:
+ resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- '@esbuild/linux-x64@0.23.1':
- optional: true
+ babel-preset-current-node-syntax@1.1.0:
+ resolution: {integrity: sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==}
+ peerDependencies:
+ '@babel/core': ^7.0.0
- '@esbuild/netbsd-x64@0.23.1':
- optional: true
+ babel-preset-jest@29.6.3:
+ resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ peerDependencies:
+ '@babel/core': ^7.0.0
- '@esbuild/openbsd-arm64@0.23.1':
- optional: true
+ balanced-match@1.0.2:
+ resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
- '@esbuild/openbsd-x64@0.23.1':
- optional: true
+ basic-auth@2.0.1:
+ resolution: {integrity: sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==}
+ engines: {node: '>= 0.8'}
- '@esbuild/sunos-x64@0.23.1':
- optional: true
+ boolbase@1.0.0:
+ resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
- '@esbuild/win32-arm64@0.23.1':
- optional: true
+ brace-expansion@1.1.11:
+ resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
- '@esbuild/win32-ia32@0.23.1':
- optional: true
+ brace-expansion@2.0.1:
+ resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
- '@esbuild/win32-x64@0.23.1':
- optional: true
+ braces@3.0.3:
+ resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
+ engines: {node: '>=8'}
- '@mixmark-io/domino@2.2.0': {}
+ browserslist@4.24.4:
+ resolution: {integrity: sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==}
+ engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
+ hasBin: true
- '@modelcontextprotocol/sdk@1.0.1':
- dependencies:
- content-type: 1.0.5
- raw-body: 3.0.0
- zod: 3.23.8
+ bs-logger@0.2.6:
+ resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==}
+ engines: {node: '>= 6'}
- '@types/turndown@5.0.5': {}
+ bser@2.1.1:
+ resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==}
- balanced-match@1.0.2: {}
+ bson@6.10.1:
+ resolution: {integrity: sha512-P92xmHDQjSKPLHqFxefqMxASNq/aWJMEZugpCjf+AF/pgcUpMMQCg7t7+ewko0/u8AapvF3luf/FoehddEK+sA==}
+ engines: {node: '>=16.20.1'}
- brace-expansion@1.1.11:
- dependencies:
- balanced-match: 1.0.2
- concat-map: 0.0.1
+ buffer-from@1.1.2:
+ resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
- bytes@3.1.2: {}
+ bytes@3.1.2:
+ resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
+ engines: {node: '>= 0.8'}
- concat-map@0.0.1: {}
+ call-bind-apply-helpers@1.0.1:
+ resolution: {integrity: sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==}
+ engines: {node: '>= 0.4'}
- content-type@1.0.5: {}
+ call-bound@1.0.3:
+ resolution: {integrity: sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==}
+ engines: {node: '>= 0.4'}
- depd@2.0.0: {}
+ callsites@3.1.0:
+ resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
+ engines: {node: '>=6'}
- esbuild@0.23.1:
- optionalDependencies:
- '@esbuild/aix-ppc64': 0.23.1
- '@esbuild/android-arm': 0.23.1
- '@esbuild/android-arm64': 0.23.1
- '@esbuild/android-x64': 0.23.1
- '@esbuild/darwin-arm64': 0.23.1
- '@esbuild/darwin-x64': 0.23.1
- '@esbuild/freebsd-arm64': 0.23.1
- '@esbuild/freebsd-x64': 0.23.1
- '@esbuild/linux-arm': 0.23.1
- '@esbuild/linux-arm64': 0.23.1
- '@esbuild/linux-ia32': 0.23.1
- '@esbuild/linux-loong64': 0.23.1
- '@esbuild/linux-mips64el': 0.23.1
- '@esbuild/linux-ppc64': 0.23.1
- '@esbuild/linux-riscv64': 0.23.1
- '@esbuild/linux-s390x': 0.23.1
- '@esbuild/linux-x64': 0.23.1
- '@esbuild/netbsd-x64': 0.23.1
- '@esbuild/openbsd-arm64': 0.23.1
- '@esbuild/openbsd-x64': 0.23.1
- '@esbuild/sunos-x64': 0.23.1
- '@esbuild/win32-arm64': 0.23.1
- '@esbuild/win32-ia32': 0.23.1
- '@esbuild/win32-x64': 0.23.1
+ camelcase@5.3.1:
+ resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
+ engines: {node: '>=6'}
- fs.realpath@1.0.0: {}
+ camelcase@6.3.0:
+ resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==}
+ engines: {node: '>=10'}
- fsevents@2.3.2:
- optional: true
+ caniuse-lite@1.0.30001692:
+ resolution: {integrity: sha512-A95VKan0kdtrsnMubMKxEKUKImOPSuCpYgxSQBo036P5YYgVIcOYJEgt/txJWqObiRQeISNCfef9nvlQ0vbV7A==}
- fsevents@2.3.3:
- optional: true
+ chalk@4.1.2:
+ resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
+ engines: {node: '>=10'}
- function-bind@1.1.2: {}
+ char-regex@1.0.2:
+ resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==}
+ engines: {node: '>=10'}
- get-tsconfig@4.8.1:
- dependencies:
- resolve-pkg-maps: 1.0.0
+ cheerio-select@2.1.0:
+ resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==}
- glob@7.2.3:
- dependencies:
- fs.realpath: 1.0.0
- inflight: 1.0.6
- inherits: 2.0.4
- minimatch: 3.1.2
- once: 1.4.0
- path-is-absolute: 1.0.1
+ cheerio@1.0.0:
+ resolution: {integrity: sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww==}
+ engines: {node: '>=18.17'}
- hasown@2.0.2:
- dependencies:
- function-bind: 1.1.2
+ ci-info@3.9.0:
+ resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==}
+ engines: {node: '>=8'}
- http-errors@2.0.0:
- dependencies:
- depd: 2.0.0
- inherits: 2.0.4
- setprototypeof: 1.2.0
- statuses: 2.0.1
- toidentifier: 1.0.1
+ cjs-module-lexer@1.4.1:
+ resolution: {integrity: sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==}
- iconv-lite@0.6.3:
- dependencies:
- safer-buffer: 2.1.2
+ cliui@8.0.1:
+ resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
+ engines: {node: '>=12'}
- inflight@1.0.6:
- dependencies:
- once: 1.4.0
- wrappy: 1.0.2
+ cluster-key-slot@1.1.2:
+ resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==}
+ engines: {node: '>=0.10.0'}
- inherits@2.0.4: {}
+ co@4.6.0:
+ resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==}
+ engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'}
- interpret@1.4.0: {}
+ collect-v8-coverage@1.0.2:
+ resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==}
- is-core-module@2.15.1:
- dependencies:
- hasown: 2.0.2
+ color-convert@2.0.1:
+ resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
+ engines: {node: '>=7.0.0'}
- minimatch@3.1.2:
- dependencies:
- brace-expansion: 1.1.11
+ color-name@1.1.4:
+ resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
- minimist@1.2.8: {}
+ combined-stream@1.0.8:
+ resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
+ engines: {node: '>= 0.8'}
- once@1.4.0:
- dependencies:
- wrappy: 1.0.2
+ concat-map@0.0.1:
+ resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
- path-is-absolute@1.0.1: {}
+ content-type@1.0.5:
+ resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
+ engines: {node: '>= 0.6'}
- path-parse@1.0.7: {}
+ convert-source-map@2.0.0:
+ resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
- playwright-core@1.49.0: {}
+ corser@2.0.1:
+ resolution: {integrity: sha512-utCYNzRSQIZNPIcGZdQc92UVJYAhtGAteCFg0yRaFm8f0P+CPtyGyHXJcGXnffjCybUCEx3FQ2G7U3/o9eIkVQ==}
+ engines: {node: '>= 0.4.0'}
- playwright@1.49.0:
- dependencies:
- playwright-core: 1.49.0
- optionalDependencies:
- fsevents: 2.3.2
+ create-jest@29.7.0:
+ resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ hasBin: true
- raw-body@3.0.0:
+ create-require@1.1.1:
+ resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==}
+
+ cross-spawn@7.0.6:
+ resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
+ engines: {node: '>= 8'}
+
+ css-select@5.1.0:
+ resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==}
+
+ css-what@6.1.0:
+ resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==}
+ engines: {node: '>= 6'}
+
+ cssstyle@4.2.1:
+ resolution: {integrity: sha512-9+vem03dMXG7gDmZ62uqmRiMRNtinIZ9ZyuF6BdxzfOD+FdN5hretzynkn0ReS2DO2GSw76RWHs0UmJPI2zUjw==}
+ engines: {node: '>=18'}
+
+ data-urls@5.0.0:
+ resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==}
+ engines: {node: '>=18'}
+
+ debug@3.2.7:
+ resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ debug@4.4.0:
+ resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ decimal.js@10.4.3:
+ resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==}
+
+ dedent@1.5.3:
+ resolution: {integrity: sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==}
+ peerDependencies:
+ babel-plugin-macros: ^3.1.0
+ peerDependenciesMeta:
+ babel-plugin-macros:
+ optional: true
+
+ deep-is@0.1.4:
+ resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
+
+ deepmerge@4.3.1:
+ resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
+ engines: {node: '>=0.10.0'}
+
+ delayed-stream@1.0.0:
+ resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
+ engines: {node: '>=0.4.0'}
+
+ depd@2.0.0:
+ resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
+ engines: {node: '>= 0.8'}
+
+ detect-newline@3.1.0:
+ resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==}
+ engines: {node: '>=8'}
+
+ diff-sequences@29.6.3:
+ resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ diff@4.0.2:
+ resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==}
+ engines: {node: '>=0.3.1'}
+
+ dir-glob@3.0.1:
+ resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
+ engines: {node: '>=8'}
+
+ doctrine@3.0.0:
+ resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
+ engines: {node: '>=6.0.0'}
+
+ dom-serializer@2.0.0:
+ resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
+
+ domelementtype@2.3.0:
+ resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
+
+ domhandler@5.0.3:
+ resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
+ engines: {node: '>= 4'}
+
+ domutils@3.2.2:
+ resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==}
+
+ dotenv@16.4.7:
+ resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==}
+ engines: {node: '>=12'}
+
+ dunder-proto@1.0.1:
+ resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
+ engines: {node: '>= 0.4'}
+
+ eastasianwidth@0.2.0:
+ resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
+
+ ejs@3.1.10:
+ resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==}
+ engines: {node: '>=0.10.0'}
+ hasBin: true
+
+ electron-to-chromium@1.5.80:
+ resolution: {integrity: sha512-LTrKpW0AqIuHwmlVNV+cjFYTnXtM9K37OGhpe0ZI10ScPSxqVSryZHIY3WnCS5NSYbBODRTZyhRMS2h5FAEqAw==}
+
+ emittery@0.13.1:
+ resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==}
+ engines: {node: '>=12'}
+
+ emoji-regex@8.0.0:
+ resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
+
+ emoji-regex@9.2.2:
+ resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
+
+ encoding-sniffer@0.2.0:
+ resolution: {integrity: sha512-ju7Wq1kg04I3HtiYIOrUrdfdDvkyO9s5XM8QAj/bN61Yo/Vb4vgJxy5vi4Yxk01gWHbrofpPtpxM8bKger9jhg==}
+
+ entities@4.5.0:
+ resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
+ engines: {node: '>=0.12'}
+
+ error-ex@1.3.2:
+ resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
+
+ es-define-property@1.0.1:
+ resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
+ engines: {node: '>= 0.4'}
+
+ es-errors@1.3.0:
+ resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
+ engines: {node: '>= 0.4'}
+
+ es-object-atoms@1.0.0:
+ resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==}
+ engines: {node: '>= 0.4'}
+
+ escalade@3.2.0:
+ resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
+ engines: {node: '>=6'}
+
+ escape-string-regexp@2.0.0:
+ resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==}
+ engines: {node: '>=8'}
+
+ escape-string-regexp@4.0.0:
+ resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
+ engines: {node: '>=10'}
+
+ eslint-scope@7.2.2:
+ resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
+ eslint-visitor-keys@3.4.3:
+ resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
+ eslint@8.57.1:
+ resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options.
+ hasBin: true
+
+ espree@9.6.1:
+ resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
+ esprima@4.0.1:
+ resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
+ engines: {node: '>=4'}
+ hasBin: true
+
+ esquery@1.6.0:
+ resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==}
+ engines: {node: '>=0.10'}
+
+ esrecurse@4.3.0:
+ resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
+ engines: {node: '>=4.0'}
+
+ estraverse@5.3.0:
+ resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
+ engines: {node: '>=4.0'}
+
+ esutils@2.0.3:
+ resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
+ engines: {node: '>=0.10.0'}
+
+ eventemitter3@4.0.7:
+ resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
+
+ execa@5.1.1:
+ resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
+ engines: {node: '>=10'}
+
+ exit@0.1.2:
+ resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==}
+ engines: {node: '>= 0.8.0'}
+
+ expect@29.7.0:
+ resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ fast-deep-equal@3.1.3:
+ resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
+
+ fast-glob@3.3.3:
+ resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==}
+ engines: {node: '>=8.6.0'}
+
+ fast-json-stable-stringify@2.1.0:
+ resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
+
+ fast-levenshtein@2.0.6:
+ resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
+
+ fastq@1.18.0:
+ resolution: {integrity: sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==}
+
+ fb-watchman@2.0.2:
+ resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==}
+
+ file-entry-cache@6.0.1:
+ resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
+ engines: {node: ^10.12.0 || >=12.0.0}
+
+ filelist@1.0.4:
+ resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==}
+
+ fill-range@7.1.1:
+ resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
+ engines: {node: '>=8'}
+
+ find-up@4.1.0:
+ resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
+ engines: {node: '>=8'}
+
+ find-up@5.0.0:
+ resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
+ engines: {node: '>=10'}
+
+ flat-cache@3.2.0:
+ resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==}
+ engines: {node: ^10.12.0 || >=12.0.0}
+
+ flatted@3.3.2:
+ resolution: {integrity: sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==}
+
+ follow-redirects@1.15.9:
+ resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==}
+ engines: {node: '>=4.0'}
+ peerDependencies:
+ debug: '*'
+ peerDependenciesMeta:
+ debug:
+ optional: true
+
+ foreground-child@3.3.0:
+ resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==}
+ engines: {node: '>=14'}
+
+ form-data@4.0.1:
+ resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==}
+ engines: {node: '>= 6'}
+
+ fs.realpath@1.0.0:
+ resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
+
+ fsevents@2.3.2:
+ resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+
+ fsevents@2.3.3:
+ resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+
+ function-bind@1.1.2:
+ resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
+
+ generic-pool@3.9.0:
+ resolution: {integrity: sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==}
+ engines: {node: '>= 4'}
+
+ gensync@1.0.0-beta.2:
+ resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
+ engines: {node: '>=6.9.0'}
+
+ get-caller-file@2.0.5:
+ resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
+ engines: {node: 6.* || 8.* || >= 10.*}
+
+ get-intrinsic@1.2.7:
+ resolution: {integrity: sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==}
+ engines: {node: '>= 0.4'}
+
+ get-package-type@0.1.0:
+ resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==}
+ engines: {node: '>=8.0.0'}
+
+ get-proto@1.0.1:
+ resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
+ engines: {node: '>= 0.4'}
+
+ get-stream@6.0.1:
+ resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
+ engines: {node: '>=10'}
+
+ glob-parent@5.1.2:
+ resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
+ engines: {node: '>= 6'}
+
+ glob-parent@6.0.2:
+ resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
+ engines: {node: '>=10.13.0'}
+
+ glob@10.4.5:
+ resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==}
+ hasBin: true
+
+ glob@7.2.3:
+ resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
+ deprecated: Glob versions prior to v9 are no longer supported
+
+ globals@11.12.0:
+ resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
+ engines: {node: '>=4'}
+
+ globals@13.24.0:
+ resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==}
+ engines: {node: '>=8'}
+
+ globby@11.1.0:
+ resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
+ engines: {node: '>=10'}
+
+ gopd@1.2.0:
+ resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
+ engines: {node: '>= 0.4'}
+
+ graceful-fs@4.2.11:
+ resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
+
+ graphemer@1.4.0:
+ resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
+
+ has-flag@4.0.0:
+ resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
+ engines: {node: '>=8'}
+
+ has-symbols@1.1.0:
+ resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
+ engines: {node: '>= 0.4'}
+
+ hasown@2.0.2:
+ resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
+ engines: {node: '>= 0.4'}
+
+ he@1.2.0:
+ resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
+ hasBin: true
+
+ html-encoding-sniffer@3.0.0:
+ resolution: {integrity: sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==}
+ engines: {node: '>=12'}
+
+ html-encoding-sniffer@4.0.0:
+ resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==}
+ engines: {node: '>=18'}
+
+ html-escaper@2.0.2:
+ resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
+
+ html-to-md@0.8.6:
+ resolution: {integrity: sha512-KaRoYxML9AIETfgz5tgI1ioCsT8+skHTIILzrDV66XwCxuWUVjwCcpbnfeUwT9r8VBrfDAa8B5p5b5Pcs9LtRg==}
+
+ htmlparser2@9.1.0:
+ resolution: {integrity: sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==}
+
+ htmlparser@1.7.7:
+ resolution: {integrity: sha512-zpK66ifkT0fauyFh2Mulrq4AqGTucxGtOhZ8OjkbSfcCpkqQEI8qRkY0tSQSJNAQ4HUZkgWaU4fK4EH6SVH9PQ==}
+ engines: {node: '>=0.1.33'}
+
+ http-errors@2.0.0:
+ resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
+ engines: {node: '>= 0.8'}
+
+ http-proxy-agent@7.0.2:
+ resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==}
+ engines: {node: '>= 14'}
+
+ http-proxy@1.18.1:
+ resolution: {integrity: sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==}
+ engines: {node: '>=8.0.0'}
+
+ http-server@14.1.1:
+ resolution: {integrity: sha512-+cbxadF40UXd9T01zUHgA+rlo2Bg1Srer4+B4NwIHdaGxAGGv59nYRnGGDJ9LBk7alpS0US+J+bLLdQOOkJq4A==}
+ engines: {node: '>=12'}
+ hasBin: true
+
+ https-proxy-agent@7.0.6:
+ resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==}
+ engines: {node: '>= 14'}
+
+ human-signals@2.1.0:
+ resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
+ engines: {node: '>=10.17.0'}
+
+ iconv-lite@0.6.3:
+ resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
+ engines: {node: '>=0.10.0'}
+
+ ignore@5.3.2:
+ resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
+ engines: {node: '>= 4'}
+
+ import-fresh@3.3.0:
+ resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
+ engines: {node: '>=6'}
+
+ import-local@3.2.0:
+ resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==}
+ engines: {node: '>=8'}
+ hasBin: true
+
+ imurmurhash@0.1.4:
+ resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
+ engines: {node: '>=0.8.19'}
+
+ inflight@1.0.6:
+ resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
+ deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
+
+ inherits@2.0.4:
+ resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
+
+ is-arrayish@0.2.1:
+ resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
+
+ is-core-module@2.15.1:
+ resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==}
+ engines: {node: '>= 0.4'}
+
+ is-extglob@2.1.1:
+ resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
+ engines: {node: '>=0.10.0'}
+
+ is-fullwidth-code-point@3.0.0:
+ resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
+ engines: {node: '>=8'}
+
+ is-generator-fn@2.1.0:
+ resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==}
+ engines: {node: '>=6'}
+
+ is-glob@4.0.3:
+ resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
+ engines: {node: '>=0.10.0'}
+
+ is-number@7.0.0:
+ resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
+ engines: {node: '>=0.12.0'}
+
+ is-path-inside@3.0.3:
+ resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
+ engines: {node: '>=8'}
+
+ is-potential-custom-element-name@1.0.1:
+ resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
+
+ is-stream@2.0.1:
+ resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
+ engines: {node: '>=8'}
+
+ isexe@2.0.0:
+ resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+
+ istanbul-lib-coverage@3.2.2:
+ resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==}
+ engines: {node: '>=8'}
+
+ istanbul-lib-instrument@5.2.1:
+ resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==}
+ engines: {node: '>=8'}
+
+ istanbul-lib-instrument@6.0.3:
+ resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==}
+ engines: {node: '>=10'}
+
+ istanbul-lib-report@3.0.1:
+ resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==}
+ engines: {node: '>=10'}
+
+ istanbul-lib-source-maps@4.0.1:
+ resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==}
+ engines: {node: '>=10'}
+
+ istanbul-reports@3.1.7:
+ resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==}
+ engines: {node: '>=8'}
+
+ jackspeak@3.4.3:
+ resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
+
+ jake@10.9.2:
+ resolution: {integrity: sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==}
+ engines: {node: '>=10'}
+ hasBin: true
+
+ jest-changed-files@29.7.0:
+ resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-circus@29.7.0:
+ resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-cli@29.7.0:
+ resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ hasBin: true
+ peerDependencies:
+ node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
+ peerDependenciesMeta:
+ node-notifier:
+ optional: true
+
+ jest-config@29.7.0:
+ resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ peerDependencies:
+ '@types/node': '*'
+ ts-node: '>=9.0.0'
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+ ts-node:
+ optional: true
+
+ jest-diff@29.7.0:
+ resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-docblock@29.7.0:
+ resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-each@29.7.0:
+ resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-environment-node@29.7.0:
+ resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-get-type@29.6.3:
+ resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-haste-map@29.7.0:
+ resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-leak-detector@29.7.0:
+ resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-matcher-utils@29.7.0:
+ resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-message-util@29.7.0:
+ resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-mock@29.7.0:
+ resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-pnp-resolver@1.2.3:
+ resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==}
+ engines: {node: '>=6'}
+ peerDependencies:
+ jest-resolve: '*'
+ peerDependenciesMeta:
+ jest-resolve:
+ optional: true
+
+ jest-regex-util@29.6.3:
+ resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-resolve-dependencies@29.7.0:
+ resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-resolve@29.7.0:
+ resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-runner@29.7.0:
+ resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-runtime@29.7.0:
+ resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-snapshot@29.7.0:
+ resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-util@29.7.0:
+ resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-validate@29.7.0:
+ resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-watcher@29.7.0:
+ resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest-worker@29.7.0:
+ resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ jest@29.7.0:
+ resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ hasBin: true
+ peerDependencies:
+ node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
+ peerDependenciesMeta:
+ node-notifier:
+ optional: true
+
+ js-tokens@4.0.0:
+ resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+
+ js-yaml@3.14.1:
+ resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}
+ hasBin: true
+
+ js-yaml@4.1.0:
+ resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
+ hasBin: true
+
+ jsdom@26.0.0:
+ resolution: {integrity: sha512-BZYDGVAIriBWTpIxYzrXjv3E/4u8+/pSG5bQdIYCbNCGOvsPkDQfTVLAIXAf9ETdCpduCVTkDe2NNZ8NIwUVzw==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ canvas: ^3.0.0
+ peerDependenciesMeta:
+ canvas:
+ optional: true
+
+ jsesc@3.1.0:
+ resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
+ engines: {node: '>=6'}
+ hasBin: true
+
+ json-buffer@3.0.1:
+ resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
+
+ json-parse-even-better-errors@2.3.1:
+ resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
+
+ json-schema-traverse@0.4.1:
+ resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
+
+ json-stable-stringify-without-jsonify@1.0.1:
+ resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
+
+ json5@2.2.3:
+ resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
+ engines: {node: '>=6'}
+ hasBin: true
+
+ kareem@2.6.3:
+ resolution: {integrity: sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==}
+ engines: {node: '>=12.0.0'}
+
+ keyv@4.5.4:
+ resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
+
+ kleur@3.0.3:
+ resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
+ engines: {node: '>=6'}
+
+ leven@3.1.0:
+ resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==}
+ engines: {node: '>=6'}
+
+ levn@0.4.1:
+ resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
+ engines: {node: '>= 0.8.0'}
+
+ lines-and-columns@1.2.4:
+ resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
+
+ locate-path@5.0.0:
+ resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
+ engines: {node: '>=8'}
+
+ locate-path@6.0.0:
+ resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
+ engines: {node: '>=10'}
+
+ lodash.memoize@4.1.2:
+ resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==}
+
+ lodash.merge@4.6.2:
+ resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
+
+ lodash@4.17.21:
+ resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
+
+ lru-cache@10.4.3:
+ resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
+
+ lru-cache@11.0.2:
+ resolution: {integrity: sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA==}
+ engines: {node: 20 || >=22}
+
+ lru-cache@5.1.1:
+ resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+
+ make-dir@4.0.0:
+ resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
+ engines: {node: '>=10'}
+
+ make-error@1.3.6:
+ resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==}
+
+ makeerror@1.0.12:
+ resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==}
+
+ math-intrinsics@1.1.0:
+ resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
+ engines: {node: '>= 0.4'}
+
+ memjs@1.3.2:
+ resolution: {integrity: sha512-qUEg2g8vxPe+zPn09KidjIStHPtoBO8Cttm8bgJFWWabbsjQ9Av9Ky+6UcvKx6ue0LLb/LEhtcyQpRyKfzeXcg==}
+ engines: {node: '>=0.10.0'}
+
+ memory-pager@1.5.0:
+ resolution: {integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==}
+
+ merge-stream@2.0.0:
+ resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
+
+ merge2@1.4.1:
+ resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
+ engines: {node: '>= 8'}
+
+ micromatch@4.0.8:
+ resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
+ engines: {node: '>=8.6'}
+
+ mime-db@1.52.0:
+ resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
+ engines: {node: '>= 0.6'}
+
+ mime-types@2.1.35:
+ resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
+ engines: {node: '>= 0.6'}
+
+ mime@1.6.0:
+ resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==}
+ engines: {node: '>=4'}
+ hasBin: true
+
+ mimic-fn@2.1.0:
+ resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
+ engines: {node: '>=6'}
+
+ minimatch@3.1.2:
+ resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
+
+ minimatch@5.1.6:
+ resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==}
+ engines: {node: '>=10'}
+
+ minimatch@9.0.3:
+ resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==}
+ engines: {node: '>=16 || 14 >=14.17'}
+
+ minimatch@9.0.5:
+ resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
+ engines: {node: '>=16 || 14 >=14.17'}
+
+ minimist@1.2.8:
+ resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
+
+ minipass@7.1.2:
+ resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
+ engines: {node: '>=16 || 14 >=14.17'}
+
+ mjsunit.runner@0.1.3:
+ resolution: {integrity: sha512-m0LYKN/kv+Yx1TwYGneCsztgPp5zTa5Erx0KuF20opXjeEO+5xOCjwoaq+qx69/tte3DaFD6atgcf/JFW0l8Pw==}
+ engines: {node: '>=0.1.9'}
+
+ mkdirp@0.5.6:
+ resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
+ hasBin: true
+
+ mongodb-connection-string-url@3.0.1:
+ resolution: {integrity: sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg==}
+
+ mongodb@6.12.0:
+ resolution: {integrity: sha512-RM7AHlvYfS7jv7+BXund/kR64DryVI+cHbVAy9P61fnb1RcWZqOW1/Wj2YhqMCx+MuYhqTRGv7AwHBzmsCKBfA==}
+ engines: {node: '>=16.20.1'}
+ peerDependencies:
+ '@aws-sdk/credential-providers': ^3.188.0
+ '@mongodb-js/zstd': ^1.1.0 || ^2.0.0
+ gcp-metadata: ^5.2.0
+ kerberos: ^2.0.1
+ mongodb-client-encryption: '>=6.0.0 <7'
+ snappy: ^7.2.2
+ socks: ^2.7.1
+ peerDependenciesMeta:
+ '@aws-sdk/credential-providers':
+ optional: true
+ '@mongodb-js/zstd':
+ optional: true
+ gcp-metadata:
+ optional: true
+ kerberos:
+ optional: true
+ mongodb-client-encryption:
+ optional: true
+ snappy:
+ optional: true
+ socks:
+ optional: true
+
+ mongoose@8.9.4:
+ resolution: {integrity: sha512-DndoI01aV/q40P9DiYDXsYjhj8vZjmmuFwcC3Tro5wFznoE1z6Fe2JgMnbLR6ghglym5ziYizSfAJykp+UPZWg==}
+ engines: {node: '>=16.20.1'}
+
+ mpath@0.9.0:
+ resolution: {integrity: sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==}
+ engines: {node: '>=4.0.0'}
+
+ mquery@5.0.0:
+ resolution: {integrity: sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==}
+ engines: {node: '>=14.0.0'}
+
+ ms@2.1.3:
+ resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+
+ natural-compare@1.4.0:
+ resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
+
+ natural@8.0.1:
+ resolution: {integrity: sha512-VVw8O5KrfvwqAFeNZEgBbdgA+AQaBlHcXEootWU7TWDaFWFI0VLfzyKMsRjnfdS3cVCpWmI04xLJonCvEv11VQ==}
+ engines: {node: '>=0.4.10'}
+
+ node-int64@0.4.0:
+ resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==}
+
+ node-releases@2.0.19:
+ resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==}
+
+ normalize-path@3.0.0:
+ resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
+ engines: {node: '>=0.10.0'}
+
+ npm-run-path@4.0.1:
+ resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
+ engines: {node: '>=8'}
+
+ nth-check@2.1.1:
+ resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
+
+ nwsapi@2.2.16:
+ resolution: {integrity: sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==}
+
+ object-inspect@1.13.3:
+ resolution: {integrity: sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==}
+ engines: {node: '>= 0.4'}
+
+ once@1.4.0:
+ resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
+
+ onetime@5.1.2:
+ resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
+ engines: {node: '>=6'}
+
+ opener@1.5.2:
+ resolution: {integrity: sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==}
+ hasBin: true
+
+ optionator@0.9.4:
+ resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
+ engines: {node: '>= 0.8.0'}
+
+ p-limit@2.3.0:
+ resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
+ engines: {node: '>=6'}
+
+ p-limit@3.1.0:
+ resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
+ engines: {node: '>=10'}
+
+ p-locate@4.1.0:
+ resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
+ engines: {node: '>=8'}
+
+ p-locate@5.0.0:
+ resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
+ engines: {node: '>=10'}
+
+ p-try@2.2.0:
+ resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
+ engines: {node: '>=6'}
+
+ package-json-from-dist@1.0.1:
+ resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
+
+ parent-module@1.0.1:
+ resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
+ engines: {node: '>=6'}
+
+ parse-json@5.2.0:
+ resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
+ engines: {node: '>=8'}
+
+ parse5-htmlparser2-tree-adapter@7.1.0:
+ resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==}
+
+ parse5-parser-stream@7.1.2:
+ resolution: {integrity: sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==}
+
+ parse5@7.2.1:
+ resolution: {integrity: sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==}
+
+ path-exists@4.0.0:
+ resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
+ engines: {node: '>=8'}
+
+ path-is-absolute@1.0.1:
+ resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
+ engines: {node: '>=0.10.0'}
+
+ path-key@3.1.1:
+ resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
+ engines: {node: '>=8'}
+
+ path-parse@1.0.7:
+ resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
+
+ path-scurry@1.11.1:
+ resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
+ engines: {node: '>=16 || 14 >=14.18'}
+
+ path-type@4.0.0:
+ resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
+ engines: {node: '>=8'}
+
+ pg-cloudflare@1.1.1:
+ resolution: {integrity: sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==}
+
+ pg-connection-string@2.7.0:
+ resolution: {integrity: sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA==}
+
+ pg-int8@1.0.1:
+ resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==}
+ engines: {node: '>=4.0.0'}
+
+ pg-pool@3.7.0:
+ resolution: {integrity: sha512-ZOBQForurqh4zZWjrgSwwAtzJ7QiRX0ovFkZr2klsen3Nm0aoh33Ls0fzfv3imeH/nw/O27cjdz5kzYJfeGp/g==}
+ peerDependencies:
+ pg: '>=8.0'
+
+ pg-protocol@1.7.0:
+ resolution: {integrity: sha512-hTK/mE36i8fDDhgDFjy6xNOG+LCorxLG3WO17tku+ij6sVHXh1jQUJ8hYAnRhNla4QVD2H8er/FOjc/+EgC6yQ==}
+
+ pg-types@2.2.0:
+ resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==}
+ engines: {node: '>=4'}
+
+ pg@8.13.1:
+ resolution: {integrity: sha512-OUir1A0rPNZlX//c7ksiu7crsGZTKSOXJPgtNiHGIlC9H0lO+NC6ZDYksSgBYY/thSWhnSRBv8w1lieNNGATNQ==}
+ engines: {node: '>= 8.0.0'}
+ peerDependencies:
+ pg-native: '>=3.0.1'
+ peerDependenciesMeta:
+ pg-native:
+ optional: true
+
+ pgpass@1.0.5:
+ resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==}
+
+ picocolors@1.1.1:
+ resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
+
+ picomatch@2.3.1:
+ resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
+ engines: {node: '>=8.6'}
+
+ pirates@4.0.6:
+ resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==}
+ engines: {node: '>= 6'}
+
+ pkg-dir@4.2.0:
+ resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==}
+ engines: {node: '>=8'}
+
+ playwright-core@1.49.0:
+ resolution: {integrity: sha512-R+3KKTQF3npy5GTiKH/T+kdhoJfJojjHESR1YEWhYuEKRVfVaxH3+4+GvXE5xyCngCxhxnykk0Vlah9v8fs3jA==}
+ engines: {node: '>=18'}
+ hasBin: true
+
+ playwright@1.49.0:
+ resolution: {integrity: sha512-eKpmys0UFDnfNb3vfsf8Vx2LEOtflgRebl0Im2eQQnYMA4Aqd+Zw8bEOB+7ZKvN76901mRnqdsiOGKxzVTbi7A==}
+ engines: {node: '>=18'}
+ hasBin: true
+
+ portfinder@1.0.32:
+ resolution: {integrity: sha512-on2ZJVVDXRADWE6jnQaX0ioEylzgBpQk8r55NE4wjXW1ZxO+BgDlY6DXwj20i0V8eB4SenDQ00WEaxfiIQPcxg==}
+ engines: {node: '>= 0.12.0'}
+
+ postgres-array@2.0.0:
+ resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==}
+ engines: {node: '>=4'}
+
+ postgres-bytea@1.0.0:
+ resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==}
+ engines: {node: '>=0.10.0'}
+
+ postgres-date@1.0.7:
+ resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==}
+ engines: {node: '>=0.10.0'}
+
+ postgres-interval@1.2.0:
+ resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==}
+ engines: {node: '>=0.10.0'}
+
+ prelude-ls@1.2.1:
+ resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
+ engines: {node: '>= 0.8.0'}
+
+ pretty-format@29.7.0:
+ resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+
+ prompts@2.4.2:
+ resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==}
+ engines: {node: '>= 6'}
+
+ punycode@2.3.1:
+ resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
+ engines: {node: '>=6'}
+
+ pure-rand@6.1.0:
+ resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==}
+
+ qs@6.13.1:
+ resolution: {integrity: sha512-EJPeIn0CYrGu+hli1xilKAPXODtJ12T0sP63Ijx2/khC2JtuaN3JyNIpvmnkmaEtha9ocbG4A4cMcr+TvqvwQg==}
+ engines: {node: '>=0.6'}
+
+ queue-microtask@1.2.3:
+ resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
+
+ rate-limiter-flexible@5.0.4:
+ resolution: {integrity: sha512-ftYHrIfSqWYDIJZ4yPTrgOduByAp+86gUS9iklv0JoXVM8eQCAjTnydCj1hAT4MmhmkSw86NaFEJ28m/LC1pKA==}
+
+ raw-body@3.0.0:
+ resolution: {integrity: sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==}
+ engines: {node: '>= 0.8'}
+
+ react-is@18.3.1:
+ resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==}
+
+ readability@0.1.0:
+ resolution: {integrity: sha512-rt7d3Us0ev/VNBfsSdNHjWn1xibcfkvpQ/Ahtt87s9nzcIri5L4b6r3oxqBjKh1BhTwJcGk6kUd0Y6Q5jl+20Q==}
+ engines: {node: '>=0.3.1'}
+
+ redis@4.7.0:
+ resolution: {integrity: sha512-zvmkHEAdGMn+hMRXuMBtu4Vo5P6rHQjLoHftu+lBqq8ZTA3RCVC/WzD790bkKKiNFp7d5/9PcSD19fJyyRvOdQ==}
+
+ require-directory@2.1.1:
+ resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
+ engines: {node: '>=0.10.0'}
+
+ requires-port@1.0.0:
+ resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
+
+ resolve-cwd@3.0.0:
+ resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==}
+ engines: {node: '>=8'}
+
+ resolve-from@4.0.0:
+ resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
+ engines: {node: '>=4'}
+
+ resolve-from@5.0.0:
+ resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==}
+ engines: {node: '>=8'}
+
+ resolve.exports@2.0.3:
+ resolution: {integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==}
+ engines: {node: '>=10'}
+
+ resolve@1.22.8:
+ resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==}
+ hasBin: true
+
+ reusify@1.0.4:
+ resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
+ engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
+
+ rimraf@3.0.2:
+ resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
+ deprecated: Rimraf versions prior to v4 are no longer supported
+ hasBin: true
+
+ rimraf@5.0.10:
+ resolution: {integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==}
+ hasBin: true
+
+ rrweb-cssom@0.8.0:
+ resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==}
+
+ run-parallel@1.2.0:
+ resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
+
+ safe-buffer@5.1.2:
+ resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
+
+ safe-stable-stringify@2.5.0:
+ resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==}
+ engines: {node: '>=10'}
+
+ safer-buffer@2.1.2:
+ resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
+
+ saxes@6.0.0:
+ resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==}
+ engines: {node: '>=v12.22.7'}
+
+ secure-compare@3.0.1:
+ resolution: {integrity: sha512-AckIIV90rPDcBcglUwXPF3kg0P0qmPsPXAj6BBEENQE1p5yA1xfmDJzfi1Tappj37Pv2mVbKpL3Z1T+Nn7k1Qw==}
+
+ semver@6.3.1:
+ resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
+ hasBin: true
+
+ semver@7.6.3:
+ resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==}
+ engines: {node: '>=10'}
+ hasBin: true
+
+ setprototypeof@1.2.0:
+ resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
+
+ shebang-command@2.0.0:
+ resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
+ engines: {node: '>=8'}
+
+ shebang-regex@3.0.0:
+ resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
+ engines: {node: '>=8'}
+
+ side-channel-list@1.0.0:
+ resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==}
+ engines: {node: '>= 0.4'}
+
+ side-channel-map@1.0.1:
+ resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==}
+ engines: {node: '>= 0.4'}
+
+ side-channel-weakmap@1.0.2:
+ resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==}
+ engines: {node: '>= 0.4'}
+
+ side-channel@1.1.0:
+ resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
+ engines: {node: '>= 0.4'}
+
+ sift@17.1.3:
+ resolution: {integrity: sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==}
+
+ signal-exit@3.0.7:
+ resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
+
+ signal-exit@4.1.0:
+ resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
+ engines: {node: '>=14'}
+
+ sisteransi@1.0.5:
+ resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
+
+ slash@3.0.0:
+ resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
+ engines: {node: '>=8'}
+
+ source-map-support@0.5.13:
+ resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==}
+
+ source-map@0.6.1:
+ resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
+ engines: {node: '>=0.10.0'}
+
+ sparse-bitfield@3.0.3:
+ resolution: {integrity: sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==}
+
+ split2@4.2.0:
+ resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
+ engines: {node: '>= 10.x'}
+
+ sprintf-js@1.0.3:
+ resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
+
+ stack-utils@2.0.6:
+ resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==}
+ engines: {node: '>=10'}
+
+ statuses@2.0.1:
+ resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==}
+ engines: {node: '>= 0.8'}
+
+ stopwords-iso@1.1.0:
+ resolution: {integrity: sha512-I6GPS/E0zyieHehMRPQcqkiBMJKGgLta+1hREixhoLPqEA0AlVFiC43dl8uPpmkkeRdDMzYRWFWk5/l9x7nmNg==}
+ engines: {node: '>=0.10.0'}
+
+ string-length@4.0.2:
+ resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==}
+ engines: {node: '>=10'}
+
+ string-width@4.2.3:
+ resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
+ engines: {node: '>=8'}
+
+ string-width@5.1.2:
+ resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
+ engines: {node: '>=12'}
+
+ strip-ansi@6.0.1:
+ resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
+ engines: {node: '>=8'}
+
+ strip-ansi@7.1.0:
+ resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
+ engines: {node: '>=12'}
+
+ strip-bom@4.0.0:
+ resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==}
+ engines: {node: '>=8'}
+
+ strip-final-newline@2.0.0:
+ resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
+ engines: {node: '>=6'}
+
+ strip-json-comments@3.1.1:
+ resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
+ engines: {node: '>=8'}
+
+ supports-color@7.2.0:
+ resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
+ engines: {node: '>=8'}
+
+ supports-color@8.1.1:
+ resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==}
+ engines: {node: '>=10'}
+
+ supports-preserve-symlinks-flag@1.0.0:
+ resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
+ engines: {node: '>= 0.4'}
+
+ sylvester@0.0.12:
+ resolution: {integrity: sha512-SzRP5LQ6Ts2G5NyAa/jg16s8e3R7rfdFjizy1zeoecYWw+nGL+YA1xZvW/+iJmidBGSdLkuvdwTYEyJEb+EiUw==}
+ engines: {node: '>=0.2.6'}
+
+ symbol-tree@3.2.4:
+ resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
+
+ test-exclude@6.0.0:
+ resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==}
+ engines: {node: '>=8'}
+
+ text-table@0.2.0:
+ resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
+
+ tldts-core@6.1.71:
+ resolution: {integrity: sha512-LRbChn2YRpic1KxY+ldL1pGXN/oVvKfCVufwfVzEQdFYNo39uF7AJa/WXdo+gYO7PTvdfkCPCed6Hkvz/kR7jg==}
+
+ tldts@6.1.71:
+ resolution: {integrity: sha512-LQIHmHnuzfZgZWAf2HzL83TIIrD8NhhI0DVxqo9/FdOd4ilec+NTNZOlDZf7EwrTNoutccbsHjvWHYXLAtvxjw==}
+ hasBin: true
+
+ tmpl@1.0.5:
+ resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==}
+
+ to-regex-range@5.0.1:
+ resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
+ engines: {node: '>=8.0'}
+
+ toidentifier@1.0.1:
+ resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
+ engines: {node: '>=0.6'}
+
+ tough-cookie@5.1.0:
+ resolution: {integrity: sha512-rvZUv+7MoBYTiDmFPBrhL7Ujx9Sk+q9wwm22x8c8T5IJaR+Wsyc7TNxbVxo84kZoRJZZMazowFLqpankBEQrGg==}
+ engines: {node: '>=16'}
+
+ tr46@4.1.1:
+ resolution: {integrity: sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==}
+ engines: {node: '>=14'}
+
+ tr46@5.0.0:
+ resolution: {integrity: sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==}
+ engines: {node: '>=18'}
+
+ ts-api-utils@1.4.3:
+ resolution: {integrity: sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==}
+ engines: {node: '>=16'}
+ peerDependencies:
+ typescript: '>=4.2.0'
+
+ ts-jest@29.2.5:
+ resolution: {integrity: sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA==}
+ engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0}
+ hasBin: true
+ peerDependencies:
+ '@babel/core': '>=7.0.0-beta.0 <8'
+ '@jest/transform': ^29.0.0
+ '@jest/types': ^29.0.0
+ babel-jest: ^29.0.0
+ esbuild: '*'
+ jest: ^29.0.0
+ typescript: '>=4.3 <6'
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ '@jest/transform':
+ optional: true
+ '@jest/types':
+ optional: true
+ babel-jest:
+ optional: true
+ esbuild:
+ optional: true
+
+ ts-node@10.9.2:
+ resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==}
+ hasBin: true
+ peerDependencies:
+ '@swc/core': '>=1.2.50'
+ '@swc/wasm': '>=1.2.50'
+ '@types/node': '*'
+ typescript: '>=2.7'
+ peerDependenciesMeta:
+ '@swc/core':
+ optional: true
+ '@swc/wasm':
+ optional: true
+
+ turndown@7.2.0:
+ resolution: {integrity: sha512-eCZGBN4nNNqM9Owkv9HAtWRYfLA4h909E/WGAWWBpmB275ehNhZyk87/Tpvjbp0jjNl9XwCsbe6bm6CqFsgD+A==}
+
+ type-check@0.4.0:
+ resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
+ engines: {node: '>= 0.8.0'}
+
+ type-detect@4.0.8:
+ resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==}
+ engines: {node: '>=4'}
+
+ type-fest@0.20.2:
+ resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
+ engines: {node: '>=10'}
+
+ type-fest@0.21.3:
+ resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==}
+ engines: {node: '>=10'}
+
+ typescript@5.7.2:
+ resolution: {integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==}
+ engines: {node: '>=14.17'}
+ hasBin: true
+
+ underscore@1.13.7:
+ resolution: {integrity: sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==}
+
+ undici-types@6.19.8:
+ resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==}
+
+ undici@6.21.0:
+ resolution: {integrity: sha512-BUgJXc752Kou3oOIuU1i+yZZypyZRqNPW0vqoMPl8VaoalSfeR0D8/t4iAS3yirs79SSMTxTag+ZC86uswv+Cw==}
+ engines: {node: '>=18.17'}
+
+ union@0.5.0:
+ resolution: {integrity: sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==}
+ engines: {node: '>= 0.8.0'}
+
+ unpipe@1.0.0:
+ resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
+ engines: {node: '>= 0.8'}
+
+ update-browserslist-db@1.1.2:
+ resolution: {integrity: sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==}
+ hasBin: true
+ peerDependencies:
+ browserslist: '>= 4.21.0'
+
+ uri-js@4.4.1:
+ resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
+
+ url-join@4.0.1:
+ resolution: {integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==}
+
+ uuid@9.0.1:
+ resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==}
+ hasBin: true
+
+ v8-compile-cache-lib@3.0.1:
+ resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==}
+
+ v8-to-istanbul@9.3.0:
+ resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==}
+ engines: {node: '>=10.12.0'}
+
+ w3c-xmlserializer@5.0.0:
+ resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==}
+ engines: {node: '>=18'}
+
+ walker@1.0.8:
+ resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==}
+
+ webidl-conversions@7.0.0:
+ resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
+ engines: {node: '>=12'}
+
+ whatwg-encoding@2.0.0:
+ resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==}
+ engines: {node: '>=12'}
+
+ whatwg-encoding@3.1.1:
+ resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==}
+ engines: {node: '>=18'}
+
+ whatwg-mimetype@4.0.0:
+ resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==}
+ engines: {node: '>=18'}
+
+ whatwg-url@13.0.0:
+ resolution: {integrity: sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==}
+ engines: {node: '>=16'}
+
+ whatwg-url@14.1.0:
+ resolution: {integrity: sha512-jlf/foYIKywAt3x/XWKZ/3rz8OSJPiWktjmk891alJUEjiVxKX9LEO92qH3hv4aJ0mN3MWPvGMCy8jQi95xK4w==}
+ engines: {node: '>=18'}
+
+ which@2.0.2:
+ resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
+ engines: {node: '>= 8'}
+ hasBin: true
+
+ word-wrap@1.2.5:
+ resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
+ engines: {node: '>=0.10.0'}
+
+ wordnet-db@3.1.14:
+ resolution: {integrity: sha512-zVyFsvE+mq9MCmwXUWHIcpfbrHHClZWZiVOzKSxNJruIcFn2RbY55zkhiAMMxM8zCVSmtNiViq8FsAZSFpMYag==}
+ engines: {node: '>=0.6.0'}
+
+ wrap-ansi@7.0.0:
+ resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
+ engines: {node: '>=10'}
+
+ wrap-ansi@8.1.0:
+ resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
+ engines: {node: '>=12'}
+
+ wrappy@1.0.2:
+ resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
+
+ write-file-atomic@4.0.2:
+ resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==}
+ engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
+
+ ws@8.18.0:
+ resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==}
+ engines: {node: '>=10.0.0'}
+ peerDependencies:
+ bufferutil: ^4.0.1
+ utf-8-validate: '>=5.0.2'
+ peerDependenciesMeta:
+ bufferutil:
+ optional: true
+ utf-8-validate:
+ optional: true
+
+ xml-name-validator@5.0.0:
+ resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==}
+ engines: {node: '>=18'}
+
+ xmlchars@2.2.0:
+ resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
+
+ xtend@4.0.2:
+ resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
+ engines: {node: '>=0.4'}
+
+ y18n@5.0.8:
+ resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
+ engines: {node: '>=10'}
+
+ yallist@3.1.1:
+ resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
+
+ yallist@4.0.0:
+ resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
+
+ yargs-parser@21.1.1:
+ resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
+ engines: {node: '>=12'}
+
+ yargs@17.7.2:
+ resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
+ engines: {node: '>=12'}
+
+ yn@3.1.1:
+ resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==}
+ engines: {node: '>=6'}
+
+ yocto-queue@0.1.0:
+ resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
+ engines: {node: '>=10'}
+
+ zod@3.23.8:
+ resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==}
+
+snapshots:
+
+ '@ampproject/remapping@2.3.0':
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.8
+ '@jridgewell/trace-mapping': 0.3.25
+
+ '@asamuzakjp/css-color@2.8.2':
+ dependencies:
+ '@csstools/css-calc': 2.1.1(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3)
+ '@csstools/css-color-parser': 3.0.7(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3)
+ '@csstools/css-parser-algorithms': 3.0.4(@csstools/css-tokenizer@3.0.3)
+ '@csstools/css-tokenizer': 3.0.3
+ lru-cache: 11.0.2
+
+ '@babel/code-frame@7.26.2':
+ dependencies:
+ '@babel/helper-validator-identifier': 7.25.9
+ js-tokens: 4.0.0
+ picocolors: 1.1.1
+
+ '@babel/compat-data@7.26.5': {}
+
+ '@babel/core@7.26.0':
+ dependencies:
+ '@ampproject/remapping': 2.3.0
+ '@babel/code-frame': 7.26.2
+ '@babel/generator': 7.26.5
+ '@babel/helper-compilation-targets': 7.26.5
+ '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0)
+ '@babel/helpers': 7.26.0
+ '@babel/parser': 7.26.5
+ '@babel/template': 7.25.9
+ '@babel/traverse': 7.26.5
+ '@babel/types': 7.26.5
+ convert-source-map: 2.0.0
+ debug: 4.4.0
+ gensync: 1.0.0-beta.2
+ json5: 2.2.3
+ semver: 6.3.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/generator@7.26.5':
+ dependencies:
+ '@babel/parser': 7.26.5
+ '@babel/types': 7.26.5
+ '@jridgewell/gen-mapping': 0.3.8
+ '@jridgewell/trace-mapping': 0.3.25
+ jsesc: 3.1.0
+
+ '@babel/helper-compilation-targets@7.26.5':
+ dependencies:
+ '@babel/compat-data': 7.26.5
+ '@babel/helper-validator-option': 7.25.9
+ browserslist: 4.24.4
+ lru-cache: 5.1.1
+ semver: 6.3.1
+
+ '@babel/helper-module-imports@7.25.9':
+ dependencies:
+ '@babel/traverse': 7.26.5
+ '@babel/types': 7.26.5
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.0)':
+ dependencies:
+ '@babel/core': 7.26.0
+ '@babel/helper-module-imports': 7.25.9
+ '@babel/helper-validator-identifier': 7.25.9
+ '@babel/traverse': 7.26.5
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/helper-plugin-utils@7.26.5': {}
+
+ '@babel/helper-string-parser@7.25.9': {}
+
+ '@babel/helper-validator-identifier@7.25.9': {}
+
+ '@babel/helper-validator-option@7.25.9': {}
+
+ '@babel/helpers@7.26.0':
+ dependencies:
+ '@babel/template': 7.25.9
+ '@babel/types': 7.26.5
+
+ '@babel/parser@7.26.5':
+ dependencies:
+ '@babel/types': 7.26.5
+
+ '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.26.0)':
+ dependencies:
+ '@babel/core': 7.26.0
+ '@babel/helper-plugin-utils': 7.26.5
+
+ '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.26.0)':
+ dependencies:
+ '@babel/core': 7.26.0
+ '@babel/helper-plugin-utils': 7.26.5
+
+ '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.26.0)':
+ dependencies:
+ '@babel/core': 7.26.0
+ '@babel/helper-plugin-utils': 7.26.5
+
+ '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.26.0)':
+ dependencies:
+ '@babel/core': 7.26.0
+ '@babel/helper-plugin-utils': 7.26.5
+
+ '@babel/plugin-syntax-import-attributes@7.26.0(@babel/core@7.26.0)':
+ dependencies:
+ '@babel/core': 7.26.0
+ '@babel/helper-plugin-utils': 7.26.5
+
+ '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.26.0)':
+ dependencies:
+ '@babel/core': 7.26.0
+ '@babel/helper-plugin-utils': 7.26.5
+
+ '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.26.0)':
+ dependencies:
+ '@babel/core': 7.26.0
+ '@babel/helper-plugin-utils': 7.26.5
+
+ '@babel/plugin-syntax-jsx@7.25.9(@babel/core@7.26.0)':
+ dependencies:
+ '@babel/core': 7.26.0
+ '@babel/helper-plugin-utils': 7.26.5
+
+ '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.26.0)':
+ dependencies:
+ '@babel/core': 7.26.0
+ '@babel/helper-plugin-utils': 7.26.5
+
+ '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.26.0)':
+ dependencies:
+ '@babel/core': 7.26.0
+ '@babel/helper-plugin-utils': 7.26.5
+
+ '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.26.0)':
+ dependencies:
+ '@babel/core': 7.26.0
+ '@babel/helper-plugin-utils': 7.26.5
+
+ '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.26.0)':
+ dependencies:
+ '@babel/core': 7.26.0
+ '@babel/helper-plugin-utils': 7.26.5
+
+ '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.26.0)':
+ dependencies:
+ '@babel/core': 7.26.0
+ '@babel/helper-plugin-utils': 7.26.5
+
+ '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.26.0)':
+ dependencies:
+ '@babel/core': 7.26.0
+ '@babel/helper-plugin-utils': 7.26.5
+
+ '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.26.0)':
+ dependencies:
+ '@babel/core': 7.26.0
+ '@babel/helper-plugin-utils': 7.26.5
+
+ '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.26.0)':
+ dependencies:
+ '@babel/core': 7.26.0
+ '@babel/helper-plugin-utils': 7.26.5
+
+ '@babel/plugin-syntax-typescript@7.25.9(@babel/core@7.26.0)':
+ dependencies:
+ '@babel/core': 7.26.0
+ '@babel/helper-plugin-utils': 7.26.5
+
+ '@babel/template@7.25.9':
+ dependencies:
+ '@babel/code-frame': 7.26.2
+ '@babel/parser': 7.26.5
+ '@babel/types': 7.26.5
+
+ '@babel/traverse@7.26.5':
+ dependencies:
+ '@babel/code-frame': 7.26.2
+ '@babel/generator': 7.26.5
+ '@babel/parser': 7.26.5
+ '@babel/template': 7.25.9
+ '@babel/types': 7.26.5
+ debug: 4.4.0
+ globals: 11.12.0
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/types@7.26.5':
+ dependencies:
+ '@babel/helper-string-parser': 7.25.9
+ '@babel/helper-validator-identifier': 7.25.9
+
+ '@bcoe/v8-coverage@0.2.3': {}
+
+ '@cspotcode/source-map-support@0.8.1':
+ dependencies:
+ '@jridgewell/trace-mapping': 0.3.9
+
+ '@csstools/color-helpers@5.0.1': {}
+
+ '@csstools/css-calc@2.1.1(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3)':
+ dependencies:
+ '@csstools/css-parser-algorithms': 3.0.4(@csstools/css-tokenizer@3.0.3)
+ '@csstools/css-tokenizer': 3.0.3
+
+ '@csstools/css-color-parser@3.0.7(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3)':
+ dependencies:
+ '@csstools/color-helpers': 5.0.1
+ '@csstools/css-calc': 2.1.1(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3)
+ '@csstools/css-parser-algorithms': 3.0.4(@csstools/css-tokenizer@3.0.3)
+ '@csstools/css-tokenizer': 3.0.3
+
+ '@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3)':
+ dependencies:
+ '@csstools/css-tokenizer': 3.0.3
+
+ '@csstools/css-tokenizer@3.0.3': {}
+
+ '@eslint-community/eslint-utils@4.4.1(eslint@8.57.1)':
+ dependencies:
+ eslint: 8.57.1
+ eslint-visitor-keys: 3.4.3
+
+ '@eslint-community/regexpp@4.12.1': {}
+
+ '@eslint/eslintrc@2.1.4':
+ dependencies:
+ ajv: 6.12.6
+ debug: 4.4.0
+ espree: 9.6.1
+ globals: 13.24.0
+ ignore: 5.3.2
+ import-fresh: 3.3.0
+ js-yaml: 4.1.0
+ minimatch: 3.1.2
+ strip-json-comments: 3.1.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@eslint/js@8.57.1': {}
+
+ '@humanwhocodes/config-array@0.13.0':
+ dependencies:
+ '@humanwhocodes/object-schema': 2.0.3
+ debug: 4.4.0
+ minimatch: 3.1.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@humanwhocodes/module-importer@1.0.1': {}
+
+ '@humanwhocodes/object-schema@2.0.3': {}
+
+ '@isaacs/cliui@8.0.2':
+ dependencies:
+ string-width: 5.1.2
+ string-width-cjs: string-width@4.2.3
+ strip-ansi: 7.1.0
+ strip-ansi-cjs: strip-ansi@6.0.1
+ wrap-ansi: 8.1.0
+ wrap-ansi-cjs: wrap-ansi@7.0.0
+
+ '@istanbuljs/load-nyc-config@1.1.0':
+ dependencies:
+ camelcase: 5.3.1
+ find-up: 4.1.0
+ get-package-type: 0.1.0
+ js-yaml: 3.14.1
+ resolve-from: 5.0.0
+
+ '@istanbuljs/schema@0.1.3': {}
+
+ '@jest/console@29.7.0':
+ dependencies:
+ '@jest/types': 29.6.3
+ '@types/node': 20.17.12
+ chalk: 4.1.2
+ jest-message-util: 29.7.0
+ jest-util: 29.7.0
+ slash: 3.0.0
+
+ '@jest/core@29.7.0(ts-node@10.9.2(@types/node@20.17.12)(typescript@5.7.2))':
+ dependencies:
+ '@jest/console': 29.7.0
+ '@jest/reporters': 29.7.0
+ '@jest/test-result': 29.7.0
+ '@jest/transform': 29.7.0
+ '@jest/types': 29.6.3
+ '@types/node': 20.17.12
+ ansi-escapes: 4.3.2
+ chalk: 4.1.2
+ ci-info: 3.9.0
+ exit: 0.1.2
+ graceful-fs: 4.2.11
+ jest-changed-files: 29.7.0
+ jest-config: 29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@types/node@20.17.12)(typescript@5.7.2))
+ jest-haste-map: 29.7.0
+ jest-message-util: 29.7.0
+ jest-regex-util: 29.6.3
+ jest-resolve: 29.7.0
+ jest-resolve-dependencies: 29.7.0
+ jest-runner: 29.7.0
+ jest-runtime: 29.7.0
+ jest-snapshot: 29.7.0
+ jest-util: 29.7.0
+ jest-validate: 29.7.0
+ jest-watcher: 29.7.0
+ micromatch: 4.0.8
+ pretty-format: 29.7.0
+ slash: 3.0.0
+ strip-ansi: 6.0.1
+ transitivePeerDependencies:
+ - babel-plugin-macros
+ - supports-color
+ - ts-node
+
+ '@jest/environment@29.7.0':
+ dependencies:
+ '@jest/fake-timers': 29.7.0
+ '@jest/types': 29.6.3
+ '@types/node': 20.17.12
+ jest-mock: 29.7.0
+
+ '@jest/expect-utils@29.7.0':
+ dependencies:
+ jest-get-type: 29.6.3
+
+ '@jest/expect@29.7.0':
+ dependencies:
+ expect: 29.7.0
+ jest-snapshot: 29.7.0
+ transitivePeerDependencies:
+ - supports-color
+
+ '@jest/fake-timers@29.7.0':
+ dependencies:
+ '@jest/types': 29.6.3
+ '@sinonjs/fake-timers': 10.3.0
+ '@types/node': 20.17.12
+ jest-message-util: 29.7.0
+ jest-mock: 29.7.0
+ jest-util: 29.7.0
+
+ '@jest/globals@29.7.0':
+ dependencies:
+ '@jest/environment': 29.7.0
+ '@jest/expect': 29.7.0
+ '@jest/types': 29.6.3
+ jest-mock: 29.7.0
+ transitivePeerDependencies:
+ - supports-color
+
+ '@jest/reporters@29.7.0':
+ dependencies:
+ '@bcoe/v8-coverage': 0.2.3
+ '@jest/console': 29.7.0
+ '@jest/test-result': 29.7.0
+ '@jest/transform': 29.7.0
+ '@jest/types': 29.6.3
+ '@jridgewell/trace-mapping': 0.3.25
+ '@types/node': 20.17.12
+ chalk: 4.1.2
+ collect-v8-coverage: 1.0.2
+ exit: 0.1.2
+ glob: 7.2.3
+ graceful-fs: 4.2.11
+ istanbul-lib-coverage: 3.2.2
+ istanbul-lib-instrument: 6.0.3
+ istanbul-lib-report: 3.0.1
+ istanbul-lib-source-maps: 4.0.1
+ istanbul-reports: 3.1.7
+ jest-message-util: 29.7.0
+ jest-util: 29.7.0
+ jest-worker: 29.7.0
+ slash: 3.0.0
+ string-length: 4.0.2
+ strip-ansi: 6.0.1
+ v8-to-istanbul: 9.3.0
+ transitivePeerDependencies:
+ - supports-color
+
+ '@jest/schemas@29.6.3':
+ dependencies:
+ '@sinclair/typebox': 0.27.8
+
+ '@jest/source-map@29.6.3':
+ dependencies:
+ '@jridgewell/trace-mapping': 0.3.25
+ callsites: 3.1.0
+ graceful-fs: 4.2.11
+
+ '@jest/test-result@29.7.0':
+ dependencies:
+ '@jest/console': 29.7.0
+ '@jest/types': 29.6.3
+ '@types/istanbul-lib-coverage': 2.0.6
+ collect-v8-coverage: 1.0.2
+
+ '@jest/test-sequencer@29.7.0':
+ dependencies:
+ '@jest/test-result': 29.7.0
+ graceful-fs: 4.2.11
+ jest-haste-map: 29.7.0
+ slash: 3.0.0
+
+ '@jest/transform@29.7.0':
+ dependencies:
+ '@babel/core': 7.26.0
+ '@jest/types': 29.6.3
+ '@jridgewell/trace-mapping': 0.3.25
+ babel-plugin-istanbul: 6.1.1
+ chalk: 4.1.2
+ convert-source-map: 2.0.0
+ fast-json-stable-stringify: 2.1.0
+ graceful-fs: 4.2.11
+ jest-haste-map: 29.7.0
+ jest-regex-util: 29.6.3
+ jest-util: 29.7.0
+ micromatch: 4.0.8
+ pirates: 4.0.6
+ slash: 3.0.0
+ write-file-atomic: 4.0.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@jest/types@29.6.3':
+ dependencies:
+ '@jest/schemas': 29.6.3
+ '@types/istanbul-lib-coverage': 2.0.6
+ '@types/istanbul-reports': 3.0.4
+ '@types/node': 20.17.12
+ '@types/yargs': 17.0.33
+ chalk: 4.1.2
+
+ '@jridgewell/gen-mapping@0.3.8':
+ dependencies:
+ '@jridgewell/set-array': 1.2.1
+ '@jridgewell/sourcemap-codec': 1.5.0
+ '@jridgewell/trace-mapping': 0.3.25
+
+ '@jridgewell/resolve-uri@3.1.2': {}
+
+ '@jridgewell/set-array@1.2.1': {}
+
+ '@jridgewell/sourcemap-codec@1.5.0': {}
+
+ '@jridgewell/trace-mapping@0.3.25':
+ dependencies:
+ '@jridgewell/resolve-uri': 3.1.2
+ '@jridgewell/sourcemap-codec': 1.5.0
+
+ '@jridgewell/trace-mapping@0.3.9':
+ dependencies:
+ '@jridgewell/resolve-uri': 3.1.2
+ '@jridgewell/sourcemap-codec': 1.5.0
+
+ '@mixmark-io/domino@2.2.0': {}
+
+ '@modelcontextprotocol/sdk@1.1.1':
+ dependencies:
+ content-type: 1.0.5
+ raw-body: 3.0.0
+ zod: 3.23.8
+
+ '@mongodb-js/saslprep@1.1.9':
+ dependencies:
+ sparse-bitfield: 3.0.3
+
+ '@nodelib/fs.scandir@2.1.5':
+ dependencies:
+ '@nodelib/fs.stat': 2.0.5
+ run-parallel: 1.2.0
+
+ '@nodelib/fs.stat@2.0.5': {}
+
+ '@nodelib/fs.walk@1.2.8':
+ dependencies:
+ '@nodelib/fs.scandir': 2.1.5
+ fastq: 1.18.0
+
+ '@pkgjs/parseargs@0.11.0':
+ optional: true
+
+ '@redis/bloom@1.2.0(@redis/client@1.6.0)':
+ dependencies:
+ '@redis/client': 1.6.0
+
+ '@redis/client@1.6.0':
+ dependencies:
+ cluster-key-slot: 1.1.2
+ generic-pool: 3.9.0
+ yallist: 4.0.0
+
+ '@redis/graph@1.1.1(@redis/client@1.6.0)':
+ dependencies:
+ '@redis/client': 1.6.0
+
+ '@redis/json@1.0.7(@redis/client@1.6.0)':
+ dependencies:
+ '@redis/client': 1.6.0
+
+ '@redis/search@1.2.0(@redis/client@1.6.0)':
+ dependencies:
+ '@redis/client': 1.6.0
+
+ '@redis/time-series@1.1.0(@redis/client@1.6.0)':
+ dependencies:
+ '@redis/client': 1.6.0
+
+ '@sinclair/typebox@0.27.8': {}
+
+ '@sinonjs/commons@3.0.1':
+ dependencies:
+ type-detect: 4.0.8
+
+ '@sinonjs/fake-timers@10.3.0':
+ dependencies:
+ '@sinonjs/commons': 3.0.1
+
+ '@tsconfig/node10@1.0.11': {}
+
+ '@tsconfig/node12@1.0.11': {}
+
+ '@tsconfig/node14@1.0.3': {}
+
+ '@tsconfig/node16@1.0.4': {}
+
+ '@types/babel__core@7.20.5':
+ dependencies:
+ '@babel/parser': 7.26.5
+ '@babel/types': 7.26.5
+ '@types/babel__generator': 7.6.8
+ '@types/babel__template': 7.4.4
+ '@types/babel__traverse': 7.20.6
+
+ '@types/babel__generator@7.6.8':
+ dependencies:
+ '@babel/types': 7.26.5
+
+ '@types/babel__template@7.4.4':
+ dependencies:
+ '@babel/parser': 7.26.5
+ '@babel/types': 7.26.5
+
+ '@types/babel__traverse@7.20.6':
+ dependencies:
+ '@babel/types': 7.26.5
+
+ '@types/cheerio@0.22.35':
+ dependencies:
+ '@types/node': 20.17.12
+
+ '@types/graceful-fs@4.1.9':
+ dependencies:
+ '@types/node': 20.17.12
+
+ '@types/istanbul-lib-coverage@2.0.6': {}
+
+ '@types/istanbul-lib-report@3.0.3':
+ dependencies:
+ '@types/istanbul-lib-coverage': 2.0.6
+
+ '@types/istanbul-reports@3.0.4':
+ dependencies:
+ '@types/istanbul-lib-report': 3.0.3
+
+ '@types/jest@29.5.14':
+ dependencies:
+ expect: 29.7.0
+ pretty-format: 29.7.0
+
+ '@types/json-schema@7.0.15': {}
+
+ '@types/node@20.17.12':
+ dependencies:
+ undici-types: 6.19.8
+
+ '@types/semver@7.5.8': {}
+
+ '@types/stack-utils@2.0.3': {}
+
+ '@types/turndown@5.0.5': {}
+
+ '@types/webidl-conversions@7.0.3': {}
+
+ '@types/whatwg-url@11.0.5':
+ dependencies:
+ '@types/webidl-conversions': 7.0.3
+
+ '@types/yargs-parser@21.0.3': {}
+
+ '@types/yargs@17.0.33':
+ dependencies:
+ '@types/yargs-parser': 21.0.3
+
+ '@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1)(typescript@5.7.2)':
+ dependencies:
+ '@eslint-community/regexpp': 4.12.1
+ '@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.7.2)
+ '@typescript-eslint/scope-manager': 6.21.0
+ '@typescript-eslint/type-utils': 6.21.0(eslint@8.57.1)(typescript@5.7.2)
+ '@typescript-eslint/utils': 6.21.0(eslint@8.57.1)(typescript@5.7.2)
+ '@typescript-eslint/visitor-keys': 6.21.0
+ debug: 4.4.0
+ eslint: 8.57.1
+ graphemer: 1.4.0
+ ignore: 5.3.2
+ natural-compare: 1.4.0
+ semver: 7.6.3
+ ts-api-utils: 1.4.3(typescript@5.7.2)
+ optionalDependencies:
+ typescript: 5.7.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.7.2)':
+ dependencies:
+ '@typescript-eslint/scope-manager': 6.21.0
+ '@typescript-eslint/types': 6.21.0
+ '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.7.2)
+ '@typescript-eslint/visitor-keys': 6.21.0
+ debug: 4.4.0
+ eslint: 8.57.1
+ optionalDependencies:
+ typescript: 5.7.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/scope-manager@6.21.0':
+ dependencies:
+ '@typescript-eslint/types': 6.21.0
+ '@typescript-eslint/visitor-keys': 6.21.0
+
+ '@typescript-eslint/type-utils@6.21.0(eslint@8.57.1)(typescript@5.7.2)':
+ dependencies:
+ '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.7.2)
+ '@typescript-eslint/utils': 6.21.0(eslint@8.57.1)(typescript@5.7.2)
+ debug: 4.4.0
+ eslint: 8.57.1
+ ts-api-utils: 1.4.3(typescript@5.7.2)
+ optionalDependencies:
+ typescript: 5.7.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/types@6.21.0': {}
+
+ '@typescript-eslint/typescript-estree@6.21.0(typescript@5.7.2)':
+ dependencies:
+ '@typescript-eslint/types': 6.21.0
+ '@typescript-eslint/visitor-keys': 6.21.0
+ debug: 4.4.0
+ globby: 11.1.0
+ is-glob: 4.0.3
+ minimatch: 9.0.3
+ semver: 7.6.3
+ ts-api-utils: 1.4.3(typescript@5.7.2)
+ optionalDependencies:
+ typescript: 5.7.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/utils@6.21.0(eslint@8.57.1)(typescript@5.7.2)':
+ dependencies:
+ '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1)
+ '@types/json-schema': 7.0.15
+ '@types/semver': 7.5.8
+ '@typescript-eslint/scope-manager': 6.21.0
+ '@typescript-eslint/types': 6.21.0
+ '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.7.2)
+ eslint: 8.57.1
+ semver: 7.6.3
+ transitivePeerDependencies:
+ - supports-color
+ - typescript
+
+ '@typescript-eslint/visitor-keys@6.21.0':
+ dependencies:
+ '@typescript-eslint/types': 6.21.0
+ eslint-visitor-keys: 3.4.3
+
+ '@ungap/structured-clone@1.2.1': {}
+
+ acorn-jsx@5.3.2(acorn@8.14.0):
+ dependencies:
+ acorn: 8.14.0
+
+ acorn-walk@8.3.4:
+ dependencies:
+ acorn: 8.14.0
+
+ acorn@8.14.0: {}
+
+ afinn-165-financialmarketnews@3.0.0: {}
+
+ afinn-165@1.0.4: {}
+
+ agent-base@7.1.3: {}
+
+ ajv@6.12.6:
+ dependencies:
+ fast-deep-equal: 3.1.3
+ fast-json-stable-stringify: 2.1.0
+ json-schema-traverse: 0.4.1
+ uri-js: 4.4.1
+
+ ansi-escapes@4.3.2:
+ dependencies:
+ type-fest: 0.21.3
+
+ ansi-regex@5.0.1: {}
+
+ ansi-regex@6.1.0: {}
+
+ ansi-styles@4.3.0:
+ dependencies:
+ color-convert: 2.0.1
+
+ ansi-styles@5.2.0: {}
+
+ ansi-styles@6.2.1: {}
+
+ anymatch@3.1.3:
+ dependencies:
+ normalize-path: 3.0.0
+ picomatch: 2.3.1
+
+ apparatus@0.0.10:
+ dependencies:
+ sylvester: 0.0.12
+
+ arg@4.1.3: {}
+
+ argparse@1.0.10:
+ dependencies:
+ sprintf-js: 1.0.3
+
+ argparse@2.0.1: {}
+
+ array-union@2.1.0: {}
+
+ async@2.6.4:
+ dependencies:
+ lodash: 4.17.21
+
+ async@3.2.6: {}
+
+ asynckit@0.4.0: {}
+
+ babel-jest@29.7.0(@babel/core@7.26.0):
+ dependencies:
+ '@babel/core': 7.26.0
+ '@jest/transform': 29.7.0
+ '@types/babel__core': 7.20.5
+ babel-plugin-istanbul: 6.1.1
+ babel-preset-jest: 29.6.3(@babel/core@7.26.0)
+ chalk: 4.1.2
+ graceful-fs: 4.2.11
+ slash: 3.0.0
+ transitivePeerDependencies:
+ - supports-color
+
+ babel-plugin-istanbul@6.1.1:
+ dependencies:
+ '@babel/helper-plugin-utils': 7.26.5
+ '@istanbuljs/load-nyc-config': 1.1.0
+ '@istanbuljs/schema': 0.1.3
+ istanbul-lib-instrument: 5.2.1
+ test-exclude: 6.0.0
+ transitivePeerDependencies:
+ - supports-color
+
+ babel-plugin-jest-hoist@29.6.3:
+ dependencies:
+ '@babel/template': 7.25.9
+ '@babel/types': 7.26.5
+ '@types/babel__core': 7.20.5
+ '@types/babel__traverse': 7.20.6
+
+ babel-preset-current-node-syntax@1.1.0(@babel/core@7.26.0):
+ dependencies:
+ '@babel/core': 7.26.0
+ '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.26.0)
+ '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.26.0)
+ '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.26.0)
+ '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.26.0)
+ '@babel/plugin-syntax-import-attributes': 7.26.0(@babel/core@7.26.0)
+ '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.26.0)
+ '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.26.0)
+ '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.26.0)
+ '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.26.0)
+ '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.26.0)
+ '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.26.0)
+ '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.26.0)
+ '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.26.0)
+ '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.26.0)
+ '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.26.0)
+
+ babel-preset-jest@29.6.3(@babel/core@7.26.0):
+ dependencies:
+ '@babel/core': 7.26.0
+ babel-plugin-jest-hoist: 29.6.3
+ babel-preset-current-node-syntax: 1.1.0(@babel/core@7.26.0)
+
+ balanced-match@1.0.2: {}
+
+ basic-auth@2.0.1:
+ dependencies:
+ safe-buffer: 5.1.2
+
+ boolbase@1.0.0: {}
+
+ brace-expansion@1.1.11:
+ dependencies:
+ balanced-match: 1.0.2
+ concat-map: 0.0.1
+
+ brace-expansion@2.0.1:
+ dependencies:
+ balanced-match: 1.0.2
+
+ braces@3.0.3:
+ dependencies:
+ fill-range: 7.1.1
+
+ browserslist@4.24.4:
+ dependencies:
+ caniuse-lite: 1.0.30001692
+ electron-to-chromium: 1.5.80
+ node-releases: 2.0.19
+ update-browserslist-db: 1.1.2(browserslist@4.24.4)
+
+ bs-logger@0.2.6:
+ dependencies:
+ fast-json-stable-stringify: 2.1.0
+
+ bser@2.1.1:
+ dependencies:
+ node-int64: 0.4.0
+
+ bson@6.10.1: {}
+
+ buffer-from@1.1.2: {}
+
+ bytes@3.1.2: {}
+
+ call-bind-apply-helpers@1.0.1:
+ dependencies:
+ es-errors: 1.3.0
+ function-bind: 1.1.2
+
+ call-bound@1.0.3:
+ dependencies:
+ call-bind-apply-helpers: 1.0.1
+ get-intrinsic: 1.2.7
+
+ callsites@3.1.0: {}
+
+ camelcase@5.3.1: {}
+
+ camelcase@6.3.0: {}
+
+ caniuse-lite@1.0.30001692: {}
+
+ chalk@4.1.2:
+ dependencies:
+ ansi-styles: 4.3.0
+ supports-color: 7.2.0
+
+ char-regex@1.0.2: {}
+
+ cheerio-select@2.1.0:
+ dependencies:
+ boolbase: 1.0.0
+ css-select: 5.1.0
+ css-what: 6.1.0
+ domelementtype: 2.3.0
+ domhandler: 5.0.3
+ domutils: 3.2.2
+
+ cheerio@1.0.0:
+ dependencies:
+ cheerio-select: 2.1.0
+ dom-serializer: 2.0.0
+ domhandler: 5.0.3
+ domutils: 3.2.2
+ encoding-sniffer: 0.2.0
+ htmlparser2: 9.1.0
+ parse5: 7.2.1
+ parse5-htmlparser2-tree-adapter: 7.1.0
+ parse5-parser-stream: 7.1.2
+ undici: 6.21.0
+ whatwg-mimetype: 4.0.0
+
+ ci-info@3.9.0: {}
+
+ cjs-module-lexer@1.4.1: {}
+
+ cliui@8.0.1:
+ dependencies:
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+ wrap-ansi: 7.0.0
+
+ cluster-key-slot@1.1.2: {}
+
+ co@4.6.0: {}
+
+ collect-v8-coverage@1.0.2: {}
+
+ color-convert@2.0.1:
+ dependencies:
+ color-name: 1.1.4
+
+ color-name@1.1.4: {}
+
+ combined-stream@1.0.8:
+ dependencies:
+ delayed-stream: 1.0.0
+
+ concat-map@0.0.1: {}
+
+ content-type@1.0.5: {}
+
+ convert-source-map@2.0.0: {}
+
+ corser@2.0.1: {}
+
+ create-jest@29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@types/node@20.17.12)(typescript@5.7.2)):
+ dependencies:
+ '@jest/types': 29.6.3
+ chalk: 4.1.2
+ exit: 0.1.2
+ graceful-fs: 4.2.11
+ jest-config: 29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@types/node@20.17.12)(typescript@5.7.2))
+ jest-util: 29.7.0
+ prompts: 2.4.2
+ transitivePeerDependencies:
+ - '@types/node'
+ - babel-plugin-macros
+ - supports-color
+ - ts-node
+
+ create-require@1.1.1: {}
+
+ cross-spawn@7.0.6:
+ dependencies:
+ path-key: 3.1.1
+ shebang-command: 2.0.0
+ which: 2.0.2
+
+ css-select@5.1.0:
+ dependencies:
+ boolbase: 1.0.0
+ css-what: 6.1.0
+ domhandler: 5.0.3
+ domutils: 3.2.2
+ nth-check: 2.1.1
+
+ css-what@6.1.0: {}
+
+ cssstyle@4.2.1:
+ dependencies:
+ '@asamuzakjp/css-color': 2.8.2
+ rrweb-cssom: 0.8.0
+
+ data-urls@5.0.0:
+ dependencies:
+ whatwg-mimetype: 4.0.0
+ whatwg-url: 14.1.0
+
+ debug@3.2.7:
+ dependencies:
+ ms: 2.1.3
+
+ debug@4.4.0:
+ dependencies:
+ ms: 2.1.3
+
+ decimal.js@10.4.3: {}
+
+ dedent@1.5.3: {}
+
+ deep-is@0.1.4: {}
+
+ deepmerge@4.3.1: {}
+
+ delayed-stream@1.0.0: {}
+
+ depd@2.0.0: {}
+
+ detect-newline@3.1.0: {}
+
+ diff-sequences@29.6.3: {}
+
+ diff@4.0.2: {}
+
+ dir-glob@3.0.1:
+ dependencies:
+ path-type: 4.0.0
+
+ doctrine@3.0.0:
+ dependencies:
+ esutils: 2.0.3
+
+ dom-serializer@2.0.0:
+ dependencies:
+ domelementtype: 2.3.0
+ domhandler: 5.0.3
+ entities: 4.5.0
+
+ domelementtype@2.3.0: {}
+
+ domhandler@5.0.3:
+ dependencies:
+ domelementtype: 2.3.0
+
+ domutils@3.2.2:
+ dependencies:
+ dom-serializer: 2.0.0
+ domelementtype: 2.3.0
+ domhandler: 5.0.3
+
+ dotenv@16.4.7: {}
+
+ dunder-proto@1.0.1:
+ dependencies:
+ call-bind-apply-helpers: 1.0.1
+ es-errors: 1.3.0
+ gopd: 1.2.0
+
+ eastasianwidth@0.2.0: {}
+
+ ejs@3.1.10:
+ dependencies:
+ jake: 10.9.2
+
+ electron-to-chromium@1.5.80: {}
+
+ emittery@0.13.1: {}
+
+ emoji-regex@8.0.0: {}
+
+ emoji-regex@9.2.2: {}
+
+ encoding-sniffer@0.2.0:
+ dependencies:
+ iconv-lite: 0.6.3
+ whatwg-encoding: 3.1.1
+
+ entities@4.5.0: {}
+
+ error-ex@1.3.2:
+ dependencies:
+ is-arrayish: 0.2.1
+
+ es-define-property@1.0.1: {}
+
+ es-errors@1.3.0: {}
+
+ es-object-atoms@1.0.0:
+ dependencies:
+ es-errors: 1.3.0
+
+ escalade@3.2.0: {}
+
+ escape-string-regexp@2.0.0: {}
+
+ escape-string-regexp@4.0.0: {}
+
+ eslint-scope@7.2.2:
+ dependencies:
+ esrecurse: 4.3.0
+ estraverse: 5.3.0
+
+ eslint-visitor-keys@3.4.3: {}
+
+ eslint@8.57.1:
+ dependencies:
+ '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1)
+ '@eslint-community/regexpp': 4.12.1
+ '@eslint/eslintrc': 2.1.4
+ '@eslint/js': 8.57.1
+ '@humanwhocodes/config-array': 0.13.0
+ '@humanwhocodes/module-importer': 1.0.1
+ '@nodelib/fs.walk': 1.2.8
+ '@ungap/structured-clone': 1.2.1
+ ajv: 6.12.6
+ chalk: 4.1.2
+ cross-spawn: 7.0.6
+ debug: 4.4.0
+ doctrine: 3.0.0
+ escape-string-regexp: 4.0.0
+ eslint-scope: 7.2.2
+ eslint-visitor-keys: 3.4.3
+ espree: 9.6.1
+ esquery: 1.6.0
+ esutils: 2.0.3
+ fast-deep-equal: 3.1.3
+ file-entry-cache: 6.0.1
+ find-up: 5.0.0
+ glob-parent: 6.0.2
+ globals: 13.24.0
+ graphemer: 1.4.0
+ ignore: 5.3.2
+ imurmurhash: 0.1.4
+ is-glob: 4.0.3
+ is-path-inside: 3.0.3
+ js-yaml: 4.1.0
+ json-stable-stringify-without-jsonify: 1.0.1
+ levn: 0.4.1
+ lodash.merge: 4.6.2
+ minimatch: 3.1.2
+ natural-compare: 1.4.0
+ optionator: 0.9.4
+ strip-ansi: 6.0.1
+ text-table: 0.2.0
+ transitivePeerDependencies:
+ - supports-color
+
+ espree@9.6.1:
+ dependencies:
+ acorn: 8.14.0
+ acorn-jsx: 5.3.2(acorn@8.14.0)
+ eslint-visitor-keys: 3.4.3
+
+ esprima@4.0.1: {}
+
+ esquery@1.6.0:
+ dependencies:
+ estraverse: 5.3.0
+
+ esrecurse@4.3.0:
+ dependencies:
+ estraverse: 5.3.0
+
+ estraverse@5.3.0: {}
+
+ esutils@2.0.3: {}
+
+ eventemitter3@4.0.7: {}
+
+ execa@5.1.1:
+ dependencies:
+ cross-spawn: 7.0.6
+ get-stream: 6.0.1
+ human-signals: 2.1.0
+ is-stream: 2.0.1
+ merge-stream: 2.0.0
+ npm-run-path: 4.0.1
+ onetime: 5.1.2
+ signal-exit: 3.0.7
+ strip-final-newline: 2.0.0
+
+ exit@0.1.2: {}
+
+ expect@29.7.0:
+ dependencies:
+ '@jest/expect-utils': 29.7.0
+ jest-get-type: 29.6.3
+ jest-matcher-utils: 29.7.0
+ jest-message-util: 29.7.0
+ jest-util: 29.7.0
+
+ fast-deep-equal@3.1.3: {}
+
+ fast-glob@3.3.3:
+ dependencies:
+ '@nodelib/fs.stat': 2.0.5
+ '@nodelib/fs.walk': 1.2.8
+ glob-parent: 5.1.2
+ merge2: 1.4.1
+ micromatch: 4.0.8
+
+ fast-json-stable-stringify@2.1.0: {}
+
+ fast-levenshtein@2.0.6: {}
+
+ fastq@1.18.0:
+ dependencies:
+ reusify: 1.0.4
+
+ fb-watchman@2.0.2:
+ dependencies:
+ bser: 2.1.1
+
+ file-entry-cache@6.0.1:
+ dependencies:
+ flat-cache: 3.2.0
+
+ filelist@1.0.4:
+ dependencies:
+ minimatch: 5.1.6
+
+ fill-range@7.1.1:
+ dependencies:
+ to-regex-range: 5.0.1
+
+ find-up@4.1.0:
+ dependencies:
+ locate-path: 5.0.0
+ path-exists: 4.0.0
+
+ find-up@5.0.0:
+ dependencies:
+ locate-path: 6.0.0
+ path-exists: 4.0.0
+
+ flat-cache@3.2.0:
+ dependencies:
+ flatted: 3.3.2
+ keyv: 4.5.4
+ rimraf: 3.0.2
+
+ flatted@3.3.2: {}
+
+ follow-redirects@1.15.9: {}
+
+ foreground-child@3.3.0:
+ dependencies:
+ cross-spawn: 7.0.6
+ signal-exit: 4.1.0
+
+ form-data@4.0.1:
+ dependencies:
+ asynckit: 0.4.0
+ combined-stream: 1.0.8
+ mime-types: 2.1.35
+
+ fs.realpath@1.0.0: {}
+
+ fsevents@2.3.2:
+ optional: true
+
+ fsevents@2.3.3:
+ optional: true
+
+ function-bind@1.1.2: {}
+
+ generic-pool@3.9.0: {}
+
+ gensync@1.0.0-beta.2: {}
+
+ get-caller-file@2.0.5: {}
+
+ get-intrinsic@1.2.7:
+ dependencies:
+ call-bind-apply-helpers: 1.0.1
+ es-define-property: 1.0.1
+ es-errors: 1.3.0
+ es-object-atoms: 1.0.0
+ 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
+
+ get-package-type@0.1.0: {}
+
+ get-proto@1.0.1:
+ dependencies:
+ dunder-proto: 1.0.1
+ es-object-atoms: 1.0.0
+
+ get-stream@6.0.1: {}
+
+ glob-parent@5.1.2:
+ dependencies:
+ is-glob: 4.0.3
+
+ glob-parent@6.0.2:
+ dependencies:
+ is-glob: 4.0.3
+
+ glob@10.4.5:
+ dependencies:
+ foreground-child: 3.3.0
+ jackspeak: 3.4.3
+ minimatch: 9.0.5
+ minipass: 7.1.2
+ package-json-from-dist: 1.0.1
+ path-scurry: 1.11.1
+
+ glob@7.2.3:
+ dependencies:
+ fs.realpath: 1.0.0
+ inflight: 1.0.6
+ inherits: 2.0.4
+ minimatch: 3.1.2
+ once: 1.4.0
+ path-is-absolute: 1.0.1
+
+ globals@11.12.0: {}
+
+ globals@13.24.0:
+ dependencies:
+ type-fest: 0.20.2
+
+ globby@11.1.0:
+ dependencies:
+ array-union: 2.1.0
+ dir-glob: 3.0.1
+ fast-glob: 3.3.3
+ ignore: 5.3.2
+ merge2: 1.4.1
+ slash: 3.0.0
+
+ gopd@1.2.0: {}
+
+ graceful-fs@4.2.11: {}
+
+ graphemer@1.4.0: {}
+
+ has-flag@4.0.0: {}
+
+ has-symbols@1.1.0: {}
+
+ hasown@2.0.2:
+ dependencies:
+ function-bind: 1.1.2
+
+ he@1.2.0: {}
+
+ html-encoding-sniffer@3.0.0:
+ dependencies:
+ whatwg-encoding: 2.0.0
+
+ html-encoding-sniffer@4.0.0:
+ dependencies:
+ whatwg-encoding: 3.1.1
+
+ html-escaper@2.0.2: {}
+
+ html-to-md@0.8.6: {}
+
+ htmlparser2@9.1.0:
+ dependencies:
+ domelementtype: 2.3.0
+ domhandler: 5.0.3
+ domutils: 3.2.2
+ entities: 4.5.0
+
+ htmlparser@1.7.7: {}
+
+ http-errors@2.0.0:
+ dependencies:
+ depd: 2.0.0
+ inherits: 2.0.4
+ setprototypeof: 1.2.0
+ statuses: 2.0.1
+ toidentifier: 1.0.1
+
+ http-proxy-agent@7.0.2:
+ dependencies:
+ agent-base: 7.1.3
+ debug: 4.4.0
+ transitivePeerDependencies:
+ - supports-color
+
+ http-proxy@1.18.1:
+ dependencies:
+ eventemitter3: 4.0.7
+ follow-redirects: 1.15.9
+ requires-port: 1.0.0
+ transitivePeerDependencies:
+ - debug
+
+ http-server@14.1.1:
+ dependencies:
+ basic-auth: 2.0.1
+ chalk: 4.1.2
+ corser: 2.0.1
+ he: 1.2.0
+ html-encoding-sniffer: 3.0.0
+ http-proxy: 1.18.1
+ mime: 1.6.0
+ minimist: 1.2.8
+ opener: 1.5.2
+ portfinder: 1.0.32
+ secure-compare: 3.0.1
+ union: 0.5.0
+ url-join: 4.0.1
+ transitivePeerDependencies:
+ - debug
+ - supports-color
+
+ https-proxy-agent@7.0.6:
+ dependencies:
+ agent-base: 7.1.3
+ debug: 4.4.0
+ transitivePeerDependencies:
+ - supports-color
+
+ human-signals@2.1.0: {}
+
+ iconv-lite@0.6.3:
+ dependencies:
+ safer-buffer: 2.1.2
+
+ ignore@5.3.2: {}
+
+ import-fresh@3.3.0:
+ dependencies:
+ parent-module: 1.0.1
+ resolve-from: 4.0.0
+
+ import-local@3.2.0:
+ dependencies:
+ pkg-dir: 4.2.0
+ resolve-cwd: 3.0.0
+
+ imurmurhash@0.1.4: {}
+
+ inflight@1.0.6:
+ dependencies:
+ once: 1.4.0
+ wrappy: 1.0.2
+
+ inherits@2.0.4: {}
+
+ is-arrayish@0.2.1: {}
+
+ is-core-module@2.15.1:
+ dependencies:
+ hasown: 2.0.2
+
+ is-extglob@2.1.1: {}
+
+ is-fullwidth-code-point@3.0.0: {}
+
+ is-generator-fn@2.1.0: {}
+
+ is-glob@4.0.3:
+ dependencies:
+ is-extglob: 2.1.1
+
+ is-number@7.0.0: {}
+
+ is-path-inside@3.0.3: {}
+
+ is-potential-custom-element-name@1.0.1: {}
+
+ is-stream@2.0.1: {}
+
+ isexe@2.0.0: {}
+
+ istanbul-lib-coverage@3.2.2: {}
+
+ istanbul-lib-instrument@5.2.1:
+ dependencies:
+ '@babel/core': 7.26.0
+ '@babel/parser': 7.26.5
+ '@istanbuljs/schema': 0.1.3
+ istanbul-lib-coverage: 3.2.2
+ semver: 6.3.1
+ transitivePeerDependencies:
+ - supports-color
+
+ istanbul-lib-instrument@6.0.3:
+ dependencies:
+ '@babel/core': 7.26.0
+ '@babel/parser': 7.26.5
+ '@istanbuljs/schema': 0.1.3
+ istanbul-lib-coverage: 3.2.2
+ semver: 7.6.3
+ transitivePeerDependencies:
+ - supports-color
+
+ istanbul-lib-report@3.0.1:
+ dependencies:
+ istanbul-lib-coverage: 3.2.2
+ make-dir: 4.0.0
+ supports-color: 7.2.0
+
+ istanbul-lib-source-maps@4.0.1:
+ dependencies:
+ debug: 4.4.0
+ istanbul-lib-coverage: 3.2.2
+ source-map: 0.6.1
+ transitivePeerDependencies:
+ - supports-color
+
+ istanbul-reports@3.1.7:
+ dependencies:
+ html-escaper: 2.0.2
+ istanbul-lib-report: 3.0.1
+
+ jackspeak@3.4.3:
+ dependencies:
+ '@isaacs/cliui': 8.0.2
+ optionalDependencies:
+ '@pkgjs/parseargs': 0.11.0
+
+ jake@10.9.2:
+ dependencies:
+ async: 3.2.6
+ chalk: 4.1.2
+ filelist: 1.0.4
+ minimatch: 3.1.2
+
+ jest-changed-files@29.7.0:
+ dependencies:
+ execa: 5.1.1
+ jest-util: 29.7.0
+ p-limit: 3.1.0
+
+ jest-circus@29.7.0:
+ dependencies:
+ '@jest/environment': 29.7.0
+ '@jest/expect': 29.7.0
+ '@jest/test-result': 29.7.0
+ '@jest/types': 29.6.3
+ '@types/node': 20.17.12
+ chalk: 4.1.2
+ co: 4.6.0
+ dedent: 1.5.3
+ is-generator-fn: 2.1.0
+ jest-each: 29.7.0
+ jest-matcher-utils: 29.7.0
+ jest-message-util: 29.7.0
+ jest-runtime: 29.7.0
+ jest-snapshot: 29.7.0
+ jest-util: 29.7.0
+ p-limit: 3.1.0
+ pretty-format: 29.7.0
+ pure-rand: 6.1.0
+ slash: 3.0.0
+ stack-utils: 2.0.6
+ transitivePeerDependencies:
+ - babel-plugin-macros
+ - supports-color
+
+ jest-cli@29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@types/node@20.17.12)(typescript@5.7.2)):
+ dependencies:
+ '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@20.17.12)(typescript@5.7.2))
+ '@jest/test-result': 29.7.0
+ '@jest/types': 29.6.3
+ chalk: 4.1.2
+ create-jest: 29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@types/node@20.17.12)(typescript@5.7.2))
+ exit: 0.1.2
+ import-local: 3.2.0
+ jest-config: 29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@types/node@20.17.12)(typescript@5.7.2))
+ jest-util: 29.7.0
+ jest-validate: 29.7.0
+ yargs: 17.7.2
+ transitivePeerDependencies:
+ - '@types/node'
+ - babel-plugin-macros
+ - supports-color
+ - ts-node
+
+ jest-config@29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@types/node@20.17.12)(typescript@5.7.2)):
+ dependencies:
+ '@babel/core': 7.26.0
+ '@jest/test-sequencer': 29.7.0
+ '@jest/types': 29.6.3
+ babel-jest: 29.7.0(@babel/core@7.26.0)
+ chalk: 4.1.2
+ ci-info: 3.9.0
+ deepmerge: 4.3.1
+ glob: 7.2.3
+ graceful-fs: 4.2.11
+ jest-circus: 29.7.0
+ jest-environment-node: 29.7.0
+ jest-get-type: 29.6.3
+ jest-regex-util: 29.6.3
+ jest-resolve: 29.7.0
+ jest-runner: 29.7.0
+ jest-util: 29.7.0
+ jest-validate: 29.7.0
+ micromatch: 4.0.8
+ parse-json: 5.2.0
+ pretty-format: 29.7.0
+ slash: 3.0.0
+ strip-json-comments: 3.1.1
+ optionalDependencies:
+ '@types/node': 20.17.12
+ ts-node: 10.9.2(@types/node@20.17.12)(typescript@5.7.2)
+ transitivePeerDependencies:
+ - babel-plugin-macros
+ - supports-color
+
+ jest-diff@29.7.0:
+ dependencies:
+ chalk: 4.1.2
+ diff-sequences: 29.6.3
+ jest-get-type: 29.6.3
+ pretty-format: 29.7.0
+
+ jest-docblock@29.7.0:
+ dependencies:
+ detect-newline: 3.1.0
+
+ jest-each@29.7.0:
+ dependencies:
+ '@jest/types': 29.6.3
+ chalk: 4.1.2
+ jest-get-type: 29.6.3
+ jest-util: 29.7.0
+ pretty-format: 29.7.0
+
+ jest-environment-node@29.7.0:
+ dependencies:
+ '@jest/environment': 29.7.0
+ '@jest/fake-timers': 29.7.0
+ '@jest/types': 29.6.3
+ '@types/node': 20.17.12
+ jest-mock: 29.7.0
+ jest-util: 29.7.0
+
+ jest-get-type@29.6.3: {}
+
+ jest-haste-map@29.7.0:
+ dependencies:
+ '@jest/types': 29.6.3
+ '@types/graceful-fs': 4.1.9
+ '@types/node': 20.17.12
+ anymatch: 3.1.3
+ fb-watchman: 2.0.2
+ graceful-fs: 4.2.11
+ jest-regex-util: 29.6.3
+ jest-util: 29.7.0
+ jest-worker: 29.7.0
+ micromatch: 4.0.8
+ walker: 1.0.8
+ optionalDependencies:
+ fsevents: 2.3.3
+
+ jest-leak-detector@29.7.0:
+ dependencies:
+ jest-get-type: 29.6.3
+ pretty-format: 29.7.0
+
+ jest-matcher-utils@29.7.0:
+ dependencies:
+ chalk: 4.1.2
+ jest-diff: 29.7.0
+ jest-get-type: 29.6.3
+ pretty-format: 29.7.0
+
+ jest-message-util@29.7.0:
+ dependencies:
+ '@babel/code-frame': 7.26.2
+ '@jest/types': 29.6.3
+ '@types/stack-utils': 2.0.3
+ chalk: 4.1.2
+ graceful-fs: 4.2.11
+ micromatch: 4.0.8
+ pretty-format: 29.7.0
+ slash: 3.0.0
+ stack-utils: 2.0.6
+
+ jest-mock@29.7.0:
+ dependencies:
+ '@jest/types': 29.6.3
+ '@types/node': 20.17.12
+ jest-util: 29.7.0
+
+ jest-pnp-resolver@1.2.3(jest-resolve@29.7.0):
+ optionalDependencies:
+ jest-resolve: 29.7.0
+
+ jest-regex-util@29.6.3: {}
+
+ jest-resolve-dependencies@29.7.0:
+ dependencies:
+ jest-regex-util: 29.6.3
+ jest-snapshot: 29.7.0
+ transitivePeerDependencies:
+ - supports-color
+
+ jest-resolve@29.7.0:
+ dependencies:
+ chalk: 4.1.2
+ graceful-fs: 4.2.11
+ jest-haste-map: 29.7.0
+ jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0)
+ jest-util: 29.7.0
+ jest-validate: 29.7.0
+ resolve: 1.22.8
+ resolve.exports: 2.0.3
+ slash: 3.0.0
+
+ jest-runner@29.7.0:
+ dependencies:
+ '@jest/console': 29.7.0
+ '@jest/environment': 29.7.0
+ '@jest/test-result': 29.7.0
+ '@jest/transform': 29.7.0
+ '@jest/types': 29.6.3
+ '@types/node': 20.17.12
+ chalk: 4.1.2
+ emittery: 0.13.1
+ graceful-fs: 4.2.11
+ jest-docblock: 29.7.0
+ jest-environment-node: 29.7.0
+ jest-haste-map: 29.7.0
+ jest-leak-detector: 29.7.0
+ jest-message-util: 29.7.0
+ jest-resolve: 29.7.0
+ jest-runtime: 29.7.0
+ jest-util: 29.7.0
+ jest-watcher: 29.7.0
+ jest-worker: 29.7.0
+ p-limit: 3.1.0
+ source-map-support: 0.5.13
+ transitivePeerDependencies:
+ - supports-color
+
+ jest-runtime@29.7.0:
+ dependencies:
+ '@jest/environment': 29.7.0
+ '@jest/fake-timers': 29.7.0
+ '@jest/globals': 29.7.0
+ '@jest/source-map': 29.6.3
+ '@jest/test-result': 29.7.0
+ '@jest/transform': 29.7.0
+ '@jest/types': 29.6.3
+ '@types/node': 20.17.12
+ chalk: 4.1.2
+ cjs-module-lexer: 1.4.1
+ collect-v8-coverage: 1.0.2
+ glob: 7.2.3
+ graceful-fs: 4.2.11
+ jest-haste-map: 29.7.0
+ jest-message-util: 29.7.0
+ jest-mock: 29.7.0
+ jest-regex-util: 29.6.3
+ jest-resolve: 29.7.0
+ jest-snapshot: 29.7.0
+ jest-util: 29.7.0
+ slash: 3.0.0
+ strip-bom: 4.0.0
+ transitivePeerDependencies:
+ - supports-color
+
+ jest-snapshot@29.7.0:
+ dependencies:
+ '@babel/core': 7.26.0
+ '@babel/generator': 7.26.5
+ '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.0)
+ '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.0)
+ '@babel/types': 7.26.5
+ '@jest/expect-utils': 29.7.0
+ '@jest/transform': 29.7.0
+ '@jest/types': 29.6.3
+ babel-preset-current-node-syntax: 1.1.0(@babel/core@7.26.0)
+ chalk: 4.1.2
+ expect: 29.7.0
+ graceful-fs: 4.2.11
+ jest-diff: 29.7.0
+ jest-get-type: 29.6.3
+ jest-matcher-utils: 29.7.0
+ jest-message-util: 29.7.0
+ jest-util: 29.7.0
+ natural-compare: 1.4.0
+ pretty-format: 29.7.0
+ semver: 7.6.3
+ transitivePeerDependencies:
+ - supports-color
+
+ jest-util@29.7.0:
+ dependencies:
+ '@jest/types': 29.6.3
+ '@types/node': 20.17.12
+ chalk: 4.1.2
+ ci-info: 3.9.0
+ graceful-fs: 4.2.11
+ picomatch: 2.3.1
+
+ jest-validate@29.7.0:
+ dependencies:
+ '@jest/types': 29.6.3
+ camelcase: 6.3.0
+ chalk: 4.1.2
+ jest-get-type: 29.6.3
+ leven: 3.1.0
+ pretty-format: 29.7.0
+
+ jest-watcher@29.7.0:
+ dependencies:
+ '@jest/test-result': 29.7.0
+ '@jest/types': 29.6.3
+ '@types/node': 20.17.12
+ ansi-escapes: 4.3.2
+ chalk: 4.1.2
+ emittery: 0.13.1
+ jest-util: 29.7.0
+ string-length: 4.0.2
+
+ jest-worker@29.7.0:
+ dependencies:
+ '@types/node': 20.17.12
+ jest-util: 29.7.0
+ merge-stream: 2.0.0
+ supports-color: 8.1.1
+
+ jest@29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@types/node@20.17.12)(typescript@5.7.2)):
+ dependencies:
+ '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@20.17.12)(typescript@5.7.2))
+ '@jest/types': 29.6.3
+ import-local: 3.2.0
+ jest-cli: 29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@types/node@20.17.12)(typescript@5.7.2))
+ transitivePeerDependencies:
+ - '@types/node'
+ - babel-plugin-macros
+ - supports-color
+ - ts-node
+
+ js-tokens@4.0.0: {}
+
+ js-yaml@3.14.1:
+ dependencies:
+ argparse: 1.0.10
+ esprima: 4.0.1
+
+ js-yaml@4.1.0:
+ dependencies:
+ argparse: 2.0.1
+
+ jsdom@26.0.0:
+ dependencies:
+ cssstyle: 4.2.1
+ data-urls: 5.0.0
+ decimal.js: 10.4.3
+ form-data: 4.0.1
+ html-encoding-sniffer: 4.0.0
+ http-proxy-agent: 7.0.2
+ https-proxy-agent: 7.0.6
+ is-potential-custom-element-name: 1.0.1
+ nwsapi: 2.2.16
+ parse5: 7.2.1
+ rrweb-cssom: 0.8.0
+ saxes: 6.0.0
+ symbol-tree: 3.2.4
+ tough-cookie: 5.1.0
+ w3c-xmlserializer: 5.0.0
+ webidl-conversions: 7.0.0
+ whatwg-encoding: 3.1.1
+ whatwg-mimetype: 4.0.0
+ whatwg-url: 14.1.0
+ ws: 8.18.0
+ xml-name-validator: 5.0.0
+ transitivePeerDependencies:
+ - bufferutil
+ - supports-color
+ - utf-8-validate
+
+ jsesc@3.1.0: {}
+
+ json-buffer@3.0.1: {}
+
+ json-parse-even-better-errors@2.3.1: {}
+
+ json-schema-traverse@0.4.1: {}
+
+ json-stable-stringify-without-jsonify@1.0.1: {}
+
+ json5@2.2.3: {}
+
+ kareem@2.6.3: {}
+
+ keyv@4.5.4:
+ dependencies:
+ json-buffer: 3.0.1
+
+ kleur@3.0.3: {}
+
+ leven@3.1.0: {}
+
+ levn@0.4.1:
+ dependencies:
+ prelude-ls: 1.2.1
+ type-check: 0.4.0
+
+ lines-and-columns@1.2.4: {}
+
+ locate-path@5.0.0:
+ dependencies:
+ p-locate: 4.1.0
+
+ locate-path@6.0.0:
+ dependencies:
+ p-locate: 5.0.0
+
+ lodash.memoize@4.1.2: {}
+
+ lodash.merge@4.6.2: {}
+
+ lodash@4.17.21: {}
+
+ lru-cache@10.4.3: {}
+
+ lru-cache@11.0.2: {}
+
+ lru-cache@5.1.1:
+ dependencies:
+ yallist: 3.1.1
+
+ make-dir@4.0.0:
+ dependencies:
+ semver: 7.6.3
+
+ make-error@1.3.6: {}
+
+ makeerror@1.0.12:
+ dependencies:
+ tmpl: 1.0.5
+
+ math-intrinsics@1.1.0: {}
+
+ memjs@1.3.2: {}
+
+ memory-pager@1.5.0: {}
+
+ merge-stream@2.0.0: {}
+
+ merge2@1.4.1: {}
+
+ micromatch@4.0.8:
+ dependencies:
+ braces: 3.0.3
+ picomatch: 2.3.1
+
+ mime-db@1.52.0: {}
+
+ mime-types@2.1.35:
+ dependencies:
+ mime-db: 1.52.0
+
+ mime@1.6.0: {}
+
+ mimic-fn@2.1.0: {}
+
+ minimatch@3.1.2:
+ dependencies:
+ brace-expansion: 1.1.11
+
+ minimatch@5.1.6:
+ dependencies:
+ brace-expansion: 2.0.1
+
+ minimatch@9.0.3:
+ dependencies:
+ brace-expansion: 2.0.1
+
+ minimatch@9.0.5:
+ dependencies:
+ brace-expansion: 2.0.1
+
+ minimist@1.2.8: {}
+
+ minipass@7.1.2: {}
+
+ mjsunit.runner@0.1.3: {}
+
+ mkdirp@0.5.6:
+ dependencies:
+ minimist: 1.2.8
+
+ mongodb-connection-string-url@3.0.1:
+ dependencies:
+ '@types/whatwg-url': 11.0.5
+ whatwg-url: 13.0.0
+
+ mongodb@6.12.0:
+ dependencies:
+ '@mongodb-js/saslprep': 1.1.9
+ bson: 6.10.1
+ mongodb-connection-string-url: 3.0.1
+
+ mongoose@8.9.4:
+ dependencies:
+ bson: 6.10.1
+ kareem: 2.6.3
+ mongodb: 6.12.0
+ mpath: 0.9.0
+ mquery: 5.0.0
+ ms: 2.1.3
+ sift: 17.1.3
+ transitivePeerDependencies:
+ - '@aws-sdk/credential-providers'
+ - '@mongodb-js/zstd'
+ - gcp-metadata
+ - kerberos
+ - mongodb-client-encryption
+ - snappy
+ - socks
+ - supports-color
+
+ mpath@0.9.0: {}
+
+ mquery@5.0.0:
+ dependencies:
+ debug: 4.4.0
+ transitivePeerDependencies:
+ - supports-color
+
+ ms@2.1.3: {}
+
+ natural-compare@1.4.0: {}
+
+ natural@8.0.1:
+ dependencies:
+ afinn-165: 1.0.4
+ afinn-165-financialmarketnews: 3.0.0
+ apparatus: 0.0.10
+ dotenv: 16.4.7
+ http-server: 14.1.1
+ memjs: 1.3.2
+ mongoose: 8.9.4
+ pg: 8.13.1
+ redis: 4.7.0
+ safe-stable-stringify: 2.5.0
+ stopwords-iso: 1.1.0
+ sylvester: 0.0.12
+ underscore: 1.13.7
+ uuid: 9.0.1
+ wordnet-db: 3.1.14
+ transitivePeerDependencies:
+ - '@aws-sdk/credential-providers'
+ - '@mongodb-js/zstd'
+ - debug
+ - gcp-metadata
+ - kerberos
+ - mongodb-client-encryption
+ - pg-native
+ - snappy
+ - socks
+ - supports-color
+
+ node-int64@0.4.0: {}
+
+ node-releases@2.0.19: {}
+
+ normalize-path@3.0.0: {}
+
+ npm-run-path@4.0.1:
+ dependencies:
+ path-key: 3.1.1
+
+ nth-check@2.1.1:
+ dependencies:
+ boolbase: 1.0.0
+
+ nwsapi@2.2.16: {}
+
+ object-inspect@1.13.3: {}
+
+ once@1.4.0:
+ dependencies:
+ wrappy: 1.0.2
+
+ onetime@5.1.2:
+ dependencies:
+ mimic-fn: 2.1.0
+
+ opener@1.5.2: {}
+
+ optionator@0.9.4:
+ dependencies:
+ deep-is: 0.1.4
+ fast-levenshtein: 2.0.6
+ levn: 0.4.1
+ prelude-ls: 1.2.1
+ type-check: 0.4.0
+ word-wrap: 1.2.5
+
+ p-limit@2.3.0:
+ dependencies:
+ p-try: 2.2.0
+
+ p-limit@3.1.0:
+ dependencies:
+ yocto-queue: 0.1.0
+
+ p-locate@4.1.0:
+ dependencies:
+ p-limit: 2.3.0
+
+ p-locate@5.0.0:
+ dependencies:
+ p-limit: 3.1.0
+
+ p-try@2.2.0: {}
+
+ package-json-from-dist@1.0.1: {}
+
+ parent-module@1.0.1:
+ dependencies:
+ callsites: 3.1.0
+
+ parse-json@5.2.0:
+ dependencies:
+ '@babel/code-frame': 7.26.2
+ error-ex: 1.3.2
+ json-parse-even-better-errors: 2.3.1
+ lines-and-columns: 1.2.4
+
+ parse5-htmlparser2-tree-adapter@7.1.0:
+ dependencies:
+ domhandler: 5.0.3
+ parse5: 7.2.1
+
+ parse5-parser-stream@7.1.2:
+ dependencies:
+ parse5: 7.2.1
+
+ parse5@7.2.1:
+ dependencies:
+ entities: 4.5.0
+
+ path-exists@4.0.0: {}
+
+ path-is-absolute@1.0.1: {}
+
+ path-key@3.1.1: {}
+
+ path-parse@1.0.7: {}
+
+ path-scurry@1.11.1:
+ dependencies:
+ lru-cache: 10.4.3
+ minipass: 7.1.2
+
+ path-type@4.0.0: {}
+
+ pg-cloudflare@1.1.1:
+ optional: true
+
+ pg-connection-string@2.7.0: {}
+
+ pg-int8@1.0.1: {}
+
+ pg-pool@3.7.0(pg@8.13.1):
+ dependencies:
+ pg: 8.13.1
+
+ pg-protocol@1.7.0: {}
+
+ pg-types@2.2.0:
+ dependencies:
+ pg-int8: 1.0.1
+ postgres-array: 2.0.0
+ postgres-bytea: 1.0.0
+ postgres-date: 1.0.7
+ postgres-interval: 1.2.0
+
+ pg@8.13.1:
+ dependencies:
+ pg-connection-string: 2.7.0
+ pg-pool: 3.7.0(pg@8.13.1)
+ pg-protocol: 1.7.0
+ pg-types: 2.2.0
+ pgpass: 1.0.5
+ optionalDependencies:
+ pg-cloudflare: 1.1.1
+
+ pgpass@1.0.5:
+ dependencies:
+ split2: 4.2.0
+
+ picocolors@1.1.1: {}
+
+ picomatch@2.3.1: {}
+
+ pirates@4.0.6: {}
+
+ pkg-dir@4.2.0:
+ dependencies:
+ find-up: 4.1.0
+
+ playwright-core@1.49.0: {}
+
+ playwright@1.49.0:
+ dependencies:
+ playwright-core: 1.49.0
+ optionalDependencies:
+ fsevents: 2.3.2
+
+ portfinder@1.0.32:
+ dependencies:
+ async: 2.6.4
+ debug: 3.2.7
+ mkdirp: 0.5.6
+ transitivePeerDependencies:
+ - supports-color
+
+ postgres-array@2.0.0: {}
+
+ postgres-bytea@1.0.0: {}
+
+ postgres-date@1.0.7: {}
+
+ postgres-interval@1.2.0:
+ dependencies:
+ xtend: 4.0.2
+
+ prelude-ls@1.2.1: {}
+
+ pretty-format@29.7.0:
+ dependencies:
+ '@jest/schemas': 29.6.3
+ ansi-styles: 5.2.0
+ react-is: 18.3.1
+
+ prompts@2.4.2:
+ dependencies:
+ kleur: 3.0.3
+ sisteransi: 1.0.5
+
+ punycode@2.3.1: {}
+
+ pure-rand@6.1.0: {}
+
+ qs@6.13.1:
+ dependencies:
+ side-channel: 1.1.0
+
+ queue-microtask@1.2.3: {}
+
+ rate-limiter-flexible@5.0.4: {}
+
+ raw-body@3.0.0:
dependencies:
bytes: 3.1.2
http-errors: 2.0.0
iconv-lite: 0.6.3
unpipe: 1.0.0
- rechoir@0.6.2:
+ react-is@18.3.1: {}
+
+ readability@0.1.0:
dependencies:
- resolve: 1.22.8
+ htmlparser: 1.7.7
+ jsdom: 26.0.0
+ mjsunit.runner: 0.1.3
+ transitivePeerDependencies:
+ - bufferutil
+ - canvas
+ - supports-color
+ - utf-8-validate
+
+ redis@4.7.0:
+ dependencies:
+ '@redis/bloom': 1.2.0(@redis/client@1.6.0)
+ '@redis/client': 1.6.0
+ '@redis/graph': 1.1.1(@redis/client@1.6.0)
+ '@redis/json': 1.0.7(@redis/client@1.6.0)
+ '@redis/search': 1.2.0(@redis/client@1.6.0)
+ '@redis/time-series': 1.1.0(@redis/client@1.6.0)
- resolve-pkg-maps@1.0.0: {}
+ require-directory@2.1.1: {}
+
+ requires-port@1.0.0: {}
+
+ resolve-cwd@3.0.0:
+ dependencies:
+ resolve-from: 5.0.0
+
+ resolve-from@4.0.0: {}
+
+ resolve-from@5.0.0: {}
+
+ resolve.exports@2.0.3: {}
resolve@1.22.8:
dependencies:
@@ -573,42 +4666,362 @@ snapshots:
path-parse: 1.0.7
supports-preserve-symlinks-flag: 1.0.0
+ reusify@1.0.4: {}
+
+ rimraf@3.0.2:
+ dependencies:
+ glob: 7.2.3
+
+ rimraf@5.0.10:
+ dependencies:
+ glob: 10.4.5
+
+ rrweb-cssom@0.8.0: {}
+
+ run-parallel@1.2.0:
+ dependencies:
+ queue-microtask: 1.2.3
+
+ safe-buffer@5.1.2: {}
+
+ safe-stable-stringify@2.5.0: {}
+
safer-buffer@2.1.2: {}
+ saxes@6.0.0:
+ dependencies:
+ xmlchars: 2.2.0
+
+ secure-compare@3.0.1: {}
+
+ semver@6.3.1: {}
+
+ semver@7.6.3: {}
+
setprototypeof@1.2.0: {}
- shelljs@0.8.5:
+ shebang-command@2.0.0:
dependencies:
- glob: 7.2.3
- interpret: 1.4.0
- rechoir: 0.6.2
+ shebang-regex: 3.0.0
+
+ shebang-regex@3.0.0: {}
- shx@0.3.4:
+ side-channel-list@1.0.0:
dependencies:
- minimist: 1.2.8
- shelljs: 0.8.5
+ es-errors: 1.3.0
+ object-inspect: 1.13.3
+
+ side-channel-map@1.0.1:
+ dependencies:
+ call-bound: 1.0.3
+ es-errors: 1.3.0
+ get-intrinsic: 1.2.7
+ object-inspect: 1.13.3
+
+ side-channel-weakmap@1.0.2:
+ dependencies:
+ call-bound: 1.0.3
+ es-errors: 1.3.0
+ get-intrinsic: 1.2.7
+ object-inspect: 1.13.3
+ side-channel-map: 1.0.1
+
+ side-channel@1.1.0:
+ dependencies:
+ es-errors: 1.3.0
+ object-inspect: 1.13.3
+ side-channel-list: 1.0.0
+ side-channel-map: 1.0.1
+ side-channel-weakmap: 1.0.2
+
+ sift@17.1.3: {}
+
+ signal-exit@3.0.7: {}
+
+ signal-exit@4.1.0: {}
+
+ sisteransi@1.0.5: {}
+
+ slash@3.0.0: {}
+
+ source-map-support@0.5.13:
+ dependencies:
+ buffer-from: 1.1.2
+ source-map: 0.6.1
+
+ source-map@0.6.1: {}
+
+ sparse-bitfield@3.0.3:
+ dependencies:
+ memory-pager: 1.5.0
+
+ split2@4.2.0: {}
+
+ sprintf-js@1.0.3: {}
+
+ stack-utils@2.0.6:
+ dependencies:
+ escape-string-regexp: 2.0.0
statuses@2.0.1: {}
+ stopwords-iso@1.1.0: {}
+
+ string-length@4.0.2:
+ dependencies:
+ char-regex: 1.0.2
+ strip-ansi: 6.0.1
+
+ string-width@4.2.3:
+ dependencies:
+ emoji-regex: 8.0.0
+ is-fullwidth-code-point: 3.0.0
+ strip-ansi: 6.0.1
+
+ string-width@5.1.2:
+ dependencies:
+ eastasianwidth: 0.2.0
+ emoji-regex: 9.2.2
+ strip-ansi: 7.1.0
+
+ strip-ansi@6.0.1:
+ dependencies:
+ ansi-regex: 5.0.1
+
+ strip-ansi@7.1.0:
+ dependencies:
+ ansi-regex: 6.1.0
+
+ strip-bom@4.0.0: {}
+
+ strip-final-newline@2.0.0: {}
+
+ strip-json-comments@3.1.1: {}
+
+ supports-color@7.2.0:
+ dependencies:
+ has-flag: 4.0.0
+
+ supports-color@8.1.1:
+ dependencies:
+ has-flag: 4.0.0
+
supports-preserve-symlinks-flag@1.0.0: {}
+ sylvester@0.0.12: {}
+
+ symbol-tree@3.2.4: {}
+
+ test-exclude@6.0.0:
+ dependencies:
+ '@istanbuljs/schema': 0.1.3
+ glob: 7.2.3
+ minimatch: 3.1.2
+
+ text-table@0.2.0: {}
+
+ tldts-core@6.1.71: {}
+
+ tldts@6.1.71:
+ dependencies:
+ tldts-core: 6.1.71
+
+ tmpl@1.0.5: {}
+
+ to-regex-range@5.0.1:
+ dependencies:
+ is-number: 7.0.0
+
toidentifier@1.0.1: {}
- tsx@4.19.2:
+ tough-cookie@5.1.0:
+ dependencies:
+ tldts: 6.1.71
+
+ tr46@4.1.1:
+ dependencies:
+ punycode: 2.3.1
+
+ tr46@5.0.0:
dependencies:
- esbuild: 0.23.1
- get-tsconfig: 4.8.1
+ punycode: 2.3.1
+
+ ts-api-utils@1.4.3(typescript@5.7.2):
+ dependencies:
+ typescript: 5.7.2
+
+ ts-jest@29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@types/node@20.17.12)(typescript@5.7.2)))(typescript@5.7.2):
+ dependencies:
+ bs-logger: 0.2.6
+ ejs: 3.1.10
+ fast-json-stable-stringify: 2.1.0
+ jest: 29.7.0(@types/node@20.17.12)(ts-node@10.9.2(@types/node@20.17.12)(typescript@5.7.2))
+ jest-util: 29.7.0
+ json5: 2.2.3
+ lodash.memoize: 4.1.2
+ make-error: 1.3.6
+ semver: 7.6.3
+ typescript: 5.7.2
+ yargs-parser: 21.1.1
optionalDependencies:
- fsevents: 2.3.3
+ '@babel/core': 7.26.0
+ '@jest/transform': 29.7.0
+ '@jest/types': 29.6.3
+ babel-jest: 29.7.0(@babel/core@7.26.0)
+
+ ts-node@10.9.2(@types/node@20.17.12)(typescript@5.7.2):
+ dependencies:
+ '@cspotcode/source-map-support': 0.8.1
+ '@tsconfig/node10': 1.0.11
+ '@tsconfig/node12': 1.0.11
+ '@tsconfig/node14': 1.0.3
+ '@tsconfig/node16': 1.0.4
+ '@types/node': 20.17.12
+ acorn: 8.14.0
+ acorn-walk: 8.3.4
+ arg: 4.1.3
+ create-require: 1.1.1
+ diff: 4.0.2
+ make-error: 1.3.6
+ typescript: 5.7.2
+ v8-compile-cache-lib: 3.0.1
+ yn: 3.1.1
turndown@7.2.0:
dependencies:
'@mixmark-io/domino': 2.2.0
+ type-check@0.4.0:
+ dependencies:
+ prelude-ls: 1.2.1
+
+ type-detect@4.0.8: {}
+
+ type-fest@0.20.2: {}
+
+ type-fest@0.21.3: {}
+
typescript@5.7.2: {}
+ underscore@1.13.7: {}
+
+ undici-types@6.19.8: {}
+
+ undici@6.21.0: {}
+
+ union@0.5.0:
+ dependencies:
+ qs: 6.13.1
+
unpipe@1.0.0: {}
+ update-browserslist-db@1.1.2(browserslist@4.24.4):
+ dependencies:
+ browserslist: 4.24.4
+ escalade: 3.2.0
+ picocolors: 1.1.1
+
+ uri-js@4.4.1:
+ dependencies:
+ punycode: 2.3.1
+
+ url-join@4.0.1: {}
+
+ uuid@9.0.1: {}
+
+ v8-compile-cache-lib@3.0.1: {}
+
+ v8-to-istanbul@9.3.0:
+ dependencies:
+ '@jridgewell/trace-mapping': 0.3.25
+ '@types/istanbul-lib-coverage': 2.0.6
+ convert-source-map: 2.0.0
+
+ w3c-xmlserializer@5.0.0:
+ dependencies:
+ xml-name-validator: 5.0.0
+
+ walker@1.0.8:
+ dependencies:
+ makeerror: 1.0.12
+
+ webidl-conversions@7.0.0: {}
+
+ whatwg-encoding@2.0.0:
+ dependencies:
+ iconv-lite: 0.6.3
+
+ whatwg-encoding@3.1.1:
+ dependencies:
+ iconv-lite: 0.6.3
+
+ whatwg-mimetype@4.0.0: {}
+
+ whatwg-url@13.0.0:
+ dependencies:
+ tr46: 4.1.1
+ webidl-conversions: 7.0.0
+
+ whatwg-url@14.1.0:
+ dependencies:
+ tr46: 5.0.0
+ webidl-conversions: 7.0.0
+
+ which@2.0.2:
+ dependencies:
+ isexe: 2.0.0
+
+ word-wrap@1.2.5: {}
+
+ wordnet-db@3.1.14: {}
+
+ wrap-ansi@7.0.0:
+ dependencies:
+ ansi-styles: 4.3.0
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+
+ wrap-ansi@8.1.0:
+ dependencies:
+ ansi-styles: 6.2.1
+ string-width: 5.1.2
+ strip-ansi: 7.1.0
+
wrappy@1.0.2: {}
+ write-file-atomic@4.0.2:
+ dependencies:
+ imurmurhash: 0.1.4
+ signal-exit: 3.0.7
+
+ ws@8.18.0: {}
+
+ xml-name-validator@5.0.0: {}
+
+ xmlchars@2.2.0: {}
+
+ xtend@4.0.2: {}
+
+ y18n@5.0.8: {}
+
+ yallist@3.1.1: {}
+
+ yallist@4.0.0: {}
+
+ yargs-parser@21.1.1: {}
+
+ yargs@17.7.2:
+ dependencies:
+ cliui: 8.0.1
+ escalade: 3.2.0
+ get-caller-file: 2.0.5
+ require-directory: 2.1.1
+ string-width: 4.2.3
+ y18n: 5.0.8
+ yargs-parser: 21.1.1
+
+ yn@3.1.1: {}
+
+ yocto-queue@0.1.0: {}
+
zod@3.23.8: {}
diff --git a/prompt_generator.py b/prompt_generator.py
new file mode 100644
index 0000000..b181529
--- /dev/null
+++ b/prompt_generator.py
@@ -0,0 +1,245 @@
+import json
+import boto3
+import os
+from typing import Dict, List
+import subprocess
+import json
+from datetime import datetime, timezone
+
+class PromptGenerator:
+ def __init__(self):
+ self.bedrock = boto3.client(
+ service_name='bedrock-runtime',
+ region_name=os.getenv('AWS_REGION'),
+ aws_access_key_id=os.getenv('AWS_ACCESS_KEY_ID'),
+ aws_secret_access_key=os.getenv('AWS_SECRET_ACCESS_KEY')
+ )
+ self.model_id = "anthropic.claude-3-5-sonnet-20241022-v2:0"
+
+ def _gather_topic_info(self, topic: str) -> str:
+ """Gather initial information about the topic using the research system."""
+ try:
+ print("\n[INFO] Starting topic information gathering process...")
+ print(f"[INFO] Topic: {topic}")
+
+ # Ensure TypeScript is compiled
+ if not os.path.exists('dist/quick_research.js'):
+ print("[BUILD] TypeScript code not found, attempting compilation...")
+ try:
+ subprocess.run(['npm', 'run', 'build'], check=True)
+ print("[BUILD] Successfully compiled TypeScript code")
+ except subprocess.CalledProcessError as e:
+ print(f"[BUILD] Failed to compile TypeScript: {str(e)}")
+ return ""
+ else:
+ print("[BUILD] Found compiled TypeScript code")
+
+ # Run quick research
+ print("\n[RESEARCH] Initiating quick research process...")
+ print(f"[CMD] Executing: node dist/quick_research.js {topic}")
+
+ process = subprocess.Popen(
+ ['node', 'dist/quick_research.js', topic],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ encoding='utf-8'
+ )
+
+ # Wait for quick research to complete (max 600 seconds / 10 minutes)
+ try:
+ print("[WAIT] Waiting for research process (timeout: 600s)...")
+ stdout, stderr = process.communicate(timeout=600)
+
+ print(f"[DEBUG] Process return code: {process.returncode}")
+ if stderr:
+ print(f"[DEBUG] Process stderr: {stderr}")
+ if stdout:
+ print(f"[DEBUG] Process stdout length: {len(stdout)} characters")
+
+ if process.returncode != 0:
+ print(f"[ERROR] Quick research failed: {stderr}")
+ print("[INFO] Falling back to direct Claude prompt generation")
+ return ""
+
+ # Extract research results from stdout
+ if "=== Quick Research Results ===" in stdout:
+ context = stdout.split("=== Quick Research Results ===")[1].strip()
+ if context:
+ print("[INFO] Successfully gathered topic context")
+ print(f"[DEBUG] Context length: {len(context)} characters")
+ return context
+
+ print("[WARN] No research results found in process output")
+ print("[INFO] Falling back to direct Claude prompt generation")
+ return ""
+
+ except subprocess.TimeoutExpired:
+ process.kill()
+ print("[WARN] Quick research timed out after 600 seconds (10 minutes)")
+ print("[DEBUG] Attempting to collect any partial output...")
+ try:
+ stdout, stderr = process.communicate()
+ if stdout:
+ print(f"[DEBUG] Partial stdout length: {len(stdout)} characters")
+ if stderr:
+ print(f"[DEBUG] Error output: {stderr}")
+ except:
+ print("[DEBUG] Failed to collect partial output")
+ print("[INFO] Falling back to direct Claude prompt generation")
+ return ""
+
+ except Exception as e:
+ print(f"[ERROR] Unexpected error during topic info gathering: {str(e)}")
+ print("[DEBUG] Error type:", type(e).__name__)
+ print("[INFO] Falling back to direct Claude prompt generation")
+ return ""
+
+ def generate_improved_prompt(self, topic: str) -> str:
+ """Generate an improved research prompt for the given topic."""
+ print("\n[STEP] Starting improved prompt generation process...")
+ print(f"[INFO] Generating prompt for topic: {topic}")
+
+ # First gather information about the topic
+ print("[STEP] Attempting to gather topic context...")
+ topic_info = self._gather_topic_info(topic)
+
+ if topic_info:
+ print("[INFO] Successfully gathered topic context")
+ print(f"[DEBUG] Context length: {len(topic_info)} characters")
+ else:
+ print("[INFO] No context gathered, using base template")
+
+ print("[STEP] Creating prompt with Claude 3.5...")
+
+ # Create a prompt that incorporates the gathered information
+ prompt = (
+ f"You are an expert research prompt engineer. Your task is to create a comprehensive "
+ f"research prompt for: \"{topic}\"\n\n"
+ f"Context about the topic:\n{topic_info if topic_info else 'No additional context available.'}\n\n"
+ f"Based on the above context about what this topic is, create a tailored research plan that:\n\n"
+ f"1. Focuses on the most relevant types of sources for this specific content\n"
+ f"2. Includes appropriate metrics and analysis methods for this type of work\n"
+ f"3. Considers the historical and current context\n"
+ f"4. Examines the key themes and claims made\n"
+ f"5. Evaluates the impact and implications\n"
+ f"6. Addresses any relevant criticisms or controversies\n\n"
+ f"Format your response as a clear research plan with:\n"
+ f"- Numbered main sections that match the content type\n"
+ f"- Specific, actionable research tasks\n"
+ f"- Appropriate depth and scope for this topic\n"
+ f"- Clear connection to the topic's context and purpose\n\n"
+ f"Begin your response with \"Research and analyze {topic} by:\" followed by your tailored research plan.\n"
+ f"Make sure the plan reflects understanding of what this topic actually is."
+ )
+
+ try:
+ print("[API] Preparing Bedrock API request...")
+ request_body = {
+ "messages": [
+ {
+ "role": "user",
+ "content": prompt
+ }
+ ],
+ "max_tokens": 4000,
+ "temperature": 0.7,
+ "top_p": 0.999,
+ "anthropic_version": "bedrock-2023-05-31"
+ }
+ print(f"[DEBUG] Request max_tokens: {request_body['max_tokens']}")
+ print(f"[DEBUG] Request temperature: {request_body['temperature']}")
+
+ print("[API] Sending request to Bedrock Claude 3.5...")
+ response = self.bedrock.invoke_model(
+ modelId=self.model_id,
+ body=json.dumps(request_body)
+ )
+
+ print("[API] Processing Bedrock response...")
+ response_body = json.loads(response.get('body').read())
+
+ if 'content' not in response_body or not response_body['content']:
+ print("[ERROR] Invalid response structure from Bedrock")
+ print("[DEBUG] Response body:", response_body)
+ print("[INFO] Falling back to default prompt template")
+ return self._get_fallback_prompt(topic)
+
+ improved_prompt = response_body['content'][0].get('text', '')
+ print(f"[DEBUG] Generated prompt length: {len(improved_prompt)} characters")
+
+ print("[STEP] Formatting final prompt...")
+ formatted_prompt = self._format_prompt(improved_prompt)
+ print("[SUCCESS] Successfully generated improved prompt")
+ return formatted_prompt
+
+ except Exception as e:
+ print(f"[ERROR] Failed to generate improved prompt: {str(e)}")
+ print("[DEBUG] Error type:", type(e).__name__)
+ print("[INFO] Falling back to default prompt template")
+ return self._get_fallback_prompt(topic)
+
+ def _format_prompt(self, prompt: str) -> str:
+ """Format the generated prompt with consistent styling."""
+ sections = prompt.split('\n')
+ formatted_sections = []
+
+ for section in sections:
+ # Clean up section formatting
+ section = section.strip()
+ if section:
+ # Add proper indentation for subsections
+ if section.startswith('- '):
+ section = ' ' + section
+ formatted_sections.append(section)
+
+ # Join with double newlines for better readability
+ formatted_prompt = '\n'.join(formatted_sections)
+
+ # Wrap in XML-style tags for clear identification
+ return f"\n{formatted_prompt}\n"
+
+ def _get_fallback_prompt(self, topic: str) -> str:
+ """Generate a fallback prompt if the API call fails."""
+ return f"""
+Research and analyze {topic} by:
+
+(1) Find peer-reviewed publications and technical papers from leading institutions and organizations in this field.
+
+(2) Find official documentation, white papers, and public statements from major companies and organizations.
+
+(3) Find and analyze concrete metrics and benchmarks, including:
+ - Performance measurements
+ - Implementation success rates
+ - Adoption patterns
+ - Technical limitations
+
+(4) Find information about current and emerging technologies, including:
+ - Technical specifications
+ - Implementation methodologies
+ - Integration approaches
+ - Best practices
+
+(5) Find expert analysis and academic research on:
+ - Current state of the field
+ - Future projections
+ - Potential impacts
+ - Development patterns
+
+(6) Find documentation of:
+ - Safety measures
+ - Best practices
+ - Regulatory frameworks
+ - Risk assessments
+
+This structured approach ensures comprehensive coverage while maintaining focus on credible sources and concrete developments.
+"""
+
+def main():
+ """Test the prompt generator."""
+ generator = PromptGenerator()
+ test_topic = "AI Safety and Alignment Methods 2025"
+ improved_prompt = generator.generate_improved_prompt(test_topic)
+ print(improved_prompt)
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/quantum-deep-research-report.txt b/quantum-deep-research-report.txt
new file mode 100644
index 0000000..d9899f4
--- /dev/null
+++ b/quantum-deep-research-report.txt
@@ -0,0 +1,15 @@
+Deep Research Report on Quantum Computing Advancements
+
+Sources:
+1. [Quantum Computers News](https://www.sciencedaily.com/news/computers_math/quantum_computers/)
+2. [2025 Will See Huge Advances in Quantum Computing. So What is a Quantum Chip And How Does it Work?](https://thequantuminsider.com/2025/01/08/2025-will-see-huge-advances-in-quantum-computing-so-what-is-a-quantum-chip-and-how-does-it-work/)
+3. [5 breakthroughs made possible by quantum technologies](https://www.polytechnique-insights.com/en/columns/science/5-breakthroughs-made-possible-by-quantum-technologies/)
+4. [Quantum Computing: Developments in the UK and US | Inside Privacy](https://www.insideprivacy.com/data-privacy/quantum-computing-developments-in-the-uk-and-us/)
+5. [Exploring the Latest Quantum Computing Advancements in 2024 - FirstIgnite](https://firstignite.com/exploring-the-latest-quantum-computing-advancements-in-2024/)
+6. [World Quantum Day 2024: The latest developments in quantum science and technology | Pritzker School of Molecular Engineering | The University of Chicago](https://pme.uchicago.edu/news/world-quantum-day-2024-latest-developments-quantum-science-and-technology)
+7. [Quantum Computing: Potential and Challenges ahead - Plain Concepts](https://www.plainconcepts.com/quantum-computing-potential-challenges/)
+8. [Quantum Technology: Applications and Implications](https://www.csis.org/analysis/quantum-technology-applications-and-implications)
+9. [Quantum computing technology pushes for IT advantage | TechTarget](https://www.techtarget.com/searchcio/feature/Quantum-computing-technology-pushes-for-IT-advantage)
+10. [References](https://www.wevolver.com/article/breakthroughs-in-quantum-computing)
+11. [What's next for quantum computing | MIT Technology Review](https://www.technologyreview.com/2023/01/06/1066317/whats-next-for-quantum-computing/)
+12. [What is quantum computing?](https://www.ibm.com/think/topics/quantum-computing)
\ No newline at end of file
diff --git a/quantum-parallel-report.txt b/quantum-parallel-report.txt
new file mode 100644
index 0000000..22360c7
--- /dev/null
+++ b/quantum-parallel-report.txt
@@ -0,0 +1,93 @@
+Parallel Search Report on Quantum Computing Advancements
+
+1. **Quantum Computing advancements**
+ - [Quantum computing technology pushes for IT advantage](https://www.techtarget.com/searchcio/feature/Quantum-computing-technology-pushes-for-IT-advantage): Nov 27, 2024 — Quantum computing technology, evolving in GenAI's shadow, looks for advances to help it gain 'quantum advantage.' Read about trends in this ...
+ - [Quantum Computing Is Coming Faster Than You Think](https://www.forbes.com/sites/tiriasresearch/2023/11/28/quantum-computing-is-coming-faster-than-you-think/): Nov 28, 2023 — Another reason is the continued advancements being made in quantum computing is improvements in quantum chips, control logic, systems, and ...
+ - [Breakthroughs in Quantum Computing](https://www.wevolver.com/article/breakthroughs-in-quantum-computing): Aug 19, 2024 — Another groundbreaking advancement is the teleportation of quantum information over distances exceeding 1,200km, facilitated by the Micius ...
+ - [What's next for quantum computing](https://www.technologyreview.com/2023/01/06/1066317/whats-next-for-quantum-computing/): Jan 6, 2023 — In 2023, progress in quantum computing will be defined less by big hardware announcements than by researchers consolidating years of hard work.
+ - [Quantum Computers News](https://www.sciencedaily.com/news/computers_math/quantum_computers/): Jan. 9, 2025 — Researchers have recently achieved a significant breakthrough in the development of next-generation carbon-based quantum materials, opening new ...
+ - [The latest developments in quantum science and technology ...](https://pme.uchicago.edu/news/world-quantum-day-2024-latest-developments-quantum-science-and-technology): Apr 12, 2024 — Many more advancements in quantum technology are yet to come. Secure communication through metropolitan-scale entangled quantum networks, ...
+ - [2025 Will See Huge Advances in Quantum Computing. So ...](https://thequantuminsider.com/2025/01/08/2025-will-see-huge-advances-in-quantum-computing-so-what-is-a-quantum-chip-and-how-does-it-work/): 7 days ago — Many experts are expecting big advance in quantum computing in 2025, but what is a quantum chip and how does it work?
+ - [Quantum Computing in 2024: Breakthroughs, Challenges ...](https://microtime.com/quantum-computing-in-2024-breakthroughs-challenges-and-what-lies-ahead/): Sep 5, 2024 — 2024 has been a year of significant progress in the field of QC, with several key breakthroughs that are bringing us closer to realizing its potential.
+ - [Advancements in Quantum Computing—Viewpoint](https://link.springer.com/article/10.1007/s13222-024-00467-4): by SML Pfaendler · 2024 · Cited by 10 — This article introduces key technologies and discussion points revolving around the evaluation of quantum computing technology readiness and adoption.
+
+2. **Latest in Quantum Computing**
+ - [Quantum Computers News](https://www.sciencedaily.com/news/computers_math/quantum_computers/): Quantum Computer Research. Read the latest news in developing quantum computers.
+ - [The Quantum Insider: Quantum Computing News & Top Stories](https://thequantuminsider.com/): Find the latest Quantum Computing news, data, market research, and insights. To stay up to date with the quantum market click here!
+ - [Quantum computing](https://news.mit.edu/topic/quantum-computing): Quantum computing ; Physicists measure quantum geometry for the first time · January 13, 2025 ; MIT physicists predict exotic form of matter with potential for ...
+ - [Quantum Computing - latest research news and features](https://phys.org/tags/quantum+computing/): All the latest science news on quantum computing from Phys.org. Find the latest news, advancements, and breakthroughs.
+ - [The latest developments in quantum science and technology ...](https://pme.uchicago.edu/news/world-quantum-day-2024-latest-developments-quantum-science-and-technology): Apr 12, 2024 — Many more advancements in quantum technology are yet to come. Secure communication through metropolitan-scale entangled quantum networks, ...
+ - [Meet Willow, our state-of-the-art quantum chip](https://blog.google/technology/research/google-willow-quantum-chip/): Dec 9, 2024 — Google has developed a new quantum chip called Willow, which significantly reduces errors as it scales up, a major breakthrough in quantum error correction.
+ - [Quantum Computing News, Quantum Articles, Quantum Industry](https://quantumzeitgeist.com/): Quantum Computing News and Quantum News. Technology News from around the planet. Exciting Latest Developments in Quantum Tech.
+
+3. **Quantum Computing technology news**
+ - [The Quantum Insider: Quantum Computing News & Top Stories](https://thequantuminsider.com/): Find the latest Quantum Computing news, data, market research, and insights. To stay up to date with the quantum market click here!
+ - [Quantum Computers News](https://www.sciencedaily.com/news/computers_math/quantum_computers/): The technology could transform computing, telecommunications, and ... Novel Graphene Ribbons Poised to Advance Quantum Technologies. Jan. 9, 2025 — Researchers ...
+ - [Quantum computing](https://news.mit.edu/topic/quantum-computing): Quantum computing. Download RSS feed: News Articles / In the Media / Audio. Displaying 1 - 15 of 182 news articles related to this topic. Show: News Articles.
+ - [Quantum Computing - latest research news and features](https://phys.org/tags/quantum+computing/): All the latest science news on quantum computing from Phys.org. Find the latest news, advancements, and breakthroughs.
+ - [Quantum computing - BBC News](https://www.bbc.com/news/topics/cyz9ex69xwlt): From unhackable communication networks to powerful computers, quantum technology promises huge advances.
+ - [Quantum Computing | Latest News, Photos & Videos](https://www.wired.com/tag/quantum-computing/): Find the latest Quantum Computing news from WIRED. See related science and technology articles, photos, slideshows and videos.
+ - [Quantum Computing News, Quantum Articles, Quantum Industry](https://quantumzeitgeist.com/): Quantum Computing News and Quantum News. Technology News from around the planet. Exciting Latest Developments in Quantum Tech.
+
+4. **Quantum Computing breakthroughs**
+ - [Breakthroughs in Quantum Computing](https://www.wevolver.com/article/breakthroughs-in-quantum-computing): Aug 19, 2024 — 2023 was a landmark year for quantum computing, with innovative breakthroughs promising to reshape our technological landscape and revolutionize how we solve ...
+ - [Quantum Computing in 2024: Breakthroughs, Challenges ...](https://microtime.com/quantum-computing-in-2024-breakthroughs-challenges-and-what-lies-ahead/): Sep 5, 2024 — 2024 has been a year of significant progress in the field of QC, with several key breakthroughs that are bringing us closer to realizing its potential.
+ - [Quantum Computers News](https://www.sciencedaily.com/news/computers_math/quantum_computers/): 9, 2025 — Researchers have recently achieved a significant breakthrough in the development of next-generation carbon-based quantum materials, opening new ...
+ - [Professor Achieves Major Quantum Computing Breakthrough](https://news.northeastern.edu/2024/07/12/quantum-computing-breakthrough-manufacturing/): Jul 12, 2024 — Northeastern professor achieves major breakthrough in the manufacture of quantum computing components. Assistant professor Yoseob Yoon has ...
+ - ['A truly remarkable breakthrough': Google's new quantum ...](https://www.nature.com/articles/d41586-024-04028-3): Dec 9, 2024 — Researchers at Google have built a chip that has enabled them to demonstrate the first 'below threshold' quantum calculations.
+ - [How Quantum AI Will Reshape Our World](https://www.forbes.com/sites/bernardmarr/2024/10/08/the-next-breakthrough-in-artificial-intelligence-how-quantum-ai-will-reshape-our-world/): Oct 8, 2024 — Quantum AI, the fusion of quantum computing and artificial intelligence, is poised to revolutionize industries from finance to healthcare.
+ - [Quantum computing takes a giant leap with breakthrough ...](https://www.earth.com/news/quantum-computing-giant-leap-forward-breakthrough-ultra-pure-silicon-discovery/): May 12, 2024 — Scientists have produced an enhanced, ultra-pure form of silicon that is crucial for paving the way towards scalable quantum computing.
+ - [DARPA-Funded Research Leads to Quantum Computing ...](https://www.darpa.mil/news/2023/quantum-computing-breakthrough): Dec 6, 2023 — DARPA-funded research leads to quantum computing breakthrough. Harvard-led team develops novel logical qubits to enable scalable quantum computers.
+ - [Google Makes a Major Quantum Computing Breakthrough](https://www.scientificamerican.com/article/google-makes-a-major-quantum-computing-breakthrough/): Dec 9, 2024 — Researchers at Google created a silicon chip with 105 qubits, quantum counterparts to classical bits. Then they linked up multiple physical ...
+
+5. **Quantum Computing research updates**
+ - [Quantum Computers News](https://www.sciencedaily.com/news/computers_math/quantum_computers/): Jan. 9, 2025 — Researchers have recently achieved a significant breakthrough in the development of next-generation carbon-based quantum materials, opening new ...
+ - [Quantum Computing - latest research news and features](https://phys.org/tags/quantum+computing/): All the latest science news on quantum computing from Phys.org. Find the latest news, advancements, and breakthroughs.
+ - [Quantum computing](https://news.mit.edu/topic/quantum-computing): MIT physicists predict exotic form of matter with potential for quantum computing.
+ - [The Quantum Insider: Quantum Computing News & Top Stories](https://thequantuminsider.com/): Find the latest Quantum Computing news, data, market research, and insights. To stay up to date with the quantum market click here!
+ - [Quantum Computing News -- ScienceDaily](https://www.sciencedaily.com/news/matter_energy/quantum_computing/): 9, 2025 — Researchers have recently achieved a significant breakthrough in the development of next-generation carbon-based quantum materials, opening new ...
+ - [Quantum Computing](https://research.ibm.com/quantum-computing): We're inventing what's next in quantum research. Explore our recent work, access unique toolkits, and discover the breadth of topics that matter to us.
+ - [Quantum information - Latest research and news](https://www.nature.com/subjects/quantum-information): Quantum information systems could be able to transmit data that is fundamentally secure and solve problems that are beyond the power of modern computers. Latest ...
+ - [Quantum Computing News](https://scitechdaily.com/tag/quantum-computing/): Quantum computing is an advanced field of computing that leverages the principles of quantum mechanics to process information in fundamentally different ways.
+ - [Quantum Computing in 2024: Breakthroughs, Challenges ...](https://microtime.com/quantum-computing-in-2024-breakthroughs-challenges-and-what-lies-ahead/): Sep 5, 2024 — 2024 has been a year of significant progress in the field of QC, with several key breakthroughs that are bringing us closer to realizing its potential.
+
+6. **Quantum Computing innovations**
+ - [Breakthroughs in Quantum Computing](https://www.wevolver.com/article/breakthroughs-in-quantum-computing): Aug 19, 2024 — Another groundbreaking advancement is the teleportation of quantum information over distances exceeding 1,200km, facilitated by the Micius ...
+ - [Quantum computing: What leaders need to know now](https://mitsloan.mit.edu/ideas-made-to-matter/quantum-computing-what-leaders-need-to-know-now): Jan 11, 2024 — Quantum computing applies the laws of quantum mechanics to simulate and solve complex problems that are too difficult for the current genre of ...
+ - [Quantum Industry Explained: Applications, Innovations & ...](https://thequantuminsider.com/2024/02/05/quantum-industry-explained-applications-innovations-challenges/): Feb 5, 2024 — Quantum technology offers significant potential for innovation in various sectors including computing, communications, and sensing.
+ - [10 Quantum Computing Applications & Examples to Know](https://builtin.com/hardware/quantum-computing-applications): 10 Quantum Computing Applications to Know · Artificial intelligence · Better batteries · Cleaner fertilization · Cybersecurity · Drug development · Electronic ...
+ - [Quantum Computing Is Coming Faster Than You Think](https://www.forbes.com/sites/tiriasresearch/2023/11/28/quantum-computing-is-coming-faster-than-you-think/): Nov 28, 2023 — Another reason is the continued advancements being made in quantum computing is improvements in quantum chips, control logic, systems, and ...
+ - [What Is Quantum Computing?](https://www.ibm.com/think/topics/quantum-computing): Aug 5, 2024 — Explore IBM Quantum's latest innovations, research breakthroughs, and career opportunities as we push the boundaries of quantum computing.
+ - [Exploring the Latest Quantum Computing Advancements in ...](https://firstignite.com/exploring-the-latest-quantum-computing-advancements-in-2024/): Jul 11, 2024 — In 2024, the quantum computing landscape is set to witness exciting innovations. Key trends include continued efforts toward quantum supremacy.
+ - [Quantum Computing | Advancement of Innovations](https://www.nvidia.com/en-us/solutions/quantum-computing/): To prepare for a quantum-accelerated future, governments, universities, and industries are investing in hardware, software, and algorithm development.
+
+7. **Quantum Computing trends**
+ - [Emerging Trends in Quantum Computing for Scientific and ...](https://www.zuken.com/us/blog/emerging-trends-in-quantum-computing-for-scientific-and-industrial-applications/): In this post, we'll discuss trends for scientific and industrial applications and learn how Zuken's CR-8000 is supporting this transition.
+ - [What is quantum computing?](https://www.mckinsey.com/featured-insights/mckinsey-explainers/what-is-quantum-computing): Apr 5, 2024 — Quantum computing has so much promise and momentum that McKinsey has identified it as one of the next big trends in tech. Quantum computing ...
+ - [Quantum Computing Explained: A Must-Read for Executives](https://www.gartner.com/en/articles/quantum-computing): Sep 20, 2024 — Learn how quantum computing and other technology trends align with your digital ambitions. Plus, how to integrate them into your strategic ...
+ - [What's next for quantum computing](https://www.technologyreview.com/2023/01/06/1066317/whats-next-for-quantum-computing/): Jan 6, 2023 — In 2023, progress in quantum computing will be defined less by big hardware announcements than by researchers consolidating years of hard work.
+ - [The Rise of Quantum Computing](https://www.mckinsey.com/featured-insights/the-rise-of-quantum-computing): Accelerating technological breakthroughs, increasing investment flows, start-up proliferation, and promises of capable quantum systems by 2030 signal it's time ...
+ - [Quantum Computing Market 2024-2044: Technology, ...](https://www.idtechex.com/en/research-report/quantum-computing-market-2024-2044-technology-trends-players-forecasts/996): 20-year market forecasts for quantum computer hardware by volume (i.e., number of systems sold) and revenue. Individual forecast lines are available for eight ...
+ - [Future of Quantum Computing & 7 QC trends in 2025](https://research.aimultiple.com/future-of-quantum-computing/): Jan 7, 2025 — Future of Quantum Computing & 7 QC trends in 2025 ... Quantum computing can be a game-changer in fields such as cryptography, chemistry, material ...
+ - [Quantum cloud computing: Trends and challenges](https://www.sciencedirect.com/science/article/pii/S2949948824000271): by M Golec · 2024 · Cited by 14 — This article presents the vision and challenges for the quantum cloud computing paradigm that will emerge with the integration of quantum and cloud computing.
+ - [The Top Six Quantum Computing Trends for 2024](https://ai-techpark.com/the-top-six-quantum-computing-trends-for-2024/): May 9, 2024 — The Top Six Quantum Computing Trends for 2024 · 1. Quantum-Sensing Technologies · 2. Quantum-Safe Cryptography · 3. Quantum Machine Learning · 4 ...
+
+8. **Quantum Computing developments**
+ - [The latest developments in quantum science and technology ...](https://pme.uchicago.edu/news/world-quantum-day-2024-latest-developments-quantum-science-and-technology): Apr 12, 2024 — Many more advancements in quantum technology are yet to come. Secure communication through metropolitan-scale entangled quantum networks, ...
+ - [Quantum Computers News](https://www.sciencedaily.com/news/computers_math/quantum_computers/): 9, 2025 — Researchers have recently achieved a significant breakthrough in the development of next-generation carbon-based quantum materials, opening new ...
+ - [Breakthroughs in Quantum Computing](https://www.wevolver.com/article/breakthroughs-in-quantum-computing): Aug 19, 2024 — Another exciting academic-led development in quantum computing is its application in simulating molecular structures at the atomic scale. This ...
+ - [Quantum Computing: Developments in the UK and US](https://www.insideprivacy.com/data-privacy/quantum-computing-developments-in-the-uk-and-us/): Aug 9, 2024 — This update focuses on how growing quantum sector investment in the UK and US is leading to the development and commercialization of quantum ...
+ - [Quantum computing: What leaders need to know now](https://mitsloan.mit.edu/ideas-made-to-matter/quantum-computing-what-leaders-need-to-know-now): Jan 11, 2024 — An overview of quantum computing ... The idea for building a system that leverages physics principles to simulate problems too difficult to model ...
+ - [Quantum computing technology pushes for IT advantage](https://www.techtarget.com/searchcio/feature/Quantum-computing-technology-pushes-for-IT-advantage): Nov 27, 2024 — Timeline showing quantum computing milestones. Quantum computing developments have shifted over the years from basic research to the ...
+ - [What's next for quantum computing](https://www.technologyreview.com/2023/01/06/1066317/whats-next-for-quantum-computing/): Jan 6, 2023 — In 2023, progress in quantum computing will be defined less by big hardware announcements than by researchers consolidating years of hard work.
+ - [Quantum Computing Is Coming Faster Than You Think](https://www.forbes.com/sites/tiriasresearch/2023/11/28/quantum-computing-is-coming-faster-than-you-think/): Nov 28, 2023 — Another reason is the continued advancements being made in quantum computing is improvements in quantum chips, control logic, systems, and ...
+ - [2025 Will See Huge Advances in Quantum Computing. So ...](https://thequantuminsider.com/2025/01/08/2025-will-see-huge-advances-in-quantum-computing-so-what-is-a-quantum-chip-and-how-does-it-work/): 7 days ago — Many experts are expecting big advance in quantum computing in 2025, but what is a quantum chip and how does it work?
+
+9. **Quantum Computing future**
+ - [How Quantum Will Transform the Future of 5 Industries](https://www.honeywell.com/us/en/news/2020/07/how-quantum-will-transform-the-future-of-5-industries): Quantum computing could identify the best places to embed sensors to capture the most meaningful data as well as speed up the machine learning process. Quantum ...
+ - [Unlocking the quantum future | MIT News](https://news.mit.edu/2024/hackathon-unlocking-quantum-future-0318): Mar 18, 2024 — Quantum computing is the next frontier for faster and more powerful computing technologies. It has the potential to better optimize routes ...
+ - [Future of Quantum Computing: Unlocking the Possibilities](https://thequantuminsider.com/2023/04/06/future-of-quantum-computing/): Apr 6, 2023 — The future of quantum computing is bright, with the potential to revolutionize fields ranging from medicine to finance to cybersecurity.
+ - [The future of quantum computing | The TechTank Podcast](https://www.brookings.edu/articles/the-future-of-quantum-computing-the-techtank-podcast/): Quantum computing promises to solve problems that are impossible for today's computers, including key problems in cryptography, drug discovery, finance, ...
+ - [NVIDIA GTC 2025: Quantum Day to Illuminate the Future of ...](https://blogs.nvidia.com/blog/gtc-2025-quantum-day/): 13 hours ago — NVIDIA is celebrating and exploring remarkable progress in quantum computing by announcing its first Quantum Day at GTC 2025 on March 20.
+ - [Future of Quantum Computing & 7 QC trends in 2025](https://research.aimultiple.com/future-of-quantum-computing/): Jan 7, 2025 — Future of Quantum Computing & 7 QC trends in 2025 ... Quantum computing can be a game-changer in fields such as cryptography, chemistry, material ...
+ - [Quantum Computing Is the Future, and Schools Need to ...](https://www.scientificamerican.com/article/quantum-computing-is-the-future-and-schools-need-to-catch-up/): Mar 15, 2023 — Quantum technology is the future, and quantum computing education is STEM education, as Charles Tahan, the director at the National Quantum ...
\ No newline at end of file
diff --git a/rate_tracker.py b/rate_tracker.py
new file mode 100644
index 0000000..c38468d
--- /dev/null
+++ b/rate_tracker.py
@@ -0,0 +1,97 @@
+import time
+import math
+from typing import Dict, List, TypedDict
+
+class TokenUsage(TypedDict):
+ timestamp: float
+ tokens: int
+
+class RateTrackerConfig(TypedDict):
+ requestsPerMinute: int
+ tokensPerMinute: int
+ maxTokensPerRequest: int
+
+class RateTracker:
+ def __init__(self, config: RateTrackerConfig):
+ self.config = {
+ 'requestsPerMinute': config.get('requestsPerMinute', 50),
+ 'tokensPerMinute': config.get('tokensPerMinute', 400000),
+ 'maxTokensPerRequest': config.get('maxTokensPerRequest', 4000)
+ }
+ self.request_history: List[float] = []
+ self.token_history: List[TokenUsage] = []
+ self.last_cleanup = time.time()
+
+ def cleanup(self):
+ now = time.time()
+ one_minute_ago = now - 60
+
+ # Only cleanup if it's been at least 5 seconds since last cleanup
+ if now - self.last_cleanup < 5:
+ return
+
+ self.request_history = [t for t in self.request_history if t > one_minute_ago]
+ self.token_history = [t for t in self.token_history if t['timestamp'] > one_minute_ago]
+ self.last_cleanup = now
+
+ def get_current_usage(self) -> Dict[str, int]:
+ self.cleanup()
+ total_tokens = sum(usage['tokens'] for usage in self.token_history)
+ return {
+ 'requests': len(self.request_history),
+ 'tokens': total_tokens
+ }
+
+ def can_make_request(self, estimated_tokens: int) -> bool:
+ self.cleanup()
+
+ current_usage = self.get_current_usage()
+ within_request_limit = current_usage['requests'] < self.config['requestsPerMinute']
+ within_token_limit = current_usage['tokens'] + estimated_tokens <= self.config['tokensPerMinute']
+ within_max_tokens = estimated_tokens <= self.config['maxTokensPerRequest']
+
+ return within_request_limit and within_token_limit and within_max_tokens
+
+ def get_wait_time(self, estimated_tokens: int) -> float:
+ if estimated_tokens > self.config['maxTokensPerRequest']:
+ return -1 # Cannot make request - exceeds max tokens per request
+
+ self.cleanup()
+ current_usage = self.get_current_usage()
+
+ if current_usage['requests'] == 0 and current_usage['tokens'] == 0:
+ return 0 # No waiting needed
+
+ wait_time = 0
+
+ # Calculate wait time for request limit
+ if current_usage['requests'] >= self.config['requestsPerMinute']:
+ oldest_request = min(self.request_history) if self.request_history else time.time()
+ wait_time = max(wait_time, oldest_request + 60 - time.time())
+
+ # Calculate wait time for token limit
+ if current_usage['tokens'] + estimated_tokens > self.config['tokensPerMinute']:
+ oldest_token = min(t['timestamp'] for t in self.token_history) if self.token_history else time.time()
+ token_wait_time = oldest_token + 60 - time.time()
+ wait_time = max(wait_time, token_wait_time)
+
+ return math.ceil(wait_time * 1000) # Convert to milliseconds
+
+ def record_usage(self, tokens: int):
+ now = time.time()
+ self.request_history.append(now)
+ self.token_history.append({'timestamp': now, 'tokens': tokens})
+ self.cleanup()
+
+ def get_rate_limit_status(self) -> Dict[str, int]:
+ self.cleanup()
+ current_usage = self.get_current_usage()
+ oldest_timestamp = min(self.request_history) if self.request_history else time.time()
+
+ return {
+ 'requestsRemaining': self.config['requestsPerMinute'] - current_usage['requests'],
+ 'tokensRemaining': self.config['tokensPerMinute'] - current_usage['tokens'],
+ 'requestsUsed': current_usage['requests'],
+ 'tokensUsed': current_usage['tokens'],
+ 'nextReset': oldest_timestamp + 60
+ }
\ No newline at end of file
diff --git a/research-script.ts b/research-script.ts
new file mode 100644
index 0000000..568b6e4
--- /dev/null
+++ b/research-script.ts
@@ -0,0 +1,211 @@
+import { ParallelSearchOrchestrator } from './src/core/parallel-orchestrator.js';
+import { ResearchConfig, ResearchResult, CategoryContent, ResearchData } from './src/types/research.js';
+import * as fs from 'fs';
+
+export async function conductResearch(topic: string): Promise {
+ // Configure research parameters
+ // Read the research prompt file to get the structure
+ const promptFile = `${topic.toLowerCase().replace(/\s+/g, '-')}-research-prompt.txt`;
+ let categories: string[] = ['overview']; // Default category
+
+ try {
+ if (fs.existsSync(promptFile)) {
+ const promptContent = fs.readFileSync(promptFile, 'utf-8');
+ // Extract categories from numbered sections in the prompt
+ categories = promptContent
+ .split('\n')
+ .filter(line => /^\(\d+\)/.test(line)) // Lines starting with (1), (2), etc.
+ .map(line => {
+ // Extract main category from the section
+ const category = line.replace(/^\(\d+\)\s*Find\s+/, '') // Remove "(1) Find "
+ .split(/\s+and\s+|\s*,\s*/)[0] // Take first main topic
+ .toLowerCase()
+ .trim();
+ return category;
+ });
+
+ if (categories.length === 0) {
+ categories = ['overview']; // Fallback if no categories found
+ }
+ }
+ } catch (error) {
+ console.warn('Could not read research prompt file, using default categories');
+ }
+
+ const config: ResearchConfig = {
+ maxDepth: 2,
+ maxUrlsPerDomain: 5,
+ relevanceThreshold: 0.3,
+ maxTotalUrls: 50,
+ timeout: 30000,
+ maxDynamicQueries: 10,
+ minConfidence: 0.7,
+ categories: categories,
+ excludeCategories: ['advertisements', 'comments', 'user-generated'],
+ maxContentAge: 365 * 24 * 60 * 60 * 1000 // 1 year in milliseconds
+ };
+
+ const orchestrator = new ParallelSearchOrchestrator(config);
+ console.log(`Initializing research for topic: ${topic}`);
+
+ try {
+ // Initialize orchestrator
+ await orchestrator.initialize();
+ console.log('Initialized research orchestrator');
+
+ // Execute deep research
+ console.log('Starting deep research...');
+ const researchData = await orchestrator.executeDeepResearch(topic);
+
+ // Create research result
+ const result: ResearchResult = {
+ topic,
+ timestamp: new Date().toISOString(),
+ data: researchData,
+ metadata: {
+ totalSources: researchData.sources.size,
+ categoryBreakdown: new Map(
+ Array.from(researchData.categories.entries()).map(
+ ([category, contents]) => [category, contents.length]
+ )
+ ),
+ topEntities: researchData.entities
+ .sort((a, b) => b.confidence - a.confidence)
+ .slice(0, 10),
+ confidence: calculateOverallConfidence(researchData)
+ }
+ };
+
+ // Log research statistics
+ console.log('\n=== Research Statistics ===');
+ console.log(`Total sources analyzed: ${result.metadata.totalSources}`);
+ console.log('Category breakdown:');
+ result.metadata.categoryBreakdown.forEach((count, category) => {
+ console.log(`- ${category}: ${count} entries`);
+ });
+ console.log(`Top entities identified: ${result.metadata.topEntities.length}`);
+ console.log(`Overall confidence score: ${result.metadata.confidence}`);
+
+ return result;
+
+ } catch (error) {
+ console.error('Research failed:', error);
+ throw error;
+ } finally {
+ // Cleanup resources
+ await orchestrator.cleanup();
+ }
+}
+
+function calculateOverallConfidence(data: ResearchData): number {
+ const categoryConfidences = Array.from(data.categories.values())
+ .flat()
+ .map(content => content.relevance);
+
+ const entityConfidences = data.entities.map(entity => entity.confidence);
+ const allConfidences = [...categoryConfidences, ...entityConfidences];
+
+ return allConfidences.length > 0
+ ? allConfidences.reduce((sum, conf) => sum + conf, 0) / allConfidences.length
+ : 0;
+}
+
+export function generateSummaryReport(results: ResearchResult): string {
+ const sections: string[] = [];
+
+ // Add title and timestamp
+ sections.push(`Research Summary: ${results.topic}\n`);
+ sections.push(`Generated: ${new Date(results.timestamp).toLocaleString()}\n`);
+ sections.push(`Overall Confidence: ${(results.metadata.confidence * 100).toFixed(1)}%\n`);
+
+ // Helper function to clean content
+ const cleanContent = (content: string): string => {
+ return content
+ .replace(/\s+/g, ' ')
+ .replace(/\[.*?\]/g, '')
+ .replace(/\(.*?\)/g, '')
+ .replace(/\{.*?\}/g, '')
+ .replace(/<.*?>/g, '')
+ .replace(/\b(?:edit|citation needed)\b/gi, '')
+ .replace(/\^/g, '')
+ .replace(/\n{3,}/g, '\n\n')
+ .trim();
+ };
+
+ // Try to read the research prompt to structure the report
+ try {
+ const promptFile = `${results.topic.toLowerCase().replace(/\s+/g, '-')}-research-prompt.txt`;
+ if (fs.existsSync(promptFile)) {
+ const promptContent = fs.readFileSync(promptFile, 'utf-8');
+
+ // Extract main sections from the prompt
+ const mainSections = promptContent
+ .split('\n')
+ .filter(line => /^\(\d+\)/.test(line))
+ .map(line => {
+ return line.replace(/^\(\d+\)\s*Find\s+/, '')
+ .split(/\s+and\s+|\s*,\s*/)[0]
+ .trim();
+ });
+
+ // Process each section based on the prompt structure
+ mainSections.forEach(section => {
+ const sectionKey = section.toLowerCase();
+ const relevantContent = Array.from(results.data.categories.entries())
+ .filter(([category]) => category.includes(sectionKey))
+ .flatMap(([_, contents]) => contents);
+
+ if (relevantContent.length > 0) {
+ sections.push(`\n=== ${section} ===\n`);
+
+ // Sort by relevance and take top entries
+ const sortedContent = relevantContent
+ .sort((a, b) => b.relevance - a.relevance)
+ .slice(0, 5);
+
+ sortedContent.forEach(content => {
+ sections.push(`• ${cleanContent(content.content)}`);
+ });
+ }
+ });
+ }
+ } catch (error) {
+ // Fallback to default category-based organization
+ results.data.categories.forEach((contents, category) => {
+ if (contents.length > 0) {
+ sections.push(`\n=== ${category.charAt(0).toUpperCase() + category.slice(1)} ===\n`);
+
+ const sortedContents = contents
+ .sort((a, b) => b.relevance - a.relevance)
+ .slice(0, 5);
+
+ sortedContents.forEach(content => {
+ sections.push(`• ${cleanContent(content.content)}`);
+ });
+ }
+ });
+ }
+
+ // Add key insights
+ if (results.data.keyInsights.length > 0) {
+ sections.push('\n=== Key Findings ===\n');
+ results.data.keyInsights
+ .sort((a, b) => b.relevance - a.relevance)
+ .slice(0, 5)
+ .forEach(insight => {
+ sections.push(`• ${cleanContent(insight.content)}`);
+ });
+ }
+
+ // Add sources
+ if (results.data.sources.size > 0) {
+ sections.push('\n=== Sources ===\n');
+ Array.from(results.data.sources)
+ .sort()
+ .forEach(source => sections.push(source));
+ }
+
+ return sections.join('\n');
+}
+
+export default conductResearch;
\ No newline at end of file
diff --git a/src/core/content-analyzer.ts b/src/core/content-analyzer.ts
new file mode 100644
index 0000000..22725eb
--- /dev/null
+++ b/src/core/content-analyzer.ts
@@ -0,0 +1,945 @@
+import natural from 'natural';
+import { ContentAnalysis, Topic, KeyPoint, Entity, EntityType, EntityMention, Relationship, Citation, ContentQuality, AnalysisOptions } from '../types/analysis.js';
+import { ExtractedContent } from '../types/content.js';
+
+export class ContentAnalyzer {
+ private tokenizer: natural.WordTokenizer;
+ private tfidf: natural.TfIdf;
+ private stemmer: typeof natural.PorterStemmerFr;
+ private technicalTerms: Set;
+ private boilerplatePatterns: RegExp[];
+
+ private isTechnicalContent(text: string): boolean {
+ const technicalIndicators = [
+ 'example',
+ 'implementation',
+ 'usage',
+ 'api',
+ 'method',
+ 'function',
+ 'parameter',
+ 'return',
+ 'class',
+ 'interface',
+ 'object',
+ 'pattern'
+ ];
+
+ const lowerText = text.toLowerCase();
+ return technicalIndicators.some(indicator => lowerText.includes(indicator)) ||
+ text.includes('```') ||
+ /`[^`]+`/.test(text);
+ }
+
+ private extractTechnicalTermsFromText(text: string): string[] {
+ const words = text.toLowerCase().split(/\W+/);
+ return words.filter(word =>
+ word.length > 3 &&
+ this.technicalTerms.has(word) &&
+ !this.isStopWord(word)
+ );
+ }
+
+ constructor() {
+ this.tokenizer = new natural.WordTokenizer();
+ this.tfidf = new natural.TfIdf();
+ this.stemmer = natural.PorterStemmerFr;
+
+ // Initialize technical terms focused on API wrappers and programming
+ this.technicalTerms = new Set([
+ // API and Design Patterns
+ 'api', 'wrapper', 'client', 'sdk', 'library', 'interface',
+ 'endpoint', 'request', 'response', 'http', 'rest', 'soap',
+ 'facade', 'adapter', 'proxy', 'decorator', 'factory',
+
+ // Implementation Concepts
+ 'implementation', 'method', 'function', 'class', 'object',
+ 'parameter', 'argument', 'return', 'async', 'await', 'promise',
+ 'callback', 'error', 'exception', 'handler', 'middleware',
+
+ // Best Practices
+ 'pattern', 'practice', 'standard', 'convention', 'principle',
+ 'solid', 'dry', 'separation', 'concern', 'abstraction',
+ 'encapsulation', 'inheritance', 'polymorphism',
+
+ // Testing and Quality
+ 'test', 'mock', 'stub', 'assertion', 'coverage', 'unit',
+ 'integration', 'validation', 'verification', 'documentation',
+
+ // Common Features
+ 'authentication', 'authorization', 'security', 'cache',
+ 'rate', 'limit', 'throttle', 'retry', 'timeout', 'logging'
+ ]);
+
+ // Initialize boilerplate patterns
+ this.boilerplatePatterns = [
+ /copyright/i,
+ /all rights reserved/i,
+ /terms of service/i,
+ /privacy policy/i,
+ /cookie policy/i,
+ /contact us/i,
+ /about us/i,
+ /follow us/i,
+ /subscribe/i,
+ /sign up/i,
+ /log in/i,
+ /register/i
+ ];
+ }
+
+ public async analyze(content: ExtractedContent, options: AnalysisOptions = {}): Promise {
+ console.log('Starting content analysis for URL:', content.url);
+ console.log('Content length:', content.content.length);
+
+ // Prepare content for analysis
+ const tokens = this.tokenizeContent(content.content);
+ this.tfidf.addDocument(tokens);
+ console.log('Tokenized content length:', tokens.length);
+
+ // Extract topics and calculate relevance
+ console.log('Extracting topics...');
+ const topics = await this.extractTopics(content, options);
+ console.log('Found topics:', topics.length, topics.map(t => t.name));
+
+ console.log('Extracting key points...');
+ const keyPoints = this.extractKeyPoints(content, topics, options);
+ console.log('Found key points:', keyPoints.length);
+
+ console.log('Extracting entities...');
+ const entities = this.extractEntities(content);
+ console.log('Found entities:', entities.length);
+
+ const relationships = this.findRelationships(entities, content);
+ const sentiment = this.analyzeSentiment(content.content);
+ const quality = this.assessQuality(content);
+
+ // Merge similar topics
+ console.log('Merging similar topics...');
+ const mergedTopics = this.mergeSimilarTopics(topics);
+ console.log('After merging:', mergedTopics.length, mergedTopics.map(t => t.name));
+
+ const result = {
+ relevanceScore: this.calculateRelevanceScore(content, mergedTopics),
+ topics: mergedTopics,
+ keyPoints: this.deduplicateKeyPoints(keyPoints),
+ entities,
+ sentiment,
+ relationships,
+ citations: this.extractCitations(content),
+ quality
+ };
+
+ console.log('Analysis complete. Topics:', result.topics.length);
+ console.log('Key points:', result.keyPoints.length);
+ console.log('Relevance score:', result.relevanceScore);
+
+ return result;
+ }
+
+ private tokenizeContent(text: string): string[] {
+ return this.tokenizer.tokenize(text.toLowerCase()) || [];
+ }
+
+ private async extractTopics(content: ExtractedContent, options: AnalysisOptions): Promise {
+ console.log('Extracting topics from content...');
+ const maxTopics = options.maxTopics || 8;
+ const minConfidence = options.minConfidence || 0.15;
+
+ // Split content into sections
+ const sections = content.content.split(/\n\n+/);
+ console.log(`Found ${sections.length} sections to analyze`);
+
+ // Initialize topic tracking
+ const topicMentions = new Map
+ }>();
+
+ // Enhanced topic indicators for quantum computing
+ const topicIndicators = [
+ // General technical patterns
+ { pattern: /(?:using|implementing|creating)\s+(\w+(?:\s+\w+){0,2})\s+(?:pattern|approach|method)/i, weight: 1.2 },
+ { pattern: /(?:best\s+practice|recommended)\s+(?:is|for)\s+(\w+(?:\s+\w+){0,2})/i, weight: 1.1 },
+ { pattern: /(\w+(?:\s+\w+){0,2})\s+implementation/i, weight: 1.0 },
+ { pattern: /(\w+(?:\s+\w+){0,2})\s+(?:wrapper|api|interface)/i, weight: 1.0 },
+
+ // Domain-specific patterns
+ { pattern: /(?:quantum)\s+(\w+(?:\s+\w+){0,2})/i, weight: 1.3 },
+ { pattern: /(\w+(?:\s+\w+){0,2})\s+(?:qubit|qubits)/i, weight: 1.3 },
+ { pattern: /(\w+(?:\s+\w+){0,2})\s+(?:algorithm|computation)/i, weight: 1.2 },
+ { pattern: /(?:advances?|developments?|breakthroughs?)\s+in\s+(\w+(?:\s+\w+){0,2})/i, weight: 1.2 }
+ ];
+
+ // Analyze each section
+ sections.forEach((section, index) => {
+ console.log(`Analyzing section ${index + 1}...`);
+ const sectionLower = section.toLowerCase();
+
+ // Look for topic indicators
+ topicIndicators.forEach(({ pattern, weight }) => {
+ const matches = sectionLower.match(pattern);
+ if (matches && matches[1]) {
+ const topic = matches[1].trim();
+ const existing = topicMentions.get(topic) || { count: 0, contexts: [], keywords: new Set() };
+ existing.count += weight;
+ existing.contexts.push(section);
+
+ // Extract related keywords
+ const keywords = this.extractKeywords(section);
+ keywords.forEach(k => existing.keywords.add(k));
+
+ topicMentions.set(topic, existing);
+ console.log(`Found topic: ${topic} (weight: ${weight})`);
+ }
+ });
+
+ // Look for technical content
+ if (this.isTechnicalContent(section)) {
+ const terms = this.extractTechnicalTermsFromText(section);
+ terms.forEach((term: string) => {
+ const existing = topicMentions.get(term) || { count: 0, contexts: [], keywords: new Set() };
+ existing.count += 0.7;
+ existing.contexts.push(section);
+ topicMentions.set(term, existing);
+ });
+ }
+
+ // Look for code examples
+ if (section.includes('```') || section.includes('`')) {
+ const codeKeywords = this.extractCodeKeywords(section);
+ codeKeywords.forEach(keyword => {
+ const existing = topicMentions.get(keyword) || { count: 0, contexts: [], keywords: new Set() };
+ existing.count += 0.8;
+ existing.contexts.push(section);
+ topicMentions.set(keyword, existing);
+ console.log(`Found code keyword: ${keyword}`);
+ });
+ }
+ });
+
+ console.log(`Found ${topicMentions.size} potential topics`);
+
+ // Convert to topics with enhanced scoring
+ const topics: Topic[] = Array.from(topicMentions.entries())
+ .map(([name, data]) => {
+ // Calculate confidence with context bonus
+ let confidence = Math.min(1, data.count / 3);
+
+ // Boost confidence for topics with multiple contexts
+ if (data.contexts.length > 1) {
+ confidence *= 1.2;
+ }
+
+ // Boost confidence for topics with technical keywords
+ if (data.keywords.size > 2) {
+ confidence *= 1.1;
+ }
+
+ return {
+ name,
+ confidence: Math.min(1, confidence),
+ keywords: Array.from(data.keywords)
+ };
+ })
+ .filter(topic => {
+ const meetsThreshold = topic.confidence >= minConfidence;
+ console.log(`Topic ${topic.name}: confidence ${topic.confidence} ${meetsThreshold ? 'accepted' : 'rejected'}`);
+ return meetsThreshold;
+ })
+ .sort((a, b) => b.confidence - a.confidence)
+ .slice(0, maxTopics);
+
+ console.log(`Extracted ${topics.length} topics above confidence threshold`);
+ return topics;
+ }
+
+ private extractKeywords(text: string): string[] {
+ const words = text.toLowerCase().split(/\W+/);
+ return words.filter(word =>
+ word.length > 3 &&
+ this.technicalTerms.has(word) &&
+ !this.isStopWord(word)
+ );
+ }
+
+ private extractCodeKeywords(text: string): string[] {
+ const codePatterns = [
+ /class\s+(\w+)/g,
+ /function\s+(\w+)/g,
+ /method\s+(\w+)/g,
+ /interface\s+(\w+)/g,
+ /import\s+(\w+)/g,
+ /require\s+['"](.+?)['"]/g
+ ];
+
+ const keywords = new Set();
+ codePatterns.forEach(pattern => {
+ let match;
+ while ((match = pattern.exec(text)) !== null) {
+ if (match[1]) {
+ keywords.add(match[1].toLowerCase());
+ }
+ }
+ });
+
+ return Array.from(keywords);
+ }
+
+ private getImportantTerms(text: string): Array<{term: string; score: number}> {
+ const terms: Array<{term: string; score: number}> = [];
+ const tokens = this.tokenizeContent(text);
+
+ this.tfidf.listTerms(0).forEach(item => {
+ const term = item.term;
+ if (term.length > 2 && !this.isStopWord(term)) {
+ // Boost score for technical terms
+ const score = this.technicalTerms.has(term) ? item.tfidf * 1.5 : item.tfidf;
+ terms.push({ term, score });
+ }
+ });
+
+ return terms.sort((a, b) => b.score - a.score);
+ }
+
+ private mergeSimilarTopics(topics: Topic[]): Topic[] {
+ const merged: Topic[] = [];
+ const processed = new Set();
+
+ for (const topic of topics) {
+ if (processed.has(topic.name)) continue;
+
+ // Find similar topics
+ const similar = topics.filter(t =>
+ !processed.has(t.name) &&
+ (this.areTopicsSimilar(topic, t) || this.areTopicsRelated(topic, t))
+ );
+
+ if (similar.length > 0) {
+ // Merge topics
+ const mergedTopic: Topic = {
+ name: this.selectBestTopicName(similar.map(t => t.name)),
+ confidence: Math.max(...similar.map(t => t.confidence)),
+ keywords: Array.from(new Set(similar.flatMap(t => t.keywords)))
+ };
+ merged.push(mergedTopic);
+ similar.forEach(t => processed.add(t.name));
+ } else {
+ merged.push(topic);
+ processed.add(topic.name);
+ }
+ }
+
+ return merged;
+ }
+
+ private areTopicsSimilar(topic1: Topic, topic2: Topic): boolean {
+ // Check for stem similarity
+ const stem1 = this.stemmer.stem(topic1.name);
+ const stem2 = this.stemmer.stem(topic2.name);
+ if (stem1 === stem2) return true;
+
+ // Check for keyword overlap
+ const keywords1 = new Set(topic1.keywords);
+ const keywords2 = new Set(topic2.keywords);
+ const overlap = [...keywords1].filter(k => keywords2.has(k)).length;
+ const similarity = overlap / Math.min(keywords1.size, keywords2.size);
+ return similarity > 0.5;
+ }
+
+ private areTopicsRelated(topic1: Topic, topic2: Topic): boolean {
+ // Check if topics often appear together in technical contexts
+ const technicalPairs = [
+ ['api', 'wrapper'],
+ ['wrapper', 'implementation'],
+ ['pattern', 'practice'],
+ ['method', 'interface'],
+ ['class', 'object'],
+ ['error', 'handling'],
+ ['authentication', 'security']
+ ];
+
+ return technicalPairs.some(([t1, t2]) =>
+ (topic1.name.toLowerCase().includes(t1) && topic2.name.toLowerCase().includes(t2)) ||
+ (topic1.name.toLowerCase().includes(t2) && topic2.name.toLowerCase().includes(t1))
+ );
+ }
+
+ private selectBestTopicName(names: string[]): string {
+ // Prefer technical terms
+ const technicalNames = names.filter(name =>
+ this.technicalTerms.has(name.toLowerCase())
+ );
+ if (technicalNames.length > 0) {
+ return technicalNames[0];
+ }
+
+ // Otherwise use the longest name
+ return names.sort((a, b) => b.length - a.length)[0];
+ }
+
+ private areTermsRelated(term1: string, term2: string): boolean {
+ // Use word stems to check relation
+ const stem1 = this.stemmer.stem(term1);
+ const stem2 = this.stemmer.stem(term2);
+
+ if (stem1 === stem2) return true;
+
+ // Check technical term relationships
+ const technicalPairs = [
+ ['api', 'wrapper'],
+ ['wrapper', 'implementation'],
+ ['pattern', 'practice'],
+ ['method', 'interface'],
+ ['class', 'object'],
+ ['error', 'handling'],
+ ['authentication', 'security']
+ ];
+
+ return technicalPairs.some(([t1, t2]) =>
+ (term1.includes(t1) && term2.includes(t2)) ||
+ (term1.includes(t2) && term2.includes(t1))
+ );
+ }
+
+ private selectTopicName(mainTerm: string, relatedTerms: string[]): string {
+ // Prefer technical terms
+ const technicalTerms = [mainTerm, ...relatedTerms].filter(term =>
+ this.technicalTerms.has(term)
+ );
+
+ if (technicalTerms.length > 0) {
+ return technicalTerms[0].charAt(0).toUpperCase() + technicalTerms[0].slice(1);
+ }
+
+ return mainTerm.charAt(0).toUpperCase() + mainTerm.slice(1);
+ }
+
+ private extractKeyPoints(content: ExtractedContent, topics: Topic[], options: AnalysisOptions): KeyPoint[] {
+ // Split content into paragraphs first
+ const paragraphs = content.content.split(/\n\n+/);
+ const keyPoints: KeyPoint[] = [];
+ const minImportance = options.minImportance || 0.25; // Lowered threshold
+
+ // First pass: identify best practice and implementation sections
+ const bestPracticeSections = paragraphs.filter(p =>
+ /best\s+practices?|recommended|should|must|guidelines?/i.test(p)
+ );
+ const implementationSections = paragraphs.filter(p =>
+ /implementation|example|usage|how\s+to|approach/i.test(p) ||
+ p.includes('```') ||
+ /\b(function|class|method|interface)\b/.test(p)
+ );
+
+ // Process best practice sections
+ bestPracticeSections.forEach(section => {
+ const sentences = section.split(/[.!?]+/).map(s => s.trim()).filter(s => s.length > 20);
+ sentences.forEach(sentence => {
+ if (this.isBestPracticeStatement(sentence)) {
+ const importance = this.calculateSentenceImportance(sentence, topics) * 1.3; // Boost best practices
+ if (importance >= minImportance) {
+ keyPoints.push({
+ text: sentence.trim(),
+ importance,
+ topics: this.findRelatedTopics(sentence, topics),
+ supportingEvidence: this.findSupportingEvidence(sentence, content)
+ });
+ }
+ }
+ });
+ });
+
+ // Process implementation sections
+ implementationSections.forEach(section => {
+ const sentences = section.split(/[.!?]+/).map(s => s.trim()).filter(s => s.length > 20);
+ sentences.forEach(sentence => {
+ if (this.isImplementationGuidance(sentence)) {
+ const importance = this.calculateSentenceImportance(sentence, topics) * 1.2; // Boost implementation guidance
+ if (importance >= minImportance) {
+ const evidence = [
+ ...this.findSupportingEvidence(sentence, content),
+ ...this.extractCodeExamples(section)
+ ];
+ keyPoints.push({
+ text: sentence.trim(),
+ importance,
+ topics: this.findRelatedTopics(sentence, topics),
+ supportingEvidence: evidence
+ });
+ }
+ }
+ });
+ });
+
+ // Process remaining paragraphs for other insights
+ paragraphs.forEach(paragraph => {
+ if (!bestPracticeSections.includes(paragraph) && !implementationSections.includes(paragraph)) {
+ const sentences = paragraph.split(/[.!?]+/).map(s => s.trim()).filter(s => s.length > 20);
+ sentences.forEach(sentence => {
+ const importance = this.calculateSentenceImportance(sentence, topics);
+ if (importance >= minImportance && this.isInsightful(sentence)) {
+ keyPoints.push({
+ text: sentence.trim(),
+ importance,
+ topics: this.findRelatedTopics(sentence, topics),
+ supportingEvidence: this.findSupportingEvidence(sentence, content)
+ });
+ }
+ });
+ }
+ });
+
+ return this.deduplicateKeyPoints(
+ keyPoints.sort((a, b) => b.importance - a.importance)
+ .slice(0, options.maxKeyPoints || 15)
+ );
+ }
+
+ private isBestPracticeStatement(sentence: string): boolean {
+ const bestPracticeIndicators = [
+ /\b(?:should|must|recommend|best|practice|important|key|essential|avoid|ensure)\b/i,
+ /\b(?:pattern|approach|strategy|technique|principle)\b/i,
+ /\b(?:better|improve|optimize|enhance)\b/i,
+ /\b(?:common|typical|standard|conventional)\b/i
+ ];
+
+ const lowerSentence = sentence.toLowerCase();
+ return bestPracticeIndicators.some(pattern => pattern.test(lowerSentence)) &&
+ !this.isBoilerplate(sentence);
+ }
+
+ private isImplementationGuidance(sentence: string): boolean {
+ const implementationIndicators = [
+ /\b(?:implement|create|build|develop|use|initialize|configure)\b/i,
+ /\b(?:method|function|class|interface|object)\b/i,
+ /\b(?:parameter|argument|return|value|type)\b/i,
+ /\b(?:example|sample|demo|code)\b/i
+ ];
+
+ const lowerSentence = sentence.toLowerCase();
+ return implementationIndicators.some(pattern => pattern.test(lowerSentence)) &&
+ !this.isBoilerplate(sentence);
+ }
+
+ private isInsightful(sentence: string): boolean {
+ // Check if sentence contains meaningful technical content
+ const technicalTermCount = this.tokenizeContent(sentence)
+ .filter(token => this.technicalTerms.has(token)).length;
+
+ return technicalTermCount >= 2 && // Has multiple technical terms
+ sentence.length > 30 && // Not too short
+ !this.isBoilerplate(sentence) &&
+ !/^\s*[^a-zA-Z]*\s*$/.test(sentence); // Contains actual words
+ }
+
+ private extractCodeExamples(text: string): string[] {
+ const examples: string[] = [];
+
+ // Extract code blocks
+ const codeBlockRegex = /```[\s\S]*?```/g;
+ let match;
+ while ((match = codeBlockRegex.exec(text)) !== null) {
+ examples.push(match[0]);
+ }
+
+ // Extract inline code
+ const inlineCodeRegex = /`[^`]+`/g;
+ while ((match = inlineCodeRegex.exec(text)) !== null) {
+ examples.push(match[0]);
+ }
+
+ return examples;
+ }
+
+ private deduplicateKeyPoints(keyPoints: KeyPoint[]): KeyPoint[] {
+ const unique: KeyPoint[] = [];
+ const seen = new Set();
+
+ for (const point of keyPoints) {
+ const normalized = this.normalizeText(point.text);
+ if (!seen.has(normalized) && !this.hasVerySimilarPoint(normalized, seen)) {
+ unique.push(point);
+ seen.add(normalized);
+ }
+ }
+
+ return unique;
+ }
+
+ private normalizeText(text: string): string {
+ return text.toLowerCase()
+ .replace(/\s+/g, ' ')
+ .replace(/[^\w\s]/g, '')
+ .trim();
+ }
+
+ private hasVerySimilarPoint(text: string, seen: Set): boolean {
+ for (const existing of seen) {
+ const similarity = this.calculateTextSimilarity(text, existing);
+ if (similarity > 0.8) return true;
+ }
+ return false;
+ }
+
+ private calculateTextSimilarity(text1: string, text2: string): number {
+ const words1 = new Set(text1.split(' '));
+ const words2 = new Set(text2.split(' '));
+ const intersection = new Set([...words1].filter(x => words2.has(x)));
+ const union = new Set([...words1, ...words2]);
+ return intersection.size / union.size;
+ }
+
+ private calculateSentenceImportance(sentence: string, topics: Topic[]): number {
+ const tokens = this.tokenizeContent(sentence);
+ let importance = 0;
+ let technicalTermCount = 0;
+ let hasCodeExample = false;
+
+ // Check for code-like content
+ hasCodeExample = sentence.includes('```') ||
+ sentence.includes('`') ||
+ /\b(function|class|const|let|var|import|export)\b/.test(sentence);
+
+ // Count technical terms with weighted categories
+ const termWeights = {
+ implementation: 1.2, // Implementation details
+ pattern: 1.2, // Design patterns
+ practice: 1.2, // Best practices
+ test: 1.1, // Testing related
+ error: 1.1, // Error handling
+ api: 1.3, // API specific
+ wrapper: 1.3, // Wrapper specific
+ method: 1.1, // Method related
+ class: 1.1 // Class related
+ };
+
+ tokens.forEach(token => {
+ if (this.technicalTerms.has(token)) {
+ technicalTermCount++;
+ // Apply additional weight for key terms
+ for (const [term, weight] of Object.entries(termWeights)) {
+ if (token.includes(term)) {
+ importance += weight - 1; // Add the extra weight
+ }
+ }
+ }
+ });
+
+ // Calculate topic relevance with reduced penalty for multiple topics
+ topics.forEach(topic => {
+ topic.keywords.forEach(keyword => {
+ if (tokens.includes(keyword.toLowerCase())) {
+ importance += topic.confidence * 0.8; // Reduced weight per topic
+ }
+ });
+ });
+
+ // Boost importance based on technical term density
+ const technicalDensity = technicalTermCount / tokens.length;
+ importance += technicalDensity * 0.5; // Reduced multiplier
+
+ // Boost for code examples
+ if (hasCodeExample) {
+ importance += 0.3;
+ }
+
+ // Boost for sentences that look like best practices or implementation guidance
+ if (
+ sentence.toLowerCase().includes('should') ||
+ sentence.toLowerCase().includes('best practice') ||
+ sentence.toLowerCase().includes('recommend') ||
+ sentence.toLowerCase().includes('pattern') ||
+ sentence.toLowerCase().includes('example')
+ ) {
+ importance += 0.2;
+ }
+
+ return Math.min(importance, 1);
+ }
+
+ private findRelatedTopics(sentence: string, topics: Topic[]): string[] {
+ const tokens = this.tokenizeContent(sentence);
+ return topics
+ .filter(topic =>
+ topic.keywords.some(keyword =>
+ tokens.includes(keyword.toLowerCase())
+ )
+ )
+ .map(topic => topic.name);
+ }
+
+ private findSupportingEvidence(sentence: string, content: ExtractedContent): string[] {
+ const tokens = this.tokenizeContent(sentence);
+ const evidence: string[] = [];
+
+ // Split content into sentences
+ const sentences = content.content.split(/[.!?]+/).map(s => s.trim()).filter(s => s.length > 0);
+
+ // Find sentences that share significant terms with the input sentence
+ sentences.forEach(s => {
+ if (s === sentence) return;
+
+ const sTokens = this.tokenizeContent(s);
+ const sharedTerms = tokens.filter(t => sTokens.includes(t));
+
+ // Check if the sentence contains technical terms
+ const hasTechnicalTerms = sTokens.some(t => this.technicalTerms.has(t));
+
+ if (sharedTerms.length >= 2 && hasTechnicalTerms) {
+ evidence.push(s);
+ }
+ });
+
+ return evidence;
+ }
+
+ private extractEntities(content: ExtractedContent): Entity[] {
+ // Extract technical entities like algorithm names, standards, etc.
+ const entities: Entity[] = [];
+ const text = content.content;
+
+ // Look for standard numbers (e.g., FIPS 203)
+ const standardRegex = /(?:FIPS|SP|RFC)\s+\d+(?:-\d+)?/g;
+ const standards = text.match(standardRegex) || [];
+ standards.forEach(standard => {
+ const mentions = this.findMentions(text, standard);
+ entities.push({
+ name: standard,
+ type: 'standard' as EntityType,
+ mentions
+ });
+ });
+
+ // Look for algorithm names
+ const algorithmRegex = /(?:ML-KEM|ML-DSA|SLH-DSA|CRYSTALS-Kyber|CRYSTALS-Dilithium|SPHINCS\+|FALCON)(?:-\d+)?/g;
+ const algorithms = text.match(algorithmRegex) || [];
+ algorithms.forEach(algorithm => {
+ const mentions = this.findMentions(text, algorithm);
+ entities.push({
+ name: algorithm,
+ type: 'algorithm' as EntityType,
+ mentions
+ });
+ });
+
+ return entities;
+ }
+
+ private findMentions(text: string, term: string): EntityMention[] {
+ const mentions: EntityMention[] = [];
+ let pos = text.indexOf(term);
+ while (pos !== -1) {
+ const start = Math.max(0, pos - 50);
+ const end = Math.min(text.length, pos + term.length + 50);
+ mentions.push({
+ text: term,
+ position: {
+ start: pos,
+ end: pos + term.length
+ },
+ context: text.substring(start, end)
+ });
+ pos = text.indexOf(term, pos + 1);
+ }
+ return mentions;
+ }
+
+ private findRelationships(entities: Entity[], content: ExtractedContent): Relationship[] {
+ const relationships: Relationship[] = [];
+ const text = content.content;
+
+ // Look for relationships between standards and algorithms
+ entities.forEach(e1 => {
+ if (e1.type === 'standard') {
+ entities.forEach(e2 => {
+ if (e2.type === 'algorithm') {
+ // Check if entities appear close to each other
+ const distance = this.findMinDistance(text, e1.name, e2.name);
+ if (distance < 100) { // within 100 characters
+ relationships.push({
+ source: e1.name,
+ target: e2.name,
+ type: 'specifies',
+ confidence: 1 - (distance / 100)
+ });
+ }
+ }
+ });
+ }
+ });
+
+ return relationships;
+ }
+
+ private findMinDistance(text: string, term1: string, term2: string): number {
+ let minDistance = Infinity;
+ let pos1 = text.indexOf(term1);
+
+ while (pos1 !== -1) {
+ let pos2 = text.indexOf(term2);
+ while (pos2 !== -1) {
+ const distance = Math.abs(pos2 - pos1);
+ minDistance = Math.min(minDistance, distance);
+ pos2 = text.indexOf(term2, pos2 + 1);
+ }
+ pos1 = text.indexOf(term1, pos1 + 1);
+ }
+
+ return minDistance;
+ }
+
+ private analyzeSentiment(text: string) {
+ const analyzer = new natural.SentimentAnalyzer(
+ 'English',
+ natural.PorterStemmerFr,
+ 'afinn'
+ );
+
+ const tokens = this.tokenizeContent(text);
+ const score = analyzer.getSentiment(tokens);
+
+ return {
+ score: Math.max(-1, Math.min(1, score)), // Normalize to [-1, 1]
+ confidence: Math.abs(score) / 5, // Simple confidence calculation
+ aspects: [] // Could be enhanced with aspect-based sentiment analysis
+ };
+ }
+
+ private assessQuality(content: ExtractedContent): ContentQuality {
+ return {
+ readability: this.calculateReadabilityScore(content.content),
+ informationDensity: this.calculateInformationDensity(content),
+ technicalDepth: this.calculateTechnicalDepth(content),
+ credibilityScore: this.calculateCredibilityScore(content),
+ freshness: this.calculateFreshnessScore(content)
+ };
+ }
+
+ private calculateReadabilityScore(text: string): number {
+ const sentences = text.split(/[.!?]+/).length;
+ const words = text.split(/\s+/).length;
+ const syllables = this.countSyllables(text);
+
+ // Flesch-Kincaid Grade Level
+ const grade = 0.39 * (words / sentences) + 11.8 * (syllables / words) - 15.59;
+
+ // Convert to a 0-1 score, where 0.5 represents college level
+ return Math.max(0, Math.min(1, 1 - (grade / 20)));
+ }
+
+ private countSyllables(text: string): number {
+ const words = text.split(/\s+/);
+ return words.reduce((count, word) => {
+ return count + this.countWordSyllables(word);
+ }, 0);
+ }
+
+ private countWordSyllables(word: string): number {
+ word = word.toLowerCase();
+ if (word.length <= 3) return 1;
+
+ word = word.replace(/(?:[^laeiouy]es|ed|[^laeiouy]e)$/, '');
+ word = word.replace(/^y/, '');
+
+ const syllables = word.match(/[aeiouy]{1,2}/g);
+ return syllables ? syllables.length : 1;
+ }
+
+ private calculateInformationDensity(content: ExtractedContent): number {
+ const tokens = this.tokenizeContent(content.content);
+ const technicalTerms = tokens.filter(t => this.technicalTerms.has(t));
+ return Math.min(1, technicalTerms.length / (tokens.length * 0.2));
+ }
+
+ private calculateTechnicalDepth(content: ExtractedContent): number {
+ const tokens = this.tokenizeContent(content.content);
+ const uniqueTechnicalTerms = new Set(
+ tokens.filter(t => this.technicalTerms.has(t))
+ );
+ return Math.min(1, uniqueTechnicalTerms.size / 20);
+ }
+
+ private calculateCredibilityScore(content: ExtractedContent): number {
+ let score = 0.5; // Base score
+
+ // Check for technical domain
+ if (content.url.includes('.gov') ||
+ content.url.includes('.edu') ||
+ content.url.includes('csrc.') ||
+ content.url.includes('nist.')) {
+ score += 0.2;
+ }
+
+ // Check for citations
+ const citations = this.extractCitations(content);
+ if (citations.length > 0) {
+ score += 0.1;
+ }
+
+ // Check for technical content
+ const tokens = this.tokenizeContent(content.content);
+ const technicalTermRatio = tokens.filter(t => this.technicalTerms.has(t)).length / tokens.length;
+ score += technicalTermRatio * 0.2;
+
+ return Math.min(1, score);
+ }
+
+ private calculateFreshnessScore(content: ExtractedContent): number {
+ if (!content.metadata?.datePublished) return 0.5;
+
+ const published = new Date(content.metadata.datePublished);
+ const now = new Date();
+ const ageInDays = (now.getTime() - published.getTime()) / (1000 * 60 * 60 * 24);
+
+ // Score decreases with age, but technical content stays relevant longer
+ return Math.max(0, Math.min(1, 1 - (ageInDays / 365)));
+ }
+
+ private extractCitations(content: ExtractedContent): Citation[] {
+ const citations: Citation[] = [];
+ const text = content.content;
+
+ // Look for standard references
+ const standardRefs = text.match(/(?:FIPS|SP|RFC)\s+\d+(?:-\d+)?/g) || [];
+ standardRefs.forEach(ref => {
+ citations.push({
+ text: ref,
+ type: 'standard'
+ });
+ });
+
+ // Look for URL citations
+ const urls = text.match(/https?:\/\/[^\s)]+/g) || [];
+ urls.forEach(url => {
+ citations.push({
+ text: url,
+ type: 'url',
+ source: url
+ });
+ });
+
+ return citations;
+ }
+
+ private isStopWord(word: string): boolean {
+ return natural.stopwords.includes(word.toLowerCase());
+ }
+
+ private calculateRelevanceScore(content: ExtractedContent, topics: Topic[]): number {
+ // Calculate overall relevance based on topics and content quality
+ const topicScore = topics.reduce((sum, topic) => sum + topic.confidence, 0) / (topics.length || 1);
+ const quality = this.assessQuality(content);
+
+ return Math.min(
+ 1,
+ (topicScore * 0.6) +
+ (quality.technicalDepth * 0.2) +
+ (quality.informationDensity * 0.2)
+ );
+ }
+
+ private isBoilerplate(text: string): boolean {
+ return this.boilerplatePatterns.some(pattern => pattern.test(text));
+ }
+}
\ No newline at end of file
diff --git a/src/core/content-extractor.ts b/src/core/content-extractor.ts
new file mode 100644
index 0000000..933d0d5
--- /dev/null
+++ b/src/core/content-extractor.ts
@@ -0,0 +1,779 @@
+import * as cheerio from 'cheerio';
+import htmlToMd from 'html-to-md';
+import { ExtractedContent, ContentMetadata, ContentSection, ContentExtractionOptions } from '../types/content.js';
+
+type CheerioRoot = ReturnType;
+
+export class ContentExtractor {
+ private technicalSelectors = [
+ // Code blocks and examples
+ 'pre', 'code', '.example', '.code-example',
+ // API and implementation details
+ '.api-details', '.implementation-details',
+ '.method-signature', '.function-signature',
+ // Parameters and documentation
+ '.parameters', '.returns', '.arguments',
+ '.technical-docs', '.api-docs'
+ ];
+
+ private boilerplateSelectors = [
+ // Navigation elements
+ 'nav', 'header', 'footer',
+ // Social sharing
+ '.social-share', '.share-buttons', '[id*="share"]', '[class*="share"]',
+ // Navigation menus
+ '.menu', '.navigation', '#menu', '#nav',
+ // Sidebars
+ '.sidebar', '#sidebar', '[class*="sidebar"]',
+ // Comments
+ '#comments', '.comments', '.comment-section',
+ // Advertisements
+ '.ad', '.ads', '.advertisement', '[id*="ad-"]', '[class*="ad-"]',
+ // Popups and overlays
+ '.popup', '.modal', '.overlay',
+ // Common UI elements
+ '.header-content', '.footer-content', '.site-header', '.site-footer',
+ // Cookie notices and banners
+ '.cookie-notice', '.cookie-banner', '.gdpr', '[class*="cookie"]', '[id*="cookie"]',
+ // Search and related content
+ '.search', '.search-form', '.related-posts', '.related-articles',
+ // Common widget areas
+ '.widget', '.widgets', '[class*="widget"]',
+ // Newsletter and subscription forms
+ '.newsletter', '.subscribe', '[class*="newsletter"]', '[class*="subscribe"]',
+ // Social media elements
+ '.social', '.social-media', '[class*="social"]',
+ // Print and utility links
+ '.print', '.utility-nav', '[class*="print"]',
+ // Common dynamic elements
+ '[data-widget]', '[data-module]',
+ // Common tracking and analytics
+ '[data-analytics]', '[data-tracking]',
+ // Additional UI elements
+ 'button', '[role="button"]', '.button', '.btn',
+ // Footer-like elements
+ '[class*="footer"]', '[id*="footer"]', 'c4d-footer', 'c4d-footer-container',
+ // Navigation-like elements
+ '[class*="nav"]', '[id*="nav"]', 'c4d-nav',
+ // Legal and policy elements
+ '[class*="legal"]', '[id*="legal"]', '[class*="policy"]', '[id*="policy"]',
+ // Common web components
+ 'c4d-*',
+ // Additional cookie-related elements
+ '[class*="cookie-preferences"]', '[id*="cookie-preferences"]',
+ '[class*="cookie-settings"]', '[id*="cookie-settings"]',
+ '[class*="cookie-consent"]', '[id*="cookie-consent"]',
+ // Additional button-related elements
+ '[class*="btn-"]', '[id*="btn-"]', '[class*="button-"]', '[id*="button-"]',
+ // Additional navigation elements
+ '[class*="menu-"]', '[id*="menu-"]', '[class*="navigation-"]', '[id*="navigation-"]',
+ // Additional footer elements
+ '[class*="bottom-"]', '[id*="bottom-"]', '[class*="foot-"]', '[id*="foot-"]'
+ ];
+
+ private htmlToMarkdownOptions = {
+ skipTags: [], // Don't skip any tags by default
+ emDelimiter: '_',
+ bulletListMarker: '-',
+ codeBlockStyle: 'fenced',
+ headingStyle: 'atx',
+ keepReplacement: true,
+ keepHtml: false,
+ listStyle: 'dash',
+ codeStyle: 'fenced',
+ customRules: [
+ // Custom rule for links
+ {
+ selector: 'a',
+ replacement: (content: string, node: any) => {
+ const href = node.getAttribute('href');
+ // Only preserve external links
+ if (href && href.startsWith('http')) {
+ return `[${content}](${href})`;
+ }
+ return content;
+ }
+ },
+ // Custom rule for images
+ {
+ selector: 'img',
+ replacement: (content: string, node: any) => {
+ const alt = node.getAttribute('alt');
+ return alt ? `[Image: ${alt}]` : '';
+ }
+ },
+ // Custom rule for tables
+ {
+ selector: 'table',
+ replacement: (content: string, node: any) => {
+ return this.convertTableToMarkdown(node);
+ }
+ }
+ ]
+ };
+
+ private convertTableToMarkdown(tableNode: any): string {
+ const $ = cheerio.load(tableNode);
+ let markdown = '\n';
+
+ // Get all rows including header row
+ const rows = $('tr').toArray();
+ if (rows.length === 0) return '';
+
+ // Get maximum number of columns
+ const maxColumns = Math.max(...rows.map(row => $(row).find('th, td').length));
+ if (maxColumns === 0) return '';
+
+ // Process headers
+ const headerRow = $(rows[0]);
+ const headers: string[] = [];
+ headerRow.find('th, td').each((_, cell) => {
+ headers.push($(cell).text().trim() || ' ');
+ });
+ // Pad headers if needed
+ while (headers.length < maxColumns) {
+ headers.push(' ');
+ }
+
+ // Create header row
+ markdown += '| ' + headers.join(' | ') + ' |\n';
+ // Create separator row with proper alignment
+ markdown += '|' + Array(maxColumns).fill(' --- ').join('|') + '|\n';
+
+ // Process data rows (skip first row if it was header)
+ for (let i = headerRow.find('th').length > 0 ? 1 : 0; i < rows.length; i++) {
+ const cells: string[] = [];
+ $(rows[i]).find('td').each((_, cell) => {
+ cells.push($(cell).text().trim() || ' ');
+ });
+ // Pad cells if needed
+ while (cells.length < maxColumns) {
+ cells.push(' ');
+ }
+ markdown += '| ' + cells.join(' | ') + ' |\n';
+ }
+
+ return markdown + '\n';
+ }
+
+ public async extract(html: string, url: string, options: ContentExtractionOptions = {}): Promise {
+ console.log('Starting content extraction for URL:', url);
+ console.log('Initial HTML length:', html.length);
+
+ const $ = cheerio.load(html);
+ console.log('DOM loaded successfully');
+
+ // Remove unwanted elements
+ console.log('Cleaning up DOM...');
+ this.cleanupDOM($);
+ console.log('DOM cleanup complete');
+
+ // Extract metadata
+ console.log('Extracting metadata...');
+ const metadata = this.extractMetadata($);
+ console.log('Metadata extracted:', metadata);
+
+ // Extract main content sections
+ console.log('Extracting content sections...');
+ const sections = this.extractContentSections($);
+ console.log('Found sections:', sections.length);
+ sections.forEach((section, index) => {
+ console.log(`Section ${index + 1}:`, {
+ id: section.id,
+ type: section.type,
+ title: section.title,
+ importance: section.importance,
+ contentLength: section.content.length
+ });
+ });
+
+ // Extract structured data
+ const structuredData = options.extractStructuredData ?
+ this.extractStructuredData($) : undefined;
+
+ // Convert content to markdown
+ console.log('Converting content to markdown...');
+ const mainContent = sections
+ .map(section => section.content)
+ .join('\n\n');
+
+ const content = htmlToMd(mainContent, this.htmlToMarkdownOptions);
+ console.log('Markdown conversion complete. Length:', content.length);
+
+ // Clean up and format the content
+ console.log('Cleaning and formatting content...');
+ const cleanedContent = this.cleanContent(this.formatMarkdown(content));
+ console.log('Content cleanup complete. Final length:', cleanedContent.length);
+
+ const title = this.extractTitle($);
+ console.log('Extracted title:', title);
+
+ const result = {
+ url,
+ title,
+ content: this.truncateContent(cleanedContent, options.maxContentLength),
+ html: options.includeHtml ? html : undefined,
+ timestamp: new Date().toISOString(),
+ metadata,
+ structuredData
+ };
+
+ console.log('Content extraction complete');
+ return result;
+ }
+
+ private cleanupDOM($: CheerioRoot): void {
+ console.log('Starting DOM cleanup...');
+
+ // First pass: Remove obvious non-content elements
+ $('script, style, noscript, iframe, form, link, meta').remove();
+ $('[style*="display: none"], [style*="display:none"], [hidden]').remove();
+
+ // Second pass: Identify and preserve main content areas
+ const mainContentSelectors = [
+ 'article',
+ '[role="main"]',
+ 'main',
+ '.main-content',
+ '#main-content',
+ '.post-content',
+ '.article-content',
+ '.entry-content',
+ '.content',
+ '.documentation',
+ '.markdown-body'
+ ];
+
+ let mainContent = $('body');
+ for (const selector of mainContentSelectors) {
+ const element = $(selector);
+ if (element.length > 0) {
+ mainContent = element;
+ console.log(`Found main content using selector: ${selector}`);
+ break;
+ }
+ }
+
+ // Third pass: Remove boilerplate from main content
+ this.boilerplateSelectors.forEach(selector => {
+ mainContent.find(selector).each((_, elem) => {
+ const $elem = $(elem);
+ if (!this.containsTechnicalContent($elem)) {
+ $elem.remove();
+ }
+ });
+ });
+
+ // Fourth pass: Clean up remaining elements
+ mainContent.find('*').each((_, elem) => {
+ const $elem = $(elem);
+ const text = $elem.text().trim();
+
+ // Skip if element contains technical content
+ if (this.containsTechnicalContent($elem)) {
+ return;
+ }
+
+ // Remove elements that are clearly UI components
+ if (
+ text.match(/^(close|dismiss|accept|cancel|loading|\d+ min read|share|menu|search)$/i) ||
+ text.match(/^(follow us|subscribe|sign up|log in|register)$/i) ||
+ text.match(/^(cookie|privacy|terms|gdpr)/i)
+ ) {
+ $elem.remove();
+ return;
+ }
+
+ // Remove empty elements except code blocks
+ if (!$elem.is('pre, code') && text === '' && !$elem.find('img').length) {
+ $elem.remove();
+ }
+ });
+
+ // Fifth pass: Remove duplicate content but preserve code blocks
+ const seen = new Set();
+ mainContent.find('p, li, td, div').each((_, elem) => {
+ const $elem = $(elem);
+ if (this.containsTechnicalContent($elem)) {
+ return; // Don't deduplicate technical content
+ }
+ const text = $elem.text().trim();
+ if (text && seen.has(text)) {
+ $elem.remove();
+ } else {
+ seen.add(text);
+ }
+ });
+
+ // Replace body content with cleaned main content
+ $('body').empty().append(mainContent);
+ console.log('DOM cleanup complete');
+ }
+
+ private containsTechnicalContent($elem: cheerio.Cheerio): boolean {
+ // Check if element matches technical selectors
+ if (this.technicalSelectors.some(selector => $elem.is(selector))) {
+ return true;
+ }
+
+ // Check if element contains code blocks
+ if ($elem.find('pre, code').length > 0) {
+ return true;
+ }
+
+ // Check for technical keywords in text
+ const text = $elem.text().toLowerCase();
+ return (
+ text.includes('example') ||
+ text.includes('implementation') ||
+ text.includes('usage') ||
+ text.includes('api') ||
+ text.includes('method') ||
+ text.includes('function') ||
+ text.includes('parameter') ||
+ text.includes('return') ||
+ text.includes('class') ||
+ text.includes('interface') ||
+ text.includes('object') ||
+ text.includes('pattern')
+ );
+ }
+
+ private cleanContent(content: string): string {
+ return content
+ // Remove duplicate newlines
+ .replace(/\n{3,}/g, '\n\n')
+ // Remove lines that are just special characters or very short
+ .split('\n')
+ .filter(line => {
+ const trimmed = line.trim();
+ if (trimmed.length < 3) return false;
+ if (/^[-_=*#]+$/.test(trimmed)) return false;
+ return true;
+ })
+ // Remove duplicate paragraphs
+ .filter((line, index, arr) => {
+ return arr.indexOf(line) === index;
+ })
+ .join('\n');
+ }
+
+ private extractTitle($: CheerioRoot): string {
+ // Try OpenGraph title first
+ const ogTitle = $('meta[property="og:title"]').attr('content');
+ if (ogTitle) return ogTitle;
+
+ // Try article title
+ const articleTitle = $('article h1').first().text();
+ if (articleTitle) return articleTitle;
+
+ // Try main title
+ const mainTitle = $('h1').first().text() || $('title').text();
+ if (mainTitle) return mainTitle;
+
+ return 'Untitled';
+ }
+
+ private extractMetadata($: CheerioRoot): ContentMetadata {
+ const metadata: ContentMetadata = {};
+
+ // Extract author
+ metadata.author =
+ $('meta[name="author"]').attr('content') ||
+ $('meta[property="article:author"]').attr('content') ||
+ $('.author').first().text() ||
+ $('[itemprop="author"]').first().text();
+
+ // Extract dates
+ metadata.datePublished =
+ $('meta[property="article:published_time"]').attr('content') ||
+ $('meta[name="publication-date"]').attr('content') ||
+ $('[itemprop="datePublished"]').attr('content');
+
+ metadata.lastModified =
+ $('meta[property="article:modified_time"]').attr('content') ||
+ $('[itemprop="dateModified"]').attr('content');
+
+ // Extract language
+ metadata.language = $('html').attr('lang') || undefined;
+
+ // Calculate reading time and word count
+ const text = $('body').text();
+ const words = text.trim().split(/\s+/).length;
+ metadata.wordCount = words;
+ metadata.readingTime = Math.ceil(words / 200); // Assuming 200 words per minute
+
+ return metadata;
+ }
+
+ private extractContentSections($: CheerioRoot): ContentSection[] {
+ console.log('Starting content section extraction...');
+ const sections: ContentSection[] = [];
+
+ // Enhanced main content selectors with scoring
+ const mainSelectors = [
+ { selector: 'article[class*="content"]', score: 10 },
+ { selector: '[role="main"]', score: 9 },
+ { selector: 'main', score: 8 },
+ { selector: '.main-content', score: 8 },
+ { selector: '#main-content', score: 8 },
+ { selector: '.post-content', score: 7 },
+ { selector: '.article-content', score: 7 },
+ { selector: '.entry-content', score: 7 },
+ { selector: '.content', score: 6 },
+ { selector: '.documentation', score: 8 },
+ { selector: '.markdown-body', score: 7 },
+ { selector: '[itemprop="articleBody"]', score: 8 },
+ { selector: '[data-content-type="article"]', score: 8 }
+ ];
+
+ // Find best content container based on scoring
+ let bestScore = 0;
+ let mainContent: cheerio.Cheerio = $('body');
+
+ mainSelectors.forEach(({ selector, score }) => {
+ const elements = $(selector);
+ elements.each((_, element) => {
+ const $element = $(element);
+ let elementScore = score;
+
+ // Boost score based on content quality
+ elementScore += this.evaluateContentQuality($element);
+
+ if (elementScore > bestScore) {
+ bestScore = elementScore;
+ mainContent = $element;
+ console.log(`Found better content container: ${selector} (score: ${elementScore})`);
+ }
+ });
+ });
+
+ // Clean up the selected content container
+ this.cleanupContentContainer($, mainContent);
+
+ // Extract sections based on semantic structure
+ let currentSection: ContentSection = {
+ id: 'main',
+ content: '',
+ importance: 1,
+ type: 'main'
+ };
+
+ // Process content hierarchically
+ mainContent.find('h1, h2, h3, h4, h5, h6, p, pre, code, .example, .implementation, .method, .function, section, article').each((_, element) => {
+ const $element = $(element);
+ const text = $element.text().trim();
+
+ if (!text) return;
+
+ // Check for section breaks
+ const isHeading = $element.is('h1, h2, h3, h4, h5, h6');
+ const isTechnical = this.containsTechnicalContent($element);
+ const isNewSection = $element.is('section, article') && $element.find('h1, h2, h3, h4, h5, h6').length > 0;
+
+ if (isHeading || isTechnical || isNewSection) {
+ // Save current section if it has content
+ if (currentSection.content.trim()) {
+ sections.push(currentSection);
+ }
+
+ // Calculate importance
+ const importance = this.calculateSectionImportance($element, isHeading, isTechnical);
+
+ // Create new section
+ currentSection = {
+ id: `section-${sections.length + 1}`,
+ title: isHeading ? text : (isTechnical ? 'Technical Content' : 'Content Section'),
+ content: '',
+ importance,
+ type: isTechnical ? 'technical' : 'main'
+ };
+ }
+
+ // Add content to current section
+ if (isTechnical) {
+ // Include context for technical content
+ const context = this.getContextualContent($, $element);
+ currentSection.content += '\n' + (context || $element.html() || '');
+ } else {
+ currentSection.content += '\n' + ($element.html() || '');
+ }
+ });
+
+ // Add final section
+ if (currentSection.content.trim()) {
+ sections.push(currentSection);
+ }
+
+ console.log(`Extracted ${sections.length} content sections`);
+ return sections;
+ }
+
+ private evaluateContentQuality($element: cheerio.Cheerio): number {
+ let score = 0;
+
+ // Check for technical content density
+ const text = $element.text();
+ const technicalTerms = text.match(/\b(api|function|method|class|interface|example|implementation|code|return|parameter)\b/gi);
+ if (technicalTerms) {
+ score += technicalTerms.length * 0.5;
+ }
+
+ // Check for code blocks
+ score += $element.find('pre, code').length * 2;
+
+ // Check for proper content structure
+ score += $element.find('h1, h2, h3, h4, h5, h6').length;
+ score += $element.find('p').length * 0.5;
+ score += $element.find('ul, ol').length;
+
+ // Penalize for common boilerplate
+ score -= $element.find(this.boilerplateSelectors.join(', ')).length * 2;
+
+ return score;
+ }
+
+ private calculateSectionImportance($element: cheerio.Cheerio, isHeading: boolean, isTechnical: boolean): number {
+ let importance = 0.5;
+
+ if (isHeading) {
+ const level = parseInt($element.prop('tagName').slice(1));
+ importance = Math.max(0.5, 1 - (level - 1) * 0.1);
+ }
+
+ if (isTechnical) {
+ importance += 0.3;
+ }
+
+ // Boost importance based on content quality
+ const contentQuality = this.evaluateContentQuality($element);
+ importance += Math.min(0.2, contentQuality * 0.05);
+
+ return Math.min(1, importance);
+ }
+
+ private findContextContainer($: CheerioRoot, $element: cheerio.Cheerio): cheerio.Cheerio {
+ // Look for the nearest container that provides context
+ let $container = $element;
+ let depth = 0;
+ const maxDepth = 3; // Prevent going too far up the DOM
+
+ while (depth < maxDepth) {
+ const $parent = $container.parent();
+ if (!$parent.length) break;
+
+ // Check if parent provides good context
+ const parentText = $parent.text().trim();
+ const hasContext = parentText.length > $container.text().length * 1.5 &&
+ this.containsTechnicalContent($parent);
+
+ if (hasContext) {
+ $container = $parent;
+ }
+
+ depth++;
+ }
+
+ return $container;
+ }
+
+ private getContextualContent($: CheerioRoot, $element: cheerio.Cheerio): string | null {
+ const container = this.findContextContainer($, $element);
+ if (!container.length) return null;
+
+ // Get previous sibling if it's a heading or description
+ let content = '';
+ const $prevSibling = container.prev();
+ if ($prevSibling.is('h1, h2, h3, h4, p') &&
+ this.containsTechnicalContent($prevSibling)) {
+ content += $prevSibling.html() + '\n';
+ }
+
+ content += container.html() || '';
+
+ // Get next sibling if it provides additional context
+ const $nextSibling = container.next();
+ if ($nextSibling.is('p') &&
+ this.containsTechnicalContent($nextSibling)) {
+ content += '\n' + $nextSibling.html();
+ }
+
+ return content;
+ }
+
+ private calculateImportance($element: cheerio.Cheerio): number {
+ let importance = 0.5;
+
+ // Base importance on heading level
+ if ($element.is('h1')) importance = 1;
+ else if ($element.is('h2')) importance = 0.8;
+ else if ($element.is('h3')) importance = 0.6;
+
+ // Increase importance based on content indicators
+ const text = $element.text().toLowerCase();
+ if (
+ text.includes('example') ||
+ text.includes('implementation') ||
+ text.includes('usage') ||
+ text.includes('api') ||
+ text.includes('method') ||
+ text.includes('function') ||
+ text.includes('parameter') ||
+ text.includes('return')
+ ) {
+ importance += 0.2;
+ }
+
+ // Increase importance if contains code
+ if ($element.find('code').length > 0 || $element.is('pre')) {
+ importance += 0.2;
+ }
+
+ // Increase importance for technical elements
+ if ($element.is(this.technicalSelectors.join(','))) {
+ importance += 0.1;
+ }
+
+ return Math.min(importance, 1);
+ }
+
+ private extractStructuredData($: CheerioRoot): any[] {
+ const structuredData: any[] = [];
+
+ // Extract JSON-LD
+ $('script[type="application/ld+json"]').each((_, element) => {
+ try {
+ const data = JSON.parse($(element).html() || '{}');
+ structuredData.push(data);
+ } catch (error) {
+ // Ignore invalid JSON
+ }
+ });
+
+ return structuredData;
+ }
+
+ private formatMarkdown(content: string): string {
+ // First pass: Basic cleanup
+ let formatted = content
+ // Fix list markers
+ .replace(/^\* /gm, '- ')
+ // Add spacing around headers
+ .replace(/^(#{1,6} .+)$/gm, '\n$1\n')
+ // Add spacing around lists
+ .replace(/^(- .+)$/gm, '$1\n');
+
+ // Handle code blocks
+ formatted = formatted.replace(/`([^`]+)`/g, (match, code) => {
+ if (code.includes('\n') || code.includes('function')) {
+ return '\n\n```\n' + code.trim() + '\n```\n\n';
+ }
+ return '`' + code.trim() + '`';
+ });
+
+ // Add spacing between sections
+ formatted = formatted.replace(/^(#{1,6} .*)/gm, '\n\n$1\n');
+
+ // Handle tables - complete rewrite of table structure
+ formatted = formatted.replace(/\|(.*)\|\n/g, (match: string, row: string) => {
+ const cells = row.split('|').map((cell: string) => cell.trim()).filter((cell: string) => cell);
+ if (cells.length === 0) return '';
+
+ // Detect if this is a separator row
+ if (cells.every(cell => /^[-\s]+$/.test(cell))) {
+ return ''; // Skip separator rows, we'll add our own
+ }
+
+ // Check if this is a header row (no separator row seen yet)
+ if (!formatted.includes('| ---')) {
+ const separator = cells.map(() => '---').join(' | ');
+ return '| ' + cells.join(' | ') + ' |\n| ' + separator + ' |\n';
+ }
+
+ return '| ' + cells.join(' | ') + ' |\n';
+ });
+
+ // Final cleanup
+ return formatted
+ // Fix paragraph spacing
+ .replace(/\n{3,}/g, '\n\n')
+ // Ensure sections are properly separated
+ .replace(/(\w)\n(#{1,6} )/g, '$1\n\n$2')
+ // Add proper spacing around code blocks
+ .replace(/```/g, '\n```\n')
+ .replace(/\n{4,}/g, '\n\n\n')
+ .trim();
+ }
+
+ private cleanupContentContainer($: CheerioRoot, $container: cheerio.Cheerio): void {
+ console.log('Cleaning up content container...');
+
+ // Remove nested boilerplate elements
+ this.boilerplateSelectors.forEach(selector => {
+ $container.find(selector).each((_, elem) => {
+ const $elem = $(elem);
+ // Keep element if it contains technical content
+ if (!this.containsTechnicalContent($elem)) {
+ $elem.remove();
+ }
+ });
+ });
+
+ // Remove empty elements
+ $container.find('*').each((_, elem) => {
+ const $elem = $(elem);
+ const text = $elem.text().trim();
+
+ // Skip technical content and elements with images
+ if (this.containsTechnicalContent($elem) || $elem.find('img').length > 0) {
+ return;
+ }
+
+ // Remove if empty or just whitespace
+ if (!text || text.length < 3) {
+ $elem.remove();
+ return;
+ }
+
+ // Remove common UI text patterns
+ if (
+ text.match(/^(close|dismiss|accept|cancel|loading|\d+ min read|share|menu|search)$/i) ||
+ text.match(/^(follow us|subscribe|sign up|log in|register)$/i) ||
+ text.match(/^(cookie|privacy|terms|gdpr)/i)
+ ) {
+ $elem.remove();
+ }
+ });
+
+ // Remove duplicate content
+ const seen = new Set();
+ $container.find('p, li, td, div').each((_, elem) => {
+ const $elem = $(elem);
+
+ // Skip technical content
+ if (this.containsTechnicalContent($elem)) {
+ return;
+ }
+
+ const text = $elem.text().trim();
+ if (text && seen.has(text)) {
+ $elem.remove();
+ } else {
+ seen.add(text);
+ }
+ });
+
+ console.log('Content container cleanup complete');
+ }
+
+ private truncateContent(content: string, maxLength?: number): string {
+ if (!maxLength || content.length <= maxLength) {
+ return content;
+ }
+
+ // Truncate at word boundary
+ const truncated = content.slice(0, maxLength);
+ const lastSpace = truncated.lastIndexOf(' ');
+ return truncated.slice(0, lastSpace) + '...';
+ }
+}
\ No newline at end of file
diff --git a/src/core/research-session.ts b/src/core/research-session.ts
new file mode 100644
index 0000000..c7fc673
--- /dev/null
+++ b/src/core/research-session.ts
@@ -0,0 +1,460 @@
+import { ResearchSession as IResearchSession, ResearchPlan, ResearchStep, ResearchProgress, ResearchFindings, StepResult, SessionOptions, Evidence } from '../types/session.js';
+import { ContentExtractor } from './content-extractor.js';
+import { ContentAnalyzer } from './content-analyzer.js';
+import { ExtractedContent } from '../types/content.js';
+import { ContentAnalysis } from '../types/analysis.js';
+import { chromium, Browser, BrowserContext } from 'playwright';
+import { parse as parseUrl } from 'url';
+
+export class ResearchSession implements IResearchSession {
+ public id: string;
+ public topic: string;
+ public status: 'planning' | 'in_progress' | 'analyzing' | 'synthesizing' | 'completed' | 'failed' | 'cancelled';
+ public plan: ResearchPlan;
+ public progress: ResearchProgress;
+ public findings: ResearchFindings;
+ public timestamp: {
+ created: string;
+ updated: string;
+ completed?: string;
+ };
+
+ private visitedUrls: Set;
+ private contentExtractor: ContentExtractor;
+ private contentAnalyzer: ContentAnalyzer;
+ private options: Required;
+ private browser: Browser | null = null;
+ private context: BrowserContext | null = null;
+ private startTime: number;
+
+ private checkTimeout(): void {
+ const elapsed = Date.now() - this.startTime;
+ if (elapsed >= this.options.timeout) {
+ throw new Error('Research session timeout');
+ }
+ }
+
+ constructor(topic: string, options: SessionOptions = {}) {
+ this.id = `research_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
+ this.topic = topic;
+ this.status = 'planning';
+ this.visitedUrls = new Set();
+ this.contentExtractor = new ContentExtractor();
+ this.contentAnalyzer = new ContentAnalyzer();
+ this.startTime = Date.now();
+
+ this.options = {
+ maxSteps: options.maxSteps || 10,
+ maxDepth: options.maxDepth || 2,
+ maxBranching: options.maxBranching || 3,
+ timeout: options.timeout || 55000, // Set below MCP timeout
+ minRelevanceScore: options.minRelevanceScore || 0.7,
+ maxParallelOperations: options.maxParallelOperations || 3
+ };
+
+ this.plan = this.createInitialPlan();
+ this.progress = this.initializeProgress();
+ this.findings = this.initializeFindings();
+ this.timestamp = {
+ created: new Date().toISOString(),
+ updated: new Date().toISOString()
+ };
+ }
+
+ private async initializeBrowser(): Promise {
+ if (!this.browser) {
+ this.browser = await chromium.launch({ headless: true });
+ this.context = await this.browser.newContext({
+ userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
+ viewport: { width: 1280, height: 800 },
+ deviceScaleFactor: 1,
+ isMobile: false,
+ hasTouch: false
+ });
+ }
+ }
+
+ private isProcessableUrl(url: string): boolean {
+ try {
+ const parsedUrl = parseUrl(url);
+ const path = parsedUrl.pathname?.toLowerCase() || '';
+
+ // Skip PDFs and other non-HTML content
+ const skipExtensions = ['.pdf', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx'];
+ if (skipExtensions.some(ext => path.endsWith(ext))) {
+ console.error(`Skipping non-HTML content: ${url}`);
+ return false;
+ }
+
+ return true;
+ } catch (error) {
+ console.error(`Invalid URL: ${url}`);
+ return false;
+ }
+ }
+
+ private async fetchContent(url: string): Promise {
+ this.checkTimeout();
+
+ if (!this.isProcessableUrl(url)) {
+ throw new Error(`Cannot process URL: ${url}`);
+ }
+
+ await this.initializeBrowser();
+ if (!this.context) throw new Error('Browser context not initialized');
+
+ const page = await this.context.newPage();
+ try {
+ // Navigate to the URL with a reduced timeout
+ await page.goto(url, {
+ waitUntil: 'domcontentloaded',
+ timeout: 10000 // 10 seconds max for page load
+ });
+
+ // Get the HTML content immediately without waiting for additional content
+ const html = await page.content();
+ return html;
+ } catch (error) {
+ console.error(`Error fetching content from ${url}:`, error);
+ throw error;
+ } finally {
+ await page.close();
+ }
+ }
+
+ public async processUrl(url: string, depth: number = 0): Promise {
+ console.log(`Processing URL: ${url} at depth ${depth}`);
+
+ if (this.visitedUrls.has(url)) {
+ console.log(`URL already visited: ${url}`);
+ return { searchResults: [] };
+ }
+
+ try {
+ console.log('Fetching content...');
+ const htmlContent = await this.fetchContent(url);
+ console.log('Content fetched, length:', htmlContent.length);
+
+ console.log('Extracting content...');
+ const content = await this.contentExtractor.extract(htmlContent, url);
+ console.log('Content extracted, title:', content.title);
+ this.visitedUrls.add(url);
+
+ console.log('Analyzing content...');
+ const analysis = await this.contentAnalyzer.analyze(content);
+ console.log('Analysis complete:', {
+ topics: analysis.topics.length,
+ keyPoints: analysis.keyPoints.length,
+ relevanceScore: analysis.relevanceScore
+ });
+
+ // Update progress
+ this.progress.processedContent++;
+ this.progress.visitedUrls.add(url);
+ this.updateTimestamp();
+
+ console.log('Processing findings...');
+ await this.processFindings(content, analysis, depth);
+ console.log('Findings processed');
+
+ const result = {
+ searchResults: [{
+ url,
+ title: content.title,
+ snippet: content.content.substring(0, 200),
+ relevanceScore: analysis.relevanceScore
+ }],
+ extractedContents: [content],
+ analysis
+ };
+
+ console.log('URL processing complete:', {
+ title: content.title,
+ contentLength: content.content.length,
+ relevanceScore: analysis.relevanceScore
+ });
+
+ return result;
+ } catch (error) {
+ console.error(`Error processing URL ${url}:`, error);
+ return { searchResults: [] };
+ }
+ }
+
+ private createInitialPlan(): ResearchPlan {
+ return {
+ steps: [],
+ estimatedTime: 0,
+ maxDepth: this.options.maxDepth,
+ maxBranching: this.options.maxBranching,
+ focusAreas: []
+ };
+ }
+
+ private initializeProgress(): ResearchProgress {
+ return {
+ completedSteps: 0,
+ totalSteps: 0,
+ visitedUrls: new Set(),
+ processedContent: 0,
+ startTime: new Date().toISOString()
+ };
+ }
+
+ private initializeFindings(): ResearchFindings {
+ return {
+ mainTopics: [],
+ keyInsights: [],
+ sources: []
+ };
+ }
+
+ private async processFindings(content: ExtractedContent, analysis: ContentAnalysis, depth: number): Promise {
+ console.log('Processing findings for:', content.url);
+
+ try {
+ // Extract code blocks and technical sections first
+ console.log('Extracting code blocks and technical sections...');
+ const codeBlocks = this.extractCodeBlocks(content.content);
+ const technicalSections = this.extractTechnicalSections(content.content);
+ console.log('Found:', {
+ codeBlocks: codeBlocks.length,
+ technicalSections: technicalSections.length
+ });
+
+ // Update main topics with higher weight for technical content
+ console.log('Updating topics...');
+ console.log('Before update - Topics:', this.findings.mainTopics.length);
+ this.updateTopics(analysis, technicalSections);
+ console.log('After update - Topics:', this.findings.mainTopics.length);
+
+ // Update key insights with code examples
+ console.log('Updating insights...');
+ console.log('Before update - Insights:', this.findings.keyInsights.length);
+ this.updateInsights(analysis, codeBlocks, technicalSections);
+ console.log('After update - Insights:', this.findings.keyInsights.length);
+
+ // Update sources with technical content score
+ console.log('Updating sources...');
+ console.log('Before update - Sources:', this.findings.sources.length);
+ this.updateSources(content, analysis, technicalSections.length > 0);
+ console.log('After update - Sources:', this.findings.sources.length);
+
+ // Process related URLs if within depth limit
+ if (depth < this.options.maxDepth) {
+ console.log(`Processing related URLs at depth ${depth}...`);
+ await this.processRelatedUrls(content, depth + 1);
+ } else {
+ console.log(`Max depth ${this.options.maxDepth} reached, skipping related URLs`);
+ }
+
+ console.log('Findings processing complete');
+ } catch (error) {
+ console.error('Error processing findings:', error);
+ }
+ }
+
+ private extractCodeBlocks(content: string): string[] {
+ const blocks: string[] = [];
+ // Match both fenced code blocks and inline code
+ const codeRegex = /```[\s\S]*?```|`[^`]+`/g;
+ let match;
+
+ while ((match = codeRegex.exec(content)) !== null) {
+ blocks.push(match[0]);
+ }
+
+ return blocks;
+ }
+
+ private extractTechnicalSections(content: string): string[] {
+ const sections: string[] = [];
+ const technicalIndicators = [
+ 'implementation',
+ 'example',
+ 'usage',
+ 'code',
+ 'method',
+ 'function',
+ 'class',
+ 'pattern',
+ 'practice'
+ ];
+
+ // Split content into paragraphs
+ const paragraphs = content.split(/\n\n+/);
+
+ // Find paragraphs containing technical content
+ paragraphs.forEach(paragraph => {
+ const lowerParagraph = paragraph.toLowerCase();
+ if (
+ technicalIndicators.some(indicator => lowerParagraph.includes(indicator)) ||
+ paragraph.includes('```') ||
+ /`[^`]+`/.test(paragraph)
+ ) {
+ sections.push(paragraph);
+ }
+ });
+
+ return sections;
+ }
+
+ private updateTopics(analysis: ContentAnalysis, technicalSections: string[]): void {
+ console.log('Updating topics with analysis:', {
+ topicsCount: analysis.topics ? analysis.topics.length : 0,
+ technicalSectionsCount: technicalSections.length
+ });
+
+ if (!analysis.topics || analysis.topics.length === 0) {
+ console.log('No topics found in analysis');
+ return;
+ }
+
+ analysis.topics.forEach(topic => {
+ console.log('Processing topic:', {
+ name: topic.name,
+ confidence: topic.confidence
+ });
+
+ const existingTopic = this.findings.mainTopics.find(t => t.name === topic.name);
+ const hasTechnicalContent = technicalSections.some(section =>
+ section.toLowerCase().includes(topic.name.toLowerCase())
+ );
+
+ const adjustedConfidence = hasTechnicalContent ?
+ Math.min(1, topic.confidence * 1.3) :
+ topic.confidence;
+
+ console.log('Topic analysis:', {
+ hasTechnicalContent,
+ originalConfidence: topic.confidence,
+ adjustedConfidence
+ });
+
+ if (existingTopic) {
+ console.log('Updating existing topic:', existingTopic.name);
+ existingTopic.importance = Math.max(existingTopic.importance, adjustedConfidence);
+ } else {
+ console.log('Adding new topic:', topic.name);
+ this.findings.mainTopics.push({
+ name: topic.name,
+ importance: adjustedConfidence,
+ relatedTopics: [],
+ evidence: []
+ });
+ }
+ });
+
+ // Sort topics by importance
+ this.findings.mainTopics.sort((a, b) => b.importance - a.importance);
+ console.log('Updated topics count:', this.findings.mainTopics.length);
+ }
+
+ private updateInsights(analysis: ContentAnalysis, codeBlocks: string[], technicalSections: string[]): void {
+ analysis.keyPoints.forEach(point => {
+ // Find related code examples
+ const relatedCode = codeBlocks.filter(code =>
+ this.isCodeRelatedToPoint(code, point.text)
+ );
+
+ // Find related technical sections
+ const relatedTechnical = technicalSections.filter(section =>
+ this.isSectionRelatedToPoint(section, point.text)
+ );
+
+ // Adjust confidence based on technical content
+ let adjustedConfidence = point.importance;
+ if (relatedCode.length > 0) adjustedConfidence *= 1.2;
+ if (relatedTechnical.length > 0) adjustedConfidence *= 1.1;
+
+ if (adjustedConfidence >= this.options.minRelevanceScore) {
+ // Convert code blocks and technical sections to Evidence objects
+ const evidence: Evidence[] = [
+ ...relatedCode.map(code => ({
+ claim: "Code example supporting the insight",
+ sources: [code],
+ confidence: 0.9
+ })),
+ ...relatedTechnical.map(section => ({
+ claim: "Technical documentation supporting the insight",
+ sources: [section],
+ confidence: 0.8
+ }))
+ ];
+
+ this.findings.keyInsights.push({
+ text: point.text,
+ confidence: Math.min(1, adjustedConfidence),
+ supportingEvidence: evidence,
+ relatedTopics: point.topics
+ });
+ }
+ });
+
+ // Sort insights by confidence
+ this.findings.keyInsights.sort((a, b) => b.confidence - a.confidence);
+ }
+
+ private updateSources(content: ExtractedContent, analysis: ContentAnalysis, hasTechnicalContent: boolean): void {
+ const source = {
+ url: content.url,
+ title: content.title,
+ credibilityScore: hasTechnicalContent ?
+ Math.min(1, analysis.quality.credibilityScore * 1.2) :
+ analysis.quality.credibilityScore,
+ contributedFindings: analysis.keyPoints.map(point => point.text)
+ };
+
+ const existingSource = this.findings.sources.find(s => s.url === content.url);
+ if (!existingSource) {
+ this.findings.sources.push(source);
+ }
+ }
+
+ private isCodeRelatedToPoint(code: string, point: string): boolean {
+ const codeTerms = new Set(code.toLowerCase().split(/\W+/));
+ const pointTerms = new Set(point.toLowerCase().split(/\W+/));
+
+ // Check for common terms
+ const intersection = [...pointTerms].filter(term => codeTerms.has(term));
+ return intersection.length >= 2; // At least 2 common terms
+ }
+
+ private isSectionRelatedToPoint(section: string, point: string): boolean {
+ const sectionLower = section.toLowerCase();
+ const pointLower = point.toLowerCase();
+
+ // Check for significant term overlap
+ const sectionTerms = new Set(sectionLower.split(/\W+/));
+ const pointTerms = new Set(pointLower.split(/\W+/));
+ const intersection = [...pointTerms].filter(term => sectionTerms.has(term));
+
+ return intersection.length >= 3 || // At least 3 common terms
+ sectionLower.includes(pointLower) || // Contains the entire point
+ pointLower.includes(sectionLower); // Point contains the section
+ }
+
+ private async processRelatedUrls(content: ExtractedContent, depth: number): Promise {
+ // Extract URLs from content and process them
+ // This would be implemented to handle actual URL extraction and processing
+ }
+
+ private updateTimestamp(): void {
+ this.timestamp.updated = new Date().toISOString();
+ }
+
+ public async complete(): Promise {
+ this.status = 'completed';
+ this.timestamp.completed = new Date().toISOString();
+
+ // Cleanup browser
+ if (this.context) {
+ await this.context.close();
+ this.context = null;
+ }
+ if (this.browser) {
+ await this.browser.close();
+ this.browser = null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/deep-research.ts b/src/deep-research.ts
new file mode 100644
index 0000000..41f5a2f
--- /dev/null
+++ b/src/deep-research.ts
@@ -0,0 +1,238 @@
+import { ResearchSession } from './core/research-session.js';
+import { ParallelSearch } from './parallel-search.js';
+import { SearchQueue } from './search-queue.js';
+import { SearchResult } from './types/session.js';
+
+export interface DeepResearchOptions {
+ maxDepth?: number;
+ maxBranching?: number;
+ timeout?: number;
+ minRelevanceScore?: number;
+ maxParallelOperations?: number;
+}
+
+export interface ResearchResult {
+ sessionId: string;
+ topic: string;
+ findings: {
+ mainTopics: Array<{
+ name: string;
+ importance: number;
+ relatedTopics: string[];
+ }>;
+ keyInsights: Array<{
+ text: string;
+ confidence: number;
+ relatedTopics: string[];
+ }>;
+ sources: Array<{
+ url: string;
+ title: string;
+ credibilityScore: number;
+ }>;
+ };
+ progress: {
+ completedSteps: number;
+ totalSteps: number;
+ processedUrls: number;
+ };
+ timing: {
+ started: string;
+ completed?: string;
+ duration?: number;
+ operations?: {
+ parallelSearch?: number;
+ deduplication?: number;
+ topResultsProcessing?: number;
+ remainingResultsProcessing?: number;
+ total?: number;
+ };
+ };
+}
+
+export class DeepResearch {
+ public parallelSearch: ParallelSearch;
+ private searchQueue: SearchQueue;
+ private activeSessions: Map;
+
+ constructor() {
+ this.parallelSearch = new ParallelSearch();
+ this.searchQueue = new SearchQueue();
+ this.activeSessions = new Map();
+ }
+
+ private deduplicateResults(results: SearchResult[]): SearchResult[] {
+ const seen = new Set();
+ return results.filter(result => {
+ const normalizedUrl = this.normalizeUrl(result.url);
+ if (seen.has(normalizedUrl)) {
+ return false;
+ }
+ seen.add(normalizedUrl);
+ return true;
+ });
+ }
+
+ private normalizeUrl(url: string): string {
+ try {
+ // Remove protocol, www, trailing slashes, and query parameters
+ return url
+ .replace(/^https?:\/\//, '')
+ .replace(/^www\./, '')
+ .replace(/\/$/, '')
+ .split('?')[0]
+ .split('#')[0]
+ .toLowerCase();
+ } catch (error) {
+ return url.toLowerCase();
+ }
+ }
+
+ public async startResearch(topic: string, options: DeepResearchOptions = {}): Promise {
+ const startTime = Date.now();
+ const timings: { [key: string]: number } = {};
+
+ console.log('[Performance] Starting research for topic:', topic);
+ console.log('[Performance] Options:', options);
+
+ // Create new research session
+ const session = new ResearchSession(topic, {
+ maxDepth: options.maxDepth,
+ maxBranching: options.maxBranching,
+ timeout: options.timeout,
+ minRelevanceScore: options.minRelevanceScore,
+ maxParallelOperations: options.maxParallelOperations
+ });
+
+ console.log('[Performance] Created research session:', session.id);
+ this.activeSessions.set(session.id, session);
+
+ try {
+ console.log('[Performance] Starting parallel search...');
+ const parallelSearchStart = Date.now();
+
+ const queries = [
+ topic,
+ `${topic} tutorial`,
+ `${topic} guide`,
+ `${topic} example`,
+ `${topic} implementation`,
+ `${topic} code`,
+ `${topic} design pattern`,
+ `${topic} best practice`
+ ];
+ console.log('[Performance] Search queries:', queries);
+
+ const searchResults = await this.parallelSearch.parallelSearch(queries);
+ timings.parallelSearch = Date.now() - parallelSearchStart;
+ console.log('[Performance] Parallel search complete. Duration:', timings.parallelSearch, 'ms');
+
+ const deduplicationStart = Date.now();
+ const allResults = searchResults.results.flatMap(result => result.results);
+ console.log('[Performance] Total results:', allResults.length);
+
+ const uniqueResults = this.deduplicateResults(allResults);
+ console.log('[Performance] Unique results:', uniqueResults.length);
+
+ const sortedResults = uniqueResults.sort((a, b) => b.relevanceScore - a.relevanceScore);
+ timings.deduplication = Date.now() - deduplicationStart;
+ console.log('[Performance] Deduplication complete. Duration:', timings.deduplication, 'ms');
+
+ // Process top results first
+ console.log('[Performance] Processing top 5 results...');
+ const topProcessingStart = Date.now();
+ const topResults = sortedResults.slice(0, 5);
+ await Promise.all(topResults.map(r => {
+ console.log('[Performance] Processing URL:', r.url);
+ return session.processUrl(r.url);
+ }));
+ timings.topResultsProcessing = Date.now() - topProcessingStart;
+ console.log('[Performance] Top results processing complete. Duration:', timings.topResultsProcessing, 'ms');
+
+ // Process remaining results
+ console.log('[Performance] Processing remaining results...');
+ const remainingProcessingStart = Date.now();
+ const remainingResults = sortedResults.slice(5);
+ await Promise.all(remainingResults.map(r => {
+ console.log('[Performance] Processing URL:', r.url);
+ return session.processUrl(r.url);
+ }));
+ timings.remainingResultsProcessing = Date.now() - remainingProcessingStart;
+ console.log('[Performance] Remaining results processing complete. Duration:', timings.remainingResultsProcessing, 'ms');
+
+ // Complete the session
+ console.log('[Performance] Completing session...');
+ await session.complete();
+
+ // Format and return results
+ console.log('[Performance] Formatting results...');
+ const results = this.formatResults(session);
+
+ // Add timing information
+ timings.total = Date.now() - startTime;
+ results.timing.operations = {
+ parallelSearch: timings.parallelSearch,
+ deduplication: timings.deduplication,
+ topResultsProcessing: timings.topResultsProcessing,
+ remainingResultsProcessing: timings.remainingResultsProcessing,
+ total: timings.total
+ };
+
+ console.log('[Performance] Research complete. Total duration:', timings.total, 'ms');
+ console.log('[Performance] Operation timings:', timings);
+
+ return results;
+ } catch (error) {
+ console.error(`[Performance] Error in research session ${session.id}:`, error);
+ throw error;
+ } finally {
+ // Cleanup
+ this.activeSessions.delete(session.id);
+ await this.parallelSearch.cleanup();
+ }
+ }
+
+ private formatResults(session: ResearchSession): ResearchResult {
+ return {
+ sessionId: session.id,
+ topic: session.topic,
+ findings: {
+ mainTopics: session.findings.mainTopics.map(topic => ({
+ name: topic.name,
+ importance: topic.importance,
+ relatedTopics: topic.relatedTopics
+ })),
+ keyInsights: session.findings.keyInsights.map(insight => ({
+ text: insight.text,
+ confidence: insight.confidence,
+ relatedTopics: insight.relatedTopics
+ })),
+ sources: session.findings.sources.map(source => ({
+ url: source.url,
+ title: source.title,
+ credibilityScore: source.credibilityScore
+ }))
+ },
+ progress: {
+ completedSteps: session.progress.completedSteps,
+ totalSteps: session.progress.totalSteps,
+ processedUrls: session.progress.visitedUrls.size
+ },
+ timing: {
+ started: session.timestamp.created,
+ completed: session.timestamp.completed,
+ duration: session.timestamp.completed ?
+ new Date(session.timestamp.completed).getTime() - new Date(session.timestamp.created).getTime()
+ : undefined
+ }
+ };
+ }
+
+ public async getSessionStatus(sessionId: string): Promise {
+ const session = this.activeSessions.get(sessionId);
+ if (!session) return null;
+ return this.formatResults(session);
+ }
+}
+
+export default DeepResearch;
\ No newline at end of file
diff --git a/src/index.ts b/src/index.ts
new file mode 100644
index 0000000..1cee7e3
--- /dev/null
+++ b/src/index.ts
@@ -0,0 +1,409 @@
+#!/usr/bin/env node
+import { Server } from '@modelcontextprotocol/sdk/server/index.js';
+import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
+import {
+ CallToolRequestSchema,
+ ErrorCode,
+ ListToolsRequestSchema,
+ McpError
+} from '@modelcontextprotocol/sdk/types.js';
+import { chromium, Browser, Page } from 'playwright';
+import TurndownService from 'turndown';
+
+import DeepResearch from './deep-research.js';
+
+interface DeepResearchArgs {
+ topic: string;
+ maxDepth?: number;
+ maxBranching?: number;
+ timeout?: number;
+ minRelevanceScore?: number;
+}
+
+interface ParallelSearchArgs {
+ queries: string[];
+ maxParallel?: number;
+}
+
+interface VisitPageArgs {
+ url: string;
+}
+
+// Initialize Turndown service for converting HTML to Markdown
+const turndownService = new TurndownService({
+ headingStyle: 'atx',
+ hr: '---',
+ bulletListMarker: '-',
+ codeBlockStyle: 'fenced',
+ emDelimiter: '_',
+ strongDelimiter: '**',
+ linkStyle: 'inlined',
+});
+
+// Custom Turndown rules
+turndownService.addRule('removeScripts', {
+ filter: ['script', 'style', 'noscript'],
+ replacement: () => ''
+});
+
+turndownService.addRule('preserveLinks', {
+ filter: 'a',
+ replacement: (content: string, node: Node) => {
+ const element = node as HTMLAnchorElement;
+ const href = element.getAttribute('href');
+ return href ? `[${content}](${href})` : content;
+ }
+});
+
+// Redirect console output to stderr to keep stdout clean for MCP communication
+const originalConsoleLog = console.log;
+const originalConsoleError = console.error;
+console.log = (...args) => {
+ process.stderr.write(`[INFO] ${args.join(' ')}\n`);
+};
+console.error = (...args) => {
+ process.stderr.write(`[ERROR] ${args.join(' ')}\n`);
+};
+
+const deepResearch = new DeepResearch();
+let browser: Browser | undefined;
+let page: Page | undefined;
+
+const server = new Server(
+ {
+ name: 'mcp-deepwebresearch',
+ version: '0.3.0'
+ },
+ {
+ capabilities: {
+ tools: {}
+ }
+ }
+);
+
+// List available tools
+server.setRequestHandler(ListToolsRequestSchema, async () => ({
+ tools: [
+ {
+ name: 'deep_research',
+ description: 'Perform deep research on a topic with content extraction and analysis',
+ inputSchema: {
+ type: 'object',
+ properties: {
+ topic: {
+ type: 'string',
+ description: 'Research topic or question'
+ },
+ maxDepth: {
+ type: 'number',
+ description: 'Maximum depth of related content exploration',
+ minimum: 1,
+ maximum: 2
+ },
+ maxBranching: {
+ type: 'number',
+ description: 'Maximum number of related paths to explore',
+ minimum: 1,
+ maximum: 3
+ },
+ timeout: {
+ type: 'number',
+ description: 'Research timeout in milliseconds',
+ minimum: 30000,
+ maximum: 55000
+ },
+ minRelevanceScore: {
+ type: 'number',
+ description: 'Minimum relevance score for including content',
+ minimum: 0,
+ maximum: 1
+ }
+ },
+ required: ['topic']
+ }
+ },
+ {
+ name: 'parallel_search',
+ description: 'Perform multiple Google searches in parallel',
+ inputSchema: {
+ type: 'object',
+ properties: {
+ queries: {
+ type: 'array',
+ items: {
+ type: 'string'
+ },
+ description: 'Array of search queries to execute in parallel'
+ },
+ maxParallel: {
+ type: 'number',
+ description: 'Maximum number of parallel searches',
+ minimum: 1,
+ maximum: 5
+ }
+ },
+ required: ['queries']
+ }
+ },
+ {
+ name: 'visit_page',
+ description: 'Visit a webpage and extract its content',
+ inputSchema: {
+ type: 'object',
+ properties: {
+ url: {
+ type: 'string',
+ description: 'URL to visit'
+ }
+ },
+ required: ['url']
+ }
+ }
+ ]
+}));
+
+// Validate URL format and security
+function isValidUrl(urlString: string): boolean {
+ try {
+ const url = new URL(urlString);
+ return url.protocol === 'http:' || url.protocol === 'https:';
+ } catch {
+ return false;
+ }
+}
+
+// Safe page navigation with timeout
+async function safePageNavigation(page: Page, url: string): Promise {
+ await page.goto(url, {
+ waitUntil: 'domcontentloaded',
+ timeout: 10000 // 10 second timeout
+ });
+
+ // Quick check for bot protection or security challenges
+ const validation = await page.evaluate(() => {
+ const botProtectionExists = [
+ '#challenge-running',
+ '#cf-challenge-running',
+ '#px-captcha',
+ '#ddos-protection',
+ '#waf-challenge-html'
+ ].some(selector => document.querySelector(selector));
+
+ const suspiciousTitle = [
+ 'security check',
+ 'ddos protection',
+ 'please wait',
+ 'just a moment',
+ 'attention required'
+ ].some(phrase => document.title.toLowerCase().includes(phrase));
+
+ return {
+ botProtection: botProtectionExists,
+ suspiciousTitle,
+ title: document.title
+ };
+ });
+
+ if (validation.botProtection) {
+ throw new Error('Bot protection detected');
+ }
+
+ if (validation.suspiciousTitle) {
+ throw new Error(`Suspicious page title detected: "${validation.title}"`);
+ }
+}
+
+// Extract content as markdown
+async function extractContentAsMarkdown(page: Page): Promise {
+ const html = await page.evaluate(() => {
+ // Try standard content containers first
+ const contentSelectors = [
+ 'main',
+ 'article',
+ '[role="main"]',
+ '#content',
+ '.content',
+ '.main',
+ '.post',
+ '.article'
+ ];
+
+ for (const selector of contentSelectors) {
+ const element = document.querySelector(selector);
+ if (element) {
+ return element.outerHTML;
+ }
+ }
+
+ // Fallback to cleaning full body content
+ const body = document.body;
+ const elementsToRemove = [
+ 'header', 'footer', 'nav',
+ '[role="navigation"]', 'aside',
+ '.sidebar', '[role="complementary"]',
+ '.nav', '.menu', '.header',
+ '.footer', '.advertisement',
+ '.ads', '.cookie-notice'
+ ];
+
+ elementsToRemove.forEach(sel => {
+ body.querySelectorAll(sel).forEach(el => el.remove());
+ });
+
+ return body.outerHTML;
+ });
+
+ if (!html) {
+ return '';
+ }
+
+ try {
+ const markdown = turndownService.turndown(html);
+ return markdown
+ .replace(/\n{3,}/g, '\n\n')
+ .replace(/^- $/gm, '')
+ .replace(/^\s+$/gm, '')
+ .trim();
+ } catch (error) {
+ console.error('Error converting HTML to Markdown:', error);
+ return html;
+ }
+}
+
+// Ensure browser is initialized
+async function ensureBrowser(): Promise {
+ if (!browser) {
+ browser = await chromium.launch({ headless: true });
+ const context = await browser.newContext();
+ page = await context.newPage();
+ }
+
+ if (!page) {
+ const context = await browser.newContext();
+ page = await context.newPage();
+ }
+
+ return page;
+}
+
+// Handle tool calls
+server.setRequestHandler(CallToolRequestSchema, async (request) => {
+ try {
+ switch (request.params.name) {
+ case 'deep_research': {
+ const args = request.params.arguments as unknown as DeepResearchArgs;
+ if (!args?.topic) {
+ throw new McpError(ErrorCode.InvalidParams, 'Topic is required');
+ }
+
+ console.log(`Starting deep research on topic: ${args.topic}`);
+ const result = await deepResearch.startResearch(args.topic, {
+ maxDepth: Math.min(args.maxDepth || 2, 2),
+ maxBranching: Math.min(args.maxBranching || 3, 3),
+ timeout: Math.min(args.timeout || 55000, 55000),
+ minRelevanceScore: args.minRelevanceScore || 0.7
+ });
+
+ return {
+ content: [
+ {
+ type: 'text',
+ text: JSON.stringify(result, null, 2)
+ }
+ ]
+ };
+ }
+
+ case 'parallel_search': {
+ const args = request.params.arguments as unknown as ParallelSearchArgs;
+ if (!args?.queries) {
+ throw new McpError(ErrorCode.InvalidParams, 'Queries array is required');
+ }
+
+ const limitedQueries = args.queries.slice(0, 5);
+ console.log(`Starting parallel search with ${limitedQueries.length} queries`);
+ const result = await deepResearch.parallelSearch.parallelSearch(limitedQueries);
+
+ return {
+ content: [
+ {
+ type: 'text',
+ text: JSON.stringify(result, null, 2)
+ }
+ ]
+ };
+ }
+
+ case 'visit_page': {
+ const args = request.params.arguments as unknown as VisitPageArgs;
+ if (!args?.url) {
+ throw new McpError(ErrorCode.InvalidParams, 'URL is required');
+ }
+
+ if (!isValidUrl(args.url)) {
+ throw new McpError(
+ ErrorCode.InvalidParams,
+ `Invalid URL: ${args.url}. Only http and https protocols are supported.`
+ );
+ }
+
+ const page = await ensureBrowser();
+ try {
+ await safePageNavigation(page, args.url);
+ const title = await page.title();
+ const content = await extractContentAsMarkdown(page);
+
+ return {
+ content: [
+ {
+ type: 'text',
+ text: JSON.stringify({
+ url: args.url,
+ title,
+ content
+ }, null, 2)
+ }
+ ]
+ };
+ } catch (error) {
+ throw new McpError(
+ ErrorCode.InternalError,
+ `Failed to visit page: ${(error as Error).message}`
+ );
+ }
+ }
+
+ default:
+ throw new McpError(
+ ErrorCode.MethodNotFound,
+ `Unknown tool: ${request.params.name}`
+ );
+ }
+ } catch (error) {
+ console.error('Error executing tool:', error);
+ throw new McpError(
+ ErrorCode.InternalError,
+ error instanceof Error ? error.message : 'Unknown error occurred'
+ );
+ }
+});
+
+// Error handling
+server.onerror = (error) => {
+ console.error('[MCP Error]', error);
+};
+
+// Handle shutdown
+process.on('SIGINT', async () => {
+ if (browser) {
+ await browser.close();
+ }
+ await server.close();
+ process.exit(0);
+});
+
+// Start the server
+const transport = new StdioServerTransport();
+server.connect(transport).catch(console.error);
+
+console.error('MCP Web Research server running on stdio');
\ No newline at end of file
diff --git a/src/parallel-search.ts b/src/parallel-search.ts
new file mode 100644
index 0000000..0235c07
--- /dev/null
+++ b/src/parallel-search.ts
@@ -0,0 +1,278 @@
+import { Browser, BrowserContext, chromium } from 'playwright';
+import { writeFile, mkdir } from 'fs/promises';
+import path from 'path';
+import os from 'os';
+import { ParallelSearchResult, SearchResult, SearchOptions } from './types.js';
+
+const USER_AGENTS = [
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0',
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15',
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/121.0'
+];
+
+const VIEWPORT_SIZES = [
+ { width: 1920, height: 1080 },
+ { width: 1366, height: 768 },
+ { width: 1536, height: 864 },
+ { width: 1440, height: 900 },
+ { width: 1280, height: 720 }
+];
+
+export class ParallelSearch {
+ private browser: Browser | null = null;
+ private contexts: BrowserContext[] = [];
+ private options: Required;
+
+ constructor(options: SearchOptions = {}) {
+ this.options = {
+ maxParallel: options.maxParallel || 10,
+ delayBetweenSearches: options.delayBetweenSearches || 200,
+ outputDir: path.isAbsolute(options.outputDir || '')
+ ? (options.outputDir || path.join(os.tmpdir(), 'search-results'))
+ : path.join(os.tmpdir(), options.outputDir || 'search-results'),
+ retryAttempts: options.retryAttempts || 3,
+ includeTimings: options.includeTimings || false
+ };
+ }
+
+ private getSearchResult(result: SearchResult[], searchId: string, query: string, startTime?: number, error?: string): ParallelSearchResult {
+ const base: ParallelSearchResult = {
+ searchId,
+ query,
+ results: result,
+ error
+ };
+
+ if (this.options.includeTimings && startTime) {
+ return {
+ ...base,
+ executionTime: Date.now() - startTime
+ };
+ }
+
+ return base;
+ }
+
+ private async initialize(): Promise {
+ if (!this.browser) {
+ this.browser = await chromium.launch({ headless: true });
+ // Create browser contexts
+ for (let i = 0; i < this.options.maxParallel; i++) {
+ const context = await this.browser.newContext({
+ userAgent: USER_AGENTS[i % USER_AGENTS.length],
+ viewport: VIEWPORT_SIZES[i % VIEWPORT_SIZES.length],
+ deviceScaleFactor: 1 + (Math.random() * 0.5),
+ hasTouch: Math.random() > 0.5
+ });
+ this.contexts.push(context);
+ }
+ }
+ }
+
+ private async saveResults(searchId: string, query: string, results: SearchResult[]): Promise {
+ const filename = `${searchId}-${query.replace(/[^a-z0-9]/gi, '_')}.json`;
+ const outputDir = this.options.outputDir;
+
+ // Create output directory if it doesn't exist
+ await mkdir(outputDir, { recursive: true });
+
+ const filepath = path.join(outputDir, filename);
+ await writeFile(filepath, JSON.stringify({
+ searchId,
+ query,
+ timestamp: new Date().toISOString(),
+ results
+ }, null, 2));
+ return filepath;
+ }
+
+ private async singleSearch(
+ context: BrowserContext,
+ query: string,
+ searchId: string
+ ): Promise {
+ const startTime = this.options.includeTimings ? Date.now() : undefined;
+ const page = await context.newPage();
+ try {
+ await page.goto('https://www.google.com', { waitUntil: 'networkidle' });
+
+ // Wait for and handle any consent dialog
+ try {
+ const consentButton = await page.$('button:has-text("Accept all")');
+ if (consentButton) {
+ await consentButton.click();
+ await page.waitForLoadState('networkidle');
+ }
+ } catch (error) {
+ // Ignore consent handling errors
+ }
+
+ // Try different selectors for search input
+ const searchInput = await page.$(
+ 'textarea[name="q"], input[name="q"], input[type="text"]'
+ );
+
+ if (!searchInput) {
+ throw new Error('Search input not found');
+ }
+
+ await searchInput.click();
+ await searchInput.fill(query);
+ await Promise.all([
+ page.keyboard.press('Enter'),
+ page.waitForNavigation({ waitUntil: 'networkidle' })
+ ]);
+
+ // Wait for search results to appear
+ await page.waitForSelector('div.g', { timeout: 10000 });
+
+ // Extract results after ensuring they're loaded
+ const results = await page.$$eval('div.g', (elements, query) => {
+ return elements.map((el, index) => {
+ const titleEl = el.querySelector('h3');
+ const linkEl = el.querySelector('a');
+ const snippetEl = el.querySelector('div.VwiC3b');
+
+ if (!titleEl || !linkEl || !snippetEl) return null;
+
+ const title = titleEl.textContent || '';
+ const url = linkEl.href || '';
+ const snippet = snippetEl.textContent || '';
+
+ // Calculate relevance score based on multiple factors
+ let relevanceScore = 0;
+
+ // Position score (earlier results are more relevant)
+ relevanceScore += Math.max(0, 1 - (index * 0.1));
+
+ // Title match score
+ const titleMatchScore = title.toLowerCase().includes(query.toLowerCase()) ? 0.3 : 0;
+ relevanceScore += titleMatchScore;
+
+ // Snippet match score
+ const snippetMatchScore = snippet.toLowerCase().includes(query.toLowerCase()) ? 0.2 : 0;
+ relevanceScore += snippetMatchScore;
+
+ // URL quality score
+ const urlQualityScore =
+ url.includes('.edu') ? 0.3 :
+ url.includes('.gov') ? 0.3 :
+ url.includes('github.com') ? 0.25 :
+ url.includes('stackoverflow.com') ? 0.25 :
+ url.includes('docs.') ? 0.25 :
+ 0.1;
+ relevanceScore += urlQualityScore;
+
+ return {
+ title,
+ url,
+ snippet,
+ relevanceScore: Math.min(1, relevanceScore)
+ };
+ }).filter(result => result !== null);
+ }, query);
+
+ if (!results || results.length === 0) {
+ throw new Error('No search results found');
+ }
+
+ await this.saveResults(searchId, query, results);
+ return this.getSearchResult(results, searchId, query, startTime);
+ } catch (error) {
+ return this.getSearchResult(
+ [],
+ searchId,
+ query,
+ startTime,
+ error instanceof Error ? error.message : 'Unknown error occurred'
+ );
+ } finally {
+ await page.close();
+ }
+ }
+
+ public async parallelSearch(queries: string[]): Promise<{
+ results: ParallelSearchResult[];
+ summary: {
+ totalQueries: number;
+ successful: number;
+ failed: number;
+ totalExecutionTime?: number;
+ averageExecutionTime?: number;
+ };
+ }> {
+ const startTime = this.options.includeTimings ? Date.now() : undefined;
+ await this.initialize();
+
+ const results: ParallelSearchResult[] = [];
+ const chunks: string[][] = [];
+
+ // Split queries into chunks of maxParallel size
+ for (let i = 0; i < queries.length; i += this.options.maxParallel) {
+ chunks.push(queries.slice(i, i + this.options.maxParallel));
+ }
+
+ // Process each chunk
+ for (const chunk of chunks) {
+ const chunkPromises = chunk.map((query, index) => {
+ const searchId = `search_${Date.now()}_${index + 1}_of_${chunk.length}`;
+ // Stagger the searches
+ return new Promise(async (resolve) => {
+ await new Promise(r => setTimeout(r, index * this.options.delayBetweenSearches));
+ const result = await this.singleSearch(
+ this.contexts[index % this.contexts.length],
+ query,
+ searchId
+ );
+ resolve(result);
+ });
+ });
+
+ const chunkResults = await Promise.all(chunkPromises);
+ results.push(...chunkResults);
+
+ // Add a small delay between chunks
+ if (chunks.indexOf(chunk) < chunks.length - 1) {
+ await new Promise(r => setTimeout(r, 1000));
+ }
+ }
+
+ const endTime = Date.now();
+ const successful = results.filter(r => !r.error).length;
+ const failed = results.filter(r => r.error).length;
+
+ const summary = {
+ totalQueries: queries.length,
+ successful,
+ failed,
+ ...(this.options.includeTimings && startTime ? {
+ totalExecutionTime: endTime - startTime,
+ averageExecutionTime: Math.round((endTime - startTime) / queries.length)
+ } : {})
+ };
+
+ // Add individual execution times to results if timing is enabled
+ const timedResults = this.options.includeTimings ? results.map(r => ({
+ ...r,
+ executionTime: r.executionTime || 0
+ })) : results;
+
+ return {
+ results: timedResults,
+ summary
+ };
+ }
+
+ public async cleanup(): Promise {
+ for (const context of this.contexts) {
+ await context.close();
+ }
+ this.contexts = [];
+ if (this.browser) {
+ await this.browser.close();
+ this.browser = null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/search-queue.ts b/src/search-queue.ts
new file mode 100644
index 0000000..802ca19
--- /dev/null
+++ b/src/search-queue.ts
@@ -0,0 +1,138 @@
+import { RateLimiterMemory } from 'rate-limiter-flexible';
+import EventEmitter from 'events';
+
+interface SearchQueueItem {
+ id: string;
+ query: string;
+ status: 'pending' | 'in_progress' | 'completed' | 'failed';
+ results?: any[];
+ error?: string;
+ timestamp: number;
+ retryCount: number;
+}
+
+interface QueueStatus {
+ totalItems: number;
+ completed: number;
+ pending: number;
+ failed: number;
+ currentItem?: SearchQueueItem;
+}
+
+export class SearchQueue extends EventEmitter {
+ private queue: SearchQueueItem[] = [];
+ private inProgress: boolean = false;
+ private rateLimiter: RateLimiterMemory;
+
+ constructor() {
+ super();
+ // Allow 1 request per 2 seconds with burst of 3
+ this.rateLimiter = new RateLimiterMemory({
+ points: 3,
+ duration: 6,
+ });
+ }
+
+ public async addSearch(query: string): Promise {
+ const id = `search_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
+ const item: SearchQueueItem = {
+ id,
+ query,
+ status: 'pending',
+ timestamp: Date.now(),
+ retryCount: 0
+ };
+
+ this.queue.push(item);
+ this.emit('itemAdded', item);
+
+ if (!this.inProgress) {
+ this.processQueue();
+ }
+
+ return id;
+ }
+
+ public async addBatchSearch(queries: string[]): Promise {
+ return Promise.all(queries.map(query => this.addSearch(query)));
+ }
+
+ public getStatus(): QueueStatus {
+ const completed = this.queue.filter(item => item.status === 'completed').length;
+ const pending = this.queue.filter(item => item.status === 'pending').length;
+ const failed = this.queue.filter(item => item.status === 'failed').length;
+ const currentItem = this.queue.find(item => item.status === 'in_progress');
+
+ return {
+ totalItems: this.queue.length,
+ completed,
+ pending,
+ failed,
+ currentItem
+ };
+ }
+
+ public cancelSearch(id: string): boolean {
+ const index = this.queue.findIndex(item => item.id === id && item.status === 'pending');
+ if (index !== -1) {
+ this.queue[index].status = 'failed';
+ this.queue[index].error = 'Cancelled by user';
+ this.emit('itemCancelled', this.queue[index]);
+ return true;
+ }
+ return false;
+ }
+
+ private async processQueue(): Promise {
+ if (this.inProgress || this.queue.length === 0) {
+ return;
+ }
+
+ this.inProgress = true;
+
+ while (this.queue.some(item => item.status === 'pending')) {
+ try {
+ await this.rateLimiter.consume('search', 1);
+
+ const item = this.queue.find(item => item.status === 'pending');
+ if (!item) continue;
+
+ item.status = 'in_progress';
+ this.emit('itemStarted', item);
+
+ try {
+ // Perform the search - this will be implemented in the browser class
+ // const results = await this.browser.search(item.query);
+ // item.results = results;
+ item.status = 'completed';
+ this.emit('itemCompleted', item);
+ } catch (error) {
+ if (item.retryCount < 3) {
+ item.retryCount++;
+ item.status = 'pending';
+ this.emit('itemRetrying', item);
+ // Add exponential backoff delay
+ await new Promise(resolve => setTimeout(resolve, Math.pow(2, item.retryCount) * 1000));
+ } else {
+ item.status = 'failed';
+ item.error = error instanceof Error ? error.message : 'Unknown error occurred';
+ this.emit('itemFailed', item);
+ }
+ }
+ } catch (error) {
+ // Rate limiter error - wait and try again
+ await new Promise(resolve => setTimeout(resolve, 5000));
+ }
+ }
+
+ this.inProgress = false;
+ this.emit('queueCompleted', this.getStatus());
+ }
+
+ public clearCompleted(): void {
+ this.queue = this.queue.filter(item =>
+ item.status !== 'completed' && item.status !== 'failed'
+ );
+ this.emit('queueUpdated', this.getStatus());
+ }
+}
\ No newline at end of file
diff --git a/src/types.ts b/src/types.ts
new file mode 100644
index 0000000..cdbf0a1
--- /dev/null
+++ b/src/types.ts
@@ -0,0 +1,37 @@
+export interface SearchResult {
+ title: string;
+ url: string;
+ snippet: string;
+ relevanceScore: number;
+}
+
+export interface ParallelSearchResult {
+ searchId: string;
+ query: string;
+ results: SearchResult[];
+ error?: string;
+ executionTime?: number;
+}
+
+export interface SearchOptions {
+ maxParallel?: number;
+ delayBetweenSearches?: number;
+ outputDir?: string;
+ retryAttempts?: number;
+ includeTimings?: boolean;
+}
+
+export interface SearchSummary {
+ totalQueries: number;
+ successful: number;
+ failed: number;
+ totalExecutionTime?: number;
+ averageExecutionTime?: number;
+}
+
+export interface SearchOptions {
+ maxParallel?: number;
+ delayBetweenSearches?: number;
+ outputDir?: string;
+ retryAttempts?: number;
+}
\ No newline at end of file
diff --git a/src/types/analysis.ts b/src/types/analysis.ts
new file mode 100644
index 0000000..387aa5f
--- /dev/null
+++ b/src/types/analysis.ts
@@ -0,0 +1,80 @@
+export interface Topic {
+ name: string;
+ confidence: number;
+ keywords: string[];
+}
+
+export interface KeyPoint {
+ text: string;
+ importance: number;
+ topics: string[];
+ supportingEvidence: string[];
+}
+
+export type EntityType = 'standard' | 'algorithm' | 'organization' | 'person' | 'technology';
+
+export interface EntityMention {
+ text: string;
+ position: {
+ start: number;
+ end: number;
+ };
+ context: string;
+}
+
+export interface Entity {
+ name: string;
+ type: EntityType;
+ mentions: EntityMention[];
+}
+
+export interface Relationship {
+ source: string;
+ target: string;
+ type: string;
+ confidence: number;
+}
+
+export interface Citation {
+ text: string;
+ type: 'standard' | 'url' | 'reference';
+ source?: string;
+}
+
+export interface SentimentAnalysis {
+ score: number;
+ confidence: number;
+ aspects: Array<{
+ aspect: string;
+ score: number;
+ }>;
+}
+
+export interface ContentQuality {
+ readability: number;
+ informationDensity: number;
+ technicalDepth: number;
+ credibilityScore: number;
+ freshness: number;
+}
+
+export interface ContentAnalysis {
+ relevanceScore: number;
+ topics: Topic[];
+ keyPoints: KeyPoint[];
+ entities: Entity[];
+ sentiment: SentimentAnalysis;
+ relationships: Relationship[];
+ citations: Citation[];
+ quality: ContentQuality;
+}
+
+export interface AnalysisOptions {
+ maxTopics?: number;
+ maxKeyPoints?: number;
+ minConfidence?: number;
+ minImportance?: number;
+ includeSentiment?: boolean;
+ includeRelationships?: boolean;
+ includeCitations?: boolean;
+}
\ No newline at end of file
diff --git a/src/types/content.ts b/src/types/content.ts
new file mode 100644
index 0000000..2912536
--- /dev/null
+++ b/src/types/content.ts
@@ -0,0 +1,58 @@
+export interface ExtractedContent {
+ url: string;
+ title: string;
+ content: string;
+ html?: string;
+ timestamp: string;
+ metadata: ContentMetadata;
+ structuredData?: any[];
+}
+
+export interface ContentMetadata {
+ author?: string;
+ datePublished?: string;
+ lastModified?: string;
+ language?: string;
+ readingTime?: number;
+ wordCount?: number;
+}
+
+export interface ContentSection {
+ id: string;
+ title?: string;
+ content: string;
+ importance: number;
+ type: 'main' | 'technical' | 'sidebar' | 'header' | 'footer' | 'navigation' | 'other';
+}
+
+export interface StructuredContent {
+ mainContent: ContentSection[];
+ relatedLinks: string[];
+ images: ImageContent[];
+ tables: TableContent[];
+}
+
+export interface ImageContent {
+ url: string;
+ alt?: string;
+ caption?: string;
+ dimensions?: {
+ width: number;
+ height: number;
+ };
+}
+
+export interface TableContent {
+ headers: string[];
+ rows: string[][];
+ caption?: string;
+}
+
+export interface ContentExtractionOptions {
+ includeHtml?: boolean;
+ extractStructuredData?: boolean;
+ extractImages?: boolean;
+ extractTables?: boolean;
+ maxContentLength?: number;
+ timeout?: number;
+}
\ No newline at end of file
diff --git a/src/types/session.ts b/src/types/session.ts
new file mode 100644
index 0000000..4b6b828
--- /dev/null
+++ b/src/types/session.ts
@@ -0,0 +1,162 @@
+import { ExtractedContent } from './content';
+import { ContentAnalysis } from './analysis';
+
+export interface ResearchSession {
+ id: string;
+ topic: string;
+ status: ResearchStatus;
+ plan: ResearchPlan;
+ progress: ResearchProgress;
+ findings: ResearchFindings;
+ timestamp: {
+ created: string;
+ updated: string;
+ completed?: string;
+ };
+}
+
+export type ResearchStatus =
+ | 'planning'
+ | 'in_progress'
+ | 'analyzing'
+ | 'synthesizing'
+ | 'completed'
+ | 'failed'
+ | 'cancelled';
+
+export interface ResearchPlan {
+ steps: ResearchStep[];
+ estimatedTime: number;
+ maxDepth: number;
+ maxBranching: number;
+ focusAreas: string[];
+}
+
+export interface ResearchStep {
+ id: string;
+ type: StepType;
+ status: StepStatus;
+ query: string;
+ dependsOn: string[];
+ refinements: string[];
+ results: StepResult;
+ timing: {
+ started?: string;
+ completed?: string;
+ duration?: number;
+ };
+}
+
+export type StepType =
+ | 'initial_search'
+ | 'follow_up_search'
+ | 'content_extraction'
+ | 'analysis'
+ | 'synthesis';
+
+export type StepStatus =
+ | 'pending'
+ | 'in_progress'
+ | 'completed'
+ | 'failed'
+ | 'skipped';
+
+export interface StepResult {
+ searchResults?: SearchResult[];
+ extractedContents?: ExtractedContent[];
+ analysis?: ContentAnalysis;
+ synthesis?: SynthesisResult;
+}
+
+export interface SearchResult {
+ url: string;
+ title: string;
+ snippet: string;
+ relevanceScore: number;
+}
+
+export interface SynthesisResult {
+ summary: string;
+ keyFindings: string[];
+ relationships: RelationshipMap;
+ evidence: Evidence[];
+}
+
+export interface RelationshipMap {
+ nodes: Node[];
+ edges: Edge[];
+}
+
+export interface Node {
+ id: string;
+ type: string;
+ label: string;
+ properties: Record;
+}
+
+export interface Edge {
+ source: string;
+ target: string;
+ type: string;
+ properties: Record;
+}
+
+export interface Evidence {
+ claim: string;
+ sources: string[];
+ confidence: number;
+}
+
+export interface ResearchProgress {
+ completedSteps: number;
+ totalSteps: number;
+ currentStep?: string;
+ visitedUrls: Set;
+ processedContent: number;
+ startTime: string;
+ estimatedCompletion?: string;
+}
+
+export interface ResearchFindings {
+ mainTopics: Topic[];
+ keyInsights: KeyInsight[];
+ timeline?: TimelineEvent[];
+ sources: Source[];
+}
+
+export interface Topic {
+ name: string;
+ importance: number;
+ relatedTopics: string[];
+ evidence: Evidence[];
+}
+
+export interface KeyInsight {
+ text: string;
+ confidence: number;
+ supportingEvidence: Evidence[];
+ relatedTopics: string[];
+}
+
+export interface TimelineEvent {
+ date: string;
+ description: string;
+ importance: number;
+ sources: string[];
+}
+
+export interface Source {
+ url: string;
+ title: string;
+ credibilityScore: number;
+ contributedFindings: string[];
+}
+
+export interface SessionOptions {
+ maxSteps?: number;
+ maxDepth?: number;
+ maxBranching?: number;
+ timeout?: number;
+ minRelevanceScore?: number;
+ maxParallelOperations?: number;
+}
\ No newline at end of file
diff --git a/summarize_report.py b/summarize_report.py
new file mode 100644
index 0000000..9bbbfe5
--- /dev/null
+++ b/summarize_report.py
@@ -0,0 +1,163 @@
+import os
+import json
+from typing import List, Dict
+import boto3
+from dotenv import load_dotenv
+from concurrent.futures import ThreadPoolExecutor, as_completed
+
+# Load environment variables
+load_dotenv()
+
+class BedrockSummarizer:
+ def __init__(self):
+ self.bedrock = boto3.client(
+ service_name='bedrock-runtime',
+ region_name=os.getenv('AWS_REGION'),
+ aws_access_key_id=os.getenv('AWS_ACCESS_KEY_ID'),
+ aws_secret_access_key=os.getenv('AWS_SECRET_ACCESS_KEY')
+ )
+ self.model_id = "anthropic.claude-3-5-sonnet-20241022-v2:0"
+ self.max_tokens = 4000
+ self.temperature = 0.7
+
+ def create_prompt(self, content: str, task: str, is_final: bool = False) -> dict:
+ if is_final:
+ prompt = f"""Please create a cohesive final summary about AWS Bedrock focusing on {task}.
+ Use these previous chunk summaries to create a well-organized, comprehensive analysis:
+
+ {content}
+
+ Provide a detailed yet concise summary that brings together the key points from all chunks into a unified analysis."""
+ else:
+ prompt = f"""Please analyze and summarize this portion of AWS Bedrock documentation. Focus on {task}:
+
+ {content}
+
+ Provide a detailed analysis focusing specifically on the requested aspect. Be thorough but concise, and include specific details about features, capabilities, and requirements where relevant."""
+
+ return {
+ "anthropic_version": "bedrock-2023-05-31",
+ "max_tokens": self.max_tokens,
+ "messages": [
+ {
+ "role": "user",
+ "content": prompt
+ }
+ ],
+ "temperature": self.temperature
+ }
+
+ def invoke_model(self, prompt: dict) -> str:
+ try:
+ response = self.bedrock.invoke_model(
+ modelId=self.model_id,
+ body=json.dumps(prompt)
+ )
+ response_body = json.loads(response.get('body').read())
+ return response_body['content'][0]['text']
+ except Exception as e:
+ print(f"Error invoking model: {str(e)}")
+ return ""
+
+ def process_chunk(self, chunk: str, task: str) -> str:
+ prompt = self.create_prompt(chunk, task)
+ return self.invoke_model(prompt)
+
+ def create_final_summary(self, chunk_summaries: List[str], task: str) -> str:
+ combined_summaries = "\n\n".join(chunk_summaries)
+ prompt = self.create_prompt(combined_summaries, task, is_final=True)
+ return self.invoke_model(prompt)
+
+ def process_content(self, chunks: List[str]) -> Dict[str, str]:
+ # Define analysis tasks
+ tasks = {
+ "overview": "main features and capabilities of Amazon Bedrock",
+ "models": "supported foundation models and their characteristics",
+ "setup": "setup and configuration requirements",
+ "features": "key features like model inference, knowledge bases, and agents",
+ "security": "security considerations and best practices"
+ }
+
+ results = {}
+ for task_name, task_desc in tasks.items():
+ print(f"\nProcessing task: {task_name}")
+ chunk_summaries = []
+
+ # Process each chunk
+ for i, chunk in enumerate(chunks):
+ print(f"Processing chunk {i+1}/{len(chunks)} for {task_name}...")
+ summary = self.process_chunk(chunk, task_desc)
+ if summary:
+ chunk_summaries.append(summary)
+
+ # Create final summary for this task
+ if chunk_summaries:
+ print(f"Creating final summary for {task_name}...")
+ results[task_name] = self.create_final_summary(chunk_summaries, task_desc)
+ else:
+ results[task_name] = f"Error: No valid summaries generated for {task_name}"
+
+ return results
+
+def main():
+ # Check for required environment variables
+ required_env_vars = ['AWS_REGION', 'AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY']
+ missing_vars = [var for var in required_env_vars if not os.getenv(var)]
+ if missing_vars:
+ print("Error: Missing required environment variables:", missing_vars)
+ print("Please set these variables in your .env file")
+ return
+
+ # Initialize summarizer
+ summarizer = BedrockSummarizer()
+
+ # Load chunks from JSON file
+ print("Loading document chunks...")
+ try:
+ with open('chunks.json', 'r', encoding='utf-8') as f:
+ chunks_data = json.load(f)
+ chunks = chunks_data.get('chunks', [])
+ print(f"Loaded {len(chunks)} chunks")
+ except FileNotFoundError:
+ print("Error: chunks.json not found. Please run chunk_document.py first and save the chunks.")
+ return
+ except json.JSONDecodeError:
+ print("Error: Invalid JSON format in chunks.json")
+ return
+
+ # Process chunks
+ results = summarizer.process_content(chunks)
+
+ # Generate final report
+ final_report = """# Amazon Bedrock Documentation Analysis
+Generated using AWS Bedrock Claude 3.5 Sonnet
+
+## 1. Overview and Key Features
+{}
+
+## 2. Foundation Models
+{}
+
+## 3. Setup and Configuration
+{}
+
+## 4. Key Features and Capabilities
+{}
+
+## 5. Security and Best Practices
+{}
+""".format(
+ results['overview'],
+ results['models'],
+ results['setup'],
+ results['features'],
+ results['security']
+ )
+
+ # Write final report
+ with open('TOPIC-FINAL-REPORT.txt', 'w') as f:
+ f.write(final_report)
+ print("\nFinal report has been generated: TOPIC-FINAL-REPORT.txt")
+
+if __name__ == "__main__":
+ main()
diff --git a/tsconfig.json b/tsconfig.json
index c7c0fc0..1704786 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,25 +1,35 @@
{
"compilerOptions": {
- "target": "ES2023",
- "module": "NodeNext",
- "moduleResolution": "NodeNext",
- "esModuleInterop": true,
+ "target": "ES2020",
+ "module": "ES2020",
+ "moduleResolution": "node",
+ "lib": ["ES2020", "DOM"],
+ "outDir": "./dist",
+ "rootDir": "./src",
"strict": true,
- "outDir": "dist",
- "sourceMap": true,
- "declaration": true,
+ "esModuleInterop": true,
"skipLibCheck": true,
- "lib": [
- "ES2023",
- "DOM",
- "DOM.Iterable"
- ]
+ "forceConsistentCasingInFileNames": true,
+ "resolveJsonModule": true,
+ "declaration": true,
+ "sourceMap": true,
+ "allowJs": false,
+ "noImplicitAny": true,
+ "noImplicitThis": true,
+ "strictNullChecks": true,
+ "strictFunctionTypes": true,
+ "strictPropertyInitialization": true,
+ "noImplicitReturns": true,
+ "noFallthroughCasesInSwitch": true,
+ "experimentalDecorators": true,
+ "emitDecoratorMetadata": true
},
"include": [
- "*.ts"
+ "src/**/*"
],
"exclude": [
"node_modules",
- "dist"
+ "dist",
+ "**/*.test.ts"
]
}
\ No newline at end of file