@forwardimpact/pathway 0.22.0 → 0.23.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/package.json +3 -2
- package/src/commands/agent.js +7 -3
- package/src/commands/behaviour.js +11 -1
- package/src/commands/build.js +11 -2
- package/src/commands/command-factory.js +4 -2
- package/src/commands/dev.js +9 -2
- package/src/commands/discipline.js +19 -2
- package/src/commands/driver.js +11 -1
- package/src/commands/job.js +25 -12
- package/src/commands/level.js +19 -3
- package/src/commands/skill.js +11 -1
- package/src/commands/stage.js +11 -1
- package/src/commands/tool.js +4 -3
- package/src/commands/track.js +11 -1
- package/src/components/card.js +8 -104
- package/src/components/comparison-radar.js +1 -1
- package/src/components/detail.js +16 -118
- package/src/components/error-page.js +8 -68
- package/src/components/grid.js +12 -106
- package/src/components/list.js +7 -116
- package/src/components/nav.js +7 -60
- package/src/css/bundles/app.css +25 -21
- package/src/css/bundles/handout.css +33 -33
- package/src/css/bundles/slides.css +25 -25
- package/src/formatters/interview/shared.js +3 -3
- package/src/formatters/job/description.js +2 -2
- package/src/formatters/progress/shared.js +3 -3
- package/src/formatters/skill/shared.js +1 -1
- package/src/formatters/track/shared.js +1 -1
- package/src/handout.html +32 -13
- package/src/index.html +32 -13
- package/src/lib/error-boundary.js +3 -66
- package/src/lib/errors.js +7 -45
- package/src/lib/job-cache.js +1 -1
- package/src/lib/markdown.js +2 -109
- package/src/lib/reactive.js +7 -73
- package/src/lib/render.js +49 -197
- package/src/lib/router-core.js +2 -156
- package/src/lib/router-pages.js +2 -11
- package/src/lib/router-slides.js +2 -197
- package/src/lib/state.js +14 -63
- package/src/lib/utils.js +3 -10
- package/src/lib/yaml-loader.js +13 -71
- package/src/pages/agent-builder.js +1 -1
- package/src/pages/assessment-results.js +1 -1
- package/src/pages/job-builder.js +1 -1
- package/src/pages/job.js +1 -1
- package/src/pages/skill.js +1 -1
- package/src/slide-main.js +1 -1
- package/src/slides/index.js +1 -1
- package/src/slides/job.js +1 -1
- package/src/slides/overview.js +1 -1
- package/src/slides.html +32 -13
- package/src/css/base.css +0 -56
- package/src/css/components/badges.css +0 -232
- package/src/css/components/buttons.css +0 -101
- package/src/css/components/forms.css +0 -191
- package/src/css/components/layout.css +0 -218
- package/src/css/components/nav.css +0 -206
- package/src/css/components/progress.css +0 -166
- package/src/css/components/states.css +0 -82
- package/src/css/components/surfaces.css +0 -347
- package/src/css/components/tables.css +0 -362
- package/src/css/components/top-bar.css +0 -180
- package/src/css/components/typography.css +0 -121
- package/src/css/components/utilities.css +0 -41
- package/src/css/pages/detail.css +0 -119
- package/src/css/reset.css +0 -50
- package/src/css/tokens.css +0 -162
- package/src/css/views/handout.css +0 -30
- package/src/css/views/print.css +0 -634
- package/src/css/views/slide-animations.css +0 -113
- package/src/css/views/slide-base.css +0 -331
- package/src/css/views/slide-sections.css +0 -597
- package/src/css/views/slide-tables.css +0 -275
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forwardimpact/pathway",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.0",
|
|
4
4
|
"description": "Career progression web app and CLI for exploring roles and generating agent teams",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -41,7 +41,8 @@
|
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@forwardimpact/map": "^0.11.0",
|
|
44
|
-
"@forwardimpact/
|
|
44
|
+
"@forwardimpact/libskill": "^3.0.0",
|
|
45
|
+
"@forwardimpact/libui": "^1.0.0",
|
|
45
46
|
"mustache": "^4.2.0",
|
|
46
47
|
"simple-icons": "^16.7.0",
|
|
47
48
|
"yaml": "^2.3.4"
|
package/src/commands/agent.js
CHANGED
|
@@ -42,7 +42,7 @@ import {
|
|
|
42
42
|
buildAgentIndex,
|
|
43
43
|
getDisciplineAbbreviation,
|
|
44
44
|
toKebabCase,
|
|
45
|
-
} from "@forwardimpact/
|
|
45
|
+
} from "@forwardimpact/libskill";
|
|
46
46
|
import { formatAgentProfile } from "../formatters/agent/profile.js";
|
|
47
47
|
import {
|
|
48
48
|
formatAgentSkill,
|
|
@@ -199,7 +199,7 @@ function showAgentSummary(data, agentData, skillsWithAgent) {
|
|
|
199
199
|
*/
|
|
200
200
|
function listAgentCombinations(data, agentData, verbose = false) {
|
|
201
201
|
if (!verbose) {
|
|
202
|
-
//
|
|
202
|
+
// Descriptive output for piping and AI agent discovery
|
|
203
203
|
for (const discipline of agentData.disciplines) {
|
|
204
204
|
for (const track of agentData.tracks) {
|
|
205
205
|
const humanDiscipline = data.disciplines.find(
|
|
@@ -209,7 +209,11 @@ function listAgentCombinations(data, agentData, verbose = false) {
|
|
|
209
209
|
if (humanDiscipline && humanTrack) {
|
|
210
210
|
const abbrev = getDisciplineAbbreviation(discipline.id);
|
|
211
211
|
const agentName = `${abbrev}-${toKebabCase(track.id)}`;
|
|
212
|
-
|
|
212
|
+
const specName =
|
|
213
|
+
humanDiscipline.specialization || humanDiscipline.id;
|
|
214
|
+
console.log(
|
|
215
|
+
`${agentName} ${discipline.id} ${track.id}, ${specName} (${humanTrack.name})`,
|
|
216
|
+
);
|
|
213
217
|
}
|
|
214
218
|
}
|
|
215
219
|
}
|
|
@@ -14,6 +14,15 @@ import { createEntityCommand } from "./command-factory.js";
|
|
|
14
14
|
import { behaviourToMarkdown } from "../formatters/behaviour/markdown.js";
|
|
15
15
|
import { formatTable } from "../lib/cli-output.js";
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Format behaviour list item for --list output
|
|
19
|
+
* @param {Object} behaviour - Behaviour entity
|
|
20
|
+
* @returns {string} Formatted list line
|
|
21
|
+
*/
|
|
22
|
+
function formatListItem(behaviour) {
|
|
23
|
+
return `${behaviour.id}, ${behaviour.name}`;
|
|
24
|
+
}
|
|
25
|
+
|
|
17
26
|
/**
|
|
18
27
|
* Format behaviour summary output
|
|
19
28
|
* @param {Array} behaviours - Raw behaviour entities
|
|
@@ -34,7 +43,7 @@ function formatSummary(behaviours, data) {
|
|
|
34
43
|
|
|
35
44
|
console.log(formatTable(["ID", "Name", "Drivers"], rows));
|
|
36
45
|
console.log(`\nTotal: ${behaviours.length} behaviours`);
|
|
37
|
-
console.log(`\nRun 'npx pathway behaviour --list' for IDs`);
|
|
46
|
+
console.log(`\nRun 'npx pathway behaviour --list' for IDs and names`);
|
|
38
47
|
console.log(`Run 'npx pathway behaviour <id>' for details\n`);
|
|
39
48
|
}
|
|
40
49
|
|
|
@@ -57,5 +66,6 @@ export const runBehaviourCommand = createEntityCommand({
|
|
|
57
66
|
}),
|
|
58
67
|
formatSummary,
|
|
59
68
|
formatDetail,
|
|
69
|
+
formatListItem,
|
|
60
70
|
emojiIcon: "🧠",
|
|
61
71
|
});
|
package/src/commands/build.js
CHANGED
|
@@ -42,7 +42,8 @@ function resolvePackageLib(packageName) {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
const mapLibDir = resolvePackageLib("@forwardimpact/map");
|
|
45
|
-
const modelLibDir = resolvePackageLib("@forwardimpact/
|
|
45
|
+
const modelLibDir = resolvePackageLib("@forwardimpact/libskill");
|
|
46
|
+
const uiLibDir = resolvePackageLib("@forwardimpact/libui");
|
|
46
47
|
|
|
47
48
|
/**
|
|
48
49
|
* Files and directories to copy from app/
|
|
@@ -141,13 +142,21 @@ ${framework.emojiIcon} Generating ${framework.title} static site...
|
|
|
141
142
|
}
|
|
142
143
|
}
|
|
143
144
|
|
|
144
|
-
// Copy @forwardimpact/map and @forwardimpact/
|
|
145
|
+
// Copy @forwardimpact/map and @forwardimpact/libskill packages
|
|
145
146
|
// These are needed by the browser's import map
|
|
146
147
|
console.log("📚 Copying package dependencies...");
|
|
147
148
|
await cp(mapLibDir, join(outputDir, "map/lib"), { recursive: true });
|
|
148
149
|
console.log(` ✓ map/lib`);
|
|
149
150
|
await cp(modelLibDir, join(outputDir, "model/lib"), { recursive: true });
|
|
150
151
|
console.log(` ✓ model/lib`);
|
|
152
|
+
// Copy libui JS (src/) and CSS (src/css/)
|
|
153
|
+
await cp(uiLibDir, join(outputDir, "ui/lib"), { recursive: true });
|
|
154
|
+
// CSS is within uiLibDir/css/ so it's already copied as ui/lib/css/
|
|
155
|
+
// Create ui/css/ symlink-like copy for the CSS @import paths
|
|
156
|
+
await cp(join(uiLibDir, "css"), join(outputDir, "ui/css"), {
|
|
157
|
+
recursive: true,
|
|
158
|
+
});
|
|
159
|
+
console.log(` ✓ ui/lib + ui/css`);
|
|
151
160
|
|
|
152
161
|
// Copy data directory (dereference symlinks to copy actual content)
|
|
153
162
|
console.log("📁 Copying data files...");
|
|
@@ -22,6 +22,7 @@ import { capitalize } from "../formatters/shared.js";
|
|
|
22
22
|
* @param {Function} config.presentDetail - Function to present detail: (entity, data, options) => view
|
|
23
23
|
* @param {Function} config.formatSummary - Function to format summary output: (items, data) => void
|
|
24
24
|
* @param {Function} config.formatDetail - Function to format detail output: (view, framework) => void
|
|
25
|
+
* @param {Function} [config.formatListItem] - Optional function to format list item: (item) => string (defaults to item.id)
|
|
25
26
|
* @param {Function} [config.sortItems] - Optional function to sort items: (items) => sortedItems
|
|
26
27
|
* @param {Function} [config.validate] - Optional validation function: (data) => {errors: [], warnings: []}
|
|
27
28
|
* @param {string} [config.emojiIcon] - Optional emoji for the entity
|
|
@@ -34,6 +35,7 @@ export function createEntityCommand({
|
|
|
34
35
|
presentDetail,
|
|
35
36
|
formatSummary,
|
|
36
37
|
formatDetail,
|
|
38
|
+
formatListItem,
|
|
37
39
|
sortItems,
|
|
38
40
|
validate,
|
|
39
41
|
_emojiIcon = "",
|
|
@@ -48,10 +50,10 @@ export function createEntityCommand({
|
|
|
48
50
|
return handleValidate({ data, entityName, pluralName, validate });
|
|
49
51
|
}
|
|
50
52
|
|
|
51
|
-
// --list: Output
|
|
53
|
+
// --list: Output descriptive comma-separated lines for piping and AI agent discovery
|
|
52
54
|
if (options.list) {
|
|
53
55
|
for (const item of items) {
|
|
54
|
-
console.log(item.id);
|
|
56
|
+
console.log(formatListItem ? formatListItem(item) : item.id);
|
|
55
57
|
}
|
|
56
58
|
return;
|
|
57
59
|
}
|
package/src/commands/dev.js
CHANGED
|
@@ -31,7 +31,8 @@ function resolvePackageLib(packageName) {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
const mapLibDir = resolvePackageLib("@forwardimpact/map");
|
|
34
|
-
const modelLibDir = resolvePackageLib("@forwardimpact/
|
|
34
|
+
const modelLibDir = resolvePackageLib("@forwardimpact/libskill");
|
|
35
|
+
const uiLibDir = resolvePackageLib("@forwardimpact/libui");
|
|
35
36
|
|
|
36
37
|
const MIME_TYPES = {
|
|
37
38
|
".html": "text/html; charset=utf-8",
|
|
@@ -138,8 +139,14 @@ export async function runDevCommand({ dataDir, options }) {
|
|
|
138
139
|
// Serve @forwardimpact/map package files (resolved via Node module resolution)
|
|
139
140
|
filePath = join(mapLibDir, pathname.slice(9));
|
|
140
141
|
} else if (pathname.startsWith("/model/lib/")) {
|
|
141
|
-
// Serve @forwardimpact/
|
|
142
|
+
// Serve @forwardimpact/libskill package files (resolved via Node module resolution)
|
|
142
143
|
filePath = join(modelLibDir, pathname.slice(11));
|
|
144
|
+
} else if (pathname.startsWith("/ui/lib/")) {
|
|
145
|
+
// Serve @forwardimpact/libui package JS files
|
|
146
|
+
filePath = join(uiLibDir, pathname.slice(8));
|
|
147
|
+
} else if (pathname.startsWith("/ui/css/")) {
|
|
148
|
+
// Serve @forwardimpact/libui package CSS files
|
|
149
|
+
filePath = join(uiLibDir, "css", pathname.slice(8));
|
|
143
150
|
} else if (pathname === "/" || pathname === "") {
|
|
144
151
|
// Serve index.html for root
|
|
145
152
|
filePath = join(publicDir, "index.html");
|
|
@@ -14,6 +14,15 @@ import { createEntityCommand } from "./command-factory.js";
|
|
|
14
14
|
import { disciplineToMarkdown } from "../formatters/discipline/markdown.js";
|
|
15
15
|
import { formatTable } from "../lib/cli-output.js";
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Format discipline list item for --list output
|
|
19
|
+
* @param {Object} discipline - Discipline entity
|
|
20
|
+
* @returns {string} Formatted list line
|
|
21
|
+
*/
|
|
22
|
+
function formatListItem(discipline) {
|
|
23
|
+
return `${discipline.id}, ${discipline.specialization || discipline.id}, ${discipline.roleTitle || discipline.id}`;
|
|
24
|
+
}
|
|
25
|
+
|
|
17
26
|
/**
|
|
18
27
|
* Format discipline summary output
|
|
19
28
|
* @param {Array} disciplines - Raw discipline entities
|
|
@@ -23,14 +32,21 @@ function formatSummary(disciplines) {
|
|
|
23
32
|
|
|
24
33
|
const rows = disciplines.map((d) => [
|
|
25
34
|
d.id,
|
|
35
|
+
d.specialization || d.id,
|
|
36
|
+
d.roleTitle || d.id,
|
|
26
37
|
d.coreSkills?.length || 0,
|
|
27
38
|
d.supportingSkills?.length || 0,
|
|
28
39
|
d.broadSkills?.length || 0,
|
|
29
40
|
]);
|
|
30
41
|
|
|
31
|
-
console.log(
|
|
42
|
+
console.log(
|
|
43
|
+
formatTable(
|
|
44
|
+
["ID", "Specialization", "Role Title", "Core", "Supporting", "Broad"],
|
|
45
|
+
rows,
|
|
46
|
+
),
|
|
47
|
+
);
|
|
32
48
|
console.log(`\nTotal: ${disciplines.length} disciplines`);
|
|
33
|
-
console.log(`\nRun 'npx pathway discipline --list' for IDs`);
|
|
49
|
+
console.log(`\nRun 'npx pathway discipline --list' for IDs and names`);
|
|
34
50
|
console.log(`Run 'npx pathway discipline <id>' for details\n`);
|
|
35
51
|
}
|
|
36
52
|
|
|
@@ -54,5 +70,6 @@ export const runDisciplineCommand = createEntityCommand({
|
|
|
54
70
|
}),
|
|
55
71
|
formatSummary,
|
|
56
72
|
formatDetail,
|
|
73
|
+
formatListItem,
|
|
57
74
|
emojiIcon: "📋",
|
|
58
75
|
});
|
package/src/commands/driver.js
CHANGED
|
@@ -20,6 +20,15 @@ import {
|
|
|
20
20
|
} from "../lib/cli-output.js";
|
|
21
21
|
import { getConceptEmoji } from "@forwardimpact/map/levels";
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Format driver list item for --list output
|
|
25
|
+
* @param {Object} driver - Driver entity
|
|
26
|
+
* @returns {string} Formatted list line
|
|
27
|
+
*/
|
|
28
|
+
function formatListItem(driver) {
|
|
29
|
+
return `${driver.id}, ${driver.name}`;
|
|
30
|
+
}
|
|
31
|
+
|
|
23
32
|
/**
|
|
24
33
|
* Format driver summary output
|
|
25
34
|
* @param {Array} drivers - Raw driver entities
|
|
@@ -43,7 +52,7 @@ function formatSummary(drivers, data) {
|
|
|
43
52
|
|
|
44
53
|
console.log(formatTable(["ID", "Name", "Skills", "Behaviours"], rows));
|
|
45
54
|
console.log(`\nTotal: ${drivers.length} drivers`);
|
|
46
|
-
console.log(`\nRun 'npx pathway driver --list' for IDs`);
|
|
55
|
+
console.log(`\nRun 'npx pathway driver --list' for IDs and names`);
|
|
47
56
|
console.log(`Run 'npx pathway driver <id>' for details\n`);
|
|
48
57
|
}
|
|
49
58
|
|
|
@@ -90,5 +99,6 @@ export const runDriverCommand = createEntityCommand({
|
|
|
90
99
|
}),
|
|
91
100
|
formatSummary,
|
|
92
101
|
formatDetail,
|
|
102
|
+
formatListItem,
|
|
93
103
|
emojiIcon: "🎯",
|
|
94
104
|
});
|
package/src/commands/job.js
CHANGED
|
@@ -14,14 +14,14 @@
|
|
|
14
14
|
* npx pathway job --validate # Validation checks
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import { prepareJobDetail } from "@forwardimpact/
|
|
17
|
+
import { prepareJobDetail } from "@forwardimpact/libskill/job";
|
|
18
18
|
import { jobToMarkdown } from "../formatters/job/markdown.js";
|
|
19
|
-
import { generateAllJobs } from "@forwardimpact/
|
|
19
|
+
import { generateJobTitle, generateAllJobs } from "@forwardimpact/libskill/derivation";
|
|
20
20
|
import { formatTable } from "../lib/cli-output.js";
|
|
21
21
|
import {
|
|
22
22
|
deriveChecklist,
|
|
23
23
|
formatChecklistMarkdown,
|
|
24
|
-
} from "@forwardimpact/
|
|
24
|
+
} from "@forwardimpact/libskill/checklist";
|
|
25
25
|
import { loadJobTemplate } from "../lib/template-loader.js";
|
|
26
26
|
import { toolkitToPlainList } from "../formatters/toolkit/markdown.js";
|
|
27
27
|
|
|
@@ -54,13 +54,16 @@ export async function runJobCommand({ data, args, options, dataDir }) {
|
|
|
54
54
|
validationRules: data.framework.validationRules,
|
|
55
55
|
});
|
|
56
56
|
|
|
57
|
-
// --list: Output
|
|
57
|
+
// --list: Output descriptive comma-separated lines for piping and AI agent discovery
|
|
58
58
|
if (options.list) {
|
|
59
59
|
for (const job of jobs) {
|
|
60
|
+
const title = generateJobTitle(job.discipline, job.level, job.track);
|
|
60
61
|
if (job.track) {
|
|
61
|
-
console.log(
|
|
62
|
+
console.log(
|
|
63
|
+
`${job.discipline.id} ${job.level.id} ${job.track.id}, ${title}`,
|
|
64
|
+
);
|
|
62
65
|
} else {
|
|
63
|
-
console.log(`${job.discipline.id} ${job.level.id}`);
|
|
66
|
+
console.log(`${job.discipline.id} ${job.level.id}, ${title}`);
|
|
64
67
|
}
|
|
65
68
|
}
|
|
66
69
|
return;
|
|
@@ -70,17 +73,27 @@ export async function runJobCommand({ data, args, options, dataDir }) {
|
|
|
70
73
|
if (args.length === 0) {
|
|
71
74
|
console.log(`\n💼 Jobs\n`);
|
|
72
75
|
|
|
73
|
-
// Count by discipline
|
|
76
|
+
// Count by discipline with name
|
|
74
77
|
const byDiscipline = {};
|
|
75
78
|
for (const job of jobs) {
|
|
76
|
-
|
|
77
|
-
|
|
79
|
+
const key = job.discipline.id;
|
|
80
|
+
if (!byDiscipline[key]) {
|
|
81
|
+
byDiscipline[key] = {
|
|
82
|
+
name: job.discipline.specialization || job.discipline.id,
|
|
83
|
+
count: 0,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
byDiscipline[key].count++;
|
|
78
87
|
}
|
|
79
88
|
|
|
80
|
-
const rows = Object.entries(byDiscipline).map(([id,
|
|
81
|
-
|
|
89
|
+
const rows = Object.entries(byDiscipline).map(([id, info]) => [
|
|
90
|
+
id,
|
|
91
|
+
info.name,
|
|
92
|
+
info.count,
|
|
93
|
+
]);
|
|
94
|
+
console.log(formatTable(["ID", "Specialization", "Combinations"], rows));
|
|
82
95
|
console.log(`\nTotal: ${jobs.length} valid job combinations`);
|
|
83
|
-
console.log(`\nRun 'npx pathway job --list' for all combinations`);
|
|
96
|
+
console.log(`\nRun 'npx pathway job --list' for all combinations with titles`);
|
|
84
97
|
console.log(
|
|
85
98
|
`Run 'npx pathway job <discipline> <level> [--track=<track>]' for details\n`,
|
|
86
99
|
);
|
package/src/commands/level.js
CHANGED
|
@@ -16,6 +16,15 @@ import { formatTable } from "../lib/cli-output.js";
|
|
|
16
16
|
import { getConceptEmoji } from "@forwardimpact/map/levels";
|
|
17
17
|
import { capitalize } from "../formatters/shared.js";
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Format level list item for --list output
|
|
21
|
+
* @param {Object} level - Level entity
|
|
22
|
+
* @returns {string} Formatted list line
|
|
23
|
+
*/
|
|
24
|
+
function formatListItem(level) {
|
|
25
|
+
return `${level.id}, ${level.professionalTitle || level.id}, ${level.managementTitle || level.id}`;
|
|
26
|
+
}
|
|
27
|
+
|
|
19
28
|
/**
|
|
20
29
|
* Format level summary output
|
|
21
30
|
* @param {Array} levels - Raw level entities
|
|
@@ -29,14 +38,20 @@ function formatSummary(levels, data) {
|
|
|
29
38
|
|
|
30
39
|
const rows = levels.map((g) => [
|
|
31
40
|
g.id,
|
|
32
|
-
g.displayName || g.id,
|
|
41
|
+
g.professionalTitle || g.displayName || g.id,
|
|
42
|
+
g.managementTitle || "-",
|
|
33
43
|
g.typicalExperienceRange || "-",
|
|
34
44
|
capitalize(g.baseSkillProficiencies?.primary || "-"),
|
|
35
45
|
]);
|
|
36
46
|
|
|
37
|
-
console.log(
|
|
47
|
+
console.log(
|
|
48
|
+
formatTable(
|
|
49
|
+
["ID", "Professional Title", "Management Title", "Experience", "Primary Level"],
|
|
50
|
+
rows,
|
|
51
|
+
),
|
|
52
|
+
);
|
|
38
53
|
console.log(`\nTotal: ${levels.length} levels`);
|
|
39
|
-
console.log(`\nRun 'npx pathway level --list' for IDs`);
|
|
54
|
+
console.log(`\nRun 'npx pathway level --list' for IDs and titles`);
|
|
40
55
|
console.log(`Run 'npx pathway level <id>' for details\n`);
|
|
41
56
|
}
|
|
42
57
|
|
|
@@ -56,5 +71,6 @@ export const runLevelCommand = createEntityCommand({
|
|
|
56
71
|
presentDetail: (entity) => entity,
|
|
57
72
|
formatSummary,
|
|
58
73
|
formatDetail,
|
|
74
|
+
formatListItem,
|
|
59
75
|
emojiIcon: "📊",
|
|
60
76
|
});
|
package/src/commands/skill.js
CHANGED
|
@@ -16,7 +16,7 @@ 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
18
|
import { formatTable, formatError } from "../lib/cli-output.js";
|
|
19
|
-
import { generateSkillMarkdown } from "@forwardimpact/
|
|
19
|
+
import { generateSkillMarkdown } from "@forwardimpact/libskill/agent";
|
|
20
20
|
import { formatAgentSkill } from "../formatters/agent/skill.js";
|
|
21
21
|
import { loadSkillTemplate } from "../lib/template-loader.js";
|
|
22
22
|
|
|
@@ -85,6 +85,15 @@ async function formatAgentDetail(skill, stages, dataDir) {
|
|
|
85
85
|
console.log(output);
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Format skill list item for --list output
|
|
90
|
+
* @param {Object} skill - Skill entity
|
|
91
|
+
* @returns {string} Formatted list line
|
|
92
|
+
*/
|
|
93
|
+
function formatListItem(skill) {
|
|
94
|
+
return `${skill.id}, ${skill.name}, ${skill.capability || "-"}`;
|
|
95
|
+
}
|
|
96
|
+
|
|
88
97
|
const baseSkillCommand = createEntityCommand({
|
|
89
98
|
entityName: "skill",
|
|
90
99
|
pluralName: "skills",
|
|
@@ -98,6 +107,7 @@ const baseSkillCommand = createEntityCommand({
|
|
|
98
107
|
}),
|
|
99
108
|
formatSummary,
|
|
100
109
|
formatDetail,
|
|
110
|
+
formatListItem,
|
|
101
111
|
emojiIcon: "📚",
|
|
102
112
|
});
|
|
103
113
|
|
package/src/commands/stage.js
CHANGED
|
@@ -21,6 +21,15 @@ import {
|
|
|
21
21
|
formatBullet,
|
|
22
22
|
} from "../lib/cli-output.js";
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Format stage list item for --list output
|
|
26
|
+
* @param {Object} stage - Stage entity
|
|
27
|
+
* @returns {string} Formatted list line
|
|
28
|
+
*/
|
|
29
|
+
function formatListItem(stage) {
|
|
30
|
+
return `${stage.id}, ${stage.name}`;
|
|
31
|
+
}
|
|
32
|
+
|
|
24
33
|
/**
|
|
25
34
|
* Format stage summary output
|
|
26
35
|
* @param {Array} stages - Raw stage entities
|
|
@@ -43,7 +52,7 @@ function formatSummary(stages, _data) {
|
|
|
43
52
|
|
|
44
53
|
console.log(formatTable(["ID", "Name", "Mode", "Tools", "Handoffs"], rows));
|
|
45
54
|
console.log(`\nTotal: ${stages.length} stages`);
|
|
46
|
-
console.log(`\nRun 'npx pathway stage --list' for IDs`);
|
|
55
|
+
console.log(`\nRun 'npx pathway stage --list' for IDs and names`);
|
|
47
56
|
console.log(`Run 'npx pathway stage <id>' for details\n`);
|
|
48
57
|
}
|
|
49
58
|
|
|
@@ -115,5 +124,6 @@ export const runStageCommand = createEntityCommand({
|
|
|
115
124
|
}),
|
|
116
125
|
formatSummary,
|
|
117
126
|
formatDetail,
|
|
127
|
+
formatListItem,
|
|
118
128
|
emojiIcon: "🔄",
|
|
119
129
|
});
|
package/src/commands/tool.js
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* npx pathway tool <name> # Detail view for specific tool
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
import { truncate } from "../formatters/shared.js";
|
|
12
13
|
import { prepareToolsList } from "../formatters/tool/shared.js";
|
|
13
14
|
import {
|
|
14
15
|
formatTable,
|
|
@@ -27,10 +28,10 @@ export async function runToolCommand({ data, args, options }) {
|
|
|
27
28
|
const [name] = args;
|
|
28
29
|
const { tools, totalCount } = prepareToolsList(data.skills);
|
|
29
30
|
|
|
30
|
-
// --list: Output
|
|
31
|
+
// --list: Output descriptive comma-separated tool lines for piping
|
|
31
32
|
if (options.list) {
|
|
32
33
|
for (const tool of tools) {
|
|
33
|
-
console.log(tool.name);
|
|
34
|
+
console.log(`${tool.name}, ${truncate(tool.description, 60)}`);
|
|
34
35
|
}
|
|
35
36
|
return;
|
|
36
37
|
}
|
|
@@ -87,7 +88,7 @@ function formatSummary(tools, totalCount) {
|
|
|
87
88
|
if (sorted.length > 15) {
|
|
88
89
|
console.log(`(showing top 15 by usage)`);
|
|
89
90
|
}
|
|
90
|
-
console.log(`\nRun 'npx pathway tool --list' for all tool names`);
|
|
91
|
+
console.log(`\nRun 'npx pathway tool --list' for all tool names and descriptions`);
|
|
91
92
|
console.log(`Run 'npx pathway tool <name>' for details\n`);
|
|
92
93
|
}
|
|
93
94
|
|
package/src/commands/track.js
CHANGED
|
@@ -16,6 +16,15 @@ import { sortTracksByName } from "../formatters/track/shared.js";
|
|
|
16
16
|
import { formatTable } from "../lib/cli-output.js";
|
|
17
17
|
import { getConceptEmoji } from "@forwardimpact/map/levels";
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Format track list item for --list output
|
|
21
|
+
* @param {Object} track - Track entity
|
|
22
|
+
* @returns {string} Formatted list line
|
|
23
|
+
*/
|
|
24
|
+
function formatListItem(track) {
|
|
25
|
+
return `${track.id}, ${track.name}`;
|
|
26
|
+
}
|
|
27
|
+
|
|
19
28
|
/**
|
|
20
29
|
* Format track summary output
|
|
21
30
|
* @param {Array} tracks - Raw track entities
|
|
@@ -34,7 +43,7 @@ function formatSummary(tracks, data) {
|
|
|
34
43
|
|
|
35
44
|
console.log(formatTable(["ID", "Name", "Modifiers"], rows));
|
|
36
45
|
console.log(`\nTotal: ${tracks.length} tracks`);
|
|
37
|
-
console.log(`\nRun 'npx pathway track --list' for IDs`);
|
|
46
|
+
console.log(`\nRun 'npx pathway track --list' for IDs and names`);
|
|
38
47
|
console.log(`Run 'npx pathway track <id>' for details\n`);
|
|
39
48
|
}
|
|
40
49
|
|
|
@@ -63,5 +72,6 @@ export const runTrackCommand = createEntityCommand({
|
|
|
63
72
|
sortItems: sortTracksByName,
|
|
64
73
|
formatSummary,
|
|
65
74
|
formatDetail,
|
|
75
|
+
formatListItem,
|
|
66
76
|
emojiIcon: "🛤️",
|
|
67
77
|
});
|
package/src/components/card.js
CHANGED
|
@@ -1,108 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Reusable card component
|
|
3
|
+
*
|
|
4
|
+
* Re-exports from @forwardimpact/libui/components/card.
|
|
3
5
|
*/
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
* @param {string} [options.description] - Card description
|
|
12
|
-
* @param {string} [options.href] - Link destination (makes card clickable)
|
|
13
|
-
* @param {HTMLElement[]} [options.badges] - Badges to display
|
|
14
|
-
* @param {HTMLElement[]} [options.meta] - Meta information
|
|
15
|
-
* @param {HTMLElement} [options.content] - Additional content
|
|
16
|
-
* @param {HTMLElement} [options.icon] - Icon element to display
|
|
17
|
-
* @param {string} [options.className] - Additional CSS class
|
|
18
|
-
* @returns {HTMLElement}
|
|
19
|
-
*/
|
|
20
|
-
export function createCard({
|
|
21
|
-
title,
|
|
22
|
-
description,
|
|
23
|
-
href,
|
|
24
|
-
badges = [],
|
|
25
|
-
meta = [],
|
|
26
|
-
content,
|
|
27
|
-
icon,
|
|
28
|
-
className = "",
|
|
29
|
-
}) {
|
|
30
|
-
const isClickable = !!href;
|
|
31
|
-
|
|
32
|
-
const titleContent = icon
|
|
33
|
-
? div(
|
|
34
|
-
{ className: "card-title-with-icon" },
|
|
35
|
-
icon,
|
|
36
|
-
h3({ className: "card-title" }, title),
|
|
37
|
-
)
|
|
38
|
-
: h3({ className: "card-title" }, title);
|
|
39
|
-
|
|
40
|
-
const cardHeader = div(
|
|
41
|
-
{ className: "card-header" },
|
|
42
|
-
titleContent,
|
|
43
|
-
badges.length > 0 ? div({ className: "card-badges" }, ...badges) : null,
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
const card = div(
|
|
47
|
-
{
|
|
48
|
-
className:
|
|
49
|
-
`card ${isClickable ? "card-clickable" : ""} ${className}`.trim(),
|
|
50
|
-
},
|
|
51
|
-
cardHeader,
|
|
52
|
-
description ? p({ className: "card-description" }, description) : null,
|
|
53
|
-
content || null,
|
|
54
|
-
meta.length > 0 ? div({ className: "card-meta" }, ...meta) : null,
|
|
55
|
-
);
|
|
56
|
-
|
|
57
|
-
if (isClickable) {
|
|
58
|
-
card.addEventListener("click", () => {
|
|
59
|
-
window.location.hash = href;
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return card;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Create a stat card for the landing page
|
|
68
|
-
* @param {Object} options
|
|
69
|
-
* @param {number|string} options.value - The stat value
|
|
70
|
-
* @param {string} options.label - The stat label
|
|
71
|
-
* @param {string} [options.href] - Optional link
|
|
72
|
-
* @returns {HTMLElement}
|
|
73
|
-
*/
|
|
74
|
-
export function createStatCard({ value, label, href }) {
|
|
75
|
-
const card = div(
|
|
76
|
-
{ className: "stat-card" },
|
|
77
|
-
div({ className: "stat-value" }, String(value)),
|
|
78
|
-
div({ className: "stat-label" }, label),
|
|
79
|
-
);
|
|
80
|
-
|
|
81
|
-
if (href) {
|
|
82
|
-
card.style.cursor = "pointer";
|
|
83
|
-
card.addEventListener("click", () => {
|
|
84
|
-
window.location.hash = href;
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
return card;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Create a badge element
|
|
93
|
-
* @param {string} text - Badge text
|
|
94
|
-
* @param {string} [type] - Badge type (default, primary, secondary, broad, technical, ai, etc.)
|
|
95
|
-
* @returns {HTMLElement}
|
|
96
|
-
*/
|
|
97
|
-
export function createBadge(text, type = "default") {
|
|
98
|
-
return span({ className: `badge badge-${type}` }, text);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Create a tag element
|
|
103
|
-
* @param {string} text
|
|
104
|
-
* @returns {HTMLElement}
|
|
105
|
-
*/
|
|
106
|
-
export function createTag(text) {
|
|
107
|
-
return span({ className: "info-tag" }, text);
|
|
108
|
-
}
|
|
7
|
+
export {
|
|
8
|
+
createCard,
|
|
9
|
+
createStatCard,
|
|
10
|
+
createBadge,
|
|
11
|
+
createTag,
|
|
12
|
+
} from "@forwardimpact/libui/components/card";
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
getBehaviourMaturityIndex,
|
|
14
14
|
formatLevel,
|
|
15
15
|
} from "../lib/render.js";
|
|
16
|
-
import { compareByCapability } from "@forwardimpact/
|
|
16
|
+
import { compareByCapability } from "@forwardimpact/libskill/policies";
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* Create a comparison skill radar chart
|