@forwardimpact/pathway 0.8.1 → 0.10.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.
@@ -48,9 +48,9 @@ import { runInterviewCommand } from "../src/commands/interview.js";
48
48
  import { runProgressCommand } from "../src/commands/progress.js";
49
49
  import { runQuestionsCommand } from "../src/commands/questions.js";
50
50
  import { runAgentCommand } from "../src/commands/agent.js";
51
- import { runServeCommand } from "../src/commands/serve.js";
51
+ import { runDevCommand } from "../src/commands/dev.js";
52
52
  import { runInitCommand } from "../src/commands/init.js";
53
- import { runSiteCommand } from "../src/commands/site.js";
53
+ import { runBuildCommand } from "../src/commands/build.js";
54
54
 
55
55
  const COMMANDS = {
56
56
  discipline: runDisciplineCommand,
@@ -85,8 +85,8 @@ GETTING STARTED
85
85
  ────────────────────────────────────────────────────────────────────────────────
86
86
 
87
87
  init Create ./data/ with example data
88
- serve [--port=PORT] Serve web app at http://localhost:3000
89
- site [--output=PATH] Generate static site to ./site/
88
+ dev [--port=PORT] Run live development server
89
+ build [--output=PATH] Generate static site to ./public/
90
90
 
91
91
  ────────────────────────────────────────────────────────────────────────────────
92
92
  ENTITY COMMANDS
@@ -104,7 +104,7 @@ All entity commands support: summary (default), --list (IDs for piping), <id> (d
104
104
  skill [<id>] Browse skills
105
105
  --agent Output as agent SKILL.md format
106
106
 
107
- tool [<name>] Browse recommended tools (aggregated from skills)
107
+ tool [<name>] Browse required tools (aggregated from skills)
108
108
 
109
109
  ────────────────────────────────────────────────────────────────────────────────
110
110
  JOB COMMAND
@@ -400,16 +400,16 @@ async function main() {
400
400
 
401
401
  const dataDir = resolveDataPath(options);
402
402
 
403
- // Handle serve command (needs data directory)
404
- if (command === "serve") {
405
- await runServeCommand({ dataDir, options });
406
- // serve doesn't exit, keeps running
403
+ // Handle dev command (needs data directory)
404
+ if (command === "dev") {
405
+ await runDevCommand({ dataDir, options });
406
+ // dev doesn't exit, keeps running
407
407
  return;
408
408
  }
409
409
 
410
- // Handle site command (generates static site)
411
- if (command === "site") {
412
- await runSiteCommand({ dataDir, options });
410
+ // Handle build command (generates static site)
411
+ if (command === "build") {
412
+ await runBuildCommand({ dataDir, options });
413
413
  process.exit(0);
414
414
  }
415
415
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forwardimpact/pathway",
3
- "version": "0.8.1",
3
+ "version": "0.10.0",
4
4
  "description": "Career progression web app and CLI for exploring roles and generating agents",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -40,8 +40,8 @@
40
40
  "./commands": "./src/commands/index.js"
41
41
  },
42
42
  "dependencies": {
43
- "@forwardimpact/schema": "^0.3.0",
44
- "@forwardimpact/model": "^0.3.0",
43
+ "@forwardimpact/schema": "^0.4.0",
44
+ "@forwardimpact/model": "^0.5.0",
45
45
  "mustache": "^4.2.0",
46
46
  "simple-icons": "^16.7.0",
47
47
  "yaml": "^2.3.4"
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Site Command
2
+ * Build Command
3
3
  *
4
4
  * Generates a static site from the Engineering Pathway data.
5
5
  * Copies all necessary files (HTML, JS, CSS) and data to an output directory.
@@ -59,13 +59,13 @@ const PUBLIC_ASSETS = [
59
59
  const ROOT_ASSETS = ["templates"];
60
60
 
61
61
  /**
62
- * Run the site command
62
+ * Run the build command
63
63
  * @param {Object} params - Command parameters
64
64
  * @param {string} params.dataDir - Path to data directory
65
65
  * @param {Object} params.options - Command options
66
66
  */
67
- export async function runSiteCommand({ dataDir, options }) {
68
- const outputDir = options.output || join(process.cwd(), "site");
67
+ export async function runBuildCommand({ dataDir, options }) {
68
+ const outputDir = options.output || join(process.cwd(), "public");
69
69
  const clean = options.clean !== false;
70
70
 
71
71
  // Load framework config for display
@@ -1,7 +1,7 @@
1
1
  /**
2
- * Serve Command
2
+ * Dev Command
3
3
  *
4
- * Serves the Engineering Pathway web application with local data.
4
+ * Runs a live development server for the Engineering Pathway web application.
5
5
  * Uses Node.js built-in http module (no external dependencies).
6
6
  */
7
7
 
@@ -96,12 +96,12 @@ async function isDirectory(path) {
96
96
  }
97
97
 
98
98
  /**
99
- * Run the serve command
99
+ * Run the dev command
100
100
  * @param {Object} params - Command parameters
101
101
  * @param {string} params.dataDir - Path to data directory
102
102
  * @param {Object} params.options - Command options
103
103
  */
104
- export async function runServeCommand({ dataDir, options }) {
104
+ export async function runDevCommand({ dataDir, options }) {
105
105
  const port = options.port || 3000;
106
106
 
107
107
  // Load framework config for display
@@ -18,6 +18,13 @@ import { trimValue, trimRequired, trimFields } from "../shared.js";
18
18
  * @property {string} content - Working style content (markdown)
19
19
  */
20
20
 
21
+ /**
22
+ * @typedef {Object} BeforeHandoffEntry
23
+ * @property {{id: string, name: string}} skill - Skill info
24
+ * @property {{id: string, name: string, emojiIcon: string}} capability - Capability info
25
+ * @property {string[]} items - Checklist items
26
+ */
27
+
21
28
  /**
22
29
  * Prepare agent profile data for template rendering
23
30
  * Normalizes string values by trimming trailing newlines for consistent template output.
@@ -35,7 +42,7 @@ import { trimValue, trimRequired, trimFields } from "../shared.js";
35
42
  * @param {Array<{name: string, dirname: string, useWhen: string}>} params.bodyData.skillIndex - Skill index entries
36
43
  * @param {string} params.bodyData.roleContext - Role context text
37
44
  * @param {WorkingStyleEntry[]} params.bodyData.workingStyles - Working style entries
38
- * @param {string} [params.bodyData.beforeHandoff] - Before handoff checklist markdown
45
+ * @param {BeforeHandoffEntry[]} [params.bodyData.beforeHandoff] - Before handoff checklist entries
39
46
  * @param {string[]} params.bodyData.constraints - List of constraints
40
47
  * @param {Array<{id: string, name: string, description: string}>} [params.bodyData.agentIndex] - List of all available agents
41
48
  * @param {boolean} [params.bodyData.hasAgentIndex] - Whether agent index is available
@@ -60,6 +67,13 @@ function prepareAgentProfileData({ frontmatter, bodyData }) {
60
67
  content: "required",
61
68
  });
62
69
 
70
+ // Process beforeHandoff: trim items in each entry
71
+ const beforeHandoff = (bodyData.beforeHandoff || []).map((entry) => ({
72
+ skill: entry.skill,
73
+ capability: entry.capability,
74
+ items: (entry.items || []).map((item) => trimRequired(item)),
75
+ }));
76
+
63
77
  return {
64
78
  // Frontmatter
65
79
  name: frontmatter.name,
@@ -77,7 +91,8 @@ function prepareAgentProfileData({ frontmatter, bodyData }) {
77
91
  roleContext: trimValue(bodyData.roleContext),
78
92
  workingStyles,
79
93
  hasWorkingStyles: workingStyles.length > 0,
80
- beforeHandoff: trimValue(bodyData.beforeHandoff),
94
+ beforeHandoff,
95
+ hasBeforeHandoff: beforeHandoff.length > 0,
81
96
  constraints,
82
97
  hasConstraints: constraints.length > 0,
83
98
  agentIndex,
@@ -102,7 +117,7 @@ function prepareAgentProfileData({ frontmatter, bodyData }) {
102
117
  * @param {Array<{name: string, dirname: string, useWhen: string}>} profile.bodyData.skillIndex - Skill index entries
103
118
  * @param {string} profile.bodyData.roleContext - Role context text
104
119
  * @param {WorkingStyleEntry[]} profile.bodyData.workingStyles - Working style entries
105
- * @param {string} [profile.bodyData.beforeHandoff] - Before handoff checklist markdown (optional)
120
+ * @param {BeforeHandoffEntry[]} [profile.bodyData.beforeHandoff] - Before handoff checklist entries (optional)
106
121
  * @param {string[]} profile.bodyData.constraints - List of constraints
107
122
  * @param {string} template - Mustache template string
108
123
  * @returns {string} Complete .agent.md file content
@@ -33,7 +33,7 @@ import { createJsonLdScript, skillToJsonLd } from "../json-ld.js";
33
33
  * @param {Array} context.drivers - All drivers
34
34
  * @param {Array} context.capabilities - Capability entities
35
35
  * @param {boolean} [context.showBackLink=true] - Whether to show back navigation link
36
- * @param {boolean} [context.showToolsAndPatterns=true] - Whether to show recommended tools and implementation patterns
36
+ * @param {boolean} [context.showToolsAndPatterns=true] - Whether to show required tools and implementation patterns
37
37
  * @returns {HTMLElement}
38
38
  */
39
39
  export function skillToDOM(
@@ -178,11 +178,11 @@ export function skillToDOM(
178
178
  )
179
179
  : null,
180
180
 
181
- // Recommended Tools
181
+ // Required Tools
182
182
  showToolsAndPatterns && view.toolReferences.length > 0
183
183
  ? div(
184
184
  { className: "detail-section" },
185
- heading2({ className: "section-title" }, "Recommended Tools"),
185
+ heading2({ className: "section-title" }, "Required Tools"),
186
186
  table(
187
187
  { className: "tools-table" },
188
188
  thead({}, tr({}, th({}, "Tool"), th({}, "Use When"))),
@@ -204,6 +204,7 @@ export function skillToDOM(
204
204
  rel: "noopener noreferrer",
205
205
  },
206
206
  tool.name,
207
+ span({ className: "external-icon" }, " ↗"),
207
208
  )
208
209
  : tool.name,
209
210
  ),
@@ -105,9 +105,9 @@ export function skillToMarkdown(
105
105
  lines.push("");
106
106
  }
107
107
 
108
- // Recommended tools
108
+ // Required tools
109
109
  if (view.toolReferences.length > 0) {
110
- lines.push("## Recommended Tools", "");
110
+ lines.push("## Required Tools", "");
111
111
  const toolRows = view.toolReferences.map((tool) => [
112
112
  tool.url ? `[${tool.name}](${tool.url})` : tool.name,
113
113
  tool.useWhen,
@@ -28,12 +28,9 @@ export function createToolkitTable(toolkit) {
28
28
  }
29
29
 
30
30
  const rows = toolkit.map((tool) => {
31
- const iconCell = tool.simpleIcon
32
- ? td(
33
- { className: "tool-icon-cell" },
34
- createToolIcon(tool.simpleIcon, tool.name),
35
- )
36
- : td({ className: "tool-icon-cell" });
31
+ const icon = tool.simpleIcon
32
+ ? createToolIcon(tool.simpleIcon, tool.name)
33
+ : null;
37
34
 
38
35
  const nameContent = tool.url
39
36
  ? a(
@@ -50,8 +47,7 @@ export function createToolkitTable(toolkit) {
50
47
 
51
48
  return tr(
52
49
  {},
53
- iconCell,
54
- td({ className: "tool-name-cell" }, nameContent),
50
+ td({ className: "tool-name-cell" }, icon, nameContent),
55
51
  td({ className: "tool-description-cell" }, tool.description),
56
52
  );
57
53
  });
@@ -60,15 +56,7 @@ export function createToolkitTable(toolkit) {
60
56
  { className: "table-container" },
61
57
  table(
62
58
  { className: "table toolkit-table" },
63
- thead(
64
- {},
65
- tr(
66
- {},
67
- th({ style: "width: 40px" }, ""),
68
- th({}, "Tool"),
69
- th({}, "Description"),
70
- ),
71
- ),
59
+ thead({}, tr({}, th({}, "Tool"), th({}, "Description"))),
72
60
  tbody({}, ...rows),
73
61
  ),
74
62
  );
@@ -190,7 +190,7 @@ export function toolToCardConfig(tool, capabilities) {
190
190
  title: tool.name,
191
191
  description: tool.description,
192
192
  // Docs link in header badges (upper right)
193
- badges: tool.url ? [createExternalLink("Docs ", tool.url)] : [],
193
+ badges: tool.url ? [createExternalLink("Docs ", tool.url)] : [],
194
194
  content: skillsList,
195
195
  icon,
196
196
  };
@@ -50,17 +50,18 @@ handoffs:
50
50
  {{/hasWorkingStyles}}
51
51
  {{#hasSkills}}
52
52
 
53
- ## Available Skills and Tools
53
+ ## Required Skills
54
54
 
55
- **IMPORTANT:** Before starting work, read the relevant skill file for
56
- project-specific guidance, tools and technology recommendations. Do not rely
57
- solely on pre-training knowledge.
55
+ **MANDATORY:** Before starting work, you MUST read the relevant skill files for
56
+ project-specific guidance, required tools, and technology standards. Pre-training
57
+ knowledge alone is insufficient—skills contain organizational standards that
58
+ override general knowledge.
58
59
 
59
- Skills represent validated organizational patterns. When a skill recommends
60
- specific tools in its "Recommended Tools" section, use them unless a blocking
61
- constraint exists. If you choose a different tool, document in your output: (1)
62
- which skill recommendation you're overriding, (2) the constraint preventing use,
63
- and (3) trade-offs of the alternative.
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.
64
65
 
65
66
  | Skill | Location | Use When |
66
67
  | ----- | -------- | -------- |
@@ -70,16 +71,16 @@ and (3) trade-offs of the alternative.
70
71
  {{/hasSkills}}
71
72
  {{#hasAgentIndex}}
72
73
 
73
- ## Available Sub-Agents for Delegation
74
+ ## Required Sub-Agent Delegations
74
75
 
75
- **IMPORTANT:** If you come across work that is not strictly within your
76
- speciality, then you must delegate the task using the `runSubagent` tool.
76
+ **MANDATORY:** You MUST delegate work outside your speciality using the
77
+ `runSubagent` tool. Do not attempt work that another agent is better suited for.
77
78
 
78
- You are part of a team of agents and should not carry out all work yourself.
79
- Rely on other agents around you that have a speciality better suited for
80
- individual tasks. If you choose to not delegate specialised work to a sub-agent,
81
- document in your output: (1) what the specialised work is, (2) the constraint
82
- preventing delegation and (3) trade-offs of the alternative.
79
+ You are part of an agentic team with specialized roles. Attempting work outside
80
+ your speciality produces inferior results and violates team structure. If you
81
+ cannot delegate due to a blocking constraint, document in your output: (1) the
82
+ specialized work required, (2) the specific constraint preventing delegation,
83
+ and (3) the compromised approach with acknowledged limitations.
83
84
 
84
85
  | Agent Name | Speciality | Description |
85
86
  | ---------- | ---------- | ----------- |
@@ -87,17 +88,23 @@ preventing delegation and (3) trade-offs of the alternative.
87
88
  | `{{id}}` | {{{name}}} | {{{description}}} |
88
89
  {{/agentIndex}}
89
90
  {{/hasAgentIndex}}
90
- {{#beforeHandoff}}
91
+ {{#hasBeforeHandoff}}
91
92
 
92
93
  ## Before Handoff
93
94
 
94
95
  Before offering a handoff, verify and summarize completion of these items:
95
96
 
96
- {{{beforeHandoff}}}
97
+ {{#beforeHandoff}}
98
+ ### {{{capability.emojiIcon}}} {{{skill.name}}}
99
+
100
+ {{#items}}
101
+ - [ ] {{{.}}}
102
+ {{/items}}
97
103
 
104
+ {{/beforeHandoff}}
98
105
  When verified, summarize what was accomplished then offer the handoff. If items
99
106
  are incomplete, explain what remains.
100
- {{/beforeHandoff}}
107
+ {{/hasBeforeHandoff}}
101
108
 
102
109
  ## Return Format
103
110
 
@@ -1,20 +1,17 @@
1
1
  ---
2
2
  name: {{name}}
3
3
  description: |
4
- {{#descriptionLines}}
5
- {{{.}}}
6
- {{/descriptionLines}}
4
+ {{#descriptionLines}}{{{.}}} {{/descriptionLines}}
7
5
  {{#hasUseWhen}}
8
- **Use When:** {{#useWhenLines}}{{{.}}}{{/useWhenLines}}
6
+ Use When: {{#useWhenLines}}{{{.}}} {{/useWhenLines}}
9
7
  {{/hasUseWhen}}
10
8
  ---
11
9
 
12
10
  # {{{title}}}
13
- {{#hasUseWhen}}
14
11
 
15
- **Use This Skill When:**
16
- {{#useWhenLines}}{{{.}}}{{/useWhenLines}}
17
- {{/hasUseWhen}}
12
+ {{#descriptionLines}}
13
+ {{{.}}}
14
+ {{/descriptionLines}}
18
15
  {{#hasStages}}
19
16
 
20
17
  ## Stage Guidance
@@ -37,7 +34,10 @@ description: |
37
34
  {{/hasStages}}
38
35
  {{#hasToolReferences}}
39
36
 
40
- # Recommended Tools
37
+ # Required Tools
38
+
39
+ Use these tools when applying this skill. Alternative tools require documented
40
+ justification with acknowledged trade-offs.
41
41
 
42
42
  | Tool | Use When |
43
43
  | ---- | -------- |