@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
@@ -6,7 +6,7 @@
6
6
  * interview questions, career progression analysis, and AI agent configurations.
7
7
  *
8
8
  * Usage:
9
- * npx pathway <command> [options]
9
+ * npx fit-pathway <command> [options]
10
10
  *
11
11
  * Commands:
12
12
  * discipline [<id>] Show disciplines
@@ -25,40 +25,36 @@
25
25
  *
26
26
  * Global Options:
27
27
  * --list Output IDs only (for piping)
28
- * --validate Run validation checks
29
28
  * --json Output as JSON
30
29
  * --help Show help
30
+ *
31
+ * Validation (moved to fit-schema):
32
+ * npx fit-schema validate
33
+ * npx fit-schema generate-index
31
34
  */
32
35
 
33
- import { fileURLToPath } from "url";
34
- import { dirname, join, resolve } from "path";
36
+ import { join, resolve } from "path";
35
37
  import { existsSync } from "fs";
36
- import { loadAllData } from "../app/model/loader.js";
37
- import { generateAllIndexes } from "../app/model/index-generator.js";
38
- import { formatError } from "../app/lib/cli-output.js";
39
- import { runSchemaValidation } from "../app/model/schema-validation.js";
38
+ import { loadAllData } from "@forwardimpact/schema/loader";
39
+ import { formatError } from "../src/lib/cli-output.js";
40
40
 
41
41
  // Import command handlers
42
- import { runDisciplineCommand } from "../app/commands/discipline.js";
43
- import { runGradeCommand } from "../app/commands/grade.js";
44
- import { runTrackCommand } from "../app/commands/track.js";
45
- import { runBehaviourCommand } from "../app/commands/behaviour.js";
46
- import { runSkillCommand } from "../app/commands/skill.js";
47
- import { runDriverCommand } from "../app/commands/driver.js";
48
- import { runStageCommand } from "../app/commands/stage.js";
49
- import { runToolCommand } from "../app/commands/tool.js";
50
- import { runJobCommand } from "../app/commands/job.js";
51
- import { runInterviewCommand } from "../app/commands/interview.js";
52
- import { runProgressCommand } from "../app/commands/progress.js";
53
- import { runQuestionsCommand } from "../app/commands/questions.js";
54
- import { runAgentCommand } from "../app/commands/agent.js";
55
- import { runServeCommand } from "../app/commands/serve.js";
56
- import { runInitCommand } from "../app/commands/init.js";
57
- import { runSiteCommand } from "../app/commands/site.js";
58
-
59
- const __filename = fileURLToPath(import.meta.url);
60
- const __dirname = dirname(__filename);
61
- const rootDir = join(__dirname, "..");
42
+ import { runDisciplineCommand } from "../src/commands/discipline.js";
43
+ import { runGradeCommand } from "../src/commands/grade.js";
44
+ import { runTrackCommand } from "../src/commands/track.js";
45
+ import { runBehaviourCommand } from "../src/commands/behaviour.js";
46
+ import { runSkillCommand } from "../src/commands/skill.js";
47
+ import { runDriverCommand } from "../src/commands/driver.js";
48
+ import { runStageCommand } from "../src/commands/stage.js";
49
+ import { runToolCommand } from "../src/commands/tool.js";
50
+ import { runJobCommand } from "../src/commands/job.js";
51
+ import { runInterviewCommand } from "../src/commands/interview.js";
52
+ import { runProgressCommand } from "../src/commands/progress.js";
53
+ import { runQuestionsCommand } from "../src/commands/questions.js";
54
+ import { runAgentCommand } from "../src/commands/agent.js";
55
+ import { runServeCommand } from "../src/commands/serve.js";
56
+ import { runInitCommand } from "../src/commands/init.js";
57
+ import { runSiteCommand } from "../src/commands/site.js";
62
58
 
