@forwardimpact/pathway 0.5.0 → 0.6.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 (233) hide show
  1. package/bin/{pathway.js → fit-pathway.js} +65 -153
  2. package/package.json +17 -41
  3. package/{app → src}/commands/agent.js +5 -2
  4. package/{app → src}/commands/driver.js +1 -1
  5. package/{app → src}/commands/grade.js +1 -1
  6. package/{app → src}/commands/job.js +3 -3
  7. package/{app → src}/commands/serve.js +24 -2
  8. package/{app → src}/commands/site.js +2 -2
  9. package/{app → src}/commands/skill.js +2 -2
  10. package/{app → src}/commands/track.js +1 -1
  11. package/{app → src}/components/checklist.js +1 -1
  12. package/{app → src}/components/comparison-radar.js +1 -1
  13. package/{app → src}/components/detail.js +1 -1
  14. package/{app → src}/components/skill-matrix.js +1 -1
  15. package/{app → src}/formatters/behaviour/dom.js +1 -1
  16. package/{app → src}/formatters/discipline/dom.js +1 -1
  17. package/{app → src}/formatters/driver/dom.js +1 -1
  18. package/{app → src}/formatters/grade/dom.js +1 -1
  19. package/{app → src}/formatters/grade/markdown.js +1 -1
  20. package/{app → src}/formatters/interview/dom.js +1 -1
  21. package/{app → src}/formatters/interview/markdown.js +1 -1
  22. package/{app → src}/formatters/interview/shared.js +3 -3
  23. package/{app → src}/formatters/job/description.js +1 -1
  24. package/{app → src}/formatters/job/markdown.js +1 -1
  25. package/{app → src}/formatters/progress/shared.js +3 -3
  26. package/{app → src}/formatters/skill/dom.js +1 -1
  27. package/{app → src}/formatters/skill/markdown.js +1 -1
  28. package/{app → src}/formatters/skill/shared.js +2 -2
  29. package/{app → src}/formatters/track/dom.js +1 -1
  30. package/{app → src}/formatters/track/markdown.js +1 -1
  31. package/{app → src}/formatters/track/shared.js +4 -1
  32. package/{app → src}/handout-main.js +4 -1
  33. package/src/handout.html +43 -0
  34. package/{app → src}/index.html +16 -1
  35. package/{app → src}/lib/card-mappers.js +1 -1
  36. package/{app → src}/lib/job-cache.js +1 -1
  37. package/{app → src}/lib/render.js +1 -1
  38. package/{app → src}/pages/agent-builder.js +1 -1
  39. package/{app → src}/pages/assessment-results.js +1 -1
  40. package/{app → src}/pages/interview.js +1 -1
  41. package/{app → src}/pages/job-builder.js +1 -1
  42. package/{app → src}/pages/job.js +1 -1
  43. package/{app → src}/pages/landing.js +4 -1
  44. package/{app → src}/pages/self-assessment.js +1 -1
  45. package/{app → src}/pages/skill.js +1 -1
  46. package/{app → src}/pages/stage.js +1 -1
  47. package/{app → src}/pages/tool.js +1 -1
  48. package/{app → src}/slide-main.js +1 -1
  49. package/{app → src}/slides/index.js +2 -2
  50. package/{app → src}/slides/job.js +1 -1
  51. package/{app → src}/slides/overview.js +1 -1
  52. package/{app → src}/slides.html +16 -1
  53. package/templates/agent.template.md +27 -26
  54. package/templates/job.template.md +11 -17
  55. package/templates/skill.template.md +15 -21
  56. package/LICENSE +0 -201
  57. package/README.md +0 -104
  58. package/app/handout.html +0 -28
  59. package/app/model/agent.js +0 -754
  60. package/app/model/checklist.js +0 -103
  61. package/app/model/derivation.js +0 -766
  62. package/app/model/index-generator.js +0 -65
  63. package/app/model/interview.js +0 -539
  64. package/app/model/job.js +0 -228
  65. package/app/model/levels.js +0 -601
  66. package/app/model/loader.js +0 -599
  67. package/app/model/matching.js +0 -888
  68. package/app/model/modifiers.js +0 -158
  69. package/app/model/profile.js +0 -259
  70. package/app/model/progression.js +0 -507
  71. package/app/model/schema-validation.js +0 -438
  72. package/app/model/validation.js +0 -2130
  73. package/examples/behaviours/_index.yaml +0 -8
  74. package/examples/behaviours/outcome_ownership.yaml +0 -43
  75. package/examples/behaviours/polymathic_knowledge.yaml +0 -41
  76. package/examples/behaviours/precise_communication.yaml +0 -39
  77. package/examples/behaviours/relentless_curiosity.yaml +0 -37
  78. package/examples/behaviours/systems_thinking.yaml +0 -40
  79. package/examples/capabilities/_index.yaml +0 -8
  80. package/examples/capabilities/business.yaml +0 -189
  81. package/examples/capabilities/delivery.yaml +0 -305
  82. package/examples/capabilities/people.yaml +0 -68
  83. package/examples/capabilities/reliability.yaml +0 -414
  84. package/examples/capabilities/scale.yaml +0 -378
  85. package/examples/copilot-setup-steps.yaml +0 -25
  86. package/examples/devcontainer.yaml +0 -21
  87. package/examples/disciplines/_index.yaml +0 -6
  88. package/examples/disciplines/data_engineering.yaml +0 -78
  89. package/examples/disciplines/engineering_management.yaml +0 -63
  90. package/examples/disciplines/software_engineering.yaml +0 -78
  91. package/examples/drivers.yaml +0 -202
  92. package/examples/framework.yaml +0 -69
  93. package/examples/grades.yaml +0 -115
  94. package/examples/questions/behaviours/outcome_ownership.yaml +0 -51
  95. package/examples/questions/behaviours/polymathic_knowledge.yaml +0 -47
  96. package/examples/questions/behaviours/precise_communication.yaml +0 -54
  97. package/examples/questions/behaviours/relentless_curiosity.yaml +0 -50
  98. package/examples/questions/behaviours/systems_thinking.yaml +0 -52
  99. package/examples/questions/skills/architecture_design.yaml +0 -53
  100. package/examples/questions/skills/cloud_platforms.yaml +0 -47
  101. package/examples/questions/skills/code_quality.yaml +0 -48
  102. package/examples/questions/skills/data_modeling.yaml +0 -45
  103. package/examples/questions/skills/devops.yaml +0 -46
  104. package/examples/questions/skills/full_stack_development.yaml +0 -47
  105. package/examples/questions/skills/sre_practices.yaml +0 -43
  106. package/examples/questions/skills/stakeholder_management.yaml +0 -48
  107. package/examples/questions/skills/team_collaboration.yaml +0 -42
  108. package/examples/questions/skills/technical_writing.yaml +0 -42
  109. package/examples/self-assessments.yaml +0 -64
  110. package/examples/stages.yaml +0 -139
  111. package/examples/tracks/_index.yaml +0 -5
  112. package/examples/tracks/platform.yaml +0 -49
  113. package/examples/tracks/sre.yaml +0 -48
  114. package/examples/vscode-settings.yaml +0 -17
  115. /package/{app → src}/commands/behaviour.js +0 -0
  116. /package/{app → src}/commands/command-factory.js +0 -0
  117. /package/{app → src}/commands/discipline.js +0 -0
  118. /package/{app → src}/commands/index.js +0 -0
  119. /package/{app → src}/commands/init.js +0 -0
  120. /package/{app → src}/commands/interview.js +0 -0
  121. /package/{app → src}/commands/progress.js +0 -0
  122. /package/{app → src}/commands/questions.js +0 -0
  123. /package/{app → src}/commands/stage.js +0 -0
  124. /package/{app → src}/commands/tool.js +0 -0
  125. /package/{app → src}/components/action-buttons.js +0 -0
  126. /package/{app → src}/components/behaviour-profile.js +0 -0
  127. /package/{app → src}/components/builder.js +0 -0
  128. /package/{app → src}/components/card.js +0 -0
  129. /package/{app → src}/components/code-display.js +0 -0
  130. /package/{app → src}/components/error-page.js +0 -0
  131. /package/{app → src}/components/grid.js +0 -0
  132. /package/{app → src}/components/list.js +0 -0
  133. /package/{app → src}/components/markdown-textarea.js +0 -0
  134. /package/{app → src}/components/modifier-table.js +0 -0
  135. /package/{app → src}/components/nav.js +0 -0
  136. /package/{app → src}/components/progression-table.js +0 -0
  137. /package/{app → src}/components/radar-chart.js +0 -0
  138. /package/{app → src}/css/base.css +0 -0
  139. /package/{app → src}/css/bundles/app.css +0 -0
  140. /package/{app → src}/css/bundles/handout.css +0 -0
  141. /package/{app → src}/css/bundles/slides.css +0 -0
  142. /package/{app → src}/css/components/badges.css +0 -0
  143. /package/{app → src}/css/components/buttons.css +0 -0
  144. /package/{app → src}/css/components/forms.css +0 -0
  145. /package/{app → src}/css/components/layout.css +0 -0
  146. /package/{app → src}/css/components/nav.css +0 -0
  147. /package/{app → src}/css/components/progress.css +0 -0
  148. /package/{app → src}/css/components/states.css +0 -0
  149. /package/{app → src}/css/components/surfaces.css +0 -0
  150. /package/{app → src}/css/components/tables.css +0 -0
  151. /package/{app → src}/css/components/typography.css +0 -0
  152. /package/{app → src}/css/components/utilities.css +0 -0
  153. /package/{app → src}/css/pages/agent-builder.css +0 -0
  154. /package/{app → src}/css/pages/assessment-results.css +0 -0
  155. /package/{app → src}/css/pages/detail.css +0 -0
  156. /package/{app → src}/css/pages/interview-builder.css +0 -0
  157. /package/{app → src}/css/pages/job-builder.css +0 -0
  158. /package/{app → src}/css/pages/landing.css +0 -0
  159. /package/{app → src}/css/pages/lifecycle.css +0 -0
  160. /package/{app → src}/css/pages/progress-builder.css +0 -0
  161. /package/{app → src}/css/pages/self-assessment.css +0 -0
  162. /package/{app → src}/css/reset.css +0 -0
  163. /package/{app → src}/css/tokens.css +0 -0
  164. /package/{app → src}/css/views/handout.css +0 -0
  165. /package/{app → src}/css/views/print.css +0 -0
  166. /package/{app → src}/css/views/slide-animations.css +0 -0
  167. /package/{app → src}/css/views/slide-base.css +0 -0
  168. /package/{app → src}/css/views/slide-sections.css +0 -0
  169. /package/{app → src}/css/views/slide-tables.css +0 -0
  170. /package/{app → src}/formatters/agent/dom.js +0 -0
  171. /package/{app → src}/formatters/agent/profile.js +0 -0
  172. /package/{app → src}/formatters/agent/skill.js +0 -0
  173. /package/{app → src}/formatters/behaviour/markdown.js +0 -0
  174. /package/{app → src}/formatters/behaviour/microdata.js +0 -0
  175. /package/{app → src}/formatters/behaviour/shared.js +0 -0
  176. /package/{app → src}/formatters/discipline/markdown.js +0 -0
  177. /package/{app → src}/formatters/discipline/microdata.js +0 -0
  178. /package/{app → src}/formatters/discipline/shared.js +0 -0
  179. /package/{app → src}/formatters/driver/microdata.js +0 -0
  180. /package/{app → src}/formatters/driver/shared.js +0 -0
  181. /package/{app → src}/formatters/grade/microdata.js +0 -0
  182. /package/{app → src}/formatters/grade/shared.js +0 -0
  183. /package/{app → src}/formatters/index.js +0 -0
  184. /package/{app → src}/formatters/job/dom.js +0 -0
  185. /package/{app → src}/formatters/json-ld.js +0 -0
  186. /package/{app → src}/formatters/microdata-shared.js +0 -0
  187. /package/{app → src}/formatters/progress/dom.js +0 -0
  188. /package/{app → src}/formatters/progress/markdown.js +0 -0
  189. /package/{app → src}/formatters/questions/json.js +0 -0
  190. /package/{app → src}/formatters/questions/markdown.js +0 -0
  191. /package/{app → src}/formatters/questions/shared.js +0 -0
  192. /package/{app → src}/formatters/questions/yaml.js +0 -0
  193. /package/{app → src}/formatters/shared.js +0 -0
  194. /package/{app → src}/formatters/skill/microdata.js +0 -0
  195. /package/{app → src}/formatters/stage/dom.js +0 -0
  196. /package/{app → src}/formatters/stage/index.js +0 -0
  197. /package/{app → src}/formatters/stage/microdata.js +0 -0
  198. /package/{app → src}/formatters/stage/shared.js +0 -0
  199. /package/{app → src}/formatters/tool/shared.js +0 -0
  200. /package/{app → src}/formatters/track/microdata.js +0 -0
  201. /package/{app → src}/lib/cli-output.js +0 -0
  202. /package/{app → src}/lib/error-boundary.js +0 -0
  203. /package/{app → src}/lib/errors.js +0 -0
  204. /package/{app → src}/lib/form-controls.js +0 -0
  205. /package/{app → src}/lib/markdown.js +0 -0
  206. /package/{app → src}/lib/radar.js +0 -0
  207. /package/{app → src}/lib/reactive.js +0 -0
  208. /package/{app → src}/lib/router-core.js +0 -0
  209. /package/{app → src}/lib/router-pages.js +0 -0
  210. /package/{app → src}/lib/router-slides.js +0 -0
  211. /package/{app → src}/lib/state.js +0 -0
  212. /package/{app → src}/lib/template-loader.js +0 -0
  213. /package/{app → src}/lib/utils.js +0 -0
  214. /package/{app → src}/lib/yaml-loader.js +0 -0
  215. /package/{app → src}/main.js +0 -0
  216. /package/{app → src}/pages/behaviour.js +0 -0
  217. /package/{app → src}/pages/discipline.js +0 -0
  218. /package/{app → src}/pages/driver.js +0 -0
  219. /package/{app → src}/pages/grade.js +0 -0
  220. /package/{app → src}/pages/interview-builder.js +0 -0
  221. /package/{app → src}/pages/progress-builder.js +0 -0
  222. /package/{app → src}/pages/progress.js +0 -0
  223. /package/{app → src}/pages/track.js +0 -0
  224. /package/{app → src}/slides/behaviour.js +0 -0
  225. /package/{app → src}/slides/chapter.js +0 -0
  226. /package/{app → src}/slides/discipline.js +0 -0
  227. /package/{app → src}/slides/driver.js +0 -0
  228. /package/{app → src}/slides/grade.js +0 -0
  229. /package/{app → src}/slides/interview.js +0 -0
  230. /package/{app → src}/slides/progress.js +0 -0
  231. /package/{app → src}/slides/skill.js +0 -0
  232. /package/{app → src}/slides/track.js +0 -0
  233. /package/{app → src}/types.js +0 -0
