@forwardimpact/pathway 0.19.0 → 0.21.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 (47) hide show
  1. package/bin/fit-pathway.js +6 -6
  2. package/package.json +3 -3
  3. package/src/commands/agent.js +1 -1
  4. package/src/commands/build.js +7 -7
  5. package/src/commands/dev.js +7 -7
  6. package/src/commands/driver.js +1 -1
  7. package/src/commands/grade.js +1 -1
  8. package/src/commands/skill.js +1 -1
  9. package/src/commands/track.js +1 -1
  10. package/src/commands/update.js +12 -14
  11. package/src/components/checklist.js +1 -1
  12. package/src/components/detail.js +1 -1
  13. package/src/components/skill-matrix.js +1 -1
  14. package/src/formatters/behaviour/dom.js +1 -1
  15. package/src/formatters/discipline/dom.js +1 -1
  16. package/src/formatters/driver/dom.js +1 -1
  17. package/src/formatters/grade/dom.js +1 -1
  18. package/src/formatters/grade/markdown.js +1 -1
  19. package/src/formatters/interview/dom.js +1 -1
  20. package/src/formatters/interview/markdown.js +1 -1
  21. package/src/formatters/job/description.js +42 -47
  22. package/src/formatters/job/markdown.js +1 -1
  23. package/src/formatters/skill/dom.js +1 -1
  24. package/src/formatters/skill/markdown.js +1 -1
  25. package/src/formatters/skill/shared.js +1 -1
  26. package/src/formatters/track/dom.js +1 -1
  27. package/src/formatters/track/markdown.js +1 -1
  28. package/src/handout-main.js +1 -4
  29. package/src/handout.html +4 -4
  30. package/src/index.html +4 -4
  31. package/src/lib/card-mappers.js +1 -1
  32. package/src/lib/render.js +1 -1
  33. package/src/pages/behaviour.js +1 -1
  34. package/src/pages/discipline.js +1 -1
  35. package/src/pages/driver.js +1 -1
  36. package/src/pages/grade.js +1 -1
  37. package/src/pages/interview.js +1 -1
  38. package/src/pages/landing.js +1 -1
  39. package/src/pages/self-assessment.js +1 -1
  40. package/src/pages/skill.js +1 -4
  41. package/src/pages/stage.js +1 -1
  42. package/src/pages/tool.js +1 -1
  43. package/src/pages/track.js +1 -1
  44. package/src/slides/index.js +1 -1
  45. package/src/slides.html +4 -4
  46. package/templates/install.template.sh +11 -8
  47. package/templates/job.template.md +9 -13
@@ -32,7 +32,7 @@
32
32
  import { join, resolve } from "path";
33
33
  import { existsSync } from "fs";
34
34
  import { homedir } from "os";
35
- import { loadAllData } from "@forwardimpact/schema/loader";
35
+ import { loadAllData } from "@forwardimpact/map/loader";
36
36
  import { formatError } from "../src/lib/cli-output.js";
37
37
 
38
38
  // Import command handlers
