@forwardimpact/pathway 0.20.0 → 0.22.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 (96) hide show
  1. package/README.md +3 -3
  2. package/bin/fit-pathway.js +28 -28
  3. package/package.json +4 -4
  4. package/src/commands/agent.js +8 -8
  5. package/src/commands/build.js +7 -7
  6. package/src/commands/dev.js +7 -7
  7. package/src/commands/driver.js +1 -1
  8. package/src/commands/index.js +1 -1
  9. package/src/commands/init.js +1 -1
  10. package/src/commands/interview.js +8 -8
  11. package/src/commands/job.js +19 -19
  12. package/src/commands/level.js +60 -0
  13. package/src/commands/progress.js +20 -20
  14. package/src/commands/questions.js +3 -3
  15. package/src/commands/skill.js +1 -1
  16. package/src/commands/track.js +1 -1
  17. package/src/commands/update.js +12 -14
  18. package/src/components/action-buttons.js +3 -3
  19. package/src/components/builder.js +25 -25
  20. package/src/components/checklist.js +1 -1
  21. package/src/components/comparison-radar.js +3 -3
  22. package/src/components/detail.js +3 -3
  23. package/src/components/grid.js +1 -1
  24. package/src/components/radar-chart.js +3 -3
  25. package/src/components/skill-matrix.js +7 -7
  26. package/src/css/pages/landing.css +5 -5
  27. package/src/formatters/behaviour/dom.js +1 -1
  28. package/src/formatters/discipline/dom.js +1 -1
  29. package/src/formatters/driver/dom.js +1 -1
  30. package/src/formatters/index.js +5 -5
  31. package/src/formatters/interview/dom.js +1 -1
  32. package/src/formatters/interview/markdown.js +1 -1
  33. package/src/formatters/interview/shared.js +20 -20
  34. package/src/formatters/job/description.js +18 -18
  35. package/src/formatters/job/dom.js +12 -12
  36. package/src/formatters/job/markdown.js +7 -7
  37. package/src/formatters/json-ld.js +24 -24
  38. package/src/formatters/{grade → level}/dom.js +32 -28
  39. package/src/formatters/{grade → level}/markdown.js +20 -29
  40. package/src/formatters/{grade → level}/microdata.js +28 -38
  41. package/src/formatters/level/shared.js +86 -0
  42. package/src/formatters/progress/markdown.js +2 -2
  43. package/src/formatters/progress/shared.js +48 -48
  44. package/src/formatters/questions/markdown.js +8 -6
  45. package/src/formatters/questions/shared.js +7 -7
  46. package/src/formatters/skill/dom.js +4 -4
  47. package/src/formatters/skill/markdown.js +2 -2
  48. package/src/formatters/skill/microdata.js +3 -3
  49. package/src/formatters/skill/shared.js +3 -3
  50. package/src/formatters/track/dom.js +1 -1
  51. package/src/formatters/track/markdown.js +1 -1
  52. package/src/handout-main.js +13 -16
  53. package/src/handout.html +4 -4
  54. package/src/index.html +5 -5
  55. package/src/lib/card-mappers.js +17 -17
  56. package/src/lib/cli-command.js +3 -3
  57. package/src/lib/cli-output.js +2 -2
  58. package/src/lib/job-cache.js +11 -11
  59. package/src/lib/render.js +6 -6
  60. package/src/lib/state.js +2 -2
  61. package/src/lib/yaml-loader.js +9 -9
  62. package/src/main.js +10 -10
  63. package/src/pages/agent-builder.js +11 -11
  64. package/src/pages/assessment-results.js +27 -23
  65. package/src/pages/behaviour.js +1 -1
  66. package/src/pages/discipline.js +1 -1
  67. package/src/pages/driver.js +1 -1
  68. package/src/pages/interview-builder.js +6 -6
  69. package/src/pages/interview.js +9 -9
  70. package/src/pages/job-builder.js +6 -6
  71. package/src/pages/job.js +7 -7
  72. package/src/pages/landing.js +9 -9
  73. package/src/pages/level.js +122 -0
  74. package/src/pages/progress-builder.js +8 -8
  75. package/src/pages/progress.js +74 -74
  76. package/src/pages/self-assessment.js +8 -8
  77. package/src/pages/skill.js +1 -4
  78. package/src/pages/stage.js +1 -1
  79. package/src/pages/tool.js +1 -1
  80. package/src/pages/track.js +1 -1
  81. package/src/slide-main.js +22 -22
  82. package/src/slides/chapter.js +4 -4
  83. package/src/slides/index.js +11 -11
  84. package/src/slides/interview.js +2 -2
  85. package/src/slides/job.js +3 -3
  86. package/src/slides/level.js +32 -0
  87. package/src/slides/overview.js +9 -9
  88. package/src/slides/progress.js +13 -13
  89. package/src/slides.html +4 -4
  90. package/src/types.js +1 -1
  91. package/templates/install.template.sh +11 -8
  92. package/templates/job.template.md +2 -2
  93. package/src/commands/grade.js +0 -60
  94. package/src/formatters/grade/shared.js +0 -86
  95. package/src/pages/grade.js +0 -122
  96. package/src/slides/grade.js +0 -32
