@forwardimpact/pathway 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +104 -0
- package/app/commands/agent.js +430 -0
- package/app/commands/behaviour.js +61 -0
- package/app/commands/command-factory.js +211 -0
- package/app/commands/discipline.js +58 -0
- package/app/commands/driver.js +94 -0
- package/app/commands/grade.js +60 -0
- package/app/commands/index.js +20 -0
- package/app/commands/init.js +67 -0
- package/app/commands/interview.js +68 -0
- package/app/commands/job.js +157 -0
- package/app/commands/progress.js +77 -0
- package/app/commands/questions.js +179 -0
- package/app/commands/serve.js +143 -0
- package/app/commands/site.js +121 -0
- package/app/commands/skill.js +76 -0
- package/app/commands/stage.js +129 -0
- package/app/commands/track.js +70 -0
- package/app/components/action-buttons.js +66 -0
- package/app/components/behaviour-profile.js +53 -0
- package/app/components/builder.js +341 -0
- package/app/components/card.js +98 -0
- package/app/components/checklist.js +145 -0
- package/app/components/comparison-radar.js +237 -0
- package/app/components/detail.js +230 -0
- package/app/components/error-page.js +72 -0
- package/app/components/grid.js +109 -0
- package/app/components/list.js +120 -0
- package/app/components/modifier-table.js +142 -0
- package/app/components/nav.js +64 -0
- package/app/components/progression-table.js +320 -0
- package/app/components/radar-chart.js +102 -0
- package/app/components/skill-matrix.js +97 -0
- package/app/css/base.css +56 -0
- package/app/css/bundles/app.css +40 -0
- package/app/css/bundles/handout.css +43 -0
- package/app/css/bundles/slides.css +40 -0
- package/app/css/components/badges.css +215 -0
- package/app/css/components/buttons.css +101 -0
- package/app/css/components/forms.css +105 -0
- package/app/css/components/layout.css +209 -0
- package/app/css/components/nav.css +166 -0
- package/app/css/components/progress.css +166 -0
- package/app/css/components/states.css +82 -0
- package/app/css/components/surfaces.css +243 -0
- package/app/css/components/tables.css +362 -0
- package/app/css/components/typography.css +122 -0
- package/app/css/components/utilities.css +41 -0
- package/app/css/pages/agent-builder.css +391 -0
- package/app/css/pages/assessment-results.css +453 -0
- package/app/css/pages/detail.css +59 -0
- package/app/css/pages/interview-builder.css +148 -0
- package/app/css/pages/job-builder.css +134 -0
- package/app/css/pages/landing.css +92 -0
- package/app/css/pages/lifecycle.css +118 -0
- package/app/css/pages/progress-builder.css +274 -0
- package/app/css/pages/self-assessment.css +502 -0
- package/app/css/reset.css +50 -0
- package/app/css/tokens.css +153 -0
- package/app/css/views/handout.css +30 -0
- package/app/css/views/print.css +608 -0
- package/app/css/views/slide-animations.css +113 -0
- package/app/css/views/slide-base.css +330 -0
- package/app/css/views/slide-sections.css +597 -0
- package/app/css/views/slide-tables.css +275 -0
- package/app/formatters/agent/dom.js +540 -0
- package/app/formatters/agent/profile.js +133 -0
- package/app/formatters/agent/skill.js +58 -0
- package/app/formatters/behaviour/dom.js +91 -0
- package/app/formatters/behaviour/markdown.js +54 -0
- package/app/formatters/behaviour/shared.js +64 -0
- package/app/formatters/discipline/dom.js +187 -0
- package/app/formatters/discipline/markdown.js +87 -0
- package/app/formatters/discipline/shared.js +131 -0
- package/app/formatters/driver/dom.js +103 -0
- package/app/formatters/driver/shared.js +92 -0
- package/app/formatters/grade/dom.js +208 -0
- package/app/formatters/grade/markdown.js +94 -0
- package/app/formatters/grade/shared.js +86 -0
- package/app/formatters/index.js +50 -0
- package/app/formatters/interview/dom.js +97 -0
- package/app/formatters/interview/markdown.js +66 -0
- package/app/formatters/interview/shared.js +332 -0
- package/app/formatters/job/description.js +176 -0
- package/app/formatters/job/dom.js +411 -0
- package/app/formatters/job/markdown.js +102 -0
- package/app/formatters/progress/dom.js +135 -0
- package/app/formatters/progress/markdown.js +86 -0
- package/app/formatters/progress/shared.js +339 -0
- package/app/formatters/questions/json.js +43 -0
- package/app/formatters/questions/markdown.js +303 -0
- package/app/formatters/questions/shared.js +274 -0
- package/app/formatters/questions/yaml.js +76 -0
- package/app/formatters/shared.js +71 -0
- package/app/formatters/skill/dom.js +168 -0
- package/app/formatters/skill/markdown.js +109 -0
- package/app/formatters/skill/shared.js +125 -0
- package/app/formatters/stage/dom.js +135 -0
- package/app/formatters/stage/index.js +12 -0
- package/app/formatters/stage/shared.js +111 -0
- package/app/formatters/track/dom.js +128 -0
- package/app/formatters/track/markdown.js +105 -0
- package/app/formatters/track/shared.js +181 -0
- package/app/handout-main.js +421 -0
- package/app/handout.html +21 -0
- package/app/index.html +59 -0
- package/app/lib/card-mappers.js +173 -0
- package/app/lib/cli-output.js +270 -0
- package/app/lib/error-boundary.js +70 -0
- package/app/lib/errors.js +49 -0
- package/app/lib/form-controls.js +47 -0
- package/app/lib/job-cache.js +86 -0
- package/app/lib/markdown.js +114 -0
- package/app/lib/radar.js +866 -0
- package/app/lib/reactive.js +77 -0
- package/app/lib/render.js +212 -0
- package/app/lib/router-core.js +160 -0
- package/app/lib/router-pages.js +16 -0
- package/app/lib/router-slides.js +202 -0
- package/app/lib/state.js +148 -0
- package/app/lib/utils.js +14 -0
- package/app/lib/yaml-loader.js +327 -0
- package/app/main.js +213 -0
- package/app/model/agent.js +702 -0
- package/app/model/checklist.js +137 -0
- package/app/model/derivation.js +699 -0
- package/app/model/index-generator.js +71 -0
- package/app/model/interview.js +539 -0
- package/app/model/job.js +222 -0
- package/app/model/levels.js +591 -0
- package/app/model/loader.js +564 -0
- package/app/model/matching.js +858 -0
- package/app/model/modifiers.js +158 -0
- package/app/model/profile.js +266 -0
- package/app/model/progression.js +507 -0
- package/app/model/validation.js +1385 -0
- package/app/pages/agent-builder.js +823 -0
- package/app/pages/assessment-results.js +507 -0
- package/app/pages/behaviour.js +70 -0
- package/app/pages/discipline.js +71 -0
- package/app/pages/driver.js +106 -0
- package/app/pages/grade.js +117 -0
- package/app/pages/interview-builder.js +50 -0
- package/app/pages/interview.js +304 -0
- package/app/pages/job-builder.js +50 -0
- package/app/pages/job.js +58 -0
- package/app/pages/landing.js +305 -0
- package/app/pages/progress-builder.js +58 -0
- package/app/pages/progress.js +495 -0
- package/app/pages/self-assessment.js +729 -0
- package/app/pages/skill.js +113 -0
- package/app/pages/stage.js +231 -0
- package/app/pages/track.js +69 -0
- package/app/slide-main.js +360 -0
- package/app/slides/behaviour.js +38 -0
- package/app/slides/chapter.js +82 -0
- package/app/slides/discipline.js +40 -0
- package/app/slides/driver.js +39 -0
- package/app/slides/grade.js +32 -0
- package/app/slides/index.js +198 -0
- package/app/slides/interview.js +58 -0
- package/app/slides/job.js +55 -0
- package/app/slides/overview.js +126 -0
- package/app/slides/progress.js +83 -0
- package/app/slides/skill.js +40 -0
- package/app/slides/track.js +39 -0
- package/app/slides.html +56 -0
- package/app/types.js +147 -0
- package/bin/pathway.js +489 -0
- package/examples/agents/.claude/skills/architecture-design/SKILL.md +88 -0
- package/examples/agents/.claude/skills/cloud-platforms/SKILL.md +90 -0
- package/examples/agents/.claude/skills/code-quality-review/SKILL.md +67 -0
- package/examples/agents/.claude/skills/data-modeling/SKILL.md +99 -0
- package/examples/agents/.claude/skills/developer-experience/SKILL.md +99 -0
- package/examples/agents/.claude/skills/devops-cicd/SKILL.md +96 -0
- package/examples/agents/.claude/skills/full-stack-development/SKILL.md +90 -0
- package/examples/agents/.claude/skills/knowledge-management/SKILL.md +100 -0
- package/examples/agents/.claude/skills/pattern-generalization/SKILL.md +102 -0
- package/examples/agents/.claude/skills/sre-practices/SKILL.md +117 -0
- package/examples/agents/.claude/skills/technical-debt-management/SKILL.md +123 -0
- package/examples/agents/.claude/skills/technical-writing/SKILL.md +129 -0
- package/examples/agents/.github/agents/se-platform-code.agent.md +181 -0
- package/examples/agents/.github/agents/se-platform-plan.agent.md +178 -0
- package/examples/agents/.github/agents/se-platform-review.agent.md +113 -0
- package/examples/agents/.vscode/settings.json +8 -0
- package/examples/behaviours/_index.yaml +8 -0
- package/examples/behaviours/outcome_ownership.yaml +44 -0
- package/examples/behaviours/polymathic_knowledge.yaml +42 -0
- package/examples/behaviours/precise_communication.yaml +40 -0
- package/examples/behaviours/relentless_curiosity.yaml +38 -0
- package/examples/behaviours/systems_thinking.yaml +41 -0
- package/examples/capabilities/_index.yaml +8 -0
- package/examples/capabilities/business.yaml +251 -0
- package/examples/capabilities/delivery.yaml +352 -0
- package/examples/capabilities/people.yaml +100 -0
- package/examples/capabilities/reliability.yaml +318 -0
- package/examples/capabilities/scale.yaml +394 -0
- package/examples/disciplines/_index.yaml +5 -0
- package/examples/disciplines/data_engineering.yaml +76 -0
- package/examples/disciplines/software_engineering.yaml +76 -0
- package/examples/drivers.yaml +205 -0
- package/examples/framework.yaml +58 -0
- package/examples/grades.yaml +118 -0
- package/examples/questions/behaviours/outcome_ownership.yaml +52 -0
- package/examples/questions/behaviours/polymathic_knowledge.yaml +48 -0
- package/examples/questions/behaviours/precise_communication.yaml +55 -0
- package/examples/questions/behaviours/relentless_curiosity.yaml +51 -0
- package/examples/questions/behaviours/systems_thinking.yaml +53 -0
- package/examples/questions/skills/architecture_design.yaml +54 -0
- package/examples/questions/skills/cloud_platforms.yaml +48 -0
- package/examples/questions/skills/code_quality.yaml +49 -0
- package/examples/questions/skills/data_modeling.yaml +46 -0
- package/examples/questions/skills/devops.yaml +47 -0
- package/examples/questions/skills/full_stack_development.yaml +48 -0
- package/examples/questions/skills/sre_practices.yaml +44 -0
- package/examples/questions/skills/stakeholder_management.yaml +49 -0
- package/examples/questions/skills/team_collaboration.yaml +43 -0
- package/examples/questions/skills/technical_writing.yaml +43 -0
- package/examples/self-assessments.yaml +66 -0
- package/examples/stages.yaml +76 -0
- package/examples/tracks/_index.yaml +6 -0
- package/examples/tracks/manager.yaml +53 -0
- package/examples/tracks/platform.yaml +54 -0
- package/examples/tracks/sre.yaml +58 -0
- package/examples/vscode-settings.yaml +22 -0
- package/package.json +68 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discipline CLI Command
|
|
3
|
+
*
|
|
4
|
+
* Handles discipline summary, listing, and detail display in the terminal.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* npx pathway discipline # Summary with stats
|
|
8
|
+
* npx pathway discipline --list # IDs only (for piping)
|
|
9
|
+
* npx pathway discipline <id> # Detail view
|
|
10
|
+
* npx pathway discipline --validate # Validation checks
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { createEntityCommand } from "./command-factory.js";
|
|
14
|
+
import { disciplineToMarkdown } from "../formatters/discipline/markdown.js";
|
|
15
|
+
import { formatTable } from "../lib/cli-output.js";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Format discipline summary output
|
|
19
|
+
* @param {Array} disciplines - Raw discipline entities
|
|
20
|
+
*/
|
|
21
|
+
function formatSummary(disciplines) {
|
|
22
|
+
console.log(`\n📋 Disciplines\n`);
|
|
23
|
+
|
|
24
|
+
const rows = disciplines.map((d) => [
|
|
25
|
+
d.id,
|
|
26
|
+
d.coreSkills?.length || 0,
|
|
27
|
+
d.supportingSkills?.length || 0,
|
|
28
|
+
d.broadSkills?.length || 0,
|
|
29
|
+
]);
|
|
30
|
+
|
|
31
|
+
console.log(formatTable(["ID", "Core", "Supporting", "Broad"], rows));
|
|
32
|
+
console.log(`\nTotal: ${disciplines.length} disciplines`);
|
|
33
|
+
console.log(`\nRun 'npx pathway discipline --list' for IDs`);
|
|
34
|
+
console.log(`Run 'npx pathway discipline <id>' for details\n`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Format discipline detail output
|
|
39
|
+
* @param {Object} viewAndContext - Contains discipline entity and context
|
|
40
|
+
*/
|
|
41
|
+
function formatDetail(viewAndContext) {
|
|
42
|
+
const { discipline, skills, behaviours } = viewAndContext;
|
|
43
|
+
console.log(disciplineToMarkdown(discipline, { skills, behaviours }));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const runDisciplineCommand = createEntityCommand({
|
|
47
|
+
entityName: "discipline",
|
|
48
|
+
pluralName: "disciplines",
|
|
49
|
+
findEntity: (data, id) => data.disciplines.find((d) => d.id === id),
|
|
50
|
+
presentDetail: (entity, data) => ({
|
|
51
|
+
discipline: entity,
|
|
52
|
+
skills: data.skills,
|
|
53
|
+
behaviours: data.behaviours,
|
|
54
|
+
}),
|
|
55
|
+
formatSummary,
|
|
56
|
+
formatDetail,
|
|
57
|
+
emoji: "📋",
|
|
58
|
+
});
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Driver CLI Command
|
|
3
|
+
*
|
|
4
|
+
* Handles driver summary, listing, and detail display in the terminal.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* npx pathway driver # Summary with stats
|
|
8
|
+
* npx pathway driver --list # IDs only (for piping)
|
|
9
|
+
* npx pathway driver <id> # Detail view
|
|
10
|
+
* npx pathway driver --validate # Validation checks
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { createEntityCommand } from "./command-factory.js";
|
|
14
|
+
import { prepareDriverDetail } from "../formatters/driver/shared.js";
|
|
15
|
+
import { formatTable } from "../lib/cli-output.js";
|
|
16
|
+
import {
|
|
17
|
+
formatHeader,
|
|
18
|
+
formatSubheader,
|
|
19
|
+
formatBullet,
|
|
20
|
+
} from "../lib/cli-output.js";
|
|
21
|
+
import { getConceptEmoji } from "../model/levels.js";
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Format driver summary output
|
|
25
|
+
* @param {Array} drivers - Raw driver entities
|
|
26
|
+
* @param {Object} data - Full data context
|
|
27
|
+
*/
|
|
28
|
+
function formatSummary(drivers, data) {
|
|
29
|
+
const { skills, behaviours, framework } = data;
|
|
30
|
+
const emoji = framework ? getConceptEmoji(framework, "driver") : "🎯";
|
|
31
|
+
|
|
32
|
+
console.log(`\n${emoji} Drivers\n`);
|
|
33
|
+
|
|
34
|
+
const rows = drivers.map((d) => {
|
|
35
|
+
const contributingSkills = skills.filter((s) =>
|
|
36
|
+
d.contributingSkills?.includes(s.id),
|
|
37
|
+
).length;
|
|
38
|
+
const contributingBehaviours = behaviours.filter((b) =>
|
|
39
|
+
d.contributingBehaviours?.includes(b.id),
|
|
40
|
+
).length;
|
|
41
|
+
return [d.id, d.name, contributingSkills, contributingBehaviours];
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
console.log(formatTable(["ID", "Name", "Skills", "Behaviours"], rows));
|
|
45
|
+
console.log(`\nTotal: ${drivers.length} drivers`);
|
|
46
|
+
console.log(`\nRun 'npx pathway driver --list' for IDs`);
|
|
47
|
+
console.log(`Run 'npx pathway driver <id>' for details\n`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Format driver detail output
|
|
52
|
+
* @param {Object} viewAndContext - Contains driver entity and context
|
|
53
|
+
* @param {Object} framework - Framework config
|
|
54
|
+
*/
|
|
55
|
+
function formatDetail(viewAndContext, framework) {
|
|
56
|
+
const { driver, skills, behaviours } = viewAndContext;
|
|
57
|
+
const view = prepareDriverDetail(driver, { skills, behaviours });
|
|
58
|
+
const emoji = framework ? getConceptEmoji(framework, "driver") : "🎯";
|
|
59
|
+
|
|
60
|
+
console.log(formatHeader(`\n${emoji} ${view.name}\n`));
|
|
61
|
+
console.log(`${view.description}\n`);
|
|
62
|
+
|
|
63
|
+
// Contributing skills
|
|
64
|
+
if (view.contributingSkills.length > 0) {
|
|
65
|
+
console.log(formatSubheader("Contributing Skills\n"));
|
|
66
|
+
for (const s of view.contributingSkills) {
|
|
67
|
+
console.log(formatBullet(s.name, 1));
|
|
68
|
+
}
|
|
69
|
+
console.log();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Contributing behaviours
|
|
73
|
+
if (view.contributingBehaviours.length > 0) {
|
|
74
|
+
console.log(formatSubheader("Contributing Behaviours\n"));
|
|
75
|
+
for (const b of view.contributingBehaviours) {
|
|
76
|
+
console.log(formatBullet(b.name, 1));
|
|
77
|
+
}
|
|
78
|
+
console.log();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export const runDriverCommand = createEntityCommand({
|
|
83
|
+
entityName: "driver",
|
|
84
|
+
pluralName: "drivers",
|
|
85
|
+
findEntity: (data, id) => data.drivers.find((d) => d.id === id),
|
|
86
|
+
presentDetail: (entity, data) => ({
|
|
87
|
+
driver: entity,
|
|
88
|
+
skills: data.skills,
|
|
89
|
+
behaviours: data.behaviours,
|
|
90
|
+
}),
|
|
91
|
+
formatSummary,
|
|
92
|
+
formatDetail,
|
|
93
|
+
emoji: "🎯",
|
|
94
|
+
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Grade CLI Command
|
|
3
|
+
*
|
|
4
|
+
* Handles grade summary, listing, and detail display in the terminal.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* npx pathway grade # Summary with stats
|
|
8
|
+
* npx pathway grade --list # IDs only (for piping)
|
|
9
|
+
* npx pathway grade <id> # Detail view
|
|
10
|
+
* npx pathway grade --validate # Validation checks
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { createEntityCommand } from "./command-factory.js";
|
|
14
|
+
import { gradeToMarkdown } from "../formatters/grade/markdown.js";
|
|
15
|
+
import { formatTable } from "../lib/cli-output.js";
|
|
16
|
+
import { getConceptEmoji } from "../model/levels.js";
|
|
17
|
+
import { capitalize } from "../formatters/shared.js";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Format grade summary output
|
|
21
|
+
* @param {Array} grades - Raw grade entities
|
|
22
|
+
* @param {Object} data - Full data context
|
|
23
|
+
*/
|
|
24
|
+
function formatSummary(grades, data) {
|
|
25
|
+
const { framework } = data;
|
|
26
|
+
const emoji = framework ? getConceptEmoji(framework, "grade") : "📊";
|
|
27
|
+
|
|
28
|
+
console.log(`\n${emoji} Grades\n`);
|
|
29
|
+
|
|
30
|
+
const rows = grades.map((g) => [
|
|
31
|
+
g.id,
|
|
32
|
+
g.displayName || g.id,
|
|
33
|
+
g.typicalExperienceRange || "-",
|
|
34
|
+
capitalize(g.baseSkillLevels?.primary || "-"),
|
|
35
|
+
]);
|
|
36
|
+
|
|
37
|
+
console.log(formatTable(["ID", "Name", "Experience", "Primary Level"], rows));
|
|
38
|
+
console.log(`\nTotal: ${grades.length} grades`);
|
|
39
|
+
console.log(`\nRun 'npx pathway grade --list' for IDs`);
|
|
40
|
+
console.log(`Run 'npx pathway grade <id>' for details\n`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Format grade detail output
|
|
45
|
+
* @param {Object} grade - Raw grade entity
|
|
46
|
+
* @param {Object} framework - Framework config
|
|
47
|
+
*/
|
|
48
|
+
function formatDetail(grade, framework) {
|
|
49
|
+
console.log(gradeToMarkdown(grade, framework));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const runGradeCommand = createEntityCommand({
|
|
53
|
+
entityName: "grade",
|
|
54
|
+
pluralName: "grades",
|
|
55
|
+
findEntity: (data, id) => data.grades.find((g) => g.id === id),
|
|
56
|
+
presentDetail: (entity) => entity,
|
|
57
|
+
formatSummary,
|
|
58
|
+
formatDetail,
|
|
59
|
+
emoji: "📊",
|
|
60
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Commands Index
|
|
3
|
+
*
|
|
4
|
+
* Re-exports all command handlers for convenient importing.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export { runSkillCommand } from "./skill.js";
|
|
8
|
+
export { runBehaviourCommand } from "./behaviour.js";
|
|
9
|
+
export { runDriverCommand } from "./driver.js";
|
|
10
|
+
export { runDisciplineCommand } from "./discipline.js";
|
|
11
|
+
export { runGradeCommand } from "./grade.js";
|
|
12
|
+
export { runTrackCommand } from "./track.js";
|
|
13
|
+
export { runStageCommand } from "./stage.js";
|
|
14
|
+
export { runJobCommand } from "./job.js";
|
|
15
|
+
export { runInterviewCommand } from "./interview.js";
|
|
16
|
+
export { runProgressCommand } from "./progress.js";
|
|
17
|
+
export { runQuestionsCommand } from "./questions.js";
|
|
18
|
+
export { runServeCommand } from "./serve.js";
|
|
19
|
+
export { runInitCommand } from "./init.js";
|
|
20
|
+
export { runSiteCommand } from "./site.js";
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Init Command
|
|
3
|
+
*
|
|
4
|
+
* Initializes a new Engineering Pathway project by copying example data.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { cp, access } from "fs/promises";
|
|
8
|
+
import { join, dirname } from "path";
|
|
9
|
+
import { fileURLToPath } from "url";
|
|
10
|
+
|
|
11
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
12
|
+
const __dirname = dirname(__filename);
|
|
13
|
+
const examplesDir = join(__dirname, "..", "..", "examples");
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Run the init command
|
|
17
|
+
* @param {Object} params - Command parameters
|
|
18
|
+
* @param {Object} params.options - Command options
|
|
19
|
+
*/
|
|
20
|
+
export async function runInitCommand({ options }) {
|
|
21
|
+
const targetPath = options.path || process.cwd();
|
|
22
|
+
const dataDir = join(targetPath, "data");
|
|
23
|
+
|
|
24
|
+
// Check if data/ already exists
|
|
25
|
+
try {
|
|
26
|
+
await access(dataDir);
|
|
27
|
+
console.error("Error: ./data/ already exists.");
|
|
28
|
+
console.error("Remove it first or use a different directory.");
|
|
29
|
+
process.exit(1);
|
|
30
|
+
} catch {
|
|
31
|
+
// Directory doesn't exist, proceed
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Check if examples directory exists
|
|
35
|
+
try {
|
|
36
|
+
await access(examplesDir);
|
|
37
|
+
} catch {
|
|
38
|
+
console.error("Error: Examples directory not found in package.");
|
|
39
|
+
console.error("This may indicate a corrupted package installation.");
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Copy example data
|
|
44
|
+
console.log("Creating ./data/ with example data...\n");
|
|
45
|
+
await cp(examplesDir, dataDir, { recursive: true });
|
|
46
|
+
|
|
47
|
+
console.log(`✅ Created ./data/ with example data.
|
|
48
|
+
|
|
49
|
+
Next steps:
|
|
50
|
+
1. Edit data files to match your organization
|
|
51
|
+
2. npx pathway --validate
|
|
52
|
+
3. npx pathway serve
|
|
53
|
+
|
|
54
|
+
Data structure:
|
|
55
|
+
data/
|
|
56
|
+
├── framework.yaml # Framework metadata
|
|
57
|
+
├── grades.yaml # Career levels
|
|
58
|
+
├── stages.yaml # Lifecycle stages
|
|
59
|
+
├── drivers.yaml # Business drivers
|
|
60
|
+
├── capabilities.yaml # Capability areas
|
|
61
|
+
├── disciplines/ # Engineering disciplines
|
|
62
|
+
├── tracks/ # Role tracks
|
|
63
|
+
├── skills/ # Technical skills
|
|
64
|
+
├── behaviours/ # Behavioural expectations
|
|
65
|
+
└── questions/ # Interview questions
|
|
66
|
+
`);
|
|
67
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interview CLI Command
|
|
3
|
+
*
|
|
4
|
+
* Generates and displays interview questions in the terminal.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { createCompositeCommand } from "./command-factory.js";
|
|
8
|
+
import {
|
|
9
|
+
prepareInterviewDetail,
|
|
10
|
+
INTERVIEW_TYPES,
|
|
11
|
+
} from "../formatters/interview/shared.js";
|
|
12
|
+
import { interviewToMarkdown } from "../formatters/interview/markdown.js";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Format interview output
|
|
16
|
+
* @param {Object} view - Presenter view
|
|
17
|
+
* @param {Object} options - Options including framework
|
|
18
|
+
*/
|
|
19
|
+
function formatInterview(view, options) {
|
|
20
|
+
console.log(interviewToMarkdown(view, { framework: options.framework }));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const runInterviewCommand = createCompositeCommand({
|
|
24
|
+
commandName: "interview",
|
|
25
|
+
requiredArgs: ["discipline_id", "track_id", "grade_id"],
|
|
26
|
+
findEntities: (data, args, options) => {
|
|
27
|
+
const interviewType = options.type || "full";
|
|
28
|
+
|
|
29
|
+
if (!INTERVIEW_TYPES[interviewType]) {
|
|
30
|
+
console.error(`Unknown interview type: ${interviewType}`);
|
|
31
|
+
console.error("Available types: full, short, behaviour");
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
discipline: data.disciplines.find((d) => d.id === args[0]),
|
|
37
|
+
track: data.tracks.find((t) => t.id === args[1]),
|
|
38
|
+
grade: data.grades.find((g) => g.id === args[2]),
|
|
39
|
+
interviewType,
|
|
40
|
+
};
|
|
41
|
+
},
|
|
42
|
+
validateEntities: (entities, _data) => {
|
|
43
|
+
if (!entities.discipline) {
|
|
44
|
+
return `Discipline not found: ${entities.discipline}`;
|
|
45
|
+
}
|
|
46
|
+
if (!entities.grade) {
|
|
47
|
+
return `Grade not found: ${entities.grade}`;
|
|
48
|
+
}
|
|
49
|
+
if (!entities.track) {
|
|
50
|
+
return `Track not found: ${entities.track}`;
|
|
51
|
+
}
|
|
52
|
+
return null;
|
|
53
|
+
},
|
|
54
|
+
presenter: (entities, data, _options) =>
|
|
55
|
+
prepareInterviewDetail({
|
|
56
|
+
discipline: entities.discipline,
|
|
57
|
+
grade: entities.grade,
|
|
58
|
+
track: entities.track,
|
|
59
|
+
skills: data.skills,
|
|
60
|
+
behaviours: data.behaviours,
|
|
61
|
+
questions: data.questions,
|
|
62
|
+
interviewType: entities.interviewType,
|
|
63
|
+
}),
|
|
64
|
+
formatter: (view, options, data) =>
|
|
65
|
+
formatInterview(view, { ...options, framework: data.framework }),
|
|
66
|
+
usageExample:
|
|
67
|
+
"npx pathway interview software_engineering platform L4 --type=short",
|
|
68
|
+
});
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Job CLI Command
|
|
3
|
+
*
|
|
4
|
+
* Generates and displays job definitions in the terminal.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* npx pathway job # Summary with stats
|
|
8
|
+
* npx pathway job --list # All valid combinations (for piping)
|
|
9
|
+
* npx pathway job <discipline> <track> <grade> # Detail view
|
|
10
|
+
* npx pathway job se platform L3 --checklist=code_to_review # Show checklist for handoff
|
|
11
|
+
* npx pathway job --validate # Validation checks
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { prepareJobDetail } from "../model/job.js";
|
|
15
|
+
import { jobToMarkdown } from "../formatters/job/markdown.js";
|
|
16
|
+
import { generateAllJobs } from "../model/derivation.js";
|
|
17
|
+
import { formatTable } from "../lib/cli-output.js";
|
|
18
|
+
import {
|
|
19
|
+
deriveChecklist,
|
|
20
|
+
formatChecklistMarkdown,
|
|
21
|
+
} from "../model/checklist.js";
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Format job output
|
|
25
|
+
* @param {Object} view - Presenter view
|
|
26
|
+
* @param {Object} _options - Command options
|
|
27
|
+
* @param {Object} entities - Original entities
|
|
28
|
+
*/
|
|
29
|
+
function formatJob(view, _options, entities) {
|
|
30
|
+
console.log(jobToMarkdown(view, entities));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Run job command
|
|
35
|
+
* @param {Object} params
|
|
36
|
+
* @param {Object} params.data - All loaded data
|
|
37
|
+
* @param {string[]} params.args - Command arguments
|
|
38
|
+
* @param {Object} params.options - Command options
|
|
39
|
+
*/
|
|
40
|
+
export async function runJobCommand({ data, args, options }) {
|
|
41
|
+
const jobs = generateAllJobs({
|
|
42
|
+
disciplines: data.disciplines,
|
|
43
|
+
grades: data.grades,
|
|
44
|
+
tracks: data.tracks,
|
|
45
|
+
skills: data.skills,
|
|
46
|
+
behaviours: data.behaviours,
|
|
47
|
+
validationRules: data.framework.validationRules,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// --list: Output clean lines for piping
|
|
51
|
+
if (options.list) {
|
|
52
|
+
for (const job of jobs) {
|
|
53
|
+
console.log(`${job.discipline.id} ${job.track.id} ${job.grade.id}`);
|
|
54
|
+
}
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// No args: Show summary
|
|
59
|
+
if (args.length === 0) {
|
|
60
|
+
console.log(`\n💼 Jobs\n`);
|
|
61
|
+
|
|
62
|
+
// Count by discipline
|
|
63
|
+
const byDiscipline = {};
|
|
64
|
+
for (const job of jobs) {
|
|
65
|
+
byDiscipline[job.discipline.id] =
|
|
66
|
+
(byDiscipline[job.discipline.id] || 0) + 1;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const rows = Object.entries(byDiscipline).map(([id, count]) => [id, count]);
|
|
70
|
+
console.log(formatTable(["Discipline", "Combinations"], rows));
|
|
71
|
+
console.log(`\nTotal: ${jobs.length} valid job combinations`);
|
|
72
|
+
console.log(`\nRun 'npx pathway job --list' for all combinations`);
|
|
73
|
+
console.log(
|
|
74
|
+
`Run 'npx pathway job <discipline> <track> <grade>' for details\n`,
|
|
75
|
+
);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Handle job detail view
|
|
80
|
+
if (args.length < 3) {
|
|
81
|
+
console.error("Usage: npx pathway job <discipline> <track> <grade>");
|
|
82
|
+
console.error(" npx pathway job --list");
|
|
83
|
+
console.error("Example: npx pathway job software_engineering platform L4");
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const discipline = data.disciplines.find((d) => d.id === args[0]);
|
|
88
|
+
const track = data.tracks.find((t) => t.id === args[1]);
|
|
89
|
+
const grade = data.grades.find((g) => g.id === args[2]);
|
|
90
|
+
|
|
91
|
+
if (!discipline) {
|
|
92
|
+
console.error(`Discipline not found: ${args[0]}`);
|
|
93
|
+
console.error(`Available: ${data.disciplines.map((d) => d.id).join(", ")}`);
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (!track) {
|
|
98
|
+
console.error(`Track not found: ${args[1]}`);
|
|
99
|
+
console.error(`Available: ${data.tracks.map((t) => t.id).join(", ")}`);
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (!grade) {
|
|
104
|
+
console.error(`Grade not found: ${args[2]}`);
|
|
105
|
+
console.error(`Available: ${data.grades.map((g) => g.id).join(", ")}`);
|
|
106
|
+
process.exit(1);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const view = prepareJobDetail({
|
|
110
|
+
discipline,
|
|
111
|
+
grade,
|
|
112
|
+
track,
|
|
113
|
+
skills: data.skills,
|
|
114
|
+
behaviours: data.behaviours,
|
|
115
|
+
drivers: data.drivers,
|
|
116
|
+
capabilities: data.capabilities,
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
if (!view) {
|
|
120
|
+
console.error("Failed to generate job output.");
|
|
121
|
+
process.exit(1);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (options.json) {
|
|
125
|
+
console.log(JSON.stringify(view, null, 2));
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// --checklist: Show checklist for a specific handoff
|
|
130
|
+
if (options.checklist) {
|
|
131
|
+
const validHandoffs = ["plan_to_code", "code_to_review"];
|
|
132
|
+
if (!validHandoffs.includes(options.checklist)) {
|
|
133
|
+
console.error(`Invalid handoff: ${options.checklist}`);
|
|
134
|
+
console.error(`Available: ${validHandoffs.join(", ")}`);
|
|
135
|
+
process.exit(1);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const checklist = deriveChecklist({
|
|
139
|
+
handoff: options.checklist,
|
|
140
|
+
skillMatrix: view.skillMatrix,
|
|
141
|
+
capabilities: data.capabilities,
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
if (checklist.length === 0) {
|
|
145
|
+
console.log(`\nNo checklist items for ${options.checklist}\n`);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const handoffLabel = options.checklist.replace(/_/g, " → ");
|
|
150
|
+
console.log(`\n# ${view.title} — ${handoffLabel}\n`);
|
|
151
|
+
console.log(formatChecklistMarkdown(checklist));
|
|
152
|
+
console.log("");
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
formatJob(view, options, { discipline, grade, track });
|
|
157
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Progress CLI Command
|
|
3
|
+
*
|
|
4
|
+
* Shows career progression analysis in the terminal.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { createCompositeCommand } from "./command-factory.js";
|
|
8
|
+
import {
|
|
9
|
+
prepareProgressDetail,
|
|
10
|
+
getDefaultTargetGrade,
|
|
11
|
+
} from "../formatters/progress/shared.js";
|
|
12
|
+
import { progressToMarkdown } from "../formatters/progress/markdown.js";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Format progress output
|
|
16
|
+
* @param {Object} view - Presenter view
|
|
17
|
+
*/
|
|
18
|
+
function formatProgress(view) {
|
|
19
|
+
console.log(progressToMarkdown(view));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const runProgressCommand = createCompositeCommand({
|
|
23
|
+
commandName: "progress",
|
|
24
|
+
requiredArgs: ["discipline_id", "track_id", "grade_id"],
|
|
25
|
+
findEntities: (data, args, options) => {
|
|
26
|
+
const discipline = data.disciplines.find((d) => d.id === args[0]);
|
|
27
|
+
const track = data.tracks.find((t) => t.id === args[1]);
|
|
28
|
+
const grade = data.grades.find((g) => g.id === args[2]);
|
|
29
|
+
|
|
30
|
+
let targetGrade;
|
|
31
|
+
if (options.compare) {
|
|
32
|
+
targetGrade = data.grades.find((g) => g.id === options.compare);
|
|
33
|
+
if (!targetGrade) {
|
|
34
|
+
console.error(`Target grade not found: ${options.compare}`);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
} else {
|
|
38
|
+
targetGrade = getDefaultTargetGrade(grade, data.grades);
|
|
39
|
+
if (!targetGrade) {
|
|
40
|
+
console.error("No next grade available for progression.");
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return { discipline, grade, track, targetGrade };
|
|
46
|
+
},
|
|
47
|
+
validateEntities: (entities, _data) => {
|
|
48
|
+
if (!entities.discipline) {
|
|
49
|
+
return `Discipline not found`;
|
|
50
|
+
}
|
|
51
|
+
if (!entities.grade) {
|
|
52
|
+
return `Grade not found`;
|
|
53
|
+
}
|
|
54
|
+
if (!entities.track) {
|
|
55
|
+
return `Track not found`;
|
|
56
|
+
}
|
|
57
|
+
if (!entities.targetGrade) {
|
|
58
|
+
return `Target grade not found`;
|
|
59
|
+
}
|
|
60
|
+
return null;
|
|
61
|
+
},
|
|
62
|
+
presenter: (entities, data) =>
|
|
63
|
+
prepareProgressDetail({
|
|
64
|
+
fromDiscipline: entities.discipline,
|
|
65
|
+
fromGrade: entities.grade,
|
|
66
|
+
fromTrack: entities.track,
|
|
67
|
+
toDiscipline: entities.discipline,
|
|
68
|
+
toGrade: entities.targetGrade,
|
|
69
|
+
toTrack: entities.track,
|
|
70
|
+
skills: data.skills,
|
|
71
|
+
behaviours: data.behaviours,
|
|
72
|
+
capabilities: data.capabilities,
|
|
73
|
+
}),
|
|
74
|
+
formatter: formatProgress,
|
|
75
|
+
usageExample:
|
|
76
|
+
"npx pathway progress software_engineering platform L3 --compare=L4",
|
|
77
|
+
});
|