@pennyfarthing/shared 7.5.0 → 7.9.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.
Files changed (74) hide show
  1. package/dist/generate-skill-docs.d.ts +35 -0
  2. package/dist/generate-skill-docs.d.ts.map +1 -0
  3. package/dist/generate-skill-docs.js +442 -0
  4. package/dist/generate-skill-docs.js.map +1 -0
  5. package/dist/generate-skill-docs.test.d.ts +13 -0
  6. package/dist/generate-skill-docs.test.d.ts.map +1 -0
  7. package/dist/generate-skill-docs.test.js +519 -0
  8. package/dist/generate-skill-docs.test.js.map +1 -0
  9. package/dist/index.d.ts +11 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +13 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/marker/constants.d.ts +37 -0
  14. package/dist/marker/constants.d.ts.map +1 -0
  15. package/dist/marker/constants.js +43 -0
  16. package/dist/marker/constants.js.map +1 -0
  17. package/dist/marker/detect.d.ts +25 -0
  18. package/dist/marker/detect.d.ts.map +1 -0
  19. package/dist/marker/detect.js +53 -0
  20. package/dist/marker/detect.js.map +1 -0
  21. package/dist/marker/detect.test.d.ts +10 -0
  22. package/dist/marker/detect.test.d.ts.map +1 -0
  23. package/dist/marker/detect.test.js +417 -0
  24. package/dist/marker/detect.test.js.map +1 -0
  25. package/dist/marker/index.d.ts +14 -0
  26. package/dist/marker/index.d.ts.map +1 -0
  27. package/dist/marker/index.js +15 -0
  28. package/dist/marker/index.js.map +1 -0
  29. package/dist/marker/strip.d.ts +26 -0
  30. package/dist/marker/strip.d.ts.map +1 -0
  31. package/dist/marker/strip.js +39 -0
  32. package/dist/marker/strip.js.map +1 -0
  33. package/dist/marker/types.d.ts +23 -0
  34. package/dist/marker/types.d.ts.map +1 -0
  35. package/dist/marker/types.js +7 -0
  36. package/dist/marker/types.js.map +1 -0
  37. package/dist/migrate-theme-schema.test.d.ts +8 -0
  38. package/dist/migrate-theme-schema.test.d.ts.map +1 -0
  39. package/dist/migrate-theme-schema.test.js +67 -0
  40. package/dist/migrate-theme-schema.test.js.map +1 -0
  41. package/dist/portrait-resolver.d.ts +32 -0
  42. package/dist/portrait-resolver.d.ts.map +1 -0
  43. package/dist/portrait-resolver.js +147 -0
  44. package/dist/portrait-resolver.js.map +1 -0
  45. package/dist/portrait-resolver.test.d.ts +2 -0
  46. package/dist/portrait-resolver.test.d.ts.map +1 -0
  47. package/dist/portrait-resolver.test.js +156 -0
  48. package/dist/portrait-resolver.test.js.map +1 -0
  49. package/dist/skill-search.d.ts +36 -0
  50. package/dist/skill-search.d.ts.map +1 -0
  51. package/dist/skill-search.js +300 -0
  52. package/dist/skill-search.js.map +1 -0
  53. package/dist/skill-search.sh +41 -0
  54. package/dist/skill-search.test.d.ts +16 -0
  55. package/dist/skill-search.test.d.ts.map +1 -0
  56. package/dist/skill-search.test.js +177 -0
  57. package/dist/skill-search.test.js.map +1 -0
  58. package/dist/skill-suggest.d.ts +76 -0
  59. package/dist/skill-suggest.d.ts.map +1 -0
  60. package/dist/skill-suggest.js +256 -0
  61. package/dist/skill-suggest.js.map +1 -0
  62. package/dist/skill-suggest.test.d.ts +12 -0
  63. package/dist/skill-suggest.test.d.ts.map +1 -0
  64. package/dist/skill-suggest.test.js +257 -0
  65. package/dist/skill-suggest.test.js.map +1 -0
  66. package/dist/theme-loader.d.ts +35 -0
  67. package/dist/theme-loader.d.ts.map +1 -0
  68. package/dist/theme-loader.js +84 -0
  69. package/dist/theme-loader.js.map +1 -0
  70. package/dist/theme-loader.test.d.ts +8 -0
  71. package/dist/theme-loader.test.d.ts.map +1 -0
  72. package/dist/theme-loader.test.js +62 -0
  73. package/dist/theme-loader.test.js.map +1 -0
  74. package/package.json +4 -1
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Theme Loader - Load and parse Pennyfarthing theme configurations
3
+ */
4
+ import { existsSync, readFileSync, readdirSync } from 'node:fs';
5
+ import { join, basename } from 'node:path';
6
+ import { parse as parseYaml } from 'yaml';
7
+ import { resolvePennyfarthingDist, getPortraitPaths } from './portrait-resolver.js';
8
+ /**
9
+ * Load a theme configuration by name
10
+ * @param themeName - Name of the theme (e.g., 'shakespeare', 'norse-mythology')
11
+ * @returns Parsed theme configuration or null if not found
12
+ */
13
+ export function loadTheme(themeName) {
14
+ const distPath = resolvePennyfarthingDist();
15
+ if (!distPath) {
16
+ return null;
17
+ }
18
+ const paths = getPortraitPaths(distPath);
19
+ const themePath = join(paths.themesDir, 'themes', `${themeName}.yaml`);
20
+ if (!existsSync(themePath)) {
21
+ return null;
22
+ }
23
+ try {
24
+ const content = readFileSync(themePath, 'utf-8');
25
+ const raw = parseYaml(content);
26
+ const agents = {};
27
+ for (const [agentKey, agentData] of Object.entries(raw.agents || {})) {
28
+ agents[agentKey] = {
29
+ character: agentData.character || '',
30
+ style: agentData.style || '',
31
+ role: agentData.role || '',
32
+ trait: agentData.trait || '',
33
+ catchphrases: agentData.catchphrases || [],
34
+ helper: agentData.helper?.name,
35
+ };
36
+ }
37
+ return {
38
+ name: themeName,
39
+ description: raw.theme?.description || '',
40
+ agents,
41
+ };
42
+ }
43
+ catch {
44
+ return null;
45
+ }
46
+ }
47
+ /**
48
+ * List all available themes
49
+ * @returns Array of theme names
50
+ */
51
+ export function listThemes() {
52
+ const distPath = resolvePennyfarthingDist();
53
+ if (!distPath) {
54
+ return [];
55
+ }
56
+ const paths = getPortraitPaths(distPath);
57
+ const themesDir = join(paths.themesDir, 'themes');
58
+ if (!existsSync(themesDir)) {
59
+ return [];
60
+ }
61
+ try {
62
+ const files = readdirSync(themesDir);
63
+ return files
64
+ .filter(f => f.endsWith('.yaml'))
65
+ .map(f => basename(f, '.yaml'));
66
+ }
67
+ catch {
68
+ return [];
69
+ }
70
+ }
71
+ /**
72
+ * Get agent persona from a theme
73
+ * @param themeName - Theme name
74
+ * @param agentName - Agent name (e.g., 'sm', 'tea', 'dev')
75
+ * @returns Agent persona or null if not found
76
+ */
77
+ export function getAgentPersona(themeName, agentName) {
78
+ const theme = loadTheme(themeName);
79
+ if (!theme) {
80
+ return null;
81
+ }
82
+ return theme.agents[agentName] || null;
83
+ }
84
+ //# sourceMappingURL=theme-loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme-loader.js","sourceRoot":"","sources":["../src/theme-loader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Theme Schema Consolidation Tests - MSSCI-12478
3
+ *
4
+ * Tests for consolidating quote field into catchphrases array.
5
+ * RED STATE: These tests should FAIL until implementation is complete.
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=theme-loader.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme-loader.test.d.ts","sourceRoot":"","sources":["../src/theme-loader.test.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Theme Schema Consolidation Tests - MSSCI-12478
3
+ *
4
+ * Tests for consolidating quote field into catchphrases array.
5
+ * RED STATE: These tests should FAIL until implementation is complete.
6
+ */
7
+ import { describe, it } from 'node:test';
8
+ import assert from 'node:assert';
9
+ import { loadTheme } from './theme-loader.js';
10
+ describe('MSSCI-12478: Theme Schema Consolidation', () => {
11
+ describe('AC3: quote field removed from schema', () => {
12
+ it('ThemeAgent interface should have catchphrases array, not quote string', () => {
13
+ // Load any theme and check the agent structure
14
+ const theme = loadTheme('the-expanse');
15
+ assert.ok(theme !== null, 'Theme should load');
16
+ const agent = theme.agents['sm'];
17
+ assert.ok(agent !== undefined, 'SM agent should exist');
18
+ // Should have catchphrases array
19
+ assert.ok('catchphrases' in agent, 'Agent should have catchphrases property');
20
+ assert.ok(Array.isArray(agent.catchphrases), 'catchphrases should be an array');
21
+ // Should NOT have quote field (removed from schema)
22
+ assert.ok(!('quote' in agent), 'Agent should NOT have quote property after migration');
23
+ });
24
+ it('catchphrases array should contain at least one entry', () => {
25
+ const theme = loadTheme('the-expanse');
26
+ assert.ok(theme !== null, 'Theme should load');
27
+ const agent = theme.agents['tea'];
28
+ assert.ok(agent.catchphrases !== undefined, 'catchphrases should be defined');
29
+ assert.ok(agent.catchphrases.length > 0, 'catchphrases should have at least one entry');
30
+ });
31
+ });
32
+ describe('AC1: Migration script merges quote into catchphrases', () => {
33
+ it('original quote should be present in catchphrases array', () => {
34
+ // The Investigator's quote was "Doors and corners, kid. That's where they get you."
35
+ // After migration, this should be in the catchphrases array
36
+ const theme = loadTheme('the-expanse');
37
+ assert.ok(theme !== null, 'Theme should load');
38
+ const agent = theme.agents['orchestrator'];
39
+ assert.ok(agent.catchphrases.includes("Doors and corners, kid. That's where they get you."), 'Original quote should be in catchphrases array');
40
+ });
41
+ it('catchphrases should not have duplicates after migration', () => {
42
+ const theme = loadTheme('the-expanse');
43
+ assert.ok(theme !== null, 'Theme should load');
44
+ const agent = theme.agents['sm'];
45
+ // Check for duplicates
46
+ const uniqueCatchphrases = [...new Set(agent.catchphrases)];
47
+ assert.strictEqual(agent.catchphrases.length, uniqueCatchphrases.length, 'catchphrases should have no duplicates');
48
+ });
49
+ });
50
+ describe('AC4: Theme validation updated', () => {
51
+ it('should parse catchphrases array from YAML', () => {
52
+ const theme = loadTheme('star-trek-tng');
53
+ assert.ok(theme !== null, 'Theme should load');
54
+ // Every agent should have catchphrases parsed
55
+ for (const [agentName, agent] of Object.entries(theme.agents)) {
56
+ assert.ok(agent.catchphrases !== undefined, `Agent ${agentName} should have catchphrases`);
57
+ assert.ok(Array.isArray(agent.catchphrases), `Agent ${agentName} catchphrases should be array`);
58
+ }
59
+ });
60
+ });
61
+ });
62
+ //# sourceMappingURL=theme-loader.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme-loader.test.js","sourceRoot":"","sources":["../src/theme-loader.test.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE9C,QAAQ,CAAC,yCAAyC,EAAE,GAAG,EAAE;IAEvD,QAAQ,CAAC,sCAAsC,EAAE,GAAG,EAAE;QACpD,EAAE,CAAC,uEAAuE,EAAE,GAAG,EAAE;YAC/E,+CAA+C;YAC/C,MAAM,KAAK,GAAG,SAAS,CAAC,aAAa,CAAC,CAAC;YACvC,MAAM,CAAC,EAAE,CAAC,KAAK,KAAK,IAAI,EAAE,mBAAmB,CAAC,CAAC;YAE/C,MAAM,KAAK,GAAG,KAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM,CAAC,EAAE,CAAC,KAAK,KAAK,SAAS,EAAE,uBAAuB,CAAC,CAAC;YAExD,iCAAiC;YACjC,MAAM,CAAC,EAAE,CAAC,cAAc,IAAI,KAAK,EAAE,yCAAyC,CAAC,CAAC;YAC9E,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,iCAAiC,CAAC,CAAC;YAEhF,oDAAoD;YACpD,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,KAAK,CAAC,EAAE,sDAAsD,CAAC,CAAC;QACzF,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;YAC9D,MAAM,KAAK,GAAG,SAAS,CAAC,aAAa,CAAC,CAAC;YACvC,MAAM,CAAC,EAAE,CAAC,KAAK,KAAK,IAAI,EAAE,mBAAmB,CAAC,CAAC;YAE/C,MAAM,KAAK,GAAG,KAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAEnC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,KAAK,SAAS,EAAE,gCAAgC,CAAC,CAAC;YAC9E,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,6CAA6C,CAAC,CAAC;QAC1F,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,sDAAsD,EAAE,GAAG,EAAE;QACpE,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;YAChE,oFAAoF;YACpF,4DAA4D;YAC5D,MAAM,KAAK,GAAG,SAAS,CAAC,aAAa,CAAC,CAAC;YACvC,MAAM,CAAC,EAAE,CAAC,KAAK,KAAK,IAAI,EAAE,mBAAmB,CAAC,CAAC;YAE/C,MAAM,KAAK,GAAG,KAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;YAE5C,MAAM,CAAC,EAAE,CACP,KAAK,CAAC,YAAY,CAAC,QAAQ,CAAC,oDAAoD,CAAC,EACjF,gDAAgD,CACjD,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;YACjE,MAAM,KAAK,GAAG,SAAS,CAAC,aAAa,CAAC,CAAC;YACvC,MAAM,CAAC,EAAE,CAAC,KAAK,KAAK,IAAI,EAAE,mBAAmB,CAAC,CAAC;YAE/C,MAAM,KAAK,GAAG,KAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAElC,uBAAuB;YACvB,MAAM,kBAAkB,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC;YAC5D,MAAM,CAAC,WAAW,CAChB,KAAK,CAAC,YAAY,CAAC,MAAM,EACzB,kBAAkB,CAAC,MAAM,EACzB,wCAAwC,CACzC,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,+BAA+B,EAAE,GAAG,EAAE;QAC7C,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;YACnD,MAAM,KAAK,GAAG,SAAS,CAAC,eAAe,CAAC,CAAC;YACzC,MAAM,CAAC,EAAE,CAAC,KAAK,KAAK,IAAI,EAAE,mBAAmB,CAAC,CAAC;YAE/C,8CAA8C;YAC9C,KAAK,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAM,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC/D,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,KAAK,SAAS,EAAE,SAAS,SAAS,2BAA2B,CAAC,CAAC;gBAC3F,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,SAAS,SAAS,+BAA+B,CAAC,CAAC;YAClG,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pennyfarthing/shared",
3
- "version": "7.5.0",
3
+ "version": "7.9.0",
4
4
  "description": "Shared utilities for Pennyfarthing including portrait path resolution",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -34,5 +34,8 @@
34
34
  "devDependencies": {
35
35
  "@types/node": "^20.10.0",
36
36
  "typescript": "^5.3.3"
37
+ },
38
+ "dependencies": {
39
+ "yaml": "^2.8.2"
37
40
  }
38
41
  }