@forwardimpact/pathway 0.9.0 → 0.11.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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forwardimpact/pathway",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Career progression web app and CLI for exploring roles and generating agents",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@forwardimpact/schema": "^0.4.0",
|
|
44
|
-
"@forwardimpact/model": "^0.
|
|
44
|
+
"@forwardimpact/model": "^0.5.0",
|
|
45
45
|
"mustache": "^4.2.0",
|
|
46
46
|
"simple-icons": "^16.7.0",
|
|
47
47
|
"yaml": "^2.3.4"
|
|
@@ -11,6 +11,10 @@
|
|
|
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
18
|
|
|
15
19
|
/**
|
|
16
20
|
* @typedef {Object} WorkingStyleEntry
|
|
@@ -18,6 +22,13 @@ import { trimValue, trimRequired, trimFields } from "../shared.js";
|
|
|
18
22
|
* @property {string} content - Working style content (markdown)
|
|
19
23
|
*/
|
|
20
24
|
|
|
25
|
+
/**
|
|
26
|
+
* @typedef {Object} BeforeHandoffEntry
|
|
27
|
+
* @property {{id: string, name: string}} skill - Skill info
|
|
28
|
+
* @property {{id: string, name: string, emojiIcon: string}} capability - Capability info
|
|
29
|
+
* @property {string[]} items - Checklist items
|
|
30
|
+
*/
|
|
31
|
+
|
|
21
32
|
/**
|
|
22
33
|
* Prepare agent profile data for template rendering
|
|
23
34
|
* Normalizes string values by trimming trailing newlines for consistent template output.
|
|
@@ -35,15 +46,21 @@ import { trimValue, trimRequired, trimFields } from "../shared.js";
|
|
|
35
46
|
* @param {Array<{name: string, dirname: string, useWhen: string}>} params.bodyData.skillIndex - Skill index entries
|
|
36
47
|
* @param {string} params.bodyData.roleContext - Role context text
|
|
37
48
|
* @param {WorkingStyleEntry[]} params.bodyData.workingStyles - Working style entries
|
|
38
|
-
* @param {
|
|
49
|
+
* @param {BeforeHandoffEntry[]} [params.bodyData.beforeHandoff] - Before handoff checklist entries
|
|
39
50
|
* @param {string[]} params.bodyData.constraints - List of constraints
|
|
40
51
|
* @param {Array<{id: string, name: string, description: string}>} [params.bodyData.agentIndex] - List of all available agents
|
|
41
52
|
* @param {boolean} [params.bodyData.hasAgentIndex] - Whether agent index is available
|
|
42
53
|
* @returns {Object} Data object ready for Mustache template
|
|
43
54
|
*/
|
|
44
55
|
function prepareAgentProfileData({ frontmatter, bodyData }) {
|
|
45
|
-
//
|
|
46
|
-
const
|
|
56
|
+
// Preprocess handoffs - flatten prompt field for front matter compatibility
|
|
57
|
+
const preprocessedHandoffs = preprocessArrayFrontmatter(
|
|
58
|
+
frontmatter.handoffs,
|
|
59
|
+
["prompt"],
|
|
60
|
+
);
|
|
61
|
+
// Then trim as before
|
|
62
|
+
const handoffs = trimFields(preprocessedHandoffs, { prompt: "required" });
|
|
63
|
+
|
|
47
64
|
const constraints = (bodyData.constraints || []).map((c) => trimRequired(c));
|
|
48
65
|
const skillIndex = trimFields(bodyData.skillIndex, {
|
|
49
66
|
name: "required",
|
|
@@ -60,10 +77,17 @@ function prepareAgentProfileData({ frontmatter, bodyData }) {
|
|
|
60
77
|
content: "required",
|
|
61
78
|
});
|
|
62
79
|
|
|
80
|
+
// Process beforeHandoff: trim items in each entry
|
|
81
|
+
const beforeHandoff = (bodyData.beforeHandoff || []).map((entry) => ({
|
|
82
|
+
skill: entry.skill,
|
|
83
|
+
capability: entry.capability,
|
|
84
|
+
items: (entry.items || []).map((item) => trimRequired(item)),
|
|
85
|
+
}));
|
|
86
|
+
|
|
63
87
|
return {
|
|
64
|
-
// Frontmatter
|
|
88
|
+
// Frontmatter - flatten description for single-line front matter
|
|
65
89
|
name: frontmatter.name,
|
|
66
|
-
description:
|
|
90
|
+
description: flattenToLine(frontmatter.description),
|
|
67
91
|
infer: frontmatter.infer,
|
|
68
92
|
handoffs,
|
|
69
93
|
|
|
@@ -77,7 +101,8 @@ function prepareAgentProfileData({ frontmatter, bodyData }) {
|
|
|
77
101
|
roleContext: trimValue(bodyData.roleContext),
|
|
78
102
|
workingStyles,
|
|
79
103
|
hasWorkingStyles: workingStyles.length > 0,
|
|
80
|
-
beforeHandoff
|
|
104
|
+
beforeHandoff,
|
|
105
|
+
hasBeforeHandoff: beforeHandoff.length > 0,
|
|
81
106
|
constraints,
|
|
82
107
|
hasConstraints: constraints.length > 0,
|
|
83
108
|
agentIndex,
|
|
@@ -102,7 +127,7 @@ function prepareAgentProfileData({ frontmatter, bodyData }) {
|
|
|
102
127
|
* @param {Array<{name: string, dirname: string, useWhen: string}>} profile.bodyData.skillIndex - Skill index entries
|
|
103
128
|
* @param {string} profile.bodyData.roleContext - Role context text
|
|
104
129
|
* @param {WorkingStyleEntry[]} profile.bodyData.workingStyles - Working style entries
|
|
105
|
-
* @param {
|
|
130
|
+
* @param {BeforeHandoffEntry[]} [profile.bodyData.beforeHandoff] - Before handoff checklist entries (optional)
|
|
106
131
|
* @param {string[]} profile.bodyData.constraints - List of constraints
|
|
107
132
|
* @param {string} template - Mustache template string
|
|
108
133
|
* @returns {string} Complete .agent.md file content
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
import Mustache from "mustache";
|
|
12
12
|
|
|
13
13
|
import { trimValue, splitLines, trimFields } from "../shared.js";
|
|
14
|
+
import { flattenToLine } from "../template-preprocess.js";
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Prepare agent skill data for template rendering
|
|
@@ -40,17 +41,25 @@ function prepareAgentSkillData({
|
|
|
40
41
|
ready: "array",
|
|
41
42
|
});
|
|
42
43
|
|
|
44
|
+
// Flatten multi-line strings to single line for front matter compatibility
|
|
45
|
+
const description = flattenToLine(frontmatter.description);
|
|
46
|
+
const useWhen = flattenToLine(frontmatter.useWhen);
|
|
47
|
+
|
|
48
|
+
// Keep line arrays for body rendering
|
|
43
49
|
const descriptionLines = splitLines(frontmatter.description);
|
|
44
|
-
|
|
50
|
+
|
|
45
51
|
const trimmedReference = trimValue(reference) || "";
|
|
46
52
|
const tools = toolReferences || [];
|
|
47
53
|
|
|
48
54
|
return {
|
|
49
55
|
name: frontmatter.name,
|
|
56
|
+
// Single-line versions for front matter
|
|
57
|
+
description,
|
|
58
|
+
hasDescription: !!description,
|
|
59
|
+
useWhen,
|
|
60
|
+
hasUseWhen: !!useWhen,
|
|
61
|
+
// Line arrays for body content
|
|
50
62
|
descriptionLines,
|
|
51
|
-
hasDescription: descriptionLines.length > 0,
|
|
52
|
-
useWhenLines,
|
|
53
|
-
hasUseWhen: useWhenLines.length > 0,
|
|
54
63
|
title,
|
|
55
64
|
stages: processedStages,
|
|
56
65
|
hasStages: processedStages.length > 0,
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template Preprocessing Utilities
|
|
3
|
+
*
|
|
4
|
+
* Functions to prepare template data for front matter compatibility.
|
|
5
|
+
* Ensures all front matter values are single-line strings for maximum
|
|
6
|
+
* compatibility with coding agents that have limited YAML parsing.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Flatten a multi-line string into a single line
|
|
11
|
+
* Replaces newlines with spaces and collapses multiple spaces.
|
|
12
|
+
* @param {string|null|undefined} value - Value to flatten
|
|
13
|
+
* @returns {string} Single-line string (empty string if no value)
|
|
14
|
+
*/
|
|
15
|
+
export function flattenToLine(value) {
|
|
16
|
+
if (value == null) return "";
|
|
17
|
+
return value
|
|
18
|
+
.replace(/\s*\n\s*/g, " ") // Replace newlines (with surrounding whitespace) with single space
|
|
19
|
+
.replace(/\s+/g, " ") // Collapse multiple spaces
|
|
20
|
+
.trim();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Join an array of strings into a single line
|
|
25
|
+
* @param {string[]|null|undefined} lines - Array of lines to join
|
|
26
|
+
* @param {string} separator - Separator between lines (default: single space)
|
|
27
|
+
* @returns {string} Single-line string
|
|
28
|
+
*/
|
|
29
|
+
export function joinLines(lines, separator = " ") {
|
|
30
|
+
if (!lines || !Array.isArray(lines)) return "";
|
|
31
|
+
return lines.map((line) => line.trim()).join(separator);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Preprocess an object's string fields for front matter
|
|
36
|
+
* Flattens specified fields to single-line strings.
|
|
37
|
+
* @param {Object} obj - Object to preprocess
|
|
38
|
+
* @param {string[]} fields - Field names to flatten
|
|
39
|
+
* @returns {Object} New object with flattened fields
|
|
40
|
+
*/
|
|
41
|
+
export function preprocessFrontmatter(obj, fields) {
|
|
42
|
+
const result = { ...obj };
|
|
43
|
+
for (const field of fields) {
|
|
44
|
+
if (result[field] != null) {
|
|
45
|
+
result[field] = flattenToLine(result[field]);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Preprocess an array of objects, flattening specified fields in each
|
|
53
|
+
* @param {Array<Object>|null|undefined} array - Array to preprocess
|
|
54
|
+
* @param {string[]} fields - Field names to flatten in each object
|
|
55
|
+
* @returns {Array<Object>} Array with preprocessed objects
|
|
56
|
+
*/
|
|
57
|
+
export function preprocessArrayFrontmatter(array, fields) {
|
|
58
|
+
if (!array) return [];
|
|
59
|
+
return array.map((item) => preprocessFrontmatter(item, fields));
|
|
60
|
+
}
|
|
@@ -88,17 +88,23 @@ and (3) the compromised approach with acknowledged limitations.
|
|
|
88
88
|
| `{{id}}` | {{{name}}} | {{{description}}} |
|
|
89
89
|
{{/agentIndex}}
|
|
90
90
|
{{/hasAgentIndex}}
|
|
91
|
-
{{#
|
|
91
|
+
{{#hasBeforeHandoff}}
|
|
92
92
|
|
|
93
93
|
## Before Handoff
|
|
94
94
|
|
|
95
95
|
Before offering a handoff, verify and summarize completion of these items:
|
|
96
96
|
|
|
97
|
-
{{
|
|
97
|
+
{{#beforeHandoff}}
|
|
98
|
+
### {{{capability.emojiIcon}}} {{{skill.name}}}
|
|
99
|
+
|
|
100
|
+
{{#items}}
|
|
101
|
+
- [ ] {{{.}}}
|
|
102
|
+
{{/items}}
|
|
98
103
|
|
|
104
|
+
{{/beforeHandoff}}
|
|
99
105
|
When verified, summarize what was accomplished then offer the handoff. If items
|
|
100
106
|
are incomplete, explain what remains.
|
|
101
|
-
{{/
|
|
107
|
+
{{/hasBeforeHandoff}}
|
|
102
108
|
|
|
103
109
|
## Return Format
|
|
104
110
|
|
|
@@ -1,20 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: {{name}}
|
|
3
|
-
description:
|
|
4
|
-
{{#descriptionLines}}
|
|
5
|
-
{{{.}}}
|
|
6
|
-
{{/descriptionLines}}
|
|
7
|
-
{{#hasUseWhen}}
|
|
8
|
-
**Use When:** {{#useWhenLines}}{{{.}}}{{/useWhenLines}}
|
|
9
|
-
{{/hasUseWhen}}
|
|
3
|
+
description: {{{description}}}{{#hasUseWhen}} Use When: {{{useWhen}}}{{/hasUseWhen}}
|
|
10
4
|
---
|
|
11
5
|
|
|
12
6
|
# {{{title}}}
|
|
13
|
-
{{#hasUseWhen}}
|
|
14
7
|
|
|
15
|
-
|
|
16
|
-
{{
|
|
17
|
-
{{/
|
|
8
|
+
{{#descriptionLines}}
|
|
9
|
+
{{{.}}}
|
|
10
|
+
{{/descriptionLines}}
|
|
18
11
|
{{#hasStages}}
|
|
19
12
|
|
|
20
13
|
## Stage Guidance
|