@ai-plugin-marketplace/core 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 +67 -0
- package/dist/config.d.ts +47 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +38 -0
- package/dist/config.js.map +1 -0
- package/dist/core.d.ts +291 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/pipeline/build.d.ts +90 -0
- package/dist/pipeline/build.d.ts.map +1 -0
- package/dist/pipeline/build.js +224 -0
- package/dist/pipeline/build.js.map +1 -0
- package/dist/pipeline/discover.d.ts +37 -0
- package/dist/pipeline/discover.d.ts.map +1 -0
- package/dist/pipeline/discover.js +71 -0
- package/dist/pipeline/discover.js.map +1 -0
- package/dist/pipeline/init-template.d.ts +33 -0
- package/dist/pipeline/init-template.d.ts.map +1 -0
- package/dist/pipeline/init-template.js +142 -0
- package/dist/pipeline/init-template.js.map +1 -0
- package/dist/pipeline/init.d.ts +39 -0
- package/dist/pipeline/init.d.ts.map +1 -0
- package/dist/pipeline/init.js +84 -0
- package/dist/pipeline/init.js.map +1 -0
- package/dist/pipeline/load-config.d.ts +47 -0
- package/dist/pipeline/load-config.d.ts.map +1 -0
- package/dist/pipeline/load-config.js +106 -0
- package/dist/pipeline/load-config.js.map +1 -0
- package/dist/pipeline/operations.d.ts +70 -0
- package/dist/pipeline/operations.d.ts.map +1 -0
- package/dist/pipeline/operations.js +100 -0
- package/dist/pipeline/operations.js.map +1 -0
- package/dist/pipeline/scaffold.d.ts +105 -0
- package/dist/pipeline/scaffold.d.ts.map +1 -0
- package/dist/pipeline/scaffold.js +422 -0
- package/dist/pipeline/scaffold.js.map +1 -0
- package/dist/pipeline/sentinel.d.ts +127 -0
- package/dist/pipeline/sentinel.d.ts.map +1 -0
- package/dist/pipeline/sentinel.js +263 -0
- package/dist/pipeline/sentinel.js.map +1 -0
- package/dist/pipeline/types.d.ts +178 -0
- package/dist/pipeline/types.d.ts.map +1 -0
- package/dist/pipeline/types.js +26 -0
- package/dist/pipeline/types.js.map +1 -0
- package/dist/pipeline/validate.d.ts +90 -0
- package/dist/pipeline/validate.d.ts.map +1 -0
- package/dist/pipeline/validate.js +617 -0
- package/dist/pipeline/validate.js.map +1 -0
- package/dist/targets/claude/scaffold.d.ts +32 -0
- package/dist/targets/claude/scaffold.d.ts.map +1 -0
- package/dist/targets/claude/scaffold.js +48 -0
- package/dist/targets/claude/scaffold.js.map +1 -0
- package/dist/targets/claude/schemas.d.ts +119 -0
- package/dist/targets/claude/schemas.d.ts.map +1 -0
- package/dist/targets/claude/schemas.js +204 -0
- package/dist/targets/claude/schemas.js.map +1 -0
- package/dist/targets/claude/transform.d.ts +40 -0
- package/dist/targets/claude/transform.d.ts.map +1 -0
- package/dist/targets/claude/transform.js +48 -0
- package/dist/targets/claude/transform.js.map +1 -0
- package/dist/targets/claude/validate.d.ts +25 -0
- package/dist/targets/claude/validate.d.ts.map +1 -0
- package/dist/targets/claude/validate.js +263 -0
- package/dist/targets/claude/validate.js.map +1 -0
- package/dist/targets/cursor/scaffold.d.ts +29 -0
- package/dist/targets/cursor/scaffold.d.ts.map +1 -0
- package/dist/targets/cursor/scaffold.js +45 -0
- package/dist/targets/cursor/scaffold.js.map +1 -0
- package/dist/targets/cursor/schemas.d.ts +49 -0
- package/dist/targets/cursor/schemas.d.ts.map +1 -0
- package/dist/targets/cursor/schemas.js +125 -0
- package/dist/targets/cursor/schemas.js.map +1 -0
- package/dist/targets/cursor/validate.d.ts +28 -0
- package/dist/targets/cursor/validate.d.ts.map +1 -0
- package/dist/targets/cursor/validate.js +181 -0
- package/dist/targets/cursor/validate.js.map +1 -0
- package/dist/targets/gemini/bundle.d.ts +25 -0
- package/dist/targets/gemini/bundle.d.ts.map +1 -0
- package/dist/targets/gemini/bundle.js +149 -0
- package/dist/targets/gemini/bundle.js.map +1 -0
- package/dist/targets/gemini/scaffold.d.ts +28 -0
- package/dist/targets/gemini/scaffold.d.ts.map +1 -0
- package/dist/targets/gemini/scaffold.js +57 -0
- package/dist/targets/gemini/scaffold.js.map +1 -0
- package/dist/targets/gemini/schemas.d.ts +53 -0
- package/dist/targets/gemini/schemas.d.ts.map +1 -0
- package/dist/targets/gemini/schemas.js +72 -0
- package/dist/targets/gemini/schemas.js.map +1 -0
- package/dist/targets/gemini/transform.d.ts +106 -0
- package/dist/targets/gemini/transform.d.ts.map +1 -0
- package/dist/targets/gemini/transform.js +137 -0
- package/dist/targets/gemini/transform.js.map +1 -0
- package/dist/targets/gemini/validate.d.ts +26 -0
- package/dist/targets/gemini/validate.d.ts.map +1 -0
- package/dist/targets/gemini/validate.js +146 -0
- package/dist/targets/gemini/validate.js.map +1 -0
- package/dist/targets/kiro/bundle.d.ts +32 -0
- package/dist/targets/kiro/bundle.d.ts.map +1 -0
- package/dist/targets/kiro/bundle.js +106 -0
- package/dist/targets/kiro/bundle.js.map +1 -0
- package/dist/targets/kiro/scaffold.d.ts +28 -0
- package/dist/targets/kiro/scaffold.d.ts.map +1 -0
- package/dist/targets/kiro/scaffold.js +55 -0
- package/dist/targets/kiro/scaffold.js.map +1 -0
- package/dist/targets/kiro/schemas.d.ts +100 -0
- package/dist/targets/kiro/schemas.d.ts.map +1 -0
- package/dist/targets/kiro/schemas.js +147 -0
- package/dist/targets/kiro/schemas.js.map +1 -0
- package/dist/targets/kiro/transform.d.ts +53 -0
- package/dist/targets/kiro/transform.d.ts.map +1 -0
- package/dist/targets/kiro/transform.js +113 -0
- package/dist/targets/kiro/transform.js.map +1 -0
- package/dist/targets/kiro/validate.d.ts +36 -0
- package/dist/targets/kiro/validate.d.ts.map +1 -0
- package/dist/targets/kiro/validate.js +232 -0
- package/dist/targets/kiro/validate.js.map +1 -0
- package/dist/targets/scaffold-kit.d.ts +56 -0
- package/dist/targets/scaffold-kit.d.ts.map +1 -0
- package/dist/targets/scaffold-kit.js +33 -0
- package/dist/targets/scaffold-kit.js.map +1 -0
- package/dist/targets/vercel/scaffold.d.ts +34 -0
- package/dist/targets/vercel/scaffold.d.ts.map +1 -0
- package/dist/targets/vercel/scaffold.js +58 -0
- package/dist/targets/vercel/scaffold.js.map +1 -0
- package/dist/targets/vercel/schemas.d.ts +42 -0
- package/dist/targets/vercel/schemas.d.ts.map +1 -0
- package/dist/targets/vercel/schemas.js +69 -0
- package/dist/targets/vercel/schemas.js.map +1 -0
- package/dist/targets/vercel/validate.d.ts +28 -0
- package/dist/targets/vercel/validate.d.ts.map +1 -0
- package/dist/targets/vercel/validate.js +180 -0
- package/dist/targets/vercel/validate.js.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generated-file sentinels.
|
|
3
|
+
*
|
|
4
|
+
* Per §4.3 of the architecture spec, every toolkit-generated file carries a sentinel so
|
|
5
|
+
* hand-edits are detectable by the freshness check (§10.5). There are three carriers:
|
|
6
|
+
*
|
|
7
|
+
* 1. **Inline text** — a comment block prepended to plain-text generated files.
|
|
8
|
+
* 2. **JSON `_generated` field** — a top-level object on JSON outputs that tolerate extra keys.
|
|
9
|
+
* 3. **Sidecar `<artifact>.generated`** — a companion file holding the inline-text body, used
|
|
10
|
+
* for strict-schema hosts that reject unknown top-level fields (Gemini's
|
|
11
|
+
* `gemini-extension.json`, Kiro's `.kiro/agents/*.json`).
|
|
12
|
+
*
|
|
13
|
+
* This module is **pure**: string/object in, string out. It performs no filesystem I/O — the
|
|
14
|
+
* build (§5.2) and freshness (§10.5) layers own all reads and writes. It is internal to
|
|
15
|
+
* `@ai-plugin-marketplace/core` and intentionally NOT re-exported from the package root.
|
|
16
|
+
*
|
|
17
|
+
* Round-trip invariants hold for every carrier:
|
|
18
|
+
* - `stripSentinel(applyXSentinel(x, src), mode) === x`
|
|
19
|
+
* - `readSentinelSource(applyXSentinel(x, src), mode) === src`
|
|
20
|
+
*
|
|
21
|
+
* @see docs/specs/architecture.md §4.3 (author-authored vs toolkit-generated — governing section)
|
|
22
|
+
* @see docs/specs/architecture.md §10.5 (freshness check — consumer of the detect/strip helpers)
|
|
23
|
+
* @see docs/specs/architecture.md §5.2 (build phase — consumer of the apply helpers)
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* Canonical generator identity string embedded in every sentinel. Centralized here so the
|
|
27
|
+
* inline comment block, the JSON `_generated.by` field, and any detector all agree on one
|
|
28
|
+
* literal — there is no second copy to drift.
|
|
29
|
+
*/
|
|
30
|
+
export const GENERATOR_ID = '@ai-plugin-marketplace/cli';
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
// Inline-text carrier
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
/** First line of the inline/sidecar comment body. */
|
|
35
|
+
const INLINE_LINE_1 = `# Generated by ${GENERATOR_ID}. Do not edit directly.`;
|
|
36
|
+
/** Second line of the inline/sidecar comment body. */
|
|
37
|
+
const INLINE_LINE_2 = '# Edit the source file listed in the sentinel and run `aipm build`.';
|
|
38
|
+
/** Prefix of the third (source) line; the relative source path is appended verbatim. */
|
|
39
|
+
const INLINE_SOURCE_PREFIX = '# source: ';
|
|
40
|
+
/**
|
|
41
|
+
* Build the canonical inline-text sentinel body for a source path. This three-line block is
|
|
42
|
+
* shared by the inline carrier (prepended to content) and the sidecar carrier (used as the
|
|
43
|
+
* whole sidecar file). Always terminated by a trailing newline so the following content — or
|
|
44
|
+
* the file end, for a sidecar — starts on a fresh line.
|
|
45
|
+
*
|
|
46
|
+
* @param source - Author-authored source path, relative to the plugin directory.
|
|
47
|
+
* @returns The three-line comment block, newline-terminated.
|
|
48
|
+
*/
|
|
49
|
+
function inlineSentinelBlock(source) {
|
|
50
|
+
return `${INLINE_LINE_1}\n${INLINE_LINE_2}\n${INLINE_SOURCE_PREFIX}${source}\n`;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Prepend the inline-text sentinel (§4.3) to a plain-text generated file's content.
|
|
54
|
+
*
|
|
55
|
+
* @param content - The generated file body, sans sentinel.
|
|
56
|
+
* @param source - Author-authored source path, relative to the plugin directory.
|
|
57
|
+
* @returns Content with the three-line sentinel block prepended.
|
|
58
|
+
*/
|
|
59
|
+
export function applyInlineSentinel(content, source) {
|
|
60
|
+
return inlineSentinelBlock(source) + content;
|
|
61
|
+
}
|
|
62
|
+
// ---------------------------------------------------------------------------
|
|
63
|
+
// Sidecar carrier
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
/** Suffix appended to an artifact path to form its sidecar sentinel path. */
|
|
66
|
+
const SIDECAR_SUFFIX = '.generated';
|
|
67
|
+
/**
|
|
68
|
+
* The body of a `<artifact>.generated` sidecar file (§4.3). Identical to the inline-text
|
|
69
|
+
* sentinel block — the sidecar carries no artifact content, only the sentinel.
|
|
70
|
+
*
|
|
71
|
+
* @param source - Author-authored source path, relative to the plugin directory.
|
|
72
|
+
* @returns The three-line sentinel block, newline-terminated.
|
|
73
|
+
*/
|
|
74
|
+
export function sidecarContent(source) {
|
|
75
|
+
return inlineSentinelBlock(source);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Derive the sidecar sentinel path for an artifact: `<artifactPath>.generated` (§4.3). The
|
|
79
|
+
* sidecar sits next to the artifact; the artifact itself is left untouched.
|
|
80
|
+
*
|
|
81
|
+
* @param artifactPath - Path to the strict-schema artifact (e.g. `gemini-extension.json`).
|
|
82
|
+
* @returns The sidecar path.
|
|
83
|
+
*/
|
|
84
|
+
export function sidecarPath(artifactPath) {
|
|
85
|
+
return `${artifactPath}${SIDECAR_SUFFIX}`;
|
|
86
|
+
}
|
|
87
|
+
// ---------------------------------------------------------------------------
|
|
88
|
+
// JSON `_generated`-field carrier
|
|
89
|
+
// ---------------------------------------------------------------------------
|
|
90
|
+
/**
|
|
91
|
+
* Serialize an object as canonical JSON with a top-level `_generated` sentinel (§4.3). The
|
|
92
|
+
* `_generated` key is emitted FIRST, every other own-enumerable key follows in its original
|
|
93
|
+
* order, and the output uses 2-space indentation with a trailing newline — matching the JSON
|
|
94
|
+
* conventions in `claude/transform.ts`'s `serializeClaudeHooksJson`.
|
|
95
|
+
*
|
|
96
|
+
* Any pre-existing `_generated` key on the input is overwritten by the fresh sentinel rather
|
|
97
|
+
* than duplicated, so re-applying is idempotent at the field level.
|
|
98
|
+
*
|
|
99
|
+
* @param obj - The value to serialize. Treated as a string-keyed object; non-object inputs
|
|
100
|
+
* (arrays, primitives) cannot carry a top-level field and are rejected.
|
|
101
|
+
* @param source - Author-authored source path, relative to the plugin directory.
|
|
102
|
+
* @returns Canonical JSON string with `_generated` first and a trailing `\n`.
|
|
103
|
+
* @throws {TypeError} If `obj` is not a plain JSON object (null, array, or primitive).
|
|
104
|
+
*/
|
|
105
|
+
export function applyJsonSentinel(obj, source) {
|
|
106
|
+
if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {
|
|
107
|
+
throw new TypeError('applyJsonSentinel: expected a plain object to carry a top-level _generated field');
|
|
108
|
+
}
|
|
109
|
+
const sentinel = { by: GENERATOR_ID, source };
|
|
110
|
+
// `_generated` first, then every other own key in its original insertion order. Spreading a
|
|
111
|
+
// pre-existing `_generated` would re-introduce it after ours, so drop it from the rest.
|
|
112
|
+
const rest = {};
|
|
113
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
114
|
+
if (key === '_generated')
|
|
115
|
+
continue;
|
|
116
|
+
rest[key] = value;
|
|
117
|
+
}
|
|
118
|
+
const withSentinel = { _generated: sentinel, ...rest };
|
|
119
|
+
return JSON.stringify(withSentinel, null, 2) + '\n';
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Convenience overload for validated Claude hooks data, matching the call shape of
|
|
123
|
+
* `serializeClaudeHooksJson`. Equivalent to {@link applyJsonSentinel} with the hooks object.
|
|
124
|
+
*
|
|
125
|
+
* @param data - Validated {@link ClaudeHooksFile}.
|
|
126
|
+
* @param source - Author-authored source path, relative to the plugin directory.
|
|
127
|
+
* @returns Canonical JSON string with `_generated` first and a trailing `\n`.
|
|
128
|
+
*/
|
|
129
|
+
export function applyJsonSentinelToHooks(data, source) {
|
|
130
|
+
return applyJsonSentinel(data, source);
|
|
131
|
+
}
|
|
132
|
+
// ---------------------------------------------------------------------------
|
|
133
|
+
// Detection / source extraction / stripping (consumed by freshness — §10.5)
|
|
134
|
+
// ---------------------------------------------------------------------------
|
|
135
|
+
/**
|
|
136
|
+
* Parse JSON content into a string-keyed object, returning `undefined` for malformed JSON or
|
|
137
|
+
* any non-object top-level value (array, primitive, null). Used by the JSON-carrier detectors
|
|
138
|
+
* so a hand-corrupted generated file degrades gracefully rather than throwing.
|
|
139
|
+
*/
|
|
140
|
+
function parseJsonObject(content) {
|
|
141
|
+
let parsed;
|
|
142
|
+
try {
|
|
143
|
+
parsed = JSON.parse(content);
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
return undefined;
|
|
147
|
+
}
|
|
148
|
+
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
|
|
149
|
+
return undefined;
|
|
150
|
+
}
|
|
151
|
+
return parsed;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Read the `source` from a JSON `_generated` field, validating that the field is a well-formed
|
|
155
|
+
* {@link JsonSentinelField}. Returns `undefined` if absent or malformed.
|
|
156
|
+
*/
|
|
157
|
+
function readJsonSentinelSource(content) {
|
|
158
|
+
const obj = parseJsonObject(content);
|
|
159
|
+
if (!obj)
|
|
160
|
+
return undefined;
|
|
161
|
+
const generated = obj['_generated'];
|
|
162
|
+
if (typeof generated !== 'object' || generated === null || Array.isArray(generated)) {
|
|
163
|
+
return undefined;
|
|
164
|
+
}
|
|
165
|
+
const source = generated['source'];
|
|
166
|
+
return typeof source === 'string' ? source : undefined;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Read the `source` from an inline/sidecar comment block. Returns `undefined` if the content
|
|
170
|
+
* does not begin with the canonical two-line preamble followed by a `# source:` line.
|
|
171
|
+
*/
|
|
172
|
+
function readInlineSentinelSource(content) {
|
|
173
|
+
const lines = content.split('\n');
|
|
174
|
+
if (lines[0] !== INLINE_LINE_1 || lines[1] !== INLINE_LINE_2)
|
|
175
|
+
return undefined;
|
|
176
|
+
const sourceLine = lines[2];
|
|
177
|
+
if (!sourceLine?.startsWith(INLINE_SOURCE_PREFIX))
|
|
178
|
+
return undefined;
|
|
179
|
+
return sourceLine.slice(INLINE_SOURCE_PREFIX.length);
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Detect whether `content` carries a sentinel for the given carrier (§4.3). For `'sidecar'`,
|
|
183
|
+
* `content` is the sidecar file body (same shape as inline); the artifact itself is never
|
|
184
|
+
* inspected by this function.
|
|
185
|
+
*
|
|
186
|
+
* @param content - File content to inspect (artifact body, or sidecar body for `'sidecar'`).
|
|
187
|
+
* @param mode - Which carrier to check for.
|
|
188
|
+
* @returns `true` iff a well-formed sentinel of that carrier is present.
|
|
189
|
+
*/
|
|
190
|
+
export function hasSentinel(content, mode) {
|
|
191
|
+
return readSentinelSource(content, mode) !== undefined;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Extract the author-authored source path recorded in a sentinel, or `undefined` if no
|
|
195
|
+
* well-formed sentinel of the given carrier is present (§10.5 uses this to identify the source
|
|
196
|
+
* and to distinguish generated files from hand-authored ones).
|
|
197
|
+
*
|
|
198
|
+
* @param content - File content to inspect (artifact body, or sidecar body for `'sidecar'`).
|
|
199
|
+
* @param mode - Which carrier to read.
|
|
200
|
+
* @returns The recorded source path, or `undefined`.
|
|
201
|
+
*/
|
|
202
|
+
export function readSentinelSource(content, mode) {
|
|
203
|
+
switch (mode) {
|
|
204
|
+
case 'inline':
|
|
205
|
+
case 'sidecar':
|
|
206
|
+
return readInlineSentinelSource(content);
|
|
207
|
+
case 'json-field':
|
|
208
|
+
return readJsonSentinelSource(content);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Remove a sentinel from `content`, returning the body sans sentinel. The inverse of the
|
|
213
|
+
* matching `applyXSentinel`, so freshness (§10.5) can compare an on-disk generated file to
|
|
214
|
+
* freshly-built content modulo the sentinel.
|
|
215
|
+
*
|
|
216
|
+
* - `'inline'` — drops the three-line comment block if present; otherwise returns `content`
|
|
217
|
+
* unchanged.
|
|
218
|
+
* - `'sidecar'` — the sidecar carries only the sentinel, so the stripped body is the empty
|
|
219
|
+
* string; if `content` is not a recognized sidecar it is returned unchanged.
|
|
220
|
+
* - `'json-field'` — re-serializes the object without `_generated`, preserving the remaining
|
|
221
|
+
* keys' order, 2-space indent, and trailing newline. Malformed JSON is returned unchanged.
|
|
222
|
+
*
|
|
223
|
+
* @param content - File content to strip.
|
|
224
|
+
* @param mode - Which carrier to strip.
|
|
225
|
+
* @returns The content with its sentinel removed.
|
|
226
|
+
*/
|
|
227
|
+
export function stripSentinel(content, mode) {
|
|
228
|
+
switch (mode) {
|
|
229
|
+
case 'inline':
|
|
230
|
+
return stripInlineSentinel(content);
|
|
231
|
+
case 'sidecar':
|
|
232
|
+
// A sidecar is wholly sentinel; stripping yields an empty body. Leave unrecognized
|
|
233
|
+
// content untouched so a non-sidecar file is not silently emptied.
|
|
234
|
+
return hasSentinel(content, 'sidecar') ? '' : content;
|
|
235
|
+
case 'json-field':
|
|
236
|
+
return stripJsonSentinel(content);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
/** Drop the leading three-line inline sentinel block, if present. */
|
|
240
|
+
function stripInlineSentinel(content) {
|
|
241
|
+
if (readInlineSentinelSource(content) === undefined)
|
|
242
|
+
return content;
|
|
243
|
+
// The block is exactly three newline-terminated lines; remove up to and including the third
|
|
244
|
+
// newline. Locate it without assuming the source path is newline-free beyond line 3.
|
|
245
|
+
const firstNl = content.indexOf('\n');
|
|
246
|
+
const secondNl = content.indexOf('\n', firstNl + 1);
|
|
247
|
+
const thirdNl = content.indexOf('\n', secondNl + 1);
|
|
248
|
+
return content.slice(thirdNl + 1);
|
|
249
|
+
}
|
|
250
|
+
/** Re-serialize JSON content without its `_generated` field; passthrough on malformed JSON. */
|
|
251
|
+
function stripJsonSentinel(content) {
|
|
252
|
+
const obj = parseJsonObject(content);
|
|
253
|
+
if (!obj)
|
|
254
|
+
return content;
|
|
255
|
+
const rest = {};
|
|
256
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
257
|
+
if (key === '_generated')
|
|
258
|
+
continue;
|
|
259
|
+
rest[key] = value;
|
|
260
|
+
}
|
|
261
|
+
return JSON.stringify(rest, null, 2) + '\n';
|
|
262
|
+
}
|
|
263
|
+
//# sourceMappingURL=sentinel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sentinel.js","sourceRoot":"","sources":["../../src/pipeline/sentinel.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public types for the core API. These are the contract surface per §8.1 of the spec.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* A host-platform identity. The closed union of target IDs this toolkit version knows about.
|
|
6
|
+
*
|
|
7
|
+
* Declared as an explicit literal union (matching the public contract in spec §8.1) rather than
|
|
8
|
+
* derived from `TARGET_IDS`. This keeps the public type self-contained: a
|
|
9
|
+
* `typeof TARGET_IDS` derivation would make the published `TargetId` depend on the non-exported
|
|
10
|
+
* `TARGET_IDS` const, which API Extractor reports as `ae-forgotten-export`. The runtime array
|
|
11
|
+
* below is validated against this union with `satisfies`, so the two cannot drift.
|
|
12
|
+
*
|
|
13
|
+
* @public
|
|
14
|
+
*/
|
|
15
|
+
export type TargetId = 'claude' | 'cursor' | 'gemini' | 'kiro' | 'vercel';
|
|
16
|
+
/**
|
|
17
|
+
* Canonical list of target IDs known to this toolkit version. Runtime-exposed so
|
|
18
|
+
* `listTargets()` and config validation share one source of truth.
|
|
19
|
+
*
|
|
20
|
+
* `as const satisfies readonly TargetId[]` preserves the literal tuple type (required by
|
|
21
|
+
* `z.enum`) while guaranteeing every entry is a valid {@link TargetId}. The
|
|
22
|
+
* `_targetIdsAreExhaustive` assertion below closes the other direction (every {@link TargetId}
|
|
23
|
+
* appears here), so the union and the array cannot drift in either direction.
|
|
24
|
+
*
|
|
25
|
+
* Not part of the public API — `index.ts` re-exports only the `TargetId` type, not this runtime
|
|
26
|
+
* array. Marked `@internal` so the release-tag lint rule is satisfied without widening the
|
|
27
|
+
* public surface.
|
|
28
|
+
*
|
|
29
|
+
* @internal
|
|
30
|
+
*/
|
|
31
|
+
export declare const TARGET_IDS: readonly ["claude", "cursor", "gemini", "kiro", "vercel"];
|
|
32
|
+
/**
|
|
33
|
+
* Options for {@link build}.
|
|
34
|
+
*
|
|
35
|
+
* @public
|
|
36
|
+
*/
|
|
37
|
+
export interface BuildOptions {
|
|
38
|
+
/** Abort after the first hard validation finding. Default: false. */
|
|
39
|
+
failFast?: boolean;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Result of building a single plugin. One entry per plugin built.
|
|
43
|
+
*
|
|
44
|
+
* @public
|
|
45
|
+
*/
|
|
46
|
+
export interface BuildResult {
|
|
47
|
+
/** Plugin directory name, e.g. 'skill-evaluator'. */
|
|
48
|
+
plugin: string;
|
|
49
|
+
/** Absolute path to the plugin directory. */
|
|
50
|
+
pluginDir: string;
|
|
51
|
+
/** Every file the build produced or verified as up-to-date. */
|
|
52
|
+
artifacts: GeneratedFile[];
|
|
53
|
+
/** Wall-clock time in milliseconds. */
|
|
54
|
+
durationMs: number;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* A file produced or verified by the build.
|
|
58
|
+
*
|
|
59
|
+
* @public
|
|
60
|
+
*/
|
|
61
|
+
export interface GeneratedFile {
|
|
62
|
+
/** Absolute path. */
|
|
63
|
+
path: string;
|
|
64
|
+
/** The author-authored file this was generated from, if applicable. */
|
|
65
|
+
source?: string;
|
|
66
|
+
/** Which target's build step produced this file. */
|
|
67
|
+
target: TargetId;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Options for {@link validate}.
|
|
71
|
+
*
|
|
72
|
+
* @public
|
|
73
|
+
*/
|
|
74
|
+
export interface ValidateOptions {
|
|
75
|
+
/** When true, skip the freshness check (§10.5). Default: false. */
|
|
76
|
+
skipFreshness?: boolean;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Result of validating one or more plugins.
|
|
80
|
+
*
|
|
81
|
+
* @public
|
|
82
|
+
*/
|
|
83
|
+
export interface ValidationResult {
|
|
84
|
+
findings: Finding[];
|
|
85
|
+
/** True iff no hard findings were emitted. Soft findings do not flip this. */
|
|
86
|
+
passed: boolean;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Enumerated finding codes. Additive — new codes arrive in toolkit MINOR releases; removing
|
|
90
|
+
* or renaming a code is MAJOR. Consumers SHOULD handle unknown codes gracefully.
|
|
91
|
+
*
|
|
92
|
+
* @public
|
|
93
|
+
*/
|
|
94
|
+
export type FindingCode = 'envelope-invalid' | 'envelope-adherence' | 'schema-invalid' | 'name-consistency' | 'mcp-key-sync' | 'marketplace-registration' | 'freshness';
|
|
95
|
+
/**
|
|
96
|
+
* A single validation finding.
|
|
97
|
+
*
|
|
98
|
+
* @public
|
|
99
|
+
*/
|
|
100
|
+
export interface Finding {
|
|
101
|
+
severity: 'hard' | 'soft';
|
|
102
|
+
code: FindingCode;
|
|
103
|
+
/** Plugin name, if the finding is scoped to a specific plugin. */
|
|
104
|
+
plugin?: string;
|
|
105
|
+
/** Human-readable message. */
|
|
106
|
+
message: string;
|
|
107
|
+
/** Optional remediation hint. */
|
|
108
|
+
hint?: string;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Options for {@link scaffold}.
|
|
112
|
+
*
|
|
113
|
+
* @public
|
|
114
|
+
*/
|
|
115
|
+
export interface ScaffoldOptions {
|
|
116
|
+
/** Targets to scaffold for. Defaults to all known targets. */
|
|
117
|
+
targets?: readonly TargetId[];
|
|
118
|
+
/** Description field for the generated plugin. */
|
|
119
|
+
description?: string;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Options for {@link init}.
|
|
123
|
+
*
|
|
124
|
+
* @public
|
|
125
|
+
*/
|
|
126
|
+
export interface InitOptions {
|
|
127
|
+
/**
|
|
128
|
+
* Repo name written into the generated `package.json`. Defaults to the basename of the target
|
|
129
|
+
* directory.
|
|
130
|
+
*/
|
|
131
|
+
name?: string;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Options for {@link migrate}.
|
|
135
|
+
*
|
|
136
|
+
* @public
|
|
137
|
+
*/
|
|
138
|
+
export interface MigrateOptions {
|
|
139
|
+
/** When true, print planned changes without writing. Default: false. */
|
|
140
|
+
dryRun?: boolean;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Result of running {@link migrate}.
|
|
144
|
+
*
|
|
145
|
+
* @public
|
|
146
|
+
*/
|
|
147
|
+
export interface MigrateResult {
|
|
148
|
+
/**
|
|
149
|
+
* Discriminant so consumers distinguish "ran and did nothing" from "ran and applied zero
|
|
150
|
+
* of N" from "ran and failed." Retrofitting this later would be breaking.
|
|
151
|
+
*/
|
|
152
|
+
status: 'no-migrations-needed' | 'applied' | 'failed';
|
|
153
|
+
/** 0 in v0.1.0. */
|
|
154
|
+
migrationsApplied: number;
|
|
155
|
+
/** Absolute paths of files modified. */
|
|
156
|
+
filesChanged: string[];
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Diagnostic report from {@link checkSupport} describing a plugin's support envelope.
|
|
160
|
+
*
|
|
161
|
+
* @public
|
|
162
|
+
*/
|
|
163
|
+
export interface SupportReport {
|
|
164
|
+
plugin: string;
|
|
165
|
+
/** Targets the plugin declares support for. */
|
|
166
|
+
declared: TargetId[];
|
|
167
|
+
/** Declared targets that are missing required artifacts. */
|
|
168
|
+
missingArtifacts: {
|
|
169
|
+
target: TargetId;
|
|
170
|
+
missing: string[];
|
|
171
|
+
}[];
|
|
172
|
+
/** Targets not declared but plausibly addable, with the files the author would need. */
|
|
173
|
+
suggestions: {
|
|
174
|
+
target: TargetId;
|
|
175
|
+
wouldNeed: string[];
|
|
176
|
+
}[];
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/pipeline/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;;;;;GAUG;AACH,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;AAE1E;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,UAAU,2DAMiB,CAAC;AAmBzC;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,qEAAqE;IACrE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,+DAA+D;IAC/D,SAAS,EAAE,aAAa,EAAE,CAAC;IAC3B,uCAAuC;IACvC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,qBAAqB;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,uEAAuE;IACvE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oDAAoD;IACpD,MAAM,EAAE,QAAQ,CAAC;CAClB;AAKD;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,mEAAmE;IACnE,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,8EAA8E;IAC9E,MAAM,EAAE,OAAO,CAAC;CACjB;AAED;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GACnB,kBAAkB,GAClB,oBAAoB,GACpB,gBAAgB,GAChB,kBAAkB,GAClB,cAAc,GACd,0BAA0B,GAC1B,WAAW,CAAC;AAEhB;;;;GAIG;AACH,MAAM,WAAW,OAAO;IACtB,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,IAAI,EAAE,WAAW,CAAC;IAClB,kEAAkE;IAClE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8BAA8B;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,iCAAiC;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAKD;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,8DAA8D;IAC9D,OAAO,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAC;IAC9B,kDAAkD;IAClD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAKD;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAKD;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,wEAAwE;IACxE,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,MAAM,EAAE,sBAAsB,GAAG,SAAS,GAAG,QAAQ,CAAC;IACtD,mBAAmB;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,wCAAwC;IACxC,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAKD;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,QAAQ,EAAE,QAAQ,EAAE,CAAC;IACrB,4DAA4D;IAC5D,gBAAgB,EAAE;QAAE,MAAM,EAAE,QAAQ,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,CAAC;IAC5D,wFAAwF;IACxF,WAAW,EAAE;QAAE,MAAM,EAAE,QAAQ,CAAC;QAAC,SAAS,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,CAAC;CAC1D"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public types for the core API. These are the contract surface per §8.1 of the spec.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Canonical list of target IDs known to this toolkit version. Runtime-exposed so
|
|
6
|
+
* `listTargets()` and config validation share one source of truth.
|
|
7
|
+
*
|
|
8
|
+
* `as const satisfies readonly TargetId[]` preserves the literal tuple type (required by
|
|
9
|
+
* `z.enum`) while guaranteeing every entry is a valid {@link TargetId}. The
|
|
10
|
+
* `_targetIdsAreExhaustive` assertion below closes the other direction (every {@link TargetId}
|
|
11
|
+
* appears here), so the union and the array cannot drift in either direction.
|
|
12
|
+
*
|
|
13
|
+
* Not part of the public API — `index.ts` re-exports only the `TargetId` type, not this runtime
|
|
14
|
+
* array. Marked `@internal` so the release-tag lint rule is satisfied without widening the
|
|
15
|
+
* public surface.
|
|
16
|
+
*
|
|
17
|
+
* @internal
|
|
18
|
+
*/
|
|
19
|
+
export const TARGET_IDS = [
|
|
20
|
+
'claude',
|
|
21
|
+
'cursor',
|
|
22
|
+
'gemini',
|
|
23
|
+
'kiro',
|
|
24
|
+
'vercel',
|
|
25
|
+
];
|
|
26
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/pipeline/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAeH;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,MAAM;IACN,QAAQ;CAC8B,CAAC"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-target validator for the pipeline layer.
|
|
3
|
+
*
|
|
4
|
+
* Implements §10.1 steps 1, 3, 4, and most of 5 (freshness deferred to Stage 5).
|
|
5
|
+
* Step 2 (per-target schema validation) lives in each target's own validate.ts and is
|
|
6
|
+
* not invoked here — this module is concerned only with cross-target consistency.
|
|
7
|
+
*
|
|
8
|
+
* @see docs/specs/architecture.md §6, §8.1, §10.1, §10.2
|
|
9
|
+
*/
|
|
10
|
+
import type { Finding, TargetId, ValidateOptions, ValidationResult } from './types.js';
|
|
11
|
+
/**
|
|
12
|
+
* Minimum required artifacts for each target. Missing any of these when the target is
|
|
13
|
+
* in the envelope is an adherence violation.
|
|
14
|
+
* Vercel requires at least one skills/<name>/SKILL.md — handled specially below.
|
|
15
|
+
*/
|
|
16
|
+
export declare const TARGET_MIN_REQUIRED: Record<TargetId, string[]>;
|
|
17
|
+
/**
|
|
18
|
+
* Validate an already-loaded `aipm.config.ts` value against AipmConfig's Zod schema.
|
|
19
|
+
* Loading from disk is the pipeline orchestrator's job (Stage 5). Here we only validate shape.
|
|
20
|
+
* Emits `envelope-invalid` findings on malformed input.
|
|
21
|
+
*
|
|
22
|
+
* `pluginName` is used to populate Finding.plugin.
|
|
23
|
+
*/
|
|
24
|
+
export declare function validateEnvelopeShape(rawConfig: unknown, pluginName: string): Finding[];
|
|
25
|
+
/**
|
|
26
|
+
* For each target in the envelope: verify the plugin provides the minimum required artifacts.
|
|
27
|
+
* For each target NOT in the envelope: verify no target-specific artifacts exist for it.
|
|
28
|
+
*
|
|
29
|
+
* Emits `envelope-adherence` findings.
|
|
30
|
+
*/
|
|
31
|
+
export declare function validateEnvelopeAdherence(pluginDir: string, envelope: readonly TargetId[]): Finding[];
|
|
32
|
+
/**
|
|
33
|
+
* Check that the plugin directory name matches the `name` field in every declared target's
|
|
34
|
+
* manifest. Reads each manifest and parses its `name` field (doesn't re-run the full schema —
|
|
35
|
+
* just extracts name).
|
|
36
|
+
*
|
|
37
|
+
* Emits `name-consistency` findings, one per mismatched manifest.
|
|
38
|
+
*/
|
|
39
|
+
export declare function validateNameConsistency(pluginDir: string, envelope: readonly TargetId[]): Finding[];
|
|
40
|
+
/**
|
|
41
|
+
* When both Claude/Cursor (.mcp.json) and Kiro (mcp.json) are in the envelope, the set of
|
|
42
|
+
* mcpServers keys must match between them. Skip the check if fewer than two MCP-consuming
|
|
43
|
+
* targets are in the envelope.
|
|
44
|
+
*
|
|
45
|
+
* Emits `mcp-key-sync` findings.
|
|
46
|
+
*/
|
|
47
|
+
export declare function validateMcpKeySync(pluginDir: string, envelope: readonly TargetId[]): Finding[];
|
|
48
|
+
/**
|
|
49
|
+
* Verify the plugin is listed in the appropriate template-level marketplace.json files.
|
|
50
|
+
*
|
|
51
|
+
* - If `claude` is in the envelope, the plugin MUST appear in `<repoRoot>/.claude-plugin/marketplace.json`'s
|
|
52
|
+
* plugins array with name matching directory basename and source pointing at `./plugins/<name>`.
|
|
53
|
+
* - If `cursor` is in the envelope, same check against `<repoRoot>/.cursor-plugin/marketplace.json`.
|
|
54
|
+
* - If a target is NOT in the envelope, the plugin MUST NOT be listed in that marketplace.
|
|
55
|
+
*
|
|
56
|
+
* Emits `marketplace-registration` findings.
|
|
57
|
+
*/
|
|
58
|
+
export declare function validateMarketplaceRegistration(pluginDir: string, repoRoot: string, envelope: readonly TargetId[]): Finding[];
|
|
59
|
+
/**
|
|
60
|
+
* Convenience: run all cross-target validators for a single plugin and combine findings.
|
|
61
|
+
* Stage 5's pipeline operations.ts uses this.
|
|
62
|
+
*
|
|
63
|
+
* Note: validateEnvelopeShape is excluded here because the caller must already have a
|
|
64
|
+
* parsed envelope (TargetId[]) — meaning shape validation already passed. Shape validation
|
|
65
|
+
* must be done separately before calling this function.
|
|
66
|
+
*/
|
|
67
|
+
export declare function validateCrossTarget(pluginDir: string, repoRoot: string, envelope: readonly TargetId[]): Finding[];
|
|
68
|
+
/**
|
|
69
|
+
* Validate one plugin or every plugin under a repo root (§5.3). Runs the validators in the order
|
|
70
|
+
* mandated by §10.1 / §10.3:
|
|
71
|
+
*
|
|
72
|
+
* 1. Envelope load + shape validation. A load/shape failure emits `envelope-invalid` and
|
|
73
|
+
* **skips all further checks for that plugin** (no point validating an undeclared target).
|
|
74
|
+
* 2. Per-target schema validation (each declared target's `validate.ts`). Schema errors
|
|
75
|
+
* **block cross-target checks** for that plugin (§10.3).
|
|
76
|
+
* 3. Envelope adherence.
|
|
77
|
+
* 4. Cross-target consistency (only when the envelope has more than one target and no blocking
|
|
78
|
+
* schema errors): name consistency, MCP key sync, marketplace registration.
|
|
79
|
+
* 5. Freshness (unless `opts.skipFreshness`). Severity is `hard` in CI, `soft` locally (§10.2).
|
|
80
|
+
*
|
|
81
|
+
* `passed` is `true` iff no **hard** findings were emitted (§10.2).
|
|
82
|
+
*
|
|
83
|
+
* @param targetPath - Absolute path to a single plugin directory or a repo root.
|
|
84
|
+
* @param opts - Validate options. `ci` controls freshness severity (default: local/soft).
|
|
85
|
+
* @returns The combined validation result.
|
|
86
|
+
*/
|
|
87
|
+
export declare function runValidate(targetPath: string, opts?: ValidateOptions & {
|
|
88
|
+
ci?: boolean;
|
|
89
|
+
}): Promise<ValidationResult>;
|
|
90
|
+
//# sourceMappingURL=validate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/pipeline/validate.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAqBH,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAgCvF;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,CAM1D,CAAC;AA4DF;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,EAAE,CAsBvF;AAMD;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,SAAS,QAAQ,EAAE,GAC5B,OAAO,EAAE,CA4FX;AAMD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,SAAS,QAAQ,EAAE,GAC5B,OAAO,EAAE,CAkFX;AAMD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,QAAQ,EAAE,GAAG,OAAO,EAAE,CAgD9F;AAMD;;;;;;;;;GASG;AACH,wBAAgB,+BAA+B,CAC7C,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,SAAS,QAAQ,EAAE,GAC5B,OAAO,EAAE,CAqGX;AAMD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,SAAS,QAAQ,EAAE,GAC5B,OAAO,EAAE,CAOX;AA+KD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,WAAW,CAC/B,UAAU,EAAE,MAAM,EAClB,IAAI,CAAC,EAAE,eAAe,GAAG;IAAE,EAAE,CAAC,EAAE,OAAO,CAAA;CAAE,GACxC,OAAO,CAAC,gBAAgB,CAAC,CAwD3B"}
|