markdown-lsp 0.1.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/LICENSE +21 -0
- package/README.md +104 -0
- package/bin/markdown-lsp +2 -0
- package/dist/ai/config.d.ts +9 -0
- package/dist/ai/config.d.ts.map +1 -0
- package/dist/ai/config.js +19 -0
- package/dist/ai/config.js.map +1 -0
- package/dist/ai/embeddings.d.ts +7 -0
- package/dist/ai/embeddings.d.ts.map +1 -0
- package/dist/ai/embeddings.js +27 -0
- package/dist/ai/embeddings.js.map +1 -0
- package/dist/ai/extract.d.ts +58 -0
- package/dist/ai/extract.d.ts.map +1 -0
- package/dist/ai/extract.js +58 -0
- package/dist/ai/extract.js.map +1 -0
- package/dist/ai/gateway.d.ts +5 -0
- package/dist/ai/gateway.d.ts.map +1 -0
- package/dist/ai/gateway.js +18 -0
- package/dist/ai/gateway.js.map +1 -0
- package/dist/bridge/inMemoryGraph.d.ts +32 -0
- package/dist/bridge/inMemoryGraph.d.ts.map +1 -0
- package/dist/bridge/inMemoryGraph.js +94 -0
- package/dist/bridge/inMemoryGraph.js.map +1 -0
- package/dist/core/documentSymbols.d.ts +33 -0
- package/dist/core/documentSymbols.d.ts.map +1 -0
- package/dist/core/documentSymbols.js +113 -0
- package/dist/core/documentSymbols.js.map +1 -0
- package/dist/core/findReferences.d.ts +38 -0
- package/dist/core/findReferences.d.ts.map +1 -0
- package/dist/core/findReferences.js +59 -0
- package/dist/core/findReferences.js.map +1 -0
- package/dist/core/index.d.ts +3 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +3 -0
- package/dist/core/index.js.map +1 -0
- package/dist/db/client.d.ts +6 -0
- package/dist/db/client.d.ts.map +1 -0
- package/dist/db/client.js +22 -0
- package/dist/db/client.js.map +1 -0
- package/dist/db/schema.d.ts +812 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +118 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/indexer/indexer.d.ts +24 -0
- package/dist/indexer/indexer.d.ts.map +1 -0
- package/dist/indexer/indexer.js +248 -0
- package/dist/indexer/indexer.js.map +1 -0
- package/dist/indexer/parseMarkdown.d.ts +30 -0
- package/dist/indexer/parseMarkdown.d.ts.map +1 -0
- package/dist/indexer/parseMarkdown.js +191 -0
- package/dist/indexer/parseMarkdown.js.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +343 -0
- package/dist/server.js.map +1 -0
- package/package.json +82 -0
- package/src/db/migrations/0000_init.sql +94 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Dan Bondarev
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# @docsbook/markdown-lsp
|
|
2
|
+
|
|
3
|
+
Language Server Protocol implementation for Markdown documentation. Optional AI-powered semantic layer on top.
|
|
4
|
+
|
|
5
|
+
**Status: M1 complete, M2 (AI layer) opt-in.**
|
|
6
|
+
|
|
7
|
+
## Two layers
|
|
8
|
+
|
|
9
|
+
### Structural (default, no AI)
|
|
10
|
+
|
|
11
|
+
Out of the box — like Marksman, but persisted in Postgres and addressable from a service.
|
|
12
|
+
|
|
13
|
+
- `textDocument/documentSymbol` — heading outline
|
|
14
|
+
- `workspace/symbol` — fuzzy subsequence search across all headings (e.g. `oaf` matches `OAuth flow`)
|
|
15
|
+
- `textDocument/definition` — jump from a link to its target document
|
|
16
|
+
- `textDocument/references` — find every page linking to the current document
|
|
17
|
+
- `textDocument/completion` — wiki-link completion `[[...]]`
|
|
18
|
+
- `textDocument/publishDiagnostics` — warnings for unresolved link targets
|
|
19
|
+
- `workspace.executeCommand("markdownLsp/reindex")` — force re-index of the workspace
|
|
20
|
+
- Incremental indexing via content-hash diff; watched-files cleanup
|
|
21
|
+
|
|
22
|
+
This layer is fully deterministic, free, and runs offline against your Postgres.
|
|
23
|
+
|
|
24
|
+
### Semantic (optional, AI-powered)
|
|
25
|
+
|
|
26
|
+
Off by default. When enabled, an extract pass identifies canonical concepts per section so that
|
|
27
|
+
references survive synonym variation (`auth` ≡ `authentication` ≡ `OAuth` ≡ `login`).
|
|
28
|
+
|
|
29
|
+
Enable with:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
export MARKDOWN_LSP_AI_ENABLED=1
|
|
33
|
+
export AI_GATEWAY_API_KEY=... # Vercel AI Gateway
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
If the flag is not set, no AI calls are ever made. The server starts and behaves as a
|
|
37
|
+
pure-structural LSP — no key required.
|
|
38
|
+
|
|
39
|
+
## Architecture
|
|
40
|
+
|
|
41
|
+
- LSP over stdio (`vscode-languageserver/node`) — works in any editor
|
|
42
|
+
- pgvector (Neon serverless) for cosine search on canonical-term embeddings (only when AI layer is enabled)
|
|
43
|
+
- Drizzle ORM; all tables prefixed `mdlsp_`
|
|
44
|
+
- Vercel AI Gateway (`text-embedding-3-small` for embeddings, `gpt-4o-mini` for extraction) — when AI on
|
|
45
|
+
- An optional MCP HTTP facade (M3) over the same handlers — for AI agents like Claude Code
|
|
46
|
+
|
|
47
|
+
## Setup
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pnpm install
|
|
51
|
+
cp .env.example .env.local # fill DATABASE_URL; AI_GATEWAY_API_KEY only if you want the AI layer
|
|
52
|
+
pnpm migrate # runs scripts/apply-migration.ts against DATABASE_URL
|
|
53
|
+
pnpm build
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Run
|
|
57
|
+
|
|
58
|
+
LSP via stdio (for editor integration):
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
node dist/server.js --stdio
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
`bin/markdown-lsp` wraps the same entry point as a CLI.
|
|
65
|
+
|
|
66
|
+
## Use from Docsbook
|
|
67
|
+
|
|
68
|
+
The structural layer is what Docsbook's "Source of Truth" feature wants. Wire it in like this:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
import { ensureWorkspace, indexWorkspace } from "@docsbook/markdown-lsp/indexer"
|
|
72
|
+
import { getDocumentSymbols, getWorkspaceSymbols } from "@docsbook/markdown-lsp/core"
|
|
73
|
+
|
|
74
|
+
// after cloning a workspace repo into ./tmp/<workspace-id>/
|
|
75
|
+
const ws = await ensureWorkspace("./tmp/42")
|
|
76
|
+
await indexWorkspace(ws)
|
|
77
|
+
|
|
78
|
+
// MCP tools then call:
|
|
79
|
+
await getWorkspaceSymbols(ws, "auth")
|
|
80
|
+
await findReferencesToDocument(ws, authDocId)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
No AI required.
|
|
84
|
+
|
|
85
|
+
## Tests
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
pnpm test
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
27 tests cover the parser, indexer, and core handlers (plus a small suite for the AI feature flag).
|
|
92
|
+
|
|
93
|
+
## Milestones
|
|
94
|
+
|
|
95
|
+
- **M0 — Scaffold** ✅
|
|
96
|
+
- **M1 — Structural layer** ✅
|
|
97
|
+
- M2 — Semantic extract (opt-in, code present, awaiting live AI Gateway credit)
|
|
98
|
+
- M3 — MCP HTTP facade
|
|
99
|
+
- M4 — User overrides for the glossary (merge / split / rename / add_synonym)
|
|
100
|
+
- M5 — Docsbook integration
|
|
101
|
+
|
|
102
|
+
## License
|
|
103
|
+
|
|
104
|
+
MIT
|
package/bin/markdown-lsp
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface AiConfig {
|
|
2
|
+
enabled: boolean;
|
|
3
|
+
embeddingModel: string;
|
|
4
|
+
extractModel: string;
|
|
5
|
+
hasGatewayKey: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare function getAiConfig(): AiConfig;
|
|
8
|
+
export declare function assertAiEnabled(): void;
|
|
9
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/ai/config.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,OAAO,CAAA;IAChB,cAAc,EAAE,MAAM,CAAA;IACtB,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,EAAE,OAAO,CAAA;CACvB;AAED,wBAAgB,WAAW,IAAI,QAAQ,CAQtC;AAED,wBAAgB,eAAe,IAAI,IAAI,CAYtC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export function getAiConfig() {
|
|
2
|
+
const enabled = process.env.MARKDOWN_LSP_AI_ENABLED === "1" || process.env.MARKDOWN_LSP_AI_ENABLED === "true";
|
|
3
|
+
return {
|
|
4
|
+
enabled,
|
|
5
|
+
embeddingModel: process.env.EMBEDDING_MODEL ?? "text-embedding-3-small",
|
|
6
|
+
extractModel: process.env.EXTRACT_MODEL ?? "gpt-4o-mini",
|
|
7
|
+
hasGatewayKey: Boolean(process.env.AI_GATEWAY_API_KEY),
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export function assertAiEnabled() {
|
|
11
|
+
const cfg = getAiConfig();
|
|
12
|
+
if (!cfg.enabled) {
|
|
13
|
+
throw new Error("AI features are disabled. Set MARKDOWN_LSP_AI_ENABLED=1 to enable embeddings + semantic extraction.");
|
|
14
|
+
}
|
|
15
|
+
if (!cfg.hasGatewayKey) {
|
|
16
|
+
throw new Error("AI features require AI_GATEWAY_API_KEY (Vercel AI Gateway) — or fork the gateway module to use a different provider.");
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/ai/config.ts"],"names":[],"mappings":"AAOA,MAAM,UAAU,WAAW;IACzB,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,uBAAuB,KAAK,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,uBAAuB,KAAK,MAAM,CAAA;IAC7G,OAAO;QACL,OAAO;QACP,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,wBAAwB;QACvE,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,aAAa;QACxD,aAAa,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;KACvD,CAAA;AACH,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,MAAM,GAAG,GAAG,WAAW,EAAE,CAAA;IACzB,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CACb,qGAAqG,CACtG,CAAA;IACH,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CACb,sHAAsH,CACvH,CAAA;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface EmbeddingResult {
|
|
2
|
+
vectors: number[][];
|
|
3
|
+
tokensUsed: number;
|
|
4
|
+
}
|
|
5
|
+
export declare function embedTexts(texts: string[]): Promise<EmbeddingResult>;
|
|
6
|
+
export declare function embedOne(text: string): Promise<number[]>;
|
|
7
|
+
//# sourceMappingURL=embeddings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embeddings.d.ts","sourceRoot":"","sources":["../../src/ai/embeddings.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,EAAE,EAAE,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,wBAAsB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,CAAC,CAiB1E;AAED,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAG9D"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { embedMany } from "ai";
|
|
2
|
+
import { getGateway, EMBEDDING_MODEL } from "./gateway.js";
|
|
3
|
+
import { assertAiEnabled } from "./config.js";
|
|
4
|
+
const BATCH_SIZE = 96;
|
|
5
|
+
const MAX_INPUT_CHARS = 6000;
|
|
6
|
+
export async function embedTexts(texts) {
|
|
7
|
+
if (texts.length === 0)
|
|
8
|
+
return { vectors: [], tokensUsed: 0 };
|
|
9
|
+
assertAiEnabled();
|
|
10
|
+
const gw = getGateway();
|
|
11
|
+
const model = gw.embedding(EMBEDDING_MODEL);
|
|
12
|
+
const out = [];
|
|
13
|
+
let tokensUsed = 0;
|
|
14
|
+
for (let i = 0; i < texts.length; i += BATCH_SIZE) {
|
|
15
|
+
const batch = texts.slice(i, i + BATCH_SIZE).map((t) => t.slice(0, MAX_INPUT_CHARS));
|
|
16
|
+
const res = await embedMany({ model, values: batch });
|
|
17
|
+
for (const v of res.embeddings)
|
|
18
|
+
out.push(v);
|
|
19
|
+
tokensUsed += res.usage?.tokens ?? 0;
|
|
20
|
+
}
|
|
21
|
+
return { vectors: out, tokensUsed };
|
|
22
|
+
}
|
|
23
|
+
export async function embedOne(text) {
|
|
24
|
+
const { vectors } = await embedTexts([text]);
|
|
25
|
+
return vectors[0];
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=embeddings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embeddings.js","sourceRoot":"","sources":["../../src/ai/embeddings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,IAAI,CAAA;AAC9B,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAE7C,MAAM,UAAU,GAAG,EAAE,CAAA;AACrB,MAAM,eAAe,GAAG,IAAI,CAAA;AAO5B,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,KAAe;IAC9C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,CAAA;IAC7D,eAAe,EAAE,CAAA;IACjB,MAAM,EAAE,GAAG,UAAU,EAAE,CAAA;IACvB,MAAM,KAAK,GAAG,EAAE,CAAC,SAAS,CAAC,eAAe,CAAC,CAAA;IAE3C,MAAM,GAAG,GAAe,EAAE,CAAA;IAC1B,IAAI,UAAU,GAAG,CAAC,CAAA;IAElB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,UAAU,EAAE,CAAC;QAClD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC,CAAA;QACpF,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAA;QACrD,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,UAAU;YAAE,GAAG,CAAC,IAAI,CAAC,CAAa,CAAC,CAAA;QACvD,UAAU,IAAI,GAAG,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC,CAAA;IACtC,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,CAAA;AACrC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,IAAY;IACzC,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;IAC5C,OAAO,OAAO,CAAC,CAAC,CAAE,CAAA;AACpB,CAAC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const ExtractedTermSchema: z.ZodObject<{
|
|
3
|
+
surface: z.ZodString;
|
|
4
|
+
canonical: z.ZodString;
|
|
5
|
+
kind: z.ZodEnum<["definition", "mention", "example"]>;
|
|
6
|
+
}, "strip", z.ZodTypeAny, {
|
|
7
|
+
kind: "definition" | "mention" | "example";
|
|
8
|
+
surface: string;
|
|
9
|
+
canonical: string;
|
|
10
|
+
}, {
|
|
11
|
+
kind: "definition" | "mention" | "example";
|
|
12
|
+
surface: string;
|
|
13
|
+
canonical: string;
|
|
14
|
+
}>;
|
|
15
|
+
export declare const SectionExtractionSchema: z.ZodObject<{
|
|
16
|
+
terms: z.ZodArray<z.ZodObject<{
|
|
17
|
+
surface: z.ZodString;
|
|
18
|
+
canonical: z.ZodString;
|
|
19
|
+
kind: z.ZodEnum<["definition", "mention", "example"]>;
|
|
20
|
+
}, "strip", z.ZodTypeAny, {
|
|
21
|
+
kind: "definition" | "mention" | "example";
|
|
22
|
+
surface: string;
|
|
23
|
+
canonical: string;
|
|
24
|
+
}, {
|
|
25
|
+
kind: "definition" | "mention" | "example";
|
|
26
|
+
surface: string;
|
|
27
|
+
canonical: string;
|
|
28
|
+
}>, "many">;
|
|
29
|
+
summary: z.ZodNullable<z.ZodString>;
|
|
30
|
+
}, "strip", z.ZodTypeAny, {
|
|
31
|
+
terms: {
|
|
32
|
+
kind: "definition" | "mention" | "example";
|
|
33
|
+
surface: string;
|
|
34
|
+
canonical: string;
|
|
35
|
+
}[];
|
|
36
|
+
summary: string | null;
|
|
37
|
+
}, {
|
|
38
|
+
terms: {
|
|
39
|
+
kind: "definition" | "mention" | "example";
|
|
40
|
+
surface: string;
|
|
41
|
+
canonical: string;
|
|
42
|
+
}[];
|
|
43
|
+
summary: string | null;
|
|
44
|
+
}>;
|
|
45
|
+
export type ExtractedTerm = z.infer<typeof ExtractedTermSchema>;
|
|
46
|
+
export type SectionExtraction = z.infer<typeof SectionExtractionSchema>;
|
|
47
|
+
export interface ExtractInput {
|
|
48
|
+
documentPath: string;
|
|
49
|
+
headingPath: string[];
|
|
50
|
+
content: string;
|
|
51
|
+
existingCanonicals?: string[];
|
|
52
|
+
}
|
|
53
|
+
export interface ExtractResult extends SectionExtraction {
|
|
54
|
+
tokensIn: number;
|
|
55
|
+
tokensOut: number;
|
|
56
|
+
}
|
|
57
|
+
export declare function extractSectionTerms(input: ExtractInput): Promise<ExtractResult>;
|
|
58
|
+
//# sourceMappingURL=extract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../../src/ai/extract.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,eAAO,MAAM,mBAAmB;;;;;;;;;;;;EAM9B,CAAA;AAEF,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGlC,CAAA;AAEF,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAA;AAC/D,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAA;AAEvE,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,OAAO,EAAE,MAAM,CAAA;IACf,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAA;CAC9B;AAED,MAAM,WAAW,aAAc,SAAQ,iBAAiB;IACtD,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;CAClB;AAgBD,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,CAiCrF"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { generateObject } from "ai";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { getGateway, EXTRACT_MODEL } from "./gateway.js";
|
|
4
|
+
import { assertAiEnabled } from "./config.js";
|
|
5
|
+
export const ExtractedTermSchema = z.object({
|
|
6
|
+
surface: z.string().describe("The exact term as it appears in text"),
|
|
7
|
+
canonical: z.string().describe("Normalized kebab-case canonical id (lowercase, no spaces)"),
|
|
8
|
+
kind: z.enum(["definition", "mention", "example"]).describe("'definition' when the section explains the term; 'mention' when the term is used in passing; 'example' inside an example/code block"),
|
|
9
|
+
});
|
|
10
|
+
export const SectionExtractionSchema = z.object({
|
|
11
|
+
terms: z.array(ExtractedTermSchema),
|
|
12
|
+
summary: z.string().nullable().describe("One-sentence summary of the section; null if section is trivial"),
|
|
13
|
+
});
|
|
14
|
+
const SYSTEM_PROMPT = `You extract canonical concepts from technical documentation sections.
|
|
15
|
+
|
|
16
|
+
For each meaningful term in the section, return:
|
|
17
|
+
- surface: the exact word/phrase as written
|
|
18
|
+
- canonical: a normalized kebab-case id (e.g. "oauth", "authentication", "session-storage")
|
|
19
|
+
- kind: "definition" if the section defines/explains the concept; "mention" if used in passing; "example" if shown inside an example or code block
|
|
20
|
+
|
|
21
|
+
Rules:
|
|
22
|
+
- Extract concepts, not generic words ("user", "page", "function" are too generic)
|
|
23
|
+
- Multiple surface forms of the same concept must share the same canonical id (auth/authentication/log-in → "authentication")
|
|
24
|
+
- Prefer an existing canonical id from the provided list when applicable
|
|
25
|
+
- Stay focused: 0-12 terms per section, only what a docs reader would search for
|
|
26
|
+
- The summary must be one sentence, present tense, no marketing fluff. Return null if the section is just a heading or trivial.`;
|
|
27
|
+
export async function extractSectionTerms(input) {
|
|
28
|
+
assertAiEnabled();
|
|
29
|
+
const gw = getGateway();
|
|
30
|
+
const model = gw(EXTRACT_MODEL);
|
|
31
|
+
const userPrompt = [
|
|
32
|
+
`Document: ${input.documentPath}`,
|
|
33
|
+
`Heading path: ${input.headingPath.join(" > ") || "(root)"}`,
|
|
34
|
+
input.existingCanonicals?.length
|
|
35
|
+
? `Existing canonicals in this workspace (reuse when applicable): ${input.existingCanonicals.slice(0, 100).join(", ")}`
|
|
36
|
+
: "",
|
|
37
|
+
"",
|
|
38
|
+
"Section content:",
|
|
39
|
+
"---",
|
|
40
|
+
input.content.slice(0, 8000),
|
|
41
|
+
"---",
|
|
42
|
+
]
|
|
43
|
+
.filter(Boolean)
|
|
44
|
+
.join("\n");
|
|
45
|
+
const res = await generateObject({
|
|
46
|
+
model,
|
|
47
|
+
schema: SectionExtractionSchema,
|
|
48
|
+
system: SYSTEM_PROMPT,
|
|
49
|
+
prompt: userPrompt,
|
|
50
|
+
temperature: 0,
|
|
51
|
+
});
|
|
52
|
+
return {
|
|
53
|
+
...res.object,
|
|
54
|
+
tokensIn: res.usage?.inputTokens ?? 0,
|
|
55
|
+
tokensOut: res.usage?.outputTokens ?? 0,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=extract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract.js","sourceRoot":"","sources":["../../src/ai/extract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,IAAI,CAAA;AACnC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAE7C,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sCAAsC,CAAC;IACpE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2DAA2D,CAAC;IAC3F,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,QAAQ,CACzD,qIAAqI,CACtI;CACF,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,mBAAmB,CAAC;IACnC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,iEAAiE,CAAC;CAC3G,CAAC,CAAA;AAiBF,MAAM,aAAa,GAAG;;;;;;;;;;;;gIAY0G,CAAA;AAEhI,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,KAAmB;IAC3D,eAAe,EAAE,CAAA;IACjB,MAAM,EAAE,GAAG,UAAU,EAAE,CAAA;IACvB,MAAM,KAAK,GAAG,EAAE,CAAC,aAAa,CAAC,CAAA;IAE/B,MAAM,UAAU,GAAG;QACjB,aAAa,KAAK,CAAC,YAAY,EAAE;QACjC,iBAAiB,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,QAAQ,EAAE;QAC5D,KAAK,CAAC,kBAAkB,EAAE,MAAM;YAC9B,CAAC,CAAC,kEAAkE,KAAK,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;YACvH,CAAC,CAAC,EAAE;QACN,EAAE;QACF,kBAAkB;QAClB,KAAK;QACL,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC;QAC5B,KAAK;KACN;SACE,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,IAAI,CAAC,CAAA;IAEb,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC;QAC/B,KAAK;QACL,MAAM,EAAE,uBAAuB;QAC/B,MAAM,EAAE,aAAa;QACrB,MAAM,EAAE,UAAU;QAClB,WAAW,EAAE,CAAC;KACf,CAAC,CAAA;IAEF,OAAO;QACL,GAAG,GAAG,CAAC,MAAM;QACb,QAAQ,EAAE,GAAG,CAAC,KAAK,EAAE,WAAW,IAAI,CAAC;QACrC,SAAS,EAAE,GAAG,CAAC,KAAK,EAAE,YAAY,IAAI,CAAC;KACxC,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gateway.d.ts","sourceRoot":"","sources":["../../src/ai/gateway.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,eAAe,QAA0D,CAAA;AACtF,eAAO,MAAM,aAAa,OAAO,CAAA;AACjC,eAAO,MAAM,aAAa,QAA6C,CAAA;AAIvE,wBAAgB,UAAU,4CASzB"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { createOpenAI } from "@ai-sdk/openai";
|
|
2
|
+
export const EMBEDDING_MODEL = process.env.EMBEDDING_MODEL ?? "text-embedding-3-small";
|
|
3
|
+
export const EMBEDDING_DIM = 1536;
|
|
4
|
+
export const EXTRACT_MODEL = process.env.EXTRACT_MODEL ?? "gpt-4o-mini";
|
|
5
|
+
let _gw = null;
|
|
6
|
+
export function getGateway() {
|
|
7
|
+
if (_gw)
|
|
8
|
+
return _gw;
|
|
9
|
+
const apiKey = process.env.AI_GATEWAY_API_KEY;
|
|
10
|
+
if (!apiKey)
|
|
11
|
+
throw new Error("AI_GATEWAY_API_KEY is not set");
|
|
12
|
+
_gw = createOpenAI({
|
|
13
|
+
apiKey,
|
|
14
|
+
baseURL: process.env.AI_GATEWAY_BASE_URL ?? "https://ai-gateway.vercel.sh/v1",
|
|
15
|
+
});
|
|
16
|
+
return _gw;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=gateway.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gateway.js","sourceRoot":"","sources":["../../src/ai/gateway.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAE7C,MAAM,CAAC,MAAM,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,wBAAwB,CAAA;AACtF,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,CAAA;AACjC,MAAM,CAAC,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,aAAa,CAAA;AAEvE,IAAI,GAAG,GAA2C,IAAI,CAAA;AAEtD,MAAM,UAAU,UAAU;IACxB,IAAI,GAAG;QAAE,OAAO,GAAG,CAAA;IACnB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAA;IAC7C,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAA;IAC7D,GAAG,GAAG,YAAY,CAAC;QACjB,MAAM;QACN,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,iCAAiC;KAC9E,CAAC,CAAA;IACF,OAAO,GAAG,CAAA;AACZ,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type ParsedLink } from "../indexer/parseMarkdown.js";
|
|
2
|
+
export interface InMemoryFile {
|
|
3
|
+
path: string;
|
|
4
|
+
content: string;
|
|
5
|
+
}
|
|
6
|
+
export interface GraphPage {
|
|
7
|
+
path: string;
|
|
8
|
+
title: string | null;
|
|
9
|
+
sections: Array<{
|
|
10
|
+
headingPath: string[];
|
|
11
|
+
anchor: string | null;
|
|
12
|
+
level: number;
|
|
13
|
+
charCount: number;
|
|
14
|
+
positionStartLine: number;
|
|
15
|
+
positionEndLine: number;
|
|
16
|
+
}>;
|
|
17
|
+
}
|
|
18
|
+
export interface GraphLink {
|
|
19
|
+
fromPath: string;
|
|
20
|
+
toPath: string;
|
|
21
|
+
toResolvedPath: string | null;
|
|
22
|
+
toAnchor: string | null;
|
|
23
|
+
kind: ParsedLink["kind"];
|
|
24
|
+
textAtLink: string | null;
|
|
25
|
+
}
|
|
26
|
+
export interface InMemoryGraph {
|
|
27
|
+
pages: GraphPage[];
|
|
28
|
+
links: GraphLink[];
|
|
29
|
+
unresolved: GraphLink[];
|
|
30
|
+
}
|
|
31
|
+
export declare function buildInMemoryGraph(files: InMemoryFile[]): InMemoryGraph;
|
|
32
|
+
//# sourceMappingURL=inMemoryGraph.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inMemoryGraph.d.ts","sourceRoot":"","sources":["../../src/bridge/inMemoryGraph.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqC,KAAK,UAAU,EAAE,MAAM,6BAA6B,CAAA;AAEhG,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,QAAQ,EAAE,KAAK,CAAC;QACd,WAAW,EAAE,MAAM,EAAE,CAAA;QACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;QACrB,KAAK,EAAE,MAAM,CAAA;QACb,SAAS,EAAE,MAAM,CAAA;QACjB,iBAAiB,EAAE,MAAM,CAAA;QACzB,eAAe,EAAE,MAAM,CAAA;KACxB,CAAC,CAAA;CACH;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,CAAA;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CAC1B;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,SAAS,EAAE,CAAA;IAClB,KAAK,EAAE,SAAS,EAAE,CAAA;IAClB,UAAU,EAAE,SAAS,EAAE,CAAA;CACxB;AA0BD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,aAAa,CAqEvE"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { parseMarkdown } from "../indexer/parseMarkdown.js";
|
|
2
|
+
function slugify(text) {
|
|
3
|
+
return text
|
|
4
|
+
.toLowerCase()
|
|
5
|
+
.trim()
|
|
6
|
+
.replace(/[^\w\s-]/g, "")
|
|
7
|
+
.replace(/\s+/g, "-");
|
|
8
|
+
}
|
|
9
|
+
function normalizePath(p) {
|
|
10
|
+
return p.replace(/\.(md|mdx|markdown)$/i, "").replace(/^\.?\//, "");
|
|
11
|
+
}
|
|
12
|
+
function joinPath(baseDir, rel) {
|
|
13
|
+
if (!baseDir)
|
|
14
|
+
return rel;
|
|
15
|
+
if (rel.startsWith("/"))
|
|
16
|
+
return rel.slice(1);
|
|
17
|
+
const parts = baseDir.split("/").filter(Boolean);
|
|
18
|
+
for (const segment of rel.split("/")) {
|
|
19
|
+
if (segment === "." || segment === "")
|
|
20
|
+
continue;
|
|
21
|
+
if (segment === "..")
|
|
22
|
+
parts.pop();
|
|
23
|
+
else
|
|
24
|
+
parts.push(segment);
|
|
25
|
+
}
|
|
26
|
+
return parts.join("/");
|
|
27
|
+
}
|
|
28
|
+
export function buildInMemoryGraph(files) {
|
|
29
|
+
const pages = [];
|
|
30
|
+
const allLinks = [];
|
|
31
|
+
const pathLookup = new Map();
|
|
32
|
+
const baseNameLookup = new Map();
|
|
33
|
+
const titleSlugLookup = new Map();
|
|
34
|
+
const parsedByPath = new Map();
|
|
35
|
+
for (const f of files) {
|
|
36
|
+
const parsed = parseMarkdown(f.content);
|
|
37
|
+
parsedByPath.set(f.path, parsed);
|
|
38
|
+
const norm = normalizePath(f.path);
|
|
39
|
+
pathLookup.set(norm, f.path);
|
|
40
|
+
pathLookup.set(f.path, f.path);
|
|
41
|
+
const baseName = (norm.split("/").pop() ?? norm).toLowerCase();
|
|
42
|
+
baseNameLookup.set(baseName, f.path);
|
|
43
|
+
if (parsed.title)
|
|
44
|
+
titleSlugLookup.set(slugify(parsed.title), f.path);
|
|
45
|
+
}
|
|
46
|
+
for (const f of files) {
|
|
47
|
+
const parsed = parsedByPath.get(f.path);
|
|
48
|
+
pages.push({
|
|
49
|
+
path: f.path,
|
|
50
|
+
title: parsed.title,
|
|
51
|
+
sections: parsed.sections.map((s) => ({
|
|
52
|
+
headingPath: s.headingPath,
|
|
53
|
+
anchor: s.anchor,
|
|
54
|
+
level: s.level,
|
|
55
|
+
charCount: s.charCount,
|
|
56
|
+
positionStartLine: s.positionStartLine,
|
|
57
|
+
positionEndLine: s.positionEndLine,
|
|
58
|
+
})),
|
|
59
|
+
});
|
|
60
|
+
for (const l of parsed.links) {
|
|
61
|
+
let toResolved = null;
|
|
62
|
+
if (l.kind === "wiki") {
|
|
63
|
+
toResolved =
|
|
64
|
+
baseNameLookup.get(l.toPath.toLowerCase()) ??
|
|
65
|
+
titleSlugLookup.get(slugify(l.toPath)) ??
|
|
66
|
+
pathLookup.get(normalizePath(l.toPath)) ??
|
|
67
|
+
null;
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
const fromDir = f.path.includes("/") ? f.path.slice(0, f.path.lastIndexOf("/")) : "";
|
|
71
|
+
const joined = joinPath(fromDir, l.toPath);
|
|
72
|
+
const candidates = [l.toPath, l.toPath.replace(/^\.\//, ""), joined];
|
|
73
|
+
for (const c of candidates) {
|
|
74
|
+
const norm = normalizePath(c);
|
|
75
|
+
toResolved = pathLookup.get(norm) ?? pathLookup.get(c) ?? null;
|
|
76
|
+
if (toResolved)
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const link = {
|
|
81
|
+
fromPath: f.path,
|
|
82
|
+
toPath: l.toPath,
|
|
83
|
+
toResolvedPath: toResolved,
|
|
84
|
+
toAnchor: l.toAnchor,
|
|
85
|
+
kind: l.kind,
|
|
86
|
+
textAtLink: l.textAtLink,
|
|
87
|
+
};
|
|
88
|
+
allLinks.push(link);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const unresolved = allLinks.filter((l) => l.toResolvedPath === null);
|
|
92
|
+
return { pages, links: allLinks, unresolved };
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=inMemoryGraph.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inMemoryGraph.js","sourceRoot":"","sources":["../../src/bridge/inMemoryGraph.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { WorkspaceRef } from "../indexer/indexer.js";
|
|
2
|
+
export interface SymbolNode {
|
|
3
|
+
name: string;
|
|
4
|
+
level: number;
|
|
5
|
+
anchor: string | null;
|
|
6
|
+
range: {
|
|
7
|
+
startLine: number;
|
|
8
|
+
startCol: number;
|
|
9
|
+
endLine: number;
|
|
10
|
+
endCol: number;
|
|
11
|
+
};
|
|
12
|
+
selectionRange: {
|
|
13
|
+
startLine: number;
|
|
14
|
+
startCol: number;
|
|
15
|
+
endLine: number;
|
|
16
|
+
endCol: number;
|
|
17
|
+
};
|
|
18
|
+
children: SymbolNode[];
|
|
19
|
+
}
|
|
20
|
+
export declare function getDocumentSymbols(workspace: WorkspaceRef, relPath: string): Promise<SymbolNode[]>;
|
|
21
|
+
export interface WorkspaceSymbol {
|
|
22
|
+
name: string;
|
|
23
|
+
containerName: string | null;
|
|
24
|
+
documentPath: string;
|
|
25
|
+
range: {
|
|
26
|
+
startLine: number;
|
|
27
|
+
startCol: number;
|
|
28
|
+
endLine: number;
|
|
29
|
+
endCol: number;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export declare function getWorkspaceSymbols(workspace: WorkspaceRef, query: string, limit?: number): Promise<WorkspaceSymbol[]>;
|
|
33
|
+
//# sourceMappingURL=documentSymbols.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"documentSymbols.d.ts","sourceRoot":"","sources":["../../src/core/documentSymbols.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAEzD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,KAAK,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IAC/E,cAAc,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IACxF,QAAQ,EAAE,UAAU,EAAE,CAAA;CACvB;AAED,wBAAsB,kBAAkB,CAAC,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CA8CxG;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,YAAY,EAAE,MAAM,CAAA;IACpB,KAAK,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CAChF;AAaD,wBAAsB,mBAAmB,CAAC,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,SAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CA+CzH"}
|