@@ -1,158 +0,0 @@
1
- /**
2
- * Skill Modifier Expansion Functions
3
- *
4
- * This module provides pure functions for expanding capability-based skill modifiers
5
- * to individual skill modifiers. Tracks define modifiers by capability only
6
- * (e.g., "delivery: 1", "scale: -1") - individual skill modifiers are not allowed.
7
- */
8
-
9
- import { CAPABILITY_ORDER } from "./levels.js";
10
-
11
- /**
12
- * Valid skill capability names for modifier expansion
13
- * @type {Set<string>}
14
- */
15
- const VALID_CAPABILITIES = new Set(CAPABILITY_ORDER);
16
-
17
- /**
18
- * Check if a key is a skill capability
19
- * @param {string} key - The key to check
20
- * @returns {boolean} True if the key is a valid skill capability
21
- */
22
- export function isCapability(key) {
23
- return VALID_CAPABILITIES.has(key);
24
- }
25
-
26
- /**
27
- * Get skills by capability from a skills array
28
- * @param {import('./levels.js').Skill[]} skills - Array of all skills
29
- * @param {string} capability - The capability to filter by
30
- * @returns {import('./levels.js').Skill[]} Skills in the specified capability
31
- */
32
- export function getSkillsByCapability(skills, capability) {
33
- return skills.filter((skill) => skill.capability === capability);
34
- }
35
-
36
- /**
37
- * Build a map of capability to skill IDs
38
- * @param {import('./levels.js').Skill[]} skills - Array of all skills
39
- * @returns {Object<string, string[]>} Map of capability to array of skill IDs
40
- */
41
- export function buildCapabilityToSkillsMap(skills) {
42
- const capabilityMap = {};
43
-
44
- for (const capability of VALID_CAPABILITIES) {
45
- capabilityMap[capability] = [];
46
- }
47
-
48
- for (const skill of skills) {
49
- if (skill.capability && capabilityMap[skill.capability]) {
50
- capabilityMap[skill.capability].push(skill.id);
51
- }
52
- }
53
-
54
- return capabilityMap;
55
- }
56
-
57
- /**
58
- * Expand capability-based skill modifiers to individual skill modifiers
59
- *
60
- * Takes a skillModifiers object containing capability-based modifiers only
61
- * (e.g., { delivery: 1, scale: -1 }). Individual skill modifiers are not allowed.
62
- *
63
- * Returns an object with individual skill modifiers expanded from capabilities.
64
- *
65
- * @param {Object<string, number>} skillModifiers - The capability skill modifiers
66
- * @param {import('./levels.js').Skill[]} skills - Array of all skills (for capability lookup)
67
- * @returns {Object<string, number>} Expanded skill modifiers with individual skill IDs
68
- */
69
- export function expandSkillModifiers(skillModifiers, skills) {
70
- if (!skillModifiers) {
71
- return {};
72
- }
73
-
74
- const capabilityMap = buildCapabilityToSkillsMap(skills);
75
- const expanded = {};
76
-
77
- // Expand capability modifiers to individual skills
78
- for (const [key, modifier] of Object.entries(skillModifiers)) {
79
- if (isCapability(key)) {
80
- // This is a capability - expand to all skills in that capability
81
- const skillIds = capabilityMap[key] || [];
82
- for (const skillId of skillIds) {
83
- expanded[skillId] = modifier;
84
- }
85
- }
86
- // Non-capability keys are ignored (validation should catch these)
87
- }
88
-
89
- return expanded;
90
- }
91
-
92
- /**
93
- * Extract capability modifiers from a skillModifiers object
94
- * @param {Object<string, number>} skillModifiers - The skill modifiers
95
- * @returns {Object<string, number>} Only the capability-based modifiers
96
- */
97
- export function extractCapabilityModifiers(skillModifiers) {
98
- if (!skillModifiers) {
99
- return {};
100
- }
101
-
102
- const result = {};
103
- for (const [key, modifier] of Object.entries(skillModifiers)) {
104
- if (isCapability(key)) {
105
- result[key] = modifier;
106
- }
107
- }
108
- return result;
109
- }
110
-
111
- /**
112
- * Extract individual skill modifiers from a skillModifiers object
113
- * @param {Object<string, number>} skillModifiers - The skill modifiers
114
- * @returns {Object<string, number>} Only the individual skill modifiers
115
- */
116
- export function extractIndividualModifiers(skillModifiers) {
117
- if (!skillModifiers) {
118
- return {};
119
- }
120
-
121
- const result = {};
122
- for (const [key, modifier] of Object.entries(skillModifiers)) {
123
- if (!isCapability(key)) {
124
- result[key] = modifier;
125
- }
126
- }
127
- return result;
128
- }
129
-
130
- /**
131
- * Get the effective skill modifier for a specific skill
132
- *
133
- * Looks up the capability modifier for the skill's capability.
134
- * Returns 0 if no modifier applies.
135
- *
136
- * @param {string} skillId - The skill ID to get modifier for
137
- * @param {Object<string, number>} skillModifiers - The capability skill modifiers
138
- * @param {import('./levels.js').Skill[]} skills - Array of all skills
139
- * @returns {number} The effective modifier for this skill
140
- */
141
- export function resolveSkillModifier(skillId, skillModifiers, skills) {
142
- if (!skillModifiers) {
143
- return 0;
144
- }
145
-
146
- // Find the skill's capability
147
- const skill = skills.find((s) => s.id === skillId);
148
- if (!skill || !skill.capability) {
149
- return 0;
150
- }
151
-
152
- // Check for capability modifier
153
- if (skill.capability in skillModifiers) {
154
- return skillModifiers[skill.capability];
155
- }
156
-
157
- return 0;
158
- }
@@ -1,259 +0,0 @@
1
- /**
2
- * Unified Profile Derivation
3
- *
4
- * Shared functions for deriving skill and behaviour profiles for both
5
- * human jobs and AI agents. This module provides:
6
- *
7
- * 1. Filtering functions - reusable filters for skills and behaviours
8
- * 2. Sorting functions - sort by level/maturity for display
9
- * 3. prepareBaseProfile() - shared profile derivation used by both job.js and agent.js
10
- *
11
- * The core derivation (deriveSkillMatrix, deriveBehaviourProfile) remains in
12
- * derivation.js. This module adds post-processing for specific use cases.
13
- *
14
- * Agent filtering keeps only skills at the highest derived level. This ensures
15
- * track modifiers are respected—a broad skill boosted by a +1 track modifier
16
- * may reach the same level as primary skills and thus be included.
17
- */
18
-
19
- import { SKILL_LEVEL_ORDER, BEHAVIOUR_MATURITY_ORDER } from "./levels.js";
20
- import {
21
- deriveSkillMatrix,
22
- deriveBehaviourProfile,
23
- deriveResponsibilities,
24
- } from "./derivation.js";
25
-
26
- // =============================================================================
27
- // Skill Filters
28
- // =============================================================================
29
-
30
- /**
31
- * Build set of capabilities with positive track modifiers
32
- * @param {Object} track - Track definition
33
- * @returns {Set<string>} Set of capability IDs with positive modifiers
34
- */
35
- export function getPositiveTrackCapabilities(track) {
36
- return new Set(
37
- Object.entries(track.skillModifiers || {})
38
- .filter(([_, modifier]) => modifier > 0)
39
- .map(([capability]) => capability),
40
- );
41
- }
42
-
43
- /**
44
- * Filter out human-only skills
45
- * Human-only skills are those requiring human presence/experience
46
- * @param {Array} skillMatrix - Skill matrix entries
47
- * @returns {Array} Filtered skill matrix
48
- */
49
- export function filterHumanOnlySkills(skillMatrix) {
50
- return skillMatrix.filter((entry) => !entry.isHumanOnly);
51
- }
52
-
53
- /**
54
- * Filter skills to keep only those at the highest derived level
55
- * After track modifiers are applied, some skills will be at higher levels
56
- * than others. This filter keeps only the skills at the maximum level.
57
- * @param {Array} skillMatrix - Skill matrix entries with derived levels
58
- * @returns {Array} Filtered skill matrix containing only highest-level skills
59
- */
60
- export function filterByHighestLevel(skillMatrix) {
61
- if (skillMatrix.length === 0) return [];
62
-
63
- // Find the highest level index in the matrix
64
- const maxLevelIndex = Math.max(
65
- ...skillMatrix.map((entry) => SKILL_LEVEL_ORDER.indexOf(entry.level)),
66
- );
67
-
68
- // Keep only skills at that level
69
- return skillMatrix.filter(
70
- (entry) => SKILL_LEVEL_ORDER.indexOf(entry.level) === maxLevelIndex,
71
- );
72
- }
73
-
74
- /**
75
- * Apply agent-specific skill filters
76
- * Filters to human-only skills and keeps only skills at the highest derived level.
77
- * This approach respects track modifiers—a broad skill boosted to the same level
78
- * as primary skills will be included.
79
- * @param {Array} skillMatrix - Skill matrix entries with derived levels
80
- * @returns {Array} Filtered skill matrix
81
- */
82
- export function filterSkillsForAgent(skillMatrix) {
83
- // First exclude human-only skills
84
- const withoutHumanOnly = filterHumanOnlySkills(skillMatrix);
85
-
86
- // Then keep only skills at the highest level
87
- return filterByHighestLevel(withoutHumanOnly);
88
- }
89
-
90
- // =============================================================================
91
- // Sorting Functions
92
- // =============================================================================
93
-
94
- /**
95
- * Sort skills by level (highest first)
96
- * Used for agent profiles where top skills should appear first
97
- * @param {Array} skillMatrix - Skill matrix entries
98
- * @returns {Array} Sorted skill matrix (new array)
99
- */
100
- export function sortByLevelDescending(skillMatrix) {
101
- return [...skillMatrix].sort((a, b) => {
102
- const aIndex = SKILL_LEVEL_ORDER.indexOf(a.level);
103
- const bIndex = SKILL_LEVEL_ORDER.indexOf(b.level);
104
- return bIndex - aIndex;
105
- });
106
- }
107
-
108
- /**
109
- * Sort behaviours by maturity (highest first)
110
- * Used for agent profiles where top behaviours should appear first
111
- * @param {Array} behaviourProfile - Behaviour profile entries
112
- * @returns {Array} Sorted behaviour profile (new array)
113
- */
114
- export function sortByMaturityDescending(behaviourProfile) {
115
- return [...behaviourProfile].sort((a, b) => {
116
- const aIndex = BEHAVIOUR_MATURITY_ORDER.indexOf(a.maturity);
117
- const bIndex = BEHAVIOUR_MATURITY_ORDER.indexOf(b.maturity);
118
- return bIndex - aIndex;
119
- });
120
- }
121
-
122
- // =============================================================================
123
- // Profile Derivation
124
- // =============================================================================
125
-
126
- /**
127
- * @typedef {Object} ProfileOptions
128
- * @property {boolean} [excludeHumanOnly=false] - Filter out human-only skills
129
- * @property {boolean} [keepHighestLevelOnly=false] - Keep only skills at the highest derived level
130
- * @property {boolean} [sortByLevel=false] - Sort skills by level descending
131
- * @property {boolean} [sortByMaturity=false] - Sort behaviours by maturity descending
132
- */
133
-
134
- /**
135
- * @typedef {Object} BaseProfile
136
- * @property {Array} skillMatrix - Derived skill matrix
137
- * @property {Array} behaviourProfile - Derived behaviour profile
138
- * @property {Array} derivedResponsibilities - Derived responsibilities (if capabilities provided)
139
- * @property {Object} discipline - The discipline
140
- * @property {Object} track - The track
141
- * @property {Object} grade - The grade
142
- */
143
-
144
- /**
145
- * Prepare a base profile shared by jobs and agents
146
- *
147
- * This is the unified entry point for profile derivation. Both human jobs
148
- * and AI agents use this function, with different options:
149
- *
150
- * - Human jobs: No filtering, default sorting by type
151
- * - AI agents: Filter humanOnly, keep only highest-level skills, sort by level
152
- *
153
- * @param {Object} params
154
- * @param {Object} params.discipline - The discipline
155
- * @param {Object} params.track - The track
156
- * @param {Object} params.grade - The grade
157
- * @param {Array} params.skills - All available skills
158
- * @param {Array} params.behaviours - All available behaviours
159
- * @param {Array} [params.capabilities] - Optional capabilities for responsibility derivation
160
- * @param {ProfileOptions} [params.options={}] - Filtering and sorting options
161
- * @returns {BaseProfile} The prepared profile
162
- */
163
- export function prepareBaseProfile({
164
- discipline,
165
- track,
166
- grade,
167
- skills,
168
- behaviours,
169
- capabilities,
170
- options = {},
171
- }) {
172
- const {
173
- excludeHumanOnly = false,
174
- keepHighestLevelOnly = false,
175
- sortByLevel = false,
176
- sortByMaturity = false,
177
- } = options;
178
-
179
- // Core derivation
180
- let skillMatrix = deriveSkillMatrix({ discipline, grade, track, skills });
181
- let behaviourProfile = deriveBehaviourProfile({
182
- discipline,
183
- grade,
184
- track,
185
- behaviours,
186
- });
187
-
188
- // Apply skill filters
189
- if (excludeHumanOnly) {
190
- skillMatrix = filterHumanOnlySkills(skillMatrix);
191
- }
192
- if (keepHighestLevelOnly) {
193
- skillMatrix = filterByHighestLevel(skillMatrix);
194
- }
195
-
196
- // Apply sorting
197
- if (sortByLevel) {
198
- skillMatrix = sortByLevelDescending(skillMatrix);
199
- }
200
- if (sortByMaturity) {
201
- behaviourProfile = sortByMaturityDescending(behaviourProfile);
202
- }
203
-
204
- // Derive responsibilities if capabilities provided
205
- let derivedResponsibilities = [];
206
- if (capabilities && capabilities.length > 0) {
207
- derivedResponsibilities = deriveResponsibilities({
208
- skillMatrix,
209
- capabilities,
210
- track,
211
- });
212
- }
213
-
214
- return {
215
- skillMatrix,
216
- behaviourProfile,
217
- derivedResponsibilities,
218
- discipline,
219
- track,
220
- grade,
221
- };
222
- }
223
-
224
- /**
225
- * Preset options for agent profile derivation
226
- * Excludes human-only skills, keeps only skills at the highest derived level,
227
- * and sorts by level/maturity descending
228
- */
229
- export const AGENT_PROFILE_OPTIONS = {
230
- excludeHumanOnly: true,
231
- keepHighestLevelOnly: true,
232
- sortByLevel: true,
233
- sortByMaturity: true,
234
- };
235
-
236
- /**
237
- * Prepare a profile optimized for agent generation
238
- * Convenience function that applies AGENT_PROFILE_OPTIONS
239
- * @param {Object} params - Same as prepareBaseProfile, without options
240
- * @returns {BaseProfile} The prepared profile
241
- */
242
- export function prepareAgentProfile({
243
- discipline,
244
- track,
245
- grade,
246
- skills,
247
- behaviours,
248
- capabilities,
249
- }) {
250
- return prepareBaseProfile({
251
- discipline,
252
- track,
253
- grade,
254
- skills,
255
- behaviours,
256
- capabilities,
257
- options: AGENT_PROFILE_OPTIONS,
258
- });
259
- }