@forwardimpact/pathway 0.13.0 → 0.14.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 (45) hide show
  1. package/bin/fit-pathway.js +26 -7
  2. package/package.json +2 -2
  3. package/src/commands/build.js +98 -2
  4. package/src/commands/index.js +1 -0
  5. package/src/commands/job.js +1 -0
  6. package/src/commands/stage.js +8 -8
  7. package/src/commands/update.js +133 -0
  8. package/src/components/command-prompt.js +85 -0
  9. package/src/components/nav.js +2 -2
  10. package/src/components/top-bar.js +97 -0
  11. package/src/css/bundles/app.css +2 -0
  12. package/src/css/components/command-prompt.css +98 -0
  13. package/src/css/components/layout.css +0 -3
  14. package/src/css/components/nav.css +121 -81
  15. package/src/css/components/surfaces.css +1 -1
  16. package/src/css/components/top-bar.css +180 -0
  17. package/src/css/pages/agent-builder.css +0 -9
  18. package/src/css/pages/landing.css +4 -0
  19. package/src/css/pages/lifecycle.css +5 -2
  20. package/src/css/reset.css +1 -1
  21. package/src/css/tokens.css +4 -2
  22. package/src/css/views/slide-base.css +2 -1
  23. package/src/formatters/agent/dom.js +0 -26
  24. package/src/formatters/agent/profile.js +13 -7
  25. package/src/formatters/agent/skill.js +4 -4
  26. package/src/formatters/stage/dom.js +13 -10
  27. package/src/formatters/stage/microdata.js +14 -8
  28. package/src/formatters/stage/shared.js +4 -4
  29. package/src/index.html +69 -44
  30. package/src/lib/cli-command.js +145 -0
  31. package/src/lib/state.js +2 -0
  32. package/src/main.js +47 -26
  33. package/src/pages/agent-builder.js +0 -28
  34. package/src/pages/behaviour.js +3 -1
  35. package/src/pages/discipline.js +3 -1
  36. package/src/pages/driver.js +6 -1
  37. package/src/pages/grade.js +6 -1
  38. package/src/pages/job.js +1 -0
  39. package/src/pages/landing.js +7 -0
  40. package/src/pages/skill.js +9 -2
  41. package/src/pages/track.js +6 -1
  42. package/src/slides/job.js +1 -0
  43. package/templates/agent.template.md +17 -10
  44. package/templates/install.template.sh +33 -0
  45. package/templates/skill.template.md +15 -7
@@ -9,6 +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
13
 
