@forwardimpact/pathway 0.4.0 → 0.5.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 (69) hide show
  1. package/app/commands/behaviour.js +1 -1
  2. package/app/commands/command-factory.js +2 -2
  3. package/app/commands/discipline.js +1 -1
  4. package/app/commands/driver.js +1 -1
  5. package/app/commands/grade.js +1 -1
  6. package/app/commands/serve.js +2 -2
  7. package/app/commands/site.js +22 -2
  8. package/app/commands/skill.js +1 -1
  9. package/app/commands/stage.js +1 -1
  10. package/app/commands/track.js +1 -1
  11. package/app/components/card.js +11 -1
  12. package/app/components/code-display.js +153 -0
  13. package/app/components/markdown-textarea.js +68 -47
  14. package/app/css/bundles/app.css +14 -0
  15. package/app/css/components/badges.css +15 -8
  16. package/app/css/components/forms.css +23 -13
  17. package/app/css/components/surfaces.css +49 -3
  18. package/app/css/components/typography.css +1 -2
  19. package/app/css/pages/agent-builder.css +11 -102
  20. package/app/css/pages/detail.css +11 -1
  21. package/app/css/tokens.css +3 -0
  22. package/app/formatters/agent/dom.js +26 -71
  23. package/app/formatters/agent/profile.js +11 -6
  24. package/app/formatters/grade/dom.js +6 -6
  25. package/app/formatters/job/dom.js +3 -3
  26. package/app/formatters/json-ld.js +1 -1
  27. package/app/formatters/skill/dom.js +68 -56
  28. package/app/formatters/skill/shared.js +3 -1
  29. package/app/formatters/stage/microdata.js +2 -2
  30. package/app/formatters/stage/shared.js +3 -3
  31. package/app/formatters/tool/shared.js +6 -0
  32. package/app/handout-main.js +12 -11
  33. package/app/index.html +7 -1
  34. package/app/lib/card-mappers.js +27 -0
  35. package/app/model/agent.js +21 -5
  36. package/app/model/checklist.js +2 -2
  37. package/app/model/derivation.js +2 -2
  38. package/app/model/levels.js +2 -2
  39. package/app/model/validation.js +3 -3
  40. package/app/pages/agent-builder.js +119 -75
  41. package/app/pages/landing.js +1 -1
  42. package/app/pages/stage.js +4 -4
  43. package/app/slide-main.js +1 -1
  44. package/app/slides/chapter.js +8 -8
  45. package/app/slides/index.js +1 -1
  46. package/app/slides/overview.js +8 -8
  47. package/app/slides/skill.js +1 -0
  48. package/examples/capabilities/business.yaml +1 -1
  49. package/examples/capabilities/delivery.yaml +3 -1
  50. package/examples/capabilities/people.yaml +1 -1
  51. package/examples/capabilities/reliability.yaml +3 -1
  52. package/examples/capabilities/scale.yaml +1 -1
  53. package/examples/framework.yaml +11 -11
  54. package/examples/stages.yaml +18 -10
  55. package/package.json +2 -1
  56. package/templates/agent.template.md +47 -17
  57. package/templates/job.template.md +8 -8
  58. package/templates/skill.template.md +12 -9
  59. package/examples/agents/.claude/skills/architecture-design/SKILL.md +0 -130
  60. package/examples/agents/.claude/skills/cloud-platforms/SKILL.md +0 -131
  61. package/examples/agents/.claude/skills/code-quality-review/SKILL.md +0 -108
  62. package/examples/agents/.claude/skills/devops-cicd/SKILL.md +0 -142
  63. package/examples/agents/.claude/skills/full-stack-development/SKILL.md +0 -134
  64. package/examples/agents/.claude/skills/sre-practices/SKILL.md +0 -163
  65. package/examples/agents/.claude/skills/technical-debt-management/SKILL.md +0 -164
  66. package/examples/agents/.github/agents/se-platform-code.agent.md +0 -132
  67. package/examples/agents/.github/agents/se-platform-plan.agent.md +0 -131
  68. package/examples/agents/.github/agents/se-platform-review.agent.md +0 -136
  69. package/examples/agents/.vscode/settings.json +0 -8
