@skillmark/cli 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/dist/cli-entry-point.d.ts +3 -0
- package/dist/cli-entry-point.d.ts.map +1 -0
- package/dist/cli-entry-point.js +207 -0
- package/dist/cli-entry-point.js.map +1 -0
- package/dist/commands/auth-setup-and-token-storage-command.d.ts +21 -0
- package/dist/commands/auth-setup-and-token-storage-command.d.ts.map +1 -0
- package/dist/commands/auth-setup-and-token-storage-command.js +166 -0
- package/dist/commands/auth-setup-and-token-storage-command.js.map +1 -0
- package/dist/commands/publish-results-command.d.ts +21 -0
- package/dist/commands/publish-results-command.d.ts.map +1 -0
- package/dist/commands/publish-results-command.js +256 -0
- package/dist/commands/publish-results-command.js.map +1 -0
- package/dist/commands/run-benchmark-command.d.ts +6 -0
- package/dist/commands/run-benchmark-command.d.ts.map +1 -0
- package/dist/commands/run-benchmark-command.js +331 -0
- package/dist/commands/run-benchmark-command.js.map +1 -0
- package/dist/commands/view-leaderboard-command.d.ts +8 -0
- package/dist/commands/view-leaderboard-command.d.ts.map +1 -0
- package/dist/commands/view-leaderboard-command.js +169 -0
- package/dist/commands/view-leaderboard-command.js.map +1 -0
- package/dist/config/api-key-config-reader.d.ts +14 -0
- package/dist/config/api-key-config-reader.d.ts.map +1 -0
- package/dist/config/api-key-config-reader.js +107 -0
- package/dist/config/api-key-config-reader.js.map +1 -0
- package/dist/config/api-key-config-reader.test.d.ts +2 -0
- package/dist/config/api-key-config-reader.test.d.ts.map +1 -0
- package/dist/config/api-key-config-reader.test.js +21 -0
- package/dist/config/api-key-config-reader.test.js.map +1 -0
- package/dist/engine/claude-cli-executor.d.ts +33 -0
- package/dist/engine/claude-cli-executor.d.ts.map +1 -0
- package/dist/engine/claude-cli-executor.js +251 -0
- package/dist/engine/claude-cli-executor.js.map +1 -0
- package/dist/engine/concept-accuracy-scorer.d.ts +24 -0
- package/dist/engine/concept-accuracy-scorer.d.ts.map +1 -0
- package/dist/engine/concept-accuracy-scorer.js +186 -0
- package/dist/engine/concept-accuracy-scorer.js.map +1 -0
- package/dist/engine/concept-accuracy-scorer.test.d.ts +2 -0
- package/dist/engine/concept-accuracy-scorer.test.d.ts.map +1 -0
- package/dist/engine/concept-accuracy-scorer.test.js +230 -0
- package/dist/engine/concept-accuracy-scorer.test.js.map +1 -0
- package/dist/engine/enhanced-test-prompt-builder.d.ts +30 -0
- package/dist/engine/enhanced-test-prompt-builder.d.ts.map +1 -0
- package/dist/engine/enhanced-test-prompt-builder.js +134 -0
- package/dist/engine/enhanced-test-prompt-builder.js.map +1 -0
- package/dist/engine/markdown-test-definition-parser.d.ts +18 -0
- package/dist/engine/markdown-test-definition-parser.d.ts.map +1 -0
- package/dist/engine/markdown-test-definition-parser.js +525 -0
- package/dist/engine/markdown-test-definition-parser.js.map +1 -0
- package/dist/engine/markdown-test-definition-parser.test.d.ts +2 -0
- package/dist/engine/markdown-test-definition-parser.test.d.ts.map +1 -0
- package/dist/engine/markdown-test-definition-parser.test.js +265 -0
- package/dist/engine/markdown-test-definition-parser.test.js.map +1 -0
- package/dist/engine/retry-with-degrade-utils.d.ts +58 -0
- package/dist/engine/retry-with-degrade-utils.d.ts.map +1 -0
- package/dist/engine/retry-with-degrade-utils.js +86 -0
- package/dist/engine/retry-with-degrade-utils.js.map +1 -0
- package/dist/engine/skill-content-collector.d.ts +53 -0
- package/dist/engine/skill-content-collector.d.ts.map +1 -0
- package/dist/engine/skill-content-collector.js +157 -0
- package/dist/engine/skill-content-collector.js.map +1 -0
- package/dist/engine/skill-creator-invoker.d.ts +36 -0
- package/dist/engine/skill-creator-invoker.d.ts.map +1 -0
- package/dist/engine/skill-creator-invoker.js +222 -0
- package/dist/engine/skill-creator-invoker.js.map +1 -0
- package/dist/engine/transcript-jsonl-parser.d.ts +28 -0
- package/dist/engine/transcript-jsonl-parser.d.ts.map +1 -0
- package/dist/engine/transcript-jsonl-parser.js +175 -0
- package/dist/engine/transcript-jsonl-parser.js.map +1 -0
- package/dist/sources/git-repository-skill-source-handler.d.ts +18 -0
- package/dist/sources/git-repository-skill-source-handler.d.ts.map +1 -0
- package/dist/sources/git-repository-skill-source-handler.js +119 -0
- package/dist/sources/git-repository-skill-source-handler.js.map +1 -0
- package/dist/sources/local-skill-source-handler.d.ts +21 -0
- package/dist/sources/local-skill-source-handler.d.ts.map +1 -0
- package/dist/sources/local-skill-source-handler.js +138 -0
- package/dist/sources/local-skill-source-handler.js.map +1 -0
- package/dist/sources/local-skill-source-handler.test.d.ts +2 -0
- package/dist/sources/local-skill-source-handler.test.d.ts.map +1 -0
- package/dist/sources/local-skill-source-handler.test.js +55 -0
- package/dist/sources/local-skill-source-handler.test.js.map +1 -0
- package/dist/sources/skillsh-registry-source-handler.d.ts +18 -0
- package/dist/sources/skillsh-registry-source-handler.d.ts.map +1 -0
- package/dist/sources/skillsh-registry-source-handler.js +130 -0
- package/dist/sources/skillsh-registry-source-handler.js.map +1 -0
- package/dist/sources/unified-skill-source-resolver.d.ts +20 -0
- package/dist/sources/unified-skill-source-resolver.d.ts.map +1 -0
- package/dist/sources/unified-skill-source-resolver.js +64 -0
- package/dist/sources/unified-skill-source-resolver.js.map +1 -0
- package/dist/sources/unified-skill-source-resolver.test.d.ts +2 -0
- package/dist/sources/unified-skill-source-resolver.test.d.ts.map +1 -0
- package/dist/sources/unified-skill-source-resolver.test.js +84 -0
- package/dist/sources/unified-skill-source-resolver.test.js.map +1 -0
- package/dist/types/benchmark-types.d.ts +142 -0
- package/dist/types/benchmark-types.d.ts.map +1 -0
- package/dist/types/benchmark-types.js +5 -0
- package/dist/types/benchmark-types.js.map +1 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +5 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +38 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for markdown-test-definition-parser.ts
|
|
3
|
+
* Verifies parsing of test markdown files with YAML frontmatter
|
|
4
|
+
*/
|
|
5
|
+
import { describe, it, expect } from 'vitest';
|
|
6
|
+
import { parseTestContent } from './markdown-test-definition-parser.js';
|
|
7
|
+
describe('parseTestContent', () => {
|
|
8
|
+
describe('frontmatter parsing', () => {
|
|
9
|
+
it('parses name from frontmatter', () => {
|
|
10
|
+
const content = `---
|
|
11
|
+
name: my-test
|
|
12
|
+
type: knowledge
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# Prompt
|
|
16
|
+
What is the answer?
|
|
17
|
+
|
|
18
|
+
# Expected
|
|
19
|
+
- Correct response`;
|
|
20
|
+
const result = parseTestContent(content, 'test.md');
|
|
21
|
+
expect(result.name).toBe('my-test');
|
|
22
|
+
});
|
|
23
|
+
it('throws error when name is missing', () => {
|
|
24
|
+
const content = `---
|
|
25
|
+
type: knowledge
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
# Prompt
|
|
29
|
+
What is the answer?
|
|
30
|
+
|
|
31
|
+
# Expected
|
|
32
|
+
- Correct`;
|
|
33
|
+
expect(() => parseTestContent(content, 'test.md')).toThrow("Test file missing required 'name' field");
|
|
34
|
+
});
|
|
35
|
+
it('parses type with default to knowledge', () => {
|
|
36
|
+
const content = `---
|
|
37
|
+
name: test-with-type
|
|
38
|
+
type: task
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
# Prompt
|
|
42
|
+
Do something
|
|
43
|
+
|
|
44
|
+
# Expected
|
|
45
|
+
- Done`;
|
|
46
|
+
const result = parseTestContent(content, 'test.md');
|
|
47
|
+
expect(result.type).toBe('task');
|
|
48
|
+
// Test default
|
|
49
|
+
const contentNoType = `---
|
|
50
|
+
name: test-no-type
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
# Prompt
|
|
54
|
+
Question?
|
|
55
|
+
|
|
56
|
+
# Expected
|
|
57
|
+
- Answer`;
|
|
58
|
+
const resultDefault = parseTestContent(contentNoType, 'default.md');
|
|
59
|
+
expect(resultDefault.type).toBe('knowledge');
|
|
60
|
+
});
|
|
61
|
+
it('parses timeout with default to 600', () => {
|
|
62
|
+
const content = `---
|
|
63
|
+
name: test-timeout
|
|
64
|
+
timeout: 1800
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
# Prompt
|
|
68
|
+
Long task
|
|
69
|
+
|
|
70
|
+
# Expected
|
|
71
|
+
- Complete`;
|
|
72
|
+
const result = parseTestContent(content, 'test.md');
|
|
73
|
+
expect(result.timeout).toBe(1800);
|
|
74
|
+
// Test default
|
|
75
|
+
const contentNoTimeout = `---
|
|
76
|
+
name: test-default-timeout
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
# Prompt
|
|
80
|
+
Question
|
|
81
|
+
|
|
82
|
+
# Expected
|
|
83
|
+
- Answer`;
|
|
84
|
+
const resultDefault = parseTestContent(contentNoTimeout, 'default.md');
|
|
85
|
+
expect(resultDefault.timeout).toBe(600);
|
|
86
|
+
});
|
|
87
|
+
it('parses concepts array from frontmatter', () => {
|
|
88
|
+
const content = `---
|
|
89
|
+
name: test-concepts
|
|
90
|
+
concepts:
|
|
91
|
+
- orchestrator
|
|
92
|
+
- consensus
|
|
93
|
+
- isolation
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
# Prompt
|
|
97
|
+
Explain multi-agent systems
|
|
98
|
+
|
|
99
|
+
# Expected
|
|
100
|
+
- Covers key concepts`;
|
|
101
|
+
const result = parseTestContent(content, 'test.md');
|
|
102
|
+
expect(result.concepts).toContain('orchestrator');
|
|
103
|
+
expect(result.concepts).toContain('consensus');
|
|
104
|
+
expect(result.concepts).toContain('isolation');
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
describe('section parsing', () => {
|
|
108
|
+
it('extracts prompt from # Prompt section', () => {
|
|
109
|
+
const content = `---
|
|
110
|
+
name: test-prompt
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
# Prompt
|
|
114
|
+
This is the prompt text.
|
|
115
|
+
It can span multiple lines.
|
|
116
|
+
|
|
117
|
+
# Expected
|
|
118
|
+
- Expected output`;
|
|
119
|
+
const result = parseTestContent(content, 'test.md');
|
|
120
|
+
expect(result.prompt).toBe('This is the prompt text.\nIt can span multiple lines.');
|
|
121
|
+
});
|
|
122
|
+
it('extracts prompt from # Question section as fallback', () => {
|
|
123
|
+
const content = `---
|
|
124
|
+
name: test-question
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
# Question
|
|
128
|
+
What is 2 + 2?
|
|
129
|
+
|
|
130
|
+
# Expected
|
|
131
|
+
- 4`;
|
|
132
|
+
const result = parseTestContent(content, 'test.md');
|
|
133
|
+
expect(result.prompt).toBe('What is 2 + 2?');
|
|
134
|
+
});
|
|
135
|
+
it('throws error when prompt section is missing', () => {
|
|
136
|
+
const content = `---
|
|
137
|
+
name: test-no-prompt
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
# Expected
|
|
141
|
+
- Something`;
|
|
142
|
+
expect(() => parseTestContent(content, 'test.md')).toThrow("Test file missing 'Prompt' or 'Question' section");
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
describe('expected patterns parsing', () => {
|
|
146
|
+
it('parses checkbox items', () => {
|
|
147
|
+
const content = `---
|
|
148
|
+
name: test-checkbox
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
# Prompt
|
|
152
|
+
Question?
|
|
153
|
+
|
|
154
|
+
# Expected
|
|
155
|
+
- [ ] First item
|
|
156
|
+
- [x] Second item (checked)
|
|
157
|
+
- [ ] Third item`;
|
|
158
|
+
const result = parseTestContent(content, 'test.md');
|
|
159
|
+
expect(result.expected).toContain('First item');
|
|
160
|
+
expect(result.expected).toContain('Second item (checked)');
|
|
161
|
+
expect(result.expected).toContain('Third item');
|
|
162
|
+
});
|
|
163
|
+
it('parses bullet list items', () => {
|
|
164
|
+
const content = `---
|
|
165
|
+
name: test-bullets
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
# Prompt
|
|
169
|
+
Question?
|
|
170
|
+
|
|
171
|
+
# Expected
|
|
172
|
+
- First bullet
|
|
173
|
+
- Second bullet
|
|
174
|
+
* Asterisk bullet`;
|
|
175
|
+
const result = parseTestContent(content, 'test.md');
|
|
176
|
+
expect(result.expected).toContain('First bullet');
|
|
177
|
+
expect(result.expected).toContain('Second bullet');
|
|
178
|
+
expect(result.expected).toContain('Asterisk bullet');
|
|
179
|
+
});
|
|
180
|
+
it('parses numbered list items', () => {
|
|
181
|
+
const content = `---
|
|
182
|
+
name: test-numbered
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
# Prompt
|
|
186
|
+
Question?
|
|
187
|
+
|
|
188
|
+
# Expected
|
|
189
|
+
1. First item
|
|
190
|
+
2. Second item
|
|
191
|
+
3. Third item`;
|
|
192
|
+
const result = parseTestContent(content, 'test.md');
|
|
193
|
+
expect(result.expected).toContain('First item');
|
|
194
|
+
expect(result.expected).toContain('Second item');
|
|
195
|
+
expect(result.expected).toContain('Third item');
|
|
196
|
+
});
|
|
197
|
+
it('extracts concepts from expected patterns with quotes', () => {
|
|
198
|
+
const content = `---
|
|
199
|
+
name: test-quoted-concepts
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
# Prompt
|
|
203
|
+
Question?
|
|
204
|
+
|
|
205
|
+
# Expected
|
|
206
|
+
- Should mention "orchestrator" pattern
|
|
207
|
+
- Include "context isolation" technique`;
|
|
208
|
+
const result = parseTestContent(content, 'test.md');
|
|
209
|
+
expect(result.concepts).toContain('orchestrator');
|
|
210
|
+
expect(result.concepts).toContain('context isolation');
|
|
211
|
+
});
|
|
212
|
+
it('extracts concepts from backticked terms', () => {
|
|
213
|
+
const content = `---
|
|
214
|
+
name: test-backtick-concepts
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
# Prompt
|
|
218
|
+
Question?
|
|
219
|
+
|
|
220
|
+
# Expected
|
|
221
|
+
- Uses \`spawn\` function
|
|
222
|
+
- Calls \`Task\` tool`;
|
|
223
|
+
const result = parseTestContent(content, 'test.md');
|
|
224
|
+
expect(result.concepts).toContain('spawn');
|
|
225
|
+
expect(result.concepts).toContain('Task');
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
describe('concept deduplication', () => {
|
|
229
|
+
it('removes duplicate concepts', () => {
|
|
230
|
+
const content = `---
|
|
231
|
+
name: test-dedup
|
|
232
|
+
concepts:
|
|
233
|
+
- orchestrator
|
|
234
|
+
- consensus
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
# Prompt
|
|
238
|
+
Question?
|
|
239
|
+
|
|
240
|
+
# Expected
|
|
241
|
+
- Uses "orchestrator" pattern
|
|
242
|
+
- Implements "consensus"`;
|
|
243
|
+
const result = parseTestContent(content, 'test.md');
|
|
244
|
+
// Should have unique concepts only
|
|
245
|
+
const orchestratorCount = result.concepts.filter((c) => c === 'orchestrator').length;
|
|
246
|
+
expect(orchestratorCount).toBe(1);
|
|
247
|
+
});
|
|
248
|
+
});
|
|
249
|
+
describe('sourcePath tracking', () => {
|
|
250
|
+
it('includes source path in result', () => {
|
|
251
|
+
const content = `---
|
|
252
|
+
name: test-source
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
# Prompt
|
|
256
|
+
Q
|
|
257
|
+
|
|
258
|
+
# Expected
|
|
259
|
+
- A`;
|
|
260
|
+
const result = parseTestContent(content, '/path/to/test.md');
|
|
261
|
+
expect(result.sourcePath).toBe('/path/to/test.md');
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
//# sourceMappingURL=markdown-test-definition-parser.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-test-definition-parser.test.js","sourceRoot":"","sources":["../../src/engine/markdown-test-definition-parser.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retry-then-degrade utilities for graceful error handling.
|
|
3
|
+
*
|
|
4
|
+
* Provides retry logic with exponential backoff and graceful
|
|
5
|
+
* degradation when operations fail after exhausting retries.
|
|
6
|
+
*/
|
|
7
|
+
/** Options for retry behavior */
|
|
8
|
+
export interface RetryOptions {
|
|
9
|
+
/** Maximum number of retry attempts (default: 1) */
|
|
10
|
+
maxRetries?: number;
|
|
11
|
+
/** Initial delay between retries in milliseconds (default: 1000) */
|
|
12
|
+
delayMs?: number;
|
|
13
|
+
/** Whether to use exponential backoff (default: false) */
|
|
14
|
+
exponentialBackoff?: boolean;
|
|
15
|
+
/** Optional callback for logging retry attempts */
|
|
16
|
+
onRetry?: (attempt: number, error: Error) => void;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Sleep for a specified duration
|
|
20
|
+
*/
|
|
21
|
+
export declare function sleep(ms: number): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Execute a function with retry logic and graceful degradation.
|
|
24
|
+
*
|
|
25
|
+
* Attempts the function up to maxRetries times. If all attempts fail,
|
|
26
|
+
* returns null instead of throwing, allowing callers to gracefully
|
|
27
|
+
* degrade to fallback behavior.
|
|
28
|
+
*
|
|
29
|
+
* @param fn - Async function to execute
|
|
30
|
+
* @param options - Retry configuration
|
|
31
|
+
* @returns Result of fn, or null if all attempts fail
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* const result = await withRetry(
|
|
36
|
+
* () => invokeSkillCreator(skillPath),
|
|
37
|
+
* { maxRetries: 1, delayMs: 1000 }
|
|
38
|
+
* );
|
|
39
|
+
*
|
|
40
|
+
* if (!result) {
|
|
41
|
+
* // Gracefully degrade to basic generation
|
|
42
|
+
* return generateFallbackTests(skillPath);
|
|
43
|
+
* }
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare function withRetry<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T | null>;
|
|
47
|
+
/**
|
|
48
|
+
* Execute multiple functions with retry, returning the first successful result.
|
|
49
|
+
*
|
|
50
|
+
* Tries each function in order, applying retry logic to each.
|
|
51
|
+
* Returns the first successful result, or null if all fail.
|
|
52
|
+
*
|
|
53
|
+
* @param fns - Array of async functions to try in order
|
|
54
|
+
* @param options - Retry configuration for each function
|
|
55
|
+
* @returns First successful result, or null if all fail
|
|
56
|
+
*/
|
|
57
|
+
export declare function withRetryChain<T>(fns: Array<() => Promise<T>>, options?: RetryOptions): Promise<T | null>;
|
|
58
|
+
//# sourceMappingURL=retry-with-degrade-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry-with-degrade-utils.d.ts","sourceRoot":"","sources":["../../src/engine/retry-with-degrade-utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,iCAAiC;AACjC,MAAM,WAAW,YAAY;IAC3B,oDAAoD;IACpD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0DAA0D;IAC1D,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,mDAAmD;IACnD,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CACnD;AASD;;GAEG;AACH,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/C;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAC/B,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CA8BnB;AAED;;;;;;;;;GASG;AACH,wBAAsB,cAAc,CAAC,CAAC,EACpC,GAAG,EAAE,KAAK,CAAC,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC,EAC5B,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAQnB"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retry-then-degrade utilities for graceful error handling.
|
|
3
|
+
*
|
|
4
|
+
* Provides retry logic with exponential backoff and graceful
|
|
5
|
+
* degradation when operations fail after exhausting retries.
|
|
6
|
+
*/
|
|
7
|
+
/** Default retry options */
|
|
8
|
+
const DEFAULT_RETRY_OPTIONS = {
|
|
9
|
+
maxRetries: 1,
|
|
10
|
+
delayMs: 1000,
|
|
11
|
+
exponentialBackoff: false,
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Sleep for a specified duration
|
|
15
|
+
*/
|
|
16
|
+
export function sleep(ms) {
|
|
17
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Execute a function with retry logic and graceful degradation.
|
|
21
|
+
*
|
|
22
|
+
* Attempts the function up to maxRetries times. If all attempts fail,
|
|
23
|
+
* returns null instead of throwing, allowing callers to gracefully
|
|
24
|
+
* degrade to fallback behavior.
|
|
25
|
+
*
|
|
26
|
+
* @param fn - Async function to execute
|
|
27
|
+
* @param options - Retry configuration
|
|
28
|
+
* @returns Result of fn, or null if all attempts fail
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```ts
|
|
32
|
+
* const result = await withRetry(
|
|
33
|
+
* () => invokeSkillCreator(skillPath),
|
|
34
|
+
* { maxRetries: 1, delayMs: 1000 }
|
|
35
|
+
* );
|
|
36
|
+
*
|
|
37
|
+
* if (!result) {
|
|
38
|
+
* // Gracefully degrade to basic generation
|
|
39
|
+
* return generateFallbackTests(skillPath);
|
|
40
|
+
* }
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export async function withRetry(fn, options = {}) {
|
|
44
|
+
const opts = { ...DEFAULT_RETRY_OPTIONS, ...options };
|
|
45
|
+
for (let attempt = 0; attempt <= opts.maxRetries; attempt++) {
|
|
46
|
+
try {
|
|
47
|
+
return await fn();
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
const isLastAttempt = attempt === opts.maxRetries;
|
|
51
|
+
if (opts.onRetry && !isLastAttempt) {
|
|
52
|
+
opts.onRetry(attempt + 1, error);
|
|
53
|
+
}
|
|
54
|
+
if (isLastAttempt) {
|
|
55
|
+
console.warn(`Failed after ${attempt + 1} attempt(s), degrading gracefully: ${error.message}`);
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
// Calculate delay with optional exponential backoff
|
|
59
|
+
const delay = opts.exponentialBackoff
|
|
60
|
+
? opts.delayMs * Math.pow(2, attempt)
|
|
61
|
+
: opts.delayMs;
|
|
62
|
+
await sleep(delay);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Execute multiple functions with retry, returning the first successful result.
|
|
69
|
+
*
|
|
70
|
+
* Tries each function in order, applying retry logic to each.
|
|
71
|
+
* Returns the first successful result, or null if all fail.
|
|
72
|
+
*
|
|
73
|
+
* @param fns - Array of async functions to try in order
|
|
74
|
+
* @param options - Retry configuration for each function
|
|
75
|
+
* @returns First successful result, or null if all fail
|
|
76
|
+
*/
|
|
77
|
+
export async function withRetryChain(fns, options = {}) {
|
|
78
|
+
for (const fn of fns) {
|
|
79
|
+
const result = await withRetry(fn, options);
|
|
80
|
+
if (result !== null) {
|
|
81
|
+
return result;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=retry-with-degrade-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry-with-degrade-utils.js","sourceRoot":"","sources":["../../src/engine/retry-with-degrade-utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAcH,4BAA4B;AAC5B,MAAM,qBAAqB,GAA4C;IACrE,UAAU,EAAE,CAAC;IACb,OAAO,EAAE,IAAI;IACb,kBAAkB,EAAE,KAAK;CAC1B,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,KAAK,CAAC,EAAU;IAC9B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,EAAoB,EACpB,UAAwB,EAAE;IAE1B,MAAM,IAAI,GAAG,EAAE,GAAG,qBAAqB,EAAE,GAAG,OAAO,EAAE,CAAC;IAEtD,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,EAAE,CAAC;QAC5D,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,EAAE,CAAC;QACpB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,aAAa,GAAG,OAAO,KAAK,IAAI,CAAC,UAAU,CAAC;YAElD,IAAI,IAAI,CAAC,OAAO,IAAI,CAAC,aAAa,EAAE,CAAC;gBACnC,IAAI,CAAC,OAAO,CAAC,OAAO,GAAG,CAAC,EAAE,KAAc,CAAC,CAAC;YAC5C,CAAC;YAED,IAAI,aAAa,EAAE,CAAC;gBAClB,OAAO,CAAC,IAAI,CACV,gBAAgB,OAAO,GAAG,CAAC,sCAAuC,KAAe,CAAC,OAAO,EAAE,CAC5F,CAAC;gBACF,OAAO,IAAI,CAAC;YACd,CAAC;YAED,oDAAoD;YACpD,MAAM,KAAK,GAAG,IAAI,CAAC,kBAAkB;gBACnC,CAAC,CAAC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC;gBACrC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;YAEjB,MAAM,KAAK,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,GAA4B,EAC5B,UAAwB,EAAE;IAE1B,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;QACrB,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QAC5C,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,OAAO,MAAM,CAAC;QAChB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/** Collected skill content for Claude analysis */
|
|
2
|
+
export interface SkillContent {
|
|
3
|
+
/** Skill name from frontmatter */
|
|
4
|
+
skillName: string;
|
|
5
|
+
/** Full SKILL.md content */
|
|
6
|
+
skillMd: string;
|
|
7
|
+
/** Reference files (filename -> content) */
|
|
8
|
+
references: Map<string, string>;
|
|
9
|
+
/** Script files (filename -> first 100 lines) */
|
|
10
|
+
scripts: Map<string, string>;
|
|
11
|
+
}
|
|
12
|
+
/** Validation result */
|
|
13
|
+
export interface ValidationResult {
|
|
14
|
+
valid: boolean;
|
|
15
|
+
message: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Skill content collector - gathers skill files for test generation
|
|
19
|
+
*/
|
|
20
|
+
export declare class SkillContentCollector {
|
|
21
|
+
private skillPath;
|
|
22
|
+
private skillMdPath;
|
|
23
|
+
constructor(skillPath: string);
|
|
24
|
+
/**
|
|
25
|
+
* Validate skill has required SKILL.md with YAML frontmatter
|
|
26
|
+
*/
|
|
27
|
+
validate(): Promise<ValidationResult>;
|
|
28
|
+
/**
|
|
29
|
+
* Extract skill name from SKILL.md frontmatter
|
|
30
|
+
*/
|
|
31
|
+
getSkillName(): Promise<string | null>;
|
|
32
|
+
/**
|
|
33
|
+
* Read SKILL.md content
|
|
34
|
+
*/
|
|
35
|
+
collectSkillMd(): Promise<string>;
|
|
36
|
+
/**
|
|
37
|
+
* Collect all markdown files from references/ directory
|
|
38
|
+
*/
|
|
39
|
+
collectReferences(): Promise<Map<string, string>>;
|
|
40
|
+
/**
|
|
41
|
+
* Collect Python scripts from scripts/ directory (first 100 lines)
|
|
42
|
+
*/
|
|
43
|
+
collectScripts(): Promise<Map<string, string>>;
|
|
44
|
+
/**
|
|
45
|
+
* Collect all skill content for Claude analysis
|
|
46
|
+
*/
|
|
47
|
+
collectAll(): Promise<SkillContent>;
|
|
48
|
+
/**
|
|
49
|
+
* Format collected content as a prompt-friendly string
|
|
50
|
+
*/
|
|
51
|
+
formatForPrompt(): Promise<string>;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=skill-content-collector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-content-collector.d.ts","sourceRoot":"","sources":["../../src/engine/skill-content-collector.ts"],"names":[],"mappings":"AAUA,kDAAkD;AAClD,MAAM,WAAW,YAAY;IAC3B,kCAAkC;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,4BAA4B;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,4CAA4C;IAC5C,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,iDAAiD;IACjD,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED,wBAAwB;AACxB,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,qBAAa,qBAAqB;IAChC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,WAAW,CAAS;gBAEhB,SAAS,EAAE,MAAM;IAK7B;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAoC3C;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAU5C;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;IAIvC;;OAEG;IACG,iBAAiB,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAqBvD;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAuBpD;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,YAAY,CAAC;IAgBzC;;OAEG;IACG,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC;CAuBzC"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill content collector for test generation.
|
|
3
|
+
*
|
|
4
|
+
* Collects and formats skill content (SKILL.md, references/, scripts/)
|
|
5
|
+
* for analysis by Claude CLI to generate test files.
|
|
6
|
+
*/
|
|
7
|
+
import { readFile, readdir, stat } from 'node:fs/promises';
|
|
8
|
+
import { join, extname } from 'node:path';
|
|
9
|
+
import matter from 'gray-matter';
|
|
10
|
+
/**
|
|
11
|
+
* Skill content collector - gathers skill files for test generation
|
|
12
|
+
*/
|
|
13
|
+
export class SkillContentCollector {
|
|
14
|
+
skillPath;
|
|
15
|
+
skillMdPath;
|
|
16
|
+
constructor(skillPath) {
|
|
17
|
+
this.skillPath = skillPath;
|
|
18
|
+
this.skillMdPath = join(skillPath, 'SKILL.md');
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Validate skill has required SKILL.md with YAML frontmatter
|
|
22
|
+
*/
|
|
23
|
+
async validate() {
|
|
24
|
+
try {
|
|
25
|
+
await stat(this.skillPath);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return { valid: false, message: `Skill path not found: ${this.skillPath}` };
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
await stat(this.skillMdPath);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return { valid: false, message: `SKILL.md not found in ${this.skillPath}` };
|
|
35
|
+
}
|
|
36
|
+
const content = await readFile(this.skillMdPath, 'utf-8');
|
|
37
|
+
if (!content.startsWith('---')) {
|
|
38
|
+
return { valid: false, message: 'SKILL.md missing YAML frontmatter' };
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
const { data: frontmatter } = matter(content);
|
|
42
|
+
if (!frontmatter.name) {
|
|
43
|
+
return { valid: false, message: "Missing 'name' in frontmatter" };
|
|
44
|
+
}
|
|
45
|
+
if (!frontmatter.description) {
|
|
46
|
+
return { valid: false, message: "Missing 'description' in frontmatter" };
|
|
47
|
+
}
|
|
48
|
+
return { valid: true, message: 'Valid' };
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return { valid: false, message: 'Invalid YAML frontmatter format' };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Extract skill name from SKILL.md frontmatter
|
|
56
|
+
*/
|
|
57
|
+
async getSkillName() {
|
|
58
|
+
try {
|
|
59
|
+
const content = await readFile(this.skillMdPath, 'utf-8');
|
|
60
|
+
const { data: frontmatter } = matter(content);
|
|
61
|
+
return frontmatter.name || null;
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Read SKILL.md content
|
|
69
|
+
*/
|
|
70
|
+
async collectSkillMd() {
|
|
71
|
+
return readFile(this.skillMdPath, 'utf-8');
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Collect all markdown files from references/ directory
|
|
75
|
+
*/
|
|
76
|
+
async collectReferences() {
|
|
77
|
+
const refs = new Map();
|
|
78
|
+
const refsDir = join(this.skillPath, 'references');
|
|
79
|
+
try {
|
|
80
|
+
const entries = await readdir(refsDir);
|
|
81
|
+
for (const entry of entries) {
|
|
82
|
+
if (extname(entry) === '.md') {
|
|
83
|
+
const filePath = join(refsDir, entry);
|
|
84
|
+
const content = await readFile(filePath, 'utf-8');
|
|
85
|
+
refs.set(entry, content);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// references/ directory doesn't exist - that's okay
|
|
91
|
+
}
|
|
92
|
+
return refs;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Collect Python scripts from scripts/ directory (first 100 lines)
|
|
96
|
+
*/
|
|
97
|
+
async collectScripts() {
|
|
98
|
+
const scripts = new Map();
|
|
99
|
+
const scriptsDir = join(this.skillPath, 'scripts');
|
|
100
|
+
try {
|
|
101
|
+
const entries = await readdir(scriptsDir);
|
|
102
|
+
for (const entry of entries) {
|
|
103
|
+
if (extname(entry) === '.py') {
|
|
104
|
+
const filePath = join(scriptsDir, entry);
|
|
105
|
+
const content = await readFile(filePath, 'utf-8');
|
|
106
|
+
// Limit to first 100 lines to reduce token usage
|
|
107
|
+
const lines = content.split('\n').slice(0, 100);
|
|
108
|
+
scripts.set(entry, lines.join('\n'));
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
// scripts/ directory doesn't exist - that's okay
|
|
114
|
+
}
|
|
115
|
+
return scripts;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Collect all skill content for Claude analysis
|
|
119
|
+
*/
|
|
120
|
+
async collectAll() {
|
|
121
|
+
const [skillName, skillMd, references, scripts] = await Promise.all([
|
|
122
|
+
this.getSkillName(),
|
|
123
|
+
this.collectSkillMd(),
|
|
124
|
+
this.collectReferences(),
|
|
125
|
+
this.collectScripts(),
|
|
126
|
+
]);
|
|
127
|
+
return {
|
|
128
|
+
skillName: skillName || 'unknown-skill',
|
|
129
|
+
skillMd,
|
|
130
|
+
references,
|
|
131
|
+
scripts,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Format collected content as a prompt-friendly string
|
|
136
|
+
*/
|
|
137
|
+
async formatForPrompt() {
|
|
138
|
+
const content = await this.collectAll();
|
|
139
|
+
const parts = [];
|
|
140
|
+
parts.push(`# Skill: ${content.skillName}\n`);
|
|
141
|
+
parts.push('## SKILL.md\n```markdown\n' + content.skillMd + '\n```\n');
|
|
142
|
+
if (content.references.size > 0) {
|
|
143
|
+
parts.push('## Reference Files\n');
|
|
144
|
+
for (const [name, text] of content.references) {
|
|
145
|
+
parts.push(`### ${name}\n\`\`\`markdown\n${text}\n\`\`\`\n`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
if (content.scripts.size > 0) {
|
|
149
|
+
parts.push('## Scripts (first 100 lines each)\n');
|
|
150
|
+
for (const [name, text] of content.scripts) {
|
|
151
|
+
parts.push(`### ${name}\n\`\`\`python\n${text}\n\`\`\`\n`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return parts.join('\n');
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=skill-content-collector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-content-collector.js","sourceRoot":"","sources":["../../src/engine/skill-content-collector.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,MAAM,MAAM,aAAa,CAAC;AAoBjC;;GAEG;AACH,MAAM,OAAO,qBAAqB;IACxB,SAAS,CAAS;IAClB,WAAW,CAAS;IAE5B,YAAY,SAAiB;QAC3B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IACjD,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,QAAQ;QACZ,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC7B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,yBAAyB,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC;QAC9E,CAAC;QAED,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC/B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,yBAAyB,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC;QAC9E,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAE1D,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YAC/B,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,mCAAmC,EAAE,CAAC;QACxE,CAAC;QAED,IAAI,CAAC;YACH,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;YAE9C,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;gBACtB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,+BAA+B,EAAE,CAAC;YACpE,CAAC;YAED,IAAI,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC;gBAC7B,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,sCAAsC,EAAE,CAAC;YAC3E,CAAC;YAED,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;QAC3C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,iCAAiC,EAAE,CAAC;QACtE,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,YAAY;QAChB,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;YAC1D,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;YAC9C,OAAO,WAAW,CAAC,IAAI,IAAI,IAAI,CAAC;QAClC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,cAAc;QAClB,OAAO,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAC7C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,iBAAiB;QACrB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;QACvC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;QAEnD,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;YAEvC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;gBAC5B,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,KAAK,EAAE,CAAC;oBAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;oBACtC,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;oBAClD,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;gBAC3B,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,oDAAoD;QACtD,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,cAAc;QAClB,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;QAC1C,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QAEnD,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC;YAE1C,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;gBAC5B,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,KAAK,EAAE,CAAC;oBAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;oBACzC,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;oBAClD,iDAAiD;oBACjD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;oBAChD,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;gBACvC,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,iDAAiD;QACnD,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,UAAU;QACd,MAAM,CAAC,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YAClE,IAAI,CAAC,YAAY,EAAE;YACnB,IAAI,CAAC,cAAc,EAAE;YACrB,IAAI,CAAC,iBAAiB,EAAE;YACxB,IAAI,CAAC,cAAc,EAAE;SACtB,CAAC,CAAC;QAEH,OAAO;YACL,SAAS,EAAE,SAAS,IAAI,eAAe;YACvC,OAAO;YACP,UAAU;YACV,OAAO;SACR,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,eAAe;QACnB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;QACxC,MAAM,KAAK,GAAa,EAAE,CAAC;QAE3B,KAAK,CAAC,IAAI,CAAC,YAAY,OAAO,CAAC,SAAS,IAAI,CAAC,CAAC;QAC9C,KAAK,CAAC,IAAI,CAAC,4BAA4B,GAAG,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;QAEvE,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;YAChC,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;YACnC,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;gBAC9C,KAAK,CAAC,IAAI,CAAC,OAAO,IAAI,qBAAqB,IAAI,YAAY,CAAC,CAAC;YAC/D,CAAC;QACH,CAAC;QAED,IAAI,OAAO,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;YAC7B,KAAK,CAAC,IAAI,CAAC,qCAAqC,CAAC,CAAC;YAClD,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;gBAC3C,KAAK,CAAC,IAAI,CAAC,OAAO,IAAI,mBAAmB,IAAI,YAAY,CAAC,CAAC;YAC7D,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;CACF"}
|