@forwardimpact/pathway 0.24.0 → 0.25.1
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/README.md +3 -3
- package/bin/fit-pathway.js +18 -47
- package/package.json +4 -4
- package/src/commands/agent.js +11 -93
- package/src/commands/build.js +18 -0
- package/src/commands/dev.js +15 -0
- package/src/commands/update.js +8 -4
- package/src/components/skill-matrix.js +21 -9
- package/src/formatters/agent/dom.js +27 -47
- package/src/formatters/agent/profile.js +49 -35
- package/src/formatters/job/dom.js +5 -59
- package/src/handout.html +1 -1
- package/src/index.html +9 -3
- package/src/lib/radar.js +19 -5
- package/src/lib/yaml-loader.js +10 -24
- package/src/pages/agent-builder.js +26 -83
- package/src/pages/landing.js +1 -1
- package/src/slide-main.js +16 -2
- package/src/slides.html +1 -1
- package/templates/agent.template.md +55 -76
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Agent Profile Formatter
|
|
3
3
|
*
|
|
4
|
-
* Formats agent profile data into .
|
|
5
|
-
* following the
|
|
4
|
+
* Formats agent profile data into .md file content
|
|
5
|
+
* following the Claude Code agent specification.
|
|
6
6
|
*
|
|
7
7
|
* Uses Mustache templates for flexible output formatting.
|
|
8
8
|
* Templates are loaded from data/ directory with fallback to templates/ directory.
|
|
@@ -11,10 +11,7 @@
|
|
|
11
11
|
import Mustache from "mustache";
|
|
12
12
|
|
|
13
13
|
import { trimValue, trimRequired, trimFields } from "../shared.js";
|
|
14
|
-
import {
|
|
15
|
-
flattenToLine,
|
|
16
|
-
preprocessArrayFrontmatter,
|
|
17
|
-
} from "../template-preprocess.js";
|
|
14
|
+
import { flattenToLine } from "../template-preprocess.js";
|
|
18
15
|
|
|
19
16
|
/**
|
|
20
17
|
* @typedef {Object} WorkingStyleEntry
|
|
@@ -29,8 +26,8 @@ import {
|
|
|
29
26
|
* @param {Object} params.frontmatter - YAML frontmatter data
|
|
30
27
|
* @param {string} params.frontmatter.name - Agent name
|
|
31
28
|
* @param {string} params.frontmatter.description - Agent description
|
|
32
|
-
* @param {
|
|
33
|
-
* @param {
|
|
29
|
+
* @param {string} params.frontmatter.model - Claude Code model (sonnet, opus, haiku)
|
|
30
|
+
* @param {string[]} params.frontmatter.skills - Skill dirnames for auto-loading
|
|
34
31
|
* @param {Object} params.bodyData - Structured body data
|
|
35
32
|
* @param {string} params.bodyData.title - Agent title
|
|
36
33
|
* @param {string} params.bodyData.stageDescription - Stage description text
|
|
@@ -43,41 +40,51 @@ import {
|
|
|
43
40
|
* @param {string} params.bodyData.roleContext - Role context text
|
|
44
41
|
* @param {WorkingStyleEntry[]} params.bodyData.workingStyles - Working style entries
|
|
45
42
|
* @param {string[]} params.bodyData.constraints - List of constraints
|
|
46
|
-
* @param {Array<{
|
|
47
|
-
* @param {boolean} [params.bodyData.hasAgentIndex] - Whether agent index is available
|
|
43
|
+
* @param {Array<{targetStageName: string, summaryInstruction: string, entryCriteria: string[]}>} params.bodyData.stageTransitions - Stage transition definitions
|
|
48
44
|
* @returns {Object} Data object ready for Mustache template
|
|
49
45
|
*/
|
|
50
46
|
function prepareAgentProfileData({ frontmatter, bodyData }) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
47
|
+
const stageConstraints = (bodyData.stageConstraints || []).map((c) =>
|
|
48
|
+
trimRequired(c),
|
|
49
|
+
);
|
|
50
|
+
const disciplineConstraints = (bodyData.disciplineConstraints || []).map(
|
|
51
|
+
(c) => trimRequired(c),
|
|
52
|
+
);
|
|
53
|
+
const trackConstraints = (bodyData.trackConstraints || []).map((c) =>
|
|
54
|
+
trimRequired(c),
|
|
55
|
+
);
|
|
56
|
+
const returnFormat = (bodyData.returnFormat || []).map((r) =>
|
|
57
|
+
trimRequired(r),
|
|
55
58
|
);
|
|
56
|
-
// Then trim as before
|
|
57
|
-
const handoffs = trimFields(preprocessedHandoffs, { prompt: "required" });
|
|
58
|
-
|
|
59
|
-
const constraints = (bodyData.constraints || []).map((c) => trimRequired(c));
|
|
60
59
|
const skillIndex = trimFields(bodyData.skillIndex, {
|
|
61
60
|
name: "required",
|
|
62
61
|
dirname: "required",
|
|
63
62
|
useWhen: "required",
|
|
64
63
|
});
|
|
65
|
-
const agentIndex = trimFields(bodyData.agentIndex, {
|
|
66
|
-
id: "required",
|
|
67
|
-
name: "required",
|
|
68
|
-
description: "required",
|
|
69
|
-
});
|
|
70
64
|
const workingStyles = trimFields(bodyData.workingStyles, {
|
|
71
65
|
title: "required",
|
|
72
66
|
content: "required",
|
|
73
67
|
});
|
|
74
68
|
|
|
69
|
+
// Prepare stage transitions for body rendering
|
|
70
|
+
const stageTransitions = (bodyData.stageTransitions || []).map((t) => ({
|
|
71
|
+
targetStageName: t.targetStageName,
|
|
72
|
+
summaryInstruction: trimValue(t.summaryInstruction),
|
|
73
|
+
entryCriteria: (t.entryCriteria || []).map((c) => trimRequired(c)),
|
|
74
|
+
hasEntryCriteria: (t.entryCriteria || []).length > 0,
|
|
75
|
+
}));
|
|
76
|
+
|
|
77
|
+
const hasConstraints =
|
|
78
|
+
stageConstraints.length > 0 ||
|
|
79
|
+
disciplineConstraints.length > 0 ||
|
|
80
|
+
trackConstraints.length > 0;
|
|
81
|
+
|
|
75
82
|
return {
|
|
76
|
-
// Frontmatter
|
|
83
|
+
// Frontmatter
|
|
77
84
|
name: frontmatter.name,
|
|
78
85
|
description: flattenToLine(frontmatter.description),
|
|
79
|
-
|
|
80
|
-
|
|
86
|
+
model: frontmatter.model,
|
|
87
|
+
skills: frontmatter.skills,
|
|
81
88
|
|
|
82
89
|
// Body data - trim all string fields
|
|
83
90
|
title: bodyData.title,
|
|
@@ -92,22 +99,28 @@ function prepareAgentProfileData({ frontmatter, bodyData }) {
|
|
|
92
99
|
roleContext: trimValue(bodyData.roleContext),
|
|
93
100
|
workingStyles,
|
|
94
101
|
hasWorkingStyles: workingStyles.length > 0,
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
102
|
+
stageConstraints,
|
|
103
|
+
disciplineConstraints,
|
|
104
|
+
trackConstraints,
|
|
105
|
+
hasStageConstraints: stageConstraints.length > 0,
|
|
106
|
+
hasDisciplineOrTrackConstraints:
|
|
107
|
+
disciplineConstraints.length > 0 || trackConstraints.length > 0,
|
|
108
|
+
hasConstraints,
|
|
109
|
+
returnFormat,
|
|
110
|
+
hasReturnFormat: returnFormat.length > 0,
|
|
111
|
+
stageTransitions,
|
|
112
|
+
hasStageTransitions: stageTransitions.length > 0,
|
|
99
113
|
};
|
|
100
114
|
}
|
|
101
115
|
|
|
102
116
|
/**
|
|
103
|
-
* Format agent profile as .
|
|
117
|
+
* Format agent profile as .md file content using Mustache template
|
|
104
118
|
* @param {Object} profile - Profile with frontmatter and bodyData
|
|
105
119
|
* @param {Object} profile.frontmatter - YAML frontmatter data
|
|
106
120
|
* @param {string} profile.frontmatter.name - Agent name
|
|
107
121
|
* @param {string} profile.frontmatter.description - Agent description
|
|
108
|
-
* @param {string
|
|
109
|
-
* @param {
|
|
110
|
-
* @param {Array} [profile.frontmatter.handoffs] - Handoff definitions
|
|
122
|
+
* @param {string} profile.frontmatter.model - Claude Code model
|
|
123
|
+
* @param {string[]} profile.frontmatter.skills - Skill dirnames
|
|
111
124
|
* @param {Object} profile.bodyData - Structured body data
|
|
112
125
|
* @param {string} profile.bodyData.title - Agent title (e.g. "Software Engineering - Platform - Plan Agent")
|
|
113
126
|
* @param {string} profile.bodyData.stageDescription - Stage description text
|
|
@@ -117,8 +130,9 @@ function prepareAgentProfileData({ frontmatter, bodyData }) {
|
|
|
117
130
|
* @param {string} profile.bodyData.roleContext - Role context text
|
|
118
131
|
* @param {WorkingStyleEntry[]} profile.bodyData.workingStyles - Working style entries
|
|
119
132
|
* @param {string[]} profile.bodyData.constraints - List of constraints
|
|
133
|
+
* @param {Array} profile.bodyData.stageTransitions - Stage transitions for body section
|
|
120
134
|
* @param {string} template - Mustache template string
|
|
121
|
-
* @returns {string} Complete .
|
|
135
|
+
* @returns {string} Complete .md file content
|
|
122
136
|
*/
|
|
123
137
|
export function formatAgentProfile({ frontmatter, bodyData }, template) {
|
|
124
138
|
const data = prepareAgentProfileData({ frontmatter, bodyData });
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Job formatting for DOM/web output
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { div, h1, h2,
|
|
5
|
+
import { div, h1, h2, a, section } from "../../lib/render.js";
|
|
6
6
|
import { createBackLink } from "../../components/nav.js";
|
|
7
7
|
import {
|
|
8
8
|
createDetailSection,
|
|
@@ -117,7 +117,9 @@ export function jobToDOM(view, options = {}) {
|
|
|
117
117
|
|
|
118
118
|
createDetailSection({
|
|
119
119
|
title: "Skill Matrix",
|
|
120
|
-
content: createSkillMatrix(view.skillMatrix
|
|
120
|
+
content: createSkillMatrix(view.skillMatrix, {
|
|
121
|
+
capabilityOrder: view.capabilityOrder,
|
|
122
|
+
}),
|
|
121
123
|
}),
|
|
122
124
|
|
|
123
125
|
// Toolkit (after skill matrix)
|
|
@@ -127,21 +129,6 @@ export function jobToDOM(view, options = {}) {
|
|
|
127
129
|
content: createToolkitTable(view.toolkit),
|
|
128
130
|
})
|
|
129
131
|
: null,
|
|
130
|
-
|
|
131
|
-
// Driver coverage
|
|
132
|
-
view.driverCoverage.length > 0
|
|
133
|
-
? createDetailSection({
|
|
134
|
-
title: "Driver Coverage",
|
|
135
|
-
content: div(
|
|
136
|
-
{},
|
|
137
|
-
p(
|
|
138
|
-
{ className: "text-muted", style: "margin-bottom: 1rem" },
|
|
139
|
-
"How well this job aligns with organizational outcome drivers.",
|
|
140
|
-
),
|
|
141
|
-
createDriverCoverageDisplay(view.driverCoverage),
|
|
142
|
-
),
|
|
143
|
-
})
|
|
144
|
-
: null,
|
|
145
132
|
)
|
|
146
133
|
: null,
|
|
147
134
|
|
|
@@ -164,48 +151,6 @@ export function jobToDOM(view, options = {}) {
|
|
|
164
151
|
);
|
|
165
152
|
}
|
|
166
153
|
|
|
167
|
-
/**
|
|
168
|
-
* Create driver coverage display
|
|
169
|
-
*/
|
|
170
|
-
function createDriverCoverageDisplay(coverage) {
|
|
171
|
-
const items = coverage.map((c) => {
|
|
172
|
-
const percentage = Math.round(c.coverage * 100);
|
|
173
|
-
|
|
174
|
-
return div(
|
|
175
|
-
{ className: "driver-coverage-item" },
|
|
176
|
-
div(
|
|
177
|
-
{ className: "driver-coverage-header" },
|
|
178
|
-
a(
|
|
179
|
-
{
|
|
180
|
-
href: `#/driver/${c.id}`,
|
|
181
|
-
className: "driver-coverage-name",
|
|
182
|
-
},
|
|
183
|
-
c.name,
|
|
184
|
-
),
|
|
185
|
-
span({ className: "driver-coverage-score" }, `${percentage}%`),
|
|
186
|
-
),
|
|
187
|
-
div(
|
|
188
|
-
{ className: "progress-bar" },
|
|
189
|
-
div({
|
|
190
|
-
className: "progress-bar-fill",
|
|
191
|
-
style: `width: ${percentage}%; background: ${getScoreColor(c.coverage)}`,
|
|
192
|
-
}),
|
|
193
|
-
),
|
|
194
|
-
);
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
return div({ className: "driver-coverage" }, ...items);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Get color based on score
|
|
202
|
-
*/
|
|
203
|
-
function getScoreColor(score) {
|
|
204
|
-
if (score >= 0.8) return "#10b981"; // Green
|
|
205
|
-
if (score >= 0.5) return "#f59e0b"; // Yellow
|
|
206
|
-
return "#ef4444"; // Red
|
|
207
|
-
}
|
|
208
|
-
|
|
209
154
|
/**
|
|
210
155
|
* Create the job description section with copy button
|
|
211
156
|
* @param {Object} params
|
|
@@ -243,6 +188,7 @@ export function createJobDescriptionSection({
|
|
|
243
188
|
"Copy this markdown-formatted job description for use in job postings, documentation, or sharing.",
|
|
244
189
|
toHtml: markdownToHtml,
|
|
245
190
|
minHeight: 450,
|
|
191
|
+
open: true,
|
|
246
192
|
}),
|
|
247
193
|
);
|
|
248
194
|
}
|
package/src/handout.html
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<script type="importmap">
|
|
9
9
|
{
|
|
10
10
|
"imports": {
|
|
11
|
-
"mustache": "
|
|
11
|
+
"mustache": "/vendor/mustache.mjs",
|
|
12
12
|
"@forwardimpact/map": "/map/lib/index.js",
|
|
13
13
|
"@forwardimpact/map/levels": "/map/lib/levels.js",
|
|
14
14
|
"@forwardimpact/map/loader": "/map/lib/loader.js",
|
package/src/index.html
CHANGED
|
@@ -15,12 +15,18 @@
|
|
|
15
15
|
href="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism.min.css"
|
|
16
16
|
/>
|
|
17
17
|
<link rel="stylesheet" href="css/bundles/app.css" />
|
|
18
|
-
<script
|
|
19
|
-
|
|
18
|
+
<script
|
|
19
|
+
src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/prism.min.js"
|
|
20
|
+
defer
|
|
21
|
+
></script>
|
|
22
|
+
<script
|
|
23
|
+
src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-markdown.min.js"
|
|
24
|
+
defer
|
|
25
|
+
></script>
|
|
20
26
|
<script type="importmap">
|
|
21
27
|
{
|
|
22
28
|
"imports": {
|
|
23
|
-
"mustache": "
|
|
29
|
+
"mustache": "/vendor/mustache.mjs",
|
|
24
30
|
"@forwardimpact/map": "/map/lib/index.js",
|
|
25
31
|
"@forwardimpact/map/levels": "/map/lib/levels.js",
|
|
26
32
|
"@forwardimpact/map/loader": "/map/lib/loader.js",
|
package/src/lib/radar.js
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
* Radar chart visualization using SVG
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Escape HTML special characters to prevent XSS
|
|
7
|
+
* @param {string} text
|
|
8
|
+
* @returns {string}
|
|
9
|
+
*/
|
|
10
|
+
function escapeHtml(text) {
|
|
11
|
+
return text
|
|
12
|
+
.replace(/&/g, "&")
|
|
13
|
+
.replace(/</g, "<")
|
|
14
|
+
.replace(/>/g, ">")
|
|
15
|
+
.replace(/"/g, """)
|
|
16
|
+
.replace(/'/g, "'");
|
|
17
|
+
}
|
|
18
|
+
|
|
5
19
|
/**
|
|
6
20
|
* @typedef {Object} RadarDataPoint
|
|
7
21
|
* @property {string} label - Label for this axis
|
|
@@ -393,9 +407,9 @@ export class RadarChart {
|
|
|
393
407
|
const y = event.clientY - rect.top;
|
|
394
408
|
|
|
395
409
|
this.tooltip.innerHTML = `
|
|
396
|
-
<strong>${data.label}</strong><br>
|
|
410
|
+
<strong>${escapeHtml(data.label)}</strong><br>
|
|
397
411
|
Value: ${data.value}/${data.maxValue}
|
|
398
|
-
${data.description ? `<br><small>${data.description}</small>` : ""}
|
|
412
|
+
${data.description ? `<br><small>${escapeHtml(data.description)}</small>` : ""}
|
|
399
413
|
`;
|
|
400
414
|
|
|
401
415
|
this.tooltip.style.left = `${x + 10}px`;
|
|
@@ -815,9 +829,9 @@ export class ComparisonRadarChart {
|
|
|
815
829
|
const typeLabel = type === "current" ? "Current" : "Target";
|
|
816
830
|
|
|
817
831
|
this.tooltip.innerHTML = `
|
|
818
|
-
<strong>${data.label}</strong><br>
|
|
832
|
+
<strong>${escapeHtml(data.label)}</strong><br>
|
|
819
833
|
${typeLabel}: ${data.value}/${data.maxValue}
|
|
820
|
-
${data.description ? `<br><small>${data.description}</small>` : ""}
|
|
834
|
+
${data.description ? `<br><small>${escapeHtml(data.description)}</small>` : ""}
|
|
821
835
|
`;
|
|
822
836
|
|
|
823
837
|
this.tooltip.style.left = `${x + 10}px`;
|
|
@@ -844,7 +858,7 @@ export class ComparisonRadarChart {
|
|
|
844
858
|
: "<span style='color: #94a3b8'>No change</span>";
|
|
845
859
|
|
|
846
860
|
this.tooltip.innerHTML = `
|
|
847
|
-
<strong>${currentData.label}</strong><br>
|
|
861
|
+
<strong>${escapeHtml(currentData.label)}</strong><br>
|
|
848
862
|
Current: ${currentData.value}/${currentData.maxValue}<br>
|
|
849
863
|
Target: ${targetData.value}/${targetData.maxValue}<br>
|
|
850
864
|
${diffText}
|
package/src/lib/yaml-loader.js
CHANGED
|
@@ -287,27 +287,15 @@ export async function loadAllData(dataDir = "./data") {
|
|
|
287
287
|
* @returns {Promise<Object>}
|
|
288
288
|
*/
|
|
289
289
|
export async function loadAgentDataBrowser(dataDir = "./data") {
|
|
290
|
-
const [
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
loadTracksFromDir(`${dataDir}/tracks`),
|
|
300
|
-
loadBehavioursFromDir(`${dataDir}/behaviours`),
|
|
301
|
-
tryLoadYamlFile(`${dataDir}/repository/vscode-settings.yaml`).then(
|
|
302
|
-
(r) => r ?? tryLoadYamlFile(`${dataDir}/vscode-settings.yaml`),
|
|
303
|
-
),
|
|
304
|
-
tryLoadYamlFile(`${dataDir}/repository/devcontainer.yaml`).then(
|
|
305
|
-
(r) => r ?? tryLoadYamlFile(`${dataDir}/devcontainer.yaml`),
|
|
306
|
-
),
|
|
307
|
-
tryLoadYamlFile(`${dataDir}/repository/copilot-setup-steps.yaml`).then(
|
|
308
|
-
(r) => r ?? tryLoadYamlFile(`${dataDir}/copilot-setup-steps.yaml`),
|
|
309
|
-
),
|
|
310
|
-
]);
|
|
290
|
+
const [disciplines, tracks, behaviours, claudeCodeSettings] =
|
|
291
|
+
await Promise.all([
|
|
292
|
+
loadDisciplinesFromDir(`${dataDir}/disciplines`),
|
|
293
|
+
loadTracksFromDir(`${dataDir}/tracks`),
|
|
294
|
+
loadBehavioursFromDir(`${dataDir}/behaviours`),
|
|
295
|
+
tryLoadYamlFile(`${dataDir}/repository/claude-code-settings.yaml`).then(
|
|
296
|
+
(r) => r ?? tryLoadYamlFile(`${dataDir}/claude-code-settings.yaml`),
|
|
297
|
+
),
|
|
298
|
+
]);
|
|
311
299
|
|
|
312
300
|
return {
|
|
313
301
|
disciplines: disciplines
|
|
@@ -319,8 +307,6 @@ export async function loadAgentDataBrowser(dataDir = "./data") {
|
|
|
319
307
|
behaviours: behaviours
|
|
320
308
|
.filter((b) => b.agent)
|
|
321
309
|
.map((b) => ({ id: b.id, ...b.agent })),
|
|
322
|
-
|
|
323
|
-
devcontainer: devcontainer || {},
|
|
324
|
-
copilotSetupSteps: copilotSetupSteps || null,
|
|
310
|
+
claudeCodeSettings: claudeCodeSettings || {},
|
|
325
311
|
};
|
|
326
312
|
}
|
|
@@ -28,7 +28,6 @@ import {
|
|
|
28
28
|
deriveAgentSkills,
|
|
29
29
|
deriveReferenceLevel,
|
|
30
30
|
deriveToolkit,
|
|
31
|
-
buildAgentIndex,
|
|
32
31
|
} from "@forwardimpact/libskill";
|
|
33
32
|
import {
|
|
34
33
|
createSelectWithValue,
|
|
@@ -259,15 +258,6 @@ export async function renderAgentBuilder() {
|
|
|
259
258
|
// Get reference level for derivation
|
|
260
259
|
const level = deriveReferenceLevel(data.levels);
|
|
261
260
|
|
|
262
|
-
// Build agent index for all valid combinations
|
|
263
|
-
const agentIndex = buildAgentIndex({
|
|
264
|
-
disciplines: data.disciplines,
|
|
265
|
-
tracks: data.tracks,
|
|
266
|
-
stages,
|
|
267
|
-
agentDisciplines: agentData.disciplines,
|
|
268
|
-
agentTracks: agentData.tracks,
|
|
269
|
-
});
|
|
270
|
-
|
|
271
261
|
// Build context for generation
|
|
272
262
|
const context = {
|
|
273
263
|
humanDiscipline,
|
|
@@ -279,10 +269,8 @@ export async function renderAgentBuilder() {
|
|
|
279
269
|
skills: data.skills,
|
|
280
270
|
behaviours: data.behaviours,
|
|
281
271
|
agentBehaviours: agentData.behaviours,
|
|
282
|
-
|
|
283
|
-
devcontainer: agentData.devcontainer,
|
|
272
|
+
claudeCodeSettings: agentData.claudeCodeSettings,
|
|
284
273
|
templates,
|
|
285
|
-
agentIndex,
|
|
286
274
|
};
|
|
287
275
|
|
|
288
276
|
// Generate preview based on stage selection
|
|
@@ -316,7 +304,7 @@ export async function renderAgentBuilder() {
|
|
|
316
304
|
p(
|
|
317
305
|
{ className: "page-description" },
|
|
318
306
|
"Generate coding agent teams from discipline × track × stage combinations. " +
|
|
319
|
-
"Export complete agent profiles and skill files for
|
|
307
|
+
"Export complete agent profiles and skill files for Claude Code.",
|
|
320
308
|
),
|
|
321
309
|
),
|
|
322
310
|
|
|
@@ -456,10 +444,8 @@ function createAllStagesPreview(context) {
|
|
|
456
444
|
skills,
|
|
457
445
|
behaviours,
|
|
458
446
|
agentBehaviours,
|
|
459
|
-
|
|
460
|
-
devcontainer,
|
|
447
|
+
claudeCodeSettings,
|
|
461
448
|
templates,
|
|
462
|
-
agentIndex,
|
|
463
449
|
} = context;
|
|
464
450
|
|
|
465
451
|
// Generate all stage agents
|
|
@@ -474,7 +460,6 @@ function createAllStagesPreview(context) {
|
|
|
474
460
|
agentBehaviours,
|
|
475
461
|
agentDiscipline,
|
|
476
462
|
agentTrack,
|
|
477
|
-
stages,
|
|
478
463
|
});
|
|
479
464
|
|
|
480
465
|
const profile = generateStageAgentProfile({
|
|
@@ -488,7 +473,6 @@ function createAllStagesPreview(context) {
|
|
|
488
473
|
agentDiscipline,
|
|
489
474
|
agentTrack,
|
|
490
475
|
stages,
|
|
491
|
-
agentIndex,
|
|
492
476
|
});
|
|
493
477
|
|
|
494
478
|
return { stage, derived, profile };
|
|
@@ -521,8 +505,7 @@ function createAllStagesPreview(context) {
|
|
|
521
505
|
createDownloadAllButton(
|
|
522
506
|
stageAgents,
|
|
523
507
|
skillFiles,
|
|
524
|
-
|
|
525
|
-
devcontainer,
|
|
508
|
+
claudeCodeSettings,
|
|
526
509
|
context,
|
|
527
510
|
),
|
|
528
511
|
|
|
@@ -532,7 +515,7 @@ function createAllStagesPreview(context) {
|
|
|
532
515
|
h2({}, `Agents (${stageAgents.length})`),
|
|
533
516
|
p(
|
|
534
517
|
{ className: "text-muted" },
|
|
535
|
-
"Stage-specific agents with
|
|
518
|
+
"Stage-specific agents with skills, constraints, and stage transitions.",
|
|
536
519
|
),
|
|
537
520
|
div(
|
|
538
521
|
{ className: "agent-cards-grid" },
|
|
@@ -598,11 +581,9 @@ function createSingleStagePreview(context, stage) {
|
|
|
598
581
|
skills,
|
|
599
582
|
behaviours,
|
|
600
583
|
agentBehaviours,
|
|
601
|
-
|
|
602
|
-
devcontainer,
|
|
584
|
+
claudeCodeSettings,
|
|
603
585
|
stages,
|
|
604
586
|
templates,
|
|
605
|
-
agentIndex,
|
|
606
587
|
} = context;
|
|
607
588
|
|
|
608
589
|
const profile = generateStageAgentProfile({
|
|
@@ -616,7 +597,6 @@ function createSingleStagePreview(context, stage) {
|
|
|
616
597
|
agentDiscipline,
|
|
617
598
|
agentTrack,
|
|
618
599
|
stages,
|
|
619
|
-
agentIndex,
|
|
620
600
|
});
|
|
621
601
|
|
|
622
602
|
// Get skills for this stage (using full derived skills)
|
|
@@ -645,8 +625,7 @@ function createSingleStagePreview(context, stage) {
|
|
|
645
625
|
createDownloadSingleButton(
|
|
646
626
|
profile,
|
|
647
627
|
skillFiles,
|
|
648
|
-
|
|
649
|
-
devcontainer,
|
|
628
|
+
claudeCodeSettings,
|
|
650
629
|
templates,
|
|
651
630
|
),
|
|
652
631
|
|
|
@@ -756,16 +735,14 @@ function buildSkillFileCard(skill, templates) {
|
|
|
756
735
|
* Create download all button for all stages
|
|
757
736
|
* @param {Array} stageAgents - Array of {stage, derived, profile}
|
|
758
737
|
* @param {Array} skillFiles - Array of skill file objects
|
|
759
|
-
* @param {Object}
|
|
760
|
-
* @param {Object} devcontainer - Devcontainer config
|
|
738
|
+
* @param {Object} claudeCodeSettings - Claude Code settings
|
|
761
739
|
* @param {Object} context - Context with discipline/track info and templates
|
|
762
740
|
* @returns {HTMLElement}
|
|
763
741
|
*/
|
|
764
742
|
function createDownloadAllButton(
|
|
765
743
|
stageAgents,
|
|
766
744
|
skillFiles,
|
|
767
|
-
|
|
768
|
-
devcontainer,
|
|
745
|
+
claudeCodeSettings,
|
|
769
746
|
context,
|
|
770
747
|
) {
|
|
771
748
|
const { humanDiscipline, humanTrack, templates } = context;
|
|
@@ -783,10 +760,10 @@ function createDownloadAllButton(
|
|
|
783
760
|
const JSZip = await importJSZip();
|
|
784
761
|
const zip = new JSZip();
|
|
785
762
|
|
|
786
|
-
// Add all stage agent profiles
|
|
763
|
+
// Add all stage agent profiles to .claude/agents/
|
|
787
764
|
for (const { profile } of stageAgents) {
|
|
788
765
|
const content = formatAgentProfile(profile, templates.agent);
|
|
789
|
-
zip.file(`.
|
|
766
|
+
zip.file(`.claude/agents/${profile.filename}`, content);
|
|
790
767
|
}
|
|
791
768
|
|
|
792
769
|
// Add skills (SKILL.md + optional install script + optional reference)
|
|
@@ -812,27 +789,11 @@ function createDownloadAllButton(
|
|
|
812
789
|
}
|
|
813
790
|
}
|
|
814
791
|
|
|
815
|
-
// Add
|
|
816
|
-
if (Object.keys(
|
|
817
|
-
zip.file(
|
|
818
|
-
".vscode/settings.json",
|
|
819
|
-
JSON.stringify(vscodeSettings, null, 2) + "\n",
|
|
820
|
-
);
|
|
821
|
-
}
|
|
822
|
-
|
|
823
|
-
// Add devcontainer.json with VS Code settings embedded
|
|
824
|
-
if (devcontainer && Object.keys(devcontainer).length > 0) {
|
|
825
|
-
const devcontainerJson = {
|
|
826
|
-
...devcontainer,
|
|
827
|
-
customizations: {
|
|
828
|
-
vscode: {
|
|
829
|
-
settings: vscodeSettings,
|
|
830
|
-
},
|
|
831
|
-
},
|
|
832
|
-
};
|
|
792
|
+
// Add Claude Code settings
|
|
793
|
+
if (Object.keys(claudeCodeSettings).length > 0) {
|
|
833
794
|
zip.file(
|
|
834
|
-
".
|
|
835
|
-
JSON.stringify(
|
|
795
|
+
".claude/settings.json",
|
|
796
|
+
JSON.stringify(claudeCodeSettings, null, 2) + "\n",
|
|
836
797
|
);
|
|
837
798
|
}
|
|
838
799
|
|
|
@@ -861,16 +822,14 @@ function createDownloadAllButton(
|
|
|
861
822
|
* Create download button for single stage
|
|
862
823
|
* @param {Object} profile - Agent profile
|
|
863
824
|
* @param {Array} skillFiles - Skill files
|
|
864
|
-
* @param {Object}
|
|
865
|
-
* @param {Object} devcontainer - Devcontainer config
|
|
825
|
+
* @param {Object} claudeCodeSettings - Claude Code settings
|
|
866
826
|
* @param {{agent: string, skill: string}} templates - Mustache templates
|
|
867
827
|
* @returns {HTMLElement}
|
|
868
828
|
*/
|
|
869
829
|
function createDownloadSingleButton(
|
|
870
830
|
profile,
|
|
871
831
|
skillFiles,
|
|
872
|
-
|
|
873
|
-
devcontainer,
|
|
832
|
+
claudeCodeSettings,
|
|
874
833
|
templates,
|
|
875
834
|
) {
|
|
876
835
|
const btn = document.createElement("button");
|
|
@@ -885,9 +844,9 @@ function createDownloadSingleButton(
|
|
|
885
844
|
const JSZip = await importJSZip();
|
|
886
845
|
const zip = new JSZip();
|
|
887
846
|
|
|
888
|
-
// Add profile
|
|
847
|
+
// Add profile to .claude/agents/
|
|
889
848
|
const content = formatAgentProfile(profile, templates.agent);
|
|
890
|
-
zip.file(`.
|
|
849
|
+
zip.file(`.claude/agents/${profile.filename}`, content);
|
|
891
850
|
|
|
892
851
|
// Add skills (SKILL.md + optional install script + optional reference)
|
|
893
852
|
for (const skill of skillFiles) {
|
|
@@ -912,27 +871,11 @@ function createDownloadSingleButton(
|
|
|
912
871
|
}
|
|
913
872
|
}
|
|
914
873
|
|
|
915
|
-
// Add
|
|
916
|
-
if (Object.keys(
|
|
917
|
-
zip.file(
|
|
918
|
-
".vscode/settings.json",
|
|
919
|
-
JSON.stringify(vscodeSettings, null, 2) + "\n",
|
|
920
|
-
);
|
|
921
|
-
}
|
|
922
|
-
|
|
923
|
-
// Add devcontainer.json with VS Code settings embedded
|
|
924
|
-
if (devcontainer && Object.keys(devcontainer).length > 0) {
|
|
925
|
-
const devcontainerJson = {
|
|
926
|
-
...devcontainer,
|
|
927
|
-
customizations: {
|
|
928
|
-
vscode: {
|
|
929
|
-
settings: vscodeSettings,
|
|
930
|
-
},
|
|
931
|
-
},
|
|
932
|
-
};
|
|
874
|
+
// Add Claude Code settings
|
|
875
|
+
if (Object.keys(claudeCodeSettings).length > 0) {
|
|
933
876
|
zip.file(
|
|
934
|
-
".
|
|
935
|
-
JSON.stringify(
|
|
877
|
+
".claude/settings.json",
|
|
878
|
+
JSON.stringify(claudeCodeSettings, null, 2) + "\n",
|
|
936
879
|
);
|
|
937
880
|
}
|
|
938
881
|
|
|
@@ -982,7 +925,7 @@ function createHelpSection() {
|
|
|
982
925
|
p(
|
|
983
926
|
{},
|
|
984
927
|
"Agents are generated for each stage: Plan (research), Code (implement), and Review (verify). " +
|
|
985
|
-
"Each stage has specific
|
|
928
|
+
"Each stage has specific skills, constraints, and stage transitions.",
|
|
986
929
|
),
|
|
987
930
|
),
|
|
988
931
|
div(
|
|
@@ -990,8 +933,8 @@ function createHelpSection() {
|
|
|
990
933
|
div({ className: "detail-item-label" }, "Agent Profiles"),
|
|
991
934
|
p(
|
|
992
935
|
{},
|
|
993
|
-
"The .
|
|
994
|
-
"Place them in .
|
|
936
|
+
"The .md files contain the agent's identity, skills, and constraints. " +
|
|
937
|
+
"Place them in .claude/agents/ for Claude Code to discover.",
|
|
995
938
|
),
|
|
996
939
|
),
|
|
997
940
|
div(
|
package/src/pages/landing.js
CHANGED
|
@@ -299,7 +299,7 @@ export function renderLanding() {
|
|
|
299
299
|
p(
|
|
300
300
|
{},
|
|
301
301
|
"Generate coding agent team configurations from discipline × track combinations " +
|
|
302
|
-
"for
|
|
302
|
+
"for Claude Code agents.",
|
|
303
303
|
),
|
|
304
304
|
div(
|
|
305
305
|
{ className: "page-actions", style: "justify-content: center" },
|