@copilotkit/pathfinder 1.1.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +39 -1
- package/README.md +65 -248
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +70 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +8 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +58 -5
- package/dist/config.js.map +1 -1
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +3 -1
- package/dist/db/client.js.map +1 -1
- package/dist/db/queries.d.ts +21 -4
- package/dist/db/queries.d.ts.map +1 -1
- package/dist/db/queries.js +101 -45
- package/dist/db/queries.js.map +1 -1
- package/dist/db/schema.d.ts +5 -0
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/db/schema.js +11 -0
- package/dist/db/schema.js.map +1 -1
- package/dist/faq-txt.d.ts +12 -0
- package/dist/faq-txt.d.ts.map +1 -0
- package/dist/faq-txt.js +37 -0
- package/dist/faq-txt.js.map +1 -0
- package/dist/index.js +2 -362
- package/dist/index.js.map +1 -1
- package/dist/indexing/chunking/html.d.ts +7 -0
- package/dist/indexing/chunking/html.d.ts.map +1 -0
- package/dist/indexing/chunking/html.js +356 -0
- package/dist/indexing/chunking/html.js.map +1 -0
- package/dist/indexing/chunking/index.js +5 -0
- package/dist/indexing/chunking/index.js.map +1 -1
- package/dist/indexing/chunking/qa.d.ts +8 -0
- package/dist/indexing/chunking/qa.d.ts.map +1 -0
- package/dist/indexing/chunking/qa.js +22 -0
- package/dist/indexing/chunking/qa.js.map +1 -0
- package/dist/indexing/distiller.d.ts +29 -0
- package/dist/indexing/distiller.d.ts.map +1 -0
- package/dist/indexing/distiller.js +104 -0
- package/dist/indexing/distiller.js.map +1 -0
- package/dist/indexing/orchestrator.d.ts +9 -3
- package/dist/indexing/orchestrator.d.ts.map +1 -1
- package/dist/indexing/orchestrator.js +113 -83
- package/dist/indexing/orchestrator.js.map +1 -1
- package/dist/indexing/pipeline.d.ts +18 -0
- package/dist/indexing/pipeline.d.ts.map +1 -0
- package/dist/indexing/pipeline.js +68 -0
- package/dist/indexing/pipeline.js.map +1 -0
- package/dist/indexing/providers/discord-api.d.ts +79 -0
- package/dist/indexing/providers/discord-api.d.ts.map +1 -0
- package/dist/indexing/providers/discord-api.js +167 -0
- package/dist/indexing/providers/discord-api.js.map +1 -0
- package/dist/indexing/providers/discord.d.ts +25 -0
- package/dist/indexing/providers/discord.d.ts.map +1 -0
- package/dist/indexing/providers/discord.js +282 -0
- package/dist/indexing/providers/discord.js.map +1 -0
- package/dist/indexing/providers/file.d.ts +18 -0
- package/dist/indexing/providers/file.d.ts.map +1 -0
- package/dist/indexing/providers/file.js +262 -0
- package/dist/indexing/providers/file.js.map +1 -0
- package/dist/indexing/providers/index.d.ts +5 -0
- package/dist/indexing/providers/index.d.ts.map +1 -0
- package/dist/indexing/providers/index.js +22 -0
- package/dist/indexing/providers/index.js.map +1 -0
- package/dist/indexing/providers/slack-api.d.ts +62 -0
- package/dist/indexing/providers/slack-api.d.ts.map +1 -0
- package/dist/indexing/providers/slack-api.js +167 -0
- package/dist/indexing/providers/slack-api.js.map +1 -0
- package/dist/indexing/providers/slack.d.ts +21 -0
- package/dist/indexing/providers/slack.d.ts.map +1 -0
- package/dist/indexing/providers/slack.js +192 -0
- package/dist/indexing/providers/slack.js.map +1 -0
- package/dist/indexing/providers/types.d.ts +56 -0
- package/dist/indexing/providers/types.d.ts.map +1 -0
- package/dist/indexing/providers/types.js +3 -0
- package/dist/indexing/providers/types.js.map +1 -0
- package/dist/indexing/url-derivation.d.ts +2 -2
- package/dist/indexing/url-derivation.d.ts.map +1 -1
- package/dist/indexing/url-derivation.js.map +1 -1
- package/dist/indexing/utils.d.ts +19 -0
- package/dist/indexing/utils.d.ts.map +1 -0
- package/dist/indexing/utils.js +63 -0
- package/dist/indexing/utils.js.map +1 -0
- package/dist/ip-limiter.d.ts +11 -0
- package/dist/ip-limiter.d.ts.map +1 -0
- package/dist/ip-limiter.js +40 -0
- package/dist/ip-limiter.js.map +1 -0
- package/dist/llms-txt.d.ts +11 -0
- package/dist/llms-txt.d.ts.map +1 -0
- package/dist/llms-txt.js +43 -0
- package/dist/llms-txt.js.map +1 -0
- package/dist/mcp/server.d.ts +3 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +9 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools/bash-fs.d.ts.map +1 -1
- package/dist/mcp/tools/bash-fs.js +4 -1
- package/dist/mcp/tools/bash-fs.js.map +1 -1
- package/dist/mcp/tools/bash.d.ts +8 -0
- package/dist/mcp/tools/bash.d.ts.map +1 -1
- package/dist/mcp/tools/bash.js +59 -0
- package/dist/mcp/tools/bash.js.map +1 -1
- package/dist/mcp/tools/knowledge.d.ts +13 -0
- package/dist/mcp/tools/knowledge.d.ts.map +1 -0
- package/dist/mcp/tools/knowledge.js +92 -0
- package/dist/mcp/tools/knowledge.js.map +1 -0
- package/dist/mcp/tools/search.d.ts.map +1 -1
- package/dist/mcp/tools/search.js +11 -3
- package/dist/mcp/tools/search.js.map +1 -1
- package/dist/server.d.ts +6 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +595 -0
- package/dist/server.js.map +1 -0
- package/dist/skill-md.d.ts +3 -0
- package/dist/skill-md.d.ts.map +1 -0
- package/dist/skill-md.js +75 -0
- package/dist/skill-md.js.map +1 -0
- package/dist/types.d.ts +844 -38
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +88 -6
- package/dist/types.js.map +1 -1
- package/dist/validate.d.ts +29 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +192 -0
- package/dist/validate.js.map +1 -0
- package/dist/webhooks/discord.d.ts +13 -0
- package/dist/webhooks/discord.d.ts.map +1 -0
- package/dist/webhooks/discord.js +57 -0
- package/dist/webhooks/discord.js.map +1 -0
- package/dist/webhooks/slack.d.ts +13 -0
- package/dist/webhooks/slack.d.ts.map +1 -0
- package/dist/webhooks/slack.js +106 -0
- package/dist/webhooks/slack.js.map +1 -0
- package/dist/workspace.d.ts +13 -0
- package/dist/workspace.d.ts.map +1 -0
- package/dist/workspace.js +118 -0
- package/dist/workspace.js.map +1 -0
- package/package.json +27 -2
- package/pathfinder-docs.yaml +54 -0
- package/pathfinder.example.yaml +48 -0
- package/.superpowers/brainstorm/47098-1775507869/content/homepage-mockup.html +0 -324
- package/.superpowers/brainstorm/47098-1775507869/state/server-stopped +0 -1
- package/.superpowers/brainstorm/47098-1775507869/state/server.log +0 -13
- package/.superpowers/brainstorm/47098-1775507869/state/server.pid +0 -1
- package/.superpowers/brainstorm/82141-1775511032/content/migration-v2.html +0 -340
- package/.superpowers/brainstorm/82141-1775511032/content/migration.html +0 -340
- package/.superpowers/brainstorm/82141-1775511032/state/server-stopped +0 -1
- package/.superpowers/brainstorm/82141-1775511032/state/server.log +0 -4
- package/.superpowers/brainstorm/82141-1775511032/state/server.pid +0 -1
- package/dist/indexing/source-indexer.d.ts +0 -68
- package/dist/indexing/source-indexer.d.ts.map +0 -1
- package/dist/indexing/source-indexer.js +0 -379
- package/dist/indexing/source-indexer.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,42 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @copilotkit/pathfinder
|
|
2
|
+
|
|
3
|
+
## 1.5.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- **Data Provider Abstraction**: Refactored SourceIndexer into DataProvider interface + IndexingPipeline, enabling API-based sources alongside file-based sources
|
|
8
|
+
- **Slack Data Provider**: Index Slack threads as searchable Q&A knowledge via LLM distillation (gpt-4o-mini). Configurable channels, confidence threshold, emoji-triggered reindexing
|
|
9
|
+
- **Discord Data Provider**: Index Discord text channels (LLM distillation) and forum channels (direct Q&A extraction at confidence 1.0). Forum posts are inherently Q&A-shaped — no LLM needed
|
|
10
|
+
- **FAQ Endpoint** (`/faq.txt`): Serves Q&A pairs from all FAQ-category sources, filtered by confidence at query time. Advertised via Link header
|
|
11
|
+
- **Knowledge MCP Tool**: New `knowledge` tool type with browse mode (full FAQ listing) and search mode (vector search scoped to FAQ sources)
|
|
12
|
+
- **`pathfinder validate` CLI Command**: Validates YAML config, checks env vars, probes source connectivity. Exit code 1 on errors
|
|
13
|
+
- **Q&A Chunker**: Renamed from slack-specific to source-agnostic, registered for both slack and discord source types
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- Fix bash filesystem empty after fresh deploy when DB already has current index state
|
|
18
|
+
- Fix pathfinder-docs Railway service missing deployment trigger
|
|
19
|
+
- Always refresh bash instances after startup index check completes
|
|
20
|
+
- Rename "Migrate" to "Switch" in docs nav (matches aimock)
|
|
21
|
+
- Update docs: config reference (Slack, Discord, Knowledge tool, jump links), usage (FAQ endpoint, validate command), deploy (new env vars), README
|
|
22
|
+
|
|
23
|
+
## 1.4.0
|
|
24
|
+
|
|
25
|
+
### Minor Changes
|
|
26
|
+
|
|
27
|
+
- Add HTML source type for indexing static HTML documentation sites (cheerio-based parser)
|
|
28
|
+
- Content container auto-detection (main, article, [role="main"], .content, #content)
|
|
29
|
+
- Heading-boundary chunking with headingPath tracking (h1-h3)
|
|
30
|
+
- Code block preservation, list formatting, table formatting in HTML extraction
|
|
31
|
+
- Add pathfinder-docs.yaml for dogfooding Pathfinder on its own documentation
|
|
32
|
+
|
|
33
|
+
### Patch Changes
|
|
34
|
+
|
|
35
|
+
- Generalize smoke test script for any Pathfinder instance
|
|
36
|
+
- Add mobile hamburger nav menu to all docs pages
|
|
37
|
+
- Simplify README to match aimock style, add npm metadata (repository, homepage, keywords)
|
|
38
|
+
- Fix Dockerfile to copy pathfinder.yaml for production deploy
|
|
39
|
+
- Fix schema migration: remove version index from generateSchema (was failing on existing databases)
|
|
2
40
|
|
|
3
41
|
## 1.1.0
|
|
4
42
|
|
package/README.md
CHANGED
|
@@ -1,284 +1,101 @@
|
|
|
1
|
-
#
|
|
1
|
+
# pathfinder [](https://www.npmjs.com/package/@copilotkit/pathfinder)
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## How It Works
|
|
6
|
-
|
|
7
|
-
Pathfinder indexes your GitHub repositories — documentation (Markdown/MDX) and source code — into a PostgreSQL vector database using OpenAI embeddings. It exposes configurable search tools via the [Model Context Protocol (MCP)](https://modelcontextprotocol.io), so AI agents like Claude Code can search your docs and code semantically.
|
|
3
|
+
Agentic docs retrieval for AI agents — semantic search and filesystem exploration over your documentation and code via MCP. One config file, one command, works with any AI coding agent.
|
|
8
4
|
|
|
9
5
|
## Quick Start
|
|
10
6
|
|
|
11
|
-
1. **Clone and configure:**
|
|
12
|
-
```bash
|
|
13
|
-
git clone https://github.com/CopilotKit/pathfinder.git
|
|
14
|
-
cd pathfinder
|
|
15
|
-
cp pathfinder.example.yaml pathfinder.yaml # edit for your project
|
|
16
|
-
cp .env.example .env # add your OPENAI_API_KEY
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
2. **Start the server:**
|
|
20
|
-
```bash
|
|
21
|
-
docker compose up
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
3. **Seed the index:**
|
|
25
|
-
```bash
|
|
26
|
-
docker compose exec app npx tsx scripts/seed-index.ts
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
4. **Connect your AI agent:**
|
|
30
|
-
```json
|
|
31
|
-
{
|
|
32
|
-
"mcpServers": {
|
|
33
|
-
"my-docs": { "url": "http://localhost:3001/mcp" }
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
## Configuration
|
|
39
|
-
|
|
40
|
-
All configuration lives in `pathfinder.yaml`. See [pathfinder.example.yaml](pathfinder.example.yaml) for a minimal starting point.
|
|
41
|
-
|
|
42
|
-
### Sources
|
|
43
|
-
|
|
44
|
-
Each source defines what to index:
|
|
45
|
-
|
|
46
|
-
```yaml
|
|
47
|
-
sources:
|
|
48
|
-
- name: docs
|
|
49
|
-
type: markdown # Built-in: markdown, code, raw-text
|
|
50
|
-
repo: https://github.com/your-org/your-repo.git
|
|
51
|
-
path: docs/
|
|
52
|
-
base_url: https://docs.your-project.com/
|
|
53
|
-
url_derivation:
|
|
54
|
-
strip_prefix: "docs/"
|
|
55
|
-
strip_suffix: ".md"
|
|
56
|
-
file_patterns: ["**/*.md"]
|
|
57
|
-
chunk:
|
|
58
|
-
target_tokens: 600
|
|
59
|
-
overlap_tokens: 50
|
|
60
|
-
|
|
61
|
-
- name: code
|
|
62
|
-
type: code
|
|
63
|
-
repo: https://github.com/your-org/your-repo.git
|
|
64
|
-
path: "."
|
|
65
|
-
file_patterns: ["**/*.ts", "**/*.py"]
|
|
66
|
-
exclude_patterns: ["**/test/**", "**/*.test.*"]
|
|
67
|
-
chunk:
|
|
68
|
-
target_lines: 80
|
|
69
|
-
overlap_lines: 10
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
### Tools
|
|
73
|
-
|
|
74
|
-
Each tool maps to a source and defines the MCP tool interface:
|
|
75
|
-
|
|
76
|
-
```yaml
|
|
77
|
-
tools:
|
|
78
|
-
- name: search-docs
|
|
79
|
-
description: "Search documentation for relevant information."
|
|
80
|
-
source: docs
|
|
81
|
-
default_limit: 5
|
|
82
|
-
max_limit: 20
|
|
83
|
-
result_format: docs
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
### Collect Tools
|
|
87
|
-
|
|
88
|
-
Collect tools let agents write structured data back to the server. Unlike search tools, they don't query anything — they validate the agent's input against a YAML-defined schema and store it as JSON in the database. Use them to gather signal from agents without writing any code.
|
|
89
|
-
|
|
90
|
-
The first built-in use case is search feedback: agents report whether search results were helpful, what they tried, and what went wrong. This surfaces broken or misleading documentation quickly. But collect tools are generic — you can define any schema for any use case (e.g., broken link reporting, feature requests, error logging).
|
|
91
|
-
|
|
92
|
-
```yaml
|
|
93
|
-
tools:
|
|
94
|
-
- name: submit-feedback
|
|
95
|
-
type: collect
|
|
96
|
-
description: "Submit feedback on whether search results were helpful."
|
|
97
|
-
response: "Feedback recorded. Thank you."
|
|
98
|
-
schema:
|
|
99
|
-
tool_name:
|
|
100
|
-
type: string
|
|
101
|
-
description: "Which search tool was used"
|
|
102
|
-
required: true
|
|
103
|
-
rating:
|
|
104
|
-
type: enum
|
|
105
|
-
values: ["helpful", "not_helpful"]
|
|
106
|
-
description: "Whether the results were helpful"
|
|
107
|
-
required: true
|
|
108
|
-
comment:
|
|
109
|
-
type: string
|
|
110
|
-
description: "What worked or didn't work"
|
|
111
|
-
required: true
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
Each field in `schema` supports `type` (`string`, `number`, or `enum`), an optional `description` (shown to the agent), `required` (defaults to false), and `values` (required for `enum` fields). The validated input is written as JSONB to the `collected_data` table along with the tool name and a timestamp.
|
|
115
|
-
|
|
116
|
-
### Bash Tool Options
|
|
117
|
-
|
|
118
|
-
Bash tools expose source files as a read-only virtual filesystem that agents can explore with standard commands (`find`, `grep`, `cat`, `ls`, `head`). Several options control behavior:
|
|
119
|
-
|
|
120
|
-
```yaml
|
|
121
|
-
tools:
|
|
122
|
-
- name: explore-docs
|
|
123
|
-
type: bash
|
|
124
|
-
description: "Explore documentation files"
|
|
125
|
-
sources: [docs]
|
|
126
|
-
bash:
|
|
127
|
-
session_state: true # Persistent CWD across commands (default: false)
|
|
128
|
-
grep_strategy: hybrid # memory | vector | hybrid — enables qmd semantic search (default: memory, no qmd)
|
|
129
|
-
virtual_files: true # Auto-generate INDEX.md, SEARCH_TIPS.md (default: false)
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
- **session_state**: When enabled, `cd` persists across commands within a session. Agents can run `cd /docs` in one tool call and then `ls` or `cat file.md` in the next without repeating the path.
|
|
133
|
-
- **grep_strategy**: Controls whether the `qmd` semantic search command is available. `memory` uses pure in-memory regex only (no `qmd`). `vector` or `hybrid` enable the `qmd` command, which performs semantic search via embeddings plus text `ILIKE`. The `vector` and `hybrid` modes require an `embedding` config block.
|
|
134
|
-
- **virtual_files**: Auto-generates `/INDEX.md` (file listing with descriptions) and `/SEARCH_TIPS.md` (usage guidance) at the root of the virtual filesystem.
|
|
135
|
-
|
|
136
|
-
Agents can also run the `related` command inside bash tools to find semantically similar files across all mounted sources:
|
|
137
|
-
|
|
138
7
|
```bash
|
|
139
|
-
|
|
8
|
+
npx @copilotkit/pathfinder init
|
|
9
|
+
npx @copilotkit/pathfinder serve
|
|
140
10
|
```
|
|
141
11
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
When `grep_strategy` is set to `vector` or `hybrid`, agents can use the `qmd` command for semantic search:
|
|
12
|
+
Or with Docker:
|
|
145
13
|
|
|
146
14
|
```bash
|
|
147
|
-
|
|
15
|
+
docker pull ghcr.io/copilotkit/pathfinder
|
|
16
|
+
docker run -v ./pathfinder.yaml:/app/pathfinder.yaml \
|
|
17
|
+
-v ./docs:/app/docs -p 3001:3001 \
|
|
18
|
+
ghcr.io/copilotkit/pathfinder
|
|
148
19
|
```
|
|
149
20
|
|
|
150
|
-
|
|
21
|
+
Then connect your AI agent:
|
|
151
22
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"mcpServers": {
|
|
26
|
+
"my-docs": { "url": "http://localhost:3001/mcp" }
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
```
|
|
155
30
|
|
|
156
|
-
|
|
157
|
-
|------|----------|-----------|
|
|
158
|
-
| `markdown` | .md, .mdx files | Headings (h2->h3->paragraph->line), preserves code blocks |
|
|
159
|
-
| `code` | Source code files | Blank line boundaries, respects block comments/strings |
|
|
160
|
-
| `raw-text` | Plain text, logs | Paragraph boundaries (double newline) |
|
|
31
|
+
## Try It — Pathfinder on Its Own Docs
|
|
161
32
|
|
|
162
|
-
|
|
33
|
+
This documentation is indexed by a live Pathfinder instance. Connect your agent to try it:
|
|
163
34
|
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
model: text-embedding-3-small
|
|
168
|
-
dimensions: 1536
|
|
35
|
+
```bash
|
|
36
|
+
# Claude Code
|
|
37
|
+
claude mcp add pathfinder-docs --transport http https://mcp.pathfinder.copilotkit.dev/mcp
|
|
169
38
|
```
|
|
170
39
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
40
|
+
```json
|
|
41
|
+
// Claude Desktop / Cursor / any MCP client
|
|
42
|
+
{
|
|
43
|
+
"mcpServers": {
|
|
44
|
+
"pathfinder-docs": {
|
|
45
|
+
"url": "https://mcp.pathfinder.copilotkit.dev/mcp"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
178
49
|
```
|
|
179
50
|
|
|
180
|
-
##
|
|
181
|
-
|
|
182
|
-
The simplest way to run in production:
|
|
183
|
-
|
|
184
|
-
1. **Configure:**
|
|
185
|
-
```bash
|
|
186
|
-
cp pathfinder.example.yaml pathfinder.yaml # edit for your project
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
2. **Set environment variables** in `.env`:
|
|
190
|
-
```
|
|
191
|
-
OPENAI_API_KEY=sk-...
|
|
192
|
-
POSTGRES_PASSWORD=your-secure-password
|
|
193
|
-
GITHUB_WEBHOOK_SECRET=your-webhook-secret
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
3. **Deploy:**
|
|
197
|
-
```bash
|
|
198
|
-
docker compose -f docker-compose.prod.yaml up -d
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
4. **Verify:**
|
|
202
|
-
```bash
|
|
203
|
-
curl http://localhost:3001/health | python3 -m json.tool
|
|
204
|
-
```
|
|
51
|
+
## What It Does
|
|
205
52
|
|
|
206
|
-
|
|
53
|
+
Pathfinder indexes your GitHub repos — docs (Markdown, MDX, HTML) and source code — into a PostgreSQL vector database using OpenAI embeddings. It serves configurable search and filesystem exploration tools via [MCP](https://modelcontextprotocol.io), so AI agents can search your docs semantically and browse files with bash commands.
|
|
207
54
|
|
|
208
|
-
|
|
55
|
+
| Tool Type | What It Does | Example |
|
|
56
|
+
|-----------|-------------|---------|
|
|
57
|
+
| **Search** | Semantic search over indexed content | `search-docs("how to authenticate")` |
|
|
58
|
+
| **Bash** | Virtual filesystem with find, grep, cat, ls | `explore-docs("cat /docs/quickstart.mdx")` |
|
|
59
|
+
| **Collect** | Structured data collection from agents | `submit-feedback(rating: "helpful")` |
|
|
60
|
+
| **Knowledge** | Browse/search FAQ pairs from conversational sources | `knowledge-base("how to deploy")` |
|
|
209
61
|
|
|
210
|
-
|
|
62
|
+
## Features
|
|
211
63
|
|
|
212
|
-
|
|
64
|
+
- **[Semantic Search](https://pathfinder.copilotkit.dev/search)** — pgvector RAG with configurable chunk sizes, overlap, and score thresholds
|
|
65
|
+
- **[Filesystem Exploration](https://pathfinder.copilotkit.dev/search)** — QuickJS WASM sandbox with session state, `qmd` semantic grep, `related` files
|
|
66
|
+
- **[6 Source Types](https://pathfinder.copilotkit.dev/config)** — Markdown, code, raw-text, HTML, Slack, Discord — with pluggable chunker registry
|
|
67
|
+
- **[Config-Driven](https://pathfinder.copilotkit.dev/config)** — Everything in one `pathfinder.yaml`: sources, tools, embedding, indexing, webhooks
|
|
68
|
+
- **[Client Setup](https://pathfinder.copilotkit.dev/clients)** — Claude Desktop, Claude Code, Cursor, Codex, VS Code, any Streamable HTTP client
|
|
69
|
+
- **[Docker + Railway](https://pathfinder.copilotkit.dev/deploy)** — Container image, docker-compose, Railway one-click
|
|
70
|
+
- **[Conversational Sources](https://pathfinder.copilotkit.dev/config)** — Slack threads and Discord forums distilled into searchable Q&A pairs
|
|
71
|
+
- **[Auto-Generated Endpoints](https://pathfinder.copilotkit.dev/usage)** — `/llms.txt`, `/llms-full.txt`, `/faq.txt`, `/.well-known/skills/default/skill.md`
|
|
72
|
+
- **[Webhook Reindexing](https://pathfinder.copilotkit.dev/deploy)** — GitHub push triggers incremental reindex
|
|
73
|
+
- **[IP Rate Limiting](https://pathfinder.copilotkit.dev/config)** — Per-IP session caps and configurable TTL
|
|
213
74
|
|
|
214
|
-
|
|
215
|
-
```yaml
|
|
216
|
-
webhook:
|
|
217
|
-
repo_sources:
|
|
218
|
-
"your-org/your-repo": [docs, code]
|
|
219
|
-
path_triggers:
|
|
220
|
-
docs: ["docs/"]
|
|
221
|
-
code: []
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
2. Configure the webhook on GitHub:
|
|
225
|
-
- URL: `https://your-server/webhooks/github`
|
|
226
|
-
- Secret: same as `GITHUB_WEBHOOK_SECRET`
|
|
227
|
-
- Events: Just `push`
|
|
228
|
-
|
|
229
|
-
## Deploying to Railway
|
|
230
|
-
|
|
231
|
-
1. **Run setup:**
|
|
232
|
-
```bash
|
|
233
|
-
./scripts/setup.sh # install deps, build Docker images
|
|
234
|
-
./scripts/deploy.sh # create Railway project, set vars, deploy
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
2. **Set custom domain** in Railway dashboard
|
|
238
|
-
|
|
239
|
-
3. **Configure webhooks:**
|
|
240
|
-
```bash
|
|
241
|
-
./scripts/setup-webhooks.sh
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
See [OPERATIONS.md](OPERATIONS.md) for the full operations runbook.
|
|
245
|
-
|
|
246
|
-
## Development
|
|
75
|
+
## CLI
|
|
247
76
|
|
|
248
77
|
```bash
|
|
249
|
-
#
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
# Start dev server (hot reload)
|
|
253
|
-
docker compose up
|
|
78
|
+
# Scaffold config
|
|
79
|
+
npx @copilotkit/pathfinder init
|
|
254
80
|
|
|
255
|
-
#
|
|
256
|
-
|
|
81
|
+
# Start server (uses PGlite if no DATABASE_URL)
|
|
82
|
+
npx @copilotkit/pathfinder serve
|
|
257
83
|
|
|
258
|
-
#
|
|
259
|
-
|
|
84
|
+
# Validate config, env vars, and source connectivity
|
|
85
|
+
npx @copilotkit/pathfinder validate
|
|
260
86
|
|
|
261
|
-
#
|
|
262
|
-
docker compose
|
|
87
|
+
# Docker with Postgres
|
|
88
|
+
docker compose up
|
|
89
|
+
```
|
|
263
90
|
|
|
264
|
-
|
|
265
|
-
npx tsx scripts/integration-test.ts
|
|
91
|
+
## Switching from Mintlify?
|
|
266
92
|
|
|
267
|
-
|
|
268
|
-
npx tsx scripts/test-path-filter.ts
|
|
269
|
-
```
|
|
93
|
+
Step-by-step migration guide: **[Migrate from Mintlify](https://pathfinder.copilotkit.dev/migrate-from-mintlify)**
|
|
270
94
|
|
|
271
|
-
##
|
|
95
|
+
## Documentation
|
|
272
96
|
|
|
273
|
-
|
|
274
|
-
|----------|----------|-------------|
|
|
275
|
-
| `OPENAI_API_KEY` | Yes | OpenAI API key for embeddings |
|
|
276
|
-
| `DATABASE_URL` | Yes | PostgreSQL connection string |
|
|
277
|
-
| `GITHUB_WEBHOOK_SECRET` | No | HMAC secret for webhook verification |
|
|
278
|
-
| `GITHUB_TOKEN` | No | GitHub token for private repos |
|
|
279
|
-
| `PATHFINDER_CONFIG` | No | Path to config file (default: `./pathfinder.yaml`) |
|
|
280
|
-
| `PORT` | No | Server port (default: `3001`) |
|
|
97
|
+
**[https://pathfinder.copilotkit.dev](https://pathfinder.copilotkit.dev)**
|
|
281
98
|
|
|
282
99
|
## License
|
|
283
100
|
|
|
284
|
-
MIT
|
|
101
|
+
MIT
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import fs from "fs";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import { fileURLToPath } from "url";
|
|
6
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
const program = new Command();
|
|
8
|
+
program
|
|
9
|
+
.name("pathfinder")
|
|
10
|
+
.description("Agentic docs retrieval for AI agents")
|
|
11
|
+
.version("1.5.0");
|
|
12
|
+
program
|
|
13
|
+
.command("init")
|
|
14
|
+
.description("Scaffold a new Pathfinder project in the current directory")
|
|
15
|
+
.action(async () => {
|
|
16
|
+
const cwd = process.cwd();
|
|
17
|
+
const yamlDest = path.join(cwd, "pathfinder.yaml");
|
|
18
|
+
if (fs.existsSync(yamlDest)) {
|
|
19
|
+
console.log("pathfinder.yaml already exists, skipping.");
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
const templatePath = path.join(__dirname, "..", "pathfinder.example.yaml");
|
|
23
|
+
if (!fs.existsSync(templatePath)) {
|
|
24
|
+
console.error("Could not find pathfinder.example.yaml template.");
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
fs.copyFileSync(templatePath, yamlDest);
|
|
28
|
+
console.log("Created pathfinder.yaml");
|
|
29
|
+
}
|
|
30
|
+
const envDest = path.join(cwd, ".env");
|
|
31
|
+
if (fs.existsSync(envDest)) {
|
|
32
|
+
console.log(".env already exists, skipping.");
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
const envTemplatePath = path.join(__dirname, "..", ".env.example");
|
|
36
|
+
if (fs.existsSync(envTemplatePath)) {
|
|
37
|
+
fs.copyFileSync(envTemplatePath, envDest);
|
|
38
|
+
console.log("Created .env from template");
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
console.log("No .env.example found, skipping .env creation.");
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
console.log("\nEdit pathfinder.yaml to configure your docs sources.");
|
|
45
|
+
console.log("Then run: pathfinder serve");
|
|
46
|
+
});
|
|
47
|
+
program
|
|
48
|
+
.command("serve")
|
|
49
|
+
.description("Start the Pathfinder MCP server")
|
|
50
|
+
.option("-p, --port <port>", "Port to listen on", parseInt)
|
|
51
|
+
.option("-c, --config <path>", "Path to pathfinder.yaml")
|
|
52
|
+
.action(async (opts) => {
|
|
53
|
+
const { startServer } = await import("./server.js");
|
|
54
|
+
await startServer({
|
|
55
|
+
port: opts.port,
|
|
56
|
+
configPath: opts.config,
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
program
|
|
60
|
+
.command('validate')
|
|
61
|
+
.description('Validate config and probe source connectivity')
|
|
62
|
+
.option('-c, --config <path>', 'Path to pathfinder.yaml')
|
|
63
|
+
.action(async (opts) => {
|
|
64
|
+
const { validateConfig, formatValidationResult } = await import('./validate.js');
|
|
65
|
+
const result = await validateConfig(opts.config);
|
|
66
|
+
console.log(formatValidationResult(result));
|
|
67
|
+
process.exit(result.errors.length > 0 ? 1 : 0);
|
|
68
|
+
});
|
|
69
|
+
program.parse();
|
|
70
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
CHANGED
|
@@ -9,11 +9,19 @@ export interface Config {
|
|
|
9
9
|
nodeEnv: string;
|
|
10
10
|
logLevel: string;
|
|
11
11
|
cloneDir: string;
|
|
12
|
+
slackBotToken: string;
|
|
13
|
+
slackSigningSecret: string;
|
|
14
|
+
discordBotToken: string;
|
|
15
|
+
discordPublicKey: string;
|
|
12
16
|
}
|
|
13
17
|
/**
|
|
14
18
|
* Check whether any search tools are configured (requires embeddings + indexing).
|
|
15
19
|
*/
|
|
16
20
|
export declare function hasSearchTools(): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Check whether any knowledge tools are configured (requires embeddings + indexing).
|
|
23
|
+
*/
|
|
24
|
+
export declare function hasKnowledgeTools(): boolean;
|
|
17
25
|
/**
|
|
18
26
|
* Check whether any collect tools are configured (requires database).
|
|
19
27
|
*/
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,OAAO,eAAe,CAAC;AAIvB,OAAO,EAAsB,KAAK,YAAY,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,OAAO,eAAe,CAAC;AAIvB,OAAO,EAAsB,KAAK,YAAY,EAAyB,MAAM,YAAY,CAAC;AAI1F,MAAM,WAAW,MAAM;IACnB,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;CAC5B;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAExC;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,OAAO,CAK/C;AAED;;GAEG;AACH,wBAAgB,uBAAuB,IAAI,GAAG,CAAC,MAAM,CAAC,CAKrD;AA8DD,wBAAgB,SAAS,IAAI,MAAM,CAKlC;AAED,eAAO,MAAM,MAAM,QAIjB,CAAC;AAwJH,wBAAgB,eAAe,IAAI,YAAY,CAK9C"}
|
package/dist/config.js
CHANGED
|
@@ -3,13 +3,19 @@ import 'dotenv/config';
|
|
|
3
3
|
import { readFileSync, existsSync } from 'node:fs';
|
|
4
4
|
import { resolve } from 'node:path';
|
|
5
5
|
import { parse as parseYaml } from 'yaml';
|
|
6
|
-
import { ServerConfigSchema } from './types.js';
|
|
6
|
+
import { ServerConfigSchema, isDiscordSourceConfig } from './types.js';
|
|
7
7
|
/**
|
|
8
8
|
* Check whether any search tools are configured (requires embeddings + indexing).
|
|
9
9
|
*/
|
|
10
10
|
export function hasSearchTools() {
|
|
11
11
|
return getServerConfig().tools.some(t => t.type === 'search');
|
|
12
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* Check whether any knowledge tools are configured (requires embeddings + indexing).
|
|
15
|
+
*/
|
|
16
|
+
export function hasKnowledgeTools() {
|
|
17
|
+
return getServerConfig().tools.some(t => t.type === 'knowledge');
|
|
18
|
+
}
|
|
13
19
|
/**
|
|
14
20
|
* Check whether any collect tools are configured (requires database).
|
|
15
21
|
*/
|
|
@@ -27,13 +33,15 @@ export function hasBashSemanticSearch() {
|
|
|
27
33
|
* Get the set of source names that need indexing (only those referenced by search tools).
|
|
28
34
|
*/
|
|
29
35
|
export function getIndexableSourceNames() {
|
|
30
|
-
const
|
|
31
|
-
|
|
36
|
+
const cfg = getServerConfig();
|
|
37
|
+
const searchSources = cfg.tools.filter(t => t.type === 'search').map(t => t.source);
|
|
38
|
+
const knowledgeSources = cfg.tools.filter(t => t.type === 'knowledge').flatMap(t => t.sources);
|
|
39
|
+
return new Set([...searchSources, ...knowledgeSources]);
|
|
32
40
|
}
|
|
33
41
|
let cachedConfig = null;
|
|
34
42
|
function parseConfig() {
|
|
35
43
|
const missing = [];
|
|
36
|
-
const needsRag = hasSearchTools();
|
|
44
|
+
const needsRag = hasSearchTools() || hasKnowledgeTools();
|
|
37
45
|
const needsDb = needsRag || hasCollectTools() || hasBashSemanticSearch();
|
|
38
46
|
const databaseUrl = process.env.DATABASE_URL;
|
|
39
47
|
if (!databaseUrl && needsDb)
|
|
@@ -42,6 +50,25 @@ function parseConfig() {
|
|
|
42
50
|
if (!openaiApiKey && needsRag)
|
|
43
51
|
missing.push('OPENAI_API_KEY');
|
|
44
52
|
const githubWebhookSecret = process.env.GITHUB_WEBHOOK_SECRET ?? '';
|
|
53
|
+
// Slack credentials — required when any slack source is configured
|
|
54
|
+
const hasSlackSource = getServerConfig().sources.some(s => s.type === 'slack');
|
|
55
|
+
const slackBotToken = process.env.SLACK_BOT_TOKEN ?? '';
|
|
56
|
+
const slackSigningSecret = process.env.SLACK_SIGNING_SECRET ?? '';
|
|
57
|
+
if (hasSlackSource && !slackBotToken)
|
|
58
|
+
missing.push('SLACK_BOT_TOKEN');
|
|
59
|
+
if (hasSlackSource && !openaiApiKey)
|
|
60
|
+
missing.push('OPENAI_API_KEY (required for Slack distillation)');
|
|
61
|
+
// Discord credentials — required when any discord source is configured
|
|
62
|
+
const hasDiscordSource = getServerConfig().sources.some(s => s.type === 'discord');
|
|
63
|
+
const hasDiscordTextChannels = getServerConfig().sources.some(s => isDiscordSourceConfig(s) && s.channels.some(c => c.type === 'text'));
|
|
64
|
+
const discordBotToken = process.env.DISCORD_BOT_TOKEN ?? '';
|
|
65
|
+
const discordPublicKey = process.env.DISCORD_PUBLIC_KEY ?? '';
|
|
66
|
+
if (hasDiscordSource && !discordBotToken)
|
|
67
|
+
missing.push('DISCORD_BOT_TOKEN');
|
|
68
|
+
if (hasDiscordSource && !discordPublicKey)
|
|
69
|
+
missing.push('DISCORD_PUBLIC_KEY');
|
|
70
|
+
if (hasDiscordTextChannels && !openaiApiKey)
|
|
71
|
+
missing.push('OPENAI_API_KEY (required for Discord text channel distillation)');
|
|
45
72
|
if (missing.length > 0) {
|
|
46
73
|
throw new Error(`Missing required environment variables: ${missing.join(', ')}. ` +
|
|
47
74
|
`Set them before starting the server.`);
|
|
@@ -59,6 +86,10 @@ function parseConfig() {
|
|
|
59
86
|
nodeEnv: process.env.NODE_ENV || 'development',
|
|
60
87
|
logLevel: process.env.LOG_LEVEL || 'info',
|
|
61
88
|
cloneDir: process.env.CLONE_DIR || '/tmp/mcp-repos',
|
|
89
|
+
slackBotToken,
|
|
90
|
+
slackSigningSecret,
|
|
91
|
+
discordBotToken,
|
|
92
|
+
discordPublicKey,
|
|
62
93
|
};
|
|
63
94
|
}
|
|
64
95
|
export function getConfig() {
|
|
@@ -144,6 +175,15 @@ function loadServerConfig() {
|
|
|
144
175
|
throw new Error(`Tool "${tool.name}" references source "${tool.source}" which is not defined in sources.`);
|
|
145
176
|
}
|
|
146
177
|
}
|
|
178
|
+
// Cross-validate: every knowledge tool's sources must reference existing source names
|
|
179
|
+
const knowledgeTools = result.data.tools.filter(t => t.type === 'knowledge');
|
|
180
|
+
for (const tool of knowledgeTools) {
|
|
181
|
+
for (const src of tool.sources) {
|
|
182
|
+
if (!sourceNames.has(src)) {
|
|
183
|
+
throw new Error(`Knowledge tool "${tool.name}" references source "${src}" which is not defined in sources.`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
147
187
|
// Cross-validate: webhook repo_sources and path_triggers must reference valid source names
|
|
148
188
|
if (result.data.webhook) {
|
|
149
189
|
const wh = result.data.webhook;
|
|
@@ -160,8 +200,21 @@ function loadServerConfig() {
|
|
|
160
200
|
}
|
|
161
201
|
}
|
|
162
202
|
}
|
|
163
|
-
//
|
|
203
|
+
// Warn if knowledge tools reference non-FAQ sources
|
|
204
|
+
for (const tool of result.data.tools) {
|
|
205
|
+
if (tool.type === 'knowledge') {
|
|
206
|
+
for (const srcName of tool.sources) {
|
|
207
|
+
const src = result.data.sources.find(s => s.name === srcName);
|
|
208
|
+
if (src && (!('category' in src) || src.category !== 'faq')) {
|
|
209
|
+
console.warn(`[config] Knowledge tool "${tool.name}" references source "${srcName}" which does not have category: "faq" — queries may return empty results`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
// Validate local source paths exist (file-based sources only)
|
|
164
215
|
for (const source of result.data.sources) {
|
|
216
|
+
if (source.type === 'slack' || source.type === 'discord')
|
|
217
|
+
continue;
|
|
165
218
|
if (!source.repo) {
|
|
166
219
|
const resolved = resolve(source.path);
|
|
167
220
|
if (!existsSync(resolved)) {
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,mEAAmE;AAEnE,OAAO,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAqB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,mEAAmE;AAEnE,OAAO,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAqB,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAmB1F;;GAEG;AACH,MAAM,UAAU,cAAc;IAC1B,OAAO,eAAe,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;AAClE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB;IAC7B,OAAO,eAAe,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC;AACrE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe;IAC3B,OAAO,eAAe,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;AACnE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB;IACjC,OAAO,eAAe,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CACpC,CAAC,CAAC,IAAI,KAAK,MAAM;QACjB,CAAC,CAAC,CAAC,IAAI,EAAE,aAAa,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,EAAE,aAAa,KAAK,QAAQ,CAAC,CAC7E,CAAC;AACN,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,uBAAuB;IACnC,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;IAC9B,MAAM,aAAa,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IACpF,MAAM,gBAAgB,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IAC/F,OAAO,IAAI,GAAG,CAAC,CAAC,GAAG,aAAa,EAAE,GAAG,gBAAgB,CAAC,CAAC,CAAC;AAC5D,CAAC;AAED,IAAI,YAAY,GAAkB,IAAI,CAAC;AAEvC,SAAS,WAAW;IAChB,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,MAAM,QAAQ,GAAG,cAAc,EAAE,IAAI,iBAAiB,EAAE,CAAC;IACzD,MAAM,OAAO,GAAG,QAAQ,IAAI,eAAe,EAAE,IAAI,qBAAqB,EAAE,CAAC;IAEzE,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;IAC7C,IAAI,CAAC,WAAW,IAAI,OAAO;QAAE,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAE1D,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAChD,IAAI,CAAC,YAAY,IAAI,QAAQ;QAAE,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IAE9D,MAAM,mBAAmB,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,EAAE,CAAC;IAEpE,mEAAmE;IACnE,MAAM,cAAc,GAAG,eAAe,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC;IAC/E,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,EAAE,CAAC;IACxD,MAAM,kBAAkB,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,EAAE,CAAC;IAClE,IAAI,cAAc,IAAI,CAAC,aAAa;QAAE,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IACtE,IAAI,cAAc,IAAI,CAAC,YAAY;QAAE,OAAO,CAAC,IAAI,CAAC,kDAAkD,CAAC,CAAC;IAEtG,uEAAuE;IACvE,MAAM,gBAAgB,GAAG,eAAe,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;IACnF,MAAM,sBAAsB,GAAG,eAAe,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,qBAAqB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC;IACxI,MAAM,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,EAAE,CAAC;IAC5D,MAAM,gBAAgB,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,EAAE,CAAC;IAC9D,IAAI,gBAAgB,IAAI,CAAC,eAAe;QAAE,OAAO,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAC5E,IAAI,gBAAgB,IAAI,CAAC,gBAAgB;QAAE,OAAO,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IAC9E,IAAI,sBAAsB,IAAI,CAAC,YAAY;QAAE,OAAO,CAAC,IAAI,CAAC,iEAAiE,CAAC,CAAC;IAE7H,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CACX,2CAA2C,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;YACjE,sCAAsC,CACzC,CAAC;IACN,CAAC;IAED,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,MAAM,EAAE,EAAE,CAAC,CAAC;IACtD,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,KAAK,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,uBAAuB,OAAO,CAAC,GAAG,CAAC,IAAI,yCAAyC,CAAC,CAAC;IACtG,CAAC;IAED,OAAO;QACH,WAAW;QACX,YAAY,EAAE,YAAY,IAAI,EAAE;QAChC,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE;QAC3C,mBAAmB,EAAE,mBAAoB;QACzC,IAAI;QACJ,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,aAAa;QAC9C,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,MAAM;QACzC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,gBAAgB;QACnD,aAAa;QACb,kBAAkB;QAClB,eAAe;QACf,gBAAgB;KACnB,CAAC;AACN,CAAC;AAED,MAAM,UAAU,SAAS;IACrB,IAAI,CAAC,YAAY,EAAE,CAAC;QAChB,YAAY,GAAG,WAAW,EAAE,CAAC;IACjC,CAAC;IACD,OAAO,YAAY,CAAC;AACxB,CAAC;AAED,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,KAAK,CAAC,EAAY,EAAE;IAC1C,GAAG,CAAC,OAAO,EAAE,IAAY;QACrB,OAAO,SAAS,EAAE,CAAC,IAAoB,CAAC,CAAC;IAC7C,CAAC;CACJ,CAAC,CAAC;AAEH,iFAAiF;AAEjF,IAAI,kBAAkB,GAAwB,IAAI,CAAC;AAEnD,SAAS,iBAAiB;IACtB,kBAAkB;IAClB,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IACpD,IAAI,aAAa,EAAE,CAAC;QAChB,MAAM,QAAQ,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;QACxC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,+BAA+B,QAAQ,2BAA2B,CAAC,CAAC;QACxF,CAAC;QACD,OAAO,QAAQ,CAAC;IACpB,CAAC;IAED,qBAAqB;IACrB,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IAC/C,IAAI,UAAU,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CAAC,yEAAyE,CAAC,CAAC;QACxF,MAAM,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;QACrC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,6BAA6B,QAAQ,2BAA2B,CAAC,CAAC;QACtF,CAAC;QACD,OAAO,QAAQ,CAAC;IACpB,CAAC;IAED,sBAAsB;IACtB,MAAM,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,iBAAiB,CAAC,CAAC;IACjE,IAAI,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;QAC7B,OAAO,cAAc,CAAC;IAC1B,CAAC;IAED,yBAAyB;IACzB,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,eAAe,CAAC,CAAC;IAC5D,IAAI,WAAW,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QACzC,OAAO,CAAC,IAAI,CAAC,mEAAmE,CAAC,CAAC;QAClF,OAAO,WAAW,CAAC;IACvB,CAAC;IAED,MAAM,IAAI,KAAK,CACX,4GAA4G,CAC/G,CAAC;AACN,CAAC;AAED,SAAS,gBAAgB;IACrB,MAAM,UAAU,GAAG,iBAAiB,EAAE,CAAC;IACvC,MAAM,GAAG,GAAG,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAE9B,4DAA4D;IAC5D,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC;QAC/B,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YAC9B,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,IAAI,IAAI,CAAC,EAAE,CAAC;gBACxD,OAAO,CAAC,IAAI,CAAC,kBAAkB,IAAI,CAAC,IAAI,sGAAsG,CAAC,CAAC;gBAChJ,IAAI,CAAC,IAAI,GAAG,QAAQ,CAAC;YACzB,CAAC;QACL,CAAC;IACL,CAAC;IAED,MAAM,MAAM,GAAG,kBAAkB,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACpD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QAClB,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM;aAC7B,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC;aACjD,IAAI,CAAC,IAAI,CAAC,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,qBAAqB,UAAU,MAAM,MAAM,EAAE,CAAC,CAAC;IACnE,CAAC;IAED,kCAAkC;IAClC,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAClE,IAAI,WAAW,CAAC,IAAI,KAAK,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;QAClD,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;IAC9E,CAAC;IAED,gCAAgC;IAChC,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9D,IAAI,SAAS,CAAC,IAAI,KAAK,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IAC1E,CAAC;IAED,oFAAoF;IACpF,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;IACvE,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC7B,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CACX,SAAS,IAAI,CAAC,IAAI,wBAAwB,IAAI,CAAC,MAAM,oCAAoC,CAC5F,CAAC;QACN,CAAC;IACL,CAAC;IAED,sFAAsF;IACtF,MAAM,cAAc,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC;IAC7E,KAAK,MAAM,IAAI,IAAI,cAAc,EAAE,CAAC;QAChC,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAC7B,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBACxB,MAAM,IAAI,KAAK,CACX,mBAAmB,IAAI,CAAC,IAAI,wBAAwB,GAAG,oCAAoC,CAC9F,CAAC;YACN,CAAC;QACL,CAAC;IACL,CAAC;IAED,2FAA2F;IAC3F,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QACtB,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC;QAC/B,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC;YAC5D,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;gBACxB,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;oBACxB,MAAM,IAAI,KAAK,CACX,yBAAyB,IAAI,yBAAyB,GAAG,oCAAoC,CAChG,CAAC;gBACN,CAAC;YACL,CAAC;QACL,CAAC;QACD,KAAK,MAAM,UAAU,IAAI,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,EAAE,CAAC;YACrD,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC/B,MAAM,IAAI,KAAK,CACX,8BAA8B,UAAU,2CAA2C,CACtF,CAAC;YACN,CAAC;QACL,CAAC;IACL,CAAC;IAED,oDAAoD;IACpD,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QACnC,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YAC5B,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBACjC,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC;gBAC9D,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,UAAU,IAAI,GAAG,CAAC,IAAI,GAAG,CAAC,QAAQ,KAAK,KAAK,CAAC,EAAE,CAAC;oBAC1D,OAAO,CAAC,IAAI,CAAC,4BAA4B,IAAI,CAAC,IAAI,wBAAwB,OAAO,0EAA0E,CAAC,CAAC;gBACjK,CAAC;YACL,CAAC;QACL,CAAC;IACL,CAAC;IAED,8DAA8D;IAC9D,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QACvC,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS;YAAE,SAAS;QACnE,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YACf,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACtC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACxB,MAAM,IAAI,KAAK,CACX,WAAW,MAAM,CAAC,IAAI,4BAA4B,MAAM,CAAC,IAAI,kBAAkB,QAAQ,yBAAyB,CACnH,CAAC;YACN,CAAC;QACL,CAAC;IACL,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,eAAe;IAC3B,IAAI,CAAC,kBAAkB,EAAE,CAAC;QACtB,kBAAkB,GAAG,gBAAgB,EAAE,CAAC;IAC5C,CAAC;IACD,OAAO,kBAAkB,CAAC;AAC9B,CAAC"}
|