pcl-mcp 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.
Files changed (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +122 -0
  3. package/dist/bin/pcl.d.ts +3 -0
  4. package/dist/bin/pcl.d.ts.map +1 -0
  5. package/dist/bin/pcl.js +327 -0
  6. package/dist/bin/pcl.js.map +1 -0
  7. package/dist/src/db.d.ts +38 -0
  8. package/dist/src/db.d.ts.map +1 -0
  9. package/dist/src/db.js +238 -0
  10. package/dist/src/db.js.map +1 -0
  11. package/dist/src/embeddings.d.ts +15 -0
  12. package/dist/src/embeddings.d.ts.map +1 -0
  13. package/dist/src/embeddings.js +82 -0
  14. package/dist/src/embeddings.js.map +1 -0
  15. package/dist/src/indexer.d.ts +19 -0
  16. package/dist/src/indexer.d.ts.map +1 -0
  17. package/dist/src/indexer.js +174 -0
  18. package/dist/src/indexer.js.map +1 -0
  19. package/dist/src/scanner.d.ts +30 -0
  20. package/dist/src/scanner.d.ts.map +1 -0
  21. package/dist/src/scanner.js +290 -0
  22. package/dist/src/scanner.js.map +1 -0
  23. package/dist/src/schemas.d.ts +184 -0
  24. package/dist/src/schemas.d.ts.map +1 -0
  25. package/dist/src/schemas.js +113 -0
  26. package/dist/src/schemas.js.map +1 -0
  27. package/dist/src/search.d.ts +10 -0
  28. package/dist/src/search.d.ts.map +1 -0
  29. package/dist/src/search.js +99 -0
  30. package/dist/src/search.js.map +1 -0
  31. package/dist/src/server.d.ts +3 -0
  32. package/dist/src/server.d.ts.map +1 -0
  33. package/dist/src/server.js +156 -0
  34. package/dist/src/server.js.map +1 -0
  35. package/dist/src/tools.d.ts +111 -0
  36. package/dist/src/tools.d.ts.map +1 -0
  37. package/dist/src/tools.js +190 -0
  38. package/dist/src/tools.js.map +1 -0
  39. package/dist/src/types.d.ts +31 -0
  40. package/dist/src/types.d.ts.map +1 -0
  41. package/dist/src/types.js +3 -0
  42. package/dist/src/types.js.map +1 -0
  43. package/package.json +56 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Michael Sathya Gorski
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,122 @@
1
+ # PCL — Product Context Layer
2
+
3
+ **Give AI coding agents persistent, structured knowledge of your product.**
4
+
5
+ Instead of re-explaining your personas, journeys, and architecture decisions every session, PCL serves them via MCP on demand. Any agent (Claude Code, Cursor, Windsurf) queries exactly what it needs, when it needs it.
6
+
7
+ ## Stack
8
+
9
+ | Layer | Technology | Why |
10
+ |---|---|---|
11
+ | Protocol | MCP (stdio) | Universal — works with every major agent |
12
+ | Storage | SQLite + FTS5 | Zero infra, git-friendly, offline |
13
+ | Keyword search | BM25 via FTS5 | Best-in-class for exact term matching |
14
+ | Semantic search | `all-MiniLM-L6-v2` (local) | 23MB, zero API cost, ~3ms/doc |
15
+ | Hybrid fusion | Reciprocal Rank Fusion (k=60) | Better than either alone, no tuning |
16
+ | Validation | Zod schemas | Agents rely on predictable frontmatter |
17
+ | File watching | Chokidar v4 | Live reindex on save |
18
+
19
+ ## Install
20
+
21
+ ```bash
22
+ npm install pcl-mcp
23
+ npx pcl init # scaffold /product folder
24
+ npm run serve # start MCP server
25
+ ```
26
+
27
+ ## Agent configuration
28
+
29
+ ### Claude Code — `.claude/mcp.json`
30
+ ```json
31
+ {
32
+ "mcpServers": {
33
+ "pcl": {
34
+ "command": "node",
35
+ "args": ["./node_modules/pcl-mcp/dist/src/server.js"]
36
+ }
37
+ }
38
+ }
39
+ ```
40
+
41
+ ### Cursor — `settings.json`
42
+ ```json
43
+ "mcp.servers": {
44
+ "pcl": {
45
+ "command": "npx",
46
+ "args": ["pcl-mcp", "serve"]
47
+ }
48
+ }
49
+ ```
50
+
51
+ ## File structure
52
+
53
+ ```
54
+ /product
55
+ product.md ← north star doc (required)
56
+ personas/
57
+ 001-max.md ← one persona per file
58
+ journeys/
59
+ 001-onboarding.md ← one user journey per file
60
+ specs/
61
+ 001-auth-flow.md ← feature specs with acceptance criteria
62
+ decisions/
63
+ 001-use-nextjs.md ← architecture decision records (ADRs)
64
+ domain/
65
+ core-rules.md ← business rules agents must never violate
66
+ .pcl.db ← SQLite index (auto-generated, gitignore this)
67
+ ```
68
+
69
+ ## Tools available to agents
70
+
71
+ | Tool | When to use |
72
+ |---|---|
73
+ | `pcl_product_summary` | Always — call at session start |
74
+ | `pcl_get_domain("*critical")` | Always — load hard business rules |
75
+ | `pcl_get_persona(id)` | Before any user-facing feature |
76
+ | `pcl_get_journey(id)` | Before any user flow code |
77
+ | `pcl_get_spec(id)` | Before implementing a feature |
78
+ | `pcl_get_decision(id)` | Before architectural decisions |
79
+ | `pcl_list(type)` | Discover what exists |
80
+ | `pcl_search(query)` | When you don't know the ID |
81
+ | `pcl_related(id)` | Discover connected context |
82
+
83
+ ## How hybrid search works
84
+
85
+ ```
86
+ query: "what does Max find frustrating about onboarding"
87
+
88
+ BM25 (FTS5): [persona-max, journey-onboarding, spec-magic-link, ...]
89
+ ↓ ranked by term frequency + IDF
90
+
91
+ Cosine similarity: [journey-onboarding, persona-max, domain-core-rules, ...]
92
+ ↓ ranked by embedding dot product (MiniLM-L6-v2)
93
+
94
+ RRF fusion: score(d) = Σ 1 / (60 + rank(d))
95
+ ↓ combines both rankings without weight tuning
96
+
97
+ Result: 1. journey-onboarding (0.94)
98
+ 2. persona-max (0.87)
99
+ 3. spec-onboarding-ux (0.71)
100
+ ```
101
+
102
+ ## Human workflow
103
+
104
+ The system is only as good as what you put in. Discipline:
105
+
106
+ - **Product decision made?** → Write a `decisions/` ADR (5 min)
107
+ - **New feature being planned?** → Write a `specs/` file first, then code
108
+ - **User research or feedback?** → Update persona `anti_patterns` or `jobs_to_be_done`
109
+ - **Business rule change?** → Update `domain/` first, then code
110
+ - **New user journey discovered?** → Add to `journeys/`
111
+
112
+ The agent does the rest.
113
+
114
+ ## Gitignore
115
+
116
+ ```gitignore
117
+ product/.pcl.db # SQLite index — auto-regenerated
118
+ ```
119
+
120
+ ## License
121
+
122
+ MIT
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=pcl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pcl.d.ts","sourceRoot":"","sources":["../../bin/pcl.ts"],"names":[],"mappings":""}
@@ -0,0 +1,327 @@
1
+ #!/usr/bin/env node
2
+ // bin/pcl.ts
3
+ // CLI: pcl init | pcl serve | pcl status
4
+ import { mkdir, writeFile, access } from "node:fs/promises";
5
+ import { join, resolve } from "node:path";
6
+ import { constants } from "node:fs";
7
+ const cmd = process.argv[2];
8
+ const args = process.argv.slice(3);
9
+ const hasFlag = (flag) => args.includes(flag);
10
+ // ─── Templates ────────────────────────────────────────────────────────────────
11
+ const TEMPLATES = {
12
+ "product.md": `---
13
+ name: "My Product"
14
+ tagline: "One-line description of what it does"
15
+ problem: "The problem this product solves"
16
+ solution: "How it solves that problem"
17
+ primary_persona: "change-this-to-your-persona-id"
18
+ tech_stack:
19
+ - Next.js
20
+ - Supabase
21
+ - TypeScript
22
+ stage: prototype
23
+ repo: ""
24
+ url: ""
25
+ ---
26
+
27
+ ## Vision
28
+
29
+ Write your product vision here. What does success look like in 3 years?
30
+
31
+ ## North star metric
32
+
33
+ The one number that proves this product is working.
34
+
35
+ ## What this product is NOT
36
+
37
+ (Helps agents avoid scope creep — be explicit about what you're not building)
38
+ `,
39
+ "personas/001-example.md": `---
40
+ id: example-user
41
+ name: "Alex"
42
+ role: "Freelance designer"
43
+ age_range: "25-35"
44
+ tech_level: medium
45
+ primary_goal: "Ship client projects faster without sacrificing quality"
46
+ biggest_fear: "Losing a client because a project ran over time or budget"
47
+ jobs_to_be_done:
48
+ - Track project time without friction
49
+ - Communicate progress to clients proactively
50
+ - Avoid scope creep
51
+ anti_patterns:
52
+ - Won't fill out forms longer than 2 minutes
53
+ - Ignores marketing emails, responds to Slack/WhatsApp
54
+ - Doesn't read documentation, prefers watching a 60-second demo
55
+ channels:
56
+ - Twitter/X
57
+ - Dribbble
58
+ - Designer Slack communities
59
+ ---
60
+
61
+ ## Context
62
+
63
+ Write 2-3 sentences about Alex's day-to-day life. What does their work look like?
64
+ What tools do they already use? What's the emotional context behind their problem?
65
+
66
+ ## Design implications
67
+
68
+ Write specific rules the agent must follow when building anything for this persona:
69
+ - Maximum X steps to complete core action
70
+ - Must work on mobile
71
+ - etc.
72
+ `,
73
+ "journeys/001-onboarding.md": `---
74
+ id: onboarding
75
+ name: "First-time onboarding"
76
+ persona: example-user
77
+ trigger: "User clicks 'Get started free' on landing page"
78
+ success_state: "User completes their first core action within 10 minutes of signup"
79
+ failure_modes:
80
+ - "Drops off at email verification step"
81
+ - "Completes signup but never reaches core feature"
82
+ - "Starts core feature but abandons before saving"
83
+ steps:
84
+ - landing
85
+ - signup
86
+ - verify-email
87
+ - first-action
88
+ - aha-moment
89
+ ---
90
+
91
+ ## Step detail
92
+
93
+ ### landing
94
+ Goal: Communicate value prop in under 10 seconds.
95
+ Critical: Show social proof above the fold.
96
+ Do not: Ask for credit card on landing page.
97
+
98
+ ### signup
99
+ Email + password or magic link only.
100
+ Do NOT ask for name, company, or phone at this step — capture later.
101
+
102
+ ### verify-email
103
+ Keep this step as frictionless as possible.
104
+ Provide a "resend" link immediately visible.
105
+ Auto-redirect on verification — don't make user click a button.
106
+
107
+ ### first-action
108
+ This is where users must reach immediately after signup.
109
+ Pre-fill as much as possible from their signup email/domain.
110
+ Show a progress indicator: "Step 1 of 3".
111
+
112
+ ### aha-moment
113
+ Define what the "aha moment" is for your product.
114
+ Everything before this step is setup — this is where retention begins.
115
+ `,
116
+ "specs/001-example-feature.md": `---
117
+ id: magic-link-auth
118
+ title: "Magic link authentication"
119
+ persona: example-user
120
+ journey: onboarding
121
+ status: draft
122
+ acceptance_criteria:
123
+ - "User enters email and receives a link within 30 seconds"
124
+ - "Link expires after 15 minutes"
125
+ - "Link works only once (single-use token)"
126
+ - "After clicking, user is redirected to /dashboard"
127
+ - "If link is expired, user sees a clear error with a 'Request new link' button"
128
+ out_of_scope:
129
+ - "Social login (OAuth) — deferred to v2"
130
+ - "SMS-based verification"
131
+ design_ref: ""
132
+ ---
133
+
134
+ ## Overview
135
+
136
+ Write a short description of the feature from the user's perspective.
137
+
138
+ ## Technical notes
139
+
140
+ Any implementation constraints the agent needs to know:
141
+ - Which library to use
142
+ - Which existing patterns to follow
143
+ - Security requirements
144
+
145
+ ## Edge cases
146
+
147
+ List edge cases that are NOT covered by acceptance criteria above.
148
+ `,
149
+ "decisions/001-example-adr.md": `---
150
+ id: adr-001
151
+ title: "Use Next.js App Router + Supabase"
152
+ status: accepted
153
+ date: "2025-01-01"
154
+ context: "Need a full-stack framework with good DX, easy auth, and minimal ops overhead for a solo developer."
155
+ decision: "Use Next.js App Router for the frontend/API layer and Supabase for auth, database, and storage."
156
+ consequences:
157
+ - "Edge functions for webhook handling"
158
+ - "Row Level Security (RLS) policies enforce data isolation — agents must always include RLS on new tables"
159
+ - "No separate backend service needed"
160
+ alternatives_rejected:
161
+ - "Remix — less Claude Code tooling support as of Q1 2025"
162
+ - "PlanetScale — cost at scale vs Supabase free tier"
163
+ ---
164
+
165
+ ## Detail
166
+
167
+ Write more context here if needed. What trade-offs were made?
168
+ What would make this decision worth revisiting?
169
+ `,
170
+ "domain/core-rules.md": `---
171
+ id: core-business-rules
172
+ critical: true
173
+ title: "Core business rules"
174
+ ---
175
+
176
+ ## Rules that must NEVER be violated
177
+
178
+ These are business invariants. No agent should ever write code that contradicts these rules.
179
+ If in doubt, call pcl_get_domain('*critical') before touching the relevant code.
180
+
181
+ ### Data ownership
182
+ 1. User data is NEVER deleted on account downgrade — only access is restricted
183
+ 2. Export must always be available regardless of plan
184
+
185
+ ### Billing
186
+ 1. Cancellation takes effect immediately — no grace period unless explicitly specified
187
+ 2. Downgrade happens at end of billing period, never mid-period
188
+ 3. Stripe is the source of truth for subscription status — never trust local DB alone
189
+
190
+ ### Authentication
191
+ 1. Sessions expire after 30 days of inactivity
192
+ 2. Password reset tokens expire after 1 hour
193
+ 3. Never log or store plaintext passwords, tokens, or secrets anywhere
194
+
195
+ ### Add your own rules below...
196
+ `,
197
+ };
198
+ // ─── Commands ─────────────────────────────────────────────────────────────────
199
+ async function init() {
200
+ const scanMode = hasFlag("--scan");
201
+ const scanOnly = hasFlag("--scan-only");
202
+ // First positional arg that doesn't start with -- is the dir
203
+ const dirArg = args.find((a) => !a.startsWith("--"));
204
+ const productDir = resolve(dirArg ?? "./product");
205
+ console.log(`\nInitialising PCL product folder at: ${productDir}\n`);
206
+ // Track which type categories were covered by scan imports
207
+ const coveredTypes = new Set();
208
+ // ── Scan phase ──
209
+ if (scanMode || scanOnly) {
210
+ const { runScan } = await import("../src/scanner.js");
211
+ const rootDir = process.cwd();
212
+ const summary = await runScan(rootDir, productDir);
213
+ if (scanOnly) {
214
+ console.log("\nDone (scan-only mode).\n");
215
+ return;
216
+ }
217
+ for (const r of summary.imported)
218
+ coveredTypes.add(r.type);
219
+ console.log(""); // blank line before template scaffolding
220
+ }
221
+ // ── Template scaffolding ──
222
+ // Map template relative paths to the PCL type category they belong to
223
+ const templateTypeMap = {
224
+ "product.md": "product",
225
+ "personas/001-example.md": "persona",
226
+ "journeys/001-onboarding.md": "journey",
227
+ "specs/001-example-feature.md": "spec",
228
+ "decisions/001-example-adr.md": "decision",
229
+ "domain/core-rules.md": "domain",
230
+ };
231
+ const dirs = ["", "personas", "journeys", "specs", "decisions", "domain"];
232
+ for (const dir of dirs) {
233
+ await mkdir(join(productDir, dir), { recursive: true });
234
+ }
235
+ let created = 0;
236
+ let skipped = 0;
237
+ for (const [rel, content] of Object.entries(TEMPLATES)) {
238
+ // Skip templates for categories already covered by scan imports
239
+ const category = templateTypeMap[rel];
240
+ if (category && coveredTypes.has(category)) {
241
+ console.log(` ↷ ${rel} (category covered by scan, skipped)`);
242
+ skipped++;
243
+ continue;
244
+ }
245
+ const dest = join(productDir, rel);
246
+ try {
247
+ await access(dest, constants.F_OK);
248
+ console.log(` ↷ ${rel} (exists, skipped)`);
249
+ skipped++;
250
+ }
251
+ catch {
252
+ await writeFile(dest, content, "utf8");
253
+ console.log(` ✓ ${rel}`);
254
+ created++;
255
+ }
256
+ }
257
+ // Write CLAUDE.md bridge
258
+ const claudeMd = join(process.cwd(), "CLAUDE.md");
259
+ const bridge = `
260
+ ## Product Context Layer (PCL)
261
+
262
+ This project uses PCL for product knowledge. An MCP server is running (see mcp config).
263
+
264
+ ### At the start of every coding session:
265
+ 1. Call \`pcl_product_summary\` — orient yourself
266
+ 2. Call \`pcl_get_domain("*critical")\` — load non-violable business rules
267
+
268
+ ### Before working on any user-facing feature:
269
+ - Call \`pcl_list({ type: "personas" })\` then \`pcl_get_persona(id)\` for the relevant persona
270
+ - Call \`pcl_list({ type: "journeys" })\` then \`pcl_get_journey(id)\` for the relevant journey
271
+ - Call \`pcl_list({ type: "specs" })\` then \`pcl_get_spec(id)\` for the feature spec if it exists
272
+
273
+ ### When unsure about product decisions:
274
+ - Call \`pcl_search({ query: "your question here" })\` to find relevant product knowledge
275
+ - Call \`pcl_get_decision(id)\` for architecture decisions affecting your current task
276
+
277
+ ### NEVER:
278
+ - Make assumptions about who the user is — always load the persona
279
+ - Violate any rule in domain/core-rules.md
280
+ - Build features not covered by an accepted spec without asking first
281
+ `;
282
+ try {
283
+ await access(claudeMd, constants.F_OK);
284
+ console.log(`\n ↷ CLAUDE.md exists — add the PCL instructions manually (printed above)`);
285
+ console.log(bridge);
286
+ }
287
+ catch {
288
+ const existing = "";
289
+ await writeFile(claudeMd, existing + bridge, "utf8");
290
+ console.log(` ✓ CLAUDE.md`);
291
+ created++;
292
+ }
293
+ console.log(`\nDone! Created: ${created}, skipped: ${skipped}`);
294
+ console.log("\nNext steps:");
295
+ console.log(" 1. Edit product/product.md with your actual product details");
296
+ console.log(" 2. Rename and fill in the example persona, journey, and spec files");
297
+ console.log(" 3. Add your MCP server config (see README)");
298
+ console.log(" 4. npm run serve\n");
299
+ }
300
+ // ─── Router ───────────────────────────────────────────────────────────────────
301
+ switch (cmd) {
302
+ case "init":
303
+ init().catch(console.error);
304
+ break;
305
+ case "serve":
306
+ // Delegate to the server module
307
+ import("../src/server.js").catch(console.error);
308
+ break;
309
+ default:
310
+ console.log(`
311
+ pcl — Product Context Layer CLI
312
+
313
+ Commands:
314
+ init [dir] Scaffold /product folder with templates (default: ./product)
315
+ init --scan [dir] Scan repo for existing .md files, import, then scaffold remaining templates
316
+ init --scan-only [dir] Scan and import only, don't scaffold templates
317
+ serve Start the MCP server (reads --product-dir flag)
318
+
319
+ Examples:
320
+ npx pcl-mcp init
321
+ npx pcl-mcp init --scan
322
+ npx pcl-mcp init --scan-only
323
+ npx pcl-mcp init ./my-product-docs
324
+ npx pcl-mcp serve --product-dir ./product
325
+ `);
326
+ }
327
+ //# sourceMappingURL=pcl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pcl.js","sourceRoot":"","sources":["../../bin/pcl.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import Database from "better-sqlite3";
2
+ import type { FileType, IndexedFile } from "./types.js";
3
+ export declare function packEmbedding(vec: number[]): Buffer;
4
+ export declare function unpackEmbedding(buf: Buffer): number[];
5
+ export declare function hashContent(text: string): string;
6
+ export declare function openDB(productDir: string): Database.Database;
7
+ export declare function closeDB(): void;
8
+ export interface DBRow {
9
+ id: string;
10
+ type: FileType;
11
+ path: string;
12
+ frontmatter: string;
13
+ body: string;
14
+ full_text: string;
15
+ title: string;
16
+ summary: string;
17
+ critical: number;
18
+ mtime: number;
19
+ hash: string;
20
+ embedding: Buffer | null;
21
+ }
22
+ export declare function upsertFile(db: Database.Database, file: IndexedFile): void;
23
+ export declare function updateEmbedding(db: Database.Database, path: string, embedding: number[]): void;
24
+ export declare function deleteFile(db: Database.Database, path: string): void;
25
+ export declare function getFileByPath(db: Database.Database, path: string): IndexedFile | null;
26
+ export declare function getFileById(db: Database.Database, type: FileType, id: string): IndexedFile | null;
27
+ export declare function getProductFile(db: Database.Database): IndexedFile | null;
28
+ export declare function listByType(db: Database.Database, type: FileType): IndexedFile[];
29
+ export declare function getCritical(db: Database.Database): IndexedFile[];
30
+ export declare function getAllWithEmbeddings(db: Database.Database): IndexedFile[];
31
+ export declare function getAllWithoutEmbeddings(db: Database.Database): IndexedFile[];
32
+ export interface FTSResult {
33
+ id: string;
34
+ type: string;
35
+ rank: number;
36
+ }
37
+ export declare function keywordSearch(db: Database.Database, query: string, limit?: number): FTSResult[];
38
+ //# sourceMappingURL=db.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/db.ts"],"names":[],"mappings":"AAMA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAGtC,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AA2DxD,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,CAEnD;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAErD;AAID,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD;AAQD,wBAAgB,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,QAAQ,CAAC,QAAQ,CAoB5D;AAED,wBAAgB,OAAO,IAAI,IAAI,CAO9B;AAkDD,MAAM,WAAW,KAAK;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAqBD,wBAAgB,UAAU,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,WAAW,GAAG,IAAI,CAgBzE;AAED,wBAAgB,eAAe,CAC7B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EAAE,GAClB,IAAI,CAGN;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAGpE;AAID,wBAAgB,aAAa,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAGrF;AAED,wBAAgB,WAAW,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAGjG;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,WAAW,GAAG,IAAI,CAGxE;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,GAAG,WAAW,EAAE,CAG/E;AAED,wBAAgB,WAAW,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,WAAW,EAAE,CAGhE;AAED,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,WAAW,EAAE,CAKzE;AAED,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,WAAW,EAAE,CAG5E;AAID,MAAM,WAAW,SAAS;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE;AAErE,wBAAgB,aAAa,CAC3B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,KAAK,EAAE,MAAM,EACb,KAAK,SAAK,GACT,SAAS,EAAE,CAeb"}