@forwardimpact/pathway 0.1.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.
- package/LICENSE +201 -0
- package/README.md +104 -0
- package/app/commands/agent.js +430 -0
- package/app/commands/behaviour.js +61 -0
- package/app/commands/command-factory.js +211 -0
- package/app/commands/discipline.js +58 -0
- package/app/commands/driver.js +94 -0
- package/app/commands/grade.js +60 -0
- package/app/commands/index.js +20 -0
- package/app/commands/init.js +67 -0
- package/app/commands/interview.js +68 -0
- package/app/commands/job.js +157 -0
- package/app/commands/progress.js +77 -0
- package/app/commands/questions.js +179 -0
- package/app/commands/serve.js +143 -0
- package/app/commands/site.js +121 -0
- package/app/commands/skill.js +76 -0
- package/app/commands/stage.js +129 -0
- package/app/commands/track.js +70 -0
- package/app/components/action-buttons.js +66 -0
- package/app/components/behaviour-profile.js +53 -0
- package/app/components/builder.js +341 -0
- package/app/components/card.js +98 -0
- package/app/components/checklist.js +145 -0
- package/app/components/comparison-radar.js +237 -0
- package/app/components/detail.js +230 -0
- package/app/components/error-page.js +72 -0
- package/app/components/grid.js +109 -0
- package/app/components/list.js +120 -0
- package/app/components/modifier-table.js +142 -0
- package/app/components/nav.js +64 -0
- package/app/components/progression-table.js +320 -0
- package/app/components/radar-chart.js +102 -0
- package/app/components/skill-matrix.js +97 -0
- package/app/css/base.css +56 -0
- package/app/css/bundles/app.css +40 -0
- package/app/css/bundles/handout.css +43 -0
- package/app/css/bundles/slides.css +40 -0
- package/app/css/components/badges.css +215 -0
- package/app/css/components/buttons.css +101 -0
- package/app/css/components/forms.css +105 -0
- package/app/css/components/layout.css +209 -0
- package/app/css/components/nav.css +166 -0
- package/app/css/components/progress.css +166 -0
- package/app/css/components/states.css +82 -0
- package/app/css/components/surfaces.css +243 -0
- package/app/css/components/tables.css +362 -0
- package/app/css/components/typography.css +122 -0
- package/app/css/components/utilities.css +41 -0
- package/app/css/pages/agent-builder.css +391 -0
- package/app/css/pages/assessment-results.css +453 -0
- package/app/css/pages/detail.css +59 -0
- package/app/css/pages/interview-builder.css +148 -0
- package/app/css/pages/job-builder.css +134 -0
- package/app/css/pages/landing.css +92 -0
- package/app/css/pages/lifecycle.css +118 -0
- package/app/css/pages/progress-builder.css +274 -0
- package/app/css/pages/self-assessment.css +502 -0
- package/app/css/reset.css +50 -0
- package/app/css/tokens.css +153 -0
- package/app/css/views/handout.css +30 -0
- package/app/css/views/print.css +608 -0
- package/app/css/views/slide-animations.css +113 -0
- package/app/css/views/slide-base.css +330 -0
- package/app/css/views/slide-sections.css +597 -0
- package/app/css/views/slide-tables.css +275 -0
- package/app/formatters/agent/dom.js +540 -0
- package/app/formatters/agent/profile.js +133 -0
- package/app/formatters/agent/skill.js +58 -0
- package/app/formatters/behaviour/dom.js +91 -0
- package/app/formatters/behaviour/markdown.js +54 -0
- package/app/formatters/behaviour/shared.js +64 -0
- package/app/formatters/discipline/dom.js +187 -0
- package/app/formatters/discipline/markdown.js +87 -0
- package/app/formatters/discipline/shared.js +131 -0
- package/app/formatters/driver/dom.js +103 -0
- package/app/formatters/driver/shared.js +92 -0
- package/app/formatters/grade/dom.js +208 -0
- package/app/formatters/grade/markdown.js +94 -0
- package/app/formatters/grade/shared.js +86 -0
- package/app/formatters/index.js +50 -0
- package/app/formatters/interview/dom.js +97 -0
- package/app/formatters/interview/markdown.js +66 -0
- package/app/formatters/interview/shared.js +332 -0
- package/app/formatters/job/description.js +176 -0
- package/app/formatters/job/dom.js +411 -0
- package/app/formatters/job/markdown.js +102 -0
- package/app/formatters/progress/dom.js +135 -0
- package/app/formatters/progress/markdown.js +86 -0
- package/app/formatters/progress/shared.js +339 -0
- package/app/formatters/questions/json.js +43 -0
- package/app/formatters/questions/markdown.js +303 -0
- package/app/formatters/questions/shared.js +274 -0
- package/app/formatters/questions/yaml.js +76 -0
- package/app/formatters/shared.js +71 -0
- package/app/formatters/skill/dom.js +168 -0
- package/app/formatters/skill/markdown.js +109 -0
- package/app/formatters/skill/shared.js +125 -0
- package/app/formatters/stage/dom.js +135 -0
- package/app/formatters/stage/index.js +12 -0
- package/app/formatters/stage/shared.js +111 -0
- package/app/formatters/track/dom.js +128 -0
- package/app/formatters/track/markdown.js +105 -0
- package/app/formatters/track/shared.js +181 -0
- package/app/handout-main.js +421 -0
- package/app/handout.html +21 -0
- package/app/index.html +59 -0
- package/app/lib/card-mappers.js +173 -0
- package/app/lib/cli-output.js +270 -0
- package/app/lib/error-boundary.js +70 -0
- package/app/lib/errors.js +49 -0
- package/app/lib/form-controls.js +47 -0
- package/app/lib/job-cache.js +86 -0
- package/app/lib/markdown.js +114 -0
- package/app/lib/radar.js +866 -0
- package/app/lib/reactive.js +77 -0
- package/app/lib/render.js +212 -0
- package/app/lib/router-core.js +160 -0
- package/app/lib/router-pages.js +16 -0
- package/app/lib/router-slides.js +202 -0
- package/app/lib/state.js +148 -0
- package/app/lib/utils.js +14 -0
- package/app/lib/yaml-loader.js +327 -0
- package/app/main.js +213 -0
- package/app/model/agent.js +702 -0
- package/app/model/checklist.js +137 -0
- package/app/model/derivation.js +699 -0
- package/app/model/index-generator.js +71 -0
- package/app/model/interview.js +539 -0
- package/app/model/job.js +222 -0
- package/app/model/levels.js +591 -0
- package/app/model/loader.js +564 -0
- package/app/model/matching.js +858 -0
- package/app/model/modifiers.js +158 -0
- package/app/model/profile.js +266 -0
- package/app/model/progression.js +507 -0
- package/app/model/validation.js +1385 -0
- package/app/pages/agent-builder.js +823 -0
- package/app/pages/assessment-results.js +507 -0
- package/app/pages/behaviour.js +70 -0
- package/app/pages/discipline.js +71 -0
- package/app/pages/driver.js +106 -0
- package/app/pages/grade.js +117 -0
- package/app/pages/interview-builder.js +50 -0
- package/app/pages/interview.js +304 -0
- package/app/pages/job-builder.js +50 -0
- package/app/pages/job.js +58 -0
- package/app/pages/landing.js +305 -0
- package/app/pages/progress-builder.js +58 -0
- package/app/pages/progress.js +495 -0
- package/app/pages/self-assessment.js +729 -0
- package/app/pages/skill.js +113 -0
- package/app/pages/stage.js +231 -0
- package/app/pages/track.js +69 -0
- package/app/slide-main.js +360 -0
- package/app/slides/behaviour.js +38 -0
- package/app/slides/chapter.js +82 -0
- package/app/slides/discipline.js +40 -0
- package/app/slides/driver.js +39 -0
- package/app/slides/grade.js +32 -0
- package/app/slides/index.js +198 -0
- package/app/slides/interview.js +58 -0
- package/app/slides/job.js +55 -0
- package/app/slides/overview.js +126 -0
- package/app/slides/progress.js +83 -0
- package/app/slides/skill.js +40 -0
- package/app/slides/track.js +39 -0
- package/app/slides.html +56 -0
- package/app/types.js +147 -0
- package/bin/pathway.js +489 -0
- package/examples/agents/.claude/skills/architecture-design/SKILL.md +88 -0
- package/examples/agents/.claude/skills/cloud-platforms/SKILL.md +90 -0
- package/examples/agents/.claude/skills/code-quality-review/SKILL.md +67 -0
- package/examples/agents/.claude/skills/data-modeling/SKILL.md +99 -0
- package/examples/agents/.claude/skills/developer-experience/SKILL.md +99 -0
- package/examples/agents/.claude/skills/devops-cicd/SKILL.md +96 -0
- package/examples/agents/.claude/skills/full-stack-development/SKILL.md +90 -0
- package/examples/agents/.claude/skills/knowledge-management/SKILL.md +100 -0
- package/examples/agents/.claude/skills/pattern-generalization/SKILL.md +102 -0
- package/examples/agents/.claude/skills/sre-practices/SKILL.md +117 -0
- package/examples/agents/.claude/skills/technical-debt-management/SKILL.md +123 -0
- package/examples/agents/.claude/skills/technical-writing/SKILL.md +129 -0
- package/examples/agents/.github/agents/se-platform-code.agent.md +181 -0
- package/examples/agents/.github/agents/se-platform-plan.agent.md +178 -0
- package/examples/agents/.github/agents/se-platform-review.agent.md +113 -0
- package/examples/agents/.vscode/settings.json +8 -0
- package/examples/behaviours/_index.yaml +8 -0
- package/examples/behaviours/outcome_ownership.yaml +44 -0
- package/examples/behaviours/polymathic_knowledge.yaml +42 -0
- package/examples/behaviours/precise_communication.yaml +40 -0
- package/examples/behaviours/relentless_curiosity.yaml +38 -0
- package/examples/behaviours/systems_thinking.yaml +41 -0
- package/examples/capabilities/_index.yaml +8 -0
- package/examples/capabilities/business.yaml +251 -0
- package/examples/capabilities/delivery.yaml +352 -0
- package/examples/capabilities/people.yaml +100 -0
- package/examples/capabilities/reliability.yaml +318 -0
- package/examples/capabilities/scale.yaml +394 -0
- package/examples/disciplines/_index.yaml +5 -0
- package/examples/disciplines/data_engineering.yaml +76 -0
- package/examples/disciplines/software_engineering.yaml +76 -0
- package/examples/drivers.yaml +205 -0
- package/examples/framework.yaml +58 -0
- package/examples/grades.yaml +118 -0
- package/examples/questions/behaviours/outcome_ownership.yaml +52 -0
- package/examples/questions/behaviours/polymathic_knowledge.yaml +48 -0
- package/examples/questions/behaviours/precise_communication.yaml +55 -0
- package/examples/questions/behaviours/relentless_curiosity.yaml +51 -0
- package/examples/questions/behaviours/systems_thinking.yaml +53 -0
- package/examples/questions/skills/architecture_design.yaml +54 -0
- package/examples/questions/skills/cloud_platforms.yaml +48 -0
- package/examples/questions/skills/code_quality.yaml +49 -0
- package/examples/questions/skills/data_modeling.yaml +46 -0
- package/examples/questions/skills/devops.yaml +47 -0
- package/examples/questions/skills/full_stack_development.yaml +48 -0
- package/examples/questions/skills/sre_practices.yaml +44 -0
- package/examples/questions/skills/stakeholder_management.yaml +49 -0
- package/examples/questions/skills/team_collaboration.yaml +43 -0
- package/examples/questions/skills/technical_writing.yaml +43 -0
- package/examples/self-assessments.yaml +66 -0
- package/examples/stages.yaml +76 -0
- package/examples/tracks/_index.yaml +6 -0
- package/examples/tracks/manager.yaml +53 -0
- package/examples/tracks/platform.yaml +54 -0
- package/examples/tracks/sre.yaml +58 -0
- package/examples/vscode-settings.yaml +22 -0
- package/package.json +68 -0
|
@@ -0,0 +1,158 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,266 @@
|
|
|
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
|
+
|
|
15
|
+
import { SKILL_LEVEL_ORDER, BEHAVIOUR_MATURITY_ORDER } from "./levels.js";
|
|
16
|
+
import {
|
|
17
|
+
deriveSkillMatrix,
|
|
18
|
+
deriveBehaviourProfile,
|
|
19
|
+
deriveResponsibilities,
|
|
20
|
+
} from "./derivation.js";
|
|
21
|
+
|
|
22
|
+
// =============================================================================
|
|
23
|
+
// Skill Filters
|
|
24
|
+
// =============================================================================
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Build set of capabilities with positive track modifiers
|
|
28
|
+
* @param {Object} track - Track definition
|
|
29
|
+
* @returns {Set<string>} Set of capability IDs with positive modifiers
|
|
30
|
+
*/
|
|
31
|
+
export function getPositiveTrackCapabilities(track) {
|
|
32
|
+
return new Set(
|
|
33
|
+
Object.entries(track.skillModifiers || {})
|
|
34
|
+
.filter(([_, modifier]) => modifier > 0)
|
|
35
|
+
.map(([capability]) => capability),
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Filter out human-only skills
|
|
41
|
+
* Human-only skills are those requiring human presence/experience
|
|
42
|
+
* @param {Array} skillMatrix - Skill matrix entries
|
|
43
|
+
* @returns {Array} Filtered skill matrix
|
|
44
|
+
*/
|
|
45
|
+
export function filterHumanOnlySkills(skillMatrix) {
|
|
46
|
+
return skillMatrix.filter((entry) => !entry.isHumanOnly);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Filter broad skills without positive track modifier
|
|
51
|
+
* Keeps broad skills only if their capability has a positive track modifier
|
|
52
|
+
* @param {Array} skillMatrix - Skill matrix entries
|
|
53
|
+
* @param {Set<string>} positiveCapabilities - Capabilities with positive modifiers
|
|
54
|
+
* @returns {Array} Filtered skill matrix
|
|
55
|
+
*/
|
|
56
|
+
export function filterBroadWithoutPositiveModifier(
|
|
57
|
+
skillMatrix,
|
|
58
|
+
positiveCapabilities,
|
|
59
|
+
) {
|
|
60
|
+
return skillMatrix.filter(
|
|
61
|
+
(entry) =>
|
|
62
|
+
entry.type !== "broad" || positiveCapabilities.has(entry.capability),
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Apply agent-specific skill filters
|
|
68
|
+
* Combines humanOnly and broad skill filtering for agent profiles
|
|
69
|
+
* @param {Array} skillMatrix - Skill matrix entries
|
|
70
|
+
* @param {Object} track - Track definition (for modifier lookup)
|
|
71
|
+
* @returns {Array} Filtered skill matrix
|
|
72
|
+
*/
|
|
73
|
+
export function filterSkillsForAgent(skillMatrix, track) {
|
|
74
|
+
const positiveCapabilities = getPositiveTrackCapabilities(track);
|
|
75
|
+
|
|
76
|
+
return skillMatrix.filter((entry) => {
|
|
77
|
+
// Exclude human-only skills
|
|
78
|
+
if (entry.isHumanOnly) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
// For broad skills, only include if capability has positive modifier
|
|
82
|
+
if (entry.type === "broad") {
|
|
83
|
+
return positiveCapabilities.has(entry.capability);
|
|
84
|
+
}
|
|
85
|
+
// Include primary, secondary, and track-added skills
|
|
86
|
+
return true;
|
|
87
|
+
});
|
|
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} [excludeBroadWithoutPositiveModifier=false] - Filter broad skills
|
|
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, filter broad without positive modifier, 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
|
+
excludeBroadWithoutPositiveModifier = 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 || excludeBroadWithoutPositiveModifier) {
|
|
190
|
+
const positiveCapabilities = getPositiveTrackCapabilities(track);
|
|
191
|
+
|
|
192
|
+
if (excludeHumanOnly) {
|
|
193
|
+
skillMatrix = filterHumanOnlySkills(skillMatrix);
|
|
194
|
+
}
|
|
195
|
+
if (excludeBroadWithoutPositiveModifier) {
|
|
196
|
+
skillMatrix = filterBroadWithoutPositiveModifier(
|
|
197
|
+
skillMatrix,
|
|
198
|
+
positiveCapabilities,
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Apply sorting
|
|
204
|
+
if (sortByLevel) {
|
|
205
|
+
skillMatrix = sortByLevelDescending(skillMatrix);
|
|
206
|
+
}
|
|
207
|
+
if (sortByMaturity) {
|
|
208
|
+
behaviourProfile = sortByMaturityDescending(behaviourProfile);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Derive responsibilities if capabilities provided
|
|
212
|
+
let derivedResponsibilities = [];
|
|
213
|
+
if (capabilities && capabilities.length > 0) {
|
|
214
|
+
derivedResponsibilities = deriveResponsibilities({
|
|
215
|
+
skillMatrix,
|
|
216
|
+
capabilities,
|
|
217
|
+
track,
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return {
|
|
222
|
+
skillMatrix,
|
|
223
|
+
behaviourProfile,
|
|
224
|
+
derivedResponsibilities,
|
|
225
|
+
discipline,
|
|
226
|
+
track,
|
|
227
|
+
grade,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Preset options for agent profile derivation
|
|
233
|
+
* Excludes human-only skills, excludes broad skills without positive modifiers,
|
|
234
|
+
* and sorts by level/maturity descending
|
|
235
|
+
*/
|
|
236
|
+
export const AGENT_PROFILE_OPTIONS = {
|
|
237
|
+
excludeHumanOnly: true,
|
|
238
|
+
excludeBroadWithoutPositiveModifier: true,
|
|
239
|
+
sortByLevel: true,
|
|
240
|
+
sortByMaturity: true,
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Prepare a profile optimized for agent generation
|
|
245
|
+
* Convenience function that applies AGENT_PROFILE_OPTIONS
|
|
246
|
+
* @param {Object} params - Same as prepareBaseProfile, without options
|
|
247
|
+
* @returns {BaseProfile} The prepared profile
|
|
248
|
+
*/
|
|
249
|
+
export function prepareAgentProfile({
|
|
250
|
+
discipline,
|
|
251
|
+
track,
|
|
252
|
+
grade,
|
|
253
|
+
skills,
|
|
254
|
+
behaviours,
|
|
255
|
+
capabilities,
|
|
256
|
+
}) {
|
|
257
|
+
return prepareBaseProfile({
|
|
258
|
+
discipline,
|
|
259
|
+
track,
|
|
260
|
+
grade,
|
|
261
|
+
skills,
|
|
262
|
+
behaviours,
|
|
263
|
+
capabilities,
|
|
264
|
+
options: AGENT_PROFILE_OPTIONS,
|
|
265
|
+
});
|
|
266
|
+
}
|