@forwardimpact/pathway 0.25.15 → 0.25.21

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 (34) hide show
  1. package/bin/fit-pathway.js +62 -54
  2. package/package.json +1 -3
  3. package/src/commands/agent-io.js +120 -0
  4. package/src/commands/agent.js +266 -349
  5. package/src/commands/init.js +2 -2
  6. package/src/commands/job.js +237 -183
  7. package/src/components/comparison-radar.js +118 -103
  8. package/src/components/progression-table.js +244 -208
  9. package/src/formatters/index.js +0 -19
  10. package/src/formatters/interview/markdown.js +100 -88
  11. package/src/formatters/job/description.js +76 -75
  12. package/src/formatters/job/dom.js +113 -97
  13. package/src/formatters/level/dom.js +87 -102
  14. package/src/formatters/questions/markdown.js +37 -33
  15. package/src/formatters/questions/shared.js +142 -75
  16. package/src/formatters/skill/dom.js +102 -93
  17. package/src/lib/comparison-radar-chart.js +256 -0
  18. package/src/lib/radar-utils.js +199 -0
  19. package/src/lib/radar.js +25 -662
  20. package/src/pages/agent-builder-download.js +170 -0
  21. package/src/pages/agent-builder-preview.js +344 -0
  22. package/src/pages/agent-builder.js +6 -550
  23. package/src/pages/progress-comparison.js +110 -0
  24. package/src/pages/progress.js +11 -111
  25. package/src/pages/self-assessment-steps.js +494 -0
  26. package/src/pages/self-assessment.js +54 -504
  27. package/src/formatters/behaviour/microdata.js +0 -106
  28. package/src/formatters/discipline/microdata.js +0 -117
  29. package/src/formatters/driver/microdata.js +0 -91
  30. package/src/formatters/level/microdata.js +0 -141
  31. package/src/formatters/microdata-shared.js +0 -184
  32. package/src/formatters/skill/microdata.js +0 -151
  33. package/src/formatters/stage/microdata.js +0 -116
  34. package/src/formatters/track/microdata.js +0 -111
@@ -15,6 +15,115 @@ import {
15
15
  } from "../lib/render.js";
16
16
  import { compareByCapability } from "@forwardimpact/libskill/policies";
17
17
 