@@ -18,7 +18,8 @@ import {
18
18
  } from "../../lib/render.js";
19
19
  import { createBackLink } from "../../components/nav.js";
20
20
  import { createLevelCell } from "../../components/detail.js";
21
- import { createMarkdownTextarea } from "../../components/markdown-textarea.js";
21
+ import { createCodeDisplay } from "../../components/code-display.js";
22
+ import { createToolIcon } from "../../lib/card-mappers.js";
22
23
  import { SKILL_LEVEL_ORDER } from "../../model/levels.js";
23
24
  import { prepareSkillDetail } from "./shared.js";
24
25
  import { createJsonLdScript, skillToJsonLd } from "../json-ld.js";
@@ -32,11 +33,19 @@ import { createJsonLdScript, skillToJsonLd } from "../json-ld.js";
32
33
  * @param {Array} context.drivers - All drivers
33
34
  * @param {Array} context.capabilities - Capability entities
34
35
  * @param {boolean} [context.showBackLink=true] - Whether to show back navigation link
36
+ * @param {boolean} [context.showToolsAndPatterns=true] - Whether to show recommended tools and implementation patterns
35
37
  * @returns {HTMLElement}
36
38
  */
37
39
  export function skillToDOM(
38
40
  skill,
39
- { disciplines, tracks, drivers, capabilities, showBackLink = true } = {},
41
+ {
42
+ disciplines,
43
+ tracks,
44
+ drivers,
45
+ capabilities,
46
+ showBackLink = true,
47
+ showToolsAndPatterns = true,
48
+ } = {},
40
49
  ) {
41
50
  const view = prepareSkillDetail(skill, {
42
51
  disciplines,
@@ -98,60 +107,6 @@ export function skillToDOM(
98
107
  ),
99
108
  ),
100
109
 
101
- // Recommended Tools
102
- view.toolReferences.length > 0
103
- ? div(
104
- { className: "detail-section" },
105
- heading2({ className: "section-title" }, "Recommended Tools"),
106
- table(
107
- { className: "tools-table" },
108
- thead({}, tr({}, th({}, "Tool"), th({}, "Use When"))),
109
- tbody(
110
- {},
111
- ...view.toolReferences.map((tool) =>
112
- tr(
113
- {},
114
- td(
115
- {},
116
- tool.url
117
- ? a(
118
- {
119
- href: tool.url,
120
- target: "_blank",
121
- rel: "noopener noreferrer",
122
- },
123
- tool.name,
124
- )
125
- : tool.name,
126
- ),
127
- td({}, tool.useWhen),
128
- ),
129
- ),
130
- ),
131
- ),
132
- showBackLink
133
- ? p(
134
- { className: "see-all-link" },
135
- a({ href: "#/tool" }, "See all tools →"),
136
- )
137
- : null,
138
- )
139
- : null,
140
-
141
- // Implementation Reference
142
- view.implementationReference
143
- ? div(
144
- { className: "detail-section" },
145
- heading2({ className: "section-title" }, "Implementation Patterns"),
146
- createMarkdownTextarea({
147
- markdown: view.implementationReference,
148
- description:
149
- "Project-specific implementation guidance for this skill.",
150
- minHeight: 450,
151
- }),
152
- )
153
- : null,
154
-
155
110
  // Used in Disciplines and Linked to Drivers in two columns
156
111
  view.relatedDisciplines.length > 0 || view.relatedDrivers.length > 0
157
112
  ? div(
@@ -222,5 +177,62 @@ export function skillToDOM(
222
177
  ),
223
178
  )
224
179
  : null,
180
+
181
+ // Recommended Tools
182
+ showToolsAndPatterns && view.toolReferences.length > 0
183
+ ? div(
184
+ { className: "detail-section" },
185
+ heading2({ className: "section-title" }, "Recommended Tools"),
186
+ table(
187
+ { className: "tools-table" },
188
+ thead({}, tr({}, th({}, "Tool"), th({}, "Use When"))),
189
+ tbody(
190
+ {},
191
+ ...view.toolReferences.map((tool) =>
192
+ tr(
193
+ {},
194
+ td(
195
+ { className: "tool-name-cell" },
196
+ tool.simpleIcon
197
+ ? createToolIcon(tool.simpleIcon, tool.name)
198
+ : null,
199
+ tool.url
200
+ ? a(
201
+ {
202
+ href: tool.url,
203
+ target: "_blank",
204
+ rel: "noopener noreferrer",
205
+ },
206
+ tool.name,
207
+ )
208
+ : tool.name,
209
+ ),
210
+ td({}, tool.useWhen),
211
+ ),
212
+ ),
213
+ ),
214
+ ),
215
+ showBackLink
216
+ ? p(
217
+ { className: "see-all-link" },
218
+ a({ href: "#/tool" }, "See all tools →"),
219
+ )
220
+ : null,
221
+ )
222
+ : null,
223
+
224
+ // Implementation Reference
225
+ showToolsAndPatterns && view.implementationReference
226
+ ? div(
227
+ { className: "detail-section" },
228
+ heading2({ className: "section-title" }, "Implementation Patterns"),
229
+ createCodeDisplay({
230
+ content: view.implementationReference,
231
+ description:
232
+ "Project-specific implementation guidance for this skill.",
233
+ minHeight: 450,
234
+ }),
235
+ )
236
+ : null,
225
237
  );
226
238
  }