63
59
  const COMMANDS = {
64
60
  discipline: runDisciplineCommand,
@@ -80,9 +76,11 @@ const HELP_TEXT = `
80
76
  Engineering Pathway CLI
81
77
 
82
78
  Usage:
83
- npx pathway <command> [options]
84
- npx pathway --validate Run full data validation
85
- npx pathway --generate-index Generate browser index files
79
+ npx fit-pathway <command> [options]
80
+
81
+ Validation (use fit-schema instead):
82
+ npx fit-schema validate Run full data validation
83
+ npx fit-schema generate-index Generate browser index files
86
84
 
87
85
  Getting Started:
88
86
  init Create ./data/ with example data
@@ -111,8 +109,6 @@ Composite Commands:
111
109
 
112
110
  Global Options:
113
111
  --list Output IDs only (for piping to other commands)
114
- --validate Run validation checks
115
- --generate-index Generate _index.yaml files for browser loading
116
112
  --json Output as JSON
117
113
  --data=PATH Path to data directory (default: ./data or examples/)
118
114
  --help Show this help message
@@ -133,26 +129,25 @@ Agent Options:
133
129
  --all-stages Generate all stage agents (default)
134
130
 
135
131
  Examples:
136
- npx pathway skill # Summary of all skills
137
- npx pathway skill --list # Skill IDs for piping
138
- npx pathway skill ai_evaluation # Detail view
139
- npx pathway skill architecture_design --agent # Agent SKILL.md output
140
-
141
- npx pathway tool # Summary of all tools
142
- npx pathway tool --list # Tool names for piping
143
- npx pathway tool DuckDB # Tool detail with skill usages
144
-
145
- npx pathway job # Summary of valid combinations
146
- npx pathway job --list # All combinations for piping
147
- npx pathway job software_engineering L4
148
- npx pathway job software_engineering L4 --track=platform
149
- npx pathway job se L3 --track=platform --checklist=code
150
-
151
- npx pathway questions --level=practitioner
152
- npx pathway questions --stats
153
-
154
- npx pathway agent software_engineering --track=platform --output=./agents
155
- npx pathway --validate # Validate all data
132
+ npx fit-pathway skill # Summary of all skills
133
+ npx fit-pathway skill --list # Skill IDs for piping
134
+ npx fit-pathway skill ai_evaluation # Detail view
135
+ npx fit-pathway skill architecture_design --agent # Agent SKILL.md output
136
+
137
+ npx fit-pathway tool # Summary of all tools
138
+ npx fit-pathway tool --list # Tool names for piping
139
+ npx fit-pathway tool DuckDB # Tool detail with skill usages
140
+
141
+ npx fit-pathway job # Summary of valid combinations
142
+ npx fit-pathway job --list # All combinations for piping
143
+ npx fit-pathway job software_engineering L4
144
+ npx fit-pathway job software_engineering L4 --track=platform
145
+ npx fit-pathway job se L3 --track=platform --checklist=code
146
+
147
+ npx fit-pathway questions --level=practitioner
148
+ npx fit-pathway questions --stats
149
+
150
+ npx fit-pathway agent software_engineering --track=platform --output=./agents
156
151
  `;
157
152
 
158
153
  /**
@@ -167,8 +162,6 @@ function parseArgs(args) {
167
162
  list: false,
168
163
  json: false,
169
164
  help: false,
170
- validate: false,
171
- generateIndex: false,
172
165
  type: "full",
173
166
  compare: null,
174
167
  data: null,
@@ -204,10 +197,6 @@ function parseArgs(args) {
204
197
  result.list = true;
205
198
  } else if (arg === "--json") {
206
199
  result.json = true;
207
- } else if (arg === "--validate") {
208
- result.validate = true;
209
- } else if (arg === "--generate-index") {
210
- result.generateIndex = true;
211
200
  } else if (arg.startsWith("--type=")) {
212
201
  result.type = arg.slice(7);
213
202
  } else if (arg.startsWith("--compare=")) {
@@ -269,85 +258,14 @@ function printHelp() {
269
258
  console.log(HELP_TEXT);
270
259
  }
271
260
 
272
- /**
273
- * Run full data validation using JSON schemas
274
- * @param {string} dataDir - Path to data directory
275
- */
276
- async function runFullValidation(dataDir) {
277
- console.log(`\n🔍 Validating data in: ${dataDir}\n`);
278
-
279
- let hasErrors = false;
280
-
281
- // Load data for referential integrity checking (without old validation)
282
- const data = await loadAllData(dataDir, {
283
- validate: false,
284
- throwOnError: false,
285
- });
286
-
287
- // Run schema validation + referential integrity
288
- const result = await runSchemaValidation(dataDir, data);
289
-
290
- if (result.valid) {
291
- console.log("✅ Schema validation passed");
292
- } else {
293
- console.log("❌ Schema validation failed");
294
- hasErrors = true;
295
- for (const e of result.errors) {
296
- console.log(
297
- ` - [${e.type}] ${e.message}${e.path ? ` (${e.path})` : ""}`,
298
- );
299
- }
300
- }
301
-
302
- if (result.warnings.length > 0) {
303
- console.log("\n⚠️ Warnings:");
304
- for (const w of result.warnings) {
305
- console.log(` - [${w.type}] ${w.message}`);
306
- }
307
- }
308
-
309
- // Summary
310
- console.log("\n📊 Data Summary:");
311
- console.log(` Skills: ${data.skills?.length || 0}`);
312
- console.log(` Behaviours: ${data.behaviours?.length || 0}`);
313
- console.log(` Disciplines: ${data.disciplines?.length || 0}`);
314
- console.log(` Tracks: ${data.tracks?.length || 0}`);
315
- console.log(` Grades: ${data.grades?.length || 0}`);
316
- console.log(` Drivers: ${data.drivers?.length || 0}`);
317
- console.log(` Stages: ${data.stages?.length || 0}`);
318
- console.log("");
319
-
320
- return hasErrors ? 1 : 0;
321
- }
322
-
323
- /**
324
- * Run index generation
325
- * @param {string} dataDir - Path to data directory
326
- */
327
- async function runGenerateIndex(dataDir) {
328
- console.log(`\n📁 Generating index files in: ${dataDir}\n`);
329
-
330
- const results = await generateAllIndexes(dataDir);
331
-
332
- for (const [dir, files] of Object.entries(results)) {
333
- if (files.error) {
334
- console.log(`❌ ${dir}: ${files.error}`);
335
- } else {
336
- console.log(`✅ ${dir}/_index.yaml (${files.length} files)`);
337
- }
338
- }
339
-
340
- console.log("\n✨ Index generation complete\n");
341
- return 0;
342
- }
343
-
344
261
  /**
345
262
  * Resolve the data directory path.
346
263
  * Resolution order:
347
264
  * 1. --data=<path> flag (explicit override)
348
265
  * 2. PATHWAY_DATA environment variable
349
266
  * 3. ./data/ relative to current working directory
350
- * 4. Package examples (for demo/testing)
267
+ * 4. ./examples/ relative to current working directory
268
+ * 5. apps/schema/examples/ for monorepo development
351
269
  *
352
270
  * @param {Object} options - Parsed command options
353
271
  * @returns {string} Resolved absolute path to data directory
@@ -363,16 +281,22 @@ function resolveDataPath(options) {
363
281
  return resolve(process.env.PATHWAY_DATA);
364
282
  }
365
283
 
366
- // 3. Current working directory
284
+ // 3. Current working directory ./data/
367
285
  const cwdData = join(process.cwd(), "data");
368
286
  if (existsSync(cwdData)) {
369
287
  return cwdData;
370
288
  }
371
289
 
372
- // 4. Package examples (for demo/testing)
373
- const examplesData = join(rootDir, "examples");
374
- if (existsSync(examplesData)) {
375
- return examplesData;
290
+ // 4. Current working directory ./examples/
291
+ const cwdExamples = join(process.cwd(), "examples");
292
+ if (existsSync(cwdExamples)) {
293
+ return cwdExamples;
294
+ }
295
+
296
+ // 5. Monorepo: apps/schema/examples/
297
+ const schemaExamples = join(process.cwd(), "apps/schema/examples");
298
+ if (existsSync(schemaExamples)) {
299
+ return schemaExamples;
376
300
  }
377
301
 
378
302
  throw new Error(
@@ -392,21 +316,7 @@ async function main() {
392
316
  process.exit(0);
393
317
  }
394
318
 
395
- const dataDir = resolveDataPath(options);
396
-
397
- // Handle global --generate-index (no command)
398
- if (options.generateIndex && !options.command) {
399
- const exitCode = await runGenerateIndex(dataDir);
400
- process.exit(exitCode);
401
- }
402
-
403
- // Handle global --validate (no command)
404
- if (options.validate && !options.command) {
405
- const exitCode = await runFullValidation(dataDir);
406
- process.exit(exitCode);
407
- }
408
-
409
- // No command and no flags: show help
319
+ // No command: show help
410
320
  if (!options.command) {
411
321
  printHelp();
412
322
  process.exit(0);
@@ -420,6 +330,8 @@ async function main() {
420
330
  process.exit(0);
421
331
  }
422
332
 
333
+ const dataDir = resolveDataPath(options);
334
+
423
335
  // Handle serve command (needs data directory)
424
336
  if (command === "serve") {
425
337
  await runServeCommand({ dataDir, options });
@@ -437,7 +349,7 @@ async function main() {
437
349
 
438
350
  if (!handler) {
439
351
  console.error(formatError(`Unknown command: ${command}`));
440
- console.error(`Run 'npx pathway --help' for usage.`);
352
+ console.error(`Run 'npx fit-pathway --help' for usage.`);
441
353
  process.exit(1);
442
354
  }
443
355
 
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@forwardimpact/pathway",
3
- "version": "0.5.0",
4
- "description": "Engineering Pathway framework for human and AI collaboration",
3
+ "version": "0.6.0",
4
+ "description": "Engineering Pathway CLI and web app",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
7
7
  "type": "git",
8
- "url": "https://github.com/forwardimpact/pathway"
8
+ "url": "https://github.com/forwardimpact/pathway",
9
+ "directory": "apps/pathway"
9
10
  },
10
11
  "keywords": [
11
12
  "career",
@@ -18,57 +19,32 @@
18
19
  "engineering"
19
20
  ],
20
21
  "type": "module",
21
- "main": "app/model/loader.js",
22
+ "main": "src/index.js",
22
23
  "bin": {
23
- "pathway": "./bin/pathway.js"
24
+ "fit-pathway": "./bin/fit-pathway.js"
25
+ },
26
+ "scripts": {
27
+ "start": "node ./bin/fit-pathway.js serve",
28
+ "pathway": "node ./bin/fit-pathway.js",
29
+ "site": "node ./bin/fit-pathway.js site"
24
30
  },
25
31
  "files": [
26
32
  "bin/",
27
- "app/",
28
- "examples/",
33
+ "src/",
29
34
  "templates/"
30
35
  ],
31
36
  "exports": {
32
- ".": "./app/model/loader.js",
33
- "./derivation": "./app/model/derivation.js",
34
- "./interview": "./app/model/interview.js",
35
- "./levels": "./app/model/levels.js",
36
- "./loader": "./app/model/loader.js",
37
- "./matching": "./app/model/matching.js",
38
- "./types": "./app/model/levels.js",
39
- "./validation": "./app/model/validation.js"
40
- },
41
- "scripts": {
42
- "start": "node bin/pathway.js serve",
43
- "prestart": "npm run generate-index",
44
- "check": "npm run format && npm run lint && npm run test && npm run validate:shacl",
45
- "check:fix": "npm run format:fix && npm run lint:fix",
46
- "lint": "eslint .",
47
- "lint:fix": "eslint . --fix",
48
- "format": "prettier --check .",
49
- "format:fix": "prettier --write .",
50
- "test": "find ./tests -name '*.test.js' | xargs node --test",
51
- "test:e2e": "npx playwright test",
52
- "validate": "node bin/pathway.js --validate",
53
- "validate:shacl": "node scripts/validate-shacl.js",
54
- "generate-index": "node bin/pathway.js --generate-index",
55
- "pathway": "node bin/pathway.js",
56
- "demo": "node scripts/demo.js"
37
+ ".": "./src/index.js",
38
+ "./formatters": "./src/formatters/index.js",
39
+ "./commands": "./src/commands/index.js"
57
40
  },
58
41
  "dependencies": {
59
- "ajv": "^8.17.1",
60
- "ajv-formats": "^3.0.1",
42
+ "@forwardimpact/schema": "^0.1.0",
43
+ "@forwardimpact/model": "^0.1.0",
61
44
  "mustache": "^4.2.0",
62
45
  "simple-icons": "^16.7.0",
63
46
  "yaml": "^2.3.4"
64
47
  },
65
- "devDependencies": {
66
- "@playwright/test": "^1.49.0",
67
- "eslint": "^9.39.1",
68
- "eslint-config-prettier": "^10.1.8",
69
- "n3": "^2.0.1",
70
- "prettier": "^3.7.4"
71
- },
72
48
  "engines": {
73
49
  "node": ">=18.0.0"
74
50
  }
@@ -25,7 +25,10 @@ import { writeFile, mkdir, readFile } from "fs/promises";
25
25
  import { join, dirname } from "path";
26
26
  import { existsSync } from "fs";
27
27
  import { stringify as stringifyYaml } from "yaml";
28
- import { loadAgentData, loadSkillsWithAgentData } from "../model/loader.js";
28
+ import {
29
+ loadAgentData,
30
+ loadSkillsWithAgentData,
31
+ } from "@forwardimpact/schema/loader";
29
32
  import {
30
33
  generateStageAgentProfile,
31
34
  validateAgentProfile,
@@ -33,7 +36,7 @@ import {
33
36
  deriveReferenceGrade,
34
37
  deriveAgentSkills,
35
38
  generateSkillMd,
36
- } from "../model/agent.js";
39
+ } from "@forwardimpact/model/agent";
37
40
  import { formatAgentProfile } from "../formatters/agent/profile.js";
38
41
  import { formatAgentSkill } from "../formatters/agent/skill.js";
39
42
  import { formatError, formatSuccess } from "../lib/cli-output.js";
@@ -18,7 +18,7 @@ import {
18
18
  formatSubheader,
19
19
  formatBullet,
20
20
  } from "../lib/cli-output.js";
21
- import { getConceptEmoji } from "../model/levels.js";
21
+ import { getConceptEmoji } from "@forwardimpact/schema/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 "../model/levels.js";
16
+ import { getConceptEmoji } from "@forwardimpact/schema/levels";
17
17
  import { capitalize } from "../formatters/shared.js";
18
18
 
19
19
  /**
@@ -12,14 +12,14 @@
12
12
  * npx pathway job --validate # Validation checks
13
13
  */
14
14
 
15
- import { prepareJobDetail } from "../model/job.js";
15
+ import { prepareJobDetail } from "@forwardimpact/model/job";
16
16
  import { jobToMarkdown } from "../formatters/job/markdown.js";
17
- import { generateAllJobs } from "../model/derivation.js";
17
+ import { generateAllJobs } from "@forwardimpact/model/derivation";
18
18
  import { formatTable } from "../lib/cli-output.js";
19
19
  import {
20
20
  deriveChecklist,
21
21
  formatChecklistMarkdown,
22
- } from "../model/checklist.js";
22
+ } from "@forwardimpact/model/checklist";
23
23
  import { loadJobTemplate } from "../lib/template-loader.js";