18
+ /**
19
+ * Build sorted skill entries from current and target matrices
20
+ * @param {Array} currentMatrix
21
+ * @param {Array} targetMatrix
22
+ * @param {Object} options
23
+ * @returns {{currentData: Array, targetData: Array}}
24
+ */
25
+ function buildSkillComparisonData(currentMatrix, targetMatrix, options) {
26
+ const allSkillIds = new Set([
27
+ ...currentMatrix.map((s) => s.skillId),
28
+ ...targetMatrix.map((s) => s.skillId),
29
+ ]);
30
+
31
+ const skillEntries = [];
32
+ for (const skillId of allSkillIds) {
33
+ const currentSkill = currentMatrix.find((s) => s.skillId === skillId);
34
+ const targetSkill = targetMatrix.find((s) => s.skillId === skillId);
35
+ skillEntries.push({
36
+ skillId,
37
+ skillName: currentSkill?.skillName || targetSkill?.skillName,
38
+ capability: currentSkill?.capability || targetSkill?.capability || "",
39
+ currentSkill,
40
+ targetSkill,
41
+ });
42
+ }
43
+
44
+ const capabilityComparator = options.capabilities
45
+ ? compareByCapability(options.capabilities)
46
+ : (a, b) => a.capability.localeCompare(b.capability);
47
+ skillEntries.sort((a, b) => {
48
+ const capDiff = capabilityComparator(a, b);
49
+ return capDiff !== 0 ? capDiff : a.skillName.localeCompare(b.skillName);
50
+ });
51
+
52
+ const currentData = [];
53
+ const targetData = [];
54
+
55
+ for (const { skillName, currentSkill, targetSkill } of skillEntries) {
56
+ currentData.push({
57
+ label: skillName,
58
+ value: currentSkill ? getSkillProficiencyIndex(currentSkill.level) : 0,
59
+ maxValue: 5,
60
+ description: currentSkill
61
+ ? `${formatLevel(currentSkill.type)} - ${formatLevel(currentSkill.level)}`
62
+ : "Not required",
63
+ });
64
+ targetData.push({
65
+ label: skillName,
66
+ value: targetSkill ? getSkillProficiencyIndex(targetSkill.level) : 0,
67
+ maxValue: 5,
68
+ description: targetSkill
69
+ ? `${formatLevel(targetSkill.type)} - ${formatLevel(targetSkill.level)}`
70
+ : "Not required",
71
+ });
72
+ }
73
+
74
+ return { currentData, targetData };
75
+ }
76
+
77
+ /**
78
+ * Build behaviour comparison data from current and target profiles
79
+ * @param {Array} currentProfile
80
+ * @param {Array} targetProfile
81
+ * @returns {{currentData: Array, targetData: Array}}
82
+ */
83
+ function buildBehaviourComparisonData(currentProfile, targetProfile) {
84
+ const allBehaviourIds = new Set([
85
+ ...currentProfile.map((b) => b.behaviourId),
86
+ ...targetProfile.map((b) => b.behaviourId),
87
+ ]);
88
+
89
+ const currentData = [];
90
+ const targetData = [];
91
+
92
+ for (const behaviourId of allBehaviourIds) {
93
+ const currentBehaviour = currentProfile.find(
94
+ (b) => b.behaviourId === behaviourId,
95
+ );
96
+ const targetBehaviour = targetProfile.find(
97
+ (b) => b.behaviourId === behaviourId,
98
+ );
99
+ const behaviourName =
100
+ currentBehaviour?.behaviourName || targetBehaviour?.behaviourName;
101
+
102
+ currentData.push({
103
+ label: behaviourName,
104
+ value: currentBehaviour
105
+ ? getBehaviourMaturityIndex(currentBehaviour.maturity)
106
+ : 0,
107
+ maxValue: 5,
108
+ description: currentBehaviour
109
+ ? `${formatLevel(currentBehaviour.maturity)}`
110
+ : "Not required",
111
+ });
112
+ targetData.push({
113
+ label: behaviourName,
114
+ value: targetBehaviour
115
+ ? getBehaviourMaturityIndex(targetBehaviour.maturity)
116
+ : 0,
117
+ maxValue: 5,
118
+ description: targetBehaviour
119
+ ? `${formatLevel(targetBehaviour.maturity)}`
120
+ : "Not required",
121
+ });
122
+ }
123
+
124
+ return { currentData, targetData };
125
+ }
126
+
18
127
  /**
19
128
  * Create a comparison skill radar chart
20
129
  * @param {SkillMatrixItem[]} currentMatrix - Current skill matrix entries
@@ -54,65 +163,11 @@ export function createComparisonSkillRadar(
54
163
  const wrapper = container.querySelector(".radar-chart-wrapper");
55
164
  if (!wrapper || !currentMatrix || currentMatrix.length === 0) return;
56
165
 
57
- // Build aligned data arrays that include all skills from both matrices
58
- // This handles new skills (in target but not current) and removed skills (in current but not target)
59
- const allSkillIds = new Set([
60
- ...currentMatrix.map((s) => s.skillId),
61
- ...targetMatrix.map((s) => s.skillId),
62
- ]);
63
-
64
- // Build skill entries with capability info for sorting
65
- const skillEntries = [];
66
- for (const skillId of allSkillIds) {
67
- const currentSkill = currentMatrix.find((s) => s.skillId === skillId);
68
- const targetSkill = targetMatrix.find((s) => s.skillId === skillId);
69
- const capability =
70
- currentSkill?.capability || targetSkill?.capability || "";
71
- const skillName = currentSkill?.skillName || targetSkill?.skillName;
72
-
73
- skillEntries.push({
74
- skillId,
75
- skillName,
76
- capability,
77
- currentSkill,
78
- targetSkill,
79
- });
80
- }
81
-
82
- // Sort by capability order, then by skill name within capability
83
- const capabilityComparator = options.capabilities
84
- ? compareByCapability(options.capabilities)
85
- : (a, b) => a.capability.localeCompare(b.capability);
86
- skillEntries.sort((a, b) => {
87
- const capDiff = capabilityComparator(a, b);
88
- if (capDiff !== 0) return capDiff;
89
- return a.skillName.localeCompare(b.skillName);
90
- });
91
-
92
- const currentData = [];
93
- const targetData = [];
94
-
95
- for (const entry of skillEntries) {
96
- const { skillName, currentSkill, targetSkill } = entry;
97
-
98
- currentData.push({
99
- label: skillName,
100
- value: currentSkill ? getSkillProficiencyIndex(currentSkill.level) : 0,
101
- maxValue: 5,
102
- description: currentSkill
103
- ? `${formatLevel(currentSkill.type)} - ${formatLevel(currentSkill.level)}`
104
- : "Not required",
105
- });
106
-
107
- targetData.push({
108
- label: skillName,
109
- value: targetSkill ? getSkillProficiencyIndex(targetSkill.level) : 0,
110
- maxValue: 5,
111
- description: targetSkill
112
- ? `${formatLevel(targetSkill.type)} - ${formatLevel(targetSkill.level)}`
113
- : "Not required",
114
- });
115
- }
166
+ const { currentData, targetData } = buildSkillComparisonData(
167
+ currentMatrix,
168
+ targetMatrix,
169
+ options,
170
+ );
116
171
 
117
172
  const chart = new ComparisonRadarChart({
118
173
  container: wrapper,
@@ -173,50 +228,10 @@ export function createComparisonBehaviourRadar(
173
228
  const wrapper = container.querySelector(".radar-chart-wrapper");
174
229
  if (!wrapper || !currentProfile || currentProfile.length === 0) return;
175
230
 
176
- // Build aligned data arrays that include all behaviours from both profiles
177
- // This handles new behaviours (in target but not current) and removed behaviours (in current but not target)
178
- const allBehaviourIds = new Set([
179
- ...currentProfile.map((b) => b.behaviourId),
180
- ...targetProfile.map((b) => b.behaviourId),
181
- ]);
182
-
183
- const currentData = [];
184
- const targetData = [];
185
-
186
- for (const behaviourId of allBehaviourIds) {
187
- const currentBehaviour = currentProfile.find(
188
- (b) => b.behaviourId === behaviourId,
189
- );
190
- const targetBehaviour = targetProfile.find(
191
- (b) => b.behaviourId === behaviourId,
192
- );
193
-
194
- // Use whichever behaviour entry exists for the label
195
- const behaviourName =
196
- currentBehaviour?.behaviourName || targetBehaviour?.behaviourName;
197
-
198
- currentData.push({
199
- label: behaviourName,
200
- value: currentBehaviour
201
- ? getBehaviourMaturityIndex(currentBehaviour.maturity)
202
- : 0,
203
- maxValue: 5,
204
- description: currentBehaviour
205
- ? `${formatLevel(currentBehaviour.maturity)}`
206
- : "Not required",
207
- });
208
-
209
- targetData.push({
210
- label: behaviourName,
211
- value: targetBehaviour
212
- ? getBehaviourMaturityIndex(targetBehaviour.maturity)
213
- : 0,
214
- maxValue: 5,
215
- description: targetBehaviour
216
- ? `${formatLevel(targetBehaviour.maturity)}`
217
- : "Not required",
218
- });
219
- }
231
+ const { currentData, targetData } = buildBehaviourComparisonData(
232
+ currentProfile,
233
+ targetProfile,
234
+ );
220
235
 
221
236
  const chart = new ComparisonRadarChart({
222
237
  container: wrapper,