@pennyfarthing/shared 7.0.2
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/generate-skill-docs.d.ts +35 -0
- package/dist/generate-skill-docs.d.ts.map +1 -0
- package/dist/generate-skill-docs.js +442 -0
- package/dist/generate-skill-docs.js.map +1 -0
- package/dist/generate-skill-docs.test.d.ts +13 -0
- package/dist/generate-skill-docs.test.d.ts.map +1 -0
- package/dist/generate-skill-docs.test.js +519 -0
- package/dist/generate-skill-docs.test.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/portrait-resolver.d.ts +32 -0
- package/dist/portrait-resolver.d.ts.map +1 -0
- package/dist/portrait-resolver.js +147 -0
- package/dist/portrait-resolver.js.map +1 -0
- package/dist/portrait-resolver.test.d.ts +2 -0
- package/dist/portrait-resolver.test.d.ts.map +1 -0
- package/dist/portrait-resolver.test.js +156 -0
- package/dist/portrait-resolver.test.js.map +1 -0
- package/dist/skill-search.d.ts +36 -0
- package/dist/skill-search.d.ts.map +1 -0
- package/dist/skill-search.js +300 -0
- package/dist/skill-search.js.map +1 -0
- package/dist/skill-search.sh +41 -0
- package/dist/skill-search.test.d.ts +16 -0
- package/dist/skill-search.test.d.ts.map +1 -0
- package/dist/skill-search.test.js +193 -0
- package/dist/skill-search.test.js.map +1 -0
- package/dist/skill-suggest.d.ts +76 -0
- package/dist/skill-suggest.d.ts.map +1 -0
- package/dist/skill-suggest.js +256 -0
- package/dist/skill-suggest.js.map +1 -0
- package/dist/skill-suggest.test.d.ts +12 -0
- package/dist/skill-suggest.test.d.ts.map +1 -0
- package/dist/skill-suggest.test.js +257 -0
- package/dist/skill-suggest.test.js.map +1 -0
- package/dist/theme-loader.d.ts +35 -0
- package/dist/theme-loader.d.ts.map +1 -0
- package/dist/theme-loader.js +170 -0
- package/dist/theme-loader.js.map +1 -0
- package/dist/theme-loader.test.d.ts +2 -0
- package/dist/theme-loader.test.d.ts.map +1 -0
- package/dist/theme-loader.test.js +72 -0
- package/dist/theme-loader.test.js.map +1 -0
- package/package.json +38 -0
|
@@ -0,0 +1,519 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for Story 9-4: Skill Documentation Generator
|
|
3
|
+
*
|
|
4
|
+
* These tests verify:
|
|
5
|
+
* - AC1: docs/SKILLS.md auto-generated from skill-registry.yaml
|
|
6
|
+
* - AC2: Generated docs include all skill metadata
|
|
7
|
+
* - AC3: Skills organized by category with table of contents
|
|
8
|
+
* - AC4: Build process triggers doc generation
|
|
9
|
+
*
|
|
10
|
+
* Run with: npm test -- packages/shared/src/generate-skill-docs.test.ts
|
|
11
|
+
*/
|
|
12
|
+
import { describe, it } from 'node:test';
|
|
13
|
+
import assert from 'node:assert';
|
|
14
|
+
import { execSync } from 'child_process';
|
|
15
|
+
import { existsSync, readFileSync, mkdirSync, writeFileSync, rmSync, statSync } from 'fs';
|
|
16
|
+
import { join, dirname } from 'path';
|
|
17
|
+
import { tmpdir } from 'os';
|
|
18
|
+
import { fileURLToPath } from 'url';
|
|
19
|
+
// Import the generator function - this doesn't exist yet, tests should fail (RED)
|
|
20
|
+
import { generateSkillDocs, } from './generate-skill-docs.js';
|
|
21
|
+
// Paths
|
|
22
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
23
|
+
const PROJECT_ROOT = join(__dirname, '../../..');
|
|
24
|
+
const REGISTRY_PATH = join(PROJECT_ROOT, 'pennyfarthing-dist/skills/skill-registry.yaml');
|
|
25
|
+
const OUTPUT_PATH = join(PROJECT_ROOT, 'docs/SKILLS.md');
|
|
26
|
+
const GENERATOR_SCRIPT = join(PROJECT_ROOT, 'scripts/utils/generate-skill-docs.sh');
|
|
27
|
+
// Sample minimal registry for isolated tests
|
|
28
|
+
const MINIMAL_REGISTRY = `
|
|
29
|
+
version: "1.0.0"
|
|
30
|
+
skills:
|
|
31
|
+
test-skill:
|
|
32
|
+
name: test-skill
|
|
33
|
+
description: A test skill for verification
|
|
34
|
+
category: development
|
|
35
|
+
tags: [test, example]
|
|
36
|
+
version: "1.0.0"
|
|
37
|
+
prerequisites: []
|
|
38
|
+
examples:
|
|
39
|
+
- context: Testing the generator
|
|
40
|
+
invocation: /test-skill
|
|
41
|
+
anti_patterns:
|
|
42
|
+
- Don't use in production
|
|
43
|
+
related_skills: []
|
|
44
|
+
keywords: [test, sample]
|
|
45
|
+
`;
|
|
46
|
+
describe('Story 9-4: Skill Documentation Generator', () => {
|
|
47
|
+
describe('AC1: Auto-generate docs/SKILLS.md from skill-registry.yaml', () => {
|
|
48
|
+
it('should read skill-registry.yaml and generate markdown', async () => {
|
|
49
|
+
// AC1: docs/SKILLS.md auto-generated from skill-registry.yaml
|
|
50
|
+
const result = await generateSkillDocs({
|
|
51
|
+
registryPath: REGISTRY_PATH,
|
|
52
|
+
});
|
|
53
|
+
assert.ok(result.success, 'Generation should succeed');
|
|
54
|
+
assert.ok(result.content, 'Should produce content');
|
|
55
|
+
assert.ok(result.content.length > 0, 'Content should not be empty');
|
|
56
|
+
});
|
|
57
|
+
it('should generate valid markdown output', async () => {
|
|
58
|
+
// AC1: Output should be valid markdown
|
|
59
|
+
const result = await generateSkillDocs({
|
|
60
|
+
registryPath: REGISTRY_PATH,
|
|
61
|
+
});
|
|
62
|
+
assert.ok(result.content, 'Should produce content');
|
|
63
|
+
// Basic markdown structure checks
|
|
64
|
+
assert.ok(result.content.startsWith('#'), 'Should start with a heading');
|
|
65
|
+
assert.ok(result.content.includes('##'), 'Should have section headings');
|
|
66
|
+
});
|
|
67
|
+
it('should include all 19 skills from registry', async () => {
|
|
68
|
+
// AC1: All skills from registry should appear in output
|
|
69
|
+
const result = await generateSkillDocs({
|
|
70
|
+
registryPath: REGISTRY_PATH,
|
|
71
|
+
});
|
|
72
|
+
assert.ok(result.skillCount === 19, `Should include all 19 skills, got ${result.skillCount}`);
|
|
73
|
+
// Check for a sample of known skills
|
|
74
|
+
const expectedSkills = ['testing', 'jira', 'code-review', 'changelog', 'theme'];
|
|
75
|
+
for (const skill of expectedSkills) {
|
|
76
|
+
assert.ok(result.content.includes(skill), `Output should include ${skill} skill`);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
it('should be idempotent - running twice produces same output', async () => {
|
|
80
|
+
// AC1: Generator should be deterministic
|
|
81
|
+
const result1 = await generateSkillDocs({
|
|
82
|
+
registryPath: REGISTRY_PATH,
|
|
83
|
+
});
|
|
84
|
+
const result2 = await generateSkillDocs({
|
|
85
|
+
registryPath: REGISTRY_PATH,
|
|
86
|
+
});
|
|
87
|
+
assert.strictEqual(result1.content, result2.content, 'Running twice should produce identical output');
|
|
88
|
+
});
|
|
89
|
+
it('should handle custom output path', async () => {
|
|
90
|
+
// AC1: Support writing to custom location
|
|
91
|
+
const tempDir = join(tmpdir(), `skill-docs-test-${Date.now()}`);
|
|
92
|
+
mkdirSync(tempDir, { recursive: true });
|
|
93
|
+
const customOutput = join(tempDir, 'SKILLS.md');
|
|
94
|
+
try {
|
|
95
|
+
const result = await generateSkillDocs({
|
|
96
|
+
registryPath: REGISTRY_PATH,
|
|
97
|
+
outputPath: customOutput,
|
|
98
|
+
writeFile: true,
|
|
99
|
+
});
|
|
100
|
+
assert.ok(result.success, 'Generation should succeed');
|
|
101
|
+
assert.ok(existsSync(customOutput), 'Output file should be created');
|
|
102
|
+
const fileContent = readFileSync(customOutput, 'utf-8');
|
|
103
|
+
assert.strictEqual(fileContent, result.content, 'File content should match returned content');
|
|
104
|
+
}
|
|
105
|
+
finally {
|
|
106
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
it('should throw helpful error when registry file is missing', async () => {
|
|
110
|
+
// AC1: Error handling for missing registry
|
|
111
|
+
await assert.rejects(async () => generateSkillDocs({
|
|
112
|
+
registryPath: '/nonexistent/path/registry.yaml',
|
|
113
|
+
}), {
|
|
114
|
+
message: /registry.*not found|cannot find|no such file/i,
|
|
115
|
+
}, 'Should throw error with helpful message for missing registry');
|
|
116
|
+
});
|
|
117
|
+
it('should handle malformed YAML gracefully', async () => {
|
|
118
|
+
// AC1: Error handling for invalid registry
|
|
119
|
+
const tempDir = join(tmpdir(), `skill-docs-test-${Date.now()}`);
|
|
120
|
+
mkdirSync(tempDir, { recursive: true });
|
|
121
|
+
const badRegistry = join(tempDir, 'bad-registry.yaml');
|
|
122
|
+
writeFileSync(badRegistry, 'this is not valid: yaml: content: [broken');
|
|
123
|
+
try {
|
|
124
|
+
await assert.rejects(async () => generateSkillDocs({
|
|
125
|
+
registryPath: badRegistry,
|
|
126
|
+
}), {
|
|
127
|
+
message: /invalid|parse|yaml/i,
|
|
128
|
+
}, 'Should throw error for malformed YAML');
|
|
129
|
+
}
|
|
130
|
+
finally {
|
|
131
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
describe('AC2: Include all skill metadata', () => {
|
|
136
|
+
it('should include skill description in output', async () => {
|
|
137
|
+
// AC2: description field included
|
|
138
|
+
const result = await generateSkillDocs({
|
|
139
|
+
registryPath: REGISTRY_PATH,
|
|
140
|
+
});
|
|
141
|
+
// Check that descriptions are included (not just skill names)
|
|
142
|
+
assert.ok(result.content.includes('TDD') || result.content.includes('test'), 'Should include skill descriptions mentioning TDD or testing');
|
|
143
|
+
});
|
|
144
|
+
it('should include tags for each skill', async () => {
|
|
145
|
+
// AC2: tags field included
|
|
146
|
+
const result = await generateSkillDocs({
|
|
147
|
+
registryPath: REGISTRY_PATH,
|
|
148
|
+
});
|
|
149
|
+
// Tags should appear in some form (could be **Tags:** or similar)
|
|
150
|
+
assert.ok(result.content.toLowerCase().includes('tag') ||
|
|
151
|
+
result.content.includes('tdd') ||
|
|
152
|
+
result.content.includes('quality'), 'Should include tags in output');
|
|
153
|
+
});
|
|
154
|
+
it('should include examples for each skill', async () => {
|
|
155
|
+
// AC2: examples field included
|
|
156
|
+
const result = await generateSkillDocs({
|
|
157
|
+
registryPath: REGISTRY_PATH,
|
|
158
|
+
});
|
|
159
|
+
// Examples section or invocation patterns should appear
|
|
160
|
+
assert.ok(result.content.toLowerCase().includes('example') ||
|
|
161
|
+
result.content.includes('/testing') ||
|
|
162
|
+
result.content.includes('invocation'), 'Should include examples or invocations');
|
|
163
|
+
});
|
|
164
|
+
it('should include anti-patterns for each skill', async () => {
|
|
165
|
+
// AC2: anti_patterns field included
|
|
166
|
+
const result = await generateSkillDocs({
|
|
167
|
+
registryPath: REGISTRY_PATH,
|
|
168
|
+
});
|
|
169
|
+
// Anti-patterns section should appear
|
|
170
|
+
assert.ok(result.content.toLowerCase().includes('anti-pattern') ||
|
|
171
|
+
result.content.toLowerCase().includes('antipattern') ||
|
|
172
|
+
result.content.toLowerCase().includes("don't"), 'Should include anti-patterns section');
|
|
173
|
+
});
|
|
174
|
+
it('should include related skills references', async () => {
|
|
175
|
+
// AC2: related_skills field included
|
|
176
|
+
const result = await generateSkillDocs({
|
|
177
|
+
registryPath: REGISTRY_PATH,
|
|
178
|
+
});
|
|
179
|
+
// Related skills should appear
|
|
180
|
+
assert.ok(result.content.toLowerCase().includes('related') ||
|
|
181
|
+
result.content.includes('See also'), 'Should include related skills references');
|
|
182
|
+
});
|
|
183
|
+
it('should include keywords for searchability', async () => {
|
|
184
|
+
// AC2: keywords field included (for skill discovery)
|
|
185
|
+
const result = await generateSkillDocs({
|
|
186
|
+
registryPath: REGISTRY_PATH,
|
|
187
|
+
});
|
|
188
|
+
// Keywords should appear (might be in a keywords section or as searchable terms)
|
|
189
|
+
assert.ok(result.content.toLowerCase().includes('keyword') ||
|
|
190
|
+
result.content.includes('jest') ||
|
|
191
|
+
result.content.includes('vitest'), 'Should include keywords for searchability');
|
|
192
|
+
});
|
|
193
|
+
it('should validate required fields are present in registry', async () => {
|
|
194
|
+
// AC2: Error if registry missing required fields
|
|
195
|
+
const tempDir = join(tmpdir(), `skill-docs-test-${Date.now()}`);
|
|
196
|
+
mkdirSync(tempDir, { recursive: true });
|
|
197
|
+
const incompleteRegistry = join(tempDir, 'incomplete-registry.yaml');
|
|
198
|
+
// Registry with skill missing required description
|
|
199
|
+
writeFileSync(incompleteRegistry, `
|
|
200
|
+
version: "1.0.0"
|
|
201
|
+
skills:
|
|
202
|
+
incomplete-skill:
|
|
203
|
+
name: incomplete-skill
|
|
204
|
+
# missing description
|
|
205
|
+
category: development
|
|
206
|
+
tags: []
|
|
207
|
+
`);
|
|
208
|
+
try {
|
|
209
|
+
await assert.rejects(async () => generateSkillDocs({
|
|
210
|
+
registryPath: incompleteRegistry,
|
|
211
|
+
strict: true,
|
|
212
|
+
}), {
|
|
213
|
+
message: /missing.*description|required.*field/i,
|
|
214
|
+
}, 'Should error when required fields are missing');
|
|
215
|
+
}
|
|
216
|
+
finally {
|
|
217
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
describe('AC3: Category organization with table of contents', () => {
|
|
222
|
+
it('should organize skills by category', async () => {
|
|
223
|
+
// AC3: Skills organized by category
|
|
224
|
+
const result = await generateSkillDocs({
|
|
225
|
+
registryPath: REGISTRY_PATH,
|
|
226
|
+
});
|
|
227
|
+
// Category headings should appear
|
|
228
|
+
const categories = ['development', 'project-management', 'tools', 'ai-llm', 'documentation', 'theming', 'benchmarking'];
|
|
229
|
+
let foundCategories = 0;
|
|
230
|
+
for (const category of categories) {
|
|
231
|
+
// Check for category as heading (could be ## Development or ## AI/LLM, etc.)
|
|
232
|
+
const normalizedCategory = category.replace(/-/g, ' ').replace(/ai llm/i, 'AI/LLM');
|
|
233
|
+
if (result.content.toLowerCase().includes(`## ${category}`) ||
|
|
234
|
+
result.content.toLowerCase().includes(normalizedCategory.toLowerCase())) {
|
|
235
|
+
foundCategories++;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
assert.ok(foundCategories >= 3, `Should have at least 3 category sections, found ${foundCategories}`);
|
|
239
|
+
});
|
|
240
|
+
it('should include table of contents with links', async () => {
|
|
241
|
+
// AC3: Table of contents with anchor links
|
|
242
|
+
const result = await generateSkillDocs({
|
|
243
|
+
registryPath: REGISTRY_PATH,
|
|
244
|
+
});
|
|
245
|
+
// TOC should have links (markdown format: [Text](#anchor))
|
|
246
|
+
assert.ok(result.content.includes('](#') ||
|
|
247
|
+
result.content.toLowerCase().includes('table of contents') ||
|
|
248
|
+
result.content.toLowerCase().includes('contents'), 'Should include table of contents with anchor links');
|
|
249
|
+
});
|
|
250
|
+
it('should place skills under correct category heading', async () => {
|
|
251
|
+
// AC3: Skills appear under their category
|
|
252
|
+
const result = await generateSkillDocs({
|
|
253
|
+
registryPath: REGISTRY_PATH,
|
|
254
|
+
});
|
|
255
|
+
// testing skill should be under development category
|
|
256
|
+
// Check that testing appears after development heading and before next category
|
|
257
|
+
const content = result.content.toLowerCase();
|
|
258
|
+
const devIndex = content.indexOf('development');
|
|
259
|
+
const testingIndex = content.indexOf('testing');
|
|
260
|
+
assert.ok(devIndex > -1, 'Development category should exist');
|
|
261
|
+
assert.ok(testingIndex > -1, 'Testing skill should exist');
|
|
262
|
+
// Testing should appear in development section (after heading, before significant distance)
|
|
263
|
+
});
|
|
264
|
+
it('should sort categories alphabetically', async () => {
|
|
265
|
+
// AC3: Predictable ordering
|
|
266
|
+
const result = await generateSkillDocs({
|
|
267
|
+
registryPath: REGISTRY_PATH,
|
|
268
|
+
});
|
|
269
|
+
// Find positions of category headings
|
|
270
|
+
const content = result.content.toLowerCase();
|
|
271
|
+
const _aiIndex = content.indexOf('ai') > -1 ? content.indexOf('ai') : Infinity;
|
|
272
|
+
const devIndex = content.indexOf('development');
|
|
273
|
+
const toolsIndex = content.indexOf('tools');
|
|
274
|
+
// AI/LLM should come before Development alphabetically
|
|
275
|
+
// (or however the ordering is defined - at least should be consistent)
|
|
276
|
+
assert.ok(devIndex > -1 && toolsIndex > -1, 'Multiple category sections should exist');
|
|
277
|
+
});
|
|
278
|
+
it('should sort skills alphabetically within category', async () => {
|
|
279
|
+
// AC3: Skills sorted within their category
|
|
280
|
+
const result = await generateSkillDocs({
|
|
281
|
+
registryPath: REGISTRY_PATH,
|
|
282
|
+
});
|
|
283
|
+
// Within development: code-review should come before dev-patterns (alphabetically)
|
|
284
|
+
const content = result.content.toLowerCase();
|
|
285
|
+
const codeReviewIndex = content.indexOf('code-review');
|
|
286
|
+
const devPatternsIndex = content.indexOf('dev-patterns');
|
|
287
|
+
if (codeReviewIndex > -1 && devPatternsIndex > -1) {
|
|
288
|
+
assert.ok(codeReviewIndex < devPatternsIndex, 'Skills should be sorted alphabetically within category');
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
it('should generate valid TOC anchors', async () => {
|
|
292
|
+
// AC3: TOC links should match heading anchors
|
|
293
|
+
const result = await generateSkillDocs({
|
|
294
|
+
registryPath: REGISTRY_PATH,
|
|
295
|
+
});
|
|
296
|
+
// Extract TOC links and verify they have corresponding headings
|
|
297
|
+
const tocLinkMatches = result.content.match(/\[([^\]]+)\]\(#([^)]+)\)/g) || [];
|
|
298
|
+
if (tocLinkMatches.length > 0) {
|
|
299
|
+
// At least some TOC links should exist
|
|
300
|
+
assert.ok(tocLinkMatches.length > 0, 'TOC should have anchor links');
|
|
301
|
+
// Verify at least one link has a valid target
|
|
302
|
+
for (const link of tocLinkMatches.slice(0, 3)) {
|
|
303
|
+
const anchorMatch = link.match(/\(#([^)]+)\)/);
|
|
304
|
+
if (anchorMatch) {
|
|
305
|
+
const anchor = anchorMatch[1];
|
|
306
|
+
// The heading for this anchor should exist somewhere
|
|
307
|
+
// (GitHub-style anchors: lowercase, spaces to dashes)
|
|
308
|
+
assert.ok(anchor.length > 0, `Anchor should not be empty: ${link}`);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
});
|
|
314
|
+
describe('AC4: Build process triggers doc generation', () => {
|
|
315
|
+
it('should have generate-skill-docs.sh script', () => {
|
|
316
|
+
// AC4: Script exists for build integration
|
|
317
|
+
assert.ok(existsSync(GENERATOR_SCRIPT), `Generator script should exist at ${GENERATOR_SCRIPT}`);
|
|
318
|
+
});
|
|
319
|
+
it('should script be executable', () => {
|
|
320
|
+
// AC4: Script should have execute permissions
|
|
321
|
+
if (!existsSync(GENERATOR_SCRIPT)) {
|
|
322
|
+
assert.fail('Generator script does not exist yet');
|
|
323
|
+
}
|
|
324
|
+
// Try to get file stats - executable bit
|
|
325
|
+
const stats = statSync(GENERATOR_SCRIPT);
|
|
326
|
+
const isExecutable = (stats.mode & parseInt('111', 8)) !== 0;
|
|
327
|
+
assert.ok(isExecutable, 'Script should have execute permissions');
|
|
328
|
+
});
|
|
329
|
+
it('should script produce output when run directly', () => {
|
|
330
|
+
// AC4: Shell script integration
|
|
331
|
+
if (!existsSync(GENERATOR_SCRIPT)) {
|
|
332
|
+
assert.fail('Generator script does not exist yet');
|
|
333
|
+
}
|
|
334
|
+
try {
|
|
335
|
+
const output = execSync(`bash ${GENERATOR_SCRIPT} --dry-run`, {
|
|
336
|
+
encoding: 'utf-8',
|
|
337
|
+
cwd: PROJECT_ROOT,
|
|
338
|
+
});
|
|
339
|
+
assert.ok(output.length > 0, 'Script should produce output');
|
|
340
|
+
assert.ok(output.includes('#') || output.includes('Generated'), 'Output should be markdown or status message');
|
|
341
|
+
}
|
|
342
|
+
catch (error) {
|
|
343
|
+
assert.fail(`Script execution failed: ${error}`);
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
it('should package.json include docs generation script', () => {
|
|
347
|
+
// AC4: Build process integration
|
|
348
|
+
const packageJsonPath = join(PROJECT_ROOT, 'package.json');
|
|
349
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
350
|
+
const hasDocsScript = packageJson.scripts?.docs ||
|
|
351
|
+
packageJson.scripts?.['generate-docs'] ||
|
|
352
|
+
packageJson.scripts?.build?.includes('generate-skill-docs');
|
|
353
|
+
assert.ok(hasDocsScript, 'package.json should have docs generation in scripts');
|
|
354
|
+
});
|
|
355
|
+
it('should build script include docs generation', () => {
|
|
356
|
+
// AC4: Build triggers doc generation
|
|
357
|
+
const packageJsonPath = join(PROJECT_ROOT, 'package.json');
|
|
358
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
359
|
+
const buildScript = packageJson.scripts?.build || '';
|
|
360
|
+
// Either build includes docs, or there's a prebuild/postbuild hook
|
|
361
|
+
const triggersDocGen = buildScript.includes('generate-skill-docs') ||
|
|
362
|
+
buildScript.includes('docs') ||
|
|
363
|
+
packageJson.scripts?.prebuild?.includes('docs') ||
|
|
364
|
+
packageJson.scripts?.postbuild?.includes('docs');
|
|
365
|
+
assert.ok(triggersDocGen, 'Build process should trigger doc generation');
|
|
366
|
+
});
|
|
367
|
+
it('should generate fresh docs match current registry', async () => {
|
|
368
|
+
// AC4: Generated docs should be up-to-date with registry
|
|
369
|
+
if (!existsSync(OUTPUT_PATH)) {
|
|
370
|
+
assert.fail('docs/SKILLS.md does not exist yet');
|
|
371
|
+
}
|
|
372
|
+
const result = await generateSkillDocs({
|
|
373
|
+
registryPath: REGISTRY_PATH,
|
|
374
|
+
});
|
|
375
|
+
const currentDocs = readFileSync(OUTPUT_PATH, 'utf-8');
|
|
376
|
+
// The generated content should match what's in the file
|
|
377
|
+
// (allowing for timestamp differences if there's a "generated at" header)
|
|
378
|
+
const normalize = (s) => s.replace(/Generated at:.*/g, '').replace(/\s+/g, ' ').trim();
|
|
379
|
+
assert.strictEqual(normalize(result.content), normalize(currentDocs), 'Generated docs should match current docs/SKILLS.md (regenerate if stale)');
|
|
380
|
+
});
|
|
381
|
+
});
|
|
382
|
+
describe('Shell Script Integration', () => {
|
|
383
|
+
it('should script accept --help flag', () => {
|
|
384
|
+
// Usability: Show help text
|
|
385
|
+
if (!existsSync(GENERATOR_SCRIPT)) {
|
|
386
|
+
assert.fail('Generator script does not exist yet');
|
|
387
|
+
}
|
|
388
|
+
try {
|
|
389
|
+
const output = execSync(`bash ${GENERATOR_SCRIPT} --help`, {
|
|
390
|
+
encoding: 'utf-8',
|
|
391
|
+
cwd: PROJECT_ROOT,
|
|
392
|
+
});
|
|
393
|
+
assert.ok(output.includes('usage') || output.includes('Usage') || output.includes('help'), 'Should show usage information');
|
|
394
|
+
}
|
|
395
|
+
catch (error) {
|
|
396
|
+
// --help might exit with 0 or non-zero depending on implementation
|
|
397
|
+
assert.fail(`--help should work: ${error}`);
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
it('should script accept custom registry path', () => {
|
|
401
|
+
// Flexibility: Allow custom registry
|
|
402
|
+
if (!existsSync(GENERATOR_SCRIPT)) {
|
|
403
|
+
assert.fail('Generator script does not exist yet');
|
|
404
|
+
}
|
|
405
|
+
const tempDir = join(tmpdir(), `skill-docs-test-${Date.now()}`);
|
|
406
|
+
mkdirSync(tempDir, { recursive: true });
|
|
407
|
+
const customRegistry = join(tempDir, 'custom-registry.yaml');
|
|
408
|
+
writeFileSync(customRegistry, MINIMAL_REGISTRY);
|
|
409
|
+
try {
|
|
410
|
+
const output = execSync(`bash ${GENERATOR_SCRIPT} --registry ${customRegistry} --dry-run`, {
|
|
411
|
+
encoding: 'utf-8',
|
|
412
|
+
cwd: PROJECT_ROOT,
|
|
413
|
+
});
|
|
414
|
+
assert.ok(output.includes('test-skill'), 'Should use custom registry');
|
|
415
|
+
}
|
|
416
|
+
catch (error) {
|
|
417
|
+
assert.fail(`Custom registry should work: ${error}`);
|
|
418
|
+
}
|
|
419
|
+
finally {
|
|
420
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
421
|
+
}
|
|
422
|
+
});
|
|
423
|
+
it('should script exit with error code on failure', () => {
|
|
424
|
+
// Error handling: Non-zero exit on failure
|
|
425
|
+
if (!existsSync(GENERATOR_SCRIPT)) {
|
|
426
|
+
assert.fail('Generator script does not exist yet');
|
|
427
|
+
}
|
|
428
|
+
try {
|
|
429
|
+
execSync(`bash ${GENERATOR_SCRIPT} --registry /nonexistent/path.yaml`, {
|
|
430
|
+
encoding: 'utf-8',
|
|
431
|
+
cwd: PROJECT_ROOT,
|
|
432
|
+
});
|
|
433
|
+
assert.fail('Should have thrown for missing registry');
|
|
434
|
+
}
|
|
435
|
+
catch (error) {
|
|
436
|
+
assert.ok(error.status !== 0, 'Should exit with non-zero status on error');
|
|
437
|
+
}
|
|
438
|
+
});
|
|
439
|
+
});
|
|
440
|
+
describe('Error Handling', () => {
|
|
441
|
+
it('should handle empty registry gracefully', async () => {
|
|
442
|
+
// Edge case: Registry with no skills
|
|
443
|
+
const tempDir = join(tmpdir(), `skill-docs-test-${Date.now()}`);
|
|
444
|
+
mkdirSync(tempDir, { recursive: true });
|
|
445
|
+
const emptyRegistry = join(tempDir, 'empty-registry.yaml');
|
|
446
|
+
writeFileSync(emptyRegistry, 'version: "1.0.0"\nskills: {}');
|
|
447
|
+
try {
|
|
448
|
+
const result = await generateSkillDocs({
|
|
449
|
+
registryPath: emptyRegistry,
|
|
450
|
+
});
|
|
451
|
+
assert.ok(result.success, 'Should succeed with empty registry');
|
|
452
|
+
assert.strictEqual(result.skillCount, 0, 'Should report 0 skills');
|
|
453
|
+
assert.ok(result.content.includes('#'), 'Should still produce valid markdown structure');
|
|
454
|
+
}
|
|
455
|
+
finally {
|
|
456
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
457
|
+
}
|
|
458
|
+
});
|
|
459
|
+
it('should handle skills with missing optional fields', async () => {
|
|
460
|
+
// Edge case: Skills missing optional fields
|
|
461
|
+
const tempDir = join(tmpdir(), `skill-docs-test-${Date.now()}`);
|
|
462
|
+
mkdirSync(tempDir, { recursive: true });
|
|
463
|
+
const minimalSkillRegistry = join(tempDir, 'minimal-registry.yaml');
|
|
464
|
+
writeFileSync(minimalSkillRegistry, `
|
|
465
|
+
version: "1.0.0"
|
|
466
|
+
skills:
|
|
467
|
+
minimal:
|
|
468
|
+
name: minimal
|
|
469
|
+
description: A minimal skill
|
|
470
|
+
category: development
|
|
471
|
+
tags: []
|
|
472
|
+
# optional fields omitted: examples, anti_patterns, related_skills, keywords
|
|
473
|
+
`);
|
|
474
|
+
try {
|
|
475
|
+
const result = await generateSkillDocs({
|
|
476
|
+
registryPath: minimalSkillRegistry,
|
|
477
|
+
});
|
|
478
|
+
assert.ok(result.success, 'Should succeed with minimal skill');
|
|
479
|
+
assert.ok(result.content.includes('minimal'), 'Should include minimal skill');
|
|
480
|
+
}
|
|
481
|
+
finally {
|
|
482
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
483
|
+
}
|
|
484
|
+
});
|
|
485
|
+
it('should handle special characters in skill content', async () => {
|
|
486
|
+
// Edge case: Special markdown characters in content
|
|
487
|
+
const tempDir = join(tmpdir(), `skill-docs-test-${Date.now()}`);
|
|
488
|
+
mkdirSync(tempDir, { recursive: true });
|
|
489
|
+
const specialRegistry = join(tempDir, 'special-registry.yaml');
|
|
490
|
+
writeFileSync(specialRegistry, `
|
|
491
|
+
version: "1.0.0"
|
|
492
|
+
skills:
|
|
493
|
+
special:
|
|
494
|
+
name: special
|
|
495
|
+
description: "A skill with *asterisks* and [brackets] and \`backticks\`"
|
|
496
|
+
category: development
|
|
497
|
+
tags: [tag-with-dash, tag_with_underscore]
|
|
498
|
+
examples:
|
|
499
|
+
- context: "Example with 'quotes'"
|
|
500
|
+
invocation: /special --flag=value
|
|
501
|
+
anti_patterns:
|
|
502
|
+
- "Don't do this: \`bad code\`"
|
|
503
|
+
related_skills: []
|
|
504
|
+
keywords: []
|
|
505
|
+
`);
|
|
506
|
+
try {
|
|
507
|
+
const result = await generateSkillDocs({
|
|
508
|
+
registryPath: specialRegistry,
|
|
509
|
+
});
|
|
510
|
+
assert.ok(result.success, 'Should handle special characters');
|
|
511
|
+
assert.ok(result.content.includes('special'), 'Should include skill');
|
|
512
|
+
}
|
|
513
|
+
finally {
|
|
514
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
515
|
+
}
|
|
516
|
+
});
|
|
517
|
+
});
|
|
518
|
+
});
|
|
519
|
+
//# sourceMappingURL=generate-skill-docs.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-skill-docs.test.js","sourceRoot":"","sources":["../src/generate-skill-docs.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;AAC1F,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,CAAC;AAC5B,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAEpC,kFAAkF;AAClF,OAAO,EACL,iBAAiB,GAClB,MAAM,0BAA0B,CAAC;AAElC,QAAQ;AACR,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1D,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;AACjD,MAAM,aAAa,GAAG,IAAI,CAAC,YAAY,EAAE,+CAA+C,CAAC,CAAC;AAC1F,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAC;AACzD,MAAM,gBAAgB,GAAG,IAAI,CAAC,YAAY,EAAE,sCAAsC,CAAC,CAAC;AAEpF,6CAA6C;AAC7C,MAAM,gBAAgB,GAAG;;;;;;;;;;;;;;;;;CAiBxB,CAAC;AAEF,QAAQ,CAAC,0CAA0C,EAAE,GAAG,EAAE;IAExD,QAAQ,CAAC,4DAA4D,EAAE,GAAG,EAAE;QAE1E,EAAE,CAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;YACrE,8DAA8D;YAC9D,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC;gBACrC,YAAY,EAAE,aAAa;aAC5B,CAAC,CAAC;YAEH,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,2BAA2B,CAAC,CAAC;YACvD,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,wBAAwB,CAAC,CAAC;YACpD,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,6BAA6B,CAAC,CAAC;QACtE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;YACrD,uCAAuC;YACvC,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC;gBACrC,YAAY,EAAE,aAAa;aAC5B,CAAC,CAAC;YAEH,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,wBAAwB,CAAC,CAAC;YACpD,kCAAkC;YAClC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,6BAA6B,CAAC,CAAC;YACzE,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,8BAA8B,CAAC,CAAC;QAC3E,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;YAC1D,wDAAwD;YACxD,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC;gBACrC,YAAY,EAAE,aAAa;aAC5B,CAAC,CAAC;YAEH,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,UAAU,KAAK,EAAE,EAAE,qCAAqC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;YAE9F,qCAAqC;YACrC,MAAM,cAAc,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;YAChF,KAAK,MAAM,KAAK,IAAI,cAAc,EAAE,CAAC;gBACnC,MAAM,CAAC,EAAE,CACP,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAC9B,yBAAyB,KAAK,QAAQ,CACvC,CAAC;YACJ,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2DAA2D,EAAE,KAAK,IAAI,EAAE;YACzE,yCAAyC;YACzC,MAAM,OAAO,GAAG,MAAM,iBAAiB,CAAC;gBACtC,YAAY,EAAE,aAAa;aAC5B,CAAC,CAAC;YAEH,MAAM,OAAO,GAAG,MAAM,iBAAiB,CAAC;gBACtC,YAAY,EAAE,aAAa;aAC5B,CAAC,CAAC;YAEH,MAAM,CAAC,WAAW,CAChB,OAAO,CAAC,OAAO,EACf,OAAO,CAAC,OAAO,EACf,+CAA+C,CAChD,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;YAChD,0CAA0C;YAC1C,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,mBAAmB,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YAChE,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACxC,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;YAEhD,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC;oBACrC,YAAY,EAAE,aAAa;oBAC3B,UAAU,EAAE,YAAY;oBACxB,SAAS,EAAE,IAAI;iBAChB,CAAC,CAAC;gBAEH,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,2BAA2B,CAAC,CAAC;gBACvD,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,+BAA+B,CAAC,CAAC;gBAErE,MAAM,WAAW,GAAG,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;gBACxD,MAAM,CAAC,WAAW,CAAC,WAAW,EAAE,MAAM,CAAC,OAAO,EAAE,4CAA4C,CAAC,CAAC;YAChG,CAAC;oBAAS,CAAC;gBACT,MAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACpD,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,0DAA0D,EAAE,KAAK,IAAI,EAAE;YACxE,2CAA2C;YAC3C,MAAM,MAAM,CAAC,OAAO,CAClB,KAAK,IAAI,EAAE,CAAC,iBAAiB,CAAC;gBAC5B,YAAY,EAAE,iCAAiC;aAChD,CAAC,EACF;gBACE,OAAO,EAAE,+CAA+C;aACzD,EACD,8DAA8D,CAC/D,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yCAAyC,EAAE,KAAK,IAAI,EAAE;YACvD,2CAA2C;YAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,mBAAmB,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YAChE,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACxC,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC;YACvD,aAAa,CAAC,WAAW,EAAE,2CAA2C,CAAC,CAAC;YAExE,IAAI,CAAC;gBACH,MAAM,MAAM,CAAC,OAAO,CAClB,KAAK,IAAI,EAAE,CAAC,iBAAiB,CAAC;oBAC5B,YAAY,EAAE,WAAW;iBAC1B,CAAC,EACF;oBACE,OAAO,EAAE,qBAAqB;iBAC/B,EACD,uCAAuC,CACxC,CAAC;YACJ,CAAC;oBAAS,CAAC;gBACT,MAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACpD,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,iCAAiC,EAAE,GAAG,EAAE;QAE/C,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;YAC1D,kCAAkC;YAClC,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC;gBACrC,YAAY,EAAE,aAAa;aAC5B,CAAC,CAAC;YAEH,8DAA8D;YAC9D,MAAM,CAAC,EAAE,CACP,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,EACjE,6DAA6D,CAC9D,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;YAClD,2BAA2B;YAC3B,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC;gBACrC,YAAY,EAAE,aAAa;aAC5B,CAAC,CAAC;YAEH,kEAAkE;YAClE,MAAM,CAAC,EAAE,CACP,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC;gBAC5C,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;gBAC9B,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,EAClC,+BAA+B,CAChC,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;YACtD,+BAA+B;YAC/B,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC;gBACrC,YAAY,EAAE,aAAa;aAC5B,CAAC,CAAC;YAEH,wDAAwD;YACxD,MAAM,CAAC,EAAE,CACP,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC;gBAChD,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;gBACnC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,EACrC,wCAAwC,CACzC,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;YAC3D,oCAAoC;YACpC,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC;gBACrC,YAAY,EAAE,aAAa;aAC5B,CAAC,CAAC;YAEH,sCAAsC;YACtC,MAAM,CAAC,EAAE,CACP,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC;gBACrD,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC;gBACpD,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,EAC9C,sCAAsC,CACvC,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;YACxD,qCAAqC;YACrC,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC;gBACrC,YAAY,EAAE,aAAa;aAC5B,CAAC,CAAC;YAEH,+BAA+B;YAC/B,MAAM,CAAC,EAAE,CACP,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC;gBAChD,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,EACnC,0CAA0C,CAC3C,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;YACzD,qDAAqD;YACrD,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC;gBACrC,YAAY,EAAE,aAAa;aAC5B,CAAC,CAAC;YAEH,iFAAiF;YACjF,MAAM,CAAC,EAAE,CACP,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC;gBAChD,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;gBAC/B,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,EACjC,2CAA2C,CAC5C,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yDAAyD,EAAE,KAAK,IAAI,EAAE;YACvE,iDAAiD;YACjD,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,mBAAmB,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YAChE,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACxC,MAAM,kBAAkB,GAAG,IAAI,CAAC,OAAO,EAAE,0BAA0B,CAAC,CAAC;YAErE,mDAAmD;YACnD,aAAa,CAAC,kBAAkB,EAAE;;;;;;;;CAQvC,CAAC,CAAC;YAEG,IAAI,CAAC;gBACH,MAAM,MAAM,CAAC,OAAO,CAClB,KAAK,IAAI,EAAE,CAAC,iBAAiB,CAAC;oBAC5B,YAAY,EAAE,kBAAkB;oBAChC,MAAM,EAAE,IAAI;iBACb,CAAC,EACF;oBACE,OAAO,EAAE,uCAAuC;iBACjD,EACD,+CAA+C,CAChD,CAAC;YACJ,CAAC;oBAAS,CAAC;gBACT,MAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACpD,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAEjE,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;YAClD,oCAAoC;YACpC,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC;gBACrC,YAAY,EAAE,aAAa;aAC5B,CAAC,CAAC;YAEH,kCAAkC;YAClC,MAAM,UAAU,GAAG,CAAC,aAAa,EAAE,oBAAoB,EAAE,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC;YACxH,IAAI,eAAe,GAAG,CAAC,CAAC;YAExB,KAAK,MAAM,QAAQ,IAAI,UAAU,EAAE,CAAC;gBAClC,6EAA6E;gBAC7E,MAAM,kBAAkB,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;gBACpF,IACE,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,QAAQ,EAAE,CAAC;oBACvD,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,kBAAkB,CAAC,WAAW,EAAE,CAAC,EACvE,CAAC;oBACD,eAAe,EAAE,CAAC;gBACpB,CAAC;YACH,CAAC;YAED,MAAM,CAAC,EAAE,CACP,eAAe,IAAI,CAAC,EACpB,mDAAmD,eAAe,EAAE,CACrE,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;YAC3D,2CAA2C;YAC3C,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC;gBACrC,YAAY,EAAE,aAAa;aAC5B,CAAC,CAAC;YAEH,2DAA2D;YAC3D,MAAM,CAAC,EAAE,CACP,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;gBAC9B,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,mBAAmB,CAAC;gBAC1D,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,EACjD,oDAAoD,CACrD,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;YAClE,0CAA0C;YAC1C,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC;gBACrC,YAAY,EAAE,aAAa;aAC5B,CAAC,CAAC;YAEH,qDAAqD;YACrD,gFAAgF;YAChF,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;YAC7C,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;YAChD,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAEhD,MAAM,CAAC,EAAE,CAAC,QAAQ,GAAG,CAAC,CAAC,EAAE,mCAAmC,CAAC,CAAC;YAC9D,MAAM,CAAC,EAAE,CAAC,YAAY,GAAG,CAAC,CAAC,EAAE,4BAA4B,CAAC,CAAC;YAC3D,4FAA4F;QAC9F,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;YACrD,4BAA4B;YAC5B,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC;gBACrC,YAAY,EAAE,aAAa;aAC5B,CAAC,CAAC;YAEH,sCAAsC;YACtC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;YAC7C,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;YAC/E,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;YAChD,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YAE5C,uDAAuD;YACvD,uEAAuE;YACvE,MAAM,CAAC,EAAE,CACP,QAAQ,GAAG,CAAC,CAAC,IAAI,UAAU,GAAG,CAAC,CAAC,EAChC,yCAAyC,CAC1C,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;YACjE,2CAA2C;YAC3C,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC;gBACrC,YAAY,EAAE,aAAa;aAC5B,CAAC,CAAC;YAEH,mFAAmF;YACnF,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;YAC7C,MAAM,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;YACvD,MAAM,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;YAEzD,IAAI,eAAe,GAAG,CAAC,CAAC,IAAI,gBAAgB,GAAG,CAAC,CAAC,EAAE,CAAC;gBAClD,MAAM,CAAC,EAAE,CACP,eAAe,GAAG,gBAAgB,EAClC,wDAAwD,CACzD,CAAC;YACJ,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;YACjD,8CAA8C;YAC9C,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC;gBACrC,YAAY,EAAE,aAAa;aAC5B,CAAC,CAAC;YAEH,gEAAgE;YAChE,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,2BAA2B,CAAC,IAAI,EAAE,CAAC;YAE/E,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC9B,uCAAuC;gBACvC,MAAM,CAAC,EAAE,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,8BAA8B,CAAC,CAAC;gBAErE,8CAA8C;gBAC9C,KAAK,MAAM,IAAI,IAAI,cAAc,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;oBAC9C,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;oBAC/C,IAAI,WAAW,EAAE,CAAC;wBAChB,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;wBAC9B,qDAAqD;wBACrD,sDAAsD;wBACtD,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,+BAA+B,IAAI,EAAE,CAAC,CAAC;oBACtE,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,4CAA4C,EAAE,GAAG,EAAE;QAE1D,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;YACnD,2CAA2C;YAC3C,MAAM,CAAC,EAAE,CACP,UAAU,CAAC,gBAAgB,CAAC,EAC5B,oCAAoC,gBAAgB,EAAE,CACvD,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;YACrC,8CAA8C;YAC9C,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE,CAAC;gBAClC,MAAM,CAAC,IAAI,CAAC,qCAAqC,CAAC,CAAC;YACrD,CAAC;YAED,yCAAyC;YACzC,MAAM,KAAK,GAAG,QAAQ,CAAC,gBAAgB,CAAC,CAAC;YACzC,MAAM,YAAY,GAAG,CAAC,KAAK,CAAC,IAAI,GAAG,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YAE7D,MAAM,CAAC,EAAE,CAAC,YAAY,EAAE,wCAAwC,CAAC,CAAC;QACpE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;YACxD,gCAAgC;YAChC,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE,CAAC;gBAClC,MAAM,CAAC,IAAI,CAAC,qCAAqC,CAAC,CAAC;YACrD,CAAC;YAED,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,QAAQ,CAAC,QAAQ,gBAAgB,YAAY,EAAE;oBAC5D,QAAQ,EAAE,OAAO;oBACjB,GAAG,EAAE,YAAY;iBAClB,CAAC,CAAC;gBAEH,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,8BAA8B,CAAC,CAAC;gBAC7D,MAAM,CAAC,EAAE,CACP,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,EACpD,6CAA6C,CAC9C,CAAC;YACJ,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,CAAC,IAAI,CAAC,4BAA4B,KAAK,EAAE,CAAC,CAAC;YACnD,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;YAC5D,iCAAiC;YACjC,MAAM,eAAe,GAAG,IAAI,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;YAC3D,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC,CAAC;YAEvE,MAAM,aAAa,GACjB,WAAW,CAAC,OAAO,EAAE,IAAI;gBACzB,WAAW,CAAC,OAAO,EAAE,CAAC,eAAe,CAAC;gBACtC,WAAW,CAAC,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC,qBAAqB,CAAC,CAAC;YAE9D,MAAM,CAAC,EAAE,CACP,aAAa,EACb,qDAAqD,CACtD,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;YACrD,qCAAqC;YACrC,MAAM,eAAe,GAAG,IAAI,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;YAC3D,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC,CAAC;YAEvE,MAAM,WAAW,GAAG,WAAW,CAAC,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC;YAErD,mEAAmE;YACnE,MAAM,cAAc,GAClB,WAAW,CAAC,QAAQ,CAAC,qBAAqB,CAAC;gBAC3C,WAAW,CAAC,QAAQ,CAAC,MAAM,CAAC;gBAC5B,WAAW,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC;gBAC/C,WAAW,CAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;YAEnD,MAAM,CAAC,EAAE,CACP,cAAc,EACd,6CAA6C,CAC9C,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;YACjE,yDAAyD;YACzD,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;gBAC7B,MAAM,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC;YACnD,CAAC;YAED,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC;gBACrC,YAAY,EAAE,aAAa;aAC5B,CAAC,CAAC;YAEH,MAAM,WAAW,GAAG,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;YAEvD,wDAAwD;YACxD,0EAA0E;YAC1E,MAAM,SAAS,GAAG,CAAC,CAAS,EAAE,EAAE,CAC9B,CAAC,CAAC,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;YAEhE,MAAM,CAAC,WAAW,CAChB,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,EACzB,SAAS,CAAC,WAAW,CAAC,EACtB,0EAA0E,CAC3E,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;QAExC,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;YAC1C,4BAA4B;YAC5B,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE,CAAC;gBAClC,MAAM,CAAC,IAAI,CAAC,qCAAqC,CAAC,CAAC;YACrD,CAAC;YAED,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,QAAQ,CAAC,QAAQ,gBAAgB,SAAS,EAAE;oBACzD,QAAQ,EAAE,OAAO;oBACjB,GAAG,EAAE,YAAY;iBAClB,CAAC,CAAC;gBAEH,MAAM,CAAC,EAAE,CACP,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAC/E,+BAA+B,CAChC,CAAC;YACJ,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,mEAAmE;gBACnE,MAAM,CAAC,IAAI,CAAC,uBAAuB,KAAK,EAAE,CAAC,CAAC;YAC9C,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;YACnD,qCAAqC;YACrC,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE,CAAC;gBAClC,MAAM,CAAC,IAAI,CAAC,qCAAqC,CAAC,CAAC;YACrD,CAAC;YAED,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,mBAAmB,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YAChE,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACxC,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,EAAE,sBAAsB,CAAC,CAAC;YAC7D,aAAa,CAAC,cAAc,EAAE,gBAAgB,CAAC,CAAC;YAEhD,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,QAAQ,CACrB,QAAQ,gBAAgB,eAAe,cAAc,YAAY,EACjE;oBACE,QAAQ,EAAE,OAAO;oBACjB,GAAG,EAAE,YAAY;iBAClB,CACF,CAAC;gBAEF,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,4BAA4B,CAAC,CAAC;YACzE,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,CAAC,IAAI,CAAC,gCAAgC,KAAK,EAAE,CAAC,CAAC;YACvD,CAAC;oBAAS,CAAC;gBACT,MAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACpD,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;YACvD,2CAA2C;YAC3C,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE,CAAC;gBAClC,MAAM,CAAC,IAAI,CAAC,qCAAqC,CAAC,CAAC;YACrD,CAAC;YAED,IAAI,CAAC;gBACH,QAAQ,CACN,QAAQ,gBAAgB,oCAAoC,EAC5D;oBACE,QAAQ,EAAE,OAAO;oBACjB,GAAG,EAAE,YAAY;iBAClB,CACF,CAAC;gBACF,MAAM,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC;YACzD,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,CAAC,EAAE,CAAE,KAA6B,CAAC,MAAM,KAAK,CAAC,EAAE,2CAA2C,CAAC,CAAC;YACtG,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;QAE9B,EAAE,CAAC,yCAAyC,EAAE,KAAK,IAAI,EAAE;YACvD,qCAAqC;YACrC,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,mBAAmB,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YAChE,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACxC,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,EAAE,qBAAqB,CAAC,CAAC;YAC3D,aAAa,CAAC,aAAa,EAAE,8BAA8B,CAAC,CAAC;YAE7D,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC;oBACrC,YAAY,EAAE,aAAa;iBAC5B,CAAC,CAAC;gBAEH,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,oCAAoC,CAAC,CAAC;gBAChE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,EAAE,wBAAwB,CAAC,CAAC;gBACnE,MAAM,CAAC,EAAE,CACP,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAC5B,+CAA+C,CAChD,CAAC;YACJ,CAAC;oBAAS,CAAC;gBACT,MAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACpD,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;YACjE,4CAA4C;YAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,mBAAmB,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YAChE,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACxC,MAAM,oBAAoB,GAAG,IAAI,CAAC,OAAO,EAAE,uBAAuB,CAAC,CAAC;YACpE,aAAa,CAAC,oBAAoB,EAAE;;;;;;;;;CASzC,CAAC,CAAC;YAEG,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC;oBACrC,YAAY,EAAE,oBAAoB;iBACnC,CAAC,CAAC;gBAEH,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,mCAAmC,CAAC,CAAC;gBAC/D,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,8BAA8B,CAAC,CAAC;YAChF,CAAC;oBAAS,CAAC;gBACT,MAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACpD,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;YACjE,oDAAoD;YACpD,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,mBAAmB,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YAChE,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACxC,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,EAAE,uBAAuB,CAAC,CAAC;YAC/D,aAAa,CAAC,eAAe,EAAE;;;;;;;;;;;;;;;CAepC,CAAC,CAAC;YAEG,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC;oBACrC,YAAY,EAAE,eAAe;iBAC9B,CAAC,CAAC;gBAEH,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,kCAAkC,CAAC,CAAC;gBAC9D,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,sBAAsB,CAAC,CAAC;YACxE,CAAC;oBAAS,CAAC;gBACT,MAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACpD,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pennyfarthing/shared
|
|
3
|
+
* Shared utilities for Pennyfarthing including portrait path resolution
|
|
4
|
+
*/
|
|
5
|
+
export { resolvePennyfarthingDist, resolvePortraitPath, getPortraitPaths, type PortraitPaths, } from './portrait-resolver.js';
|
|
6
|
+
export { loadTheme, listThemes, getAgentPersona, type Theme, type ThemeAgent, } from './theme-loader.js';
|
|
7
|
+
export { searchSkills, type SearchOptions, type SkillResult, } from './skill-search.js';
|
|
8
|
+
export { suggestSkills, suggestFromSession, suggestFromKeywords, type SuggestOptions, type SkillSuggestion, type SessionContext, } from './skill-suggest.js';
|
|
9
|
+
export { generateSkillDocs, type GeneratorOptions, type GeneratorResult, } from './generate-skill-docs.js';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,wBAAwB,EACxB,mBAAmB,EACnB,gBAAgB,EAChB,KAAK,aAAa,GACnB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,SAAS,EACT,UAAU,EACV,eAAe,EACf,KAAK,KAAK,EACV,KAAK,UAAU,GAChB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,YAAY,EACZ,KAAK,aAAa,EAClB,KAAK,WAAW,GACjB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,mBAAmB,EACnB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,cAAc,GACpB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,iBAAiB,EACjB,KAAK,gBAAgB,EACrB,KAAK,eAAe,GACrB,MAAM,0BAA0B,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pennyfarthing/shared
|
|
3
|
+
* Shared utilities for Pennyfarthing including portrait path resolution
|
|
4
|
+
*/
|
|
5
|
+
export { resolvePennyfarthingDist, resolvePortraitPath, getPortraitPaths, } from './portrait-resolver.js';
|
|
6
|
+
export { loadTheme, listThemes, getAgentPersona, } from './theme-loader.js';
|
|
7
|
+
export { searchSkills, } from './skill-search.js';
|
|
8
|
+
export { suggestSkills, suggestFromSession, suggestFromKeywords, } from './skill-suggest.js';
|
|
9
|
+
export { generateSkillDocs, } from './generate-skill-docs.js';
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,wBAAwB,EACxB,mBAAmB,EACnB,gBAAgB,GAEjB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,SAAS,EACT,UAAU,EACV,eAAe,GAGhB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,YAAY,GAGb,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,mBAAmB,GAIpB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,iBAAiB,GAGlB,MAAM,0BAA0B,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Portrait Resolver - Smart path resolution for Pennyfarthing portraits
|
|
3
|
+
*
|
|
4
|
+
* Checks paths in priority order:
|
|
5
|
+
* 1. PENNYFARTHING_DIST env var (explicit override)
|
|
6
|
+
* 2. Monorepo root (pennyfarthing-dist/ at repo root for dogfooding)
|
|
7
|
+
* 3. Sibling directory (for dev scenarios)
|
|
8
|
+
* 4. Scoped npm (node_modules/@pennyfarthing/core/pennyfarthing-dist/)
|
|
9
|
+
* 5. Legacy npm (node_modules/pennyfarthing/pennyfarthing-dist/)
|
|
10
|
+
*/
|
|
11
|
+
export interface PortraitPaths {
|
|
12
|
+
portraitsDir: string;
|
|
13
|
+
themesDir: string;
|
|
14
|
+
agentsDir: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Resolve the pennyfarthing-dist directory path
|
|
18
|
+
* Checks multiple locations in priority order
|
|
19
|
+
*/
|
|
20
|
+
export declare function resolvePennyfarthingDist(): string | null;
|
|
21
|
+
/**
|
|
22
|
+
* Resolve the full path to a portrait image
|
|
23
|
+
* @param theme - Theme name (e.g., 'shakespeare', 'norse-mythology')
|
|
24
|
+
* @param agent - Agent name (e.g., 'sm', 'tea', 'dev')
|
|
25
|
+
* @returns Full path to portrait file, or null if not found
|
|
26
|
+
*/
|
|
27
|
+
export declare function resolvePortraitPath(theme: string, agent: string): string | null;
|
|
28
|
+
/**
|
|
29
|
+
* Get all portrait-related paths for a resolved dist directory
|
|
30
|
+
*/
|
|
31
|
+
export declare function getPortraitPaths(distPath: string): PortraitPaths;
|
|
32
|
+
//# sourceMappingURL=portrait-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"portrait-resolver.d.ts","sourceRoot":"","sources":["../src/portrait-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAMD;;;GAGG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,GAAG,IAAI,CAgDxD;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAsE/E;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,CAShE"}
|