@forwardimpact/pathway 0.10.0 → 0.12.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/package.json +3 -3
- package/src/commands/agent.js +2 -2
- package/src/commands/skill.js +2 -2
- package/src/components/comparison-radar.js +7 -5
- package/src/css/components/badges.css +11 -31
- package/src/css/tokens.css +12 -20
- package/src/formatters/agent/profile.js +14 -4
- package/src/formatters/agent/skill.js +13 -4
- package/src/formatters/skill/shared.js +1 -1
- package/src/formatters/template-preprocess.js +60 -0
- package/src/handout.html +3 -1
- package/src/index.html +3 -1
- package/src/lib/job-cache.js +7 -7
- package/src/pages/agent-builder.js +3 -3
- package/src/pages/landing.js +4 -1
- package/src/pages/progress.js +1 -0
- package/src/pages/self-assessment.js +7 -4
- package/src/slides.html +3 -1
- package/templates/skill.template.md +9 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forwardimpact/pathway",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "Career progression web app and CLI for exploring roles and generating agents",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
"./commands": "./src/commands/index.js"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@forwardimpact/schema": "^0.
|
|
44
|
-
"@forwardimpact/model": "^0.
|
|
43
|
+
"@forwardimpact/schema": "^0.5.0",
|
|
44
|
+
"@forwardimpact/model": "^0.6.0",
|
|
45
45
|
"mustache": "^4.2.0",
|
|
46
46
|
"simple-icons": "^16.7.0",
|
|
47
47
|
"yaml": "^2.3.4"
|
package/src/commands/agent.js
CHANGED
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
validateAgentSkill,
|
|
38
38
|
deriveReferenceGrade,
|
|
39
39
|
deriveAgentSkills,
|
|
40
|
-
|
|
40
|
+
generateSkillMarkdown,
|
|
41
41
|
deriveToolkit,
|
|
42
42
|
buildAgentIndex,
|
|
43
43
|
} from "@forwardimpact/model";
|
|
@@ -502,7 +502,7 @@ export async function runAgentCommand({ data, args, options, dataDir }) {
|
|
|
502
502
|
const skillFiles = derivedSkills
|
|
503
503
|
.map((derived) => skillsWithAgent.find((s) => s.id === derived.skillId))
|
|
504
504
|
.filter((skill) => skill?.agent)
|
|
505
|
-
.map((skill) =>
|
|
505
|
+
.map((skill) => generateSkillMarkdown(skill, data.stages));
|
|
506
506
|
|
|
507
507
|
// Validate all profiles
|
|
508
508
|
for (const profile of profiles) {
|
package/src/commands/skill.js
CHANGED
|
@@ -16,7 +16,7 @@ import { skillToMarkdown } from "../formatters/skill/markdown.js";
|
|
|
16
16
|
import { prepareSkillsList } from "../formatters/skill/shared.js";
|
|
17
17
|
import { getConceptEmoji } from "@forwardimpact/schema/levels";
|
|
18
18
|
import { formatTable, formatError } from "../lib/cli-output.js";
|
|
19
|
-
import {
|
|
19
|
+
import { generateSkillMarkdown } from "@forwardimpact/model/agent";
|
|
20
20
|
import { formatAgentSkill } from "../formatters/agent/skill.js";
|
|
21
21
|
import { loadSkillTemplate } from "../lib/template-loader.js";
|
|
22
22
|
|
|
@@ -80,7 +80,7 @@ async function formatAgentDetail(skill, stages, dataDir) {
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
const template = await loadSkillTemplate(dataDir);
|
|
83
|
-
const skillMd =
|
|
83
|
+
const skillMd = generateSkillMarkdown(skill, stages);
|
|
84
84
|
const output = formatAgentSkill(skillMd, template);
|
|
85
85
|
console.log(output);
|
|
86
86
|
}
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
getBehaviourMaturityIndex,
|
|
14
14
|
formatLevel,
|
|
15
15
|
} from "../lib/render.js";
|
|
16
|
-
import {
|
|
16
|
+
import { compareByCapability } from "@forwardimpact/model/policies";
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* Create a comparison skill radar chart
|
|
@@ -24,7 +24,7 @@ import { getCapabilityIndex } from "@forwardimpact/schema/levels";
|
|
|
24
24
|
*/
|
|
25
25
|
export function createComparisonSkillRadar(
|
|
26
26
|
currentMatrix,
|
|
27
|
-
targetMatrix,
|
|
27
|
+
targetMatrix = [],
|
|
28
28
|
options = {},
|
|
29
29
|
) {
|
|
30
30
|
const container = div(
|
|
@@ -80,9 +80,11 @@ export function createComparisonSkillRadar(
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
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);
|
|
83
86
|
skillEntries.sort((a, b) => {
|
|
84
|
-
const capDiff =
|
|
85
|
-
getCapabilityIndex(a.capability) - getCapabilityIndex(b.capability);
|
|
87
|
+
const capDiff = capabilityComparator(a, b);
|
|
86
88
|
if (capDiff !== 0) return capDiff;
|
|
87
89
|
return a.skillName.localeCompare(b.skillName);
|
|
88
90
|
});
|
|
@@ -141,7 +143,7 @@ export function createComparisonSkillRadar(
|
|
|
141
143
|
*/
|
|
142
144
|
export function createComparisonBehaviourRadar(
|
|
143
145
|
currentProfile,
|
|
144
|
-
targetProfile,
|
|
146
|
+
targetProfile = [],
|
|
145
147
|
options = {},
|
|
146
148
|
) {
|
|
147
149
|
const container = div(
|
|
@@ -93,50 +93,30 @@
|
|
|
93
93
|
font-weight: 500;
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
/* Capability badges */
|
|
96
|
+
/* Capability badges - each capability ID maps to its own distinct color */
|
|
97
97
|
.badge-delivery {
|
|
98
|
-
background: var(--color-
|
|
99
|
-
color: var(--color-
|
|
98
|
+
background: var(--color-cap-delivery-light);
|
|
99
|
+
color: var(--color-cap-delivery);
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
.badge-scale {
|
|
103
|
-
background: var(--color-
|
|
104
|
-
color: var(--color-
|
|
103
|
+
background: var(--color-cap-scale-light);
|
|
104
|
+
color: var(--color-cap-scale);
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
.badge-reliability {
|
|
108
|
-
background: var(--color-
|
|
109
|
-
color: var(--color-
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
.badge-data {
|
|
113
|
-
background: var(--color-cat-data-light);
|
|
114
|
-
color: var(--color-cat-data);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
.badge-ai {
|
|
118
|
-
background: var(--color-cat-ai-light);
|
|
119
|
-
color: var(--color-cat-ai);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
.badge-process {
|
|
123
|
-
background: var(--color-cat-process-light);
|
|
124
|
-
color: var(--color-cat-process);
|
|
108
|
+
background: var(--color-cap-reliability-light);
|
|
109
|
+
color: var(--color-cap-reliability);
|
|
125
110
|
}
|
|
126
111
|
|
|
127
112
|
.badge-business {
|
|
128
|
-
background: var(--color-
|
|
129
|
-
color: var(--color-
|
|
113
|
+
background: var(--color-cap-business-light);
|
|
114
|
+
color: var(--color-cap-business);
|
|
130
115
|
}
|
|
131
116
|
|
|
132
117
|
.badge-people {
|
|
133
|
-
background: var(--color-
|
|
134
|
-
color: var(--color-
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
.badge-documentation {
|
|
138
|
-
background: var(--color-cat-documentation-light);
|
|
139
|
-
color: var(--color-cat-documentation);
|
|
118
|
+
background: var(--color-cap-people-light);
|
|
119
|
+
color: var(--color-cap-people);
|
|
140
120
|
}
|
|
141
121
|
|
|
142
122
|
/* Tool badge */
|
package/src/css/tokens.css
CHANGED
|
@@ -43,30 +43,22 @@
|
|
|
43
43
|
--color-maturity-5: #c4b5fd;
|
|
44
44
|
|
|
45
45
|
/* --------------------------------------------------------------------------
|
|
46
|
-
Colors -
|
|
46
|
+
Colors - Capabilities (text)
|
|
47
47
|
-------------------------------------------------------------------------- */
|
|
48
|
-
--color-
|
|
49
|
-
--color-
|
|
50
|
-
--color-
|
|
51
|
-
--color-
|
|
52
|
-
--color-
|
|
53
|
-
--color-cat-process: #c2410c; /* orange */
|
|
54
|
-
--color-cat-business: #a16207; /* amber */
|
|
55
|
-
--color-cat-people: #be185d; /* pink */
|
|
56
|
-
--color-cat-documentation: #15803d; /* green */
|
|
48
|
+
--color-cap-delivery: #dc2626; /* red - speed and efficiency */
|
|
49
|
+
--color-cap-scale: #1d4ed8; /* blue - infrastructure and systems */
|
|
50
|
+
--color-cap-reliability: #0891b2; /* cyan - stability and operations */
|
|
51
|
+
--color-cap-business: #b45309; /* amber - strategy and outcomes */
|
|
52
|
+
--color-cap-people: #be185d; /* pink - collaboration and leadership */
|
|
57
53
|
|
|
58
54
|
/* --------------------------------------------------------------------------
|
|
59
|
-
Colors -
|
|
55
|
+
Colors - Capabilities (backgrounds)
|
|
60
56
|
-------------------------------------------------------------------------- */
|
|
61
|
-
--color-
|
|
62
|
-
--color-
|
|
63
|
-
--color-
|
|
64
|
-
--color-
|
|
65
|
-
--color-
|
|
66
|
-
--color-cat-process-light: #ffedd5; /* orange */
|
|
67
|
-
--color-cat-business-light: #fef3c7; /* amber */
|
|
68
|
-
--color-cat-people-light: #fce7f3; /* pink */
|
|
69
|
-
--color-cat-documentation-light: #dcfce7; /* green */
|
|
57
|
+
--color-cap-delivery-light: #fecaca; /* red */
|
|
58
|
+
--color-cap-scale-light: #dbeafe; /* blue */
|
|
59
|
+
--color-cap-reliability-light: #cffafe; /* cyan */
|
|
60
|
+
--color-cap-business-light: #fef3c7; /* amber */
|
|
61
|
+
--color-cap-people-light: #fce7f3; /* pink */
|
|
70
62
|
|
|
71
63
|
/* --------------------------------------------------------------------------
|
|
72
64
|
Colors - Neutrals
|
|
@@ -11,6 +11,10 @@
|
|
|
11
11
|
import Mustache from "mustache";
|
|
12
12
|
|
|
13
13
|
import { trimValue, trimRequired, trimFields } from "../shared.js";
|
|
14
|
+
import {
|
|
15
|
+
flattenToLine,
|
|
16
|
+
preprocessArrayFrontmatter,
|
|
17
|
+
} from "../template-preprocess.js";
|
|
14
18
|
|
|
15
19
|
/**
|
|
16
20
|
* @typedef {Object} WorkingStyleEntry
|
|
@@ -49,8 +53,14 @@ import { trimValue, trimRequired, trimFields } from "../shared.js";
|
|
|
49
53
|
* @returns {Object} Data object ready for Mustache template
|
|
50
54
|
*/
|
|
51
55
|
function prepareAgentProfileData({ frontmatter, bodyData }) {
|
|
52
|
-
//
|
|
53
|
-
const
|
|
56
|
+
// Preprocess handoffs - flatten prompt field for front matter compatibility
|
|
57
|
+
const preprocessedHandoffs = preprocessArrayFrontmatter(
|
|
58
|
+
frontmatter.handoffs,
|
|
59
|
+
["prompt"],
|
|
60
|
+
);
|
|
61
|
+
// Then trim as before
|
|
62
|
+
const handoffs = trimFields(preprocessedHandoffs, { prompt: "required" });
|
|
63
|
+
|
|
54
64
|
const constraints = (bodyData.constraints || []).map((c) => trimRequired(c));
|
|
55
65
|
const skillIndex = trimFields(bodyData.skillIndex, {
|
|
56
66
|
name: "required",
|
|
@@ -75,9 +85,9 @@ function prepareAgentProfileData({ frontmatter, bodyData }) {
|
|
|
75
85
|
}));
|
|
76
86
|
|
|
77
87
|
return {
|
|
78
|
-
// Frontmatter
|
|
88
|
+
// Frontmatter - flatten description for single-line front matter
|
|
79
89
|
name: frontmatter.name,
|
|
80
|
-
description:
|
|
90
|
+
description: flattenToLine(frontmatter.description),
|
|
81
91
|
infer: frontmatter.infer,
|
|
82
92
|
handoffs,
|
|
83
93
|
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
import Mustache from "mustache";
|
|
12
12
|
|
|
13
13
|
import { trimValue, splitLines, trimFields } from "../shared.js";
|
|
14
|
+
import { flattenToLine } from "../template-preprocess.js";
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Prepare agent skill data for template rendering
|
|
@@ -40,17 +41,25 @@ function prepareAgentSkillData({
|
|
|
40
41
|
ready: "array",
|
|
41
42
|
});
|
|
42
43
|
|
|
44
|
+
// Flatten multi-line strings to single line for front matter compatibility
|
|
45
|
+
const description = flattenToLine(frontmatter.description);
|
|
46
|
+
const useWhen = flattenToLine(frontmatter.useWhen);
|
|
47
|
+
|
|
48
|
+
// Keep line arrays for body rendering
|
|
43
49
|
const descriptionLines = splitLines(frontmatter.description);
|
|
44
|
-
|
|
50
|
+
|
|
45
51
|
const trimmedReference = trimValue(reference) || "";
|
|
46
52
|
const tools = toolReferences || [];
|
|
47
53
|
|
|
48
54
|
return {
|
|
49
55
|
name: frontmatter.name,
|
|
56
|
+
// Single-line versions for front matter
|
|
57
|
+
description,
|
|
58
|
+
hasDescription: !!description,
|
|
59
|
+
useWhen,
|
|
60
|
+
hasUseWhen: !!useWhen,
|
|
61
|
+
// Line arrays for body content
|
|
50
62
|
descriptionLines,
|
|
51
|
-
hasDescription: descriptionLines.length > 0,
|
|
52
|
-
useWhenLines,
|
|
53
|
-
hasUseWhen: useWhenLines.length > 0,
|
|
54
63
|
title,
|
|
55
64
|
stages: processedStages,
|
|
56
65
|
hasStages: processedStages.length > 0,
|
|
@@ -43,7 +43,7 @@ export function prepareSkillsList(
|
|
|
43
43
|
capabilities,
|
|
44
44
|
descriptionLimit = 120,
|
|
45
45
|
) {
|
|
46
|
-
const grouped = groupSkillsByCapability(skills);
|
|
46
|
+
const grouped = groupSkillsByCapability(skills, capabilities);
|
|
47
47
|
|
|
48
48
|
const groups = {};
|
|
49
49
|
for (const [capability, capabilitySkills] of Object.entries(grouped)) {
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template Preprocessing Utilities
|
|
3
|
+
*
|
|
4
|
+
* Functions to prepare template data for front matter compatibility.
|
|
5
|
+
* Ensures all front matter values are single-line strings for maximum
|
|
6
|
+
* compatibility with coding agents that have limited YAML parsing.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Flatten a multi-line string into a single line
|
|
11
|
+
* Replaces newlines with spaces and collapses multiple spaces.
|
|
12
|
+
* @param {string|null|undefined} value - Value to flatten
|
|
13
|
+
* @returns {string} Single-line string (empty string if no value)
|
|
14
|
+
*/
|
|
15
|
+
export function flattenToLine(value) {
|
|
16
|
+
if (value == null) return "";
|
|
17
|
+
return value
|
|
18
|
+
.replace(/\s*\n\s*/g, " ") // Replace newlines (with surrounding whitespace) with single space
|
|
19
|
+
.replace(/\s+/g, " ") // Collapse multiple spaces
|
|
20
|
+
.trim();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Join an array of strings into a single line
|
|
25
|
+
* @param {string[]|null|undefined} lines - Array of lines to join
|
|
26
|
+
* @param {string} separator - Separator between lines (default: single space)
|
|
27
|
+
* @returns {string} Single-line string
|
|
28
|
+
*/
|
|
29
|
+
export function joinLines(lines, separator = " ") {
|
|
30
|
+
if (!lines || !Array.isArray(lines)) return "";
|
|
31
|
+
return lines.map((line) => line.trim()).join(separator);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Preprocess an object's string fields for front matter
|
|
36
|
+
* Flattens specified fields to single-line strings.
|
|
37
|
+
* @param {Object} obj - Object to preprocess
|
|
38
|
+
* @param {string[]} fields - Field names to flatten
|
|
39
|
+
* @returns {Object} New object with flattened fields
|
|
40
|
+
*/
|
|
41
|
+
export function preprocessFrontmatter(obj, fields) {
|
|
42
|
+
const result = { ...obj };
|
|
43
|
+
for (const field of fields) {
|
|
44
|
+
if (result[field] != null) {
|
|
45
|
+
result[field] = flattenToLine(result[field]);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Preprocess an array of objects, flattening specified fields in each
|
|
53
|
+
* @param {Array<Object>|null|undefined} array - Array to preprocess
|
|
54
|
+
* @param {string[]} fields - Field names to flatten in each object
|
|
55
|
+
* @returns {Array<Object>} Array with preprocessed objects
|
|
56
|
+
*/
|
|
57
|
+
export function preprocessArrayFrontmatter(array, fields) {
|
|
58
|
+
if (!array) return [];
|
|
59
|
+
return array.map((item) => preprocessFrontmatter(item, fields));
|
|
60
|
+
}
|
package/src/handout.html
CHANGED
|
@@ -23,7 +23,9 @@
|
|
|
23
23
|
"@forwardimpact/model/checklist": "/model/lib/checklist.js",
|
|
24
24
|
"@forwardimpact/model/matching": "/model/lib/matching.js",
|
|
25
25
|
"@forwardimpact/model/profile": "/model/lib/profile.js",
|
|
26
|
-
"@forwardimpact/model/progression": "/model/lib/progression.js"
|
|
26
|
+
"@forwardimpact/model/progression": "/model/lib/progression.js",
|
|
27
|
+
"@forwardimpact/model/policies": "/model/lib/policies/index.js",
|
|
28
|
+
"@forwardimpact/model/toolkit": "/model/lib/toolkit.js"
|
|
27
29
|
}
|
|
28
30
|
}
|
|
29
31
|
</script>
|
package/src/index.html
CHANGED
|
@@ -35,7 +35,9 @@
|
|
|
35
35
|
"@forwardimpact/model/checklist": "/model/lib/checklist.js",
|
|
36
36
|
"@forwardimpact/model/matching": "/model/lib/matching.js",
|
|
37
37
|
"@forwardimpact/model/profile": "/model/lib/profile.js",
|
|
38
|
-
"@forwardimpact/model/progression": "/model/lib/progression.js"
|
|
38
|
+
"@forwardimpact/model/progression": "/model/lib/progression.js",
|
|
39
|
+
"@forwardimpact/model/policies": "/model/lib/policies/index.js",
|
|
40
|
+
"@forwardimpact/model/toolkit": "/model/lib/toolkit.js"
|
|
39
41
|
}
|
|
40
42
|
}
|
|
41
43
|
</script>
|
package/src/lib/job-cache.js
CHANGED
|
@@ -11,13 +11,13 @@ import { deriveJob } from "@forwardimpact/model/derivation";
|
|
|
11
11
|
const cache = new Map();
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
*
|
|
14
|
+
* Build a consistent cache key from job parameters
|
|
15
15
|
* @param {string} disciplineId
|
|
16
16
|
* @param {string} gradeId
|
|
17
17
|
* @param {string} [trackId] - Optional track ID
|
|
18
18
|
* @returns {string}
|
|
19
19
|
*/
|
|
20
|
-
export function
|
|
20
|
+
export function buildJobKey(disciplineId, gradeId, trackId = null) {
|
|
21
21
|
if (trackId) {
|
|
22
22
|
return `${disciplineId}_${gradeId}_${trackId}`;
|
|
23
23
|
}
|
|
@@ -43,7 +43,7 @@ export function getOrCreateJob({
|
|
|
43
43
|
behaviours,
|
|
44
44
|
capabilities,
|
|
45
45
|
}) {
|
|
46
|
-
const key =
|
|
46
|
+
const key = buildJobKey(discipline.id, grade.id, track?.id);
|
|
47
47
|
|
|
48
48
|
if (!cache.has(key)) {
|
|
49
49
|
const job = deriveJob({
|
|
@@ -66,7 +66,7 @@ export function getOrCreateJob({
|
|
|
66
66
|
/**
|
|
67
67
|
* Clear all cached jobs
|
|
68
68
|
*/
|
|
69
|
-
export function
|
|
69
|
+
export function clearCache() {
|
|
70
70
|
cache.clear();
|
|
71
71
|
}
|
|
72
72
|
|
|
@@ -76,14 +76,14 @@ export function clearJobCache() {
|
|
|
76
76
|
* @param {string} gradeId
|
|
77
77
|
* @param {string} [trackId] - Optional track ID
|
|
78
78
|
*/
|
|
79
|
-
export function
|
|
80
|
-
cache.delete(
|
|
79
|
+
export function invalidateCachedJob(disciplineId, gradeId, trackId = null) {
|
|
80
|
+
cache.delete(buildJobKey(disciplineId, gradeId, trackId));
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
/**
|
|
84
84
|
* Get the number of cached jobs (for testing/debugging)
|
|
85
85
|
* @returns {number}
|
|
86
86
|
*/
|
|
87
|
-
export function
|
|
87
|
+
export function getCachedJobCount() {
|
|
88
88
|
return cache.size;
|
|
89
89
|
}
|
|
@@ -24,7 +24,7 @@ import { loadAgentDataBrowser } from "../lib/yaml-loader.js";
|
|
|
24
24
|
import {
|
|
25
25
|
generateStageAgentProfile,
|
|
26
26
|
deriveStageAgent,
|
|
27
|
-
|
|
27
|
+
generateSkillMarkdown,
|
|
28
28
|
deriveAgentSkills,
|
|
29
29
|
deriveReferenceGrade,
|
|
30
30
|
deriveToolkit,
|
|
@@ -502,7 +502,7 @@ function createAllStagesPreview(context) {
|
|
|
502
502
|
const skillFiles = derivedSkills
|
|
503
503
|
.map((derived) => skills.find((s) => s.id === derived.skillId))
|
|
504
504
|
.filter((skill) => skill?.agent)
|
|
505
|
-
.map((skill) =>
|
|
505
|
+
.map((skill) => generateSkillMarkdown(skill, stages));
|
|
506
506
|
|
|
507
507
|
// Derive toolkit from agent skills
|
|
508
508
|
const toolkit = deriveToolkit({
|
|
@@ -633,7 +633,7 @@ function createSingleStagePreview(context, stage) {
|
|
|
633
633
|
const skillFiles = derivedSkills
|
|
634
634
|
.map((d) => skills.find((s) => s.id === d.skillId))
|
|
635
635
|
.filter((skill) => skill?.agent)
|
|
636
|
-
.map((skill) =>
|
|
636
|
+
.map((skill) => generateSkillMarkdown(skill, stages));
|
|
637
637
|
|
|
638
638
|
// Derive toolkit from agent skills
|
|
639
639
|
const toolkit = deriveToolkit({
|
package/src/pages/landing.js
CHANGED
|
@@ -45,7 +45,10 @@ export function renderLanding() {
|
|
|
45
45
|
const stages = data.stages || [];
|
|
46
46
|
|
|
47
47
|
// Calculate stats using centralized capability ordering
|
|
48
|
-
const skillsByCapability = groupSkillsByCapability(
|
|
48
|
+
const skillsByCapability = groupSkillsByCapability(
|
|
49
|
+
data.skills,
|
|
50
|
+
data.capabilities,
|
|
51
|
+
);
|
|
49
52
|
const capabilityCount = Object.keys(skillsByCapability).length;
|
|
50
53
|
const tools = aggregateTools(data.skills);
|
|
51
54
|
|
package/src/pages/progress.js
CHANGED
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
SKILL_LEVEL_ORDER,
|
|
23
23
|
BEHAVIOUR_MATURITY_ORDER,
|
|
24
24
|
groupSkillsByCapability,
|
|
25
|
-
|
|
25
|
+
getCapabilityOrder,
|
|
26
26
|
getCapabilityEmoji,
|
|
27
27
|
getConceptEmoji,
|
|
28
28
|
} from "@forwardimpact/schema/levels";
|
|
@@ -66,7 +66,10 @@ export function getAssessmentState() {
|
|
|
66
66
|
*/
|
|
67
67
|
function getWizardSteps(data) {
|
|
68
68
|
const { framework } = data;
|
|
69
|
-
const skillsByCapability = groupSkillsByCapability(
|
|
69
|
+
const skillsByCapability = groupSkillsByCapability(
|
|
70
|
+
data.skills,
|
|
71
|
+
data.capabilities,
|
|
72
|
+
);
|
|
70
73
|
const steps = [
|
|
71
74
|
{
|
|
72
75
|
id: "intro",
|
|
@@ -77,7 +80,7 @@ function getWizardSteps(data) {
|
|
|
77
80
|
];
|
|
78
81
|
|
|
79
82
|
// Add a step for each non-empty skill capability
|
|
80
|
-
for (const capability of
|
|
83
|
+
for (const capability of getCapabilityOrder(data.capabilities)) {
|
|
81
84
|
const skills = skillsByCapability[capability];
|
|
82
85
|
if (skills && skills.length > 0) {
|
|
83
86
|
steps.push({
|
|
@@ -277,7 +280,7 @@ function renderIntroStep(data) {
|
|
|
277
280
|
div(
|
|
278
281
|
{},
|
|
279
282
|
h4({}, `${data.skills.length} Skills`),
|
|
280
|
-
p({}, "Across " +
|
|
283
|
+
p({}, "Across " + data.capabilities.length + " capabilities"),
|
|
281
284
|
),
|
|
282
285
|
),
|
|
283
286
|
div(
|
package/src/slides.html
CHANGED
|
@@ -23,7 +23,9 @@
|
|
|
23
23
|
"@forwardimpact/model/checklist": "/model/lib/checklist.js",
|
|
24
24
|
"@forwardimpact/model/matching": "/model/lib/matching.js",
|
|
25
25
|
"@forwardimpact/model/profile": "/model/lib/profile.js",
|
|
26
|
-
"@forwardimpact/model/progression": "/model/lib/progression.js"
|
|
26
|
+
"@forwardimpact/model/progression": "/model/lib/progression.js",
|
|
27
|
+
"@forwardimpact/model/policies": "/model/lib/policies/index.js",
|
|
28
|
+
"@forwardimpact/model/toolkit": "/model/lib/toolkit.js"
|
|
27
29
|
}
|
|
28
30
|
}
|
|
29
31
|
</script>
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: {{name}}
|
|
3
|
-
description:
|
|
4
|
-
{{#descriptionLines}}{{{.}}} {{/descriptionLines}}
|
|
5
|
-
{{#hasUseWhen}}
|
|
6
|
-
Use When: {{#useWhenLines}}{{{.}}} {{/useWhenLines}}
|
|
7
|
-
{{/hasUseWhen}}
|
|
3
|
+
description: {{{description}}}{{#hasUseWhen}} Use When: {{{useWhen}}}{{/hasUseWhen}}
|
|
8
4
|
---
|
|
9
5
|
|
|
10
6
|
# {{{title}}}
|
|
@@ -34,10 +30,15 @@ description: |
|
|
|
34
30
|
{{/hasStages}}
|
|
35
31
|
{{#hasToolReferences}}
|
|
36
32
|
|
|
37
|
-
|
|
33
|
+
## Required Tools
|
|
38
34
|
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
**MANDATORY:** You MUST use these tools when applying this skill. These are
|
|
36
|
+
organizational standards that override general knowledge or personal preferences.
|
|
37
|
+
|
|
38
|
+
If a blocking constraint prevents use of a required tool, document in your
|
|
39
|
+
output: (1) which tool requirement you cannot meet, (2) the specific constraint
|
|
40
|
+
preventing compliance, and (3) the alternative approach with acknowledged
|
|
41
|
+
trade-offs.
|
|
41
42
|
|
|
42
43
|
| Tool | Use When |
|
|
43
44
|
| ---- | -------- |
|