@@ -341,7 +341,7 @@ function printHelp() {
341
341
  * 3. ~/.fit/pathway/data/ (home directory install)
342
342
  * 4. ./data/ relative to current working directory
343
343
  * 5. ./examples/ relative to current working directory
344
- * 6. apps/schema/examples/ for monorepo development
344
+ * 6. products/map/examples/ for monorepo development
345
345
  *
346
346
  * @param {Object} options - Parsed command options
347
347
  * @returns {string} Resolved absolute path to data directory
@@ -375,10 +375,10 @@ function resolveDataPath(options) {
375
375
  return cwdExamples;
376
376
  }
377
377
 
378
- // 6. Monorepo: apps/schema/examples/
379
- const schemaExamples = join(process.cwd(), "apps/schema/examples");
380
- if (existsSync(schemaExamples)) {
381
- return schemaExamples;
378
+ // 6. Monorepo: products/map/examples/
379
+ const mapExamples = join(process.cwd(), "products/map/examples");
380
+ if (existsSync(mapExamples)) {
381
+ return mapExamples;
382
382
  }
383
383
 
384
384
  throw new Error(
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@forwardimpact/pathway",
3
- "version": "0.19.0",
3
+ "version": "0.21.0",
4
4
  "description": "Career progression web app and CLI for exploring roles and generating agent teams",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "https://github.com/forwardimpact/monorepo",
9
- "directory": "apps/pathway"
9
+ "directory": "products/pathway"
10
10
  },
11
11
  "homepage": "https://www.forwardimpact.team/pathway",
12
12
  "keywords": [
@@ -40,7 +40,7 @@
40
40
  "./commands": "./src/commands/index.js"
41
41
  },
42
42
  "dependencies": {
43
- "@forwardimpact/schema": "^0.10.0",
43
+ "@forwardimpact/map": "^0.10.0",
44
44
  "@forwardimpact/libpathway": "^2.0.0",
45
45
  "mustache": "^4.2.0",
46
46
  "simple-icons": "^16.7.0",
@@ -30,7 +30,7 @@ import { stringify as stringifyYaml } from "yaml";
30
30
  import {
31
31
  loadAgentData,
32
32
  loadSkillsWithAgentData,
33
- } from "@forwardimpact/schema/loader";
33
+ } from "@forwardimpact/map/loader";
34
34
  import {
35
35
  generateStageAgentProfile,
36
36
  validateAgentProfile,
@@ -21,8 +21,8 @@ import { join, dirname, relative, resolve } from "path";
21
21
  import { fileURLToPath } from "url";
22
22
  import { execFileSync } from "child_process";
23
23
  import Mustache from "mustache";
24
- import { generateAllIndexes } from "@forwardimpact/schema/index-generator";
25
- import { loadFrameworkConfig } from "@forwardimpact/schema/loader";
24
+ import { generateAllIndexes } from "@forwardimpact/map/index-generator";
25
+ import { loadFrameworkConfig } from "@forwardimpact/map/loader";
26
26
 
27
27
  const __filename = fileURLToPath(import.meta.url);
28
28
  const __dirname = dirname(__filename);
@@ -31,7 +31,7 @@ const appDir = join(__dirname, "..");
31
31
  /**
32
32
  * Resolve package directory using Node's module resolution.
33
33
  * Works in both monorepo (development) and installed (production) contexts.
34
- * @param {string} packageName - Package specifier (e.g., '@forwardimpact/schema')
34
+ * @param {string} packageName - Package specifier (e.g., '@forwardimpact/map')
35
35
  * @returns {string} Absolute path to package lib directory
36
36
  */
37
37
  function resolvePackageLib(packageName) {
@@ -41,7 +41,7 @@ function resolvePackageLib(packageName) {
41
41
  return dirname(fileURLToPath(mainUrl));
42
42
  }
43
43
 
44
- const schemaLibDir = resolvePackageLib("@forwardimpact/schema");
44
+ const mapLibDir = resolvePackageLib("@forwardimpact/map");
45
45
  const modelLibDir = resolvePackageLib("@forwardimpact/libpathway");
46
46
 
47
47
  /**
@@ -141,11 +141,11 @@ ${framework.emojiIcon} Generating ${framework.title} static site...
141
141
  }
142
142
  }
143
143
 
144
- // Copy @forwardimpact/schema and @forwardimpact/libpathway packages
144
+ // Copy @forwardimpact/map and @forwardimpact/libpathway packages
145
145
  // These are needed by the browser's import map
146
146
  console.log("📚 Copying package dependencies...");
147
- await cp(schemaLibDir, join(outputDir, "schema/lib"), { recursive: true });
148
- console.log(` ✓ schema/lib`);
147
+ await cp(mapLibDir, join(outputDir, "map/lib"), { recursive: true });
148
+ console.log(` ✓ map/lib`);
149
149
  await cp(modelLibDir, join(outputDir, "model/lib"), { recursive: true });
150
150
  console.log(` ✓ model/lib`);
151
151
 
@@ -9,8 +9,8 @@ import { createServer } from "http";
9
9
  import { readFile, stat } from "fs/promises";
10
10
  import { join, extname, dirname } from "path";
11
11
  import { fileURLToPath } from "url";
12
- import { generateAllIndexes } from "@forwardimpact/schema/index-generator";
13
- import { loadFrameworkConfig } from "@forwardimpact/schema/loader";
12
+ import { generateAllIndexes } from "@forwardimpact/map/index-generator";
13
+ import { loadFrameworkConfig } from "@forwardimpact/map/loader";
14
14
 
15
15
  const __filename = fileURLToPath(import.meta.url);
16
16
  const __dirname = dirname(__filename);
@@ -20,7 +20,7 @@ const rootDir = join(__dirname, "../..");
20
20
  /**
21
21
  * Resolve package directory using Node's module resolution.
22
22
  * Works in both monorepo (development) and installed (production) contexts.
23
- * @param {string} packageName - Package specifier (e.g., '@forwardimpact/schema')
23
+ * @param {string} packageName - Package specifier (e.g., '@forwardimpact/map')
24
24
  * @returns {string} Absolute path to package lib directory
25
25
  */
26
26
  function resolvePackageLib(packageName) {
@@ -30,7 +30,7 @@ function resolvePackageLib(packageName) {
30
30
  return dirname(fileURLToPath(mainUrl));
31
31
  }
32
32
 
33
- const schemaLibDir = resolvePackageLib("@forwardimpact/schema");
33
+ const mapLibDir = resolvePackageLib("@forwardimpact/map");
34
34
  const modelLibDir = resolvePackageLib("@forwardimpact/libpathway");
35
35
 
36
36
  const MIME_TYPES = {
@@ -134,9 +134,9 @@ export async function runDevCommand({ dataDir, options }) {
134
134
  } else if (pathname.startsWith("/templates/")) {
135
135
  // Serve from templates directory
136
136
  filePath = join(rootDir, pathname);
137
- } else if (pathname.startsWith("/schema/lib/")) {
138
- // Serve @forwardimpact/schema package files (resolved via Node module resolution)
139
- filePath = join(schemaLibDir, pathname.slice(12));
137
+ } else if (pathname.startsWith("/map/lib/")) {
138
+ // Serve @forwardimpact/map package files (resolved via Node module resolution)
139
+ filePath = join(mapLibDir, pathname.slice(9));
140
140
  } else if (pathname.startsWith("/model/lib/")) {
141
141
  // Serve @forwardimpact/libpathway package files (resolved via Node module resolution)
142
142
  filePath = join(modelLibDir, pathname.slice(11));
@@ -18,7 +18,7 @@ import {
18
18
  formatSubheader,
19
19
  formatBullet,
20
20
  } from "../lib/cli-output.js";
21
- import { getConceptEmoji } from "@forwardimpact/schema/levels";
21
+ import { getConceptEmoji } from "@forwardimpact/map/levels";
22
22
 
23
23
  /**
24
24
  * Format driver summary output
@@ -13,7 +13,7 @@
13
13
  import { createEntityCommand } from "./command-factory.js";
14
14
  import { gradeToMarkdown } from "../formatters/grade/markdown.js";
15
15
  import { formatTable } from "../lib/cli-output.js";
16
- import { getConceptEmoji } from "@forwardimpact/schema/levels";
16
+ import { getConceptEmoji } from "@forwardimpact/map/levels";
17
17
  import { capitalize } from "../formatters/shared.js";
18
18
 
19
19
  /**
@@ -14,7 +14,7 @@
14
14
  import { createEntityCommand } from "./command-factory.js";
15
15
  import { skillToMarkdown } from "../formatters/skill/markdown.js";
16
16
  import { prepareSkillsList } from "../formatters/skill/shared.js";
17
- import { getConceptEmoji } from "@forwardimpact/schema/levels";
17
+ import { getConceptEmoji } from "@forwardimpact/map/levels";
18
18
  import { formatTable, formatError } from "../lib/cli-output.js";
19
19
  import { generateSkillMarkdown } from "@forwardimpact/libpathway/agent";
20
20
  import { formatAgentSkill } from "../formatters/agent/skill.js";
@@ -14,7 +14,7 @@ import { createEntityCommand } from "./command-factory.js";
14
14
  import { trackToMarkdown } from "../formatters/track/markdown.js";
15
15
  import { sortTracksByName } from "../formatters/track/shared.js";
16
16
  import { formatTable } from "../lib/cli-output.js";
17
- import { getConceptEmoji } from "@forwardimpact/schema/levels";
17
+ import { getConceptEmoji } from "@forwardimpact/map/levels";
18
18
 
19
19
  /**
20
20
  * Format track summary output
@@ -3,20 +3,21 @@
3
3
  *
4
4
  * Re-downloads the distribution bundle from the published site URL
5
5
  * and updates the local ~/.fit/pathway/ installation.
6
+ * Updates the global @forwardimpact/pathway package if the version changed.
6
7
  */
7
8
 
8
9
  import { cp, mkdir, rm, readFile, writeFile, access } from "fs/promises";
9
10
  import { join } from "path";
10
11
  import { homedir } from "os";
11
12
  import { execFileSync, execSync } from "child_process";
12
- import { loadFrameworkConfig } from "@forwardimpact/schema/loader";
13
+ import { loadFrameworkConfig } from "@forwardimpact/map/loader";
13
14
 
14
15
  const INSTALL_DIR = join(homedir(), ".fit", "pathway");
15
16
 
16
17
  /**
17
18
  * Run the update command.
18
19
  * Reads siteUrl from the installed framework.yaml, re-downloads the bundle,
19
- * extracts data, and runs npm install to update dependencies.
20
+ * extracts data, and updates the global pathway package if the version changed.
20
21
  *
21
22
  * @param {Object} params - Command parameters
22
23
  * @param {string} params.dataDir - Path to data directory (may be the installed one)
@@ -82,7 +83,7 @@ export async function runUpdateCommand({ dataDir: _dataDir, options }) {
82
83
  ]);
83
84
  console.log(" ✓ Extracted");
84
85
 
85
- // 3. Compare versions
86
+ // 3. Compare versions from bundle's package.json (version manifest)
86
87
  const newPkgPath = join(extractDir, "package.json");
87
88
  const oldPkgPath = join(INSTALL_DIR, "package.json");
88
89
  const newPkg = JSON.parse(await readFile(newPkgPath, "utf8"));
@@ -104,21 +105,18 @@ export async function runUpdateCommand({ dataDir: _dataDir, options }) {
104
105
  await cp(join(extractDir, "data"), installDataDir, { recursive: true });
105
106
  console.log(" ✓ Data updated");
106
107
 
107
- // 5. Update package.json if version changed
108
+ // 5. Update version manifest
109
+ await writeFile(oldPkgPath, JSON.stringify(newPkg, null, 2) + "\n");
110
+
111
+ // 6. Update global pathway package if version changed
108
112
  if (oldVersion !== newVersion) {
109
113
  console.log(` Updating pathway ${oldVersion} → ${newVersion}...`);
110
- await writeFile(oldPkgPath, JSON.stringify(newPkg, null, 2) + "\n");
111
- console.log(" ✓ package.json updated");
114
+ execSync(`npm install -g @forwardimpact/pathway@${newVersion}`, {
115
+ stdio: "ignore",
116
+ });
117
+ console.log(" ✓ Global package updated");
112
118
  }
113
119
 
114
- // 6. Run npm install
115
- console.log(" Installing dependencies...");
116
- execSync("npm install --production --ignore-scripts --no-audit --no-fund", {
117
- cwd: INSTALL_DIR,
118
- stdio: "ignore",
119
- });
120
- console.log(" ✓ Dependencies installed");
121
-
122
120
  // 7. Report
123
121
  console.log(`
124
122
  ✅ Update complete!
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  import { div, span, details, summary } from "../lib/render.js";
9
- import { getCapabilityEmoji } from "@forwardimpact/schema/levels";
9
+ import { getCapabilityEmoji } from "@forwardimpact/map/levels";
10
10
 
11
11
  /**
12
12
  * Create checklist display grouped by capability
@@ -23,7 +23,7 @@ import { formatLevel } from "../lib/render.js";
23
23
  import {
24
24
  SKILL_LEVEL_ORDER,
25
25
  BEHAVIOUR_MATURITY_ORDER,
26
- } from "@forwardimpact/schema/levels";
26
+ } from "@forwardimpact/map/levels";
27
27
 
28
28
  /**
29
29
  * Create a detail page header
@@ -18,7 +18,7 @@ import {
18
18
  import { getSkillLevelIndex } from "../lib/render.js";
19
19
  import { createLevelCell } from "./detail.js";
20
20
  import { createBadge } from "./card.js";
21
- import { SKILL_LEVEL_ORDER } from "@forwardimpact/schema/levels";
21
+ import { SKILL_LEVEL_ORDER } from "@forwardimpact/map/levels";
22
22
  import { truncate } from "../formatters/shared.js";
23
23
 
24
24
  /**
@@ -21,7 +21,7 @@ import { createLevelCell } from "../../components/detail.js";
21
21
  import {
22
22
  BEHAVIOUR_MATURITY_ORDER,
23
23
  getConceptEmoji,
24
- } from "@forwardimpact/schema/levels";
24
+ } from "@forwardimpact/map/levels";
25
25
  import { prepareBehaviourDetail } from "./shared.js";
26
26
  import { createJsonLdScript, behaviourToJsonLd } from "../json-ld.js";
27
27
 
@@ -18,7 +18,7 @@ import {
18
18
  createJobBuilderButton,
19
19
  createInterviewPrepButton,
20
20
  } from "../../components/action-buttons.js";
21
- import { getConceptEmoji } from "@forwardimpact/schema/levels";
21
+ import { getConceptEmoji } from "@forwardimpact/map/levels";
22
22
  import { prepareDisciplineDetail } from "./shared.js";
23
23
  import { createJsonLdScript, disciplineToJsonLd } from "../json-ld.js";
24
24
  import { createBadge } from "../../components/card.js";
@@ -5,7 +5,7 @@
5
5
  import { div, heading1, heading2, p, a, span } from "../../lib/render.js";
6
6
  import { createBackLink } from "../../components/nav.js";
7
7
  import { prepareDriverDetail } from "./shared.js";
8
- import { getConceptEmoji } from "@forwardimpact/schema/levels";
8
+ import { getConceptEmoji } from "@forwardimpact/map/levels";
9
9
  import { createJsonLdScript, driverToJsonLd } from "../json-ld.js";
10
10
 
11
11
  /**
@@ -22,7 +22,7 @@ import {
22
22
  SKILL_LEVEL_ORDER,
23
23
  BEHAVIOUR_MATURITY_ORDER,
24
24
  getConceptEmoji,
25
- } from "@forwardimpact/schema/levels";
25
+ } from "@forwardimpact/map/levels";
26
26
  import { createJobBuilderButton } from "../../components/action-buttons.js";
27
27
  import { prepareGradeDetail } from "./shared.js";
28
28
  import { createJsonLdScript, gradeToJsonLd } from "../json-ld.js";
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { tableToMarkdown, capitalize } from "../shared.js";
6
6
  import { prepareGradesList, prepareGradeDetail } from "./shared.js";
7
- import { getConceptEmoji } from "@forwardimpact/schema/levels";
7
+ import { getConceptEmoji } from "@forwardimpact/map/levels";
8
8
 
9
9
  /**
10
10
  * Format grade list as markdown
@@ -5,7 +5,7 @@
5
5
  import { div, heading1, heading2, p, span } from "../../lib/render.js";
6
6
  import { createBackLink } from "../../components/nav.js";
7
7
  import { createLevelDots } from "../../components/detail.js";
8
- import { getConceptEmoji } from "@forwardimpact/schema/levels";
8
+ import { getConceptEmoji } from "@forwardimpact/map/levels";
9
9
 
10
10
  /**
11
11
  * Format interview detail as DOM elements
@@ -3,7 +3,7 @@
3
3
  */
4
4
 
5
5
  import { formatLevel } from "../../lib/render.js";
6
- import { getConceptEmoji } from "@forwardimpact/schema/levels";
6
+ import { getConceptEmoji } from "@forwardimpact/map/levels";
7
7
 
8
8
  /**
9
9
  * Format interview detail as markdown
@@ -10,10 +10,7 @@
10
10
 
11
11
  import Mustache from "mustache";
12
12
 
13
- import {
14
- SKILL_LEVEL_ORDER,
15
- BEHAVIOUR_MATURITY_ORDER,
16
- } from "@forwardimpact/schema/levels";
13
+ import { BEHAVIOUR_MATURITY_ORDER } from "@forwardimpact/map/levels";
17
14
  import { trimValue, trimFields } from "../shared.js";
18
15
 
19
16
  /**
@@ -84,43 +81,45 @@ function prepareJobDescriptionData({ job, discipline, grade, track }) {
84
81
  return indexB - indexA;
85
82
  });
86
83
 
87
- // Group skills by level
88
- const skillsByLevel = {};
89
- for (const skill of job.skillMatrix) {
90
- const level = skill.level || "Other";
91
- if (!skillsByLevel[level]) {
92
- skillsByLevel[level] = [];
93
- }
94
- skillsByLevel[level].push(skill);
95
- }
84
+ // Build capability skill sections at the highest skill level
85
+ let capabilitySkills = [];
86
+ const derivedResponsibilities = job.derivedResponsibilities || [];
87
+ if (derivedResponsibilities.length > 0) {
88
+ // derivedResponsibilities is sorted: highest level first, then by ordinalRank
89
+ const highestLevel = derivedResponsibilities[0].level;
96
90
 
97
- // Sort levels in reverse order (expert first, awareness last)
98
- const sortedLevels = Object.keys(skillsByLevel).sort((a, b) => {
99
- const indexA = SKILL_LEVEL_ORDER.indexOf(a.toLowerCase());
100
- const indexB = SKILL_LEVEL_ORDER.indexOf(b.toLowerCase());
101
- if (indexA === -1 && indexB === -1) return a.localeCompare(b);
102
- if (indexA === -1) return 1;
103
- if (indexB === -1) return -1;
104
- return indexB - indexA;
105
- });
91
+ // Filter responsibilities to only the highest level
92
+ const topResponsibilities = derivedResponsibilities.filter(
93
+ (r) => r.level === highestLevel,
94
+ );
106
95
 
107
- // Keep only the top 2 skill levels for job descriptions
108
- const topLevels = sortedLevels.slice(0, 2);
96
+ // Group skill matrix entries by capability at the highest level
97
+ const skillsByCapability = {};
98
+ for (const skill of job.skillMatrix) {
99
+ if (skill.level !== highestLevel) continue;
100
+ if (!skillsByCapability[skill.capability]) {
101
+ skillsByCapability[skill.capability] = [];
102
+ }
103
+ skillsByCapability[skill.capability].push(skill);
104
+ }
109
105
 
110
- // Build skill levels array for template
111
- const skillLevels = topLevels.map((level) => {
112
- const skills = skillsByLevel[level];
113
- const sortedSkills = [...skills].sort((a, b) =>
114
- (a.skillName || "").localeCompare(b.skillName || ""),
115
- );
116
- return {
117
- levelHeading: `${level.toUpperCase()}-LEVEL SKILLS`,
118
- skills: sortedSkills.map((s) => ({
119
- skillName: s.skillName,
120
- levelDescription: s.levelDescription || "",
121
- })),
122
- };
123
- });
106
+ // Build capability sections in ordinalRank order
107
+ capabilitySkills = topResponsibilities
108
+ .filter((r) => skillsByCapability[r.capability]?.length > 0)
109
+ .map((r) => {
110
+ const skills = [...skillsByCapability[r.capability]].sort((a, b) =>
111
+ (a.skillName || "").localeCompare(b.skillName || ""),
112
+ );
113
+ return {
114
+ capabilityHeading: r.capabilityName.toUpperCase(),
115
+ responsibilityDescription: r.responsibility,
116
+ skills: skills.map((s) => ({
117
+ skillName: s.skillName,
118
+ levelDescription: s.levelDescription || "",
119
+ })),
120
+ };
121
+ });
122
+ }
124
123
 
125
124
  // Build qualification summary with placeholder replacement
126
125
  const qualificationSummary =
@@ -129,9 +128,6 @@ function prepareJobDescriptionData({ job, discipline, grade, track }) {
129
128
  grade.typicalExperienceRange || "",
130
129
  ) || null;
131
130
 
132
- const responsibilities = trimFields(job.derivedResponsibilities, {
133
- responsibility: "required",
134
- });
135
131
  const behaviours = trimFields(sortedBehaviours, {
136
132
  maturityDescription: "optional",
137
133
  });
@@ -150,15 +146,14 @@ function prepareJobDescriptionData({ job, discipline, grade, track }) {
150
146
  hasTrackRoleContext: !!trimmedTrackRoleContext,
151
147
  expectationsParagraph: trimmedExpectationsParagraph,
152
148
  hasExpectationsParagraph: !!trimmedExpectationsParagraph,
153
- responsibilities,
154
- hasResponsibilities: responsibilities.length > 0,
155
149
  behaviours,
156
150
  hasBehaviours: behaviours.length > 0,
157
- skillLevels: skillLevels.map((level) => ({
158
- ...level,
159
- skills: trimFields(level.skills, { levelDescription: "optional" }),
151
+ capabilitySkills: capabilitySkills.map((cap) => ({
152
+ ...cap,
153
+ responsibilityDescription: trimValue(cap.responsibilityDescription),
154
+ skills: trimFields(cap.skills, { levelDescription: "optional" }),
160
155
  })),
161
- hasSkillLevels: skillLevels.length > 0,
156
+ hasCapabilitySkills: capabilitySkills.length > 0,
162
157
  qualificationSummary: trimmedQualificationSummary,
163
158
  hasQualificationSummary: !!trimmedQualificationSummary,
164
159
  };
@@ -9,7 +9,7 @@ import {
9
9
  } from "../shared.js";
10
10
  import { formatLevel } from "../../lib/render.js";
11
11
  import { formatJobDescription } from "./description.js";
12
- import { SKILL_LEVEL_ORDER } from "@forwardimpact/schema/levels";
12
+ import { SKILL_LEVEL_ORDER } from "@forwardimpact/map/levels";
13
13
  import { toolkitToMarkdown } from "../toolkit/markdown.js";
14
14
 
15
15
  /**
@@ -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_LEVEL_ORDER } from "@forwardimpact/map/levels";
24
24
  import { prepareSkillDetail } from "./shared.js";
25
25
  import { createJsonLdScript, skillToJsonLd } from "../json-ld.js";
26
26
 
@@ -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
@@ -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
 
@@ -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
@@ -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 {
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",
@@ -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
package/src/lib/render.js CHANGED
@@ -5,7 +5,7 @@
5
5
  import {
6
6
  SKILL_LEVEL_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
@@ -9,7 +9,7 @@ import { renderNotFound } from "../components/error-page.js";
9
9
  import { prepareBehavioursList } from "../formatters/behaviour/shared.js";
10
10
  import { behaviourToDOM } from "../formatters/behaviour/dom.js";
11
11
  import { behaviourToCardConfig } from "../lib/card-mappers.js";
12
- import { getConceptEmoji } from "@forwardimpact/schema/levels";
12
+ import { getConceptEmoji } from "@forwardimpact/map/levels";
13
13
 
14
14
  /**
15
15
  * Render behaviours list page
@@ -10,7 +10,7 @@ import { renderNotFound } from "../components/error-page.js";
10
10
  import { prepareDisciplinesList } from "../formatters/discipline/shared.js";
11
11
  import { disciplineToDOM } from "../formatters/discipline/dom.js";
12
12
  import { disciplineToCardConfig } from "../lib/card-mappers.js";
13
- import { getConceptEmoji } from "@forwardimpact/schema/levels";
13
+ import { getConceptEmoji } from "@forwardimpact/map/levels";
14
14
 
15
15
  /**
16
16
  * Format discipline group name for display
@@ -9,7 +9,7 @@ import { renderNotFound } from "../components/error-page.js";
9
9
  import { prepareDriversList } from "../formatters/driver/shared.js";
10
10
  import { driverToDOM } from "../formatters/driver/dom.js";
11
11
  import { driverToCardConfig } from "../lib/card-mappers.js";
12
- import { getConceptEmoji } from "@forwardimpact/schema/levels";
12
+ import { getConceptEmoji } from "@forwardimpact/map/levels";
13
13
 
14
14
  /**
15
15
  * Render drivers list page
@@ -8,7 +8,7 @@ import { createBadge } from "../components/card.js";
8
8
  import { renderNotFound } from "../components/error-page.js";
9
9
  import { prepareGradesList } from "../formatters/grade/shared.js";
10
10
  import { gradeToDOM } from "../formatters/grade/dom.js";
11
- import { getConceptEmoji } from "@forwardimpact/schema/levels";
11
+ import { getConceptEmoji } from "@forwardimpact/map/levels";
12
12
 
13
13
  /**
14
14
  * Render grades list page
@@ -21,7 +21,7 @@ import { createBadge } from "../components/card.js";
21
21
  import { createBackLink } from "../components/nav.js";
22
22
  import { createDetailSection } from "../components/detail.js";
23
23
  import { renderError } from "../components/error-page.js";
24
- import { getConceptEmoji } from "@forwardimpact/schema/levels";
24
+ import { getConceptEmoji } from "@forwardimpact/map/levels";
25
25
  import {
26
26
  prepareAllInterviews,
27
27
  INTERVIEW_TYPES,
@@ -8,7 +8,7 @@ import { createStatCard } from "../components/card.js";
8
8
  import {
9
9
  groupSkillsByCapability,
10
10
  getConceptEmoji,
11
- } from "@forwardimpact/schema/levels";
11
+ } from "@forwardimpact/map/levels";
12
12
  import { getStageEmoji } from "../formatters/stage/shared.js";
13
13
  import { aggregateTools } from "../formatters/tool/shared.js";
14
14
  import { createCommandPrompt } from "../components/command-prompt.js";
@@ -25,7 +25,7 @@ import {
25
25
  getCapabilityOrder,
26
26
  getCapabilityEmoji,
27
27
  getConceptEmoji,
28
- } from "@forwardimpact/schema/levels";
28
+ } from "@forwardimpact/map/levels";
29
29
  import { formatLevel } from "../lib/render.js";
30
30
 
31
31
  /**
@@ -10,10 +10,7 @@ import { renderNotFound } from "../components/error-page.js";
10
10
  import { prepareSkillsList } from "../formatters/skill/shared.js";
11
11
  import { skillToDOM } from "../formatters/skill/dom.js";
12
12
  import { skillToCardConfig } from "../lib/card-mappers.js";
13
- import {
14
- getCapabilityEmoji,
15
- getConceptEmoji,
16
- } from "@forwardimpact/schema/levels";
13
+ import { getCapabilityEmoji, getConceptEmoji } from "@forwardimpact/map/levels";
17
14
  import { generateSkillMarkdown } from "@forwardimpact/libpathway";
18
15
  import { formatAgentSkill } from "../formatters/agent/skill.js";
19
16
 
@@ -7,7 +7,7 @@ import { getState } from "../lib/state.js";
7
7
  import { createCardList } from "../components/list.js";
8
8
  import { renderNotFound } from "../components/error-page.js";
9
9
  import { prepareStagesList, stageToDOM } from "../formatters/stage/index.js";
10
- import { getConceptEmoji } from "@forwardimpact/schema/levels";
10
+ import { getConceptEmoji } from "@forwardimpact/map/levels";
11
11
 
12
12
  /**
13
13
  * Map stage to card configuration
package/src/pages/tool.js CHANGED
@@ -10,7 +10,7 @@ import { prepareToolsList } from "../formatters/tool/shared.js";
10
10
  import { createBadge } from "../components/card.js";
11
11
  import { createCardList } from "../components/list.js";
12
12
  import { toolToCardConfig } from "../lib/card-mappers.js";
13
- import { getConceptEmoji } from "@forwardimpact/schema/levels";
13
+ import { getConceptEmoji } from "@forwardimpact/map/levels";
14
14
 
15
15
  /**
16
16
  * Render tools list page
@@ -9,7 +9,7 @@ import { renderNotFound } from "../components/error-page.js";
9
9
  import { prepareTracksList } from "../formatters/track/shared.js";
10
10
  import { trackToDOM } from "../formatters/track/dom.js";
11
11
  import { trackToCardConfig } from "../lib/card-mappers.js";
12
- import { getConceptEmoji } from "@forwardimpact/schema/levels";
12
+ import { getConceptEmoji } from "@forwardimpact/map/levels";
13
13
 
14
14
  /**
15
15
  * Render tracks list page
@@ -5,7 +5,7 @@
5
5
  */
6
6
 
7
7
  import { div, heading1, heading2, p, a, ul, li, span } from "../lib/render.js";
8
- import { getConceptEmoji } from "@forwardimpact/schema/levels";
8
+ import { getConceptEmoji } from "@forwardimpact/map/levels";
9
9
  import { generateAllJobs } from "@forwardimpact/libpathway/derivation";
10
10
 
11
11
  /**
package/src/slides.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",
@@ -2,7 +2,8 @@
2
2
  # {{{frameworkTitle}}} — Local Install
3
3
  # Generated by @forwardimpact/pathway v{{{version}}}
4
4
  #
5
- # Installs to ~/.fit/pathway/
5
+ # Installs fit-pathway globally via npm and downloads organization data
6
+ # to ~/.fit/pathway/data/.
6
7
  #
7
8
  # Usage:
8
9
  # curl -fsSL {{{siteUrl}}}/install.sh | bash
@@ -15,7 +16,12 @@ INSTALL_DIR="${HOME}/.fit/pathway"
15
16
  command -v node >/dev/null 2>&1 || { echo "Error: Node.js 18+ is required. https://nodejs.org"; exit 1; }
16
17
  command -v npm >/dev/null 2>&1 || { echo "Error: npm is required."; exit 1; }
17
18
 
18
- echo "Installing to ${INSTALL_DIR}..."
19
+ # Install fit-pathway globally (provides the fit-pathway binary on PATH)
20
+ echo "Installing @forwardimpact/pathway globally..."
21
+ npm install -g @forwardimpact/pathway@{{{version}}}
22
+
23
+ # Download organization data to ~/.fit/pathway/data/
24
+ echo "Downloading organization data to ${INSTALL_DIR}/data/..."
19
25
  mkdir -p "${INSTALL_DIR}"
20
26
 
21
27
  TMPFILE=$(mktemp)
@@ -23,11 +29,8 @@ trap 'rm -f "$TMPFILE"' EXIT
23
29
  curl -fsSL "${SITE_URL}/bundle.tar.gz" -o "$TMPFILE"
24
30
  tar -xzf "$TMPFILE" -C "${INSTALL_DIR}" --strip-components=1
25
31
 
26
- (cd "${INSTALL_DIR}" && npm install --production --ignore-scripts --no-audit --no-fund --silent)
27
-
28
32
  echo ""
29
33
  echo "Done. Usage:"
30
- echo " cd ${INSTALL_DIR}"
31
- echo " npx fit-pathway skill --list"
32
- echo " npx fit-pathway job --list"
33
- echo " npx fit-pathway agent --list"
34
+ echo " fit-pathway skill --list"
35
+ echo " fit-pathway job --list"
36
+ echo " fit-pathway agent --list"
@@ -16,14 +16,6 @@
16
16
 
17
17
  {{{expectationsParagraph}}}
18
18
  {{/hasExpectationsParagraph}}
19
- {{#hasResponsibilities}}
20
-
21
- ## ROLE RESPONSIBILITIES
22
-
23
- {{#responsibilities}}
24
- - **{{{capabilityName}}}:** {{{responsibility}}}
25
- {{/responsibilities}}
26
- {{/hasResponsibilities}}
27
19
  {{#hasBehaviours}}
28
20
 
29
21
  ## ROLE BEHAVIOURS
@@ -32,16 +24,20 @@
32
24
  - **{{{behaviourName}}}:** {{{maturityDescription}}}
33
25
  {{/behaviours}}
34
26
  {{/hasBehaviours}}
35
- {{#hasSkillLevels}}
36
- {{#skillLevels}}
27
+ {{#hasCapabilitySkills}}
28
+
29
+ ## ROLE RESPONSIBILITIES
30
+ {{#capabilitySkills}}
31
+
32
+ ### {{{capabilityHeading}}}
37
33
 
38
- ## {{{levelHeading}}}
34
+ {{{responsibilityDescription}}}:
39
35
 
40
36
  {{#skills}}
41
37
  - **{{{skillName}}}:** {{{levelDescription}}}
42
38
  {{/skills}}
43
- {{/skillLevels}}
44
- {{/hasSkillLevels}}
39
+ {{/capabilitySkills}}
40
+ {{/hasCapabilitySkills}}
45
41
  {{#hasQualificationSummary}}
46
42
 
47
43
  ## QUALIFICATIONS