24
24
 
25
25
  /**
@@ -9,14 +9,30 @@ 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 "../model/index-generator.js";
13
- import { loadFrameworkConfig } from "../model/loader.js";
12
+ import { generateAllIndexes } from "@forwardimpact/schema/index-generator";
13
+ import { loadFrameworkConfig } from "@forwardimpact/schema/loader";
14
14
 
15
15
  const __filename = fileURLToPath(import.meta.url);
16
16
  const __dirname = dirname(__filename);
17
17
  const publicDir = join(__dirname, "..");
18
18
  const rootDir = join(__dirname, "../..");
19
19
 
20
+ /**
21
+ * Resolve package directory using Node's module resolution.
22
+ * Works in both monorepo (development) and installed (production) contexts.
23
+ * @param {string} packageName - Package specifier (e.g., '@forwardimpact/schema')
24
+ * @returns {string} Absolute path to package lib directory
25
+ */
26
+ function resolvePackageLib(packageName) {
27
+ // import.meta.resolve returns file:// URL to package's main entry (lib/index.js)
28
+ const mainUrl = import.meta.resolve(packageName);
29
+ // Convert to path and get lib directory
30
+ return dirname(fileURLToPath(mainUrl));
31
+ }
32
+
33
+ const schemaLibDir = resolvePackageLib("@forwardimpact/schema");
34
+ const modelLibDir = resolvePackageLib("@forwardimpact/model");
35
+
20
36
  const MIME_TYPES = {
21
37
  ".html": "text/html; charset=utf-8",
22
38
  ".css": "text/css; charset=utf-8",
@@ -118,6 +134,12 @@ export async function runServeCommand({ dataDir, options }) {
118
134
  } else if (pathname.startsWith("/templates/")) {
119
135
  // Serve from templates directory
120
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));
140
+ } else if (pathname.startsWith("/model/lib/")) {
141
+ // Serve @forwardimpact/model package files (resolved via Node module resolution)
142
+ filePath = join(modelLibDir, pathname.slice(11));
121
143
  } else if (pathname === "/" || pathname === "") {
122
144
  // Serve index.html for root
123
145
  filePath = join(publicDir, "index.html");
@@ -8,8 +8,8 @@
8
8
  import { cp, mkdir, rm, access, realpath } from "fs/promises";
9
9
  import { join, dirname, relative, resolve } from "path";
10
10
  import { fileURLToPath } from "url";
11
- import { generateAllIndexes } from "../model/index-generator.js";
12
- import { loadFrameworkConfig } from "../model/loader.js";
11
+ import { generateAllIndexes } from "@forwardimpact/schema/index-generator";
12
+ import { loadFrameworkConfig } from "@forwardimpact/schema/loader";
13
13
 
14
14
  const __filename = fileURLToPath(import.meta.url);
15
15
  const __dirname = dirname(__filename);
@@ -14,9 +14,9 @@
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 "../model/levels.js";
17
+ import { getConceptEmoji } from "@forwardimpact/schema/levels";
18
18
  import { formatTable, formatError } from "../lib/cli-output.js";
19
- import { generateSkillMd } from "../model/agent.js";
19
+ import { generateSkillMd } from "@forwardimpact/model/agent";
20
20
  import { formatAgentSkill } from "../formatters/agent/skill.js";
21
21
  import { loadSkillTemplate } from "../lib/template-loader.js";
22
22
 
@@ -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 "../model/levels.js";
17
+ import { getConceptEmoji } from "@forwardimpact/schema/levels";
18
18
 
19
19
  /**
20
20
  * Format track summary output
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  import { div, span, details, summary } from "../lib/render.js";
9
- import { getCapabilityEmoji } from "../model/levels.js";
9
+ import { getCapabilityEmoji } from "@forwardimpact/schema/levels";
10
10
 
11
11
  /**
12
12
  * Create checklist display grouped by capability
@@ -13,7 +13,7 @@ import {
13
13
  getBehaviourMaturityIndex,
14
14
  formatLevel,
15
15
  } from "../lib/render.js";
16
- import { getCapabilityIndex } from "../model/levels.js";
16
+ import { getCapabilityIndex } from "@forwardimpact/schema/levels";
17
17
 
18
18
  /**
19
19
  * Create a comparison skill radar chart
@@ -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 "../model/levels.js";
26
+ } from "@forwardimpact/schema/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 "../model/levels.js";
21
+ import { SKILL_LEVEL_ORDER } from "@forwardimpact/schema/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 "../../model/levels.js";
24
+ } from "@forwardimpact/schema/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 "../../model/levels.js";
21
+ import { getConceptEmoji } from "@forwardimpact/schema/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 "../../model/levels.js";
8
+ import { getConceptEmoji } from "@forwardimpact/schema/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 "../../model/levels.js";
25
+ } from "@forwardimpact/schema/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 "../../model/levels.js";
7
+ import { getConceptEmoji } from "@forwardimpact/schema/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 "../../model/levels.js";
8
+ import { getConceptEmoji } from "@forwardimpact/schema/levels";
9
9
 
10
10
  /**
11
11
  * Format interview detail as DOM elements