@forwardimpact/pathway 0.25.21 → 0.25.24

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 (50) hide show
  1. package/bin/fit-pathway.js +117 -325
  2. package/package.json +2 -2
  3. package/src/commands/agent-io.js +1 -1
  4. package/src/commands/agent.js +25 -23
  5. package/src/commands/behaviour.js +7 -7
  6. package/src/commands/build-bundle.js +88 -0
  7. package/src/commands/build-packs.js +566 -0
  8. package/src/commands/build.js +27 -84
  9. package/src/commands/command-factory.js +2 -2
  10. package/src/commands/discipline.js +7 -7
  11. package/src/commands/driver.js +8 -8
  12. package/src/commands/index.js +0 -1
  13. package/src/commands/interview.js +4 -4
  14. package/src/commands/job.js +24 -18
  15. package/src/commands/level.js +7 -7
  16. package/src/commands/progress.js +4 -4
  17. package/src/commands/questions.js +10 -8
  18. package/src/commands/skill.js +10 -10
  19. package/src/commands/stage.js +7 -7
  20. package/src/commands/tool.js +6 -6
  21. package/src/commands/track.js +7 -7
  22. package/src/css/pages/agent-builder.css +48 -0
  23. package/src/formatters/interview/shared.js +6 -4
  24. package/src/formatters/progress/shared.js +9 -20
  25. package/src/formatters/questions/yaml.js +1 -1
  26. package/src/formatters/skill/shared.js +9 -2
  27. package/src/formatters/track/shared.js +4 -1
  28. package/src/index.html +1 -1
  29. package/src/lib/cli-command.js +33 -33
  30. package/src/lib/cli-output.js +9 -189
  31. package/src/pages/agent-builder-install.js +118 -0
  32. package/src/pages/agent-builder-preview.js +3 -3
  33. package/src/pages/agent-builder.js +23 -1
  34. package/src/pages/progress.js +3 -3
  35. package/src/pages/skill.js +5 -2
  36. package/src/commands/init.js +0 -64
  37. package/src/lib/job-cache.js +0 -89
  38. package/starter/behaviours/systems_thinking.yaml +0 -32
  39. package/starter/capabilities/delivery.yaml +0 -105
  40. package/starter/capabilities/reliability.yaml +0 -72
  41. package/starter/disciplines/software_engineering.yaml +0 -46
  42. package/starter/drivers.yaml +0 -10
  43. package/starter/framework.yaml +0 -49
  44. package/starter/levels.yaml +0 -39
  45. package/starter/questions/behaviours/.gitkeep +0 -0
  46. package/starter/questions/capabilities/.gitkeep +0 -0
  47. package/starter/questions/skills/.gitkeep +0 -0
  48. package/starter/stages.yaml +0 -21
  49. package/starter/tracks/forward_deployed.yaml +0 -33
  50. package/starter/tracks/platform.yaml +0 -33