@@ -127,7 +127,9 @@ export function prepareSkillDetail(
127
127
  relatedDisciplines,
128
128
  relatedTracks,
129
129
  relatedDrivers,
130
- toolReferences: skill.toolReferences || [],
130
+ toolReferences: (skill.toolReferences || [])
131
+ .slice()
132
+ .sort((a, b) => a.name.localeCompare(b.name)),
131
133
  implementationReference: skill.implementationReference || null,
132
134
  };
133
135
  }
@@ -32,7 +32,7 @@ export function stageListToMicrodata(stages) {
32
32
  ? `→ ${stage.handoffs.map((h) => h.target).join(", ")}`
33
33
  : "";
34
34
  return `${openTag("article", { itemtype: "Stage", itemid: `#${stage.id}` })}
35
- ${prop("h2", "name", `${stage.emoji} ${stage.name}`)}
35
+ ${prop("h2", "name", `${stage.emojiIcon} ${stage.name}`)}
36
36
  ${prop("p", "description", stage.truncatedDescription)}
37
37
  ${handoffText ? `<p>Handoffs: ${handoffText}</p>` : ""}
38
38
  </article>`;
@@ -100,7 +100,7 @@ ${prop("p", "prompt", h.prompt)}
100
100
  ${openTag("article", { itemtype: "Stage", itemid: `#${view.id}` })}
101
101
  ${prop("h1", "name", view.name)}
102
102
  ${metaTag("id", view.id)}
103
- ${stage.emoji ? metaTag("emoji", stage.emoji) : ""}
103
+ ${stage.emojiIcon ? metaTag("emojiIcon", stage.emojiIcon) : ""}
104
104
  ${prop("p", "description", view.description)}
105
105
  ${sections.join("\n")}
106
106
  </article>
@@ -10,7 +10,7 @@ import { truncate } from "../shared.js";
10
10
  * @typedef {Object} StageListItem
11
11
  * @property {string} id
12
12
  * @property {string} name
13
- * @property {string} emoji
13
+ * @property {string} emojiIcon
14
14
  * @property {string} description
15
15
  * @property {string} truncatedDescription
16
16
  * @property {Array<{target: string, label: string}>} handoffs
@@ -27,7 +27,7 @@ export function prepareStagesList(stages, descriptionLimit = 150) {
27
27
  return {
28
28
  id: stage.id,
29
29
  name: stage.name,
30
- emoji: stage.emoji,
30
+ emojiIcon: stage.emojiIcon,
31
31
  description: stage.description,
32
32
  truncatedDescription: truncate(stage.description, descriptionLimit),
33
33
  handoffs: (stage.handoffs || []).map((h) => ({
@@ -80,5 +80,5 @@ export function prepareStageDetail(stage) {
80
80
  */
81
81
  export function getStageEmoji(stages, stageId) {
82
82
  const stage = stages.find((s) => s.id === stageId);
83
- return stage?.emoji;
83
+ return stage?.emojiIcon;
84
84
  }
@@ -16,6 +16,7 @@
16
16
  * @typedef {Object} AggregatedTool
17
17
  * @property {string} name
18
18
  * @property {string} [url]
19
+ * @property {string} [simpleIcon]
19
20
  * @property {string} description
20
21
  * @property {ToolUsage[]} usages
21
22
  */
@@ -42,10 +43,15 @@ export function aggregateTools(skills) {
42
43
  const existing = toolMap.get(tool.name);
43
44
  if (existing) {
44
45
  existing.usages.push(usage);
46
+ // Prefer simpleIcon from first occurrence that has one
47
+ if (!existing.simpleIcon && tool.simpleIcon) {
48
+ existing.simpleIcon = tool.simpleIcon;
49
+ }
45
50
  } else {
46
51
  toolMap.set(tool.name, {
47
52
  name: tool.name,
48
53
  url: tool.url,
54
+ simpleIcon: tool.simpleIcon,
49
55
  description: tool.description,
50
56
  usages: [usage],
51
57
  });
@@ -41,17 +41,17 @@ import { sortTracksByName } from "./formatters/track/shared.js";
41
41
  /**
42
42
  * Create a chapter cover page
43
43
  * @param {Object} params
44
- * @param {string} params.emoji - Chapter emoji
44
+ * @param {string} params.emojiIcon - Chapter emoji
45
45
  * @param {string} params.title - Chapter title
46
46
  * @param {string} params.description - Chapter description
47
47
  * @returns {HTMLElement}
48
48
  */
49
- function createChapterCover({ emoji, title, description }) {
49
+ function createChapterCover({ emojiIcon, title, description }) {
50
50
  return div(
51
51
  { className: "chapter-cover" },
52
52
  h1(
53
53
  { className: "chapter-title" },
54
- emoji,
54
+ emojiIcon,
55
55
  " ",
56
56
  span({ className: "gradient-text" }, title),
57
57
  ),
@@ -111,7 +111,7 @@ function renderIndex(data) {
111
111
  { className: "page-header" },
112
112
  heading1(
113
113
  { className: "page-title" },
114
- `${framework.emoji} ${framework.title} Handouts`,
114
+ `${framework.emojiIcon} ${framework.title} Handouts`,
115
115
  ),
116
116
  p(
117
117
  { className: "page-description" },
@@ -190,7 +190,7 @@ function renderDriverHandout(data) {
190
190
  const content = div(
191
191
  {},
192
192
  createChapterCover({
193
- emoji: getConceptEmoji(framework, "driver"),
193
+ emojiIcon: getConceptEmoji(framework, "driver"),
194
194
  title: framework.entityDefinitions.driver.title,
195
195
  description: framework.entityDefinitions.driver.description,
196
196
  }),
@@ -227,13 +227,14 @@ function renderSkillHandout(data) {
227
227
  drivers: data.drivers,
228
228
  capabilities: data.capabilities,
229
229
  showBackLink: false,
230
+ showToolsAndPatterns: false,
230
231
  });
231
232
  });
232
233
 
233
234
  const content = div(
234
235
  {},
235
236
  createChapterCover({
236
- emoji: getConceptEmoji(framework, "skill"),
237
+ emojiIcon: getConceptEmoji(framework, "skill"),
237
238
  title: framework.entityDefinitions.skill.title,
238
239
  description: framework.entityDefinitions.skill.description,
239
240
  }),
@@ -261,7 +262,7 @@ function renderBehaviourHandout(data) {
261
262
  const content = div(
262
263
  {},
263
264
  createChapterCover({
264
- emoji: getConceptEmoji(framework, "behaviour"),
265
+ emojiIcon: getConceptEmoji(framework, "behaviour"),
265
266
  title: framework.entityDefinitions.behaviour.title,
266
267
  description: framework.entityDefinitions.behaviour.description,
267
268
  }),
@@ -322,7 +323,7 @@ function renderJobHandout(data) {
322
323
  {},
323
324
  // Disciplines chapter
324
325
  createChapterCover({
325
- emoji: getConceptEmoji(framework, "discipline"),
326
+ emojiIcon: getConceptEmoji(framework, "discipline"),
326
327
  title: framework.entityDefinitions.discipline.title,
327
328
  description: framework.entityDefinitions.discipline.description,
328
329
  }),
@@ -330,7 +331,7 @@ function renderJobHandout(data) {
330
331
 
331
332
  // Grades chapter (moved before Tracks)
332
333
  createChapterCover({
333
- emoji: getConceptEmoji(framework, "grade"),
334
+ emojiIcon: getConceptEmoji(framework, "grade"),
334
335
  title: framework.entityDefinitions.grade.title,
335
336
  description: framework.entityDefinitions.grade.description,
336
337
  }),
@@ -338,7 +339,7 @@ function renderJobHandout(data) {
338
339
 
339
340
  // Tracks chapter (moved after Grades)
340
341
  createChapterCover({
341
- emoji: getConceptEmoji(framework, "track"),
342
+ emojiIcon: getConceptEmoji(framework, "track"),
342
343
  title: framework.entityDefinitions.track.title,
343
344
  description: framework.entityDefinitions.track.description,
344
345
  }),
@@ -393,7 +394,7 @@ function populateBrandHeader(framework) {
393
394
  header.appendChild(
394
395
  a(
395
396
  { className: "brand-title", href: "#/" },
396
- `${framework.emoji} ${framework.title}`,
397
+ `${framework.emojiIcon} ${framework.title}`,
397
398
  ),
398
399
  );
399
400
  header.appendChild(span({ className: "brand-tag" }, framework.tag));
package/app/index.html CHANGED
@@ -4,11 +4,17 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>Engineering Pathway</title>
7
- <link rel="stylesheet" href="css/bundles/app.css" />
7
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
8
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
9
+ <link
10
+ href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500&display=swap"
11
+ rel="stylesheet"
12
+ />
8
13
  <link
9
14
  rel="stylesheet"
10
15
  href="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism.min.css"
11
16
  />
17
+ <link rel="stylesheet" href="css/bundles/app.css" />
12
18
  <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/prism.min.js"></script>
13
19
  <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-markdown.min.js"></script>
14
20
  <script type="importmap">
@@ -181,13 +181,40 @@ export function toolToCardConfig(tool, capabilities) {
181
181
  // Create skills list as card content
182
182
  const skillsList = createSkillsList(tool.usages, capabilities);
183
183
 
184
+ // Create icon element if available
185
+ const icon = tool.simpleIcon
186
+ ? createToolIcon(tool.simpleIcon, tool.name)
187
+ : null;
188
+
184
189
  return {
185
190
  title: tool.name,
186
191
  description: tool.description,
187
192
  // Docs link in header badges (upper right)
188
193
  badges: tool.url ? [createExternalLink("Docs →", tool.url)] : [],
189
194
  content: skillsList,
195
+ icon,
196
+ };
197
+ }
198
+
199
+ /**
200
+ * Create a tool icon element using Simple Icons CDN
201
+ * @param {string} slug - Simple Icons slug (e.g., 'terraform', 'docker')
202
+ * @param {string} name - Tool name for alt text
203
+ * @returns {HTMLElement}
204
+ */
205
+ export function createToolIcon(slug, name) {
206
+ const img = document.createElement("img");
207
+ // Use black color for consistent monochrome appearance
208
+ img.src = `https://cdn.simpleicons.org/${slug}/000000`;
209
+ img.alt = `${name} icon`;
210
+ img.className = "tool-icon";
211
+ img.width = 28;
212
+ img.height = 28;
213
+ // Gracefully handle missing icons
214
+ img.onerror = () => {
215
+ img.style.display = "none";
190
216
  };
217
+ return img;
191
218
  }
192
219
 
193
220
  /**
@@ -320,8 +320,11 @@ function estimateBodyDataLength(bodyData) {
320
320
  }
321
321
 
322
322
  // Array fields
323
- if (bodyData.capabilities) {
324
- length += bodyData.capabilities.join(", ").length;
323
+ if (bodyData.skillIndex) {
324
+ for (const skill of bodyData.skillIndex) {
325
+ length +=
326
+ skill.name.length + skill.dirname.length + skill.useWhen.length + 50;
327
+ }
325
328
  }
326
329
  if (bodyData.beforeMakingChanges) {
327
330
  for (const item of bodyData.beforeMakingChanges) {
@@ -491,6 +494,7 @@ function getChecklistStage(stageId) {
491
494
  * @param {Array} params.derivedSkills - Skills sorted by level
492
495
  * @param {Array} params.derivedBehaviours - Behaviours sorted by maturity
493
496
  * @param {Array} params.agentBehaviours - Agent behaviour definitions
497
+ * @param {Array} params.skills - All skill definitions (for agent section lookup)
494
498
  * @param {string} params.checklistMarkdown - Pre-formatted checklist markdown
495
499
  * @returns {Object} Structured profile body data
496
500
  */
@@ -503,6 +507,7 @@ function buildStageProfileBodyData({
503
507
  derivedSkills,
504
508
  derivedBehaviours,
505
509
  agentBehaviours,
510
+ skills,
506
511
  checklistMarkdown,
507
512
  }) {
508
513
  const name = `${humanDiscipline.specialization || humanDiscipline.name} - ${humanTrack.name}`;
@@ -532,8 +537,18 @@ function buildStageProfileBodyData({
532
537
  ? substituteTemplateVars(rawDelegation, humanDiscipline)
533
538
  : null;
534
539
 
535
- // Primary capabilities from derived skills
536
- const capabilities = derivedSkills.slice(0, 6).map((s) => s.skillName);
540
+ // Build skill index from derived skills with agent sections
541
+ const skillIndex = derivedSkills
542
+ .map((derived) => {
543
+ const skill = skills.find((s) => s.id === derived.skillId);
544
+ if (!skill?.agent) return null;
545
+ return {
546
+ name: derived.skillName,
547
+ dirname: skill.agent.name,
548
+ useWhen: skill.agent.useWhen?.trim() || "",
549
+ };
550
+ })
551
+ .filter(Boolean);
537
552
 
538
553
  // Operational Context - use track's roleContext (shared with human job descriptions)
539
554
  const operationalContext = humanTrack.roleContext.trim();
@@ -557,7 +572,7 @@ function buildStageProfileBodyData({
557
572
  stageDescription: stage.description,
558
573
  identity: identity.trim(),
559
574
  priority: priority ? priority.trim() : null,
560
- capabilities,
575
+ skillIndex,
561
576
  beforeMakingChanges,
562
577
  delegation: delegation ? delegation.trim() : null,
563
578
  operationalContext,
@@ -719,6 +734,7 @@ export function generateStageAgentProfile({
719
734
  derivedSkills: agent.derivedSkills,
720
735
  derivedBehaviours: agent.derivedBehaviours,
721
736
  agentBehaviours,
737
+ skills,
722
738
  checklistMarkdown,
723
739
  });
724
740
 
@@ -72,7 +72,7 @@ export function deriveChecklist({
72
72
  capability: {
73
73
  id: capability.id,
74
74
  name: capability.name,
75
- emoji: capability.emoji,
75
+ emojiIcon: capability.emojiIcon,
76
76
  },
77
77
  items: stageData.ready,
78
78
  });
@@ -94,7 +94,7 @@ export function formatChecklistMarkdown(checklist) {
94
94
  }
95
95
 
96
96
  const sections = checklist.map(({ skill, capability, items }) => {
97
- const header = `**${capability.emoji} ${skill.name}**`;
97
+ const header = `**${capability.emojiIcon} ${skill.name}**`;
98
98
  const itemList = items.map((item) => `- [ ] ${item}`).join("\n");
99
99
  return `${header}\n\n${itemList}`;
100
100
  });
@@ -437,7 +437,7 @@ function generateJobId(discipline, grade, track = null) {
437
437
  * @param {import('./levels.js').SkillMatrixEntry[]} params.skillMatrix - Derived skill matrix for the job
438
438
  * @param {Object[]} params.capabilities - Capability definitions with responsibilities
439
439
  * @param {import('./levels.js').Discipline} params.discipline - The discipline (determines which responsibilities to use)
440
- * @returns {Array<{capability: string, capabilityName: string, emoji: string, responsibility: string, level: string}>}
440
+ * @returns {Array<{capability: string, capabilityName: string, emojiIcon: string, responsibility: string, level: string}>}
441
441
  */
442
442
  export function deriveResponsibilities({
443
443
  skillMatrix,
@@ -484,7 +484,7 @@ export function deriveResponsibilities({
484
484
  responsibilities.push({
485
485
  capability: capabilityId,
486
486
  capabilityName: capability.name,
487
- emoji: capability.emoji || "💡",
487
+ emojiIcon: capability.emojiIcon || "💡",
488
488
  displayOrder: capability.displayOrder ?? 999,
489
489
  responsibility: responsibilityText,
490
490
  level,
@@ -220,7 +220,7 @@ export function getCapabilityOrder(capabilities) {
220
220
  */
221
221
  export function getCapabilityEmoji(capabilities, capabilityId) {
222
222
  const capability = getCapabilityById(capabilities, capabilityId);
223
- return capability?.emoji || "💡";
223
+ return capability?.emojiIcon || "💡";
224
224
  }
225
225
 
226
226
  /**
@@ -597,5 +597,5 @@ export function behaviourMaturityMeetsRequirement(actual, required) {
597
597
  * @returns {string} The emoji for the concept or default "💡"
598
598
  */
599
599
  export function getConceptEmoji(framework, concept) {
600
- return framework?.entityDefinitions?.[concept]?.emoji || "💡";
600
+ return framework?.entityDefinitions?.[concept]?.emojiIcon || "💡";
601
601
  }
@@ -1239,12 +1239,12 @@ function validateCapability(capability, index) {
1239
1239
  ),
1240
1240
  );
1241
1241
  }
1242
- if (!capability.emoji) {
1242
+ if (!capability.emojiIcon) {
1243
1243
  warnings.push(
1244
1244
  createWarning(
1245
1245
  "MISSING_OPTIONAL",
1246
- "Capability missing emoji",
1247
- `${path}.emoji`,
1246
+ "Capability missing emojiIcon",
1247
+ `${path}.emojiIcon`,
1248
1248
  ),
1249
1249
  );
1250
1250
  }