@pennyfarthing/shared 7.5.0 → 9.3.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/browser.d.ts +6 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +8 -0
- package/dist/browser.js.map +1 -0
- 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 +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/marker/constants.d.ts +39 -0
- package/dist/marker/constants.d.ts.map +1 -0
- package/dist/marker/constants.js +46 -0
- package/dist/marker/constants.js.map +1 -0
- package/dist/marker/continue.test.d.ts +12 -0
- package/dist/marker/continue.test.d.ts.map +1 -0
- package/dist/marker/continue.test.js +76 -0
- package/dist/marker/continue.test.js.map +1 -0
- package/dist/marker/detect.d.ts +25 -0
- package/dist/marker/detect.d.ts.map +1 -0
- package/dist/marker/detect.js +53 -0
- package/dist/marker/detect.js.map +1 -0
- package/dist/marker/detect.test.d.ts +10 -0
- package/dist/marker/detect.test.d.ts.map +1 -0
- package/dist/marker/detect.test.js +418 -0
- package/dist/marker/detect.test.js.map +1 -0
- package/dist/marker/index.d.ts +14 -0
- package/dist/marker/index.d.ts.map +1 -0
- package/dist/marker/index.js +15 -0
- package/dist/marker/index.js.map +1 -0
- package/dist/marker/strip.d.ts +26 -0
- package/dist/marker/strip.d.ts.map +1 -0
- package/dist/marker/strip.js +39 -0
- package/dist/marker/strip.js.map +1 -0
- package/dist/marker/types.d.ts +23 -0
- package/dist/marker/types.d.ts.map +1 -0
- package/dist/marker/types.js +7 -0
- package/dist/marker/types.js.map +1 -0
- package/dist/migrate-theme-schema.test.d.ts +8 -0
- package/dist/migrate-theme-schema.test.d.ts.map +1 -0
- package/dist/migrate-theme-schema.test.js +100 -0
- package/dist/migrate-theme-schema.test.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 +225 -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 +177 -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 +81 -0
- package/dist/theme-loader.d.ts.map +1 -0
- package/dist/theme-loader.js +491 -0
- package/dist/theme-loader.js.map +1 -0
- package/dist/theme-loader.test.d.ts +8 -0
- package/dist/theme-loader.test.d.ts.map +1 -0
- package/dist/theme-loader.test.js +62 -0
- package/dist/theme-loader.test.js.map +1 -0
- package/package.json +14 -1
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { describe, it, afterEach } from 'node:test';
|
|
2
|
+
import assert from 'node:assert';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { resolvePennyfarthingDist, resolvePortraitPath, getPortraitPaths, } from './portrait-resolver.js';
|
|
5
|
+
describe('portrait-resolver', () => {
|
|
6
|
+
describe('resolvePennyfarthingDist', () => {
|
|
7
|
+
const originalEnv = process.env.PENNYFARTHING_DIST;
|
|
8
|
+
afterEach(() => {
|
|
9
|
+
// Restore original env
|
|
10
|
+
if (originalEnv !== undefined) {
|
|
11
|
+
process.env.PENNYFARTHING_DIST = originalEnv;
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
delete process.env.PENNYFARTHING_DIST;
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
it('should return PENNYFARTHING_DIST env var when set and path exists', () => {
|
|
18
|
+
// Scenario 1: Explicit env var override with existing path
|
|
19
|
+
// Use the actual pennyfarthing-dist path that exists
|
|
20
|
+
const actualDistPath = resolvePennyfarthingDist();
|
|
21
|
+
assert.ok(actualDistPath !== null, 'Should have a valid dist path');
|
|
22
|
+
process.env.PENNYFARTHING_DIST = actualDistPath;
|
|
23
|
+
const result = resolvePennyfarthingDist();
|
|
24
|
+
// When env var is set to valid existing path, should return it
|
|
25
|
+
assert.strictEqual(result, actualDistPath);
|
|
26
|
+
});
|
|
27
|
+
it('should fall through when PENNYFARTHING_DIST is set but path does not exist', () => {
|
|
28
|
+
// Scenario 1b: Env var set but invalid - should fall through to other checks
|
|
29
|
+
process.env.PENNYFARTHING_DIST = '/nonexistent/path/pennyfarthing-dist';
|
|
30
|
+
const result = resolvePennyfarthingDist();
|
|
31
|
+
// Should fall through and find monorepo path (since we're in monorepo)
|
|
32
|
+
// The key behavior is it doesn't return the invalid env var path
|
|
33
|
+
assert.ok(result === null || !result.includes('/nonexistent/'));
|
|
34
|
+
});
|
|
35
|
+
it('should find monorepo root pennyfarthing-dist directory', () => {
|
|
36
|
+
// Scenario 2: Monorepo root detection (dogfooding)
|
|
37
|
+
// When running from within pennyfarthing repo, find pennyfarthing-dist/ at root
|
|
38
|
+
delete process.env.PENNYFARTHING_DIST;
|
|
39
|
+
const result = resolvePennyfarthingDist();
|
|
40
|
+
// Should find the monorepo root path
|
|
41
|
+
assert.ok(result !== null, 'Should find monorepo root');
|
|
42
|
+
assert.ok(result.endsWith('pennyfarthing-dist'), 'Path should end with pennyfarthing-dist');
|
|
43
|
+
});
|
|
44
|
+
it('should find sibling pennyfarthing-dist directory', () => {
|
|
45
|
+
// Scenario 3: Sibling directory for dev scenarios
|
|
46
|
+
// e.g., project/pennyfarthing-dist when called from project/packages/shared
|
|
47
|
+
delete process.env.PENNYFARTHING_DIST;
|
|
48
|
+
const result = resolvePennyfarthingDist();
|
|
49
|
+
// Implementation should check ../pennyfarthing-dist, ../../pennyfarthing-dist, etc.
|
|
50
|
+
assert.ok(result === null || result.includes('pennyfarthing-dist'));
|
|
51
|
+
});
|
|
52
|
+
it('should find scoped npm package path', () => {
|
|
53
|
+
// Scenario 4: Scoped npm install
|
|
54
|
+
// node_modules/@pennyfarthing/core/pennyfarthing-dist/
|
|
55
|
+
delete process.env.PENNYFARTHING_DIST;
|
|
56
|
+
const result = resolvePennyfarthingDist();
|
|
57
|
+
// When installed via @pennyfarthing/core, should find that path
|
|
58
|
+
assert.ok(result === null || result.includes('pennyfarthing-dist'));
|
|
59
|
+
});
|
|
60
|
+
it('should find legacy npm package path', () => {
|
|
61
|
+
// Scenario 5: Legacy npm install
|
|
62
|
+
// node_modules/pennyfarthing/pennyfarthing-dist/
|
|
63
|
+
delete process.env.PENNYFARTHING_DIST;
|
|
64
|
+
const result = resolvePennyfarthingDist();
|
|
65
|
+
// When installed via pennyfarthing, should find that path
|
|
66
|
+
assert.ok(result === null || result.includes('pennyfarthing-dist'));
|
|
67
|
+
});
|
|
68
|
+
it('should return a valid path or null', () => {
|
|
69
|
+
// This tests that the function returns a valid result
|
|
70
|
+
delete process.env.PENNYFARTHING_DIST;
|
|
71
|
+
const result = resolvePennyfarthingDist();
|
|
72
|
+
// Result should be either null or a valid pennyfarthing-dist path
|
|
73
|
+
if (result !== null) {
|
|
74
|
+
assert.ok(result.includes('pennyfarthing-dist'));
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
it('should check paths in priority order - env var takes precedence', () => {
|
|
78
|
+
// When multiple paths exist, env var should return first if it exists
|
|
79
|
+
const actualDistPath = resolvePennyfarthingDist();
|
|
80
|
+
assert.ok(actualDistPath !== null, 'Should have a valid dist path');
|
|
81
|
+
// Set env var to actual path
|
|
82
|
+
process.env.PENNYFARTHING_DIST = actualDistPath;
|
|
83
|
+
const result = resolvePennyfarthingDist();
|
|
84
|
+
// Env var should take precedence (returns same path since it exists)
|
|
85
|
+
assert.strictEqual(result, actualDistPath);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
describe('resolvePortraitPath', () => {
|
|
89
|
+
it('should resolve portrait path for valid theme and agent', () => {
|
|
90
|
+
// Use a-team which has actual portraits (shakespeare has only .gitkeep)
|
|
91
|
+
const result = resolvePortraitPath('a-team', 'sm');
|
|
92
|
+
assert.ok(result !== null, 'Should find portrait');
|
|
93
|
+
assert.ok(result.includes('a-team'), 'Path should include theme');
|
|
94
|
+
// Portrait files use character names (faceman) not agent names (sm)
|
|
95
|
+
assert.ok(result.includes('face'), 'Path should include character name');
|
|
96
|
+
assert.ok(result.endsWith('.png') || result.endsWith('.jpg'), 'Should be image file');
|
|
97
|
+
});
|
|
98
|
+
it('should return null for invalid theme', () => {
|
|
99
|
+
const result = resolvePortraitPath('nonexistent-theme', 'sm');
|
|
100
|
+
assert.strictEqual(result, null);
|
|
101
|
+
});
|
|
102
|
+
it('should return null for invalid agent', () => {
|
|
103
|
+
const result = resolvePortraitPath('a-team', 'nonexistent-agent');
|
|
104
|
+
assert.strictEqual(result, null);
|
|
105
|
+
});
|
|
106
|
+
it('should handle theme with special characters in name', () => {
|
|
107
|
+
// Themes like 'star-trek-tos' have hyphens
|
|
108
|
+
const result = resolvePortraitPath('star-trek-tos', 'sm');
|
|
109
|
+
assert.ok(result === null || result.includes('star-trek-tos'));
|
|
110
|
+
});
|
|
111
|
+
it('should handle portrait resolution when dist is found', () => {
|
|
112
|
+
// When resolvePennyfarthingDist returns a valid path, we should be able
|
|
113
|
+
// to resolve portraits for known themes
|
|
114
|
+
delete process.env.PENNYFARTHING_DIST;
|
|
115
|
+
const result = resolvePortraitPath('a-team', 'dev');
|
|
116
|
+
// If dist is found (which it is in monorepo), should find portrait
|
|
117
|
+
// dev maps to ba in a-team theme
|
|
118
|
+
if (result !== null) {
|
|
119
|
+
assert.ok(result.includes('a-team'));
|
|
120
|
+
assert.ok(result.includes('ba'));
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
describe('getPortraitPaths', () => {
|
|
125
|
+
it('should return correct paths structure', () => {
|
|
126
|
+
const distPath = '/test/pennyfarthing-dist';
|
|
127
|
+
const result = getPortraitPaths(distPath);
|
|
128
|
+
assert.ok('portraitsDir' in result, 'Should have portraitsDir');
|
|
129
|
+
assert.ok('themesDir' in result, 'Should have themesDir');
|
|
130
|
+
assert.ok('agentsDir' in result, 'Should have agentsDir');
|
|
131
|
+
});
|
|
132
|
+
it('should build portraitsDir correctly', () => {
|
|
133
|
+
const distPath = '/test/pennyfarthing-dist';
|
|
134
|
+
const result = getPortraitPaths(distPath);
|
|
135
|
+
// Actual structure: pennyfarthing-dist/personas/portraits/
|
|
136
|
+
assert.strictEqual(result.portraitsDir, path.join(distPath, 'personas', 'portraits'), 'portraitsDir should be distPath/personas/portraits');
|
|
137
|
+
});
|
|
138
|
+
it('should build themesDir correctly', () => {
|
|
139
|
+
const distPath = '/test/pennyfarthing-dist';
|
|
140
|
+
const result = getPortraitPaths(distPath);
|
|
141
|
+
assert.strictEqual(result.themesDir, path.join(distPath, 'personas'), 'themesDir should be distPath/personas');
|
|
142
|
+
});
|
|
143
|
+
it('should build agentsDir correctly', () => {
|
|
144
|
+
const distPath = '/test/pennyfarthing-dist';
|
|
145
|
+
const result = getPortraitPaths(distPath);
|
|
146
|
+
assert.strictEqual(result.agentsDir, path.join(distPath, 'agents'), 'agentsDir should be distPath/agents');
|
|
147
|
+
});
|
|
148
|
+
it('should handle paths with trailing slashes', () => {
|
|
149
|
+
const distPath = '/test/pennyfarthing-dist/';
|
|
150
|
+
const result = getPortraitPaths(distPath);
|
|
151
|
+
// Should normalize paths correctly
|
|
152
|
+
assert.ok(!result.portraitsDir.includes('//'), 'Should not have double slashes');
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
//# sourceMappingURL=portrait-resolver.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"portrait-resolver.test.js","sourceRoot":"","sources":["../src/portrait-resolver.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EACL,wBAAwB,EACxB,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,wBAAwB,CAAC;AAEhC,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;QACxC,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;QAEnD,SAAS,CAAC,GAAG,EAAE;YACb,uBAAuB;YACvB,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;gBAC9B,OAAO,CAAC,GAAG,CAAC,kBAAkB,GAAG,WAAW,CAAC;YAC/C,CAAC;iBAAM,CAAC;gBACN,OAAO,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;YACxC,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;YAC3E,2DAA2D;YAC3D,qDAAqD;YACrD,MAAM,cAAc,GAAG,wBAAwB,EAAE,CAAC;YAClD,MAAM,CAAC,EAAE,CAAC,cAAc,KAAK,IAAI,EAAE,+BAA+B,CAAC,CAAC;YAEpE,OAAO,CAAC,GAAG,CAAC,kBAAkB,GAAG,cAAe,CAAC;YAEjD,MAAM,MAAM,GAAG,wBAAwB,EAAE,CAAC;YAE1C,+DAA+D;YAC/D,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4EAA4E,EAAE,GAAG,EAAE;YACpF,6EAA6E;YAC7E,OAAO,CAAC,GAAG,CAAC,kBAAkB,GAAG,sCAAsC,CAAC;YAExE,MAAM,MAAM,GAAG,wBAAwB,EAAE,CAAC;YAE1C,uEAAuE;YACvE,iEAAiE;YACjE,MAAM,CAAC,EAAE,CAAC,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC;QAClE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;YAChE,mDAAmD;YACnD,gFAAgF;YAChF,OAAO,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;YAEtC,MAAM,MAAM,GAAG,wBAAwB,EAAE,CAAC;YAE1C,qCAAqC;YACrC,MAAM,CAAC,EAAE,CAAC,MAAM,KAAK,IAAI,EAAE,2BAA2B,CAAC,CAAC;YACxD,MAAM,CAAC,EAAE,CAAC,MAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAC,EAAE,yCAAyC,CAAC,CAAC;QAC/F,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;YAC1D,kDAAkD;YAClD,4EAA4E;YAC5E,OAAO,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;YAEtC,MAAM,MAAM,GAAG,wBAAwB,EAAE,CAAC;YAE1C,oFAAoF;YACpF,MAAM,CAAC,EAAE,CAAC,MAAM,KAAK,IAAI,IAAI,MAAM,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC,CAAC;QACtE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;YAC7C,iCAAiC;YACjC,uDAAuD;YACvD,OAAO,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;YAEtC,MAAM,MAAM,GAAG,wBAAwB,EAAE,CAAC;YAE1C,gEAAgE;YAChE,MAAM,CAAC,EAAE,CAAC,MAAM,KAAK,IAAI,IAAI,MAAM,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC,CAAC;QACtE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;YAC7C,iCAAiC;YACjC,iDAAiD;YACjD,OAAO,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;YAEtC,MAAM,MAAM,GAAG,wBAAwB,EAAE,CAAC;YAE1C,0DAA0D;YAC1D,MAAM,CAAC,EAAE,CAAC,MAAM,KAAK,IAAI,IAAI,MAAM,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC,CAAC;QACtE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;YAC5C,sDAAsD;YACtD,OAAO,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;YAEtC,MAAM,MAAM,GAAG,wBAAwB,EAAE,CAAC;YAE1C,kEAAkE;YAClE,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;gBACpB,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC,CAAC;YACnD,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;YACzE,sEAAsE;YACtE,MAAM,cAAc,GAAG,wBAAwB,EAAE,CAAC;YAClD,MAAM,CAAC,EAAE,CAAC,cAAc,KAAK,IAAI,EAAE,+BAA+B,CAAC,CAAC;YAEpE,6BAA6B;YAC7B,OAAO,CAAC,GAAG,CAAC,kBAAkB,GAAG,cAAe,CAAC;YAEjD,MAAM,MAAM,GAAG,wBAAwB,EAAE,CAAC;YAE1C,qEAAqE;YACrE,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;QACnC,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;YAChE,wEAAwE;YACxE,MAAM,MAAM,GAAG,mBAAmB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YAEnD,MAAM,CAAC,EAAE,CAAC,MAAM,KAAK,IAAI,EAAE,sBAAsB,CAAC,CAAC;YACnD,MAAM,CAAC,EAAE,CAAC,MAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,2BAA2B,CAAC,CAAC;YACnE,oEAAoE;YACpE,MAAM,CAAC,EAAE,CAAC,MAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,oCAAoC,CAAC,CAAC;YAC1E,MAAM,CAAC,EAAE,CAAC,MAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,sBAAsB,CAAC,CAAC;QAC1F,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;YAC9C,MAAM,MAAM,GAAG,mBAAmB,CAAC,mBAAmB,EAAE,IAAI,CAAC,CAAC;YAE9D,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;YAC9C,MAAM,MAAM,GAAG,mBAAmB,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAC;YAElE,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;YAC7D,2CAA2C;YAC3C,MAAM,MAAM,GAAG,mBAAmB,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC;YAE1D,MAAM,CAAC,EAAE,CAAC,MAAM,KAAK,IAAI,IAAI,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC;QACjE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;YAC9D,wEAAwE;YACxE,wCAAwC;YACxC,OAAO,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;YAEtC,MAAM,MAAM,GAAG,mBAAmB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;YAEpD,mEAAmE;YACnE,iCAAiC;YACjC,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;gBACpB,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;gBACrC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;YACnC,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAChC,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;YAC/C,MAAM,QAAQ,GAAG,0BAA0B,CAAC;YAC5C,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;YAE1C,MAAM,CAAC,EAAE,CAAC,cAAc,IAAI,MAAM,EAAE,0BAA0B,CAAC,CAAC;YAChE,MAAM,CAAC,EAAE,CAAC,WAAW,IAAI,MAAM,EAAE,uBAAuB,CAAC,CAAC;YAC1D,MAAM,CAAC,EAAE,CAAC,WAAW,IAAI,MAAM,EAAE,uBAAuB,CAAC,CAAC;QAC5D,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;YAC7C,MAAM,QAAQ,GAAG,0BAA0B,CAAC;YAC5C,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;YAE1C,2DAA2D;YAC3D,MAAM,CAAC,WAAW,CAChB,MAAM,CAAC,YAAY,EACnB,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE,WAAW,CAAC,EAC5C,oDAAoD,CACrD,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;YAC1C,MAAM,QAAQ,GAAG,0BAA0B,CAAC;YAC5C,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;YAE1C,MAAM,CAAC,WAAW,CAChB,MAAM,CAAC,SAAS,EAChB,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,EAC/B,uCAAuC,CACxC,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;YAC1C,MAAM,QAAQ,GAAG,0BAA0B,CAAC;YAC5C,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;YAE1C,MAAM,CAAC,WAAW,CAChB,MAAM,CAAC,SAAS,EAChB,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAC7B,qCAAqC,CACtC,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;YACnD,MAAM,QAAQ,GAAG,2BAA2B,CAAC;YAC7C,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;YAE1C,mCAAmC;YACnC,MAAM,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,gCAAgC,CAAC,CAAC;QACnF,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill Search Utility - Story 9-2
|
|
3
|
+
*
|
|
4
|
+
* Searches the skill registry by tag, keyword, category, or description query.
|
|
5
|
+
* Returns matching skills with metadata for discovery and suggestions.
|
|
6
|
+
*/
|
|
7
|
+
export interface SearchOptions {
|
|
8
|
+
/** Filter by tag (e.g., "tdd", "quality") */
|
|
9
|
+
tag?: string;
|
|
10
|
+
/** Filter by keyword (e.g., "jest", "vitest") */
|
|
11
|
+
keyword?: string;
|
|
12
|
+
/** Search description text */
|
|
13
|
+
query?: string;
|
|
14
|
+
/** Filter by category (e.g., "development", "tools") */
|
|
15
|
+
category?: string;
|
|
16
|
+
/** Custom path to registry file (for testing) */
|
|
17
|
+
registryPath?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface SkillResult {
|
|
20
|
+
name: string;
|
|
21
|
+
description: string;
|
|
22
|
+
category: string;
|
|
23
|
+
tags: string[];
|
|
24
|
+
keywords?: string[];
|
|
25
|
+
version?: string;
|
|
26
|
+
related_skills?: string[];
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Search skills in the registry based on provided options.
|
|
30
|
+
*
|
|
31
|
+
* @param options - Search options (tag, keyword, query, category)
|
|
32
|
+
* @returns Promise resolving to array of matching skills
|
|
33
|
+
* @throws Error if registry file not found or invalid category
|
|
34
|
+
*/
|
|
35
|
+
export declare function searchSkills(options: SearchOptions): Promise<SkillResult[]>;
|
|
36
|
+
//# sourceMappingURL=skill-search.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-search.d.ts","sourceRoot":"","sources":["../src/skill-search.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,WAAW,aAAa;IAC5B,6CAA6C;IAC7C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wDAAwD;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iDAAiD;IACjD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAmLD;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAoEjF"}
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill Search Utility - Story 9-2
|
|
3
|
+
*
|
|
4
|
+
* Searches the skill registry by tag, keyword, category, or description query.
|
|
5
|
+
* Returns matching skills with metadata for discovery and suggestions.
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
import { resolvePennyfarthingDist } from './portrait-resolver.js';
|
|
10
|
+
/** Valid categories from the registry */
|
|
11
|
+
const VALID_CATEGORIES = [
|
|
12
|
+
'ai-llm',
|
|
13
|
+
'documentation',
|
|
14
|
+
'development',
|
|
15
|
+
'tools',
|
|
16
|
+
'benchmarking',
|
|
17
|
+
'project-management',
|
|
18
|
+
'theming'
|
|
19
|
+
];
|
|
20
|
+
/**
|
|
21
|
+
* Simple YAML parser for skill registry
|
|
22
|
+
* Handles nested objects and arrays in the specific structure we need
|
|
23
|
+
*/
|
|
24
|
+
function parseRegistryYaml(content) {
|
|
25
|
+
const result = { version: '', skills: {} };
|
|
26
|
+
const lines = content.split('\n');
|
|
27
|
+
let currentSkillKey = null;
|
|
28
|
+
let currentArrayField = null;
|
|
29
|
+
let insideExamples = false;
|
|
30
|
+
for (const line of lines) {
|
|
31
|
+
const trimmed = line.trimEnd();
|
|
32
|
+
// Skip empty lines and comments
|
|
33
|
+
if (!trimmed || trimmed.startsWith('#'))
|
|
34
|
+
continue;
|
|
35
|
+
const indent = line.length - line.trimStart().length;
|
|
36
|
+
const colonIndex = trimmed.indexOf(':');
|
|
37
|
+
const key = colonIndex >= 0 ? trimmed.substring(0, colonIndex).trim() : trimmed.trim();
|
|
38
|
+
const value = colonIndex >= 0 ? trimmed.substring(colonIndex + 1).trim() : '';
|
|
39
|
+
// Top-level version
|
|
40
|
+
if (indent === 0 && key === 'version') {
|
|
41
|
+
result.version = value.replace(/^["']|["']$/g, '');
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
// Top-level skills key
|
|
45
|
+
if (indent === 0 && key === 'skills') {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
// Skill key (indent 2)
|
|
49
|
+
if (indent === 2 && !trimmed.startsWith('-')) {
|
|
50
|
+
currentSkillKey = key;
|
|
51
|
+
result.skills[currentSkillKey] = {
|
|
52
|
+
name: '',
|
|
53
|
+
description: '',
|
|
54
|
+
category: '',
|
|
55
|
+
tags: [],
|
|
56
|
+
version: '',
|
|
57
|
+
prerequisites: [],
|
|
58
|
+
examples: [],
|
|
59
|
+
anti_patterns: [],
|
|
60
|
+
related_skills: [],
|
|
61
|
+
keywords: []
|
|
62
|
+
};
|
|
63
|
+
currentArrayField = null;
|
|
64
|
+
insideExamples = false;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
// Skill fields (indent 4)
|
|
68
|
+
if (indent === 4 && currentSkillKey) {
|
|
69
|
+
insideExamples = false;
|
|
70
|
+
currentArrayField = null;
|
|
71
|
+
if (key === 'name') {
|
|
72
|
+
result.skills[currentSkillKey].name = value.replace(/^["']|["']$/g, '');
|
|
73
|
+
}
|
|
74
|
+
else if (key === 'description') {
|
|
75
|
+
result.skills[currentSkillKey].description = value.replace(/^["']|["']$/g, '');
|
|
76
|
+
}
|
|
77
|
+
else if (key === 'category') {
|
|
78
|
+
result.skills[currentSkillKey].category = value.replace(/^["']|["']$/g, '');
|
|
79
|
+
}
|
|
80
|
+
else if (key === 'version') {
|
|
81
|
+
result.skills[currentSkillKey].version = value.replace(/^["']|["']$/g, '');
|
|
82
|
+
}
|
|
83
|
+
else if (key === 'tags') {
|
|
84
|
+
// Inline array: [tag1, tag2]
|
|
85
|
+
if (value.startsWith('[')) {
|
|
86
|
+
result.skills[currentSkillKey].tags = parseInlineArray(value);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
currentArrayField = 'tags';
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
else if (key === 'keywords') {
|
|
93
|
+
if (value.startsWith('[')) {
|
|
94
|
+
result.skills[currentSkillKey].keywords = parseInlineArray(value);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
currentArrayField = 'keywords';
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
else if (key === 'prerequisites') {
|
|
101
|
+
if (value.startsWith('[')) {
|
|
102
|
+
result.skills[currentSkillKey].prerequisites = parseInlineArray(value);
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
currentArrayField = 'prerequisites';
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
else if (key === 'related_skills') {
|
|
109
|
+
if (value.startsWith('[')) {
|
|
110
|
+
result.skills[currentSkillKey].related_skills = parseInlineArray(value);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
currentArrayField = 'related_skills';
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
else if (key === 'anti_patterns') {
|
|
117
|
+
currentArrayField = 'anti_patterns';
|
|
118
|
+
}
|
|
119
|
+
else if (key === 'examples') {
|
|
120
|
+
insideExamples = true;
|
|
121
|
+
currentArrayField = null;
|
|
122
|
+
}
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
// Array items (indent 6 starting with -)
|
|
126
|
+
if (indent === 6 && currentSkillKey && trimmed.startsWith('-')) {
|
|
127
|
+
const itemValue = trimmed.substring(1).trim().replace(/^["']|["']$/g, '');
|
|
128
|
+
if (insideExamples) {
|
|
129
|
+
// Start of a new example object
|
|
130
|
+
result.skills[currentSkillKey].examples.push({ context: '', invocation: '' });
|
|
131
|
+
}
|
|
132
|
+
else if (currentArrayField && currentArrayField in result.skills[currentSkillKey]) {
|
|
133
|
+
const arr = result.skills[currentSkillKey][currentArrayField];
|
|
134
|
+
if (Array.isArray(arr) && typeof arr[0] !== 'object') {
|
|
135
|
+
arr.push(itemValue);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
// Example sub-fields (indent 8)
|
|
141
|
+
if (indent === 8 && currentSkillKey && insideExamples) {
|
|
142
|
+
const examples = result.skills[currentSkillKey].examples;
|
|
143
|
+
if (examples.length > 0) {
|
|
144
|
+
const lastExample = examples[examples.length - 1];
|
|
145
|
+
if (key === 'context') {
|
|
146
|
+
lastExample.context = value.replace(/^["']|["']$/g, '');
|
|
147
|
+
}
|
|
148
|
+
else if (key === 'invocation') {
|
|
149
|
+
lastExample.invocation = value.replace(/^["']|["']$/g, '');
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return result;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Parse inline YAML array like [tag1, tag2, tag3]
|
|
159
|
+
*/
|
|
160
|
+
function parseInlineArray(value) {
|
|
161
|
+
const match = value.match(/^\[(.*)\]$/);
|
|
162
|
+
if (!match)
|
|
163
|
+
return [];
|
|
164
|
+
return match[1]
|
|
165
|
+
.split(',')
|
|
166
|
+
.map(item => item.trim().replace(/^["']|["']$/g, ''))
|
|
167
|
+
.filter(Boolean);
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Search skills in the registry based on provided options.
|
|
171
|
+
*
|
|
172
|
+
* @param options - Search options (tag, keyword, query, category)
|
|
173
|
+
* @returns Promise resolving to array of matching skills
|
|
174
|
+
* @throws Error if registry file not found or invalid category
|
|
175
|
+
*/
|
|
176
|
+
export async function searchSkills(options) {
|
|
177
|
+
// Resolve registry path
|
|
178
|
+
let registryPath = options.registryPath;
|
|
179
|
+
if (!registryPath) {
|
|
180
|
+
const distPath = resolvePennyfarthingDist();
|
|
181
|
+
if (!distPath) {
|
|
182
|
+
throw new Error('Registry not found: Cannot resolve pennyfarthing-dist directory');
|
|
183
|
+
}
|
|
184
|
+
registryPath = join(distPath, 'skills', 'skill-registry.yaml');
|
|
185
|
+
}
|
|
186
|
+
// Validate registry exists
|
|
187
|
+
if (!existsSync(registryPath)) {
|
|
188
|
+
throw new Error(`Registry not found: ${registryPath}`);
|
|
189
|
+
}
|
|
190
|
+
// Validate category if provided
|
|
191
|
+
if (options.category && !VALID_CATEGORIES.includes(options.category)) {
|
|
192
|
+
throw new Error(`Invalid category: ${options.category}. Valid categories: ${VALID_CATEGORIES.join(', ')}`);
|
|
193
|
+
}
|
|
194
|
+
// Parse registry
|
|
195
|
+
const content = readFileSync(registryPath, 'utf-8');
|
|
196
|
+
const registry = parseRegistryYaml(content);
|
|
197
|
+
// Convert to SkillResult array
|
|
198
|
+
let results = Object.values(registry.skills).map(skill => ({
|
|
199
|
+
name: skill.name,
|
|
200
|
+
description: skill.description,
|
|
201
|
+
category: skill.category,
|
|
202
|
+
tags: skill.tags,
|
|
203
|
+
keywords: skill.keywords.length > 0 ? skill.keywords : undefined,
|
|
204
|
+
version: skill.version || undefined,
|
|
205
|
+
related_skills: skill.related_skills.length > 0 ? skill.related_skills : undefined
|
|
206
|
+
}));
|
|
207
|
+
// Apply filters (AND logic - all filters must match)
|
|
208
|
+
// Filter by category
|
|
209
|
+
if (options.category) {
|
|
210
|
+
results = results.filter(s => s.category === options.category);
|
|
211
|
+
}
|
|
212
|
+
// Filter by tag (case-insensitive)
|
|
213
|
+
if (options.tag) {
|
|
214
|
+
const searchTag = options.tag.toLowerCase();
|
|
215
|
+
results = results.filter(s => s.tags.some(t => t.toLowerCase() === searchTag));
|
|
216
|
+
}
|
|
217
|
+
// Filter by keyword (case-insensitive)
|
|
218
|
+
if (options.keyword) {
|
|
219
|
+
const searchKeyword = options.keyword.toLowerCase();
|
|
220
|
+
results = results.filter(s => s.keywords?.some(k => k.toLowerCase() === searchKeyword));
|
|
221
|
+
}
|
|
222
|
+
// Filter by query (searches description, case-insensitive)
|
|
223
|
+
if (options.query) {
|
|
224
|
+
const searchQuery = options.query.toLowerCase();
|
|
225
|
+
results = results.filter(s => s.description.toLowerCase().includes(searchQuery));
|
|
226
|
+
}
|
|
227
|
+
return results;
|
|
228
|
+
}
|
|
229
|
+
// CLI entry point when run directly
|
|
230
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
231
|
+
const args = process.argv.slice(2);
|
|
232
|
+
const options = {};
|
|
233
|
+
let jsonOutput = false;
|
|
234
|
+
// Parse command-line arguments
|
|
235
|
+
for (let i = 0; i < args.length; i++) {
|
|
236
|
+
const arg = args[i];
|
|
237
|
+
if (arg === '--help' || arg === '-h') {
|
|
238
|
+
console.log(`Usage: skill-search [options]
|
|
239
|
+
|
|
240
|
+
Options:
|
|
241
|
+
--tag <tag> Filter by tag (e.g., "tdd", "quality")
|
|
242
|
+
--keyword <kw> Filter by keyword (e.g., "jest", "vitest")
|
|
243
|
+
--query <text> Search description text
|
|
244
|
+
--category <cat> Filter by category
|
|
245
|
+
--json Output as JSON (default: table)
|
|
246
|
+
--help, -h Show this help
|
|
247
|
+
|
|
248
|
+
Examples:
|
|
249
|
+
skill-search --tag tdd
|
|
250
|
+
skill-search --category development --json
|
|
251
|
+
skill-search --query "TDD workflow"
|
|
252
|
+
`);
|
|
253
|
+
process.exit(0);
|
|
254
|
+
}
|
|
255
|
+
else if (arg === '--json') {
|
|
256
|
+
jsonOutput = true;
|
|
257
|
+
}
|
|
258
|
+
else if (arg === '--tag' && args[i + 1]) {
|
|
259
|
+
options.tag = args[++i];
|
|
260
|
+
}
|
|
261
|
+
else if (arg === '--keyword' && args[i + 1]) {
|
|
262
|
+
options.keyword = args[++i];
|
|
263
|
+
}
|
|
264
|
+
else if (arg === '--query' && args[i + 1]) {
|
|
265
|
+
options.query = args[++i];
|
|
266
|
+
}
|
|
267
|
+
else if (arg === '--category' && args[i + 1]) {
|
|
268
|
+
options.category = args[++i];
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
searchSkills(options)
|
|
272
|
+
.then(results => {
|
|
273
|
+
if (jsonOutput) {
|
|
274
|
+
console.log(JSON.stringify(results, null, 2));
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
// Table output
|
|
278
|
+
if (results.length === 0) {
|
|
279
|
+
console.log('No skills found matching criteria.');
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
const maxName = Math.max(...results.map(s => s.name.length), 4);
|
|
283
|
+
const maxCat = Math.max(...results.map(s => s.category.length), 8);
|
|
284
|
+
console.log(`${'NAME'.padEnd(maxName)} ${'CATEGORY'.padEnd(maxCat)} DESCRIPTION`);
|
|
285
|
+
console.log(`${'-'.repeat(maxName)} ${'-'.repeat(maxCat)} ${'-'.repeat(40)}`);
|
|
286
|
+
for (const skill of results) {
|
|
287
|
+
const desc = skill.description.length > 50
|
|
288
|
+
? skill.description.substring(0, 47) + '...'
|
|
289
|
+
: skill.description;
|
|
290
|
+
console.log(`${skill.name.padEnd(maxName)} ${skill.category.padEnd(maxCat)} ${desc}`);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
})
|
|
295
|
+
.catch(err => {
|
|
296
|
+
console.error(`Error: ${err.message}`);
|
|
297
|
+
process.exit(1);
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
//# sourceMappingURL=skill-search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-search.js","sourceRoot":"","sources":["../src/skill-search.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Skill Search Shell Wrapper - Story 9-2
|
|
3
|
+
#
|
|
4
|
+
# Thin wrapper around the TypeScript skill-search utility.
|
|
5
|
+
# Provides CLI access to skill registry search functionality.
|
|
6
|
+
#
|
|
7
|
+
# Usage:
|
|
8
|
+
# skill-search.sh [options]
|
|
9
|
+
#
|
|
10
|
+
# Options:
|
|
11
|
+
# --tag <tag> Filter by tag (e.g., "tdd", "quality")
|
|
12
|
+
# --keyword <kw> Filter by keyword (e.g., "jest", "vitest")
|
|
13
|
+
# --query <text> Search description text
|
|
14
|
+
# --category <cat> Filter by category
|
|
15
|
+
# --json Output as JSON (default: table)
|
|
16
|
+
# --help, -h Show this help
|
|
17
|
+
#
|
|
18
|
+
# Examples:
|
|
19
|
+
# skill-search.sh --tag tdd
|
|
20
|
+
# skill-search.sh --category development --json
|
|
21
|
+
# skill-search.sh --query "TDD workflow"
|
|
22
|
+
|
|
23
|
+
set -euo pipefail
|
|
24
|
+
|
|
25
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
26
|
+
|
|
27
|
+
# Find the compiled JavaScript file
|
|
28
|
+
JS_FILE="$SCRIPT_DIR/../dist/skill-search.js"
|
|
29
|
+
|
|
30
|
+
if [[ ! -f "$JS_FILE" ]]; then
|
|
31
|
+
# Try looking relative to where we are in the repo
|
|
32
|
+
JS_FILE="$(dirname "$SCRIPT_DIR")/dist/skill-search.js"
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
if [[ ! -f "$JS_FILE" ]]; then
|
|
36
|
+
echo "Error: skill-search.js not found. Run 'npm run build' first." >&2
|
|
37
|
+
exit 1
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
# Execute the Node.js script with all arguments
|
|
41
|
+
exec node "$JS_FILE" "$@"
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for Story 9-2: Build Skill Search Utility
|
|
3
|
+
*
|
|
4
|
+
* These tests verify:
|
|
5
|
+
* - Tag filtering returns expected skills
|
|
6
|
+
* - Keyword search returns expected skills
|
|
7
|
+
* - Category filtering works
|
|
8
|
+
* - Combined filters use AND logic
|
|
9
|
+
* - JSON output is valid and includes required fields
|
|
10
|
+
* - Empty results return empty array (not error)
|
|
11
|
+
* - Error handling for missing registry
|
|
12
|
+
*
|
|
13
|
+
* Run with: npm test -- scripts/utils/skill-search.test.ts
|
|
14
|
+
*/
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=skill-search.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-search.test.d.ts","sourceRoot":"","sources":["../src/skill-search.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG"}
|