13
14
  /**
14
15
  * Render behaviours list page
@@ -16,6 +17,7 @@ import { behaviourToCardConfig } from "../lib/card-mappers.js";
16
17
  export function renderBehavioursList() {
17
18
  const { data } = getState();
18
19
  const { framework } = data;
20
+ const behaviourEmoji = getConceptEmoji(framework, "behaviour");
19
21
 
20
22
  // Transform data for list view
21
23
  const { items } = prepareBehavioursList(data.behaviours);
@@ -27,7 +29,7 @@ export function renderBehavioursList() {
27
29
  { className: "page-header" },
28
30
  h1(
29
31
  { className: "page-title" },
30
- framework.entityDefinitions.behaviour.title,
32
+ `${behaviourEmoji} ${framework.entityDefinitions.behaviour.title}`,
31
33
  ),
32
34
  p(
33
35
  { className: "page-description" },
@@ -10,6 +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
14
 
14
15
  /**
15
16
  * Format discipline group name for display
@@ -42,6 +43,7 @@ function renderDisciplineGroupHeader(groupName, count) {
42
43
  export function renderDisciplinesList() {
43
44
  const { data } = getState();
44
45
  const { framework } = data;
46
+ const disciplineEmoji = getConceptEmoji(framework, "discipline");
45
47
 
46
48
  // Transform data for list view (grouped by professional/management)
47
49
  const { groups } = prepareDisciplinesList(data.disciplines);
@@ -53,7 +55,7 @@ export function renderDisciplinesList() {
53
55
  { className: "page-header" },
54
56
  h1(
55
57
  { className: "page-title" },
56
- framework.entityDefinitions.discipline.title,
58
+ `${disciplineEmoji} ${framework.entityDefinitions.discipline.title}`,
57
59
  ),
58
60
  p(
59
61
  { className: "page-description" },
@@ -9,6 +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
13
 
13
14
  /**
14
15
  * Render drivers list page
@@ -16,6 +17,7 @@ import { driverToCardConfig } from "../lib/card-mappers.js";
16
17
  export function renderDriversList() {
17
18
  const { data } = getState();
18
19
  const { framework } = data;
20
+ const driverEmoji = getConceptEmoji(framework, "driver");
19
21
 
20
22
  // Transform data for list view
21
23
  const { items } = prepareDriversList(data.drivers);
@@ -25,7 +27,10 @@ export function renderDriversList() {
25
27
  // Header
26
28
  div(
27
29
  { className: "page-header" },
28
- h1({ className: "page-title" }, framework.entityDefinitions.driver.title),
30
+ h1(
31
+ { className: "page-title" },
32
+ `${driverEmoji} ${framework.entityDefinitions.driver.title}`,
33
+ ),
29
34
  p(
30
35
  { className: "page-description" },
31
36
  framework.entityDefinitions.driver.description.trim(),
@@ -8,6 +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
12
 
12
13
  /**
13
14
  * Render grades list page
@@ -15,6 +16,7 @@ import { gradeToDOM } from "../formatters/grade/dom.js";
15
16
  export function renderGradesList() {
16
17
  const { data } = getState();
17
18
  const { framework } = data;
19
+ const gradeEmoji = getConceptEmoji(framework, "grade");
18
20
 
19
21
  // Transform data for list view
20
22
  const { items } = prepareGradesList(data.grades);
@@ -24,7 +26,10 @@ export function renderGradesList() {
24
26
  // Header
25
27
  div(
26
28
  { className: "page-header" },
27
- h1({ className: "page-title" }, framework.entityDefinitions.grade.title),
29
+ h1(
30
+ { className: "page-title" },
31
+ `${gradeEmoji} ${framework.entityDefinitions.grade.title}`,
32
+ ),
28
33
  p(
29
34
  { className: "page-description" },
30
35
  framework.entityDefinitions.grade.description.trim(),
package/src/pages/job.js CHANGED
@@ -66,6 +66,7 @@ export async function renderJobDetail(params) {
66
66
  behaviours: data.behaviours,
67
67
  drivers: data.drivers,
68
68
  capabilities: data.capabilities,
69
+ stages: data.stages,
69
70
  });
70
71
 
71
72
  if (!jobView) {
@@ -11,6 +11,7 @@ import {
11
11
  } from "@forwardimpact/schema/levels";
12
12
  import { getStageEmoji } from "../formatters/stage/shared.js";
13
13
  import { aggregateTools } from "../formatters/tool/shared.js";
14
+ import { createCommandPrompt } from "../components/command-prompt.js";
14
15
 
15
16
  /**
16
17
  * Create lifecycle flow visualization for landing page
@@ -63,6 +64,12 @@ export function renderLanding() {
63
64
  span({ className: "brand-tag brand-tag-hero" }, framework.tag),
64
65
  ),
65
66
  p({}, framework.description.trim()),
67
+ // Install command prompt (only if distribution URL is configured)
68
+ framework.distribution?.siteUrl
69
+ ? createCommandPrompt(
70
+ `curl -fsSL ${framework.distribution.siteUrl}/install.sh | bash`,
71
+ )
72
+ : null,
66
73
  // Job builder CTA
67
74
  div(
68
75
  { className: "page-actions", style: "justify-content: center" },
@@ -10,7 +10,10 @@ 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 { getCapabilityEmoji } from "@forwardimpact/schema/levels";
13
+ import {
14
+ getCapabilityEmoji,
15
+ getConceptEmoji,
16
+ } from "@forwardimpact/schema/levels";
14
17
 
15
18
  /**
16
19
  * Render skills list page
@@ -18,6 +21,7 @@ import { getCapabilityEmoji } from "@forwardimpact/schema/levels";
18
21
  export function renderSkillsList() {
19
22
  const { data } = getState();
20
23
  const { framework } = data;
24
+ const skillEmoji = getConceptEmoji(framework, "skill");
21
25
 
22
26
  // Transform data for list view
23
27
  const { groups, groupOrder } = prepareSkillsList(
@@ -30,7 +34,10 @@ export function renderSkillsList() {
30
34
  // Header
31
35
  div(
32
36
  { className: "page-header" },
33
- h1({ className: "page-title" }, framework.entityDefinitions.skill.title),
37
+ h1(
38
+ { className: "page-title" },
39
+ `${skillEmoji} ${framework.entityDefinitions.skill.title}`,
40
+ ),
34
41
  p(
35
42
  { className: "page-description" },
36
43
  framework.entityDefinitions.skill.description.trim(),
@@ -9,6 +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
13
 
13
14
  /**
14
15
  * Render tracks list page
@@ -16,6 +17,7 @@ import { trackToCardConfig } from "../lib/card-mappers.js";
16
17
  export function renderTracksList() {
17
18
  const { data } = getState();
18
19
  const { framework } = data;
20
+ const trackEmoji = getConceptEmoji(framework, "track");
19
21
 
20
22
  // Transform data for list view
21
23
  const { items } = prepareTracksList(data.tracks);
@@ -25,7 +27,10 @@ export function renderTracksList() {
25
27
  // Header
26
28
  div(
27
29
  { className: "page-header" },
28
- h1({ className: "page-title" }, framework.entityDefinitions.track.title),
30
+ h1(
31
+ { className: "page-title" },
32
+ `${trackEmoji} ${framework.entityDefinitions.track.title}`,
33
+ ),
29
34
  p(
30
35
  { className: "page-description" },
31
36
  framework.entityDefinitions.track.description.trim(),
package/src/slides/job.js CHANGED
@@ -28,6 +28,7 @@ export function renderJobSlide({ render, data, params }) {
28
28
  behaviours: data.behaviours,
29
29
  drivers: data.drivers,
30
30
  capabilities: data.capabilities,
31
+ stages: data.stages,
31
32
  });
32
33
 
33
34
  if (!view) {
@@ -57,11 +57,18 @@ project-specific guidance, required tools, and technology standards. Pre-trainin
57
57
  knowledge alone is insufficient—skills contain organizational standards that
58
58
  override general knowledge.
59
59
 
60
- Skills represent mandatory organizational patterns. When a skill specifies tools
61
- in its "Required Tools" section, you MUST use them. If a blocking constraint
62
- prevents use, document in your output: (1) which skill requirement you cannot
63
- meet, (2) the specific constraint preventing compliance, and (3) the alternative
64
- approach with acknowledged trade-offs.
60
+ Each skill file contains XML-tagged sections for precise navigation:
61
+
62
+ - **`<{{stageId}}_stage_checklist>`** Your stage-specific checklist. Follow
63
+ the Read-Then-Do and Do-Then-Confirm items for the {{stageName}} stage.
64
+ - **`<required_tools>`** Mandatory tools for this skill. You MUST use these
65
+ organizational standards that override general knowledge or personal
66
+ preferences.
67
+ {{#isOnboard}}
68
+ - **`<onboarding_steps>`** — Step-by-step environment setup instructions.
69
+ Follow these to install prerequisites and configure the development
70
+ environment. Focus on setup only — do not begin feature implementation.
71
+ {{/isOnboard}}
65
72
 
66
73
  | Skill | Location | Use When |
67
74
  | ----- | -------- | -------- |
@@ -88,23 +95,23 @@ and (3) the compromised approach with acknowledged limitations.
88
95
  | `{{id}}` | {{{name}}} | {{{description}}} |
89
96
  {{/agentIndex}}
90
97
  {{/hasAgentIndex}}
91
- {{#hasBeforeHandoff}}
98
+ {{#hasConfirmChecklist}}
92
99
 
93
- ## Before Handoff
100
+ ## Do-Then-Confirm Checklist
94
101
 
95
102
  Before offering a handoff, verify and summarize completion of these items:
96
103
 
97
- {{#beforeHandoff}}
104
+ {{#confirmChecklist}}
98
105
  ### {{{capability.emojiIcon}}} {{{skill.name}}}
99
106
 
100
107
  {{#items}}
101
108
  - [ ] {{{.}}}
102
109
  {{/items}}
103
110
 
104
- {{/beforeHandoff}}
111
+ {{/confirmChecklist}}
105
112
  When verified, summarize what was accomplished then offer the handoff. If items
106
113
  are incomplete, explain what remains.
107
- {{/hasBeforeHandoff}}
114
+ {{/hasConfirmChecklist}}
108
115
 
109
116
  ## Return Format
110
117
 
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env bash
2
+ # {{{frameworkTitle}}} — Local Install
3
+ # Generated by @forwardimpact/pathway v{{{version}}}
4
+ #
5
+ # Installs to ~/.fit/pathway/
6
+ #
7
+ # Usage:
8
+ # curl -fsSL {{{siteUrl}}}/install.sh | bash
9
+ #
10
+ set -euo pipefail
11
+
12
+ SITE_URL="{{{siteUrl}}}"
13
+ INSTALL_DIR="${HOME}/.fit/pathway"
14
+
15
+ command -v node >/dev/null 2>&1 || { echo "Error: Node.js 18+ is required. https://nodejs.org"; exit 1; }
16
+ command -v npm >/dev/null 2>&1 || { echo "Error: npm is required."; exit 1; }
17
+
18
+ echo "Installing to ${INSTALL_DIR}..."
19
+ mkdir -p "${INSTALL_DIR}"
20
+
21
+ TMPFILE=$(mktemp)
22
+ trap 'rm -f "$TMPFILE"' EXIT
23
+ curl -fsSL "${SITE_URL}/bundle.tar.gz" -o "$TMPFILE"
24
+ tar -xzf "$TMPFILE" -C "${INSTALL_DIR}" --strip-components=1
25
+
26
+ (cd "${INSTALL_DIR}" && npm install --production --ignore-scripts --no-audit --no-fund --silent)
27
+
28
+ echo ""
29
+ 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"
@@ -13,23 +13,29 @@ description: {{{description}}}{{#hasUseWhen}} Use When: {{{useWhen}}}{{/hasUseWh
13
13
  ## Stage Guidance
14
14
  {{#stages}}
15
15
 
16
+ <{{stageId}}_stage_checklist>
17
+
16
18
  ### {{stageName}} Stage
17
19
 
18
20
  **Focus:** {{{focus}}}
19
21
 
20
- **Activities:**
21
- {{#activities}}
22
- - {{{.}}}
23
- {{/activities}}
22
+ **Read-Then-Do Checklist:**
23
+ {{#readChecklist}}
24
+ - [ ] {{{.}}}
25
+ {{/readChecklist}}
24
26
 
25
- **Ready for {{nextStageName}} when:**
26
- {{#ready}}
27
+ **Do-Then-Confirm Checklist:**
28
+ {{#confirmChecklist}}
27
29
  - [ ] {{{.}}}
28
- {{/ready}}
30
+ {{/confirmChecklist}}
31
+
32
+ </{{stageId}}_stage_checklist>
29
33
  {{/stages}}
30
34
  {{/hasStages}}
31
35
  {{#hasToolReferences}}
32
36
 
37
+ <required_tools>
38
+
33
39
  ## Required Tools
34
40
 
35
41
  **MANDATORY:** You MUST use these tools when applying this skill. These are
@@ -45,6 +51,8 @@ trade-offs.
45
51
  {{#toolReferences}}
46
52
  | {{#url}}[{{{name}}}]({{{url}}}){{/url}}{{^url}}{{{name}}}{{/url}} | {{{useWhen}}} |
47
53
  {{/toolReferences}}
54
+
55
+ </required_tools>
48
56
  {{/hasToolReferences}}
49
57
  {{#hasReference}}
50
58