mirror of
https://github.com/sourcebot-dev/sourcebot.git
synced 2025-12-12 04:15:30 +00:00
Sourcebot MCP (#292)
This commit is contained in:
parent
fb141422af
commit
873c9ef2a4
28 changed files with 1458 additions and 91 deletions
|
|
@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- Added special `*` value for `rev:` to allow searching across all branches. [#281](https://github.com/sourcebot-dev/sourcebot/pull/281)
|
- Added special `*` value for `rev:` to allow searching across all branches. [#281](https://github.com/sourcebot-dev/sourcebot/pull/281)
|
||||||
|
- Added the Sourcebot Model Context Protocol (MCP) server in [packages/mcp](./packages/mcp/README.md) to allow LLMs to interface with Sourcebot. Checkout the npm package [here](https://www.npmjs.com/package/@sourcebot/mcp). [#292](https://github.com/sourcebot-dev/sourcebot/pull/292)
|
||||||
|
|
||||||
## [3.1.2] - 2025-04-30
|
## [3.1.2] - 2025-04-30
|
||||||
|
|
||||||
|
|
|
||||||
2
Makefile
2
Makefile
|
|
@ -29,6 +29,8 @@ clean:
|
||||||
packages/crypto/dist \
|
packages/crypto/dist \
|
||||||
packages/error/node_modules \
|
packages/error/node_modules \
|
||||||
packages/error/dist \
|
packages/error/dist \
|
||||||
|
packages/mcp/node_modules \
|
||||||
|
packages/mcp/dist \
|
||||||
.sourcebot
|
.sourcebot
|
||||||
|
|
||||||
soft-reset:
|
soft-reset:
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,9 @@
|
||||||
"pages": [
|
"pages": [
|
||||||
"docs/more/syntax-reference",
|
"docs/more/syntax-reference",
|
||||||
"docs/more/multi-branch-indexing",
|
"docs/more/multi-branch-indexing",
|
||||||
"docs/more/roles-and-permissions"
|
"docs/more/roles-and-permissions",
|
||||||
|
"docs/more/mcp-server",
|
||||||
|
"docs/more/search-contexts"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
@ -71,8 +73,7 @@
|
||||||
"self-hosting/more/authentication",
|
"self-hosting/more/authentication",
|
||||||
"self-hosting/more/tenancy",
|
"self-hosting/more/tenancy",
|
||||||
"self-hosting/more/transactional-emails",
|
"self-hosting/more/transactional-emails",
|
||||||
"self-hosting/more/declarative-config",
|
"self-hosting/more/declarative-config"
|
||||||
"self-hosting/more/search-contexts"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
181
docs/docs/more/mcp-server.mdx
Normal file
181
docs/docs/more/mcp-server.mdx
Normal file
|
|
@ -0,0 +1,181 @@
|
||||||
|
---
|
||||||
|
title: Sourcebot MCP server (@sourcebot/mcp)
|
||||||
|
sidebarTitle: Sourcebot MCP server
|
||||||
|
---
|
||||||
|
|
||||||
|
<Note>
|
||||||
|
This feature is only available when [self-hosting](/self-hosting) with [authentication](/self-hosting/more/authentication) disabled.
|
||||||
|
</Note>
|
||||||
|
|
||||||
|
The [Model Context Protocol](https://modelcontextprotocol.io/introduction) (MCP) is a open standard for providing context to LLMs. The [@sourcebot/mcp](https://www.npmjs.com/package/@sourcebot/mcp) package is a MCP server that enables LLMs to interface with your Sourcebot instance, enabling MCP clients like Cursor, Vscode, and others to have context over your entire codebase.
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
<Steps>
|
||||||
|
<Step title="Launch Sourcebot">
|
||||||
|
Follow the self-hosting [quick start guide](/self-hosting/overview#quick-start-guide) to launch Sourcebot and get your code indexed. The host url of your instance (e.g., `http://localhost:3000`) is passed to the MCP server via the `SOURCEBOT_HOST` url.
|
||||||
|
|
||||||
|
If a host is not provided, then the server will fallback to using the demo instance hosted at https://demo.sourcebot.dev. You can see the list of repositories indexed [here](https://demo.sourcebot.dev/~/repos). Add additional repositories by [opening a PR](https://github.com/sourcebot-dev/sourcebot/blob/main/demo-site-config.json).
|
||||||
|
</Step>
|
||||||
|
|
||||||
|
<Step title="Install the MCP server">
|
||||||
|
<Note>
|
||||||
|
Ensure you have [Node.js](https://nodejs.org/en) >= v18.0.0 installed.
|
||||||
|
</Note>
|
||||||
|
Next, we can install the [@sourcebot/mcp](https://www.npmjs.com/package/@sourcebot/mcp) MCP server into any supported MCP client:
|
||||||
|
|
||||||
|
<AccordionGroup>
|
||||||
|
<Accordion title="Cursor">
|
||||||
|
[Cursor MCP docs](https://docs.cursor.com/context/model-context-protocol)
|
||||||
|
|
||||||
|
Go to: `Settings` -> `Cursor Settings` -> `MCP` -> `Add new global MCP server`
|
||||||
|
|
||||||
|
Paste the following into your `~/.cursor/mcp.json` file. This will install Sourcebot globally within Cursor:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"sourcebot": {
|
||||||
|
"command": "npx",
|
||||||
|
"args": ["-y", "@sourcebot/mcp@latest" ],
|
||||||
|
"env": {
|
||||||
|
"SOURCEBOT_HOST": "http://localhost:3000"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Replace `http://localhost:3000` with wherever your Sourcebot instance is hosted.
|
||||||
|
</Accordion>
|
||||||
|
<Accordion title="Windsurf">
|
||||||
|
[Windsurf MCP docs](https://docs.windsurf.com/windsurf/mcp)
|
||||||
|
|
||||||
|
Go to: `Windsurf Settings` -> `Cascade` -> `Add Server` -> `Add Custom Server`
|
||||||
|
|
||||||
|
Paste the following into your `mcp_config.json` file:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"sourcebot": {
|
||||||
|
"command": "npx",
|
||||||
|
"args": ["-y", "@sourcebot/mcp@latest" ],
|
||||||
|
"env": {
|
||||||
|
"SOURCEBOT_HOST": "http://localhost:3000"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Replace `http://localhost:3000` with wherever your Sourcebot instance is hosted.
|
||||||
|
|
||||||
|
</Accordion>
|
||||||
|
<Accordion title="VS Code">
|
||||||
|
[VS Code MCP docs](https://code.visualstudio.com/docs/copilot/chat/mcp-servers)
|
||||||
|
|
||||||
|
Add the following to your [settings.json](https://code.visualstudio.com/docs/copilot/chat/mcp-servers):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcp": {
|
||||||
|
"servers": {
|
||||||
|
"sourcebot": {
|
||||||
|
"type": "stdio",
|
||||||
|
"command": "npx",
|
||||||
|
"args": ["-y", "@sourcebot/mcp@latest"]
|
||||||
|
},
|
||||||
|
"env": {
|
||||||
|
"SOURCEBOT_HOST": "http://localhost:3000"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Replace `http://localhost:3000` with wherever your Sourcebot instance is hosted.
|
||||||
|
</Accordion>
|
||||||
|
<Accordion title="Claude Code">
|
||||||
|
[Claude Code MCP docs](https://docs.anthropic.com/en/docs/claude-code/tutorials#set-up-model-context-protocol-mcp)
|
||||||
|
|
||||||
|
Run the following command:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
claude mcp add sourcebot -e SOURCEBOT_HOST=http://localhost:3000 -- npx -y @sourcebot/mcp@latest
|
||||||
|
```
|
||||||
|
|
||||||
|
Replace `http://localhost:3000` with wherever your Sourcebot instance is hosted.
|
||||||
|
</Accordion>
|
||||||
|
<Accordion title="Claude Desktop">
|
||||||
|
[Claude Desktop MCP docs](https://modelcontextprotocol.io/quickstart/user)
|
||||||
|
|
||||||
|
Add the following to your `claude_desktop_config.json`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"sourcebot": {
|
||||||
|
"command": "npx",
|
||||||
|
"args": ["-y", "@sourcebot/mcp@latest"],
|
||||||
|
"env": {
|
||||||
|
"SOURCEBOT_HOST": "http://localhost:3000"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Replace `http://localhost:3000` with wherever your Sourcebot instance is hosted.
|
||||||
|
</Accordion>
|
||||||
|
</AccordionGroup>
|
||||||
|
</Step>
|
||||||
|
|
||||||
|
<Step title="Prompt the LLM">
|
||||||
|
Tell your LLM to `use sourcebot` when prompting.
|
||||||
|
</Step>
|
||||||
|
|
||||||
|
</Steps>
|
||||||
|
|
||||||
|
|
||||||
|
## Available Tools
|
||||||
|
|
||||||
|
|
||||||
|
### `search_code`
|
||||||
|
|
||||||
|
Fetches code that matches the provided regex pattern in `query`.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
| Name | Required | Description |
|
||||||
|
|:----------------------|:---------|:----------------------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| `query` | yes | Regex pattern to search for. Escape special characters and spaces with a single backslash (e.g., 'console\.log', 'console\ log'). |
|
||||||
|
| `filterByRepoIds` | no | Restrict search to specific repository IDs (from 'list_repos'). Leave empty to search all. |
|
||||||
|
| `filterByLanguages` | no | Restrict search to specific languages (GitHub linguist format, e.g., Python, JavaScript). |
|
||||||
|
| `caseSensitive` | no | Case sensitive search (default: false). |
|
||||||
|
| `includeCodeSnippets` | no | Include code snippets in results (default: false). |
|
||||||
|
| `maxTokens` | no | Max tokens to return (default: env.DEFAULT_MINIMUM_TOKENS). |
|
||||||
|
|
||||||
|
|
||||||
|
### `list_repos`
|
||||||
|
|
||||||
|
Lists all repositories indexed by Sourcebot.
|
||||||
|
|
||||||
|
### `get_file_source`
|
||||||
|
|
||||||
|
Fetches the source code for a given file.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
| Name | Required | Description |
|
||||||
|
|:-------------|:---------|:-----------------------------------------------------------------|
|
||||||
|
| `fileName` | yes | The file to fetch the source code for. |
|
||||||
|
| `repoId` | yes | The Sourcebot repository ID. |
|
||||||
|
|
||||||
|
|
||||||
|
## Environment Variables
|
||||||
|
|
||||||
|
| Name | Default | Description |
|
||||||
|
|:-------------------------|:-----------------------|:--------------------------------------------------|
|
||||||
|
| `SOURCEBOT_HOST` | http://localhost:3000 | URL of your Sourcebot instance. |
|
||||||
|
| `DEFAULT_MINIMUM_TOKENS` | 10000 | Minimum number of tokens to return in responses. |
|
||||||
|
| `DEFAULT_MATCHES` | 10000 | Number of code matches to fetch per search. |
|
||||||
|
| `DEFAULT_CONTEXT_LINES` | 5 | Lines of context to include above/below matches. |
|
||||||
|
|
@ -6,7 +6,7 @@ sidebarTitle: Search contexts (EE)
|
||||||
import SearchContextSchema from '/snippets/schemas/v3/searchContext.schema.mdx'
|
import SearchContextSchema from '/snippets/schemas/v3/searchContext.schema.mdx'
|
||||||
|
|
||||||
<Note>
|
<Note>
|
||||||
This is only available in the Enterprise Edition. Please add your [license key](/self-hosting/license-key) to activate it.
|
This feature is only available when [self-hosting](/self-hosting) with an active Enterprise license. Please add your [license key](/self-hosting/license-key) to activate it.
|
||||||
</Note>
|
</Note>
|
||||||
|
|
||||||
A **search context** is a user-defined grouping of repositories that helps focus searches on specific areas of your codebase, like frontend, backend, or infrastructure code. Some example queries using search contexts:
|
A **search context** is a user-defined grouping of repositories that helps focus searches on specific areas of your codebase, like frontend, backend, or infrastructure code. Some example queries using search contexts:
|
||||||
|
|
@ -6,11 +6,13 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "cross-env SKIP_ENV_VALIDATION=1 yarn workspaces foreach -A run build",
|
"build": "cross-env SKIP_ENV_VALIDATION=1 yarn workspaces foreach -A run build",
|
||||||
"test": "yarn workspaces foreach -A run test",
|
"test": "yarn workspaces foreach -A run test",
|
||||||
"dev": "yarn dev:prisma:migrate:dev && npm-run-all --print-label --parallel dev:zoekt dev:backend dev:web",
|
"dev": "yarn dev:prisma:migrate:dev && npm-run-all --print-label --parallel dev:zoekt dev:backend dev:web watch:mcp watch:schemas",
|
||||||
"with-env": "cross-env PATH=\"$PWD/bin:$PATH\" dotenv -e .env.development -c --",
|
"with-env": "cross-env PATH=\"$PWD/bin:$PATH\" dotenv -e .env.development -c --",
|
||||||
"dev:zoekt": "yarn with-env zoekt-webserver -index .sourcebot/index -rpc",
|
"dev:zoekt": "yarn with-env zoekt-webserver -index .sourcebot/index -rpc",
|
||||||
"dev:backend": "yarn with-env yarn workspace @sourcebot/backend dev:watch",
|
"dev:backend": "yarn with-env yarn workspace @sourcebot/backend dev:watch",
|
||||||
"dev:web": "yarn with-env yarn workspace @sourcebot/web dev",
|
"dev:web": "yarn with-env yarn workspace @sourcebot/web dev",
|
||||||
|
"watch:mcp": "yarn workspace @sourcebot/mcp build:watch",
|
||||||
|
"watch:schemas": "yarn workspace @sourcebot/schemas watch",
|
||||||
"dev:prisma:migrate:dev": "yarn with-env yarn workspace @sourcebot/db prisma:migrate:dev",
|
"dev:prisma:migrate:dev": "yarn with-env yarn workspace @sourcebot/db prisma:migrate:dev",
|
||||||
"dev:prisma:studio": "yarn with-env yarn workspace @sourcebot/db prisma:studio",
|
"dev:prisma:studio": "yarn with-env yarn workspace @sourcebot/db prisma:studio",
|
||||||
"dev:prisma:migrate:reset": "yarn with-env yarn workspace @sourcebot/db prisma:migrate:reset",
|
"dev:prisma:migrate:reset": "yarn with-env yarn workspace @sourcebot/db prisma:migrate:reset",
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,6 @@
|
||||||
"simple-git": "^3.27.0",
|
"simple-git": "^3.27.0",
|
||||||
"strip-json-comments": "^5.0.1",
|
"strip-json-comments": "^5.0.1",
|
||||||
"winston": "^3.15.0",
|
"winston": "^3.15.0",
|
||||||
"zod": "^3.24.2"
|
"zod": "^3.24.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
packages/mcp/.gitignore
vendored
Normal file
2
packages/mcp/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
dist/
|
||||||
|
node_modules/
|
||||||
5
packages/mcp/.npmignore
Normal file
5
packages/mcp/.npmignore
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
**/*
|
||||||
|
!/dist/**
|
||||||
|
!README.md
|
||||||
|
!package.json
|
||||||
|
!CHANGELOG.md
|
||||||
13
packages/mcp/CHANGELOG.md
Normal file
13
packages/mcp/CHANGELOG.md
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [1.0.0] - 2025-05-07
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Initial release
|
||||||
219
packages/mcp/README.md
Normal file
219
packages/mcp/README.md
Normal file
|
|
@ -0,0 +1,219 @@
|
||||||
|
# Sourcebot MCP - Blazingly fast agentic code search for GitHub, GitLab, BitBucket, and more
|
||||||
|
|
||||||
|
[](https://sourcebot.dev)
|
||||||
|
[](https://github.com/sourcebot-dev/sourcebot)
|
||||||
|
[](https://docs.sourcebot.dev/docs/more/mcp-server)
|
||||||
|
[](https://www.npmjs.com/package/@sourcebot/mcp)
|
||||||
|
|
||||||
|
|
||||||
|
The Sourcebot MCP server enables precise regular expression code search across repos hosted on [GitHub](https://docs.sourcebot.dev/docs/connections/github), [GitLab](https://docs.sourcebot.dev/docs/connections/gitlab), [BitBucket](https://docs.sourcebot.dev/docs/connections/bitbucket-cloud) and [more](#supported-code-hosts). This unlocks the capability for LLM agents to fetch code context for repositories that aren't checked out locally. Some use cases where precise search on a wider code context can help:
|
||||||
|
|
||||||
|
- Enriching responses to user requests:
|
||||||
|
- _"What repositories are using internal library X?"_
|
||||||
|
- _"Provide usage examples of the CodeMirror component"_
|
||||||
|
- _"Where is the `useCodeMirrorTheme` hook defined?"_
|
||||||
|
- _"Find all usages of `deprecatedApi` across all repos"_
|
||||||
|
|
||||||
|
- Improving reasoning ability for existing horizontal agents like AI code review, docs generation, etc.
|
||||||
|
- _"Find the definitions for all functions in this diff"_
|
||||||
|
- _"Document what systems depend on this class"_
|
||||||
|
|
||||||
|
- Building custom LLM horizontal agents like like compliance auditing agents, migration agents, etc.
|
||||||
|
- _"Find all instances of hardcoded credentials"_
|
||||||
|
- _"Identify repositories that depend on this depreacted api"_
|
||||||
|
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
1. Install Node.JS >= v18.0.0.
|
||||||
|
|
||||||
|
2. (optional) Spin up a Sourcebot instance by following [this guide](https://docs.sourcebot.dev/self-hosting/overview). The host url of your instance (e.g., `http://localhost:3000`) is passed to the MCP server via the `SOURCEBOT_HOST` url.
|
||||||
|
|
||||||
|
If a host is not provided, then the server will fallback to using the demo instance hosted at https://demo.sourcebot.dev. You can see the list of repositories indexed [here](https://demo.sourcebot.dev/~/repos). Add additional repositories by [opening a PR](https://github.com/sourcebot-dev/sourcebot/blob/main/demo-site-config.json).
|
||||||
|
|
||||||
|
3. Install `@sourcebot/mcp` into your MCP client:
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Cursor</summary>
|
||||||
|
|
||||||
|
[Cursor MCP docs](https://docs.cursor.com/context/model-context-protocol)
|
||||||
|
|
||||||
|
Go to: `Settings` -> `Cursor Settings` -> `MCP` -> `Add new global MCP server`
|
||||||
|
|
||||||
|
Paste the following into your `~/.cursor/mcp.json` file. This will install Sourcebot globally within Cursor:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"sourcebot": {
|
||||||
|
"command": "npx",
|
||||||
|
"args": ["-y", "@sourcebot/mcp@latest" ],
|
||||||
|
// Optional - if not specified, https://demo.sourcebot.dev is used
|
||||||
|
"env": {
|
||||||
|
"SOURCEBOT_HOST": "http://localhost:3000"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Windsurf</summary>
|
||||||
|
|
||||||
|
[Windsurf MCP docs](https://docs.windsurf.com/windsurf/mcp)
|
||||||
|
|
||||||
|
Go to: `Windsurf Settings` -> `Cascade` -> `Add Server` -> `Add Custom Server`
|
||||||
|
|
||||||
|
Paste the following into your `mcp_config.json` file:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"sourcebot": {
|
||||||
|
"command": "npx",
|
||||||
|
"args": ["-y", "@sourcebot/mcp@latest" ],
|
||||||
|
// Optional - if not specified, https://demo.sourcebot.dev is used
|
||||||
|
"env": {
|
||||||
|
"SOURCEBOT_HOST": "http://localhost:3000"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>VS Code</summary>
|
||||||
|
|
||||||
|
[VS Code MCP docs](https://code.visualstudio.com/docs/copilot/chat/mcp-servers)
|
||||||
|
|
||||||
|
Add the following to your [settings.json](https://code.visualstudio.com/docs/copilot/chat/mcp-servers):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcp": {
|
||||||
|
"servers": {
|
||||||
|
"sourcebot": {
|
||||||
|
"type": "stdio",
|
||||||
|
"command": "npx",
|
||||||
|
"args": ["-y", "@sourcebot/mcp@latest"],
|
||||||
|
// Optional - if not specified, https://demo.sourcebot.dev is used
|
||||||
|
"env": {
|
||||||
|
"SOURCEBOT_HOST": "http://localhost:3000"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Claude Code</summary>
|
||||||
|
|
||||||
|
[Claude Code MCP docs](https://docs.anthropic.com/en/docs/claude-code/tutorials#set-up-model-context-protocol-mcp)
|
||||||
|
|
||||||
|
Run the following command:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# SOURCEBOT_HOST env var is optional - if not specified,
|
||||||
|
# https://demo.sourcebot.dev is used.
|
||||||
|
claude mcp add sourcebot -e SOURCEBOT_HOST=http://localhost:3000 -- npx -y @sourcebot/mcp@latest
|
||||||
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Claude Desktop</summary>
|
||||||
|
|
||||||
|
[Claude Desktop MCP docs](https://modelcontextprotocol.io/quickstart/user)
|
||||||
|
|
||||||
|
Add the following to your `claude_desktop_config.json`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"sourcebot": {
|
||||||
|
"command": "npx",
|
||||||
|
"args": ["-y", "@sourcebot/mcp@latest"],
|
||||||
|
// Optional - if not specified, https://demo.sourcebot.dev is used
|
||||||
|
"env": {
|
||||||
|
"SOURCEBOT_HOST": "http://localhost:3000"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
</details>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
4. Tell your LLM to `use sourcebot` when prompting.
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
For a more detailed guide, checkout [the docs](https://docs.sourcebot.dev/docs/more/mcp-server).
|
||||||
|
|
||||||
|
|
||||||
|
## Available Tools
|
||||||
|
|
||||||
|
### search_code
|
||||||
|
|
||||||
|
Fetches code that matches the provided regex pattern in `query`.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Parameters</summary>
|
||||||
|
|
||||||
|
| Name | Required | Description |
|
||||||
|
|:----------------------|:---------|:----------------------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| `query` | yes | Regex pattern to search for. Escape special characters and spaces with a single backslash (e.g., 'console\.log', 'console\ log'). |
|
||||||
|
| `filterByRepoIds` | no | Restrict search to specific repository IDs (from 'list_repos'). Leave empty to search all. |
|
||||||
|
| `filterByLanguages` | no | Restrict search to specific languages (GitHub linguist format, e.g., Python, JavaScript). |
|
||||||
|
| `caseSensitive` | no | Case sensitive search (default: false). |
|
||||||
|
| `includeCodeSnippets` | no | Include code snippets in results (default: false). |
|
||||||
|
| `maxTokens` | no | Max tokens to return (default: env.DEFAULT_MINIMUM_TOKENS). |
|
||||||
|
</details>
|
||||||
|
|
||||||
|
|
||||||
|
### list_repos
|
||||||
|
|
||||||
|
Lists all repositories indexed by Sourcebot.
|
||||||
|
|
||||||
|
### get_file_source
|
||||||
|
|
||||||
|
Fetches the source code for a given file.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Parameters</summary>
|
||||||
|
|
||||||
|
| Name | Required | Description |
|
||||||
|
|:-------------|:---------|:-----------------------------------------------------------------|
|
||||||
|
| `fileName` | yes | The file to fetch the source code for. |
|
||||||
|
| `repoId` | yes | The Sourcebot repository ID. |
|
||||||
|
</details>
|
||||||
|
|
||||||
|
|
||||||
|
## Supported Code Hosts
|
||||||
|
Sourcebot supports the following code hosts:
|
||||||
|
- [GitHub](https://docs.sourcebot.dev/docs/connections/github)
|
||||||
|
- [GitLab](https://docs.sourcebot.dev/docs/connections/gitlab)
|
||||||
|
- [Bitbucket Cloud](https://docs.sourcebot.dev/docs/connections/bitbucket-cloud)
|
||||||
|
- [Bitbucket Data Center](https://docs.sourcebot.dev/docs/connections/bitbucket-data-center)
|
||||||
|
- [Gitea](https://docs.sourcebot.dev/docs/connections/gitea)
|
||||||
|
- [Gerrit](https://docs.sourcebot.dev/docs/connections/gerrit)
|
||||||
|
|
||||||
|
| Don't see your code host? Open a [GitHub discussion](https://github.com/sourcebot-dev/sourcebot/discussions/categories/ideas).
|
||||||
|
|
||||||
|
## Future Work
|
||||||
|
|
||||||
|
### Semantic Search
|
||||||
|
|
||||||
|
Currently, Sourcebot only supports regex-based code search (powered by [zoekt](https://github.com/sourcegraph/zoekt) under the hood). It is great for scenarios when the agent is searching for is something that is super precise and well-represented in the source code (e.g., a specific function name, a error string, etc.). It is not-so-great for _fuzzy_ searches where the objective is to find some loosely defined _category_ or _concept_ in the code (e.g., find code that verifies JWT tokens). The LLM can approximate this by crafting regex searches that attempt to capture a concept (e.g., it might try a query like `"jwt|token|(verify|validate).*(jwt|token)"`), but often yields sub-optimal search results that aren't related. Tools like Cursor solve this with [embedding models](https://docs.cursor.com/context/codebase-indexing) to capture the semantic meaning of code, allowing for LLMs to search using natural language. We would like to extend Sourcebot to support semantic search and expose this capability over MCP as a tool (e.g., `semantic_search_code` tool). [GitHub Discussion](https://github.com/sourcebot-dev/sourcebot/discussions/297)
|
||||||
|
|
||||||
|
### Code Navigation
|
||||||
|
|
||||||
|
Another idea is to allow LLMs to traverse abstract syntax trees (ASTs) of a codebase to enable reliable code navigation. This could be packaged as tools like `goto_definition`, `find_all_references`, etc., which could be useful for LLMs to get additional code context. [GitHub Discussion](https://github.com/sourcebot-dev/sourcebot/discussions/296)
|
||||||
|
|
||||||
|
### Got an idea?
|
||||||
|
|
||||||
|
Open up a [GitHub discussion](https://github.com/sourcebot-dev/sourcebot/discussions/categories/feature-requests)!
|
||||||
41
packages/mcp/package.json
Normal file
41
packages/mcp/package.json
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
{
|
||||||
|
"name": "@sourcebot/mcp",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"type": "module",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"types": "dist/index.d.ts",
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"dev": "node ./dist/index.js",
|
||||||
|
"build:watch": "tsc-watch --preserveWatchOutput"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/express": "^5.0.1",
|
||||||
|
"@types/node": "^20.0.0",
|
||||||
|
"tsc-watch": "6.2.1",
|
||||||
|
"tsx": "^4.0.0",
|
||||||
|
"typescript": "^5.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@modelcontextprotocol/sdk": "^1.10.2",
|
||||||
|
"@t3-oss/env-core": "^0.13.4",
|
||||||
|
"escape-string-regexp": "^5.0.0",
|
||||||
|
"express": "^5.1.0",
|
||||||
|
"zod": "^3.24.3"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"sourcebot-mcp": "./dist/index.js"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/sourcebot-dev/sourcebot.git",
|
||||||
|
"directory": "packages/mcp"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"mcp",
|
||||||
|
"modelcontextprotocol",
|
||||||
|
"code-search",
|
||||||
|
"sourcebot",
|
||||||
|
"code-intelligence"
|
||||||
|
]
|
||||||
|
}
|
||||||
55
packages/mcp/src/client.ts
Normal file
55
packages/mcp/src/client.ts
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
import { env } from './env.js';
|
||||||
|
import { listRepositoriesResponseSchema, searchResponseSchema, fileSourceResponseSchema } from './schemas.js';
|
||||||
|
import { FileSourceRequest, FileSourceResponse, ListRepositoriesResponse, SearchRequest, SearchResponse, ServiceError } from './types.js';
|
||||||
|
import { isServiceError } from './utils.js';
|
||||||
|
|
||||||
|
export const search = async (request: SearchRequest): Promise<SearchResponse | ServiceError> => {
|
||||||
|
console.error(`Executing search request: ${JSON.stringify(request, null, 2)}`);
|
||||||
|
const result = await fetch(`${env.SOURCEBOT_HOST}/api/search`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Org-Domain': '~'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(request)
|
||||||
|
}).then(response => response.json());
|
||||||
|
|
||||||
|
if (isServiceError(result)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return searchResponseSchema.parse(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const listRepos = async (): Promise<ListRepositoriesResponse | ServiceError> => {
|
||||||
|
const result = await fetch(`${env.SOURCEBOT_HOST}/api/repos`, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Org-Domain': '~'
|
||||||
|
},
|
||||||
|
}).then(response => response.json());
|
||||||
|
|
||||||
|
if (isServiceError(result)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return listRepositoriesResponseSchema.parse(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getFileSource = async (request: FileSourceRequest): Promise<FileSourceResponse | ServiceError> => {
|
||||||
|
const result = await fetch(`${env.SOURCEBOT_HOST}/api/source`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Org-Domain': '~'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(request)
|
||||||
|
}).then(response => response.json());
|
||||||
|
|
||||||
|
if (isServiceError(result)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileSourceResponseSchema.parse(result);
|
||||||
|
}
|
||||||
23
packages/mcp/src/env.ts
Normal file
23
packages/mcp/src/env.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { createEnv } from "@t3-oss/env-core";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export const numberSchema = z.coerce.number();
|
||||||
|
|
||||||
|
const SOURCEBOT_DEMO_HOST = "https://demo.sourcebot.dev";
|
||||||
|
|
||||||
|
export const env = createEnv({
|
||||||
|
server: {
|
||||||
|
SOURCEBOT_HOST: z.string().url().default(SOURCEBOT_DEMO_HOST),
|
||||||
|
|
||||||
|
// The minimum number of tokens to return
|
||||||
|
DEFAULT_MINIMUM_TOKENS: numberSchema.default(10000),
|
||||||
|
|
||||||
|
// The number of matches to fetch from the search API.
|
||||||
|
DEFAULT_MATCHES: numberSchema.default(10000),
|
||||||
|
|
||||||
|
// The number of lines to include above and below a match
|
||||||
|
DEFAULT_CONTEXT_LINES: numberSchema.default(5),
|
||||||
|
},
|
||||||
|
runtimeEnv: process.env,
|
||||||
|
emptyStringAsUndefined: true,
|
||||||
|
});
|
||||||
223
packages/mcp/src/index.ts
Normal file
223
packages/mcp/src/index.ts
Normal file
|
|
@ -0,0 +1,223 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
// Entry point for the MCP server
|
||||||
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
||||||
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
||||||
|
import escapeStringRegexp from 'escape-string-regexp';
|
||||||
|
import { z } from 'zod';
|
||||||
|
import { listRepos, search, getFileSource } from './client.js';
|
||||||
|
import { env, numberSchema } from './env.js';
|
||||||
|
import { TextContent } from './types.js';
|
||||||
|
import { base64Decode, isServiceError } from './utils.js';
|
||||||
|
|
||||||
|
// Create MCP server
|
||||||
|
const server = new McpServer({
|
||||||
|
name: 'sourcebot-mcp-server',
|
||||||
|
version: '0.1.0',
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
server.tool(
|
||||||
|
"search_code",
|
||||||
|
`Fetches code that matches the provided regex pattern in \`query\`. This is NOT a semantic search.
|
||||||
|
Results are returned as an array of matching files, with the file's URL, repository, and language.
|
||||||
|
If the \`includeCodeSnippets\` property is true, code snippets containing the matches will be included in the response. Only set this to true if the request requires code snippets (e.g., show me examples where library X is used).
|
||||||
|
When referencing a file in your response, **ALWAYS** include the file's external URL as a link. This makes it easier for the user to view the file, even if they don't have it locally checked out.
|
||||||
|
**ONLY USE** the \`filterByRepoIds\` property if the request requires searching a specific repo(s). Otherwise, leave it empty.`,
|
||||||
|
{
|
||||||
|
query: z
|
||||||
|
.string()
|
||||||
|
.describe(`The regex pattern to search for. RULES:
|
||||||
|
1. When a regex special character needs to be escaped, ALWAYS use a single backslash (\) (e.g., 'console\.log')
|
||||||
|
2. **ALWAYS** escape spaces with a single backslash (\) (e.g., 'console\ log')
|
||||||
|
`),
|
||||||
|
filterByRepoIds: z
|
||||||
|
.array(z.string())
|
||||||
|
.describe(`Scope the search to the provided repositories to the Sourcebot compatible repository IDs. **DO NOT** use this property if you want to search all repositories. **YOU MUST** call 'list_repos' first to obtain the exact repository ID.`)
|
||||||
|
.optional(),
|
||||||
|
filterByLanguages: z
|
||||||
|
.array(z.string())
|
||||||
|
.describe(`Scope the search to the provided languages. The language MUST be formatted as a GitHub linguist language. Examples: Python, JavaScript, TypeScript, Java, C#, C++, PHP, Go, Rust, Ruby, Swift, Kotlin, Shell, C, Dart, HTML, CSS, PowerShell, SQL, R`)
|
||||||
|
.optional(),
|
||||||
|
caseSensitive: z
|
||||||
|
.boolean()
|
||||||
|
.describe(`Whether the search should be case sensitive (default: false).`)
|
||||||
|
.optional(),
|
||||||
|
includeCodeSnippets: z
|
||||||
|
.boolean()
|
||||||
|
.describe(`Whether to include the code snippets in the response (default: false). If false, only the file's URL, repository, and language will be returned. Set to false to get a more concise response.`)
|
||||||
|
.optional(),
|
||||||
|
maxTokens: numberSchema
|
||||||
|
.describe(`The maximum number of tokens to return (default: ${env.DEFAULT_MINIMUM_TOKENS}). Higher values provide more context but consume more tokens. Values less than ${env.DEFAULT_MINIMUM_TOKENS} will be ignored.`)
|
||||||
|
.transform((val) => (val < env.DEFAULT_MINIMUM_TOKENS ? env.DEFAULT_MINIMUM_TOKENS : val))
|
||||||
|
.optional(),
|
||||||
|
},
|
||||||
|
async ({
|
||||||
|
query,
|
||||||
|
filterByRepoIds: repoIds = [],
|
||||||
|
filterByLanguages: languages = [],
|
||||||
|
maxTokens = env.DEFAULT_MINIMUM_TOKENS,
|
||||||
|
includeCodeSnippets = false,
|
||||||
|
caseSensitive = false,
|
||||||
|
}) => {
|
||||||
|
if (repoIds.length > 0) {
|
||||||
|
query += ` ( repo:${repoIds.map(id => escapeStringRegexp(id)).join(' or repo:')} )`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (languages.length > 0) {
|
||||||
|
query += ` ( lang:${languages.join(' or lang:')} )`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (caseSensitive) {
|
||||||
|
query += ` case:yes`;
|
||||||
|
} else {
|
||||||
|
query += ` case:no`;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.error(`Executing search request: ${query}`);
|
||||||
|
|
||||||
|
const response = await search({
|
||||||
|
query,
|
||||||
|
matches: env.DEFAULT_MATCHES,
|
||||||
|
contextLines: env.DEFAULT_CONTEXT_LINES,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isServiceError(response)) {
|
||||||
|
return {
|
||||||
|
content: [{
|
||||||
|
type: "text",
|
||||||
|
text: `Error searching code: ${response.message}`,
|
||||||
|
}],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.files.length === 0) {
|
||||||
|
return {
|
||||||
|
content: [{
|
||||||
|
type: "text",
|
||||||
|
text: `No results found for the query: ${query}`,
|
||||||
|
}],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const content: TextContent[] = [];
|
||||||
|
let totalTokens = 0;
|
||||||
|
let isResponseTruncated = false;
|
||||||
|
|
||||||
|
for (const file of response.files) {
|
||||||
|
const numMatches = file.chunks.reduce(
|
||||||
|
(acc, chunk) => acc + chunk.matchRanges.length,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
let text = `file: ${file.url}\nnum_matches: ${numMatches}\nrepository: ${file.repository}\nlanguage: ${file.language}`;
|
||||||
|
|
||||||
|
if (includeCodeSnippets) {
|
||||||
|
const snippets = file.chunks.map(chunk => {
|
||||||
|
const content = base64Decode(chunk.content);
|
||||||
|
return `\`\`\`\n${content}\n\`\`\``
|
||||||
|
}).join('\n');
|
||||||
|
text += `\n\n${snippets}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Rough estimate of the number of tokens in the text
|
||||||
|
// @see: https://help.openai.com/en/articles/4936856-what-are-tokens-and-how-to-count-them
|
||||||
|
const tokens = text.length / 4;
|
||||||
|
|
||||||
|
if ((totalTokens + tokens) > maxTokens) {
|
||||||
|
isResponseTruncated = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
totalTokens += tokens;
|
||||||
|
content.push({
|
||||||
|
type: "text",
|
||||||
|
text,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isResponseTruncated) {
|
||||||
|
content.push({
|
||||||
|
type: "text",
|
||||||
|
text: `The response was truncated because the number of tokens exceeded the maximum limit of ${maxTokens}.`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
content,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
server.tool(
|
||||||
|
"list_repos",
|
||||||
|
"Lists all repositories in the organization.",
|
||||||
|
async () => {
|
||||||
|
const response = await listRepos();
|
||||||
|
if (isServiceError(response)) {
|
||||||
|
return {
|
||||||
|
content: [{
|
||||||
|
type: "text",
|
||||||
|
text: `Error listing repositories: ${response.message}`,
|
||||||
|
}],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const content: TextContent[] = response.repos.map(repo => {
|
||||||
|
return {
|
||||||
|
type: "text",
|
||||||
|
text: `id: ${repo.name}\nurl: ${repo.url}`,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
content,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
server.tool(
|
||||||
|
"get_file_source",
|
||||||
|
"Fetches the source code for a given file.",
|
||||||
|
{
|
||||||
|
fileName: z.string().describe("The file to fetch the source code for."),
|
||||||
|
repoId: z.string().describe("The repository to fetch the source code for. This is the Sourcebot compatible repository ID."),
|
||||||
|
},
|
||||||
|
async ({ fileName, repoId }) => {
|
||||||
|
const response = await getFileSource({
|
||||||
|
fileName,
|
||||||
|
repository: repoId,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isServiceError(response)) {
|
||||||
|
return {
|
||||||
|
content: [{
|
||||||
|
type: "text",
|
||||||
|
text: `Error fetching file source: ${response.message}`,
|
||||||
|
}],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const content: TextContent[] = [{
|
||||||
|
type: "text",
|
||||||
|
text: `file: ${fileName}\nrepository: ${repoId}\nlanguage: ${response.language}\nsource:\n${base64Decode(response.source)}`,
|
||||||
|
}]
|
||||||
|
|
||||||
|
return {
|
||||||
|
content,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const runServer = async () => {
|
||||||
|
const transport = new StdioServerTransport();
|
||||||
|
await server.connect(transport);
|
||||||
|
console.error('Sourcebot MCP server ready');
|
||||||
|
}
|
||||||
|
|
||||||
|
runServer().catch((error) => {
|
||||||
|
console.error('Failed to start MCP server:', error);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
111
packages/mcp/src/schemas.ts
Normal file
111
packages/mcp/src/schemas.ts
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
// @NOTE : Please keep this file in sync with @sourcebot/web/src/features/search/schemas.ts
|
||||||
|
// At some point, we should move these to a shared package...
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export const locationSchema = z.object({
|
||||||
|
// 0-based byte offset from the beginning of the file
|
||||||
|
byteOffset: z.number(),
|
||||||
|
// 1-based line number from the beginning of the file
|
||||||
|
lineNumber: z.number(),
|
||||||
|
// 1-based column number (in runes) from the beginning of line
|
||||||
|
column: z.number(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const rangeSchema = z.object({
|
||||||
|
start: locationSchema,
|
||||||
|
end: locationSchema,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const symbolSchema = z.object({
|
||||||
|
symbol: z.string(),
|
||||||
|
kind: z.string(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const searchRequestSchema = z.object({
|
||||||
|
// The zoekt query to execute.
|
||||||
|
query: z.string(),
|
||||||
|
// The number of matches to return.
|
||||||
|
matches: z.number(),
|
||||||
|
// The number of context lines to return.
|
||||||
|
contextLines: z.number().optional(),
|
||||||
|
// Whether to return the whole file as part of the response.
|
||||||
|
whole: z.boolean().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const searchResponseSchema = z.object({
|
||||||
|
zoektStats: z.object({
|
||||||
|
// The duration (in nanoseconds) of the search.
|
||||||
|
duration: z.number(),
|
||||||
|
fileCount: z.number(),
|
||||||
|
matchCount: z.number(),
|
||||||
|
filesSkipped: z.number(),
|
||||||
|
contentBytesLoaded: z.number(),
|
||||||
|
indexBytesLoaded: z.number(),
|
||||||
|
crashes: z.number(),
|
||||||
|
shardFilesConsidered: z.number(),
|
||||||
|
filesConsidered: z.number(),
|
||||||
|
filesLoaded: z.number(),
|
||||||
|
shardsScanned: z.number(),
|
||||||
|
shardsSkipped: z.number(),
|
||||||
|
shardsSkippedFilter: z.number(),
|
||||||
|
ngramMatches: z.number(),
|
||||||
|
ngramLookups: z.number(),
|
||||||
|
wait: z.number(),
|
||||||
|
matchTreeConstruction: z.number(),
|
||||||
|
matchTreeSearch: z.number(),
|
||||||
|
regexpsConsidered: z.number(),
|
||||||
|
flushReason: z.number(),
|
||||||
|
}),
|
||||||
|
files: z.array(z.object({
|
||||||
|
fileName: z.object({
|
||||||
|
// The name of the file
|
||||||
|
text: z.string(),
|
||||||
|
// Any matching ranges
|
||||||
|
matchRanges: z.array(rangeSchema),
|
||||||
|
}),
|
||||||
|
repository: z.string(),
|
||||||
|
language: z.string(),
|
||||||
|
url: z.string(),
|
||||||
|
chunks: z.array(z.object({
|
||||||
|
content: z.string(),
|
||||||
|
matchRanges: z.array(rangeSchema),
|
||||||
|
contentStart: locationSchema,
|
||||||
|
symbols: z.array(z.object({
|
||||||
|
...symbolSchema.shape,
|
||||||
|
parent: symbolSchema.optional(),
|
||||||
|
})).optional(),
|
||||||
|
})),
|
||||||
|
branches: z.array(z.string()).optional(),
|
||||||
|
// Set if `whole` is true.
|
||||||
|
content: z.string().optional(),
|
||||||
|
})),
|
||||||
|
isBranchFilteringEnabled: z.boolean(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const repositorySchema = z.object({
|
||||||
|
name: z.string(),
|
||||||
|
url: z.string(),
|
||||||
|
branches: z.array(z.string()),
|
||||||
|
rawConfig: z.record(z.string(), z.string()).optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const listRepositoriesResponseSchema = z.object({
|
||||||
|
repos: z.array(repositorySchema),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const fileSourceRequestSchema = z.object({
|
||||||
|
fileName: z.string(),
|
||||||
|
repository: z.string(),
|
||||||
|
branch: z.string().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const fileSourceResponseSchema = z.object({
|
||||||
|
source: z.string(),
|
||||||
|
language: z.string(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const serviceErrorSchema = z.object({
|
||||||
|
statusCode: z.number(),
|
||||||
|
errorCode: z.string(),
|
||||||
|
message: z.string(),
|
||||||
|
});
|
||||||
32
packages/mcp/src/types.ts
Normal file
32
packages/mcp/src/types.ts
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
// @NOTE : Please keep this file in sync with @sourcebot/web/src/features/search/types.ts
|
||||||
|
// At some point, we should move these to a shared package...
|
||||||
|
import {
|
||||||
|
fileSourceResponseSchema,
|
||||||
|
listRepositoriesResponseSchema,
|
||||||
|
locationSchema,
|
||||||
|
searchRequestSchema,
|
||||||
|
searchResponseSchema,
|
||||||
|
rangeSchema,
|
||||||
|
fileSourceRequestSchema,
|
||||||
|
symbolSchema,
|
||||||
|
serviceErrorSchema,
|
||||||
|
} from "./schemas.js";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export type SearchRequest = z.infer<typeof searchRequestSchema>;
|
||||||
|
export type SearchResponse = z.infer<typeof searchResponseSchema>;
|
||||||
|
export type SearchResultRange = z.infer<typeof rangeSchema>;
|
||||||
|
export type SearchResultLocation = z.infer<typeof locationSchema>;
|
||||||
|
export type SearchResultFile = SearchResponse["files"][number];
|
||||||
|
export type SearchResultChunk = SearchResultFile["chunks"][number];
|
||||||
|
export type SearchSymbol = z.infer<typeof symbolSchema>;
|
||||||
|
|
||||||
|
export type ListRepositoriesResponse = z.infer<typeof listRepositoriesResponseSchema>;
|
||||||
|
export type Repository = ListRepositoriesResponse["repos"][number];
|
||||||
|
|
||||||
|
export type FileSourceRequest = z.infer<typeof fileSourceRequestSchema>;
|
||||||
|
export type FileSourceResponse = z.infer<typeof fileSourceResponseSchema>;
|
||||||
|
|
||||||
|
export type TextContent = { type: "text", text: string };
|
||||||
|
|
||||||
|
export type ServiceError = z.infer<typeof serviceErrorSchema>;
|
||||||
15
packages/mcp/src/utils.ts
Normal file
15
packages/mcp/src/utils.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { ServiceError } from "./types.js";
|
||||||
|
|
||||||
|
// From https://developer.mozilla.org/en-US/docs/Glossary/Base64#the_unicode_problem
|
||||||
|
export const base64Decode = (base64: string): string => {
|
||||||
|
const binString = atob(base64);
|
||||||
|
return Buffer.from(Uint8Array.from(binString, (m) => m.codePointAt(0)!).buffer).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
export const isServiceError = (data: unknown): data is ServiceError => {
|
||||||
|
return typeof data === 'object' &&
|
||||||
|
data !== null &&
|
||||||
|
'statusCode' in data &&
|
||||||
|
'errorCode' in data &&
|
||||||
|
'message' in data;
|
||||||
|
}
|
||||||
28
packages/mcp/tsconfig.json
Normal file
28
packages/mcp/tsconfig.json
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "dist",
|
||||||
|
"incremental": true,
|
||||||
|
"declaration": true,
|
||||||
|
"emitDecoratorMetadata": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"module": "Node16",
|
||||||
|
"moduleResolution": "Node16",
|
||||||
|
"target": "ES2022",
|
||||||
|
"noEmitOnError": false,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"noUnusedLocals": false,
|
||||||
|
"pretty": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"lib": [
|
||||||
|
"ES2023"
|
||||||
|
],
|
||||||
|
"strict": true,
|
||||||
|
"sourceMap": true,
|
||||||
|
"inlineSources": true,
|
||||||
|
},
|
||||||
|
"include": ["src/index.ts"]
|
||||||
|
}
|
||||||
|
|
@ -5,12 +5,14 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "yarn generate && tsc",
|
"build": "yarn generate && tsc",
|
||||||
"generate": "tsx tools/generate.ts",
|
"generate": "tsx tools/generate.ts",
|
||||||
|
"watch": "nodemon --watch ../../schemas -e json -x 'yarn generate'",
|
||||||
"postinstall": "yarn build"
|
"postinstall": "yarn build"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@apidevtools/json-schema-ref-parser": "^11.7.3",
|
"@apidevtools/json-schema-ref-parser": "^11.7.3",
|
||||||
"glob": "^11.0.1",
|
"glob": "^11.0.1",
|
||||||
"json-schema-to-typescript": "^15.0.4",
|
"json-schema-to-typescript": "^15.0.4",
|
||||||
|
"nodemon": "^3.1.10",
|
||||||
"tsx": "^4.19.2",
|
"tsx": "^4.19.2",
|
||||||
"typescript": "^5.7.3"
|
"typescript": "^5.7.3"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,7 @@
|
||||||
"tailwind-merge": "^2.5.2",
|
"tailwind-merge": "^2.5.2",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
"usehooks-ts": "^3.1.0",
|
"usehooks-ts": "^3.1.0",
|
||||||
"zod": "^3.24.2"
|
"zod": "^3.24.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/micromatch": "^4.0.9",
|
"@types/micromatch": "^4.0.9",
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ interface CodePreviewPanelProps {
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
selectedMatchIndex: number;
|
selectedMatchIndex: number;
|
||||||
onSelectedMatchIndexChange: (index: number) => void;
|
onSelectedMatchIndexChange: (index: number) => void;
|
||||||
repoUrlTemplates: Record<string, string>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CodePreviewPanel = ({
|
export const CodePreviewPanel = ({
|
||||||
|
|
@ -21,7 +20,6 @@ export const CodePreviewPanel = ({
|
||||||
onClose,
|
onClose,
|
||||||
selectedMatchIndex,
|
selectedMatchIndex,
|
||||||
onSelectedMatchIndexChange,
|
onSelectedMatchIndexChange,
|
||||||
repoUrlTemplates,
|
|
||||||
}: CodePreviewPanelProps) => {
|
}: CodePreviewPanelProps) => {
|
||||||
const domain = useDomain();
|
const domain = useDomain();
|
||||||
|
|
||||||
|
|
@ -42,45 +40,13 @@ export const CodePreviewPanel = ({
|
||||||
branch,
|
branch,
|
||||||
}, domain)
|
}, domain)
|
||||||
.then(({ source }) => {
|
.then(({ source }) => {
|
||||||
const link = (() => {
|
|
||||||
const template = repoUrlTemplates[fileMatch.repository];
|
|
||||||
|
|
||||||
// This is a hacky parser for templates generated by
|
|
||||||
// the go text/template package. Example template:
|
|
||||||
// {{URLJoinPath "https://github.com/sourcebot-dev/sourcebot" "blob" .Version .Path}}
|
|
||||||
// @see: https://pkg.go.dev/text/template
|
|
||||||
if (!template || !template.match(/^{{URLJoinPath\s.*}}(\?.+)?$/)) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const url =
|
|
||||||
template.substring("{{URLJoinPath ".length,template.indexOf("}}"))
|
|
||||||
.replace(".Version", branch ?? "HEAD")
|
|
||||||
.replace(".Path", fileMatch.fileName.text)
|
|
||||||
.split(" ")
|
|
||||||
.map((part) => {
|
|
||||||
// remove wrapping quotes
|
|
||||||
if (part.startsWith("\"")) part = part.substring(1);
|
|
||||||
if (part.endsWith("\"")) part = part.substring(0, part.length - 1);
|
|
||||||
return part;
|
|
||||||
})
|
|
||||||
.join("/");
|
|
||||||
|
|
||||||
const optionalQueryParams =
|
|
||||||
template.substring(template.indexOf("}}") + 2)
|
|
||||||
.replace("{{.Version}}", branch ?? "HEAD")
|
|
||||||
.replace("{{.Path}}", fileMatch.fileName.text);
|
|
||||||
|
|
||||||
return url + optionalQueryParams;
|
|
||||||
})();
|
|
||||||
|
|
||||||
const decodedSource = base64Decode(source);
|
const decodedSource = base64Decode(source);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content: decodedSource,
|
content: decodedSource,
|
||||||
filepath: fileMatch.fileName.text,
|
filepath: fileMatch.fileName.text,
|
||||||
matches: fileMatch.chunks,
|
matches: fileMatch.chunks,
|
||||||
link: link,
|
link: fileMatch.url,
|
||||||
language: fileMatch.language,
|
language: fileMatch.language,
|
||||||
revision: branch ?? "HEAD",
|
revision: branch ?? "HEAD",
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -141,14 +141,13 @@ const SearchPageInternal = () => {
|
||||||
});
|
});
|
||||||
}, [captureEvent, searchQuery, searchResponse]);
|
}, [captureEvent, searchQuery, searchResponse]);
|
||||||
|
|
||||||
const { fileMatches, searchDurationMs, totalMatchCount, isBranchFilteringEnabled, repoUrlTemplates } = useMemo(() => {
|
const { fileMatches, searchDurationMs, totalMatchCount, isBranchFilteringEnabled } = useMemo(() => {
|
||||||
if (!searchResponse) {
|
if (!searchResponse) {
|
||||||
return {
|
return {
|
||||||
fileMatches: [],
|
fileMatches: [],
|
||||||
searchDurationMs: 0,
|
searchDurationMs: 0,
|
||||||
totalMatchCount: 0,
|
totalMatchCount: 0,
|
||||||
isBranchFilteringEnabled: false,
|
isBranchFilteringEnabled: false,
|
||||||
repoUrlTemplates: {},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -157,7 +156,6 @@ const SearchPageInternal = () => {
|
||||||
searchDurationMs: Math.round(searchResponse.durationMs),
|
searchDurationMs: Math.round(searchResponse.durationMs),
|
||||||
totalMatchCount: searchResponse.zoektStats.matchCount,
|
totalMatchCount: searchResponse.zoektStats.matchCount,
|
||||||
isBranchFilteringEnabled: searchResponse.isBranchFilteringEnabled,
|
isBranchFilteringEnabled: searchResponse.isBranchFilteringEnabled,
|
||||||
repoUrlTemplates: searchResponse.repoUrlTemplates,
|
|
||||||
}
|
}
|
||||||
}, [searchResponse]);
|
}, [searchResponse]);
|
||||||
|
|
||||||
|
|
@ -207,7 +205,6 @@ const SearchPageInternal = () => {
|
||||||
isMoreResultsButtonVisible={isMoreResultsButtonVisible}
|
isMoreResultsButtonVisible={isMoreResultsButtonVisible}
|
||||||
onLoadMoreResults={onLoadMoreResults}
|
onLoadMoreResults={onLoadMoreResults}
|
||||||
isBranchFilteringEnabled={isBranchFilteringEnabled}
|
isBranchFilteringEnabled={isBranchFilteringEnabled}
|
||||||
repoUrlTemplates={repoUrlTemplates}
|
|
||||||
repoMetadata={repoMetadata ?? {}}
|
repoMetadata={repoMetadata ?? {}}
|
||||||
searchDurationMs={searchDurationMs}
|
searchDurationMs={searchDurationMs}
|
||||||
numMatches={numMatches}
|
numMatches={numMatches}
|
||||||
|
|
@ -222,7 +219,6 @@ interface PanelGroupProps {
|
||||||
isMoreResultsButtonVisible?: boolean;
|
isMoreResultsButtonVisible?: boolean;
|
||||||
onLoadMoreResults: () => void;
|
onLoadMoreResults: () => void;
|
||||||
isBranchFilteringEnabled: boolean;
|
isBranchFilteringEnabled: boolean;
|
||||||
repoUrlTemplates: Record<string, string>;
|
|
||||||
repoMetadata: Record<string, Repository>;
|
repoMetadata: Record<string, Repository>;
|
||||||
searchDurationMs: number;
|
searchDurationMs: number;
|
||||||
numMatches: number;
|
numMatches: number;
|
||||||
|
|
@ -233,7 +229,6 @@ const PanelGroup = ({
|
||||||
isMoreResultsButtonVisible,
|
isMoreResultsButtonVisible,
|
||||||
onLoadMoreResults,
|
onLoadMoreResults,
|
||||||
isBranchFilteringEnabled,
|
isBranchFilteringEnabled,
|
||||||
repoUrlTemplates,
|
|
||||||
repoMetadata,
|
repoMetadata,
|
||||||
searchDurationMs,
|
searchDurationMs,
|
||||||
numMatches,
|
numMatches,
|
||||||
|
|
@ -340,7 +335,6 @@ const PanelGroup = ({
|
||||||
onClose={() => setSelectedFile(undefined)}
|
onClose={() => setSelectedFile(undefined)}
|
||||||
selectedMatchIndex={selectedMatchIndex}
|
selectedMatchIndex={selectedMatchIndex}
|
||||||
onSelectedMatchIndexChange={setSelectedMatchIndex}
|
onSelectedMatchIndexChange={setSelectedMatchIndex}
|
||||||
repoUrlTemplates={repoUrlTemplates}
|
|
||||||
/>
|
/>
|
||||||
</ResizablePanel>
|
</ResizablePanel>
|
||||||
</ResizablePanelGroup>
|
</ResizablePanelGroup>
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,6 @@ export const listRepositories = async (orgId: number): Promise<ListRepositoriesR
|
||||||
repos: List.Repos.map((repo) => ({
|
repos: List.Repos.map((repo) => ({
|
||||||
name: repo.Repository.Name,
|
name: repo.Repository.Name,
|
||||||
url: repo.Repository.URL,
|
url: repo.Repository.URL,
|
||||||
source: repo.Repository.Source,
|
|
||||||
branches: repo.Repository.Branches?.map((branch) => branch.Name) ?? [],
|
branches: repo.Repository.Branches?.map((branch) => branch.Name) ?? [],
|
||||||
rawConfig: repo.Repository.RawConfig ?? undefined,
|
rawConfig: repo.Repository.RawConfig ?? undefined,
|
||||||
}))
|
}))
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
// @NOTE : Please keep this file in sync with @sourcebot/mcp/src/schemas.ts
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const locationSchema = z.object({
|
export const locationSchema = z.object({
|
||||||
|
|
@ -61,6 +62,7 @@ export const searchResponseSchema = z.object({
|
||||||
// Any matching ranges
|
// Any matching ranges
|
||||||
matchRanges: z.array(rangeSchema),
|
matchRanges: z.array(rangeSchema),
|
||||||
}),
|
}),
|
||||||
|
url: z.string(),
|
||||||
repository: z.string(),
|
repository: z.string(),
|
||||||
language: z.string(),
|
language: z.string(),
|
||||||
chunks: z.array(z.object({
|
chunks: z.array(z.object({
|
||||||
|
|
@ -76,14 +78,12 @@ export const searchResponseSchema = z.object({
|
||||||
// Set if `whole` is true.
|
// Set if `whole` is true.
|
||||||
content: z.string().optional(),
|
content: z.string().optional(),
|
||||||
})),
|
})),
|
||||||
repoUrlTemplates: z.record(z.string(), z.string()),
|
|
||||||
isBranchFilteringEnabled: z.boolean(),
|
isBranchFilteringEnabled: z.boolean(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const repositorySchema = z.object({
|
export const repositorySchema = z.object({
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
url: z.string(),
|
url: z.string(),
|
||||||
source: z.string(),
|
|
||||||
branches: z.array(z.string()),
|
branches: z.array(z.string()),
|
||||||
rawConfig: z.record(z.string(), z.string()).optional(),
|
rawConfig: z.record(z.string(), z.string()).optional(),
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import { ErrorCode } from "../../lib/errorCodes";
|
||||||
import { StatusCodes } from "http-status-codes";
|
import { StatusCodes } from "http-status-codes";
|
||||||
import { zoektSearchResponseSchema } from "./zoektSchema";
|
import { zoektSearchResponseSchema } from "./zoektSchema";
|
||||||
import { SearchRequest, SearchResponse, SearchResultRange } from "./types";
|
import { SearchRequest, SearchResponse, SearchResultRange } from "./types";
|
||||||
|
import assert from "assert";
|
||||||
|
|
||||||
// List of supported query prefixes in zoekt.
|
// List of supported query prefixes in zoekt.
|
||||||
// @see : https://github.com/sourcebot-dev/zoekt/blob/main/query/parse.go#L417
|
// @see : https://github.com/sourcebot-dev/zoekt/blob/main/query/parse.go#L417
|
||||||
|
|
@ -90,6 +91,36 @@ const transformZoektQuery = async (query: string, orgId: number): Promise<string
|
||||||
return newQueryParts.join(" ");
|
return newQueryParts.join(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extracts a repository file URL from a zoekt template, branch, and file name.
|
||||||
|
function getRepositoryUrl(template: string, branch: string, fileName: string): string {
|
||||||
|
// This is a hacky parser for templates generated by
|
||||||
|
// the go text/template package. Example template:
|
||||||
|
// {{URLJoinPath "https://github.com/sourcebot-dev/sourcebot" "blob" .Version .Path}}
|
||||||
|
|
||||||
|
// The template should always match this regex, so let's assert that.
|
||||||
|
assert(template.match(/^{{URLJoinPath\s.*}}(\?.+)?$/), "Invalid template");
|
||||||
|
|
||||||
|
const url =
|
||||||
|
template.substring("{{URLJoinPath ".length, template.indexOf("}}"))
|
||||||
|
.replace(".Version", branch)
|
||||||
|
.replace(".Path", fileName)
|
||||||
|
.split(" ")
|
||||||
|
.map((part) => {
|
||||||
|
// remove wrapping quotes
|
||||||
|
if (part.startsWith("\"")) part = part.substring(1);
|
||||||
|
if (part.endsWith("\"")) part = part.substring(0, part.length - 1);
|
||||||
|
return part;
|
||||||
|
})
|
||||||
|
.join("/");
|
||||||
|
|
||||||
|
const optionalQueryParams =
|
||||||
|
template.substring(template.indexOf("}}") + 2)
|
||||||
|
.replace("{{.Version}}", branch)
|
||||||
|
.replace("{{.Path}}", fileName);
|
||||||
|
|
||||||
|
return encodeURI(url + optionalQueryParams);
|
||||||
|
}
|
||||||
|
|
||||||
export const search = async ({ query, matches, contextLines, whole }: SearchRequest, orgId: number) => {
|
export const search = async ({ query, matches, contextLines, whole }: SearchRequest, orgId: number) => {
|
||||||
const transformedQuery = await transformZoektQuery(query, orgId);
|
const transformedQuery = await transformZoektQuery(query, orgId);
|
||||||
if (isServiceError(transformedQuery)) {
|
if (isServiceError(transformedQuery)) {
|
||||||
|
|
@ -165,6 +196,15 @@ export const search = async ({ query, matches, contextLines, whole }: SearchRequ
|
||||||
},
|
},
|
||||||
files: Result.Files?.map((file) => {
|
files: Result.Files?.map((file) => {
|
||||||
const fileNameChunks = file.ChunkMatches.filter((chunk) => chunk.FileName);
|
const fileNameChunks = file.ChunkMatches.filter((chunk) => chunk.FileName);
|
||||||
|
|
||||||
|
const template = Result.RepoURLs[file.Repository];
|
||||||
|
assert(template, `Template not found for repository ${file.Repository}`);
|
||||||
|
|
||||||
|
// If there are multiple branches pointing to the same revision of this file, it doesn't
|
||||||
|
// matter which branch we use here, so use the first one.
|
||||||
|
const branch = file.Branches && file.Branches.length > 0 ? file.Branches[0] : "HEAD";
|
||||||
|
const url = getRepositoryUrl(template, branch, file.FileName);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
fileName: {
|
fileName: {
|
||||||
text: file.FileName,
|
text: file.FileName,
|
||||||
|
|
@ -182,6 +222,7 @@ export const search = async ({ query, matches, contextLines, whole }: SearchRequ
|
||||||
})) : [],
|
})) : [],
|
||||||
},
|
},
|
||||||
repository: file.Repository,
|
repository: file.Repository,
|
||||||
|
url: url,
|
||||||
language: file.Language,
|
language: file.Language,
|
||||||
chunks: file.ChunkMatches
|
chunks: file.ChunkMatches
|
||||||
.filter((chunk) => !chunk.FileName) // Filter out filename chunks.
|
.filter((chunk) => !chunk.FileName) // Filter out filename chunks.
|
||||||
|
|
@ -220,9 +261,7 @@ export const search = async ({ query, matches, contextLines, whole }: SearchRequ
|
||||||
branches: file.Branches,
|
branches: file.Branches,
|
||||||
content: file.Content,
|
content: file.Content,
|
||||||
}
|
}
|
||||||
}
|
}) ?? [],
|
||||||
) ?? [],
|
|
||||||
repoUrlTemplates: Result.RepoURLs,
|
|
||||||
isBranchFilteringEnabled: isBranchFilteringEnabled,
|
isBranchFilteringEnabled: isBranchFilteringEnabled,
|
||||||
} satisfies SearchResponse));
|
} satisfies SearchResponse));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
// @NOTE : Please keep this file in sync with @sourcebot/mcp/src/types.ts
|
||||||
import {
|
import {
|
||||||
fileSourceResponseSchema,
|
fileSourceResponseSchema,
|
||||||
listRepositoriesResponseSchema,
|
listRepositoriesResponseSchema,
|
||||||
|
|
|
||||||
484
yarn.lock
484
yarn.lock
|
|
@ -1970,6 +1970,24 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@modelcontextprotocol/sdk@npm:^1.10.2":
|
||||||
|
version: 1.10.2
|
||||||
|
resolution: "@modelcontextprotocol/sdk@npm:1.10.2"
|
||||||
|
dependencies:
|
||||||
|
content-type: "npm:^1.0.5"
|
||||||
|
cors: "npm:^2.8.5"
|
||||||
|
cross-spawn: "npm:^7.0.3"
|
||||||
|
eventsource: "npm:^3.0.2"
|
||||||
|
express: "npm:^5.0.1"
|
||||||
|
express-rate-limit: "npm:^7.5.0"
|
||||||
|
pkce-challenge: "npm:^5.0.0"
|
||||||
|
raw-body: "npm:^3.0.0"
|
||||||
|
zod: "npm:^3.23.8"
|
||||||
|
zod-to-json-schema: "npm:^3.24.1"
|
||||||
|
checksum: 10c0/a2a146dec37d13c8108b4c42912d65f1f5b0e8f3adda4c300336369519f3caa52e996afb65d6a6c03ae3b6fc1e2425cad4af1e619206b6ee3e15327b4ee01d4c
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@msgpack/msgpack@npm:^2.5.1":
|
"@msgpack/msgpack@npm:^2.5.1":
|
||||||
version: 2.8.0
|
version: 2.8.0
|
||||||
resolution: "@msgpack/msgpack@npm:2.8.0"
|
resolution: "@msgpack/msgpack@npm:2.8.0"
|
||||||
|
|
@ -5188,7 +5206,7 @@ __metadata:
|
||||||
typescript: "npm:^5.6.2"
|
typescript: "npm:^5.6.2"
|
||||||
vitest: "npm:^2.1.9"
|
vitest: "npm:^2.1.9"
|
||||||
winston: "npm:^3.15.0"
|
winston: "npm:^3.15.0"
|
||||||
zod: "npm:^3.24.2"
|
zod: "npm:^3.24.3"
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
|
|
@ -5226,6 +5244,25 @@ __metadata:
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
|
"@sourcebot/mcp@workspace:packages/mcp":
|
||||||
|
version: 0.0.0-use.local
|
||||||
|
resolution: "@sourcebot/mcp@workspace:packages/mcp"
|
||||||
|
dependencies:
|
||||||
|
"@modelcontextprotocol/sdk": "npm:^1.10.2"
|
||||||
|
"@t3-oss/env-core": "npm:^0.13.4"
|
||||||
|
"@types/express": "npm:^5.0.1"
|
||||||
|
"@types/node": "npm:^20.0.0"
|
||||||
|
escape-string-regexp: "npm:^5.0.0"
|
||||||
|
express: "npm:^5.1.0"
|
||||||
|
tsc-watch: "npm:6.2.1"
|
||||||
|
tsx: "npm:^4.0.0"
|
||||||
|
typescript: "npm:^5.0.0"
|
||||||
|
zod: "npm:^3.24.3"
|
||||||
|
bin:
|
||||||
|
sourcebot-mcp: ./dist/index.js
|
||||||
|
languageName: unknown
|
||||||
|
linkType: soft
|
||||||
|
|
||||||
"@sourcebot/schemas@workspace:*, @sourcebot/schemas@workspace:packages/schemas":
|
"@sourcebot/schemas@workspace:*, @sourcebot/schemas@workspace:packages/schemas":
|
||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "@sourcebot/schemas@workspace:packages/schemas"
|
resolution: "@sourcebot/schemas@workspace:packages/schemas"
|
||||||
|
|
@ -5233,6 +5270,7 @@ __metadata:
|
||||||
"@apidevtools/json-schema-ref-parser": "npm:^11.7.3"
|
"@apidevtools/json-schema-ref-parser": "npm:^11.7.3"
|
||||||
glob: "npm:^11.0.1"
|
glob: "npm:^11.0.1"
|
||||||
json-schema-to-typescript: "npm:^15.0.4"
|
json-schema-to-typescript: "npm:^15.0.4"
|
||||||
|
nodemon: "npm:^3.1.10"
|
||||||
tsx: "npm:^4.19.2"
|
tsx: "npm:^4.19.2"
|
||||||
typescript: "npm:^5.7.3"
|
typescript: "npm:^5.7.3"
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
|
|
@ -5387,7 +5425,7 @@ __metadata:
|
||||||
usehooks-ts: "npm:^3.1.0"
|
usehooks-ts: "npm:^3.1.0"
|
||||||
vite-tsconfig-paths: "npm:^5.1.3"
|
vite-tsconfig-paths: "npm:^5.1.3"
|
||||||
vitest: "npm:^2.1.5"
|
vitest: "npm:^2.1.5"
|
||||||
zod: "npm:^3.24.2"
|
zod: "npm:^3.24.3"
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
|
|
@ -5457,6 +5495,25 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@t3-oss/env-core@npm:^0.13.4":
|
||||||
|
version: 0.13.4
|
||||||
|
resolution: "@t3-oss/env-core@npm:0.13.4"
|
||||||
|
peerDependencies:
|
||||||
|
arktype: ^2.1.0
|
||||||
|
typescript: ">=5.0.0"
|
||||||
|
valibot: ^1.0.0-beta.7 || ^1.0.0
|
||||||
|
zod: ^3.24.0 || ^4.0.0-beta.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
typescript:
|
||||||
|
optional: true
|
||||||
|
valibot:
|
||||||
|
optional: true
|
||||||
|
zod:
|
||||||
|
optional: true
|
||||||
|
checksum: 10c0/3598c1582b4cd0aead095a492d60cb7656ffa308c0362744fe32f04ec6563601c04d898c0da7b5efb4dc7ace1d3b18a77f268a15a9e940a6997d9dd84f86a749
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@t3-oss/env-nextjs@npm:^0.12.0":
|
"@t3-oss/env-nextjs@npm:^0.12.0":
|
||||||
version: 0.12.0
|
version: 0.12.0
|
||||||
resolution: "@t3-oss/env-nextjs@npm:0.12.0"
|
resolution: "@t3-oss/env-nextjs@npm:0.12.0"
|
||||||
|
|
@ -5610,7 +5667,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@types/express@npm:^5.0.0":
|
"@types/express@npm:^5.0.0, @types/express@npm:^5.0.1":
|
||||||
version: 5.0.1
|
version: 5.0.1
|
||||||
resolution: "@types/express@npm:5.0.1"
|
resolution: "@types/express@npm:5.0.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
@ -5710,6 +5767,15 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@types/node@npm:^20.0.0":
|
||||||
|
version: 20.17.32
|
||||||
|
resolution: "@types/node@npm:20.17.32"
|
||||||
|
dependencies:
|
||||||
|
undici-types: "npm:~6.19.2"
|
||||||
|
checksum: 10c0/2461df36f67704f68db64d33abc5ad00b4b35ac94e996adff88c7322f9572e3e60ddaeed7e9f34ae203120d2ba36cc931fd3a8ddddf0c63943e8600c365c6396
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@types/nodemailer@npm:^6.4.17":
|
"@types/nodemailer@npm:^6.4.17":
|
||||||
version: 6.4.17
|
version: 6.4.17
|
||||||
resolution: "@types/nodemailer@npm:6.4.17"
|
resolution: "@types/nodemailer@npm:6.4.17"
|
||||||
|
|
@ -6298,6 +6364,16 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"accepts@npm:^2.0.0":
|
||||||
|
version: 2.0.0
|
||||||
|
resolution: "accepts@npm:2.0.0"
|
||||||
|
dependencies:
|
||||||
|
mime-types: "npm:^3.0.0"
|
||||||
|
negotiator: "npm:^1.0.0"
|
||||||
|
checksum: 10c0/98374742097e140891546076215f90c32644feacf652db48412329de4c2a529178a81aa500fbb13dd3e6cbf6e68d829037b123ac037fc9a08bcec4b87b358eef
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"accepts@npm:~1.3.4, accepts@npm:~1.3.8":
|
"accepts@npm:~1.3.4, accepts@npm:~1.3.8":
|
||||||
version: 1.3.8
|
version: 1.3.8
|
||||||
resolution: "accepts@npm:1.3.8"
|
resolution: "accepts@npm:1.3.8"
|
||||||
|
|
@ -6738,6 +6814,23 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"body-parser@npm:^2.2.0":
|
||||||
|
version: 2.2.0
|
||||||
|
resolution: "body-parser@npm:2.2.0"
|
||||||
|
dependencies:
|
||||||
|
bytes: "npm:^3.1.2"
|
||||||
|
content-type: "npm:^1.0.5"
|
||||||
|
debug: "npm:^4.4.0"
|
||||||
|
http-errors: "npm:^2.0.0"
|
||||||
|
iconv-lite: "npm:^0.6.3"
|
||||||
|
on-finished: "npm:^2.4.1"
|
||||||
|
qs: "npm:^6.14.0"
|
||||||
|
raw-body: "npm:^3.0.0"
|
||||||
|
type-is: "npm:^2.0.0"
|
||||||
|
checksum: 10c0/a9ded39e71ac9668e2211afa72e82ff86cc5ef94de1250b7d1ba9cc299e4150408aaa5f1e8b03dd4578472a3ce6d1caa2a23b27a6c18e526e48b4595174c116c
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"brace-expansion@npm:^1.1.7":
|
"brace-expansion@npm:^1.1.7":
|
||||||
version: 1.1.11
|
version: 1.1.11
|
||||||
resolution: "brace-expansion@npm:1.1.11"
|
resolution: "brace-expansion@npm:1.1.11"
|
||||||
|
|
@ -6814,7 +6907,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"bytes@npm:3.1.2":
|
"bytes@npm:3.1.2, bytes@npm:^3.1.2":
|
||||||
version: 3.1.2
|
version: 3.1.2
|
||||||
resolution: "bytes@npm:3.1.2"
|
resolution: "bytes@npm:3.1.2"
|
||||||
checksum: 10c0/76d1c43cbd602794ad8ad2ae94095cddeb1de78c5dddaa7005c51af10b0176c69971a6d88e805a90c2b6550d76636e43c40d8427a808b8645ede885de4a0358e
|
checksum: 10c0/76d1c43cbd602794ad8ad2ae94095cddeb1de78c5dddaa7005c51af10b0176c69971a6d88e805a90c2b6550d76636e43c40d8427a808b8645ede885de4a0358e
|
||||||
|
|
@ -6973,7 +7066,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"chokidar@npm:^3.5.3, chokidar@npm:^3.6.0":
|
"chokidar@npm:^3.5.2, chokidar@npm:^3.5.3, chokidar@npm:^3.6.0":
|
||||||
version: 3.6.0
|
version: 3.6.0
|
||||||
resolution: "chokidar@npm:3.6.0"
|
resolution: "chokidar@npm:3.6.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
@ -7447,7 +7540,16 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"content-type@npm:~1.0.4, content-type@npm:~1.0.5":
|
"content-disposition@npm:^1.0.0":
|
||||||
|
version: 1.0.0
|
||||||
|
resolution: "content-disposition@npm:1.0.0"
|
||||||
|
dependencies:
|
||||||
|
safe-buffer: "npm:5.2.1"
|
||||||
|
checksum: 10c0/c7b1ba0cea2829da0352ebc1b7f14787c73884bc707c8bc2271d9e3bf447b372270d09f5d3980dc5037c749ceef56b9a13fccd0b0001c87c3f12579967e4dd27
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"content-type@npm:^1.0.5, content-type@npm:~1.0.4, content-type@npm:~1.0.5":
|
||||||
version: 1.0.5
|
version: 1.0.5
|
||||||
resolution: "content-type@npm:1.0.5"
|
resolution: "content-type@npm:1.0.5"
|
||||||
checksum: 10c0/b76ebed15c000aee4678c3707e0860cb6abd4e680a598c0a26e17f0bfae723ec9cc2802f0ff1bc6e4d80603719010431d2231018373d4dde10f9ccff9dadf5af
|
checksum: 10c0/b76ebed15c000aee4678c3707e0860cb6abd4e680a598c0a26e17f0bfae723ec9cc2802f0ff1bc6e4d80603719010431d2231018373d4dde10f9ccff9dadf5af
|
||||||
|
|
@ -7468,6 +7570,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"cookie-signature@npm:^1.2.1":
|
||||||
|
version: 1.2.2
|
||||||
|
resolution: "cookie-signature@npm:1.2.2"
|
||||||
|
checksum: 10c0/54e05df1a293b3ce81589b27dddc445f462f6fa6812147c033350cd3561a42bc14481674e05ed14c7bd0ce1e8bb3dc0e40851bad75415733711294ddce0b7bc6
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"cookie@npm:0.7.1":
|
"cookie@npm:0.7.1":
|
||||||
version: 0.7.1
|
version: 0.7.1
|
||||||
resolution: "cookie@npm:0.7.1"
|
resolution: "cookie@npm:0.7.1"
|
||||||
|
|
@ -7475,7 +7584,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"cookie@npm:~0.7.2":
|
"cookie@npm:^0.7.1, cookie@npm:~0.7.2":
|
||||||
version: 0.7.2
|
version: 0.7.2
|
||||||
resolution: "cookie@npm:0.7.2"
|
resolution: "cookie@npm:0.7.2"
|
||||||
checksum: 10c0/9596e8ccdbf1a3a88ae02cf5ee80c1c50959423e1022e4e60b91dd87c622af1da309253d8abdb258fb5e3eacb4f08e579dc58b4897b8087574eee0fd35dfa5d2
|
checksum: 10c0/9596e8ccdbf1a3a88ae02cf5ee80c1c50959423e1022e4e60b91dd87c622af1da309253d8abdb258fb5e3eacb4f08e579dc58b4897b8087574eee0fd35dfa5d2
|
||||||
|
|
@ -7489,7 +7598,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"cors@npm:~2.8.5":
|
"cors@npm:^2.8.5, cors@npm:~2.8.5":
|
||||||
version: 2.8.5
|
version: 2.8.5
|
||||||
resolution: "cors@npm:2.8.5"
|
resolution: "cors@npm:2.8.5"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
@ -7659,7 +7768,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.3.5, debug@npm:^4.3.7, debug@npm:^4.4.0":
|
"debug@npm:4, debug@npm:^4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.3.5, debug@npm:^4.3.7, debug@npm:^4.4.0":
|
||||||
version: 4.4.0
|
version: 4.4.0
|
||||||
resolution: "debug@npm:4.4.0"
|
resolution: "debug@npm:4.4.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
@ -7765,7 +7874,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"depd@npm:2.0.0":
|
"depd@npm:2.0.0, depd@npm:^2.0.0":
|
||||||
version: 2.0.0
|
version: 2.0.0
|
||||||
resolution: "depd@npm:2.0.0"
|
resolution: "depd@npm:2.0.0"
|
||||||
checksum: 10c0/58bd06ec20e19529b06f7ad07ddab60e504d9e0faca4bd23079fac2d279c3594334d736508dc350e06e510aba5e22e4594483b3a6562ce7c17dd797f4cc4ad2c
|
checksum: 10c0/58bd06ec20e19529b06f7ad07ddab60e504d9e0faca4bd23079fac2d279c3594334d736508dc350e06e510aba5e22e4594483b3a6562ce7c17dd797f4cc4ad2c
|
||||||
|
|
@ -8036,6 +8145,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"encodeurl@npm:^2.0.0, encodeurl@npm:~2.0.0":
|
||||||
|
version: 2.0.0
|
||||||
|
resolution: "encodeurl@npm:2.0.0"
|
||||||
|
checksum: 10c0/5d317306acb13e6590e28e27924c754163946a2480de11865c991a3a7eed4315cd3fba378b543ca145829569eefe9b899f3d84bb09870f675ae60bc924b01ceb
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"encodeurl@npm:~1.0.2":
|
"encodeurl@npm:~1.0.2":
|
||||||
version: 1.0.2
|
version: 1.0.2
|
||||||
resolution: "encodeurl@npm:1.0.2"
|
resolution: "encodeurl@npm:1.0.2"
|
||||||
|
|
@ -8043,13 +8159,6 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"encodeurl@npm:~2.0.0":
|
|
||||||
version: 2.0.0
|
|
||||||
resolution: "encodeurl@npm:2.0.0"
|
|
||||||
checksum: 10c0/5d317306acb13e6590e28e27924c754163946a2480de11865c991a3a7eed4315cd3fba378b543ca145829569eefe9b899f3d84bb09870f675ae60bc924b01ceb
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"encoding@npm:^0.1.13":
|
"encoding@npm:^0.1.13":
|
||||||
version: 0.1.13
|
version: 0.1.13
|
||||||
resolution: "encoding@npm:0.1.13"
|
resolution: "encoding@npm:0.1.13"
|
||||||
|
|
@ -8522,7 +8631,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"escape-html@npm:~1.0.3":
|
"escape-html@npm:^1.0.3, escape-html@npm:~1.0.3":
|
||||||
version: 1.0.3
|
version: 1.0.3
|
||||||
resolution: "escape-html@npm:1.0.3"
|
resolution: "escape-html@npm:1.0.3"
|
||||||
checksum: 10c0/524c739d776b36c3d29fa08a22e03e8824e3b2fd57500e5e44ecf3cc4707c34c60f9ca0781c0e33d191f2991161504c295e98f68c78fe7baa6e57081ec6ac0a3
|
checksum: 10c0/524c739d776b36c3d29fa08a22e03e8824e3b2fd57500e5e44ecf3cc4707c34c60f9ca0781c0e33d191f2991161504c295e98f68c78fe7baa6e57081ec6ac0a3
|
||||||
|
|
@ -8851,7 +8960,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"etag@npm:~1.8.1":
|
"etag@npm:^1.8.1, etag@npm:~1.8.1":
|
||||||
version: 1.8.1
|
version: 1.8.1
|
||||||
resolution: "etag@npm:1.8.1"
|
resolution: "etag@npm:1.8.1"
|
||||||
checksum: 10c0/12be11ef62fb9817314d790089a0a49fae4e1b50594135dcb8076312b7d7e470884b5100d249b28c18581b7fd52f8b485689ffae22a11ed9ec17377a33a08f84
|
checksum: 10c0/12be11ef62fb9817314d790089a0a49fae4e1b50594135dcb8076312b7d7e470884b5100d249b28c18581b7fd52f8b485689ffae22a11ed9ec17377a33a08f84
|
||||||
|
|
@ -8873,6 +8982,22 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"eventsource-parser@npm:^3.0.1":
|
||||||
|
version: 3.0.1
|
||||||
|
resolution: "eventsource-parser@npm:3.0.1"
|
||||||
|
checksum: 10c0/146ce5ae8325d07645a49bbc54d7ac3aef42f5138bfbbe83d5cf96293b50eab2219926d6cf41eed0a0f90132578089652ba9286a19297662900133a9da6c2fd0
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"eventsource@npm:^3.0.2":
|
||||||
|
version: 3.0.6
|
||||||
|
resolution: "eventsource@npm:3.0.6"
|
||||||
|
dependencies:
|
||||||
|
eventsource-parser: "npm:^3.0.1"
|
||||||
|
checksum: 10c0/074d865ea1c7e29e3243f85a13306e89fca2d775b982dca03fa6bfa75c56827fa89cf1ab9e730db24bd6b104cbdcae074f2b37ba498874e9dd9710fbff4979bb
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"expect-type@npm:^1.1.0":
|
"expect-type@npm:^1.1.0":
|
||||||
version: 1.2.0
|
version: 1.2.0
|
||||||
resolution: "expect-type@npm:1.2.0"
|
resolution: "expect-type@npm:1.2.0"
|
||||||
|
|
@ -8887,6 +9012,15 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"express-rate-limit@npm:^7.5.0":
|
||||||
|
version: 7.5.0
|
||||||
|
resolution: "express-rate-limit@npm:7.5.0"
|
||||||
|
peerDependencies:
|
||||||
|
express: ^4.11 || 5 || ^5.0.0-beta.1
|
||||||
|
checksum: 10c0/3e96afa05b4f577395688ede37e0cb19901f20c350b32575fb076f3d25176209fb88d3648151755c232aaf304147c58531f070757978f376e2f08326449299fd
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"express@npm:^4.21.2":
|
"express@npm:^4.21.2":
|
||||||
version: 4.21.2
|
version: 4.21.2
|
||||||
resolution: "express@npm:4.21.2"
|
resolution: "express@npm:4.21.2"
|
||||||
|
|
@ -8926,6 +9060,41 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"express@npm:^5.0.1, express@npm:^5.1.0":
|
||||||
|
version: 5.1.0
|
||||||
|
resolution: "express@npm:5.1.0"
|
||||||
|
dependencies:
|
||||||
|
accepts: "npm:^2.0.0"
|
||||||
|
body-parser: "npm:^2.2.0"
|
||||||
|
content-disposition: "npm:^1.0.0"
|
||||||
|
content-type: "npm:^1.0.5"
|
||||||
|
cookie: "npm:^0.7.1"
|
||||||
|
cookie-signature: "npm:^1.2.1"
|
||||||
|
debug: "npm:^4.4.0"
|
||||||
|
encodeurl: "npm:^2.0.0"
|
||||||
|
escape-html: "npm:^1.0.3"
|
||||||
|
etag: "npm:^1.8.1"
|
||||||
|
finalhandler: "npm:^2.1.0"
|
||||||
|
fresh: "npm:^2.0.0"
|
||||||
|
http-errors: "npm:^2.0.0"
|
||||||
|
merge-descriptors: "npm:^2.0.0"
|
||||||
|
mime-types: "npm:^3.0.0"
|
||||||
|
on-finished: "npm:^2.4.1"
|
||||||
|
once: "npm:^1.4.0"
|
||||||
|
parseurl: "npm:^1.3.3"
|
||||||
|
proxy-addr: "npm:^2.0.7"
|
||||||
|
qs: "npm:^6.14.0"
|
||||||
|
range-parser: "npm:^1.2.1"
|
||||||
|
router: "npm:^2.2.0"
|
||||||
|
send: "npm:^1.1.0"
|
||||||
|
serve-static: "npm:^2.2.0"
|
||||||
|
statuses: "npm:^2.0.1"
|
||||||
|
type-is: "npm:^2.0.1"
|
||||||
|
vary: "npm:^1.1.2"
|
||||||
|
checksum: 10c0/80ce7c53c5f56887d759b94c3f2283e2e51066c98d4b72a4cc1338e832b77f1e54f30d0239cc10815a0f849bdb753e6a284d2fa48d4ab56faf9c501f55d751d6
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"fast-content-type-parse@npm:^2.0.0":
|
"fast-content-type-parse@npm:^2.0.0":
|
||||||
version: 2.0.1
|
version: 2.0.1
|
||||||
resolution: "fast-content-type-parse@npm:2.0.1"
|
resolution: "fast-content-type-parse@npm:2.0.1"
|
||||||
|
|
@ -9056,6 +9225,20 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"finalhandler@npm:^2.1.0":
|
||||||
|
version: 2.1.0
|
||||||
|
resolution: "finalhandler@npm:2.1.0"
|
||||||
|
dependencies:
|
||||||
|
debug: "npm:^4.4.0"
|
||||||
|
encodeurl: "npm:^2.0.0"
|
||||||
|
escape-html: "npm:^1.0.3"
|
||||||
|
on-finished: "npm:^2.4.1"
|
||||||
|
parseurl: "npm:^1.3.3"
|
||||||
|
statuses: "npm:^2.0.1"
|
||||||
|
checksum: 10c0/da0bbca6d03873472ee890564eb2183f4ed377f25f3628a0fc9d16dac40bed7b150a0d82ebb77356e4c6d97d2796ad2dba22948b951dddee2c8768b0d1b9fb1f
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"find-up@npm:^5.0.0":
|
"find-up@npm:^5.0.0":
|
||||||
version: 5.0.0
|
version: 5.0.0
|
||||||
resolution: "find-up@npm:5.0.0"
|
resolution: "find-up@npm:5.0.0"
|
||||||
|
|
@ -9153,6 +9336,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"fresh@npm:^2.0.0":
|
||||||
|
version: 2.0.0
|
||||||
|
resolution: "fresh@npm:2.0.0"
|
||||||
|
checksum: 10c0/0557548194cb9a809a435bf92bcfbc20c89e8b5eb38861b73ced36750437251e39a111fc3a18b98531be9dd91fe1411e4969f229dc579ec0251ce6c5d4900bbc
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"from@npm:~0":
|
"from@npm:~0":
|
||||||
version: 0.1.7
|
version: 0.1.7
|
||||||
resolution: "from@npm:0.1.7"
|
resolution: "from@npm:0.1.7"
|
||||||
|
|
@ -9651,7 +9841,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"http-errors@npm:2.0.0":
|
"http-errors@npm:2.0.0, http-errors@npm:^2.0.0":
|
||||||
version: 2.0.0
|
version: 2.0.0
|
||||||
resolution: "http-errors@npm:2.0.0"
|
resolution: "http-errors@npm:2.0.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
@ -9710,7 +9900,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"iconv-lite@npm:0.6.3, iconv-lite@npm:^0.6.2":
|
"iconv-lite@npm:0.6.3, iconv-lite@npm:^0.6.2, iconv-lite@npm:^0.6.3":
|
||||||
version: 0.6.3
|
version: 0.6.3
|
||||||
resolution: "iconv-lite@npm:0.6.3"
|
resolution: "iconv-lite@npm:0.6.3"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
@ -9726,6 +9916,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"ignore-by-default@npm:^1.0.1":
|
||||||
|
version: 1.0.1
|
||||||
|
resolution: "ignore-by-default@npm:1.0.1"
|
||||||
|
checksum: 10c0/9ab6e70e80f7cc12735def7ecb5527cfa56ab4e1152cd64d294522827f2dcf1f6d85531241537dc3713544e88dd888f65cb3c49c7b2cddb9009087c75274e533
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"ignore@npm:^5.2.0, ignore@npm:^5.3.1":
|
"ignore@npm:^5.2.0, ignore@npm:^5.3.1":
|
||||||
version: 5.3.2
|
version: 5.3.2
|
||||||
resolution: "ignore@npm:5.3.2"
|
resolution: "ignore@npm:5.3.2"
|
||||||
|
|
@ -10035,6 +10232,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"is-promise@npm:^4.0.0":
|
||||||
|
version: 4.0.0
|
||||||
|
resolution: "is-promise@npm:4.0.0"
|
||||||
|
checksum: 10c0/ebd5c672d73db781ab33ccb155fb9969d6028e37414d609b115cc534654c91ccd061821d5b987eefaa97cf4c62f0b909bb2f04db88306de26e91bfe8ddc01503
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"is-reference@npm:1.2.1":
|
"is-reference@npm:1.2.1":
|
||||||
version: 1.2.1
|
version: 1.2.1
|
||||||
resolution: "is-reference@npm:1.2.1"
|
resolution: "is-reference@npm:1.2.1"
|
||||||
|
|
@ -10783,6 +10987,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"media-typer@npm:^1.1.0":
|
||||||
|
version: 1.1.0
|
||||||
|
resolution: "media-typer@npm:1.1.0"
|
||||||
|
checksum: 10c0/7b4baa40b25964bb90e2121ee489ec38642127e48d0cc2b6baa442688d3fde6262bfdca86d6bbf6ba708784afcac168c06840c71facac70e390f5f759ac121b9
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"memorystream@npm:^0.3.1":
|
"memorystream@npm:^0.3.1":
|
||||||
version: 0.3.1
|
version: 0.3.1
|
||||||
resolution: "memorystream@npm:0.3.1"
|
resolution: "memorystream@npm:0.3.1"
|
||||||
|
|
@ -10797,6 +11008,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"merge-descriptors@npm:^2.0.0":
|
||||||
|
version: 2.0.0
|
||||||
|
resolution: "merge-descriptors@npm:2.0.0"
|
||||||
|
checksum: 10c0/95389b7ced3f9b36fbdcf32eb946dc3dd1774c2fdf164609e55b18d03aa499b12bd3aae3a76c1c7185b96279e9803525550d3eb292b5224866060a288f335cb3
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"merge2@npm:^1.3.0, merge2@npm:^1.4.1":
|
"merge2@npm:^1.3.0, merge2@npm:^1.4.1":
|
||||||
version: 1.4.1
|
version: 1.4.1
|
||||||
resolution: "merge2@npm:1.4.1"
|
resolution: "merge2@npm:1.4.1"
|
||||||
|
|
@ -10870,6 +11088,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"mime-db@npm:^1.54.0":
|
||||||
|
version: 1.54.0
|
||||||
|
resolution: "mime-db@npm:1.54.0"
|
||||||
|
checksum: 10c0/8d907917bc2a90fa2df842cdf5dfeaf509adc15fe0531e07bb2f6ab15992416479015828d6a74200041c492e42cce3ebf78e5ce714388a0a538ea9c53eece284
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"mime-types@npm:2.1.35, mime-types@npm:^2.1.12, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34":
|
"mime-types@npm:2.1.35, mime-types@npm:^2.1.12, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34":
|
||||||
version: 2.1.35
|
version: 2.1.35
|
||||||
resolution: "mime-types@npm:2.1.35"
|
resolution: "mime-types@npm:2.1.35"
|
||||||
|
|
@ -10879,6 +11104,15 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"mime-types@npm:^3.0.0, mime-types@npm:^3.0.1":
|
||||||
|
version: 3.0.1
|
||||||
|
resolution: "mime-types@npm:3.0.1"
|
||||||
|
dependencies:
|
||||||
|
mime-db: "npm:^1.54.0"
|
||||||
|
checksum: 10c0/bd8c20d3694548089cf229016124f8f40e6a60bbb600161ae13e45f793a2d5bb40f96bbc61f275836696179c77c1d6bf4967b2a75e0a8ad40fe31f4ed5be4da5
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"mime@npm:1.6.0":
|
"mime@npm:1.6.0":
|
||||||
version: 1.6.0
|
version: 1.6.0
|
||||||
resolution: "mime@npm:1.6.0"
|
resolution: "mime@npm:1.6.0"
|
||||||
|
|
@ -11408,6 +11642,26 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"nodemon@npm:^3.1.10":
|
||||||
|
version: 3.1.10
|
||||||
|
resolution: "nodemon@npm:3.1.10"
|
||||||
|
dependencies:
|
||||||
|
chokidar: "npm:^3.5.2"
|
||||||
|
debug: "npm:^4"
|
||||||
|
ignore-by-default: "npm:^1.0.1"
|
||||||
|
minimatch: "npm:^3.1.2"
|
||||||
|
pstree.remy: "npm:^1.1.8"
|
||||||
|
semver: "npm:^7.5.3"
|
||||||
|
simple-update-notifier: "npm:^2.0.0"
|
||||||
|
supports-color: "npm:^5.5.0"
|
||||||
|
touch: "npm:^3.1.0"
|
||||||
|
undefsafe: "npm:^2.0.5"
|
||||||
|
bin:
|
||||||
|
nodemon: bin/nodemon.js
|
||||||
|
checksum: 10c0/95b64d647f2c22e85e375b250517b0a4b32c2d2392ad898444e331f70d6b1ab43b17f53a8a1d68d5879ab8401fc6cd6e26f0d2a8736240984f6b5a8435b407c0
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"nopt@npm:^8.0.0":
|
"nopt@npm:^8.0.0":
|
||||||
version: 8.1.0
|
version: 8.1.0
|
||||||
resolution: "nopt@npm:8.1.0"
|
resolution: "nopt@npm:8.1.0"
|
||||||
|
|
@ -11576,7 +11830,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"on-finished@npm:2.4.1":
|
"on-finished@npm:2.4.1, on-finished@npm:^2.4.1":
|
||||||
version: 2.4.1
|
version: 2.4.1
|
||||||
resolution: "on-finished@npm:2.4.1"
|
resolution: "on-finished@npm:2.4.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
@ -11585,7 +11839,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"once@npm:^1.3.0":
|
"once@npm:^1.3.0, once@npm:^1.4.0":
|
||||||
version: 1.4.0
|
version: 1.4.0
|
||||||
resolution: "once@npm:1.4.0"
|
resolution: "once@npm:1.4.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
@ -11751,7 +12005,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"parseurl@npm:~1.3.3":
|
"parseurl@npm:^1.3.3, parseurl@npm:~1.3.3":
|
||||||
version: 1.3.3
|
version: 1.3.3
|
||||||
resolution: "parseurl@npm:1.3.3"
|
resolution: "parseurl@npm:1.3.3"
|
||||||
checksum: 10c0/90dd4760d6f6174adb9f20cf0965ae12e23879b5f5464f38e92fce8073354341e4b3b76fa3d878351efe7d01e617121955284cfd002ab087fba1a0726ec0b4f5
|
checksum: 10c0/90dd4760d6f6174adb9f20cf0965ae12e23879b5f5464f38e92fce8073354341e4b3b76fa3d878351efe7d01e617121955284cfd002ab087fba1a0726ec0b4f5
|
||||||
|
|
@ -11820,6 +12074,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"path-to-regexp@npm:^8.0.0":
|
||||||
|
version: 8.2.0
|
||||||
|
resolution: "path-to-regexp@npm:8.2.0"
|
||||||
|
checksum: 10c0/ef7d0a887b603c0a142fad16ccebdcdc42910f0b14830517c724466ad676107476bba2fe9fffd28fd4c141391ccd42ea426f32bb44c2c82ecaefe10c37b90f5a
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"path-type@npm:^3.0.0":
|
"path-type@npm:^3.0.0":
|
||||||
version: 3.0.0
|
version: 3.0.0
|
||||||
resolution: "path-type@npm:3.0.0"
|
resolution: "path-type@npm:3.0.0"
|
||||||
|
|
@ -11973,6 +12234,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"pkce-challenge@npm:^5.0.0":
|
||||||
|
version: 5.0.0
|
||||||
|
resolution: "pkce-challenge@npm:5.0.0"
|
||||||
|
checksum: 10c0/c6706d627fdbb6f22bf8cc5d60d96d6b6a7bb481399b336a3d3f4e9bfba3e167a2c32f8ec0b5e74be686a0ba3bcc9894865d4c2dd1b91cea4c05dba1f28602c3
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"possible-typed-array-names@npm:^1.0.0":
|
"possible-typed-array-names@npm:^1.0.0":
|
||||||
version: 1.1.0
|
version: 1.1.0
|
||||||
resolution: "possible-typed-array-names@npm:1.1.0"
|
resolution: "possible-typed-array-names@npm:1.1.0"
|
||||||
|
|
@ -12328,7 +12596,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"proxy-addr@npm:~2.0.7":
|
"proxy-addr@npm:^2.0.7, proxy-addr@npm:~2.0.7":
|
||||||
version: 2.0.7
|
version: 2.0.7
|
||||||
resolution: "proxy-addr@npm:2.0.7"
|
resolution: "proxy-addr@npm:2.0.7"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
@ -12365,6 +12633,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"pstree.remy@npm:^1.1.8":
|
||||||
|
version: 1.1.8
|
||||||
|
resolution: "pstree.remy@npm:1.1.8"
|
||||||
|
checksum: 10c0/30f78c88ce6393cb3f7834216cb6e282eb83c92ccb227430d4590298ab2811bc4a4745f850a27c5178e79a8f3e316591de0fec87abc19da648c2b3c6eb766d14
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"punycode.js@npm:^2.3.1":
|
"punycode.js@npm:^2.3.1":
|
||||||
version: 2.3.1
|
version: 2.3.1
|
||||||
resolution: "punycode.js@npm:2.3.1"
|
resolution: "punycode.js@npm:2.3.1"
|
||||||
|
|
@ -12388,7 +12663,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"qs@npm:^6.11.0, qs@npm:^6.12.2":
|
"qs@npm:^6.11.0, qs@npm:^6.12.2, qs@npm:^6.14.0":
|
||||||
version: 6.14.0
|
version: 6.14.0
|
||||||
resolution: "qs@npm:6.14.0"
|
resolution: "qs@npm:6.14.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
@ -12421,7 +12696,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"range-parser@npm:~1.2.1":
|
"range-parser@npm:^1.2.1, range-parser@npm:~1.2.1":
|
||||||
version: 1.2.1
|
version: 1.2.1
|
||||||
resolution: "range-parser@npm:1.2.1"
|
resolution: "range-parser@npm:1.2.1"
|
||||||
checksum: 10c0/96c032ac2475c8027b7a4e9fe22dc0dfe0f6d90b85e496e0f016fbdb99d6d066de0112e680805075bd989905e2123b3b3d002765149294dce0c1f7f01fcc2ea0
|
checksum: 10c0/96c032ac2475c8027b7a4e9fe22dc0dfe0f6d90b85e496e0f016fbdb99d6d066de0112e680805075bd989905e2123b3b3d002765149294dce0c1f7f01fcc2ea0
|
||||||
|
|
@ -12447,6 +12722,18 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"raw-body@npm:^3.0.0":
|
||||||
|
version: 3.0.0
|
||||||
|
resolution: "raw-body@npm:3.0.0"
|
||||||
|
dependencies:
|
||||||
|
bytes: "npm:3.1.2"
|
||||||
|
http-errors: "npm:2.0.0"
|
||||||
|
iconv-lite: "npm:0.6.3"
|
||||||
|
unpipe: "npm:1.0.0"
|
||||||
|
checksum: 10c0/f8daf4b724064a4811d118745a781ca0fb4676298b8adadfd6591155549cfea0a067523cf7dd3baeb1265fecc9ce5dfb2fc788c12c66b85202a336593ece0f87
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"react-device-detect@npm:^2.2.3":
|
"react-device-detect@npm:^2.2.3":
|
||||||
version: 2.2.3
|
version: 2.2.3
|
||||||
resolution: "react-device-detect@npm:2.2.3"
|
resolution: "react-device-detect@npm:2.2.3"
|
||||||
|
|
@ -13082,6 +13369,19 @@ __metadata:
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
|
"router@npm:^2.2.0":
|
||||||
|
version: 2.2.0
|
||||||
|
resolution: "router@npm:2.2.0"
|
||||||
|
dependencies:
|
||||||
|
debug: "npm:^4.4.0"
|
||||||
|
depd: "npm:^2.0.0"
|
||||||
|
is-promise: "npm:^4.0.0"
|
||||||
|
parseurl: "npm:^1.3.3"
|
||||||
|
path-to-regexp: "npm:^8.0.0"
|
||||||
|
checksum: 10c0/3279de7450c8eae2f6e095e9edacbdeec0abb5cb7249c6e719faa0db2dba43574b4fff5892d9220631c9abaff52dd3cad648cfea2aaace845e1a071915ac8867
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"rrweb-cssom@npm:^0.7.1":
|
"rrweb-cssom@npm:^0.7.1":
|
||||||
version: 0.7.1
|
version: 0.7.1
|
||||||
resolution: "rrweb-cssom@npm:0.7.1"
|
resolution: "rrweb-cssom@npm:0.7.1"
|
||||||
|
|
@ -13247,7 +13547,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"semver@npm:^7.3.5, semver@npm:^7.5.2, semver@npm:^7.5.4, semver@npm:^7.6.0, semver@npm:^7.6.3":
|
"semver@npm:^7.3.5, semver@npm:^7.5.2, semver@npm:^7.5.3, semver@npm:^7.5.4, semver@npm:^7.6.0, semver@npm:^7.6.3":
|
||||||
version: 7.7.1
|
version: 7.7.1
|
||||||
resolution: "semver@npm:7.7.1"
|
resolution: "semver@npm:7.7.1"
|
||||||
bin:
|
bin:
|
||||||
|
|
@ -13277,6 +13577,25 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"send@npm:^1.1.0, send@npm:^1.2.0":
|
||||||
|
version: 1.2.0
|
||||||
|
resolution: "send@npm:1.2.0"
|
||||||
|
dependencies:
|
||||||
|
debug: "npm:^4.3.5"
|
||||||
|
encodeurl: "npm:^2.0.0"
|
||||||
|
escape-html: "npm:^1.0.3"
|
||||||
|
etag: "npm:^1.8.1"
|
||||||
|
fresh: "npm:^2.0.0"
|
||||||
|
http-errors: "npm:^2.0.0"
|
||||||
|
mime-types: "npm:^3.0.1"
|
||||||
|
ms: "npm:^2.1.3"
|
||||||
|
on-finished: "npm:^2.4.1"
|
||||||
|
range-parser: "npm:^1.2.1"
|
||||||
|
statuses: "npm:^2.0.1"
|
||||||
|
checksum: 10c0/531bcfb5616948d3468d95a1fd0adaeb0c20818ba4a500f439b800ca2117971489e02074ce32796fd64a6772ea3e7235fe0583d8241dbd37a053dc3378eff9a5
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"serialize-error@npm:8.1.0":
|
"serialize-error@npm:8.1.0":
|
||||||
version: 8.1.0
|
version: 8.1.0
|
||||||
resolution: "serialize-error@npm:8.1.0"
|
resolution: "serialize-error@npm:8.1.0"
|
||||||
|
|
@ -13298,6 +13617,18 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"serve-static@npm:^2.2.0":
|
||||||
|
version: 2.2.0
|
||||||
|
resolution: "serve-static@npm:2.2.0"
|
||||||
|
dependencies:
|
||||||
|
encodeurl: "npm:^2.0.0"
|
||||||
|
escape-html: "npm:^1.0.3"
|
||||||
|
parseurl: "npm:^1.3.3"
|
||||||
|
send: "npm:^1.2.0"
|
||||||
|
checksum: 10c0/30e2ed1dbff1984836cfd0c65abf5d3f3f83bcd696c99d2d3c97edbd4e2a3ff4d3f87108a7d713640d290a7b6fe6c15ddcbc61165ab2eaad48ea8d3b52c7f913
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"server-only@npm:^0.0.1":
|
"server-only@npm:^0.0.1":
|
||||||
version: 0.0.1
|
version: 0.0.1
|
||||||
resolution: "server-only@npm:0.0.1"
|
resolution: "server-only@npm:0.0.1"
|
||||||
|
|
@ -13569,6 +13900,15 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"simple-update-notifier@npm:^2.0.0":
|
||||||
|
version: 2.0.0
|
||||||
|
resolution: "simple-update-notifier@npm:2.0.0"
|
||||||
|
dependencies:
|
||||||
|
semver: "npm:^7.5.3"
|
||||||
|
checksum: 10c0/2a00bd03bfbcbf8a737c47ab230d7920f8bfb92d1159d421bdd194479f6d01ebc995d13fbe13d45dace23066a78a3dc6642999b4e3b38b847e6664191575b20c
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"slash@npm:^3.0.0":
|
"slash@npm:^3.0.0":
|
||||||
version: 3.0.0
|
version: 3.0.0
|
||||||
resolution: "slash@npm:3.0.0"
|
resolution: "slash@npm:3.0.0"
|
||||||
|
|
@ -13758,7 +14098,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"statuses@npm:2.0.1":
|
"statuses@npm:2.0.1, statuses@npm:^2.0.1":
|
||||||
version: 2.0.1
|
version: 2.0.1
|
||||||
resolution: "statuses@npm:2.0.1"
|
resolution: "statuses@npm:2.0.1"
|
||||||
checksum: 10c0/34378b207a1620a24804ce8b5d230fea0c279f00b18a7209646d5d47e419d1cc23e7cbf33a25a1e51ac38973dc2ac2e1e9c647a8e481ef365f77668d72becfd0
|
checksum: 10c0/34378b207a1620a24804ce8b5d230fea0c279f00b18a7209646d5d47e419d1cc23e7cbf33a25a1e51ac38973dc2ac2e1e9c647a8e481ef365f77668d72becfd0
|
||||||
|
|
@ -14025,7 +14365,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"supports-color@npm:^5.3.0":
|
"supports-color@npm:^5.3.0, supports-color@npm:^5.5.0":
|
||||||
version: 5.5.0
|
version: 5.5.0
|
||||||
resolution: "supports-color@npm:5.5.0"
|
resolution: "supports-color@npm:5.5.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
@ -14254,6 +14594,15 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"touch@npm:^3.1.0":
|
||||||
|
version: 3.1.1
|
||||||
|
resolution: "touch@npm:3.1.1"
|
||||||
|
bin:
|
||||||
|
nodetouch: bin/nodetouch.js
|
||||||
|
checksum: 10c0/d2e4d269a42c846a22a29065b9af0b263de58effc85a1764bb7a2e8fc4b47700e9e2fcbd7eb1f5bffbb7c73d860f93600cef282b93ddac8f0b62321cb498b36e
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"tough-cookie@npm:^5.0.0":
|
"tough-cookie@npm:^5.0.0":
|
||||||
version: 5.1.2
|
version: 5.1.2
|
||||||
resolution: "tough-cookie@npm:5.1.2"
|
resolution: "tough-cookie@npm:5.1.2"
|
||||||
|
|
@ -14318,6 +14667,22 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"tsc-watch@npm:6.2.1":
|
||||||
|
version: 6.2.1
|
||||||
|
resolution: "tsc-watch@npm:6.2.1"
|
||||||
|
dependencies:
|
||||||
|
cross-spawn: "npm:^7.0.3"
|
||||||
|
node-cleanup: "npm:^2.1.2"
|
||||||
|
ps-tree: "npm:^1.2.0"
|
||||||
|
string-argv: "npm:^0.3.1"
|
||||||
|
peerDependencies:
|
||||||
|
typescript: "*"
|
||||||
|
bin:
|
||||||
|
tsc-watch: dist/lib/tsc-watch.js
|
||||||
|
checksum: 10c0/f5fe19e5ac9f4c42a5600c20aee9ff49e282f11813aead65ed58fa11d98a20f5a82bf4f931897270f49f6475dd54e9aab9c46a07c3801b8d237dfbe77bcf1bfc
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"tsc-watch@npm:^6.2.0":
|
"tsc-watch@npm:^6.2.0":
|
||||||
version: 6.3.0
|
version: 6.3.0
|
||||||
resolution: "tsc-watch@npm:6.3.0"
|
resolution: "tsc-watch@npm:6.3.0"
|
||||||
|
|
@ -14367,7 +14732,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"tsx@npm:^4.19.1, tsx@npm:^4.19.2":
|
"tsx@npm:^4.0.0, tsx@npm:^4.19.1, tsx@npm:^4.19.2":
|
||||||
version: 4.19.3
|
version: 4.19.3
|
||||||
resolution: "tsx@npm:4.19.3"
|
resolution: "tsx@npm:4.19.3"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
@ -14406,6 +14771,17 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"type-is@npm:^2.0.0, type-is@npm:^2.0.1":
|
||||||
|
version: 2.0.1
|
||||||
|
resolution: "type-is@npm:2.0.1"
|
||||||
|
dependencies:
|
||||||
|
content-type: "npm:^1.0.5"
|
||||||
|
media-typer: "npm:^1.1.0"
|
||||||
|
mime-types: "npm:^3.0.0"
|
||||||
|
checksum: 10c0/7f7ec0a060b16880bdad36824ab37c26019454b67d73e8a465ed5a3587440fbe158bc765f0da68344498235c877e7dbbb1600beccc94628ed05599d667951b99
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"type-is@npm:~1.6.18":
|
"type-is@npm:~1.6.18":
|
||||||
version: 1.6.18
|
version: 1.6.18
|
||||||
resolution: "type-is@npm:1.6.18"
|
resolution: "type-is@npm:1.6.18"
|
||||||
|
|
@ -14479,6 +14855,16 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"typescript@npm:^5.0.0":
|
||||||
|
version: 5.8.3
|
||||||
|
resolution: "typescript@npm:5.8.3"
|
||||||
|
bin:
|
||||||
|
tsc: bin/tsc
|
||||||
|
tsserver: bin/tsserver
|
||||||
|
checksum: 10c0/5f8bb01196e542e64d44db3d16ee0e4063ce4f3e3966df6005f2588e86d91c03e1fb131c2581baf0fb65ee79669eea6e161cd448178986587e9f6844446dbb48
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"typescript@patch:typescript@npm%3A^5#optional!builtin<compat/typescript>, typescript@patch:typescript@npm%3A^5.6.2#optional!builtin<compat/typescript>, typescript@patch:typescript@npm%3A^5.7.3#optional!builtin<compat/typescript>":
|
"typescript@patch:typescript@npm%3A^5#optional!builtin<compat/typescript>, typescript@patch:typescript@npm%3A^5.6.2#optional!builtin<compat/typescript>, typescript@patch:typescript@npm%3A^5.7.3#optional!builtin<compat/typescript>":
|
||||||
version: 5.8.2
|
version: 5.8.2
|
||||||
resolution: "typescript@patch:typescript@npm%3A5.8.2#optional!builtin<compat/typescript>::version=5.8.2&hash=5786d5"
|
resolution: "typescript@patch:typescript@npm%3A5.8.2#optional!builtin<compat/typescript>::version=5.8.2&hash=5786d5"
|
||||||
|
|
@ -14489,6 +14875,16 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"typescript@patch:typescript@npm%3A^5.0.0#optional!builtin<compat/typescript>":
|
||||||
|
version: 5.8.3
|
||||||
|
resolution: "typescript@patch:typescript@npm%3A5.8.3#optional!builtin<compat/typescript>::version=5.8.3&hash=5786d5"
|
||||||
|
bin:
|
||||||
|
tsc: bin/tsc
|
||||||
|
tsserver: bin/tsserver
|
||||||
|
checksum: 10c0/39117e346ff8ebd87ae1510b3a77d5d92dae5a89bde588c747d25da5c146603a99c8ee588c7ef80faaf123d89ed46f6dbd918d534d641083177d5fac38b8a1cb
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"ua-parser-js@npm:^1.0.33":
|
"ua-parser-js@npm:^1.0.33":
|
||||||
version: 1.0.40
|
version: 1.0.40
|
||||||
resolution: "ua-parser-js@npm:1.0.40"
|
resolution: "ua-parser-js@npm:1.0.40"
|
||||||
|
|
@ -14517,6 +14913,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"undefsafe@npm:^2.0.5":
|
||||||
|
version: 2.0.5
|
||||||
|
resolution: "undefsafe@npm:2.0.5"
|
||||||
|
checksum: 10c0/96c0466a5fbf395917974a921d5d4eee67bca4b30d3a31ce7e621e0228c479cf893e783a109af6e14329b52fe2f0cb4108665fad2b87b0018c0df6ac771261d5
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"undici-types@npm:~6.19.2":
|
"undici-types@npm:~6.19.2":
|
||||||
version: 6.19.8
|
version: 6.19.8
|
||||||
resolution: "undici-types@npm:6.19.8"
|
resolution: "undici-types@npm:6.19.8"
|
||||||
|
|
@ -14728,7 +15131,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"vary@npm:^1, vary@npm:~1.1.2":
|
"vary@npm:^1, vary@npm:^1.1.2, vary@npm:~1.1.2":
|
||||||
version: 1.1.2
|
version: 1.1.2
|
||||||
resolution: "vary@npm:1.1.2"
|
resolution: "vary@npm:1.1.2"
|
||||||
checksum: 10c0/f15d588d79f3675135ba783c91a4083dcd290a2a5be9fcb6514220a1634e23df116847b1cc51f66bfb0644cf9353b2abb7815ae499bab06e46dd33c1a6bf1f4f
|
checksum: 10c0/f15d588d79f3675135ba783c91a4083dcd290a2a5be9fcb6514220a1634e23df116847b1cc51f66bfb0644cf9353b2abb7815ae499bab06e46dd33c1a6bf1f4f
|
||||||
|
|
@ -15249,10 +15652,19 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"zod@npm:^3.24.2":
|
"zod-to-json-schema@npm:^3.24.1":
|
||||||
version: 3.24.2
|
version: 3.24.5
|
||||||
resolution: "zod@npm:3.24.2"
|
resolution: "zod-to-json-schema@npm:3.24.5"
|
||||||
checksum: 10c0/c638c7220150847f13ad90635b3e7d0321b36cce36f3fc6050ed960689594c949c326dfe2c6fa87c14b126ee5d370ccdebd6efb304f41ef5557a4aaca2824565
|
peerDependencies:
|
||||||
|
zod: ^3.24.1
|
||||||
|
checksum: 10c0/0745b94ba53e652d39f262641cdeb2f75d24339fb6076a38ce55bcf53d82dfaea63adf524ebc5f658681005401687f8e9551c4feca7c4c882e123e66091dfb90
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"zod@npm:^3.23.8, zod@npm:^3.24.3":
|
||||||
|
version: 3.24.3
|
||||||
|
resolution: "zod@npm:3.24.3"
|
||||||
|
checksum: 10c0/ab0369810968d0329a1a141e9418e01e5c9c2a4905cbb7cb7f5a131d6e9487596e1400e21eeff24c4a8ee28dacfa5bd6103893765c055b7a98c2006a5a4fc68d
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue