@forwardimpact/pathway 0.25.15 → 0.25.21
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 +62 -54
- package/package.json +1 -3
- package/src/commands/agent-io.js +120 -0
- package/src/commands/agent.js +266 -349
- package/src/commands/init.js +2 -2
- package/src/commands/job.js +237 -183
- package/src/components/comparison-radar.js +118 -103
- package/src/components/progression-table.js +244 -208
- package/src/formatters/index.js +0 -19
- package/src/formatters/interview/markdown.js +100 -88
- package/src/formatters/job/description.js +76 -75
- package/src/formatters/job/dom.js +113 -97
- package/src/formatters/level/dom.js +87 -102
- package/src/formatters/questions/markdown.js +37 -33
- package/src/formatters/questions/shared.js +142 -75
- package/src/formatters/skill/dom.js +102 -93
- package/src/lib/comparison-radar-chart.js +256 -0
- package/src/lib/radar-utils.js +199 -0
- package/src/lib/radar.js +25 -662
- package/src/pages/agent-builder-download.js +170 -0
- package/src/pages/agent-builder-preview.js +344 -0
- package/src/pages/agent-builder.js +6 -550
- package/src/pages/progress-comparison.js +110 -0
- package/src/pages/progress.js +11 -111
- package/src/pages/self-assessment-steps.js +494 -0
- package/src/pages/self-assessment.js +54 -504
- package/src/formatters/behaviour/microdata.js +0 -106
- package/src/formatters/discipline/microdata.js +0 -117
- package/src/formatters/driver/microdata.js +0 -91
- package/src/formatters/level/microdata.js +0 -141
- package/src/formatters/microdata-shared.js +0 -184
- package/src/formatters/skill/microdata.js +0 -151
- package/src/formatters/stage/microdata.js +0 -116
- package/src/formatters/track/microdata.js +0 -111
package/src/commands/init.js
CHANGED
|
@@ -47,8 +47,8 @@ export async function runInitCommand({ options }) {
|
|
|
47
47
|
|
|
48
48
|
Next steps:
|
|
49
49
|
1. Edit data files to match your organization
|
|
50
|
-
2.
|
|
51
|
-
3.
|
|
50
|
+
2. npx fit-map validate
|
|
51
|
+
3. npx fit-pathway dev
|
|
52
52
|
|
|
53
53
|
Data structure:
|
|
54
54
|
data/pathway/
|
package/src/commands/job.js
CHANGED
|
@@ -39,137 +39,103 @@ function formatJob(view, _options, entities, jobTemplate) {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
/**
|
|
42
|
-
*
|
|
43
|
-
* @param {
|
|
44
|
-
* @param {Object} params.data - All loaded data
|
|
45
|
-
* @param {string[]} params.args - Command arguments
|
|
46
|
-
* @param {Object} params.options - Command options
|
|
47
|
-
* @param {string} params.dataDir - Path to data directory
|
|
42
|
+
* Print job list output
|
|
43
|
+
* @param {Array} filteredJobs
|
|
48
44
|
*/
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const jobs = generateAllJobs({
|
|
57
|
-
disciplines: data.disciplines,
|
|
58
|
-
levels: data.levels,
|
|
59
|
-
tracks: data.tracks,
|
|
60
|
-
skills: data.skills,
|
|
61
|
-
behaviours: data.behaviours,
|
|
62
|
-
validationRules: data.framework.validationRules,
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
// Apply --track filter to list and summary modes
|
|
66
|
-
const filteredJobs = options.track
|
|
67
|
-
? jobs.filter((j) => j.track && j.track.id === options.track)
|
|
68
|
-
: jobs;
|
|
69
|
-
|
|
70
|
-
if (options.track && filteredJobs.length === 0 && args.length === 0) {
|
|
71
|
-
const trackExists = data.tracks.some((t) => t.id === options.track);
|
|
72
|
-
if (!trackExists) {
|
|
73
|
-
console.error(`Track not found: ${options.track}`);
|
|
74
|
-
console.error(`Available: ${data.tracks.map((t) => t.id).join(", ")}`);
|
|
45
|
+
function printJobList(filteredJobs) {
|
|
46
|
+
for (const job of filteredJobs) {
|
|
47
|
+
const title = generateJobTitle(job.discipline, job.level, job.track);
|
|
48
|
+
if (job.track) {
|
|
49
|
+
console.log(
|
|
50
|
+
`${job.discipline.id} ${job.level.id} ${job.track.id}, ${title}`,
|
|
51
|
+
);
|
|
75
52
|
} else {
|
|
76
|
-
console.
|
|
77
|
-
const trackDisciplines = data.disciplines
|
|
78
|
-
.filter((d) => d.validTracks && d.validTracks.includes(options.track))
|
|
79
|
-
.map((d) => d.id);
|
|
80
|
-
if (trackDisciplines.length > 0) {
|
|
81
|
-
console.error(
|
|
82
|
-
`Disciplines with this track: ${trackDisciplines.join(", ")}`,
|
|
83
|
-
);
|
|
84
|
-
}
|
|
53
|
+
console.log(`${job.discipline.id} ${job.level.id}, ${title}`);
|
|
85
54
|
}
|
|
86
|
-
process.exit(1);
|
|
87
55
|
}
|
|
56
|
+
}
|
|
88
57
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
58
|
+
/**
|
|
59
|
+
* Print job summary table
|
|
60
|
+
* @param {Array} filteredJobs
|
|
61
|
+
* @param {Object} options
|
|
62
|
+
*/
|
|
63
|
+
function printJobSummary(filteredJobs, options) {
|
|
64
|
+
const trackLabel = options.track ? ` — ${options.track}` : "";
|
|
65
|
+
console.log(`\n💼 Jobs${trackLabel}\n`);
|
|
66
|
+
|
|
67
|
+
const byDiscipline = {};
|
|
68
|
+
for (const job of filteredJobs) {
|
|
69
|
+
const key = job.discipline.id;
|
|
70
|
+
if (!byDiscipline[key]) {
|
|
71
|
+
byDiscipline[key] = {
|
|
72
|
+
name: job.discipline.specialization || job.discipline.id,
|
|
73
|
+
roleTitle: job.discipline.roleTitle || job.discipline.id,
|
|
74
|
+
type: job.discipline.isProfessional ? "Professional" : "Management",
|
|
75
|
+
tracks: new Set(),
|
|
76
|
+
count: 0,
|
|
77
|
+
};
|
|
100
78
|
}
|
|
101
|
-
|
|
79
|
+
if (job.track) byDiscipline[key].tracks.add(job.track.id);
|
|
80
|
+
byDiscipline[key].count++;
|
|
102
81
|
}
|
|
103
82
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
if (job.track) byDiscipline[key].tracks.add(job.track.id);
|
|
123
|
-
byDiscipline[key].count++;
|
|
124
|
-
}
|
|
83
|
+
const rows = Object.entries(byDiscipline).map(([id, info]) => [
|
|
84
|
+
id,
|
|
85
|
+
info.name,
|
|
86
|
+
info.type,
|
|
87
|
+
info.count,
|
|
88
|
+
info.tracks.size > 0 ? [...info.tracks].join(", ") : "—",
|
|
89
|
+
]);
|
|
90
|
+
console.log(
|
|
91
|
+
formatTable(["ID", "Specialization", "Type", "Jobs", "Tracks"], rows),
|
|
92
|
+
);
|
|
93
|
+
console.log(`\nTotal: ${filteredJobs.length} valid job combinations`);
|
|
94
|
+
console.log(
|
|
95
|
+
`\nRun 'bunx pathway job --list' for all combinations with titles`,
|
|
96
|
+
);
|
|
97
|
+
console.log(
|
|
98
|
+
`Run 'bunx pathway job <discipline> <level> [--track=<track>]' for details\n`,
|
|
99
|
+
);
|
|
100
|
+
}
|
|
125
101
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
102
|
+
/**
|
|
103
|
+
* Validate and exit when a single positional arg is provided
|
|
104
|
+
* @param {string} arg
|
|
105
|
+
* @param {Object} data
|
|
106
|
+
*/
|
|
107
|
+
function handleSingleArg(arg, data) {
|
|
108
|
+
const isLevel = data.levels.some((g) => g.id === arg);
|
|
109
|
+
const isTrack = data.tracks.some((t) => t.id === arg);
|
|
110
|
+
if (isLevel) {
|
|
111
|
+
console.error(
|
|
112
|
+
`Missing discipline. Usage: bunx pathway job <discipline> ${arg} [--track=<track>]`,
|
|
135
113
|
);
|
|
136
|
-
console.
|
|
137
|
-
|
|
138
|
-
`\nRun 'bunx pathway job --list' for all combinations with titles`,
|
|
114
|
+
console.error(
|
|
115
|
+
`Disciplines: ${data.disciplines.map((d) => d.id).join(", ")}`,
|
|
139
116
|
);
|
|
140
|
-
|
|
141
|
-
|
|
117
|
+
} else if (isTrack) {
|
|
118
|
+
console.error(`Track must be passed as a flag: --track=${arg}`);
|
|
119
|
+
console.error(
|
|
120
|
+
`Usage: bunx pathway job <discipline> <level> --track=${arg}`,
|
|
142
121
|
);
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
// Check if the single arg is a level or track, hinting at what's missing
|
|
149
|
-
const arg = args[0];
|
|
150
|
-
const isLevel = data.levels.some((g) => g.id === arg);
|
|
151
|
-
const isTrack = data.tracks.some((t) => t.id === arg);
|
|
152
|
-
if (isLevel) {
|
|
153
|
-
console.error(
|
|
154
|
-
`Missing discipline. Usage: bunx pathway job <discipline> ${arg} [--track=<track>]`,
|
|
155
|
-
);
|
|
156
|
-
console.error(
|
|
157
|
-
`Disciplines: ${data.disciplines.map((d) => d.id).join(", ")}`,
|
|
158
|
-
);
|
|
159
|
-
} else if (isTrack) {
|
|
160
|
-
console.error(`Track must be passed as a flag: --track=${arg}`);
|
|
161
|
-
console.error(
|
|
162
|
-
`Usage: bunx pathway job <discipline> <level> --track=${arg}`,
|
|
163
|
-
);
|
|
164
|
-
} else {
|
|
165
|
-
console.error(
|
|
166
|
-
"Usage: bunx pathway job <discipline> <level> [--track=<track>]",
|
|
167
|
-
);
|
|
168
|
-
console.error(" bunx pathway job --list");
|
|
169
|
-
}
|
|
170
|
-
process.exit(1);
|
|
122
|
+
} else {
|
|
123
|
+
console.error(
|
|
124
|
+
"Usage: bunx pathway job <discipline> <level> [--track=<track>]",
|
|
125
|
+
);
|
|
126
|
+
console.error(" bunx pathway job --list");
|
|
171
127
|
}
|
|
128
|
+
process.exit(1);
|
|
129
|
+
}
|
|
172
130
|
|
|
131
|
+
/**
|
|
132
|
+
* Resolve and validate discipline, level, track entities from args
|
|
133
|
+
* @param {Object} data
|
|
134
|
+
* @param {string[]} args
|
|
135
|
+
* @param {Object} options
|
|
136
|
+
* @returns {{discipline: Object, level: Object, track: Object|null}}
|
|
137
|
+
*/
|
|
138
|
+
function resolveJobEntities(data, args, options) {
|
|
173
139
|
const discipline = data.disciplines.find((d) => d.id === args[0]);
|
|
174
140
|
const level = data.levels.find((g) => g.id === args[1]);
|
|
175
141
|
const track = options.track
|
|
@@ -177,7 +143,6 @@ export async function runJobCommand({
|
|
|
177
143
|
: null;
|
|
178
144
|
|
|
179
145
|
if (!discipline) {
|
|
180
|
-
// Check if args are swapped (level first, discipline second)
|
|
181
146
|
const maybeLevel = data.levels.find((g) => g.id === args[0]);
|
|
182
147
|
const maybeDiscipline = data.disciplines.find((d) => d.id === args[1]);
|
|
183
148
|
if (maybeLevel && maybeDiscipline) {
|
|
@@ -195,7 +160,6 @@ export async function runJobCommand({
|
|
|
195
160
|
}
|
|
196
161
|
|
|
197
162
|
if (!level) {
|
|
198
|
-
// Check if the second arg is a track ID passed as positional
|
|
199
163
|
const isTrack = data.tracks.some((t) => t.id === args[1]);
|
|
200
164
|
if (isTrack) {
|
|
201
165
|
console.error(
|
|
@@ -216,6 +180,158 @@ export async function runJobCommand({
|
|
|
216
180
|
process.exit(1);
|
|
217
181
|
}
|
|
218
182
|
|
|
183
|
+
return { discipline, level, track };
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Handle --checklist sub-command
|
|
188
|
+
* @param {Object} view
|
|
189
|
+
* @param {Object} data
|
|
190
|
+
* @param {string} stageId
|
|
191
|
+
*/
|
|
192
|
+
function handleChecklist(view, data, stageId) {
|
|
193
|
+
const validStages = data.stages.map((s) => s.id);
|
|
194
|
+
if (!validStages.includes(stageId)) {
|
|
195
|
+
console.error(`Invalid stage: ${stageId}`);
|
|
196
|
+
console.error(`Available: ${validStages.join(", ")}`);
|
|
197
|
+
process.exit(1);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const { readChecklist, confirmChecklist } = deriveChecklist({
|
|
201
|
+
stageId,
|
|
202
|
+
skillMatrix: view.skillMatrix,
|
|
203
|
+
skills: data.skills,
|
|
204
|
+
capabilities: data.capabilities,
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
if (readChecklist.length === 0 && confirmChecklist.length === 0) {
|
|
208
|
+
console.log(`\nNo checklist items for ${stageId} stage\n`);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const stageLabel = stageId.charAt(0).toUpperCase() + stageId.slice(1);
|
|
213
|
+
console.log(`\n# ${view.title} — ${stageLabel} Stage Checklist\n`);
|
|
214
|
+
if (readChecklist.length > 0) {
|
|
215
|
+
console.log("## Read-Then-Do\n");
|
|
216
|
+
console.log(formatChecklistMarkdown(readChecklist));
|
|
217
|
+
console.log("");
|
|
218
|
+
}
|
|
219
|
+
if (confirmChecklist.length > 0) {
|
|
220
|
+
console.log("## Do-Then-Confirm\n");
|
|
221
|
+
console.log(formatChecklistMarkdown(confirmChecklist));
|
|
222
|
+
console.log("");
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Run job command
|
|
228
|
+
* @param {Object} params
|
|
229
|
+
* @param {Object} params.data - All loaded data
|
|
230
|
+
* @param {string[]} params.args - Command arguments
|
|
231
|
+
* @param {Object} params.options - Command options
|
|
232
|
+
* @param {string} params.dataDir - Path to data directory
|
|
233
|
+
*/
|
|
234
|
+
/**
|
|
235
|
+
* Validate track filter and exit if invalid
|
|
236
|
+
* @param {Array} filteredJobs
|
|
237
|
+
* @param {Object} data
|
|
238
|
+
* @param {Object} options
|
|
239
|
+
*/
|
|
240
|
+
function validateTrackFilter(filteredJobs, data, options) {
|
|
241
|
+
if (!options.track || filteredJobs.length > 0) return;
|
|
242
|
+
const trackExists = data.tracks.some((t) => t.id === options.track);
|
|
243
|
+
if (!trackExists) {
|
|
244
|
+
console.error(`Track not found: ${options.track}`);
|
|
245
|
+
console.error(`Available: ${data.tracks.map((t) => t.id).join(", ")}`);
|
|
246
|
+
} else {
|
|
247
|
+
console.error(`No jobs found for track: ${options.track}`);
|
|
248
|
+
const trackDisciplines = data.disciplines
|
|
249
|
+
.filter((d) => d.validTracks && d.validTracks.includes(options.track))
|
|
250
|
+
.map((d) => d.id);
|
|
251
|
+
if (trackDisciplines.length > 0) {
|
|
252
|
+
console.error(
|
|
253
|
+
`Disciplines with this track: ${trackDisciplines.join(", ")}`,
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
process.exit(1);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Report an invalid job combination and exit
|
|
262
|
+
* @param {Object} discipline
|
|
263
|
+
* @param {Object} level
|
|
264
|
+
* @param {Object|null} track
|
|
265
|
+
* @param {Object} data
|
|
266
|
+
*/
|
|
267
|
+
function reportInvalidCombination(discipline, level, track, data) {
|
|
268
|
+
const combo = track
|
|
269
|
+
? `${discipline.id} × ${level.id} × ${track.id}`
|
|
270
|
+
: `${discipline.id} × ${level.id}`;
|
|
271
|
+
console.error(`Invalid combination: ${combo}`);
|
|
272
|
+
if (track) {
|
|
273
|
+
const validTracks = discipline.validTracks?.filter((t) => t !== null) || [];
|
|
274
|
+
if (validTracks.length > 0) {
|
|
275
|
+
console.error(
|
|
276
|
+
`Valid tracks for ${discipline.id}: ${validTracks.join(", ")}`,
|
|
277
|
+
);
|
|
278
|
+
} else {
|
|
279
|
+
console.error(`${discipline.id} does not support tracks`);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
if (discipline.minLevel) {
|
|
283
|
+
const levelIndex = data.levels.findIndex((g) => g.id === level.id);
|
|
284
|
+
const minIndex = data.levels.findIndex((g) => g.id === discipline.minLevel);
|
|
285
|
+
if (levelIndex >= 0 && minIndex >= 0 && levelIndex < minIndex) {
|
|
286
|
+
console.error(
|
|
287
|
+
`${discipline.id} requires minimum level: ${discipline.minLevel}`,
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
process.exit(1);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
export async function runJobCommand({
|
|
295
|
+
data,
|
|
296
|
+
args,
|
|
297
|
+
options,
|
|
298
|
+
dataDir,
|
|
299
|
+
templateLoader,
|
|
300
|
+
}) {
|
|
301
|
+
const jobs = generateAllJobs({
|
|
302
|
+
disciplines: data.disciplines,
|
|
303
|
+
levels: data.levels,
|
|
304
|
+
tracks: data.tracks,
|
|
305
|
+
skills: data.skills,
|
|
306
|
+
behaviours: data.behaviours,
|
|
307
|
+
validationRules: data.framework.validationRules,
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
const filteredJobs = options.track
|
|
311
|
+
? jobs.filter((j) => j.track && j.track.id === options.track)
|
|
312
|
+
: jobs;
|
|
313
|
+
|
|
314
|
+
if (args.length === 0 && filteredJobs.length === 0) {
|
|
315
|
+
validateTrackFilter(filteredJobs, data, options);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if (options.list) {
|
|
319
|
+
printJobList(filteredJobs);
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if (args.length === 0) {
|
|
324
|
+
printJobSummary(filteredJobs, options);
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
if (args.length < 2) {
|
|
329
|
+
handleSingleArg(args[0], data);
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
const { discipline, level, track } = resolveJobEntities(data, args, options);
|
|
334
|
+
|
|
219
335
|
const view = prepareJobDetail({
|
|
220
336
|
discipline,
|
|
221
337
|
level,
|
|
@@ -228,37 +344,9 @@ export async function runJobCommand({
|
|
|
228
344
|
});
|
|
229
345
|
|
|
230
346
|
if (!view) {
|
|
231
|
-
|
|
232
|
-
? `${discipline.id} × ${level.id} × ${track.id}`
|
|
233
|
-
: `${discipline.id} × ${level.id}`;
|
|
234
|
-
console.error(`Invalid combination: ${combo}`);
|
|
235
|
-
if (track) {
|
|
236
|
-
const validTracks =
|
|
237
|
-
discipline.validTracks?.filter((t) => t !== null) || [];
|
|
238
|
-
if (validTracks.length > 0) {
|
|
239
|
-
console.error(
|
|
240
|
-
`Valid tracks for ${discipline.id}: ${validTracks.join(", ")}`,
|
|
241
|
-
);
|
|
242
|
-
} else {
|
|
243
|
-
console.error(`${discipline.id} does not support tracks`);
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
// Check if it's a minLevel issue
|
|
247
|
-
if (discipline.minLevel) {
|
|
248
|
-
const levelIndex = data.levels.findIndex((g) => g.id === level.id);
|
|
249
|
-
const minIndex = data.levels.findIndex(
|
|
250
|
-
(g) => g.id === discipline.minLevel,
|
|
251
|
-
);
|
|
252
|
-
if (levelIndex >= 0 && minIndex >= 0 && levelIndex < minIndex) {
|
|
253
|
-
console.error(
|
|
254
|
-
`${discipline.id} requires minimum level: ${discipline.minLevel}`,
|
|
255
|
-
);
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
process.exit(1);
|
|
347
|
+
reportInvalidCombination(discipline, level, track, data);
|
|
259
348
|
}
|
|
260
349
|
|
|
261
|
-
// --skills: Output plain list of skill IDs (for piping)
|
|
262
350
|
if (options.skills) {
|
|
263
351
|
for (const skill of view.skillMatrix) {
|
|
264
352
|
console.log(skill.skillId);
|
|
@@ -266,7 +354,6 @@ export async function runJobCommand({
|
|
|
266
354
|
return;
|
|
267
355
|
}
|
|
268
356
|
|
|
269
|
-
// --tools: Output plain list of tool names (for piping)
|
|
270
357
|
if (options.tools) {
|
|
271
358
|
console.log(toolkitToPlainList(view.toolkit));
|
|
272
359
|
return;
|
|
@@ -277,44 +364,11 @@ export async function runJobCommand({
|
|
|
277
364
|
return;
|
|
278
365
|
}
|
|
279
366
|
|
|
280
|
-
// --checklist: Show checklist for a specific stage
|
|
281
367
|
if (options.checklist) {
|
|
282
|
-
|
|
283
|
-
if (!validStages.includes(options.checklist)) {
|
|
284
|
-
console.error(`Invalid stage: ${options.checklist}`);
|
|
285
|
-
console.error(`Available: ${validStages.join(", ")}`);
|
|
286
|
-
process.exit(1);
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
const { readChecklist, confirmChecklist } = deriveChecklist({
|
|
290
|
-
stageId: options.checklist,
|
|
291
|
-
skillMatrix: view.skillMatrix,
|
|
292
|
-
skills: data.skills,
|
|
293
|
-
capabilities: data.capabilities,
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
if (readChecklist.length === 0 && confirmChecklist.length === 0) {
|
|
297
|
-
console.log(`\nNo checklist items for ${options.checklist} stage\n`);
|
|
298
|
-
return;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
const stageLabel =
|
|
302
|
-
options.checklist.charAt(0).toUpperCase() + options.checklist.slice(1);
|
|
303
|
-
console.log(`\n# ${view.title} — ${stageLabel} Stage Checklist\n`);
|
|
304
|
-
if (readChecklist.length > 0) {
|
|
305
|
-
console.log("## Read-Then-Do\n");
|
|
306
|
-
console.log(formatChecklistMarkdown(readChecklist));
|
|
307
|
-
console.log("");
|
|
308
|
-
}
|
|
309
|
-
if (confirmChecklist.length > 0) {
|
|
310
|
-
console.log("## Do-Then-Confirm\n");
|
|
311
|
-
console.log(formatChecklistMarkdown(confirmChecklist));
|
|
312
|
-
console.log("");
|
|
313
|
-
}
|
|
368
|
+
handleChecklist(view, data, options.checklist);
|
|
314
369
|
return;
|
|
315
370
|
}
|
|
316
371
|
|
|
317
|
-
// Load job template for description formatting
|
|
318
372
|
const jobTemplate = templateLoader.load("job.template.md", dataDir);
|
|
319
373
|
formatJob(view, options, { discipline, level, track }, jobTemplate);
|
|
320
374
|
}
|