@forwardimpact/pathway 0.25.12 → 0.25.20
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 +3 -4
- 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/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/commands/agent.js
CHANGED
|
@@ -24,9 +24,6 @@
|
|
|
24
24
|
* bunx pathway agent software_engineering --track=platform --output=./agents
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
|
-
import { writeFile, mkdir, readFile } from "fs/promises";
|
|
28
|
-
import { join, dirname } from "path";
|
|
29
|
-
import { existsSync } from "fs";
|
|
30
27
|
import { createDataLoader } from "@forwardimpact/map/loader";
|
|
31
28
|
import {
|
|
32
29
|
generateStageAgentProfile,
|
|
@@ -41,47 +38,14 @@ import {
|
|
|
41
38
|
interpolateTeamInstructions,
|
|
42
39
|
} from "@forwardimpact/libskill";
|
|
43
40
|
import { formatAgentProfile } from "../formatters/agent/profile.js";
|
|
44
|
-
import {
|
|
45
|
-
formatAgentSkill,
|
|
46
|
-
formatInstallScript,
|
|
47
|
-
formatReference,
|
|
48
|
-
} from "../formatters/agent/skill.js";
|
|
49
41
|
import { formatError, formatSuccess } from "../lib/cli-output.js";
|
|
50
42
|
import { toolkitToPlainList } from "../formatters/toolkit/markdown.js";
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
await mkdir(dirname(filePath), { recursive: true });
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Generate Claude Code settings file
|
|
62
|
-
* Merges with existing settings if file exists
|
|
63
|
-
* @param {string} baseDir - Base output directory
|
|
64
|
-
* @param {Object} claudeCodeSettings - Settings loaded from data
|
|
65
|
-
*/
|
|
66
|
-
async function generateClaudeCodeSettings(baseDir, claudeCodeSettings) {
|
|
67
|
-
const settingsPath = join(baseDir, ".claude", "settings.json");
|
|
68
|
-
|
|
69
|
-
let settings = {};
|
|
70
|
-
if (existsSync(settingsPath)) {
|
|
71
|
-
const content = await readFile(settingsPath, "utf-8");
|
|
72
|
-
settings = JSON.parse(content);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const merged = { ...settings, ...claudeCodeSettings };
|
|
76
|
-
|
|
77
|
-
await ensureDir(settingsPath);
|
|
78
|
-
await writeFile(
|
|
79
|
-
settingsPath,
|
|
80
|
-
JSON.stringify(merged, null, 2) + "\n",
|
|
81
|
-
"utf-8",
|
|
82
|
-
);
|
|
83
|
-
console.log(formatSuccess(`Updated: ${settingsPath}`));
|
|
84
|
-
}
|
|
43
|
+
import {
|
|
44
|
+
generateClaudeCodeSettings,
|
|
45
|
+
writeProfile,
|
|
46
|
+
writeTeamInstructions,
|
|
47
|
+
writeSkills,
|
|
48
|
+
} from "./agent-io.js";
|
|
85
49
|
|
|
86
50
|
/**
|
|
87
51
|
* Show agent summary with stats
|
|
@@ -125,34 +89,54 @@ function showAgentSummary(data, agentData, skillsWithAgent) {
|
|
|
125
89
|
}
|
|
126
90
|
|
|
127
91
|
/**
|
|
128
|
-
*
|
|
92
|
+
* Find valid agent combination pairs
|
|
129
93
|
* @param {Object} data - Pathway data
|
|
130
94
|
* @param {Object} agentData - Agent-specific data
|
|
131
|
-
* @
|
|
95
|
+
* @returns {Array<{discipline: Object, track: Object, humanDiscipline: Object, humanTrack: Object}>}
|
|
132
96
|
*/
|
|
133
|
-
function
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
for (const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
const abbrev = getDisciplineAbbreviation(discipline.id);
|
|
144
|
-
const agentName = `${abbrev}-${toKebabCase(track.id)}`;
|
|
145
|
-
const specName = humanDiscipline.specialization || humanDiscipline.id;
|
|
146
|
-
console.log(
|
|
147
|
-
`${agentName} ${discipline.id} ${track.id}, ${specName} (${humanTrack.name})`,
|
|
148
|
-
);
|
|
149
|
-
}
|
|
97
|
+
function findValidCombinations(data, agentData) {
|
|
98
|
+
const pairs = [];
|
|
99
|
+
for (const discipline of agentData.disciplines) {
|
|
100
|
+
for (const track of agentData.tracks) {
|
|
101
|
+
const humanDiscipline = data.disciplines.find(
|
|
102
|
+
(d) => d.id === discipline.id,
|
|
103
|
+
);
|
|
104
|
+
const humanTrack = data.tracks.find((t) => t.id === track.id);
|
|
105
|
+
if (humanDiscipline && humanTrack) {
|
|
106
|
+
pairs.push({ discipline, track, humanDiscipline, humanTrack });
|
|
150
107
|
}
|
|
151
108
|
}
|
|
152
|
-
return;
|
|
153
109
|
}
|
|
110
|
+
return pairs;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* List available agent combinations — compact output for piping
|
|
115
|
+
* @param {Object} data - Pathway data
|
|
116
|
+
* @param {Object} agentData - Agent-specific data
|
|
117
|
+
*/
|
|
118
|
+
function listAgentCombinationsCompact(data, agentData) {
|
|
119
|
+
for (const {
|
|
120
|
+
discipline,
|
|
121
|
+
track,
|
|
122
|
+
humanDiscipline,
|
|
123
|
+
humanTrack,
|
|
124
|
+
} of findValidCombinations(data, agentData)) {
|
|
125
|
+
const abbrev = getDisciplineAbbreviation(discipline.id);
|
|
126
|
+
const agentName = `${abbrev}-${toKebabCase(track.id)}`;
|
|
127
|
+
const specName = humanDiscipline.specialization || humanDiscipline.id;
|
|
128
|
+
console.log(
|
|
129
|
+
`${agentName} ${discipline.id} ${track.id}, ${specName} (${humanTrack.name})`,
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
154
133
|
|
|
155
|
-
|
|
134
|
+
/**
|
|
135
|
+
* List available agent combinations — verbose output
|
|
136
|
+
* @param {Object} data - Pathway data
|
|
137
|
+
* @param {Object} agentData - Agent-specific data
|
|
138
|
+
*/
|
|
139
|
+
function listAgentCombinationsVerbose(data, agentData) {
|
|
156
140
|
console.log("# 🤖 Available Agent Combinations\n");
|
|
157
141
|
|
|
158
142
|
const agentDisciplineIds = new Set(agentData.disciplines.map((d) => d.id));
|
|
@@ -160,8 +144,7 @@ function listAgentCombinations(data, agentData, verbose = false) {
|
|
|
160
144
|
|
|
161
145
|
console.log("## Disciplines with agent definitions:\n");
|
|
162
146
|
for (const discipline of data.disciplines) {
|
|
163
|
-
const
|
|
164
|
-
const status = hasAgent ? "✅" : "⬜";
|
|
147
|
+
const status = agentDisciplineIds.has(discipline.id) ? "✅" : "⬜";
|
|
165
148
|
console.log(
|
|
166
149
|
` ${status} ${discipline.id} - ${discipline.specialization || discipline.name}`,
|
|
167
150
|
);
|
|
@@ -169,22 +152,13 @@ function listAgentCombinations(data, agentData, verbose = false) {
|
|
|
169
152
|
|
|
170
153
|
console.log("\n## Tracks with agent definitions:\n");
|
|
171
154
|
for (const track of data.tracks) {
|
|
172
|
-
const
|
|
173
|
-
const status = hasAgent ? "✅" : "⬜";
|
|
155
|
+
const status = agentTrackIds.has(track.id) ? "✅" : "⬜";
|
|
174
156
|
console.log(` ${status} ${track.id} - ${track.name}`);
|
|
175
157
|
}
|
|
176
158
|
|
|
177
159
|
console.log("\n## Valid combinations:\n");
|
|
178
|
-
for (const discipline of agentData
|
|
179
|
-
|
|
180
|
-
const humanDiscipline = data.disciplines.find(
|
|
181
|
-
(d) => d.id === discipline.id,
|
|
182
|
-
);
|
|
183
|
-
const humanTrack = data.tracks.find((t) => t.id === track.id);
|
|
184
|
-
if (humanDiscipline && humanTrack) {
|
|
185
|
-
console.log(` bunx pathway agent ${discipline.id} ${track.id}`);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
160
|
+
for (const { discipline, track } of findValidCombinations(data, agentData)) {
|
|
161
|
+
console.log(` bunx pathway agent ${discipline.id} ${track.id}`);
|
|
188
162
|
}
|
|
189
163
|
|
|
190
164
|
console.log("\n## Available stages:\n");
|
|
@@ -194,158 +168,44 @@ function listAgentCombinations(data, agentData, verbose = false) {
|
|
|
194
168
|
}
|
|
195
169
|
|
|
196
170
|
/**
|
|
197
|
-
*
|
|
198
|
-
* @param {Object}
|
|
199
|
-
* @param {
|
|
200
|
-
* @param {
|
|
201
|
-
*/
|
|
202
|
-
async function writeProfile(profile, baseDir, template) {
|
|
203
|
-
const profilePath = join(baseDir, ".claude", "agents", profile.filename);
|
|
204
|
-
const profileContent = formatAgentProfile(profile, template);
|
|
205
|
-
await ensureDir(profilePath);
|
|
206
|
-
await writeFile(profilePath, profileContent, "utf-8");
|
|
207
|
-
console.log(formatSuccess(`Created: ${profilePath}`));
|
|
208
|
-
return profilePath;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
* Write team instructions to CLAUDE.md
|
|
213
|
-
* @param {string|null} teamInstructions - Interpolated team instructions content
|
|
214
|
-
* @param {string} baseDir - Base output directory
|
|
215
|
-
* @returns {string|null} Path written, or null if skipped
|
|
216
|
-
*/
|
|
217
|
-
async function writeTeamInstructions(teamInstructions, baseDir) {
|
|
218
|
-
if (!teamInstructions) return null;
|
|
219
|
-
const filePath = join(baseDir, ".claude", "CLAUDE.md");
|
|
220
|
-
await ensureDir(filePath);
|
|
221
|
-
await writeFile(filePath, teamInstructions.trim() + "\n", "utf-8");
|
|
222
|
-
console.log(formatSuccess(`Created: ${filePath}`));
|
|
223
|
-
return filePath;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* Write skill files (SKILL.md, scripts/install.sh, references/REFERENCE.md)
|
|
228
|
-
* @param {Array} skills - Generated skills
|
|
229
|
-
* @param {string} baseDir - Base output directory
|
|
230
|
-
* @param {Object} templates - Templates object with skill, install, reference
|
|
171
|
+
* List available agent combinations (clean output for piping)
|
|
172
|
+
* @param {Object} data - Pathway data
|
|
173
|
+
* @param {Object} agentData - Agent-specific data
|
|
174
|
+
* @param {boolean} verbose - Show verbose output
|
|
231
175
|
*/
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
// Write SKILL.md (always)
|
|
238
|
-
const skillPath = join(skillDir, "SKILL.md");
|
|
239
|
-
const skillContent = formatAgentSkill(skill, templates.skill);
|
|
240
|
-
await ensureDir(skillPath);
|
|
241
|
-
await writeFile(skillPath, skillContent, "utf-8");
|
|
242
|
-
console.log(formatSuccess(`Created: ${skillPath}`));
|
|
243
|
-
fileCount++;
|
|
244
|
-
|
|
245
|
-
// Write scripts/install.sh (only when installScript exists)
|
|
246
|
-
if (skill.installScript) {
|
|
247
|
-
const installPath = join(skillDir, "scripts", "install.sh");
|
|
248
|
-
const installContent = formatInstallScript(skill, templates.install);
|
|
249
|
-
await ensureDir(installPath);
|
|
250
|
-
await writeFile(installPath, installContent, { mode: 0o755 });
|
|
251
|
-
console.log(formatSuccess(`Created: ${installPath}`));
|
|
252
|
-
fileCount++;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
// Write references/REFERENCE.md (only when implementationReference exists)
|
|
256
|
-
if (skill.implementationReference) {
|
|
257
|
-
const refPath = join(skillDir, "references", "REFERENCE.md");
|
|
258
|
-
const refContent = formatReference(skill, templates.reference);
|
|
259
|
-
await ensureDir(refPath);
|
|
260
|
-
await writeFile(refPath, refContent, "utf-8");
|
|
261
|
-
console.log(formatSuccess(`Created: ${refPath}`));
|
|
262
|
-
fileCount++;
|
|
263
|
-
}
|
|
176
|
+
function listAgentCombinations(data, agentData, verbose = false) {
|
|
177
|
+
if (verbose) {
|
|
178
|
+
listAgentCombinationsVerbose(data, agentData);
|
|
179
|
+
} else {
|
|
180
|
+
listAgentCombinationsCompact(data, agentData);
|
|
264
181
|
}
|
|
265
|
-
return fileCount;
|
|
266
182
|
}
|
|
267
183
|
|
|
268
184
|
/**
|
|
269
|
-
*
|
|
270
|
-
* @param {Object}
|
|
271
|
-
* @param {Object}
|
|
272
|
-
* @param {string
|
|
273
|
-
* @param {
|
|
274
|
-
* @
|
|
185
|
+
* Resolve and validate human + agent entities for a discipline/track pair
|
|
186
|
+
* @param {Object} data - Full pathway data
|
|
187
|
+
* @param {Object} agentData - Agent-specific data
|
|
188
|
+
* @param {string} disciplineId
|
|
189
|
+
* @param {string|null} trackId
|
|
190
|
+
* @returns {{humanDiscipline: Object, humanTrack: Object|null, agentDiscipline: Object, agentTrack: Object|null}}
|
|
275
191
|
*/
|
|
276
|
-
|
|
277
|
-
data,
|
|
278
|
-
args,
|
|
279
|
-
options,
|
|
280
|
-
dataDir,
|
|
281
|
-
templateLoader,
|
|
282
|
-
loader,
|
|
283
|
-
}) {
|
|
284
|
-
// Load agent-specific data
|
|
285
|
-
const dataLoader = loader || createDataLoader();
|
|
286
|
-
const agentData = await dataLoader.loadAgentData(dataDir);
|
|
287
|
-
const skillsWithAgent = await dataLoader.loadSkillsWithAgentData(dataDir);
|
|
288
|
-
|
|
289
|
-
// --list: Output clean lines for piping
|
|
290
|
-
if (options.list) {
|
|
291
|
-
listAgentCombinations(data, agentData, false);
|
|
292
|
-
return;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
// No args: Show summary
|
|
296
|
-
if (args.length === 0) {
|
|
297
|
-
showAgentSummary(data, agentData, skillsWithAgent);
|
|
298
|
-
return;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
const [disciplineId] = args;
|
|
302
|
-
const trackId = options.track;
|
|
303
|
-
|
|
304
|
-
// Reject unexpected positional args (track must use --track=<id>)
|
|
305
|
-
if (args.length > 1) {
|
|
306
|
-
console.error(
|
|
307
|
-
formatError(
|
|
308
|
-
`Unexpected argument: ${args[1]}. Did you mean --track=${args[1]}?`,
|
|
309
|
-
),
|
|
310
|
-
);
|
|
311
|
-
process.exit(1);
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
if (!disciplineId) {
|
|
315
|
-
console.error(
|
|
316
|
-
formatError(
|
|
317
|
-
"Usage: bunx pathway agent <discipline_id> [--track=<track_id>]",
|
|
318
|
-
),
|
|
319
|
-
);
|
|
320
|
-
console.error(
|
|
321
|
-
"\nRun 'bunx pathway agent --list' to see available combinations.",
|
|
322
|
-
);
|
|
323
|
-
process.exit(1);
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
// Look up human definitions
|
|
192
|
+
function resolveAgentEntities(data, agentData, disciplineId, trackId) {
|
|
327
193
|
const humanDiscipline = data.disciplines.find((d) => d.id === disciplineId);
|
|
328
194
|
const humanTrack = trackId ? data.tracks.find((t) => t.id === trackId) : null;
|
|
329
195
|
|
|
330
196
|
if (!humanDiscipline) {
|
|
331
197
|
console.error(formatError(`Unknown discipline: ${disciplineId}`));
|
|
332
198
|
console.error("\nAvailable disciplines:");
|
|
333
|
-
for (const d of data.disciplines) {
|
|
334
|
-
console.error(` - ${d.id}`);
|
|
335
|
-
}
|
|
199
|
+
for (const d of data.disciplines) console.error(` - ${d.id}`);
|
|
336
200
|
process.exit(1);
|
|
337
201
|
}
|
|
338
|
-
|
|
339
202
|
if (trackId && !humanTrack) {
|
|
340
203
|
console.error(formatError(`Unknown track: ${trackId}`));
|
|
341
204
|
console.error("\nAvailable tracks:");
|
|
342
|
-
for (const t of data.tracks) {
|
|
343
|
-
console.error(` - ${t.id}`);
|
|
344
|
-
}
|
|
205
|
+
for (const t of data.tracks) console.error(` - ${t.id}`);
|
|
345
206
|
process.exit(1);
|
|
346
207
|
}
|
|
347
208
|
|
|
348
|
-
// Look up agent definitions
|
|
349
209
|
const agentDiscipline = agentData.disciplines.find(
|
|
350
210
|
(d) => d.id === disciplineId,
|
|
351
211
|
);
|
|
@@ -358,135 +218,109 @@ export async function runAgentCommand({
|
|
|
358
218
|
formatError(`No agent definition for discipline: ${disciplineId}`),
|
|
359
219
|
);
|
|
360
220
|
console.error("\nAgent definitions exist for:");
|
|
361
|
-
for (const d of agentData.disciplines) {
|
|
362
|
-
console.error(` - ${d.id}`);
|
|
363
|
-
}
|
|
221
|
+
for (const d of agentData.disciplines) console.error(` - ${d.id}`);
|
|
364
222
|
process.exit(1);
|
|
365
223
|
}
|
|
366
|
-
|
|
367
224
|
if (trackId && !agentTrack) {
|
|
368
225
|
console.error(formatError(`No agent definition for track: ${trackId}`));
|
|
369
226
|
console.error("\nAgent definitions exist for:");
|
|
370
|
-
for (const t of agentData.tracks) {
|
|
371
|
-
console.error(` - ${t.id}`);
|
|
372
|
-
}
|
|
227
|
+
for (const t of agentData.tracks) console.error(` - ${t.id}`);
|
|
373
228
|
process.exit(1);
|
|
374
229
|
}
|
|
375
230
|
|
|
376
|
-
|
|
377
|
-
|
|
231
|
+
return { humanDiscipline, humanTrack, agentDiscipline, agentTrack };
|
|
232
|
+
}
|
|
378
233
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
234
|
+
/**
|
|
235
|
+
* Output team instructions to console if present
|
|
236
|
+
* @param {Object|null} agentTrack
|
|
237
|
+
* @param {Object} humanDiscipline
|
|
238
|
+
*/
|
|
239
|
+
function printTeamInstructions(agentTrack, humanDiscipline) {
|
|
240
|
+
const teamInstructions = interpolateTeamInstructions(
|
|
241
|
+
agentTrack,
|
|
242
|
+
humanDiscipline,
|
|
243
|
+
);
|
|
244
|
+
if (teamInstructions) {
|
|
245
|
+
console.log("# Team Instructions (CLAUDE.md)\n");
|
|
246
|
+
console.log(teamInstructions.trim());
|
|
247
|
+
console.log("\n---\n");
|
|
391
248
|
}
|
|
249
|
+
}
|
|
392
250
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
251
|
+
/**
|
|
252
|
+
* Handle single-stage agent generation
|
|
253
|
+
* @param {Object} params
|
|
254
|
+
*/
|
|
255
|
+
async function handleSingleStage({
|
|
256
|
+
stageParams,
|
|
257
|
+
options,
|
|
258
|
+
data,
|
|
259
|
+
agentTrack,
|
|
260
|
+
humanDiscipline,
|
|
261
|
+
agentData,
|
|
262
|
+
templateLoader,
|
|
263
|
+
dataDir,
|
|
264
|
+
}) {
|
|
265
|
+
const stage = data.stages.find((s) => s.id === options.stage);
|
|
266
|
+
if (!stage) {
|
|
267
|
+
console.error(formatError(`Unknown stage: ${options.stage}`));
|
|
268
|
+
console.error("\nAvailable stages:");
|
|
269
|
+
for (const s of data.stages) console.error(` - ${s.id}`);
|
|
270
|
+
process.exit(1);
|
|
407
271
|
}
|
|
408
272
|
|
|
409
|
-
const
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
skills: skillsWithAgent,
|
|
417
|
-
behaviours: data.behaviours,
|
|
418
|
-
agentBehaviours: agentData.behaviours,
|
|
419
|
-
agentDiscipline,
|
|
420
|
-
agentTrack,
|
|
421
|
-
stages: data.stages,
|
|
422
|
-
};
|
|
423
|
-
|
|
424
|
-
// Handle --stage flag for single stage agent
|
|
425
|
-
if (options.stage) {
|
|
426
|
-
const stage = data.stages.find((s) => s.id === options.stage);
|
|
427
|
-
if (!stage) {
|
|
428
|
-
console.error(formatError(`Unknown stage: ${options.stage}`));
|
|
429
|
-
console.error("\nAvailable stages:");
|
|
430
|
-
for (const s of data.stages) {
|
|
431
|
-
console.error(` - ${s.id}`);
|
|
432
|
-
}
|
|
433
|
-
process.exit(1);
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
const profile = generateStageAgentProfile({ ...stageParams, stage });
|
|
437
|
-
|
|
438
|
-
// Validate
|
|
439
|
-
const errors = validateAgentProfile(profile);
|
|
440
|
-
if (errors.length > 0) {
|
|
441
|
-
console.error(formatError("Profile validation failed:"));
|
|
442
|
-
for (const err of errors) {
|
|
443
|
-
console.error(` - ${err}`);
|
|
444
|
-
}
|
|
445
|
-
process.exit(1);
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
// Load template
|
|
449
|
-
const agentTemplate = templateLoader.load("agent.template.md", dataDir);
|
|
273
|
+
const profile = generateStageAgentProfile({ ...stageParams, stage });
|
|
274
|
+
const errors = validateAgentProfile(profile);
|
|
275
|
+
if (errors.length > 0) {
|
|
276
|
+
console.error(formatError("Profile validation failed:"));
|
|
277
|
+
for (const err of errors) console.error(` - ${err}`);
|
|
278
|
+
process.exit(1);
|
|
279
|
+
}
|
|
450
280
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
const teamInstructions = interpolateTeamInstructions(
|
|
454
|
-
agentTrack,
|
|
455
|
-
humanDiscipline,
|
|
456
|
-
);
|
|
457
|
-
if (teamInstructions) {
|
|
458
|
-
console.log("# Team Instructions (CLAUDE.md)\n");
|
|
459
|
-
console.log(teamInstructions.trim());
|
|
460
|
-
console.log("\n---\n");
|
|
461
|
-
}
|
|
462
|
-
console.log(formatAgentProfile(profile, agentTemplate));
|
|
463
|
-
return;
|
|
464
|
-
}
|
|
281
|
+
const agentTemplate = templateLoader.load("agent.template.md", dataDir);
|
|
282
|
+
const baseDir = options.output || ".";
|
|
465
283
|
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
);
|
|
470
|
-
await writeTeamInstructions(teamInstructions, baseDir);
|
|
471
|
-
await writeProfile(profile, baseDir, agentTemplate);
|
|
472
|
-
await generateClaudeCodeSettings(baseDir, agentData.claudeCodeSettings);
|
|
473
|
-
console.log("");
|
|
474
|
-
console.log(
|
|
475
|
-
formatSuccess(`Generated stage agent: ${profile.frontmatter.name}`),
|
|
476
|
-
);
|
|
284
|
+
if (!options.output) {
|
|
285
|
+
printTeamInstructions(agentTrack, humanDiscipline);
|
|
286
|
+
console.log(formatAgentProfile(profile, agentTemplate));
|
|
477
287
|
return;
|
|
478
288
|
}
|
|
479
289
|
|
|
480
|
-
|
|
481
|
-
|
|
290
|
+
const teamInstructions = interpolateTeamInstructions(
|
|
291
|
+
agentTrack,
|
|
292
|
+
humanDiscipline,
|
|
293
|
+
);
|
|
294
|
+
await writeTeamInstructions(teamInstructions, baseDir);
|
|
295
|
+
await writeProfile(profile, baseDir, agentTemplate);
|
|
296
|
+
await generateClaudeCodeSettings(baseDir, agentData.claudeCodeSettings);
|
|
297
|
+
console.log("");
|
|
298
|
+
console.log(
|
|
299
|
+
formatSuccess(`Generated stage agent: ${profile.frontmatter.name}`),
|
|
300
|
+
);
|
|
301
|
+
}
|
|
482
302
|
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
303
|
+
/**
|
|
304
|
+
* Handle all-stages agent generation
|
|
305
|
+
* @param {Object} params
|
|
306
|
+
*/
|
|
307
|
+
async function handleAllStages({
|
|
308
|
+
stageParams,
|
|
309
|
+
options,
|
|
310
|
+
data,
|
|
311
|
+
agentTrack,
|
|
312
|
+
humanDiscipline,
|
|
313
|
+
humanTrack,
|
|
314
|
+
agentData,
|
|
315
|
+
skillsWithAgent,
|
|
316
|
+
level,
|
|
317
|
+
templateLoader,
|
|
318
|
+
dataDir,
|
|
319
|
+
}) {
|
|
320
|
+
const profiles = data.stages.map((stage) =>
|
|
321
|
+
generateStageAgentProfile({ ...stageParams, stage }),
|
|
322
|
+
);
|
|
488
323
|
|
|
489
|
-
// Derive skills once for all stages
|
|
490
324
|
const derivedSkills = deriveAgentSkills({
|
|
491
325
|
discipline: humanDiscipline,
|
|
492
326
|
track: humanTrack,
|
|
@@ -499,62 +333,39 @@ export async function runAgentCommand({
|
|
|
499
333
|
.filter((skill) => skill?.agent)
|
|
500
334
|
.map((skill) => generateSkillMarkdown(skill, data.stages));
|
|
501
335
|
|
|
502
|
-
// Validate all profiles
|
|
503
336
|
for (const profile of profiles) {
|
|
504
337
|
const errors = validateAgentProfile(profile);
|
|
505
338
|
if (errors.length > 0) {
|
|
506
339
|
console.error(
|
|
507
340
|
formatError(`Profile ${profile.frontmatter.name} validation failed:`),
|
|
508
341
|
);
|
|
509
|
-
for (const err of errors) {
|
|
510
|
-
console.error(` - ${err}`);
|
|
511
|
-
}
|
|
342
|
+
for (const err of errors) console.error(` - ${err}`);
|
|
512
343
|
process.exit(1);
|
|
513
344
|
}
|
|
514
345
|
}
|
|
515
346
|
|
|
516
|
-
// Validate all skills
|
|
517
347
|
for (const skill of skillFiles) {
|
|
518
348
|
const errors = validateAgentSkill(skill);
|
|
519
349
|
if (errors.length > 0) {
|
|
520
350
|
console.error(
|
|
521
351
|
formatError(`Skill ${skill.frontmatter.name} validation failed:`),
|
|
522
352
|
);
|
|
523
|
-
for (const err of errors) {
|
|
524
|
-
console.error(` - ${err}`);
|
|
525
|
-
}
|
|
353
|
+
for (const err of errors) console.error(` - ${err}`);
|
|
526
354
|
process.exit(1);
|
|
527
355
|
}
|
|
528
356
|
}
|
|
529
357
|
|
|
530
|
-
// Load templates
|
|
531
358
|
const agentTemplate = templateLoader.load("agent.template.md", dataDir);
|
|
532
|
-
const skillTemplate = templateLoader.load("skill.template.md", dataDir);
|
|
533
|
-
const installTemplate = templateLoader.load(
|
|
534
|
-
"skill-install.template.sh",
|
|
535
|
-
dataDir,
|
|
536
|
-
);
|
|
537
|
-
const referenceTemplate = templateLoader.load(
|
|
538
|
-
"skill-reference.template.md",
|
|
539
|
-
dataDir,
|
|
540
|
-
);
|
|
541
359
|
const skillTemplates = {
|
|
542
|
-
skill:
|
|
543
|
-
install:
|
|
544
|
-
reference:
|
|
360
|
+
skill: templateLoader.load("skill.template.md", dataDir),
|
|
361
|
+
install: templateLoader.load("skill-install.template.sh", dataDir),
|
|
362
|
+
reference: templateLoader.load("skill-reference.template.md", dataDir),
|
|
545
363
|
};
|
|
546
364
|
|
|
547
|
-
|
|
365
|
+
const baseDir = options.output || ".";
|
|
366
|
+
|
|
548
367
|
if (!options.output) {
|
|
549
|
-
|
|
550
|
-
agentTrack,
|
|
551
|
-
humanDiscipline,
|
|
552
|
-
);
|
|
553
|
-
if (teamInstructions) {
|
|
554
|
-
console.log("# Team Instructions (CLAUDE.md)\n");
|
|
555
|
-
console.log(teamInstructions.trim());
|
|
556
|
-
console.log("\n---\n");
|
|
557
|
-
}
|
|
368
|
+
printTeamInstructions(agentTrack, humanDiscipline);
|
|
558
369
|
for (const profile of profiles) {
|
|
559
370
|
console.log(formatAgentProfile(profile, agentTemplate));
|
|
560
371
|
console.log("\n---\n");
|
|
@@ -580,3 +391,109 @@ export async function runAgentCommand({
|
|
|
580
391
|
}
|
|
581
392
|
console.log(` Skills: ${fileCount} files`);
|
|
582
393
|
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Run the agent command
|
|
397
|
+
* @param {Object} params - Command parameters
|
|
398
|
+
* @param {Object} params.data - Loaded pathway data
|
|
399
|
+
* @param {string[]} params.args - Command arguments [discipline_id]
|
|
400
|
+
* @param {Object} params.options - Command options
|
|
401
|
+
* @param {string} params.dataDir - Path to data directory
|
|
402
|
+
*/
|
|
403
|
+
export async function runAgentCommand({
|
|
404
|
+
data,
|
|
405
|
+
args,
|
|
406
|
+
options,
|
|
407
|
+
dataDir,
|
|
408
|
+
templateLoader,
|
|
409
|
+
loader,
|
|
410
|
+
}) {
|
|
411
|
+
const dataLoader = loader || createDataLoader();
|
|
412
|
+
const agentData = await dataLoader.loadAgentData(dataDir);
|
|
413
|
+
const skillsWithAgent = await dataLoader.loadSkillsWithAgentData(dataDir);
|
|
414
|
+
|
|
415
|
+
if (options.list) {
|
|
416
|
+
listAgentCombinations(data, agentData, false);
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
if (args.length === 0) {
|
|
421
|
+
showAgentSummary(data, agentData, skillsWithAgent);
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
const [disciplineId] = args;
|
|
426
|
+
const trackId = options.track;
|
|
427
|
+
|
|
428
|
+
if (args.length > 1) {
|
|
429
|
+
console.error(
|
|
430
|
+
formatError(
|
|
431
|
+
`Unexpected argument: ${args[1]}. Did you mean --track=${args[1]}?`,
|
|
432
|
+
),
|
|
433
|
+
);
|
|
434
|
+
process.exit(1);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
const { humanDiscipline, humanTrack, agentDiscipline, agentTrack } =
|
|
438
|
+
resolveAgentEntities(data, agentData, disciplineId, trackId);
|
|
439
|
+
|
|
440
|
+
const level = deriveReferenceLevel(data.levels);
|
|
441
|
+
|
|
442
|
+
if (options.skills) {
|
|
443
|
+
const derivedSkills = deriveAgentSkills({
|
|
444
|
+
discipline: humanDiscipline,
|
|
445
|
+
track: humanTrack,
|
|
446
|
+
level,
|
|
447
|
+
skills: skillsWithAgent,
|
|
448
|
+
});
|
|
449
|
+
for (const skill of derivedSkills) console.log(skill.skillId);
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
if (options.tools) {
|
|
454
|
+
const derivedSkills = deriveAgentSkills({
|
|
455
|
+
discipline: humanDiscipline,
|
|
456
|
+
track: humanTrack,
|
|
457
|
+
level,
|
|
458
|
+
skills: skillsWithAgent,
|
|
459
|
+
});
|
|
460
|
+
const toolkit = deriveToolkit({
|
|
461
|
+
skillMatrix: derivedSkills,
|
|
462
|
+
skills: skillsWithAgent,
|
|
463
|
+
});
|
|
464
|
+
console.log(toolkitToPlainList(toolkit));
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
const stageParams = {
|
|
469
|
+
discipline: humanDiscipline,
|
|
470
|
+
track: humanTrack,
|
|
471
|
+
level,
|
|
472
|
+
skills: skillsWithAgent,
|
|
473
|
+
behaviours: data.behaviours,
|
|
474
|
+
agentBehaviours: agentData.behaviours,
|
|
475
|
+
agentDiscipline,
|
|
476
|
+
agentTrack,
|
|
477
|
+
stages: data.stages,
|
|
478
|
+
};
|
|
479
|
+
|
|
480
|
+
const commonCtx = {
|
|
481
|
+
stageParams,
|
|
482
|
+
options,
|
|
483
|
+
data,
|
|
484
|
+
agentTrack,
|
|
485
|
+
humanDiscipline,
|
|
486
|
+
humanTrack,
|
|
487
|
+
agentData,
|
|
488
|
+
skillsWithAgent,
|
|
489
|
+
level,
|
|
490
|
+
templateLoader,
|
|
491
|
+
dataDir,
|
|
492
|
+
};
|
|
493
|
+
|
|
494
|
+
if (options.stage) {
|
|
495
|
+
await handleSingleStage(commonCtx);
|
|
496
|
+
} else {
|
|
497
|
+
await handleAllStages(commonCtx);
|
|
498
|
+
}
|
|
499
|
+
}
|