@forwardimpact/pathway 0.8.0 → 0.9.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.0",
3
+ "version": "0.9.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.4.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.
@@ -15,6 +15,22 @@ const __filename = fileURLToPath(import.meta.url);
15
15
  const __dirname = dirname(__filename);
16
16
  const appDir = join(__dirname, "..");
17
17
 
18
+ /**
19
+ * Resolve package directory using Node's module resolution.
20
+ * Works in both monorepo (development) and installed (production) contexts.
21
+ * @param {string} packageName - Package specifier (e.g., '@forwardimpact/schema')
22
+ * @returns {string} Absolute path to package lib directory
23
+ */
24
+ function resolvePackageLib(packageName) {
25
+ // import.meta.resolve returns file:// URL to package's main entry (lib/index.js)
26
+ const mainUrl = import.meta.resolve(packageName);
27
+ // Convert to path and get lib directory
28
+ return dirname(fileURLToPath(mainUrl));
29
+ }
30
+
31
+ const schemaLibDir = resolvePackageLib("@forwardimpact/schema");
32
+ const modelLibDir = resolvePackageLib("@forwardimpact/model");
33
+
18
34
  /**
19
35
  * Files and directories to copy from app/
20
36
  */
@@ -31,7 +47,6 @@ const PUBLIC_ASSETS = [
31
47
  // Directories
32
48
  "css",
33
49
  "lib",
34
- "model",
35
50
  "pages",
36
51
  "slides",
37
52
  "components",
@@ -44,13 +59,13 @@ const PUBLIC_ASSETS = [
44
59
  const ROOT_ASSETS = ["templates"];
45
60
 
46
61
  /**
47
- * Run the site command
62
+ * Run the build command
48
63
  * @param {Object} params - Command parameters
49
64
  * @param {string} params.dataDir - Path to data directory
50
65
  * @param {Object} params.options - Command options
51
66
  */
52
- export async function runSiteCommand({ dataDir, options }) {
53
- const outputDir = options.output || join(process.cwd(), "site");
67
+ export async function runBuildCommand({ dataDir, options }) {
68
+ const outputDir = options.output || join(process.cwd(), "public");
54
69
  const clean = options.clean !== false;
55
70
 
56
71
  // Load framework config for display
@@ -113,6 +128,14 @@ ${framework.emojiIcon} Generating ${framework.title} static site...
113
128
  }
114
129
  }
115
130
 
131
+ // Copy @forwardimpact/schema and @forwardimpact/model packages
132
+ // These are needed by the browser's import map
133
+ console.log("📚 Copying package dependencies...");
134
+ await cp(schemaLibDir, join(outputDir, "schema/lib"), { recursive: true });
135
+ console.log(` ✓ schema/lib`);
136
+ await cp(modelLibDir, join(outputDir, "model/lib"), { recursive: true });
137
+ console.log(` ✓ model/lib`);
138
+
116
139
  // Copy data directory (dereference symlinks to copy actual content)
117
140
  console.log("📁 Copying data files...");
118
141
  const dataOutputDir = join(outputDir, "data");
@@ -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
@@ -104,5 +104,5 @@ export function createBadge(text, type = "default") {
104
104
  * @returns {HTMLElement}
105
105
  */
106
106
  export function createTag(text) {
107
- return span({ className: "tag" }, text);
107
+ return span({ className: "info-tag" }, text);
108
108
  }
@@ -188,7 +188,7 @@ export function createTagsList(tags, emptyMessage = "None") {
188
188
  return p({ className: "text-muted" }, emptyMessage);
189
189
  }
190
190
 
191
- return div({ className: "tags" }, ...tags.map((tag) => createTag(tag)));
191
+ return div({ className: "info-tags" }, ...tags.map((tag) => createTag(tag)));
192
192
  }
193
193
 
194
194
  /**
@@ -176,14 +176,14 @@
176
176
  border: 1px solid var(--color-border);
177
177
  }
178
178
 
179
- /* Tags */
180
- .tags {
179
+ /* Info tags */
180
+ .info-tags {
181
181
  display: flex;
182
182
  gap: var(--space-sm);
183
183
  flex-wrap: wrap;
184
184
  }
185
185
 
186
- .tag {
186
+ .info-tag {
187
187
  display: inline-block;
188
188
  padding: var(--space-xs) var(--space-sm);
189
189
  background: var(--color-bg);
@@ -194,10 +194,10 @@
194
194
  /* Preserve badge colors */
195
195
  .slide-view .badge,
196
196
  .slide-view .level-badge,
197
- .slide-view .tag,
197
+ .slide-view .info-tag,
198
198
  .badge,
199
199
  .level-badge,
200
- .tag {
200
+ .info-tag {
201
201
  -webkit-print-color-adjust: exact;
202
202
  print-color-adjust: exact;
203
203
  background-color: inherit !important;
@@ -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
  | ---------- | ---------- | ----------- |
@@ -37,7 +37,10 @@ description: |
37
37
  {{/hasStages}}
38
38
  {{#hasToolReferences}}
39
39
 
40
- # Recommended Tools
40
+ # Required Tools
41
+
42
+ Use these tools when applying this skill. Alternative tools require documented
43
+ justification with acknowledged trade-offs.
41
44
 
42
45
  | Tool | Use When |
43
46
  | ---- | -------- |