@@ -89,7 +89,7 @@ export function createEntityCommand({
89
89
  function handleValidate({ data, _entityName, pluralName, validate }) {
90
90
  if (!validate) {
91
91
  console.log(`No specific validation for ${pluralName}.`);
92
- console.log(`Run 'bunx pathway --validate' for full data validation.`);
92
+ console.log(`Run 'npx fit-pathway --validate' for full data validation.`);
93
93
  return;
94
94
  }
95
95
 
@@ -178,7 +178,7 @@ export function createCompositeCommand({
178
178
  return async function runCommand({ data, args, options }) {
179
179
  if (args.length < requiredArgs.length) {
180
180
  const argsList = requiredArgs.map((arg) => `<${arg}>`).join(" ");
181
- console.error(`Usage: bunx pathway ${commandName} ${argsList}`);
181
+ console.error(`Usage: npx fit-pathway ${commandName} ${argsList}`);
182
182
  if (usageExample) {
183
183
  console.error(`Example: ${usageExample}`);
184
184
  }
@@ -4,15 +4,15 @@
4
4
  * Handles discipline summary, listing, and detail display in the terminal.
5
5
  *
6
6
  * Usage:
7
- * bunx pathway discipline # Summary with stats
8
- * bunx pathway discipline --list # IDs only (for piping)
9
- * bunx pathway discipline <id> # Detail view
10
- * bunx pathway discipline --validate # Validation checks
7
+ * npx fit-pathway discipline # Summary with stats
8
+ * npx fit-pathway discipline --list # IDs only (for piping)
9
+ * npx fit-pathway discipline <id> # Detail view
10
+ * npx fit-pathway discipline --validate # Validation checks
11
11
  */
12
12
 
13
13
  import { createEntityCommand } from "./command-factory.js";
14
14
  import { disciplineToMarkdown } from "../formatters/discipline/markdown.js";
15
- import { formatTable } from "../lib/cli-output.js";
15
+ import { formatTable } from "@forwardimpact/libcli";
16
16
 
17
17
  /**
18
18
  * Format discipline list item for --list output
@@ -43,8 +43,8 @@ function formatSummary(disciplines) {
43
43
 
44
44
  console.log(formatTable(["ID", "Specialization", "Type", "Tracks"], rows));
45
45
  console.log(`\nTotal: ${disciplines.length} disciplines`);
46
- console.log(`\nRun 'bunx pathway discipline --list' for IDs and names`);
47
- console.log(`Run 'bunx pathway discipline <id>' for details\n`);
46
+ console.log(`\nRun 'npx fit-pathway discipline --list' for IDs and names`);
47
+ console.log(`Run 'npx fit-pathway discipline <id>' for details\n`);
48
48
  }
49
49
 
50
50
  /**
@@ -4,20 +4,20 @@
4
4
  * Handles driver summary, listing, and detail display in the terminal.
5
5
  *
6
6
  * Usage:
7
- * bunx pathway driver # Summary with stats
8
- * bunx pathway driver --list # IDs only (for piping)
9
- * bunx pathway driver <id> # Detail view
10
- * bunx pathway driver --validate # Validation checks
7
+ * npx fit-pathway driver # Summary with stats
8
+ * npx fit-pathway driver --list # IDs only (for piping)
9
+ * npx fit-pathway driver <id> # Detail view
10
+ * npx fit-pathway driver --validate # Validation checks
11
11
  */
12
12
 
13
13
  import { createEntityCommand } from "./command-factory.js";
14
14
  import { prepareDriverDetail } from "../formatters/driver/shared.js";
15
- import { formatTable } from "../lib/cli-output.js";
16
15
  import {
16
+ formatTable,
17
17
  formatHeader,
18
18
  formatSubheader,
19
19
  formatBullet,
20
- } from "../lib/cli-output.js";
20
+ } from "@forwardimpact/libcli";
21
21
  import { getConceptEmoji } from "@forwardimpact/map/levels";
22
22
 
23
23
  /**
@@ -52,8 +52,8 @@ function formatSummary(drivers, data) {
52
52
 
53
53
  console.log(formatTable(["ID", "Name", "Skills", "Behaviours"], rows));
54
54
  console.log(`\nTotal: ${drivers.length} drivers`);
55
- console.log(`\nRun 'bunx pathway driver --list' for IDs and names`);
56
- console.log(`Run 'bunx pathway driver <id>' for details\n`);
55
+ console.log(`\nRun 'npx fit-pathway driver --list' for IDs and names`);
56
+ console.log(`Run 'npx fit-pathway driver <id>' for details\n`);
57
57
  }
58
58
 
59
59
  /**
@@ -17,6 +17,5 @@ export { runInterviewCommand } from "./interview.js";
17
17
  export { runProgressCommand } from "./progress.js";
18
18
  export { runQuestionsCommand } from "./questions.js";
19
19
  export { runServeCommand } from "./serve.js";
20
- export { runInitCommand } from "./init.js";
21
20
  export { runSiteCommand } from "./site.js";
22
21
  export { runUpdateCommand } from "./update.js";
@@ -4,9 +4,9 @@
4
4
  * Generates and displays interview questions in the terminal.
5
5
  *
6
6
  * Usage:
7
- * bunx fit-pathway interview <discipline> <level> # All interview types
8
- * bunx fit-pathway interview <discipline> <level> --track=<track> # With track
9
- * bunx fit-pathway interview <discipline> <level> --track=<track> --type=mission # Single type
7
+ * npx fit-pathway interview <discipline> <level> # All interview types
8
+ * npx fit-pathway interview <discipline> <level> --track=<track> # With track
9
+ * npx fit-pathway interview <discipline> <level> --track=<track> --type=mission # Single type
10
10
  */
11
11
 
12
12
  import { createCompositeCommand } from "./command-factory.js";
@@ -109,5 +109,5 @@ export const runInterviewCommand = createCompositeCommand({
109
109
  }
110
110
  },
111
111
  usageExample:
112
- "bunx fit-pathway interview software_engineering J090 --track=platform --type=mission",
112
+ "npx fit-pathway interview software_engineering J090 --track=platform --type=mission",
113
113
  });
@@ -4,14 +4,14 @@
4
4
  * Generates and displays job definitions in the terminal.
5
5
  *
6
6
  * Usage:
7
- * bunx pathway job # Summary with stats
8
- * bunx pathway job --list # All valid combinations (for piping)
9
- * bunx pathway job <discipline> <level> # Detail view (trackless)
10
- * bunx pathway job <discipline> <level> --track=<track> # Detail view (with track)
11
- * bunx pathway job <d> <l> [--track=<t>] --skills # Plain list of skill IDs
12
- * bunx pathway job <d> <l> [--track=<t>] --tools # Plain list of tool names
13
- * bunx pathway job se L3 --track=platform --checklist=code # Show checklist for handoff
14
- * bunx pathway job --validate # Validation checks
7
+ * npx fit-pathway job # Summary with stats
8
+ * npx fit-pathway job --list # All valid combinations (for piping)
9
+ * npx fit-pathway job <discipline> <level> # Detail view (trackless)
10
+ * npx fit-pathway job <discipline> <level> --track=<track> # Detail view (with track)
11
+ * npx fit-pathway job <d> <l> [--track=<t>] --skills # Plain list of skill IDs
12
+ * npx fit-pathway job <d> <l> [--track=<t>] --tools # Plain list of tool names
13
+ * npx fit-pathway job se L3 --track=platform --checklist=code # Show checklist for handoff
14
+ * npx fit-pathway job --validate # Validation checks
15
15
  */
16
16
 
17
17
  import { prepareJobDetail } from "@forwardimpact/libskill/job";
@@ -20,7 +20,7 @@ import {
20
20
  generateJobTitle,
21
21
  generateAllJobs,
22
22
  } from "@forwardimpact/libskill/derivation";
23
- import { formatTable } from "../lib/cli-output.js";
23
+ import { formatTable } from "@forwardimpact/libcli";
24
24
  import {
25
25
  deriveChecklist,
26
26
  formatChecklistMarkdown,
@@ -44,7 +44,11 @@ function formatJob(view, _options, entities, jobTemplate) {
44
44
  */
45
45
  function printJobList(filteredJobs) {
46
46
  for (const job of filteredJobs) {
47
- const title = generateJobTitle(job.discipline, job.level, job.track);
47
+ const title = generateJobTitle({
48
+ discipline: job.discipline,
49
+ level: job.level,
50
+ track: job.track,
51
+ });
48
52
  if (job.track) {
49
53
  console.log(
50
54
  `${job.discipline.id} ${job.level.id} ${job.track.id}, ${title}`,
@@ -92,10 +96,10 @@ function printJobSummary(filteredJobs, options) {
92
96
  );
93
97
  console.log(`\nTotal: ${filteredJobs.length} valid job combinations`);
94
98
  console.log(
95
- `\nRun 'bunx pathway job --list' for all combinations with titles`,
99
+ `\nRun 'npx fit-pathway job --list' for all combinations with titles`,
96
100
  );
97
101
  console.log(
98
- `Run 'bunx pathway job <discipline> <level> [--track=<track>]' for details\n`,
102
+ `Run 'npx fit-pathway job <discipline> <level> [--track=<track>]' for details\n`,
99
103
  );
100
104
  }
101
105
 
@@ -109,7 +113,7 @@ function handleSingleArg(arg, data) {
109
113
  const isTrack = data.tracks.some((t) => t.id === arg);
110
114
  if (isLevel) {
111
115
  console.error(
112
- `Missing discipline. Usage: bunx pathway job <discipline> ${arg} [--track=<track>]`,
116
+ `Missing discipline. Usage: npx fit-pathway job <discipline> ${arg} [--track=<track>]`,
113
117
  );
114
118
  console.error(
115
119
  `Disciplines: ${data.disciplines.map((d) => d.id).join(", ")}`,
@@ -117,13 +121,13 @@ function handleSingleArg(arg, data) {
117
121
  } else if (isTrack) {
118
122
  console.error(`Track must be passed as a flag: --track=${arg}`);
119
123
  console.error(
120
- `Usage: bunx pathway job <discipline> <level> --track=${arg}`,
124
+ `Usage: npx fit-pathway job <discipline> <level> --track=${arg}`,
121
125
  );
122
126
  } else {
123
127
  console.error(
124
- "Usage: bunx pathway job <discipline> <level> [--track=<track>]",
128
+ "Usage: npx fit-pathway job <discipline> <level> [--track=<track>]",
125
129
  );
126
- console.error(" bunx pathway job --list");
130
+ console.error(" npx fit-pathway job --list");
127
131
  }
128
132
  process.exit(1);
129
133
  }
@@ -148,7 +152,7 @@ function resolveJobEntities(data, args, options) {
148
152
  if (maybeLevel && maybeDiscipline) {
149
153
  console.error(`Arguments are in the wrong order. Try:`);
150
154
  console.error(
151
- ` bunx pathway job ${args[1]} ${args[0]}${options.track ? ` --track=${options.track}` : ""}`,
155
+ ` npx fit-pathway job ${args[1]} ${args[0]}${options.track ? ` --track=${options.track}` : ""}`,
152
156
  );
153
157
  } else {
154
158
  console.error(`Discipline not found: ${args[0]}`);
@@ -165,7 +169,9 @@ function resolveJobEntities(data, args, options) {
165
169
  console.error(
166
170
  `Track must be passed as a flag, not a positional argument:`,
167
171
  );
168
- console.error(` bunx pathway job ${args[0]} <level> --track=${args[1]}`);
172
+ console.error(
173
+ ` npx fit-pathway job ${args[0]} <level> --track=${args[1]}`,
174
+ );
169
175
  console.error(`Levels: ${data.levels.map((g) => g.id).join(", ")}`);
170
176
  } else {
171
177
  console.error(`Level not found: ${args[1]}`);
@@ -4,15 +4,15 @@
4
4
  * Handles level summary, listing, and detail display in the terminal.
5
5
  *
6
6
  * Usage:
7
- * bunx pathway level # Summary with stats
8
- * bunx pathway level --list # IDs only (for piping)
9
- * bunx pathway level <id> # Detail view
10
- * bunx pathway level --validate # Validation checks
7
+ * npx fit-pathway level # Summary with stats
8
+ * npx fit-pathway level --list # IDs only (for piping)
9
+ * npx fit-pathway level <id> # Detail view
10
+ * npx fit-pathway level --validate # Validation checks
11
11
  */
12
12
 
13
13
  import { createEntityCommand } from "./command-factory.js";
14
14
  import { levelToMarkdown } from "../formatters/level/markdown.js";
15
- import { formatTable } from "../lib/cli-output.js";
15
+ import { formatTable } from "@forwardimpact/libcli";
16
16
  import { getConceptEmoji } from "@forwardimpact/map/levels";
17
17
  import { capitalize } from "../formatters/shared.js";
18
18
 
@@ -57,8 +57,8 @@ function formatSummary(levels, data) {
57
57
  ),
58
58
  );
59
59
  console.log(`\nTotal: ${levels.length} levels`);
60
- console.log(`\nRun 'bunx pathway level --list' for IDs and titles`);
61
- console.log(`Run 'bunx pathway level <id>' for details\n`);
60
+ console.log(`\nRun 'npx fit-pathway level --list' for IDs and titles`);
61
+ console.log(`Run 'npx fit-pathway level <id>' for details\n`);
62
62
  }
63
63
 
64
64
  /**
@@ -4,9 +4,9 @@
4
4
  * Shows career progression analysis in the terminal.
5
5
  *
6
6
  * Usage:
7
- * bunx pathway progress <discipline> <level> # Progress for trackless job
8
- * bunx pathway progress <discipline> <level> --track=<track> # Progress with track
9
- * bunx pathway progress <discipline> <from_level> --compare=<to_level> # Compare levels
7
+ * npx fit-pathway progress <discipline> <level> # Progress for trackless job
8
+ * npx fit-pathway progress <discipline> <level> --track=<track> # Progress with track
9
+ * npx fit-pathway progress <discipline> <from_level> --compare=<to_level> # Compare levels
10
10
  */
11
11
 
12
12
  import { createCompositeCommand } from "./command-factory.js";
@@ -80,5 +80,5 @@ export const runProgressCommand = createCompositeCommand({
80
80
  }),
81
81
  formatter: formatProgress,
82
82
  usageExample:
83
- "bunx pathway progress software_engineering L3 --track=platform --compare=L4",
83
+ "npx fit-pathway progress software_engineering L3 --track=platform --compare=L4",
84
84
  });
@@ -4,10 +4,10 @@
4
4
  * Browse and compare interview questions across skills and behaviours.
5
5
  *
6
6
  * Usage:
7
- * bunx pathway questions # Summary with stats
8
- * bunx pathway questions --list # Question IDs (for piping)
9
- * bunx pathway questions --level=practitioner # Filter by level
10
- * bunx pathway questions --stats # Detailed statistics
7
+ * npx fit-pathway questions # Summary with stats
8
+ * npx fit-pathway questions --list # Question IDs (for piping)
9
+ * npx fit-pathway questions --level=practitioner # Filter by level
10
+ * npx fit-pathway questions --stats # Detailed statistics
11
11
  */
12
12
 
13
13
  import {
@@ -17,7 +17,7 @@ import {
17
17
  import { questionsToMarkdown } from "../formatters/questions/markdown.js";
18
18
  import { questionsToYaml } from "../formatters/questions/yaml.js";
19
19
  import { questionsToJson } from "../formatters/questions/json.js";
20
- import { formatTable } from "../lib/cli-output.js";
20
+ import { formatTable } from "@forwardimpact/libcli";
21
21
 
22
22
  /**
23
23
  * Parse questions command options
@@ -97,9 +97,11 @@ function showQuestionsSummary(data) {
97
97
  console.log("\nBehaviour Questions:");
98
98
  console.log(formatTable(["Maturity", "Count"], behaviourRows));
99
99
 
100
- console.log(`\nRun 'bunx pathway questions --list' for question IDs`);
101
- console.log(`Run 'bunx pathway questions --stats' for detailed stats`);
102
- console.log(`Run 'bunx pathway questions --level=practitioner' to filter\n`);
100
+ console.log(`\nRun 'npx fit-pathway questions --list' for question IDs`);
101
+ console.log(`Run 'npx fit-pathway questions --stats' for detailed stats`);
102
+ console.log(
103
+ `Run 'npx fit-pathway questions --level=practitioner' to filter\n`,
104
+ );
103
105
  }
104
106
 
105
107
  /**
@@ -4,18 +4,18 @@
4
4
  * Handles skill summary, listing, and detail display in the terminal.
5
5
  *
6
6
  * Usage:
7
- * bunx pathway skill # Summary with stats
8
- * bunx pathway skill --list # IDs only (for piping)
9
- * bunx pathway skill <id> # Detail view
10
- * bunx pathway skill <id> --agent # Agent SKILL.md output
11
- * bunx pathway skill --validate # Validation checks
7
+ * npx fit-pathway skill # Summary with stats
8
+ * npx fit-pathway skill --list # IDs only (for piping)
9
+ * npx fit-pathway skill <id> # Detail view
10
+ * npx fit-pathway skill <id> --agent # Agent SKILL.md output
11
+ * npx fit-pathway skill --validate # Validation checks
12
12
  */
13
13
 
14
14
  import { createEntityCommand } from "./command-factory.js";
15
15
  import { skillToMarkdown } from "../formatters/skill/markdown.js";
16
16
  import { prepareSkillsList } from "../formatters/skill/shared.js";
17
17
  import { getConceptEmoji } from "@forwardimpact/map/levels";
18
- import { formatTable, formatError } from "../lib/cli-output.js";
18
+ import { formatTable, formatError } from "@forwardimpact/libcli";
19
19
  import { generateSkillMarkdown } from "@forwardimpact/libskill/agent";
20
20
  import { formatAgentSkill } from "../formatters/agent/skill.js";
21
21
 
@@ -40,8 +40,8 @@ function formatSummary(skills, data) {
40
40
 
41
41
  console.log(formatTable(["Capability", "Count", "Agent"], rows));
42
42
  console.log(`\nTotal: ${skills.length} skills`);
43
- console.log(`\nRun 'bunx pathway skill --list' for IDs`);
44
- console.log(`Run 'bunx pathway skill <id>' for details\n`);
43
+ console.log(`\nRun 'npx fit-pathway skill --list' for IDs`);
44
+ console.log(`Run 'npx fit-pathway skill <id>' for details\n`);
45
45
  }
46
46
 
47
47
  /**
@@ -73,13 +73,13 @@ async function formatAgentDetail(skill, stages, templateLoader, dataDir) {
73
73
  console.error(formatError(`Skill '${skill.id}' has no agent section`));
74
74
  console.error(`\nSkills with agent support:`);
75
75
  console.error(
76
- ` bunx pathway skill --list | xargs -I{} sh -c 'bunx pathway skill {} --json | jq -e .skill.agent > /dev/null && echo {}'`,
76
+ ` npx fit-pathway skill --list | xargs -I{} sh -c 'npx fit-pathway skill {} --json | jq -e .skill.agent > /dev/null && echo {}'`,
77
77
  );
78
78
  process.exit(1);
79
79
  }
80
80
 
81
81
  const template = templateLoader.load("skill.template.md", dataDir);
82
- const skillMd = generateSkillMarkdown(skill, stages);
82
+ const skillMd = generateSkillMarkdown({ skillData: skill, stages });
83
83
  const output = formatAgentSkill(skillMd, template);
84
84
  console.log(output);
85
85
  }
@@ -4,9 +4,9 @@
4
4
  * Handles stage summary, listing, and detail display in the terminal.
5
5
  *
6
6
  * Usage:
7
- * bunx pathway stage # Summary with lifecycle flow
8
- * bunx pathway stage --list # IDs only (for piping)
9
- * bunx pathway stage <id> # Detail view
7
+ * npx fit-pathway stage # Summary with lifecycle flow
8
+ * npx fit-pathway stage --list # IDs only (for piping)
9
+ * npx fit-pathway stage <id> # Detail view
10
10
  */
11
11
 
12
12
  import { createEntityCommand } from "./command-factory.js";
@@ -14,12 +14,12 @@ import {
14
14
  prepareStageDetail,
15
15
  getStageEmoji,
16
16
  } from "../formatters/stage/shared.js";
17
- import { formatTable } from "../lib/cli-output.js";
18
17
  import {
18
+ formatTable,
19
19
  formatHeader,
20
20
  formatSubheader,
21
21
  formatBullet,
22
- } from "../lib/cli-output.js";
22
+ } from "@forwardimpact/libcli";
23
23
 
24
24
  /**
25
25
  * Format stage list item for --list output
@@ -52,8 +52,8 @@ function formatSummary(stages, _data) {
52
52
 
53
53
  console.log(formatTable(["ID", "Name", "Mode", "Tools", "Handoffs"], rows));
54
54
  console.log(`\nTotal: ${stages.length} stages`);
55
- console.log(`\nRun 'bunx pathway stage --list' for IDs and names`);
56
- console.log(`Run 'bunx pathway stage <id>' for details\n`);
55
+ console.log(`\nRun 'npx fit-pathway stage --list' for IDs and names`);
56
+ console.log(`Run 'npx fit-pathway stage <id>' for details\n`);
57
57
  }
58
58
 
59
59
  /**
@@ -4,9 +4,9 @@
4
4
  * Handles tool summary, listing, and detail display in the terminal.
5
5
  *
6
6
  * Usage:
7
- * bunx pathway tool # Summary with stats
8
- * bunx pathway tool --list # Tool names only (for piping)
9
- * bunx pathway tool <name> # Detail view for specific tool
7
+ * npx fit-pathway tool # Summary with stats
8
+ * npx fit-pathway tool --list # Tool names only (for piping)
9
+ * npx fit-pathway tool <name> # Detail view for specific tool
10
10
  */
11
11
 
12
12
  import { truncate } from "../formatters/shared.js";
@@ -15,7 +15,7 @@ import {
15
15
  formatTable,
16
16
  formatHeader,
17
17
  formatSubheader,
18
- } from "../lib/cli-output.js";
18
+ } from "@forwardimpact/libcli";
19
19
 
20
20
  /**
21
21
  * Run tool command
@@ -89,9 +89,9 @@ function formatSummary(tools, totalCount) {
89
89
  console.log(`(showing top 15 by usage)`);
90
90
  }
91
91
  console.log(
92
- `\nRun 'bunx pathway tool --list' for all tool names and descriptions`,
92
+ `\nRun 'npx fit-pathway tool --list' for all tool names and descriptions`,
93
93
  );
94
- console.log(`Run 'bunx pathway tool <name>' for details\n`);
94
+ console.log(`Run 'npx fit-pathway tool <name>' for details\n`);
95
95
  }
96
96
 
97
97
  /**
@@ -4,16 +4,16 @@
4
4
  * Handles track summary, listing, and detail display in the terminal.
5
5
  *
6
6
  * Usage:
7
- * bunx pathway track # Summary with stats
8
- * bunx pathway track --list # IDs only (for piping)
9
- * bunx pathway track <id> # Detail view
10
- * bunx pathway track --validate # Validation checks
7
+ * npx fit-pathway track # Summary with stats
8
+ * npx fit-pathway track --list # IDs only (for piping)
9
+ * npx fit-pathway track <id> # Detail view
10
+ * npx fit-pathway track --validate # Validation checks
11
11
  */
12
12
 
13
13
  import { createEntityCommand } from "./command-factory.js";
14
14
  import { trackToMarkdown } from "../formatters/track/markdown.js";
15
15
  import { sortTracksByName } from "../formatters/track/shared.js";
16
- import { formatTable } from "../lib/cli-output.js";
16
+ import { formatTable } from "@forwardimpact/libcli";
17
17
  import { getConceptEmoji } from "@forwardimpact/map/levels";
18
18
 
19
19
  /**
@@ -49,8 +49,8 @@ function formatSummary(tracks, data) {
49
49
 
50
50
  console.log(formatTable(["ID", "Name", "Modifiers", "Disciplines"], rows));
51
51
  console.log(`\nTotal: ${tracks.length} tracks`);
52
- console.log(`\nRun 'bunx pathway track --list' for IDs and names`);
53
- console.log(`Run 'bunx pathway track <id>' for details\n`);
52
+ console.log(`\nRun 'npx fit-pathway track --list' for IDs and names`);
53
+ console.log(`Run 'npx fit-pathway track <id>' for details\n`);
54
54
  }
55
55
 
56
56
  /**
@@ -33,6 +33,54 @@
33
33
  gap: var(--space-xl);
34
34
  }
35
35
 
36
+ /* Install section — ecosystem-tool install commands shown between the
37
+ dropdowns and the preview cards. Uses the same surface treatment as
38
+ the form so the two blocks read as a matched pair. */
39
+ .agent-install-section {
40
+ background: var(--color-surface);
41
+ border-radius: var(--radius-lg);
42
+ padding: var(--space-xl);
43
+ box-shadow: var(--shadow-md);
44
+ margin-bottom: var(--space-xl);
45
+ display: flex;
46
+ flex-direction: column;
47
+ gap: var(--space-lg);
48
+ }
49
+
50
+ .agent-install-header h2 {
51
+ margin: 0 0 var(--space-sm) 0;
52
+ }
53
+
54
+ .agent-install-description {
55
+ margin: 0;
56
+ }
57
+
58
+ .agent-install-commands {
59
+ display: flex;
60
+ flex-direction: column;
61
+ gap: var(--space-md);
62
+ }
63
+
64
+ .agent-install-command {
65
+ display: flex;
66
+ flex-direction: column;
67
+ gap: var(--space-xs);
68
+ }
69
+
70
+ .agent-install-command-label {
71
+ margin: 0;
72
+ font-size: var(--font-size-sm);
73
+ font-weight: 600;
74
+ color: var(--color-text-secondary);
75
+ }
76
+
77
+ /* Allow the command prompts inside the install section to grow beyond the
78
+ 600px center-aligned default used on the landing hero. */
79
+ .agent-install-command .command-prompt {
80
+ max-width: none;
81
+ margin: 0;
82
+ }
83
+
36
84
  /* Agent section — spacing container, no surface */
37
85
  .agent-section {
38
86
  margin-bottom: var(--space-lg);
@@ -14,7 +14,9 @@ import {
14
14
  deriveDecompositionInterview,
15
15
  deriveStakeholderInterview,
16
16
  } from "@forwardimpact/libskill/interview";
17
- import { getOrCreateJob } from "@forwardimpact/libskill/job-cache";
17
+ import { createJobCache } from "@forwardimpact/libskill/job-cache";
18
+
19
+ const jobCache = createJobCache();
18
20
 
19
21
  /**
20
22
  * Interview type configurations
@@ -140,7 +142,7 @@ export function prepareInterviewDetail({
140
142
  }) {
141
143
  if (!discipline || !level) return null;
142
144
 
143
- const job = getOrCreateJob({
145
+ const job = jobCache.getOrCreate({
144
146
  discipline,
145
147
  level,
146
148
  track,
@@ -275,7 +277,7 @@ export function prepareInterviewBuilderPreview({
275
277
  };
276
278
  }
277
279
 
278
- const title = generateJobTitle(discipline, level, track);
280
+ const title = generateJobTitle({ discipline, level, track });
279
281
  const totalSkills = getDisciplineSkillIds(discipline).length;
280
282
 
281
283
  return {
@@ -320,7 +322,7 @@ export function prepareAllInterviews({
320
322
  // Track is optional (null = generalist)
321
323
  if (!discipline || !level) return null;
322
324
 
323
- const job = getOrCreateJob({
325
+ const job = jobCache.getOrCreate({
324
326
  discipline,
325
327
  level,
326
328
  track,
@@ -13,7 +13,9 @@ import {
13
13
  analyzeCustomProgression,
14
14
  getNextLevel,
15
15
  } from "@forwardimpact/libskill/progression";
16
- import { getOrCreateJob } from "@forwardimpact/libskill/job-cache";
16
+ import { createJobCache } from "@forwardimpact/libskill/job-cache";
17
+
18
+ const jobCache = createJobCache();
17
19
 
18
20
  /**
19
21
  * Get the next level for progression
@@ -22,20 +24,7 @@ import { getOrCreateJob } from "@forwardimpact/libskill/job-cache";
22
24
  * @returns {Object|null}
23
25
  */
24
26
  export function getDefaultTargetLevel(currentLevel, levels) {
25
- return getNextLevel(currentLevel, levels);
26
- }
27
-
28
- /**
29
- * Check if a job combination is valid
30
- * @param {Object} params
31
- * @param {Object} params.discipline
32
- * @param {Object} params.level
33
- * @param {Object} params.track
34
- * @param {Array} [params.levels] - All levels for validation
35
- * @returns {boolean}
36
- */
37
- export function isValidCombination({ discipline, level, track, levels }) {
38
- return isValidJobCombination({ discipline, level, track, levels });
27
+ return getNextLevel({ level: currentLevel, levels });
39
28
  }
40
29
 
41
30
  /**
@@ -69,7 +58,7 @@ export function prepareCurrentJob({
69
58
  }) {
70
59
  if (!discipline || !level) return null;
71
60
 
72
- const job = getOrCreateJob({
61
+ const job = jobCache.getOrCreate({
73
62
  discipline,
74
63
  level,
75
64
  track,
@@ -148,8 +137,8 @@ export function prepareCareerProgressPreview({
148
137
  };
149
138
  }
150
139
 
151
- const title = generateJobTitle(discipline, level, track);
152
- const nextLevel = getNextLevel(level, levels);
140
+ const title = generateJobTitle({ discipline, level, track });
141
+ const nextLevel = getNextLevel({ level, levels });
153
142
 
154
143
  // Find other valid tracks for comparison (exclude current track if any)
155
144
  const validTracks = tracks.filter(
@@ -209,7 +198,7 @@ export function prepareProgressDetail({
209
198
  if (!fromDiscipline || !fromLevel) return null;
210
199
  if (!toDiscipline || !toLevel) return null;
211
200
 
212
- const fromJob = getOrCreateJob({
201
+ const fromJob = jobCache.getOrCreate({
213
202
  discipline: fromDiscipline,
214
203
  level: fromLevel,
215
204
  track: fromTrack,
@@ -218,7 +207,7 @@ export function prepareProgressDetail({
218
207
  capabilities,
219
208
  });
220
209
 
221
- const toJob = getOrCreateJob({
210
+ const toJob = jobCache.getOrCreate({
222
211
  discipline: toDiscipline,
223
212
  level: toLevel,
224
213
  track: toTrack,
@@ -26,7 +26,7 @@ export function questionsToYaml(view, _options = {}) {
26
26
 
27
27
  const filterStr =
28
28
  filterParts.length > 0 ? filterParts.join(" ") : "(no filters)";
29
- const header = `# Generated by: bunx pathway questions ${filterStr}\n# Questions: ${questions.length}\n\n`;
29
+ const header = `# Generated by: npx fit-pathway questions ${filterStr}\n# Questions: ${questions.length}\n\n`;
30
30
 
31
31
  // Group questions by source
32
32
  const bySource = {};