@skillit/core 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/LICENSE +21 -0
- package/README.md +55 -0
- package/dist/audit-formatter.d.ts +36 -0
- package/dist/audit-formatter.d.ts.map +1 -0
- package/dist/audit-formatter.js +173 -0
- package/dist/audit-formatter.js.map +1 -0
- package/dist/audit-score.d.ts +76 -0
- package/dist/audit-score.d.ts.map +1 -0
- package/dist/audit-score.js +490 -0
- package/dist/audit-score.js.map +1 -0
- package/dist/audit-types.d.ts +81 -0
- package/dist/audit-types.d.ts.map +1 -0
- package/dist/audit-types.js +2 -0
- package/dist/audit-types.js.map +1 -0
- package/dist/audit.d.ts +17 -0
- package/dist/audit.d.ts.map +1 -0
- package/dist/audit.js +567 -0
- package/dist/audit.js.map +1 -0
- package/dist/canonical.d.ts +36 -0
- package/dist/canonical.d.ts.map +1 -0
- package/dist/canonical.js +148 -0
- package/dist/canonical.js.map +1 -0
- package/dist/config-renderer.d.ts +16 -0
- package/dist/config-renderer.d.ts.map +1 -0
- package/dist/config-renderer.js +296 -0
- package/dist/config-renderer.js.map +1 -0
- package/dist/config-types.d.ts +144 -0
- package/dist/config-types.d.ts.map +1 -0
- package/dist/config-types.js +2 -0
- package/dist/config-types.js.map +1 -0
- package/dist/docs-scanner.d.ts +40 -0
- package/dist/docs-scanner.d.ts.map +1 -0
- package/dist/docs-scanner.js +176 -0
- package/dist/docs-scanner.js.map +1 -0
- package/dist/examples-scanner.d.ts +39 -0
- package/dist/examples-scanner.d.ts.map +1 -0
- package/dist/examples-scanner.js +221 -0
- package/dist/examples-scanner.js.map +1 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/llms-txt.d.ts +20 -0
- package/dist/llms-txt.d.ts.map +1 -0
- package/dist/llms-txt.js +187 -0
- package/dist/llms-txt.js.map +1 -0
- package/dist/markdown-parser.d.ts +11 -0
- package/dist/markdown-parser.d.ts.map +1 -0
- package/dist/markdown-parser.js +222 -0
- package/dist/markdown-parser.js.map +1 -0
- package/dist/markdown-types.d.ts +48 -0
- package/dist/markdown-types.d.ts.map +1 -0
- package/dist/markdown-types.js +2 -0
- package/dist/markdown-types.js.map +1 -0
- package/dist/readme-parser.d.ts +21 -0
- package/dist/readme-parser.d.ts.map +1 -0
- package/dist/readme-parser.js +137 -0
- package/dist/readme-parser.js.map +1 -0
- package/dist/references-mcp.d.ts +79 -0
- package/dist/references-mcp.d.ts.map +1 -0
- package/dist/references-mcp.js +130 -0
- package/dist/references-mcp.js.map +1 -0
- package/dist/refine/ast-edit.d.ts +21 -0
- package/dist/refine/ast-edit.d.ts.map +1 -0
- package/dist/refine/ast-edit.js +147 -0
- package/dist/refine/ast-edit.js.map +1 -0
- package/dist/refine/index.d.ts +7 -0
- package/dist/refine/index.d.ts.map +1 -0
- package/dist/refine/index.js +6 -0
- package/dist/refine/index.js.map +1 -0
- package/dist/refine/jsdoc-edit.d.ts +4 -0
- package/dist/refine/jsdoc-edit.d.ts.map +1 -0
- package/dist/refine/jsdoc-edit.js +6 -0
- package/dist/refine/jsdoc-edit.js.map +1 -0
- package/dist/refine/loop.d.ts +8 -0
- package/dist/refine/loop.d.ts.map +1 -0
- package/dist/refine/loop.js +98 -0
- package/dist/refine/loop.js.map +1 -0
- package/dist/refine/select-targets.d.ts +5 -0
- package/dist/refine/select-targets.d.ts.map +1 -0
- package/dist/refine/select-targets.js +30 -0
- package/dist/refine/select-targets.js.map +1 -0
- package/dist/refine/types.d.ts +67 -0
- package/dist/refine/types.d.ts.map +1 -0
- package/dist/refine/types.js +2 -0
- package/dist/refine/types.js.map +1 -0
- package/dist/renderer.d.ts +27 -0
- package/dist/renderer.d.ts.map +1 -0
- package/dist/renderer.js +1244 -0
- package/dist/renderer.js.map +1 -0
- package/dist/tokens.d.ts +14 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +26 -0
- package/dist/tokens.js.map +1 -0
- package/dist/types.d.ts +519 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/writer.d.ts +17 -0
- package/dist/writer.d.ts.map +1 -0
- package/dist/writer.js +313 -0
- package/dist/writer.js.map +1 -0
- package/package.json +54 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { DocsExtractionOptions, ParsedMarkdownDoc } from './markdown-types.js';
|
|
2
|
+
import type { ExtractedDocument } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Scan a docs directory and return parsed markdown documents.
|
|
5
|
+
*
|
|
6
|
+
* - Returns `[]` when `docsDir` does not exist.
|
|
7
|
+
* - Recursively collects `.md` / `.mdx` files, honouring exclude patterns.
|
|
8
|
+
* - Default exclusions: **\/api\/**, **\/node_modules\/**, **\/.specify\/**, **\/superpowers\/**.
|
|
9
|
+
* - Sorts ascending by `order`, then alphabetically by `title`.
|
|
10
|
+
* - Truncates to `maxDocs` (default 20).
|
|
11
|
+
*
|
|
12
|
+
* @category Parsing
|
|
13
|
+
* @useWhen
|
|
14
|
+
* - You have hand-written prose docs (tutorials, guides, architecture) in a docs/ directory
|
|
15
|
+
* - You want these docs included alongside API skills for richer agent context
|
|
16
|
+
* @avoidWhen
|
|
17
|
+
* - Your docs/ directory contains only auto-generated API docs — they duplicate the TypeDoc output
|
|
18
|
+
*/
|
|
19
|
+
export declare function scanDocs(options: DocsExtractionOptions): ParsedMarkdownDoc[];
|
|
20
|
+
/**
|
|
21
|
+
* Convert parsed markdown documents to the generic `ExtractedDocument` shape.
|
|
22
|
+
*
|
|
23
|
+
* @category Parsing
|
|
24
|
+
* @useWhen
|
|
25
|
+
* - You have ParsedMarkdownDoc objects from scanDocs() and need to attach them to an ExtractedSkill
|
|
26
|
+
*/
|
|
27
|
+
export declare function docsToExtractedDocuments(docs: ParsedMarkdownDoc[]): ExtractedDocument[];
|
|
28
|
+
/**
|
|
29
|
+
* Scan root-level .md files that contain useful documentation.
|
|
30
|
+
* Skips README.md (parsed separately), LICENSE, CODE_OF_CONDUCT.md.
|
|
31
|
+
*
|
|
32
|
+
* @category Parsing
|
|
33
|
+
* @useWhen
|
|
34
|
+
* - You want to include well-known root-level markdown files (ARCHITECTURE.md, MIGRATION.md, CONTRIBUTING.md) as documents
|
|
35
|
+
* - Supplementing API skills with project-level documentation context
|
|
36
|
+
* @avoidWhen
|
|
37
|
+
* - Your root directory has many auto-generated or release-tracking markdown files — use explicit include lists instead
|
|
38
|
+
*/
|
|
39
|
+
export declare function scanRootDocs(projectRoot: string): ParsedMarkdownDoc[];
|
|
40
|
+
//# sourceMappingURL=docs-scanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docs-scanner.d.ts","sourceRoot":"","sources":["../src/docs-scanner.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACpF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AA8FpD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,qBAAqB,GAAG,iBAAiB,EAAE,CAuB5E;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,iBAAiB,EAAE,GAAG,iBAAiB,EAAE,CAEvF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAyCrE"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync, statSync } from 'fs';
|
|
2
|
+
import { join, relative } from 'path';
|
|
3
|
+
import { parseMarkdownDoc } from './markdown-parser.js';
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// Default exclusions & limits
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
const DEFAULT_EXCLUDE = ['**/api/**', '**/node_modules/**', '**/.specify/**', '**/superpowers/**'];
|
|
8
|
+
const DEFAULT_MAX_DOCS = 20;
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// Exclude pattern matching
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
/**
|
|
13
|
+
* Build a predicate that returns `true` when a relative path matches any of
|
|
14
|
+
* the given glob-style exclude patterns.
|
|
15
|
+
*
|
|
16
|
+
* Supported pattern form: `** /segment/**`
|
|
17
|
+
* Matching rule: the path equals, starts with, or contains the `segment` as a
|
|
18
|
+
* directory component.
|
|
19
|
+
*/
|
|
20
|
+
function makeExcludeMatcher(patterns) {
|
|
21
|
+
// Extract the core segment from each pattern: `**/foo/**` → `foo`
|
|
22
|
+
const segments = patterns.map((p) => p
|
|
23
|
+
.replace(/^\*\*\//, '')
|
|
24
|
+
.replace(/\/\*\*$/, '')
|
|
25
|
+
.replace(/\\/g, '/'));
|
|
26
|
+
return (relativePath) => {
|
|
27
|
+
const norm = relativePath.replace(/\\/g, '/');
|
|
28
|
+
for (const seg of segments) {
|
|
29
|
+
if (norm === seg ||
|
|
30
|
+
norm.startsWith(seg + '/') ||
|
|
31
|
+
norm.includes('/' + seg + '/') ||
|
|
32
|
+
norm.endsWith('/' + seg)) {
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return false;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
// Recursive file collection
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
function collectMarkdownFiles(dir, rootDir, isExcluded) {
|
|
43
|
+
const results = [];
|
|
44
|
+
let entries;
|
|
45
|
+
try {
|
|
46
|
+
entries = readdirSync(dir);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return results;
|
|
50
|
+
}
|
|
51
|
+
for (const entry of entries) {
|
|
52
|
+
const fullPath = join(dir, entry);
|
|
53
|
+
const relPath = relative(rootDir, fullPath).replace(/\\/g, '/');
|
|
54
|
+
let stat;
|
|
55
|
+
try {
|
|
56
|
+
stat = statSync(fullPath);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (stat.isDirectory()) {
|
|
62
|
+
if (!isExcluded(relPath)) {
|
|
63
|
+
results.push(...collectMarkdownFiles(fullPath, rootDir, isExcluded));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
else if (/\.mdx?$/.test(entry)) {
|
|
67
|
+
if (!isExcluded(relPath)) {
|
|
68
|
+
results.push(relPath);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return results;
|
|
73
|
+
}
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
// Public API
|
|
76
|
+
// ---------------------------------------------------------------------------
|
|
77
|
+
/**
|
|
78
|
+
* Scan a docs directory and return parsed markdown documents.
|
|
79
|
+
*
|
|
80
|
+
* - Returns `[]` when `docsDir` does not exist.
|
|
81
|
+
* - Recursively collects `.md` / `.mdx` files, honouring exclude patterns.
|
|
82
|
+
* - Default exclusions: **\/api\/**, **\/node_modules\/**, **\/.specify\/**, **\/superpowers\/**.
|
|
83
|
+
* - Sorts ascending by `order`, then alphabetically by `title`.
|
|
84
|
+
* - Truncates to `maxDocs` (default 20).
|
|
85
|
+
*
|
|
86
|
+
* @category Parsing
|
|
87
|
+
* @useWhen
|
|
88
|
+
* - You have hand-written prose docs (tutorials, guides, architecture) in a docs/ directory
|
|
89
|
+
* - You want these docs included alongside API skills for richer agent context
|
|
90
|
+
* @avoidWhen
|
|
91
|
+
* - Your docs/ directory contains only auto-generated API docs — they duplicate the TypeDoc output
|
|
92
|
+
*/
|
|
93
|
+
export function scanDocs(options) {
|
|
94
|
+
const { docsDir, exclude, maxDocs = DEFAULT_MAX_DOCS } = options;
|
|
95
|
+
if (!existsSync(docsDir)) {
|
|
96
|
+
return [];
|
|
97
|
+
}
|
|
98
|
+
const effectiveExclude = exclude ?? DEFAULT_EXCLUDE;
|
|
99
|
+
const isExcluded = makeExcludeMatcher(effectiveExclude);
|
|
100
|
+
const filePaths = collectMarkdownFiles(docsDir, docsDir, isExcluded);
|
|
101
|
+
const docs = filePaths.map((relPath) => {
|
|
102
|
+
const fullPath = join(docsDir, relPath);
|
|
103
|
+
const content = readFileSync(fullPath, 'utf-8');
|
|
104
|
+
return parseMarkdownDoc(content, relPath);
|
|
105
|
+
});
|
|
106
|
+
docs.sort((a, b) => {
|
|
107
|
+
if (a.order !== b.order)
|
|
108
|
+
return a.order - b.order;
|
|
109
|
+
return a.title.localeCompare(b.title);
|
|
110
|
+
});
|
|
111
|
+
return docs.slice(0, maxDocs);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Convert parsed markdown documents to the generic `ExtractedDocument` shape.
|
|
115
|
+
*
|
|
116
|
+
* @category Parsing
|
|
117
|
+
* @useWhen
|
|
118
|
+
* - You have ParsedMarkdownDoc objects from scanDocs() and need to attach them to an ExtractedSkill
|
|
119
|
+
*/
|
|
120
|
+
export function docsToExtractedDocuments(docs) {
|
|
121
|
+
return docs.map((doc) => ({ title: doc.title, content: doc.rawContent }));
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Scan root-level .md files that contain useful documentation.
|
|
125
|
+
* Skips README.md (parsed separately), LICENSE, CODE_OF_CONDUCT.md.
|
|
126
|
+
*
|
|
127
|
+
* @category Parsing
|
|
128
|
+
* @useWhen
|
|
129
|
+
* - You want to include well-known root-level markdown files (ARCHITECTURE.md, MIGRATION.md, CONTRIBUTING.md) as documents
|
|
130
|
+
* - Supplementing API skills with project-level documentation context
|
|
131
|
+
* @avoidWhen
|
|
132
|
+
* - Your root directory has many auto-generated or release-tracking markdown files — use explicit include lists instead
|
|
133
|
+
*/
|
|
134
|
+
export function scanRootDocs(projectRoot) {
|
|
135
|
+
const SKIP = new Set([
|
|
136
|
+
'readme.md',
|
|
137
|
+
'license',
|
|
138
|
+
'license.md',
|
|
139
|
+
'code_of_conduct.md',
|
|
140
|
+
'changelog.md',
|
|
141
|
+
'changes.md',
|
|
142
|
+
'history.md',
|
|
143
|
+
'releases.md',
|
|
144
|
+
'security.md',
|
|
145
|
+
'support.md',
|
|
146
|
+
'contributors.md',
|
|
147
|
+
'authors.md',
|
|
148
|
+
'acknowledgments.md',
|
|
149
|
+
'agents.md',
|
|
150
|
+
'claude.md',
|
|
151
|
+
'gemini.md',
|
|
152
|
+
'copilot.md'
|
|
153
|
+
]);
|
|
154
|
+
if (!existsSync(projectRoot))
|
|
155
|
+
return [];
|
|
156
|
+
const entries = readdirSync(projectRoot, { withFileTypes: true });
|
|
157
|
+
const docs = [];
|
|
158
|
+
for (const entry of entries) {
|
|
159
|
+
if (!entry.isFile())
|
|
160
|
+
continue;
|
|
161
|
+
if (!/\.mdx?$/i.test(entry.name))
|
|
162
|
+
continue;
|
|
163
|
+
if (SKIP.has(entry.name.toLowerCase()))
|
|
164
|
+
continue;
|
|
165
|
+
try {
|
|
166
|
+
const content = readFileSync(join(projectRoot, entry.name), 'utf-8');
|
|
167
|
+
const parsed = parseMarkdownDoc(content, entry.name);
|
|
168
|
+
docs.push(parsed);
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
// skip unreadable
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return docs.sort((a, b) => a.title.localeCompare(b.title));
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=docs-scanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docs-scanner.js","sourceRoot":"","sources":["../src/docs-scanner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { ExtractedSkill } from './types.js';
|
|
2
|
+
export interface ParsedExample {
|
|
3
|
+
/** File path relative to examples dir */
|
|
4
|
+
relativePath: string;
|
|
5
|
+
/** Title derived from top-level JSDoc @description or first comment, or filename */
|
|
6
|
+
title: string;
|
|
7
|
+
/** Description from top-level JSDoc or first comment */
|
|
8
|
+
description?: string;
|
|
9
|
+
/** Imported symbol names (e.g. ["renderSkill", "writeSkills"]) */
|
|
10
|
+
importedSymbols: string[];
|
|
11
|
+
/** Package names imported from (e.g. ["@skillit/core"]) */
|
|
12
|
+
importedFrom: string[];
|
|
13
|
+
/** Full file content */
|
|
14
|
+
content: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Scan an examples directory for `.ts`/`.js`/`.tsx`/`.jsx` files and parse
|
|
18
|
+
* their import statements and top-level comments.
|
|
19
|
+
*
|
|
20
|
+
* @category Parsing
|
|
21
|
+
* @useWhen
|
|
22
|
+
* - You have an `examples/` directory alongside source code
|
|
23
|
+
* - You want to link example files to the exported symbols they demonstrate
|
|
24
|
+
* @avoidWhen
|
|
25
|
+
* - Your examples are embedded as @example JSDoc tags (use TypeDoc extraction instead)
|
|
26
|
+
*/
|
|
27
|
+
export declare function scanExamples(examplesDir: string): ParsedExample[];
|
|
28
|
+
/**
|
|
29
|
+
* Mutate an `ExtractedSkill` in place by linking each example to the first
|
|
30
|
+
* matching exported function or class. Falls back to `skill.examples` when no
|
|
31
|
+
* symbol matches any export.
|
|
32
|
+
*
|
|
33
|
+
* @category Parsing
|
|
34
|
+
* @useWhen
|
|
35
|
+
* - You have scanned examples with `scanExamples` and want to attach them to
|
|
36
|
+
* the relevant exported symbols inside an `ExtractedSkill`
|
|
37
|
+
*/
|
|
38
|
+
export declare function linkExamplesToSkill(examples: ParsedExample[], skill: ExtractedSkill): void;
|
|
39
|
+
//# sourceMappingURL=examples-scanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"examples-scanner.d.ts","sourceRoot":"","sources":["../src/examples-scanner.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAMjD,MAAM,WAAW,aAAa;IAC5B,yCAAyC;IACzC,YAAY,EAAE,MAAM,CAAC;IACrB,oFAAoF;IACpF,KAAK,EAAE,MAAM,CAAC;IACd,wDAAwD;IACxD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kEAAkE;IAClE,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,2DAA2D;IAC3D,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,wBAAwB;IACxB,OAAO,EAAE,MAAM,CAAC;CACjB;AAsJD;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa,EAAE,CA0CjE;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,aAAa,EAAE,EAAE,KAAK,EAAE,cAAc,GAAG,IAAI,CA4B1F"}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
|
|
2
|
+
import { extname, join, relative } from 'node:path';
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// Constants
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
const SUPPORTED_EXTS = new Set(['.ts', '.js', '.tsx', '.jsx']);
|
|
7
|
+
/**
|
|
8
|
+
* Matches all forms of import statements:
|
|
9
|
+
* - Named: import { X, Y as Z } from 'pkg'
|
|
10
|
+
* - Namespace: import * as X from 'pkg'
|
|
11
|
+
* - Default: import X from 'pkg'
|
|
12
|
+
*/
|
|
13
|
+
const IMPORT_RE = /import\s+(?:\{([^}]+)\}|(\*\s+as\s+\w+)|(\w+))\s+from\s+['"]([^'"]+)['"]/g;
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// Import parsing
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
function parseImports(content) {
|
|
18
|
+
const symbols = [];
|
|
19
|
+
const packages = [];
|
|
20
|
+
let match;
|
|
21
|
+
IMPORT_RE.lastIndex = 0;
|
|
22
|
+
while ((match = IMPORT_RE.exec(content)) !== null) {
|
|
23
|
+
const namedGroup = match[1]; // { X, Y as Z }
|
|
24
|
+
const namespaceGroup = match[2]; // * as X
|
|
25
|
+
const defaultGroup = match[3]; // X
|
|
26
|
+
const pkg = match[4];
|
|
27
|
+
packages.push(pkg);
|
|
28
|
+
if (namedGroup) {
|
|
29
|
+
// Extract original names (before "as" alias)
|
|
30
|
+
for (const part of namedGroup.split(',')) {
|
|
31
|
+
const trimmed = part.trim();
|
|
32
|
+
if (!trimmed)
|
|
33
|
+
continue;
|
|
34
|
+
// "X as Y" → take X; "X" → take X
|
|
35
|
+
const original = trimmed.split(/\s+as\s+/)[0].trim();
|
|
36
|
+
if (original)
|
|
37
|
+
symbols.push(original);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
else if (namespaceGroup) {
|
|
41
|
+
// "* as fs" → take "fs"
|
|
42
|
+
const nsName = namespaceGroup.replace(/^\*\s+as\s+/, '').trim();
|
|
43
|
+
if (nsName)
|
|
44
|
+
symbols.push(nsName);
|
|
45
|
+
}
|
|
46
|
+
else if (defaultGroup) {
|
|
47
|
+
symbols.push(defaultGroup);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return { symbols, packages };
|
|
51
|
+
}
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// Title / description extraction
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
/**
|
|
56
|
+
* Convert a filename (without extension) to a human-readable title.
|
|
57
|
+
* "minimal-server" → "Minimal Server", "my_example" → "My Example"
|
|
58
|
+
*/
|
|
59
|
+
function filenameToTitle(name) {
|
|
60
|
+
return name.replace(/[-_]/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase());
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Extract title and description from a top-level JSDoc or `//` comment.
|
|
64
|
+
* Returns undefined if no comment is found at the top of the file.
|
|
65
|
+
*/
|
|
66
|
+
function extractComment(content) {
|
|
67
|
+
const stripped = content.trimStart();
|
|
68
|
+
// Try JSDoc: /** ... */
|
|
69
|
+
if (stripped.startsWith('/**')) {
|
|
70
|
+
const end = stripped.indexOf('*/');
|
|
71
|
+
if (end !== -1) {
|
|
72
|
+
const block = stripped.slice(3, end);
|
|
73
|
+
const lines = block
|
|
74
|
+
.split('\n')
|
|
75
|
+
.map((l) => l.replace(/^\s*\*\s?/, '').trim())
|
|
76
|
+
.filter((l) => l.length > 0);
|
|
77
|
+
if (lines.length === 0)
|
|
78
|
+
return undefined;
|
|
79
|
+
const title = lines[0];
|
|
80
|
+
const rest = lines.slice(1).join(' ').trim() || undefined;
|
|
81
|
+
return { title, description: rest };
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// Try single-line // comment
|
|
85
|
+
if (stripped.startsWith('//')) {
|
|
86
|
+
const firstLine = stripped.split('\n')[0];
|
|
87
|
+
const title = firstLine.replace(/^\/\/\s*/, '').trim();
|
|
88
|
+
if (title)
|
|
89
|
+
return { title };
|
|
90
|
+
}
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
// ---------------------------------------------------------------------------
|
|
94
|
+
// File collection
|
|
95
|
+
// ---------------------------------------------------------------------------
|
|
96
|
+
function collectExampleFiles(dir, rootDir) {
|
|
97
|
+
const results = [];
|
|
98
|
+
let entries;
|
|
99
|
+
try {
|
|
100
|
+
entries = readdirSync(dir);
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return results;
|
|
104
|
+
}
|
|
105
|
+
for (const entry of entries) {
|
|
106
|
+
const fullPath = join(dir, entry);
|
|
107
|
+
let stat;
|
|
108
|
+
try {
|
|
109
|
+
stat = statSync(fullPath);
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (stat.isDirectory()) {
|
|
115
|
+
results.push(...collectExampleFiles(fullPath, rootDir));
|
|
116
|
+
}
|
|
117
|
+
else if (SUPPORTED_EXTS.has(extname(entry))) {
|
|
118
|
+
const relPath = relative(rootDir, fullPath).replace(/\\/g, '/');
|
|
119
|
+
results.push(relPath);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return results;
|
|
123
|
+
}
|
|
124
|
+
// ---------------------------------------------------------------------------
|
|
125
|
+
// Language tag helper
|
|
126
|
+
// ---------------------------------------------------------------------------
|
|
127
|
+
function langTag(relativePath) {
|
|
128
|
+
const ext = extname(relativePath);
|
|
129
|
+
if (ext === '.ts' || ext === '.tsx')
|
|
130
|
+
return 'typescript';
|
|
131
|
+
return 'javascript';
|
|
132
|
+
}
|
|
133
|
+
// ---------------------------------------------------------------------------
|
|
134
|
+
// Public API
|
|
135
|
+
// ---------------------------------------------------------------------------
|
|
136
|
+
/**
|
|
137
|
+
* Scan an examples directory for `.ts`/`.js`/`.tsx`/`.jsx` files and parse
|
|
138
|
+
* their import statements and top-level comments.
|
|
139
|
+
*
|
|
140
|
+
* @category Parsing
|
|
141
|
+
* @useWhen
|
|
142
|
+
* - You have an `examples/` directory alongside source code
|
|
143
|
+
* - You want to link example files to the exported symbols they demonstrate
|
|
144
|
+
* @avoidWhen
|
|
145
|
+
* - Your examples are embedded as @example JSDoc tags (use TypeDoc extraction instead)
|
|
146
|
+
*/
|
|
147
|
+
export function scanExamples(examplesDir) {
|
|
148
|
+
if (!existsSync(examplesDir))
|
|
149
|
+
return [];
|
|
150
|
+
const relPaths = collectExampleFiles(examplesDir, examplesDir);
|
|
151
|
+
const results = [];
|
|
152
|
+
for (const relPath of relPaths) {
|
|
153
|
+
const fullPath = join(examplesDir, relPath);
|
|
154
|
+
let content;
|
|
155
|
+
try {
|
|
156
|
+
content = readFileSync(fullPath, 'utf-8');
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
const { symbols, packages } = parseImports(content);
|
|
162
|
+
const comment = extractComment(content);
|
|
163
|
+
let title;
|
|
164
|
+
let description;
|
|
165
|
+
if (comment) {
|
|
166
|
+
title = comment.title;
|
|
167
|
+
description = comment.description;
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
// Derive from filename (strip extension)
|
|
171
|
+
const basename = relPath.split('/').pop();
|
|
172
|
+
const nameWithoutExt = basename.replace(/\.[^.]+$/, '');
|
|
173
|
+
title = filenameToTitle(nameWithoutExt);
|
|
174
|
+
}
|
|
175
|
+
results.push({
|
|
176
|
+
relativePath: relPath,
|
|
177
|
+
title,
|
|
178
|
+
description,
|
|
179
|
+
importedSymbols: symbols,
|
|
180
|
+
importedFrom: packages,
|
|
181
|
+
content
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
return results;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Mutate an `ExtractedSkill` in place by linking each example to the first
|
|
188
|
+
* matching exported function or class. Falls back to `skill.examples` when no
|
|
189
|
+
* symbol matches any export.
|
|
190
|
+
*
|
|
191
|
+
* @category Parsing
|
|
192
|
+
* @useWhen
|
|
193
|
+
* - You have scanned examples with `scanExamples` and want to attach them to
|
|
194
|
+
* the relevant exported symbols inside an `ExtractedSkill`
|
|
195
|
+
*/
|
|
196
|
+
export function linkExamplesToSkill(examples, skill) {
|
|
197
|
+
for (const example of examples) {
|
|
198
|
+
const lang = langTag(example.relativePath);
|
|
199
|
+
const fenced = `\`\`\`${lang}\n${example.content}\n\`\`\``;
|
|
200
|
+
let linked = false;
|
|
201
|
+
// Find first symbol that matches a function or class export
|
|
202
|
+
for (const symbol of example.importedSymbols) {
|
|
203
|
+
const fn = skill.functions.find((f) => f.name === symbol);
|
|
204
|
+
if (fn) {
|
|
205
|
+
fn.examples.push(fenced);
|
|
206
|
+
linked = true;
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
const cls = skill.classes.find((c) => c.name === symbol);
|
|
210
|
+
if (cls) {
|
|
211
|
+
cls.examples.push(fenced);
|
|
212
|
+
linked = true;
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (!linked) {
|
|
217
|
+
skill.examples.push(fenced);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
//# sourceMappingURL=examples-scanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"examples-scanner.js","sourceRoot":"","sources":["../src/examples-scanner.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types, renderers, and utilities for the skillit ecosystem.
|
|
3
|
+
*
|
|
4
|
+
* Core provides the intermediate representation (ExtractedSkill), the SKILL.md renderer
|
|
5
|
+
* with progressive disclosure (lean discovery file + on-demand reference files), the
|
|
6
|
+
* audit engine (20 checks across fatal/error/warning/alert), and utilities for
|
|
7
|
+
* token budgeting, README parsing, and docs scanning.
|
|
8
|
+
*
|
|
9
|
+
* @remarks
|
|
10
|
+
* All extractors (@skillit/typedoc, @skillit/cli, @skillit/docusaurus) produce
|
|
11
|
+
* ExtractedSkill objects. Core renders them into SKILL.md + references/ files.
|
|
12
|
+
* The rendering is framework-agnostic — it doesn't know where the data came from.
|
|
13
|
+
*
|
|
14
|
+
* @packageDocumentation
|
|
15
|
+
*/
|
|
16
|
+
export type { ExtractedSkill, ExtractedSkillAudit, ExtractedFunction, ExtractedFunctionMcpMetadata, ExtractedClass, ExtractedType, ExtractedEnum, ExtractedParameter, ExtractedProperty, ExtractedVariable, ExtractedDocument, ExtractedResource, ExtractedPrompt, ExtractedPromptArgument, SkillSetup, AdapterFingerprint, InvocationAdapter, AdapterRenderContext, AdapterRenderContextBase, AdapterRenderContextBundle, AdapterRenderContextHttp, AdapterRenderContextStdio, RefCategory, RefManifest, RefManifestEntry, RenderedFile, RenderedSkill, SkillRenderOptions, SkillWriteOptions, SkillWriteResult, SkillWritePreserveReason, McpAuditSeverity, McpAuditIssue } from './types.js';
|
|
17
|
+
export { renderSkills, renderSkill } from './renderer.js';
|
|
18
|
+
export { canonicalize } from './canonical.js';
|
|
19
|
+
export type { CanonicalizeOptions } from './canonical.js';
|
|
20
|
+
export { writeSkills, readInstalledSkillMetadata } from './writer.js';
|
|
21
|
+
export { estimateTokens, truncateToTokenBudget } from './tokens.js';
|
|
22
|
+
export { renderResourcesReference, renderPromptsReference } from './references-mcp.js';
|
|
23
|
+
export type { McpReferenceOptions } from './references-mcp.js';
|
|
24
|
+
export { renderLlmsTxt } from './llms-txt.js';
|
|
25
|
+
export type { LlmsTxtOptions, LlmsTxtResult } from './llms-txt.js';
|
|
26
|
+
export type { AuditSeverity, AuditIssue, AuditPass, AuditContext, ParsedReadme, AuditResult } from './audit-types.js';
|
|
27
|
+
export { parseReadme } from './readme-parser.js';
|
|
28
|
+
export { auditSkill } from './audit.js';
|
|
29
|
+
export { formatAuditText, formatAuditJson, formatScoreEstimate } from './audit-formatter.js';
|
|
30
|
+
export { estimateSkillJudgeScore } from './audit-score.js';
|
|
31
|
+
export type { SkillJudgeEstimate, ActionableImprovement } from './audit-score.js';
|
|
32
|
+
export type { ConfigSourceType, ExtractedConfigSurface, ExtractedConfigOption, ExtractedConfigArgument } from './config-types.js';
|
|
33
|
+
export { renderConfigSurfaceSection, renderConfigReference } from './config-renderer.js';
|
|
34
|
+
export type { ParsedSection, ParsedMarkdownDoc, DocsExtractionOptions } from './markdown-types.js';
|
|
35
|
+
export { parseMarkdownDoc } from './markdown-parser.js';
|
|
36
|
+
export { scanDocs, docsToExtractedDocuments, scanRootDocs } from './docs-scanner.js';
|
|
37
|
+
export { scanExamples, linkExamplesToSkill } from './examples-scanner.js';
|
|
38
|
+
export type { ParsedExample } from './examples-scanner.js';
|
|
39
|
+
export * from './refine/index.js';
|
|
40
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,YAAY,EACV,cAAc,EACd,mBAAmB,EACnB,iBAAiB,EACjB,4BAA4B,EAC5B,cAAc,EACd,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,uBAAuB,EACvB,UAAU,EACV,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,wBAAwB,EACxB,0BAA0B,EAC1B,wBAAwB,EACxB,yBAAyB,EACzB,WAAW,EACX,WAAW,EACX,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,wBAAwB,EACxB,gBAAgB,EAChB,aAAa,EACd,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AACtE,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpE,OAAO,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AACvF,YAAY,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnE,YAAY,EACV,aAAa,EACb,UAAU,EACV,SAAS,EACT,YAAY,EACZ,YAAY,EACZ,WAAW,EACZ,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAE7F,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,YAAY,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAElF,YAAY,EACV,gBAAgB,EAChB,sBAAsB,EACtB,qBAAqB,EACrB,uBAAuB,EACxB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,0BAA0B,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAEzF,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAEnG,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAExD,OAAO,EAAE,QAAQ,EAAE,wBAAwB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAErF,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC1E,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D,cAAc,mBAAmB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types, renderers, and utilities for the skillit ecosystem.
|
|
3
|
+
*
|
|
4
|
+
* Core provides the intermediate representation (ExtractedSkill), the SKILL.md renderer
|
|
5
|
+
* with progressive disclosure (lean discovery file + on-demand reference files), the
|
|
6
|
+
* audit engine (20 checks across fatal/error/warning/alert), and utilities for
|
|
7
|
+
* token budgeting, README parsing, and docs scanning.
|
|
8
|
+
*
|
|
9
|
+
* @remarks
|
|
10
|
+
* All extractors (@skillit/typedoc, @skillit/cli, @skillit/docusaurus) produce
|
|
11
|
+
* ExtractedSkill objects. Core renders them into SKILL.md + references/ files.
|
|
12
|
+
* The rendering is framework-agnostic — it doesn't know where the data came from.
|
|
13
|
+
*
|
|
14
|
+
* @packageDocumentation
|
|
15
|
+
*/
|
|
16
|
+
export { renderSkills, renderSkill } from './renderer.js';
|
|
17
|
+
export { canonicalize } from './canonical.js';
|
|
18
|
+
export { writeSkills, readInstalledSkillMetadata } from './writer.js';
|
|
19
|
+
export { estimateTokens, truncateToTokenBudget } from './tokens.js';
|
|
20
|
+
export { renderResourcesReference, renderPromptsReference } from './references-mcp.js';
|
|
21
|
+
export { renderLlmsTxt } from './llms-txt.js';
|
|
22
|
+
export { parseReadme } from './readme-parser.js';
|
|
23
|
+
export { auditSkill } from './audit.js';
|
|
24
|
+
export { formatAuditText, formatAuditJson, formatScoreEstimate } from './audit-formatter.js';
|
|
25
|
+
export { estimateSkillJudgeScore } from './audit-score.js';
|
|
26
|
+
export { renderConfigSurfaceSection, renderConfigReference } from './config-renderer.js';
|
|
27
|
+
export { parseMarkdownDoc } from './markdown-parser.js';
|
|
28
|
+
export { scanDocs, docsToExtractedDocuments, scanRootDocs } from './docs-scanner.js';
|
|
29
|
+
export { scanExamples, linkExamplesToSkill } from './examples-scanner.js';
|
|
30
|
+
export * from './refine/index.js';
|
|
31
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAsCH,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,OAAO,EAAE,WAAW,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AACtE,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpE,OAAO,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAEvF,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAY9C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAE7F,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAU3D,OAAO,EAAE,0BAA0B,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAIzF,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAExD,OAAO,EAAE,QAAQ,EAAE,wBAAwB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAErF,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAG1E,cAAc,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ExtractedSkill } from './types.js';
|
|
2
|
+
export interface LlmsTxtOptions {
|
|
3
|
+
/** Project name (falls back to first skill name) */
|
|
4
|
+
projectName: string;
|
|
5
|
+
/** Project description */
|
|
6
|
+
projectDescription: string;
|
|
7
|
+
}
|
|
8
|
+
export interface LlmsTxtResult {
|
|
9
|
+
/** llms.txt content (summary index) */
|
|
10
|
+
summary: string;
|
|
11
|
+
/** llms-full.txt content (complete API) */
|
|
12
|
+
full: string;
|
|
13
|
+
/** Estimated tokens for summary */
|
|
14
|
+
summaryTokens: number;
|
|
15
|
+
/** Estimated tokens for full */
|
|
16
|
+
fullTokens: number;
|
|
17
|
+
}
|
|
18
|
+
/** Render llms.txt and llms-full.txt from extracted skills */
|
|
19
|
+
export declare function renderLlmsTxt(skills: ExtractedSkill[], options: LlmsTxtOptions): LlmsTxtResult;
|
|
20
|
+
//# sourceMappingURL=llms-txt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llms-txt.d.ts","sourceRoot":"","sources":["../src/llms-txt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAMjD,MAAM,WAAW,cAAc;IAC7B,oDAAoD;IACpD,WAAW,EAAE,MAAM,CAAC;IACpB,0BAA0B;IAC1B,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,aAAa;IAC5B,uCAAuC;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,mCAAmC;IACnC,aAAa,EAAE,MAAM,CAAC;IACtB,gCAAgC;IAChC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,8DAA8D;AAC9D,wBAAgB,aAAa,CAAC,MAAM,EAAE,cAAc,EAAE,EAAE,OAAO,EAAE,cAAc,GAAG,aAAa,CAU9F"}
|