@forwardimpact/pathway 0.12.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.
- package/bin/fit-pathway.js +32 -12
- package/package.json +3 -3
- package/src/commands/build.js +98 -2
- package/src/commands/index.js +1 -0
- package/src/commands/interview.js +52 -14
- package/src/commands/job.js +1 -0
- package/src/commands/questions.js +13 -10
- package/src/commands/stage.js +8 -8
- package/src/commands/update.js +133 -0
- package/src/components/command-prompt.js +85 -0
- package/src/components/nav.js +2 -2
- package/src/components/top-bar.js +97 -0
- package/src/css/bundles/app.css +2 -0
- package/src/css/components/badges.css +41 -11
- package/src/css/components/command-prompt.css +98 -0
- package/src/css/components/layout.css +0 -3
- package/src/css/components/nav.css +121 -81
- package/src/css/components/surfaces.css +1 -1
- package/src/css/components/top-bar.css +180 -0
- package/src/css/pages/agent-builder.css +0 -9
- package/src/css/pages/landing.css +4 -0
- package/src/css/pages/lifecycle.css +5 -2
- package/src/css/reset.css +1 -1
- package/src/css/tokens.css +25 -11
- package/src/css/views/slide-base.css +2 -1
- package/src/formatters/agent/dom.js +0 -26
- package/src/formatters/agent/profile.js +13 -7
- package/src/formatters/agent/skill.js +4 -4
- package/src/formatters/interview/markdown.js +62 -3
- package/src/formatters/interview/shared.js +89 -52
- package/src/formatters/questions/markdown.js +15 -0
- package/src/formatters/questions/shared.js +70 -58
- package/src/formatters/stage/dom.js +13 -10
- package/src/formatters/stage/microdata.js +14 -8
- package/src/formatters/stage/shared.js +4 -4
- package/src/index.html +69 -44
- package/src/lib/cli-command.js +145 -0
- package/src/lib/state.js +2 -0
- package/src/lib/yaml-loader.js +39 -21
- package/src/main.js +47 -26
- package/src/pages/agent-builder.js +0 -28
- package/src/pages/behaviour.js +3 -1
- package/src/pages/discipline.js +3 -1
- package/src/pages/driver.js +6 -1
- package/src/pages/grade.js +6 -1
- package/src/pages/interview.js +61 -5
- package/src/pages/job.js +1 -0
- package/src/pages/landing.js +7 -0
- package/src/pages/skill.js +9 -2
- package/src/pages/track.js +6 -1
- package/src/slides/job.js +1 -0
- package/templates/agent.template.md +17 -10
- package/templates/install.template.sh +33 -0
- package/templates/skill.template.md +15 -7
package/src/pages/interview.js
CHANGED
|
@@ -81,8 +81,8 @@ export function renderInterviewDetail(params) {
|
|
|
81
81
|
return;
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
// State for current interview type (default to first:
|
|
85
|
-
let currentType = "
|
|
84
|
+
// State for current interview type (default to first: Mission Fit)
|
|
85
|
+
let currentType = "mission";
|
|
86
86
|
|
|
87
87
|
const page = div(
|
|
88
88
|
{ className: "interview-detail-page" },
|
|
@@ -194,23 +194,32 @@ function createInterviewSummary(interview) {
|
|
|
194
194
|
{ className: "interview-summary-header" },
|
|
195
195
|
h2({}, `${typeInfo.icon} ${typeInfo.name}`),
|
|
196
196
|
p({ className: "text-muted" }, typeInfo.description),
|
|
197
|
+
typeInfo.panel
|
|
198
|
+
? p({ className: "text-muted" }, `Panel: ${typeInfo.panel}`)
|
|
199
|
+
: null,
|
|
197
200
|
),
|
|
198
201
|
div(
|
|
199
202
|
{ className: "interview-summary-stats" },
|
|
200
203
|
createBadge(`${interview.questions.length} questions`, "default"),
|
|
201
204
|
createBadge(`~${interview.expectedDurationMinutes} minutes`, "secondary"),
|
|
202
|
-
interview.coverage.skills
|
|
205
|
+
interview.coverage.skills?.length > 0
|
|
203
206
|
? createBadge(
|
|
204
207
|
`${interview.coverage.skills.length} skills covered`,
|
|
205
208
|
"primary",
|
|
206
209
|
)
|
|
207
210
|
: null,
|
|
208
|
-
interview.coverage.behaviours
|
|
211
|
+
interview.coverage.behaviours?.length > 0
|
|
209
212
|
? createBadge(
|
|
210
213
|
`${interview.coverage.behaviours.length} behaviours covered`,
|
|
211
214
|
"primary",
|
|
212
215
|
)
|
|
213
216
|
: null,
|
|
217
|
+
interview.coverage.capabilities?.length > 0
|
|
218
|
+
? createBadge(
|
|
219
|
+
`${interview.coverage.capabilities.length} capabilities covered`,
|
|
220
|
+
"primary",
|
|
221
|
+
)
|
|
222
|
+
: null,
|
|
214
223
|
),
|
|
215
224
|
);
|
|
216
225
|
}
|
|
@@ -226,6 +235,9 @@ function createQuestionsDisplay(interview, framework) {
|
|
|
226
235
|
const behaviourQuestions = interview.questions.filter(
|
|
227
236
|
(q) => q.targetType === "behaviour",
|
|
228
237
|
);
|
|
238
|
+
const capabilityQuestions = interview.questions.filter(
|
|
239
|
+
(q) => q.targetType === "capability",
|
|
240
|
+
);
|
|
229
241
|
|
|
230
242
|
const sections = [];
|
|
231
243
|
|
|
@@ -241,12 +253,21 @@ function createQuestionsDisplay(interview, framework) {
|
|
|
241
253
|
if (behaviourQuestions.length > 0) {
|
|
242
254
|
sections.push(
|
|
243
255
|
createDetailSection({
|
|
244
|
-
title: `${getConceptEmoji(framework, "behaviour")}
|
|
256
|
+
title: `${getConceptEmoji(framework, "behaviour")} Stakeholder Simulation (${behaviourQuestions.length})`,
|
|
245
257
|
content: createQuestionsList(behaviourQuestions),
|
|
246
258
|
}),
|
|
247
259
|
);
|
|
248
260
|
}
|
|
249
261
|
|
|
262
|
+
if (capabilityQuestions.length > 0) {
|
|
263
|
+
sections.push(
|
|
264
|
+
createDetailSection({
|
|
265
|
+
title: `${getConceptEmoji(framework, "capability") || "🧩"} Decomposition Questions (${capabilityQuestions.length})`,
|
|
266
|
+
content: createQuestionsList(capabilityQuestions),
|
|
267
|
+
}),
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
|
|
250
271
|
if (sections.length === 0) {
|
|
251
272
|
return div(
|
|
252
273
|
{ className: "card" },
|
|
@@ -262,6 +283,7 @@ function createQuestionsDisplay(interview, framework) {
|
|
|
262
283
|
|
|
263
284
|
/**
|
|
264
285
|
* Create questions list
|
|
286
|
+
* @param {Array} questions - Questions to display
|
|
265
287
|
*/
|
|
266
288
|
function createQuestionsList(questions) {
|
|
267
289
|
return div(
|
|
@@ -272,10 +294,41 @@ function createQuestionsList(questions) {
|
|
|
272
294
|
|
|
273
295
|
/**
|
|
274
296
|
* Create question card
|
|
297
|
+
* @param {Object} questionEntry - Question entry
|
|
298
|
+
* @param {number} number - Question number
|
|
275
299
|
*/
|
|
276
300
|
function createQuestionCard(questionEntry, number) {
|
|
277
301
|
const { question, targetName, targetLevel } = questionEntry;
|
|
278
302
|
|
|
303
|
+
const contextSection = question.context
|
|
304
|
+
? div(
|
|
305
|
+
{ className: "question-context" },
|
|
306
|
+
h4({}, "Context:"),
|
|
307
|
+
p({}, question.context),
|
|
308
|
+
)
|
|
309
|
+
: null;
|
|
310
|
+
|
|
311
|
+
const decompositionPromptsList =
|
|
312
|
+
question.decompositionPrompts && question.decompositionPrompts.length > 0
|
|
313
|
+
? div(
|
|
314
|
+
{ className: "question-prompts" },
|
|
315
|
+
h4({}, "Guide candidate thinking:"),
|
|
316
|
+
ul(
|
|
317
|
+
{},
|
|
318
|
+
...question.decompositionPrompts.map((prompt) => li({}, prompt)),
|
|
319
|
+
),
|
|
320
|
+
)
|
|
321
|
+
: null;
|
|
322
|
+
|
|
323
|
+
const simulationPromptsList =
|
|
324
|
+
question.simulationPrompts && question.simulationPrompts.length > 0
|
|
325
|
+
? div(
|
|
326
|
+
{ className: "question-prompts" },
|
|
327
|
+
h4({}, "Steer the simulation:"),
|
|
328
|
+
ul({}, ...question.simulationPrompts.map((prompt) => li({}, prompt))),
|
|
329
|
+
)
|
|
330
|
+
: null;
|
|
331
|
+
|
|
279
332
|
const followUpsList =
|
|
280
333
|
question.followUps && question.followUps.length > 0
|
|
281
334
|
? div(
|
|
@@ -309,6 +362,9 @@ function createQuestionCard(questionEntry, number) {
|
|
|
309
362
|
),
|
|
310
363
|
),
|
|
311
364
|
div({ className: "question-text" }, question.text),
|
|
365
|
+
contextSection,
|
|
366
|
+
decompositionPromptsList,
|
|
367
|
+
simulationPromptsList,
|
|
312
368
|
followUpsList,
|
|
313
369
|
lookingForList,
|
|
314
370
|
);
|
package/src/pages/job.js
CHANGED
package/src/pages/landing.js
CHANGED
|
@@ -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" },
|
package/src/pages/skill.js
CHANGED
|
@@ -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 {
|
|
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(
|
|
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(),
|
package/src/pages/track.js
CHANGED
|
@@ -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(
|
|
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
|
@@ -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
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
-
{{#
|
|
98
|
+
{{#hasConfirmChecklist}}
|
|
92
99
|
|
|
93
|
-
##
|
|
100
|
+
## Do-Then-Confirm Checklist
|
|
94
101
|
|
|
95
102
|
Before offering a handoff, verify and summarize completion of these items:
|
|
96
103
|
|
|
97
|
-
{{#
|
|
104
|
+
{{#confirmChecklist}}
|
|
98
105
|
### {{{capability.emojiIcon}}} {{{skill.name}}}
|
|
99
106
|
|
|
100
107
|
{{#items}}
|
|
101
108
|
- [ ] {{{.}}}
|
|
102
109
|
{{/items}}
|
|
103
110
|
|
|
104
|
-
{{/
|
|
111
|
+
{{/confirmChecklist}}
|
|
105
112
|
When verified, summarize what was accomplished then offer the handoff. If items
|
|
106
113
|
are incomplete, explain what remains.
|
|
107
|
-
{{/
|
|
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
|
-
**
|
|
21
|
-
{{#
|
|
22
|
-
- {{{.}}}
|
|
23
|
-
{{/
|
|
22
|
+
**Read-Then-Do Checklist:**
|
|
23
|
+
{{#readChecklist}}
|
|
24
|
+
- [ ] {{{.}}}
|
|
25
|
+
{{/readChecklist}}
|
|
24
26
|
|
|
25
|
-
**
|
|
26
|
-
{{#
|
|
27
|
+
**Do-Then-Confirm Checklist:**
|
|
28
|
+
{{#confirmChecklist}}
|
|
27
29
|
- [ ] {{{.}}}
|
|
28
|
-
{{/
|
|
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
|
|