@@ -5,9 +5,9 @@
5
5
  */
6
6
 
7
7
  /**
8
- * Skill levels in order
8
+ * Skill proficiencies in order
9
9
  */
10
- export const SKILL_LEVELS = [
10
+ export const SKILL_PROFICIENCIES = [
11
11
  "awareness",
12
12
  "foundational",
13
13
  "working",
@@ -28,7 +28,7 @@ export const BEHAVIOUR_MATURITIES = [
28
28
 
29
29
  /**
30
30
  * @typedef {Object} QuestionsFilter
31
- * @property {string|null} level - Skill level filter
31
+ * @property {string|null} level - Skill proficiency filter
32
32
  * @property {string|null} maturity - Behaviour maturity filter
33
33
  * @property {string[]|null} skills - Skill IDs to include
34
34
  * @property {string[]|null} behaviours - Behaviour IDs to include
@@ -40,7 +40,7 @@ export const BEHAVIOUR_MATURITIES = [
40
40
  * @property {string} source - Source skill/behaviour ID
41
41
  * @property {string} sourceName - Source skill/behaviour name
42
42
  * @property {string} sourceType - 'skill' or 'behaviour'
43
- * @property {string} level - Skill level or behaviour maturity
43
+ * @property {string} level - Skill proficiency or behaviour maturity
44
44
  * @property {string} id - Question ID
45
45
  * @property {string} text - Question text
46
46
  * @property {string[]} lookingFor - Expected answer indicators
@@ -124,7 +124,7 @@ export function flattenQuestions(questionBank, skills, behaviours, filter) {
124
124
 
125
125
  // Process skill questions
126
126
  for (const [skillId, roleTypes] of Object.entries(
127
- questionBank.skillLevels || {},
127
+ questionBank.skillProficiencies || {},
128
128
  )) {
129
129
  const skillName = getSkillName(skillId, skills);
130
130
  const capability = getSkillCapability(skillId, skills);
@@ -218,10 +218,10 @@ export function calculateStats(questions, questionBank) {
218
218
  // Calculate full stats for skills and behaviours
219
219
  const skillStats = {};
220
220
  for (const [skillId, roleTypes] of Object.entries(
221
- questionBank.skillLevels || {},
221
+ questionBank.skillProficiencies || {},
222
222
  )) {
223
223
  skillStats[skillId] = {};
224
- for (const level of SKILL_LEVELS) {
224
+ for (const level of SKILL_PROFICIENCIES) {
225
225
  let count = 0;
226
226
  for (const roleType of ROLE_TYPES) {
227
227
  count += (roleTypes[roleType]?.[level] || []).length;
@@ -20,7 +20,7 @@ import { createBackLink } from "../../components/nav.js";
20
20
  import { createLevelCell } from "../../components/detail.js";
21
21
  import { createSkillFileViewer } from "../../components/skill-file-viewer.js";
22
22
  import { createToolIcon } from "../../lib/card-mappers.js";
23
- import { SKILL_LEVEL_ORDER } from "@forwardimpact/schema/levels";
23
+ import { SKILL_PROFICIENCY_ORDER } from "@forwardimpact/map/levels";
24
24
  import { prepareSkillDetail } from "./shared.js";
25
25
  import { createJsonLdScript, skillToJsonLd } from "../json-ld.js";
26
26
 
@@ -97,11 +97,11 @@ export function skillToDOM(
97
97
  thead({}, tr({}, th({}, "Level"), th({}, "Description"))),
98
98
  tbody(
99
99
  {},
100
- ...SKILL_LEVEL_ORDER.map((level, index) => {
101
- const description = view.levelDescriptions[level] || "—";
100
+ ...SKILL_PROFICIENCY_ORDER.map((level, index) => {
101
+ const description = view.proficiencyDescriptions[level] || "—";
102
102
  return tr(
103
103
  {},
104
- createLevelCell(index + 1, SKILL_LEVEL_ORDER.length, level),
104
+ createLevelCell(index + 1, SKILL_PROFICIENCY_ORDER.length, level),
105
105
  td({}, description),
106
106
  );
107
107
  }),
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { tableToMarkdown, capitalize } from "../shared.js";
6
6
  import { prepareSkillsList, prepareSkillDetail } from "./shared.js";
7
- import { getConceptEmoji } from "@forwardimpact/schema/levels";
7
+ import { getConceptEmoji } from "@forwardimpact/map/levels";
8
8
 
9
9
  /**
10
10
  * Format skill list as markdown
@@ -71,7 +71,7 @@ export function skillToMarkdown(
71
71
 
72
72
  // Level descriptions table
73
73
  lines.push("## Level Descriptions", "");
74
- const levelRows = Object.entries(view.levelDescriptions).map(
74
+ const levelRows = Object.entries(view.proficiencyDescriptions).map(
75
75
  ([level, desc]) => [capitalize(level), desc],
76
76
  );
77
77
  lines.push(tableToMarkdown(["Level", "Description"], levelRows));
@@ -87,8 +87,8 @@ export function skillToMicrodata(
87
87
  ${metaTag("isHumanOnly", "true")}`);
88
88
  }
89
89
 
90
- // Level descriptions - uses LevelDescriptions itemtype
91
- const levelPairs = Object.entries(view.levelDescriptions).map(
90
+ // Level descriptions - uses ProficiencyDescriptions itemtype
91
+ const levelPairs = Object.entries(view.proficiencyDescriptions).map(
92
92
  ([level, desc]) => ({
93
93
  term: formatLevelName(level),
94
94
  definition: desc,
@@ -98,7 +98,7 @@ ${metaTag("isHumanOnly", "true")}`);
98
98
  sections.push(
99
99
  section(
100
100
  "Level Descriptions",
101
- `${openTag("div", { itemtype: "LevelDescriptions", itemprop: "levelDescriptions" })}
101
+ `${openTag("div", { itemtype: "ProficiencyDescriptions", itemprop: "proficiencyDescriptions" })}
102
102
  ${dl(levelPairs)}
103
103
  </div>`,
104
104
  2,
@@ -7,7 +7,7 @@
7
7
  import {
8
8
  groupSkillsByCapability,
9
9
  getCapabilityEmoji,
10
- } from "@forwardimpact/schema/levels";
10
+ } from "@forwardimpact/map/levels";
11
11
  import { getSkillTypeForDiscipline } from "@forwardimpact/libpathway/derivation";
12
12
  import { truncate } from "../shared.js";
13
13
 
@@ -69,7 +69,7 @@ export function prepareSkillsList(
69
69
  * @property {string} capabilityName
70
70
  * @property {boolean} isHumanOnly
71
71
  * @property {string} capabilityEmoji
72
- * @property {Object<string, string>} levelDescriptions
72
+ * @property {Object<string, string>} proficiencyDescriptions
73
73
  * @property {Array<{id: string, name: string, skillType: string}>} relatedDisciplines
74
74
  * @property {Array<{id: string, name: string, modifier: number}>} relatedTracks
75
75
  * @property {Array<{id: string, name: string}>} relatedDrivers
@@ -124,7 +124,7 @@ export function prepareSkillDetail(
124
124
  capabilityName: capabilityEntity?.name || skill.capability,
125
125
  isHumanOnly: skill.isHumanOnly || false,
126
126
  capabilityEmoji: getCapabilityEmoji(capabilities, skill.capability),
127
- levelDescriptions: skill.levelDescriptions,
127
+ proficiencyDescriptions: skill.proficiencyDescriptions,
128
128
  relatedDisciplines,
129
129
  relatedTracks,
130
130
  relatedDrivers,
@@ -15,7 +15,7 @@ import {
15
15
  createBehaviourModifierTable,
16
16
  createSkillModifierTableWithCapabilities,
17
17
  } from "../../components/modifier-table.js";
18
- import { getConceptEmoji } from "@forwardimpact/schema/levels";
18
+ import { getConceptEmoji } from "@forwardimpact/map/levels";
19
19
  import { prepareTrackDetail } from "./shared.js";
20
20
  import { createJsonLdScript, trackToJsonLd } from "../json-ld.js";
21
21
 
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { tableToMarkdown } from "../shared.js";
6
6
  import { prepareTracksList, prepareTrackDetail } from "./shared.js";
7
- import { getConceptEmoji } from "@forwardimpact/schema/levels";
7
+ import { getConceptEmoji } from "@forwardimpact/map/levels";
8
8
 
9
9
  /**
10
10
  * Format track list as markdown
@@ -7,7 +7,7 @@
7
7
  * /driver - All driver slides
8
8
  * /skill - All skill slides
9
9
  * /behaviour - All behaviour slides
10
- * /job - All discipline, track, and grade slides
10
+ * /job - All discipline, track, and level slides
11
11
  */
12
12
 
13
13
  import { setData, getState } from "./lib/state.js";
@@ -25,10 +25,7 @@ import {
25
25
  } from "./lib/render.js";
26
26
 
27
27
  // Import model functions
28
- import {
29
- getCapabilityOrder,
30
- getConceptEmoji,
31
- } from "@forwardimpact/schema/levels";
28
+ import { getCapabilityOrder, getConceptEmoji } from "@forwardimpact/map/levels";
32
29
 
33
30
  // Import formatters
34
31
  import {
@@ -36,7 +33,7 @@ import {
36
33
  skillToDOM,
37
34
  behaviourToDOM,
38
35
  disciplineToDOM,
39
- gradeToDOM,
36
+ levelToDOM,
40
37
  trackToDOM,
41
38
  } from "./formatters/index.js";
42
39
  import { sortTracksByName } from "./formatters/track/shared.js";
@@ -138,7 +135,7 @@ function renderIndex(data) {
138
135
  `${getConceptEmoji(framework, "job")} ${framework.entityDefinitions.job.title}`,
139
136
  ),
140
137
  " - ",
141
- `${data.disciplines.length} disciplines, ${data.grades.length} grades, ${data.tracks.length} tracks`,
138
+ `${data.disciplines.length} disciplines, ${data.levels.length} levels, ${data.tracks.length} tracks`,
142
139
  ),
143
140
  li(
144
141
  {},
@@ -287,7 +284,7 @@ function sortDisciplinesByType(disciplines) {
287
284
  }
288
285
 
289
286
  /**
290
- * Render all job component slides (disciplines, grades, tracks)
287
+ * Render all job component slides (disciplines, levels, tracks)
291
288
  * @param {Object} data
292
289
  */
293
290
  function renderJobHandout(data) {
@@ -306,8 +303,8 @@ function renderJobHandout(data) {
306
303
  });
307
304
  });
308
305
 
309
- const gradeSlides = data.grades.map((grade) => {
310
- return gradeToDOM(grade, {
306
+ const levelSlides = data.levels.map((level) => {
307
+ return levelToDOM(level, {
311
308
  framework: data.framework,
312
309
  showBackLink: false,
313
310
  });
@@ -332,15 +329,15 @@ function renderJobHandout(data) {
332
329
  }),
333
330
  ...disciplineSlides,
334
331
 
335
- // Grades chapter (moved before Tracks)
332
+ // Levels chapter (moved before Tracks)
336
333
  createChapterCover({
337
- emojiIcon: getConceptEmoji(framework, "grade"),
338
- title: framework.entityDefinitions.grade.title,
339
- description: framework.entityDefinitions.grade.description,
334
+ emojiIcon: getConceptEmoji(framework, "level"),
335
+ title: framework.entityDefinitions.level.title,
336
+ description: framework.entityDefinitions.level.description,
340
337
  }),
341
- ...gradeSlides,
338
+ ...levelSlides,
342
339
 
343
- // Tracks chapter (moved after Grades)
340
+ // Tracks chapter (moved after Levels)
344
341
  createChapterCover({
345
342
  emojiIcon: getConceptEmoji(framework, "track"),
346
343
  title: framework.entityDefinitions.track.title,
package/src/handout.html CHANGED
@@ -9,10 +9,10 @@
9
9
  {
10
10
  "imports": {
11
11
  "mustache": "https://esm.sh/mustache@4.2.0",
12
- "@forwardimpact/schema": "/schema/lib/index.js",
13
- "@forwardimpact/schema/levels": "/schema/lib/levels.js",
14
- "@forwardimpact/schema/loader": "/schema/lib/loader.js",
15
- "@forwardimpact/schema/validation": "/schema/lib/validation.js",
12
+ "@forwardimpact/map": "/map/lib/index.js",
13
+ "@forwardimpact/map/levels": "/map/lib/levels.js",
14
+ "@forwardimpact/map/loader": "/map/lib/loader.js",
15
+ "@forwardimpact/map/validation": "/map/lib/validation.js",
16
16
  "@forwardimpact/libpathway": "/model/lib/index.js",
17
17
  "@forwardimpact/libpathway/derivation": "/model/lib/derivation.js",
18
18
  "@forwardimpact/libpathway/modifiers": "/model/lib/modifiers.js",
package/src/index.html CHANGED
@@ -21,10 +21,10 @@
21
21
  {
22
22
  "imports": {
23
23
  "mustache": "https://esm.sh/mustache@4.2.0",
24
- "@forwardimpact/schema": "/schema/lib/index.js",
25
- "@forwardimpact/schema/levels": "/schema/lib/levels.js",
26
- "@forwardimpact/schema/loader": "/schema/lib/loader.js",
27
- "@forwardimpact/schema/validation": "/schema/lib/validation.js",
24
+ "@forwardimpact/map": "/map/lib/index.js",
25
+ "@forwardimpact/map/levels": "/map/lib/levels.js",
26
+ "@forwardimpact/map/loader": "/map/lib/loader.js",
27
+ "@forwardimpact/map/validation": "/map/lib/validation.js",
28
28
  "@forwardimpact/libpathway": "/model/lib/index.js",
29
29
  "@forwardimpact/libpathway/derivation": "/model/lib/derivation.js",
30
30
  "@forwardimpact/libpathway/modifiers": "/model/lib/modifiers.js",
@@ -83,7 +83,7 @@
83
83
  <div class="drawer-section">
84
84
  <span class="drawer-section-label">Browse</span>
85
85
  <a href="#/discipline">Disciplines</a>
86
- <a href="#/grade">Grades</a>
86
+ <a href="#/level">Levels</a>
87
87
  <a href="#/track">Tracks</a>
88
88
  <a href="#/behaviour">Behaviours</a>
89
89
  <a href="#/skill">Skills</a>
@@ -7,7 +7,7 @@
7
7
 
8
8
  import { createBadge } from "../components/card.js";
9
9
  import { formatLevel } from "./render.js";
10
- import { getCapabilityEmoji } from "@forwardimpact/schema/levels";
10
+ import { getCapabilityEmoji } from "@forwardimpact/map/levels";
11
11
 
12
12
  /**
13
13
  * Create an external link element styled as a badge
@@ -109,31 +109,31 @@ export function driverToCardConfig(driver) {
109
109
  }
110
110
 
111
111
  /**
112
- * Map grade to card config (for timeline)
113
- * @param {Object} grade
112
+ * Map level to card config (for timeline)
113
+ * @param {Object} level
114
114
  * @returns {Object}
115
115
  */
116
- export function gradeToCardConfig(grade) {
116
+ export function levelToCardConfig(level) {
117
117
  return {
118
- title: grade.displayName,
119
- description: grade.scope || grade.truncatedDescription,
120
- href: `/grade/${grade.id}`,
121
- badges: [createBadge(grade.id, "default")],
118
+ title: level.displayName,
119
+ description: level.scope || level.truncatedDescription,
120
+ href: `/level/${level.id}`,
121
+ badges: [createBadge(level.id, "default")],
122
122
  meta: [
123
123
  createBadge(
124
- `Primary: ${formatLevel(grade.baseSkillLevels?.primary)}`,
124
+ `Primary: ${formatLevel(level.baseSkillProficiencies?.primary)}`,
125
125
  "primary",
126
126
  ),
127
127
  createBadge(
128
- `Secondary: ${formatLevel(grade.baseSkillLevels?.secondary)}`,
128
+ `Secondary: ${formatLevel(level.baseSkillProficiencies?.secondary)}`,
129
129
  "secondary",
130
130
  ),
131
131
  createBadge(
132
- `Broad: ${formatLevel(grade.baseSkillLevels?.broad)}`,
132
+ `Broad: ${formatLevel(level.baseSkillProficiencies?.broad)}`,
133
133
  "broad",
134
134
  ),
135
135
  ],
136
- yearsExperience: grade.yearsExperience,
136
+ yearsExperience: level.yearsExperience,
137
137
  };
138
138
  }
139
139
 
@@ -158,15 +158,15 @@ export function trackToCardConfig(track) {
158
158
  */
159
159
  export function jobToCardConfig(job) {
160
160
  const href = job.track
161
- ? `/job/${job.discipline.id}/${job.grade.id}/${job.track.id}`
162
- : `/job/${job.discipline.id}/${job.grade.id}`;
161
+ ? `/job/${job.discipline.id}/${job.level.id}/${job.track.id}`
162
+ : `/job/${job.discipline.id}/${job.level.id}`;
163
163
  return {
164
164
  title: job.title,
165
165
  description: job.track
166
- ? `${job.discipline.specialization || job.discipline.name} at ${job.grade.professionalTitle} level on ${job.track.name} track`
167
- : `${job.discipline.specialization || job.discipline.name} at ${job.grade.professionalTitle} level`,
166
+ ? `${job.discipline.specialization || job.discipline.name} at ${job.level.professionalTitle} level on ${job.track.name} track`
167
+ : `${job.discipline.specialization || job.discipline.name} at ${job.level.professionalTitle} level`,
168
168
  href,
169
- badges: [createBadge(job.grade.id, "default")],
169
+ badges: [createBadge(job.level.id, "default")],
170
170
  meta: job.track ? [createBadge(job.track.name, "secondary")] : [],
171
171
  };
172
172
  }
@@ -21,7 +21,7 @@ const ROUTE_COMMANDS = [
21
21
  toCommand: () => "npx fit-pathway discipline",
22
22
  },
23
23
  { pattern: /^\/track$/, toCommand: () => "npx fit-pathway track" },
24
- { pattern: /^\/grade$/, toCommand: () => "npx fit-pathway grade" },
24
+ { pattern: /^\/level$/, toCommand: () => "npx fit-pathway level" },
25
25
  { pattern: /^\/driver$/, toCommand: () => "npx fit-pathway driver" },
26
26
  { pattern: /^\/stage$/, toCommand: () => "npx fit-pathway stage" },
27
27
  { pattern: /^\/tool$/, toCommand: () => "npx fit-pathway tool" },
@@ -44,8 +44,8 @@ const ROUTE_COMMANDS = [
44
44
  toCommand: (m) => `npx fit-pathway track ${m[1]}`,
45
45
  },
46
46
  {
47
- pattern: /^\/grade\/(.+)$/,
48
- toCommand: (m) => `npx fit-pathway grade ${m[1]}`,
47
+ pattern: /^\/level\/(.+)$/,
48
+ toCommand: (m) => `npx fit-pathway level ${m[1]}`,
49
49
  },
50
50
  {
51
51
  pattern: /^\/driver\/(.+)$/,
@@ -126,11 +126,11 @@ export function formatTable(headers, rows, options = {}) {
126
126
  }
127
127
 
128
128
  /**
129
- * Format skill level with color
129
+ * Format skill proficiency with color
130
130
  * @param {string} level
131
131
  * @returns {string}
132
132
  */
133
- export function formatSkillLevel(level) {
133
+ export function formatSkillProficiency(level) {
134
134
  const levelColors = {
135
135
  awareness: colors.gray,
136
136
  foundational: colors.blue,
@@ -13,22 +13,22 @@ const cache = new Map();
13
13
  /**
14
14
  * Build a consistent cache key from job parameters
15
15
  * @param {string} disciplineId
16
- * @param {string} gradeId
16
+ * @param {string} levelId
17
17
  * @param {string} [trackId] - Optional track ID
18
18
  * @returns {string}
19
19
  */
20
- export function buildJobKey(disciplineId, gradeId, trackId = null) {
20
+ export function buildJobKey(disciplineId, levelId, trackId = null) {
21
21
  if (trackId) {
22
- return `${disciplineId}_${gradeId}_${trackId}`;
22
+ return `${disciplineId}_${levelId}_${trackId}`;
23
23
  }
24
- return `${disciplineId}_${gradeId}`;
24
+ return `${disciplineId}_${levelId}`;
25
25
  }
26
26
 
27
27
  /**
28
28
  * Get or create a cached job definition
29
29
  * @param {Object} params
30
30
  * @param {Object} params.discipline
31
- * @param {Object} params.grade
31
+ * @param {Object} params.level
32
32
  * @param {Object} [params.track] - Optional track
33
33
  * @param {Array} params.skills
34
34
  * @param {Array} params.behaviours
@@ -37,18 +37,18 @@ export function buildJobKey(disciplineId, gradeId, trackId = null) {
37
37
  */
38
38
  export function getOrCreateJob({
39
39
  discipline,
40
- grade,
40
+ level,
41
41
  track = null,
42
42
  skills,
43
43
  behaviours,
44
44
  capabilities,
45
45
  }) {
46
- const key = buildJobKey(discipline.id, grade.id, track?.id);
46
+ const key = buildJobKey(discipline.id, level.id, track?.id);
47
47
 
48
48
  if (!cache.has(key)) {
49
49
  const job = deriveJob({
50
50
  discipline,
51
- grade,
51
+ level,
52
52
  track,
53
53
  skills,
54
54
  behaviours,
@@ -73,11 +73,11 @@ export function clearCache() {
73
73
  /**
74
74
  * Invalidate a specific job from the cache
75
75
  * @param {string} disciplineId
76
- * @param {string} gradeId
76
+ * @param {string} levelId
77
77
  * @param {string} [trackId] - Optional track ID
78
78
  */
79
- export function invalidateCachedJob(disciplineId, gradeId, trackId = null) {
80
- cache.delete(buildJobKey(disciplineId, gradeId, trackId));
79
+ export function invalidateCachedJob(disciplineId, levelId, trackId = null) {
80
+ cache.delete(buildJobKey(disciplineId, levelId, trackId));
81
81
  }
82
82
 
83
83
  /**
package/src/lib/render.js CHANGED
@@ -3,9 +3,9 @@
3
3
  */
4
4
 
5
5
  import {
6
- SKILL_LEVEL_ORDER,
6
+ SKILL_PROFICIENCY_ORDER,
7
7
  BEHAVIOUR_MATURITY_ORDER,
8
- } from "@forwardimpact/schema/levels";
8
+ } from "@forwardimpact/map/levels";
9
9
 
10
10
  /**
11
11
  * Get the main content container
@@ -190,7 +190,7 @@ export function showError(message) {
190
190
  }
191
191
 
192
192
  /**
193
- * Format a skill level or behaviour maturity for display
193
+ * Format a skill proficiency or behaviour maturity for display
194
194
  * Handles both snake_case and camelCase
195
195
  * @param {string} value - The level/maturity value
196
196
  * @returns {string}
@@ -205,12 +205,12 @@ export function formatLevel(value) {
205
205
  }
206
206
 
207
207
  /**
208
- * Get the index for a skill level (1-5)
208
+ * Get the index for a skill proficiency (1-5)
209
209
  * @param {string} level
210
210
  * @returns {number}
211
211
  */
212
- export function getSkillLevelIndex(level) {
213
- return SKILL_LEVEL_ORDER.indexOf(level) + 1;
212
+ export function getSkillProficiencyIndex(level) {
213
+ return SKILL_PROFICIENCY_ORDER.indexOf(level) + 1;
214
214
  }
215
215
 
216
216
  /**
package/src/lib/state.js CHANGED
@@ -15,7 +15,7 @@ const state = {
15
15
  behaviours: [],
16
16
  disciplines: [],
17
17
  tracks: [],
18
- grades: [],
18
+ levels: [],
19
19
  drivers: [],
20
20
  questions: {},
21
21
  capabilities: [],
@@ -31,7 +31,7 @@ const state = {
31
31
  behaviours: { search: "" },
32
32
  disciplines: { search: "" },
33
33
  tracks: { search: "" },
34
- grades: { search: "" },
34
+ levels: { search: "" },
35
35
  drivers: { search: "" },
36
36
  },
37
37
  },
@@ -86,7 +86,7 @@ async function loadSkillsFromCapabilities(capabilitiesDir) {
86
86
  name,
87
87
  capability: capabilityId, // Add capability from parent
88
88
  description: human.description,
89
- levelDescriptions: human.levelDescriptions,
89
+ proficiencyDescriptions: human.proficiencyDescriptions,
90
90
  // Include isHumanOnly flag for agent filtering (defaults to false)
91
91
  ...(isHumanOnly && { isHumanOnly }),
92
92
  ...(agent && { agent }),
@@ -123,7 +123,7 @@ async function loadDisciplinesFromDir(disciplinesDir) {
123
123
  isProfessional,
124
124
  isManagement,
125
125
  validTracks,
126
- minGrade,
126
+ minLevel,
127
127
  // Shared content - now at root level
128
128
  description,
129
129
  // Structural properties (derivation inputs)
@@ -143,7 +143,7 @@ async function loadDisciplinesFromDir(disciplinesDir) {
143
143
  isProfessional,
144
144
  isManagement,
145
145
  validTracks,
146
- minGrade,
146
+ minLevel,
147
147
  // Shared content at top level
148
148
  description,
149
149
  // Structural properties
@@ -181,7 +181,7 @@ async function loadTracksFromDir(tracksDir) {
181
181
  skillModifiers,
182
182
  behaviourModifiers,
183
183
  matchingWeights,
184
- minGrade,
184
+ minLevel,
185
185
  // Agent section (no human section anymore for tracks)
186
186
  agent,
187
187
  } = content;
@@ -195,7 +195,7 @@ async function loadTracksFromDir(tracksDir) {
195
195
  skillModifiers,
196
196
  behaviourModifiers,
197
197
  matchingWeights,
198
- minGrade,
198
+ minLevel,
199
199
  ...(agent && { agent }),
200
200
  };
201
201
  }),
@@ -285,7 +285,7 @@ async function loadQuestionFolder(
285
285
  );
286
286
 
287
287
  return {
288
- skillLevels: Object.fromEntries(skillEntries),
288
+ skillProficiencies: Object.fromEntries(skillEntries),
289
289
  behaviourMaturities: Object.fromEntries(behaviourEntries),
290
290
  capabilityLevels: Object.fromEntries(capabilityEntries),
291
291
  };
@@ -304,13 +304,13 @@ export async function loadAllData(dataDir = "./data") {
304
304
  const skills = await loadSkillsFromCapabilities(`${dataDir}/capabilities`);
305
305
 
306
306
  // Load remaining core data in parallel (using _index.yaml for discovery)
307
- const [drivers, behaviours, disciplines, tracks, grades, stages, framework] =
307
+ const [drivers, behaviours, disciplines, tracks, levels, stages, framework] =
308
308
  await Promise.all([
309
309
  loadYamlFile(`${dataDir}/drivers.yaml`),
310
310
  loadBehavioursFromDir(`${dataDir}/behaviours`),
311
311
  loadDisciplinesFromDir(`${dataDir}/disciplines`),
312
312
  loadTracksFromDir(`${dataDir}/tracks`),
313
- loadYamlFile(`${dataDir}/grades.yaml`),
313
+ loadYamlFile(`${dataDir}/levels.yaml`),
314
314
  loadYamlFile(`${dataDir}/stages.yaml`),
315
315
  loadYamlFile(`${dataDir}/framework.yaml`),
316
316
  ]);
@@ -329,7 +329,7 @@ export async function loadAllData(dataDir = "./data") {
329
329
  skills,
330
330
  disciplines,
331
331
  tracks,
332
- grades,
332
+ levels,
333
333
  questions,
334
334
  capabilities,
335
335
  stages,
package/src/main.js CHANGED
@@ -25,7 +25,7 @@ import {
25
25
  renderDisciplineDetail,
26
26
  } from "./pages/discipline.js";
27
27
  import { renderTracksList, renderTrackDetail } from "./pages/track.js";
28
- import { renderGradesList, renderGradeDetail } from "./pages/grade.js";
28
+ import { renderLevelsList, renderLevelDetail } from "./pages/level.js";
29
29
  import { renderDriversList, renderDriverDetail } from "./pages/driver.js";
30
30
  import { renderStagesList, renderStageDetail } from "./pages/stage.js";
31
31
  import { renderToolsList } from "./pages/tool.js";
@@ -99,9 +99,9 @@ function setupRoutes() {
99
99
  router.on("/track", renderTracksList);
100
100
  router.on("/track/:id", renderTrackDetail);
101
101
 
102
- // Grade
103
- router.on("/grade", renderGradesList);
104
- router.on("/grade/:id", renderGradeDetail);
102
+ // Level
103
+ router.on("/level", renderLevelsList);
104
+ router.on("/level/:id", renderLevelDetail);
105
105
 
106
106
  // Driver
107
107
  router.on("/driver", renderDriversList);
@@ -116,18 +116,18 @@ function setupRoutes() {
116
116
 
117
117
  // Job builder
118
118
  router.on("/job-builder", renderJobBuilder);
119
- router.on("/job/:discipline/:grade/:track", renderJobDetail);
120
- router.on("/job/:discipline/:grade", renderJobDetail);
119
+ router.on("/job/:discipline/:level/:track", renderJobDetail);
120
+ router.on("/job/:discipline/:level", renderJobDetail);
121
121
 
122
122
  // Interview prep
123
123
  router.on("/interview-prep", renderInterviewPrep);
124
- router.on("/interview/:discipline/:grade/:track", renderInterviewDetail);
125
- router.on("/interview/:discipline/:grade", renderInterviewDetail);
124
+ router.on("/interview/:discipline/:level/:track", renderInterviewDetail);
125
+ router.on("/interview/:discipline/:level", renderInterviewDetail);
126
126
 
127
127
  // Career progress
128
128
  router.on("/career-progress", renderCareerProgress);
129
- router.on("/progress/:discipline/:grade/:track", renderProgressDetail);
130
- router.on("/progress/:discipline/:grade", renderProgressDetail);
129
+ router.on("/progress/:discipline/:level/:track", renderProgressDetail);
130
+ router.on("/progress/:discipline/:level", renderProgressDetail);
131
131
 
132
132
  // Self-assessment
133
133
  router.on("/self-assessment", renderSelfAssessment);