@forwardimpact/pathway 0.25.8 → 0.25.10
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 +1 -1
- package/package.json +1 -1
- package/src/commands/agent.js +32 -0
- package/src/commands/update.js +12 -12
- package/src/formatters/agent/dom.js +13 -0
- package/templates/install.template.sh +10 -8
package/bin/fit-pathway.js
CHANGED
|
@@ -104,7 +104,7 @@ GETTING STARTED
|
|
|
104
104
|
init Create ./data/ with example data
|
|
105
105
|
dev [--port=PORT] Run live development server
|
|
106
106
|
build [--output=PATH] [--url=URL] Generate static site + distribution bundle
|
|
107
|
-
update [--url=URL] Update local ~/.fit/pathway/ installation
|
|
107
|
+
update [--url=URL] Update local ~/.fit/data/pathway/ installation
|
|
108
108
|
|
|
109
109
|
────────────────────────────────────────────────────────────────────────────────
|
|
110
110
|
ENTITY COMMANDS
|
package/package.json
CHANGED
package/src/commands/agent.js
CHANGED
|
@@ -38,6 +38,7 @@ import {
|
|
|
38
38
|
deriveToolkit,
|
|
39
39
|
getDisciplineAbbreviation,
|
|
40
40
|
toKebabCase,
|
|
41
|
+
interpolateTeamInstructions,
|
|
41
42
|
} from "@forwardimpact/libskill";
|
|
42
43
|
import { formatAgentProfile } from "../formatters/agent/profile.js";
|
|
43
44
|
import {
|
|
@@ -207,6 +208,21 @@ async function writeProfile(profile, baseDir, template) {
|
|
|
207
208
|
return profilePath;
|
|
208
209
|
}
|
|
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
|
+
|
|
210
226
|
/**
|
|
211
227
|
* Write skill files (SKILL.md, scripts/install.sh, references/REFERENCE.md)
|
|
212
228
|
* @param {Array} skills - Generated skills
|
|
@@ -434,10 +450,18 @@ export async function runAgentCommand({
|
|
|
434
450
|
|
|
435
451
|
// Output to console (default) or write to files (with --output)
|
|
436
452
|
if (!options.output) {
|
|
453
|
+
const teamInstructions = interpolateTeamInstructions(agentTrack, humanDiscipline);
|
|
454
|
+
if (teamInstructions) {
|
|
455
|
+
console.log("# Team Instructions (CLAUDE.md)\n");
|
|
456
|
+
console.log(teamInstructions.trim());
|
|
457
|
+
console.log("\n---\n");
|
|
458
|
+
}
|
|
437
459
|
console.log(formatAgentProfile(profile, agentTemplate));
|
|
438
460
|
return;
|
|
439
461
|
}
|
|
440
462
|
|
|
463
|
+
const teamInstructions = interpolateTeamInstructions(agentTrack, humanDiscipline);
|
|
464
|
+
await writeTeamInstructions(teamInstructions, baseDir);
|
|
441
465
|
await writeProfile(profile, baseDir, agentTemplate);
|
|
442
466
|
await generateClaudeCodeSettings(baseDir, agentData.claudeCodeSettings);
|
|
443
467
|
console.log("");
|
|
@@ -516,6 +540,12 @@ export async function runAgentCommand({
|
|
|
516
540
|
|
|
517
541
|
// Output to console (default) or write to files (with --output)
|
|
518
542
|
if (!options.output) {
|
|
543
|
+
const teamInstructions = interpolateTeamInstructions(agentTrack, humanDiscipline);
|
|
544
|
+
if (teamInstructions) {
|
|
545
|
+
console.log("# Team Instructions (CLAUDE.md)\n");
|
|
546
|
+
console.log(teamInstructions.trim());
|
|
547
|
+
console.log("\n---\n");
|
|
548
|
+
}
|
|
519
549
|
for (const profile of profiles) {
|
|
520
550
|
console.log(formatAgentProfile(profile, agentTemplate));
|
|
521
551
|
console.log("\n---\n");
|
|
@@ -523,6 +553,8 @@ export async function runAgentCommand({
|
|
|
523
553
|
return;
|
|
524
554
|
}
|
|
525
555
|
|
|
556
|
+
const teamInstructions = interpolateTeamInstructions(agentTrack, humanDiscipline);
|
|
557
|
+
await writeTeamInstructions(teamInstructions, baseDir);
|
|
526
558
|
for (const profile of profiles) {
|
|
527
559
|
await writeProfile(profile, baseDir, agentTemplate);
|
|
528
560
|
}
|
package/src/commands/update.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Update Command
|
|
3
3
|
*
|
|
4
4
|
* Re-downloads the distribution bundle from the published site URL
|
|
5
|
-
* and updates the local ~/.fit/pathway/ installation.
|
|
5
|
+
* and updates the local ~/.fit/data/pathway/ installation.
|
|
6
6
|
* Updates the global @forwardimpact/pathway package if the version changed.
|
|
7
7
|
*/
|
|
8
8
|
|
|
@@ -10,9 +10,11 @@ import { cp, mkdir, rm, readFile, writeFile, access } from "fs/promises";
|
|
|
10
10
|
import { join } from "path";
|
|
11
11
|
import { homedir } from "os";
|
|
12
12
|
import { execFileSync } from "child_process";
|
|
13
|
+
import { tmpdir } from "os";
|
|
13
14
|
import { createDataLoader } from "@forwardimpact/map/loader";
|
|
14
15
|
|
|
15
|
-
const
|
|
16
|
+
const BASE_DIR = join(homedir(), ".fit", "data");
|
|
17
|
+
const INSTALL_DIR = join(BASE_DIR, "pathway");
|
|
16
18
|
|
|
17
19
|
/**
|
|
18
20
|
* Run the update command.
|
|
@@ -24,13 +26,11 @@ const INSTALL_DIR = join(homedir(), ".fit", "pathway");
|
|
|
24
26
|
* @param {Object} params.options - Command options
|
|
25
27
|
*/
|
|
26
28
|
export async function runUpdateCommand({ dataDir: _dataDir, options }) {
|
|
27
|
-
const installDataDir = join(INSTALL_DIR, "data");
|
|
28
|
-
|
|
29
29
|
// Verify we have a home-directory installation
|
|
30
30
|
try {
|
|
31
|
-
await access(
|
|
31
|
+
await access(INSTALL_DIR);
|
|
32
32
|
} catch {
|
|
33
|
-
console.error("Error: No local installation found at ~/.fit/pathway/");
|
|
33
|
+
console.error("Error: No local installation found at ~/.fit/data/pathway/");
|
|
34
34
|
console.error(
|
|
35
35
|
"Install first using the install.sh script from your organization's pathway site.",
|
|
36
36
|
);
|
|
@@ -39,12 +39,12 @@ export async function runUpdateCommand({ dataDir: _dataDir, options }) {
|
|
|
39
39
|
|
|
40
40
|
// Load framework config to get siteUrl
|
|
41
41
|
const loader = createDataLoader();
|
|
42
|
-
const framework = await loader.loadFrameworkConfig(
|
|
42
|
+
const framework = await loader.loadFrameworkConfig(INSTALL_DIR);
|
|
43
43
|
const siteUrl = options.url || framework.distribution?.siteUrl;
|
|
44
44
|
|
|
45
45
|
if (!siteUrl) {
|
|
46
46
|
console.error(
|
|
47
|
-
"Error: No siteUrl found in ~/.fit/pathway/
|
|
47
|
+
"Error: No siteUrl found in ~/.fit/data/pathway/framework.yaml (distribution.siteUrl)",
|
|
48
48
|
);
|
|
49
49
|
console.error("Provide one with --url=<URL> or add it to framework.yaml.");
|
|
50
50
|
process.exit(1);
|
|
@@ -56,7 +56,7 @@ export async function runUpdateCommand({ dataDir: _dataDir, options }) {
|
|
|
56
56
|
console.log(`\n🔄 Updating from ${baseUrl}...\n`);
|
|
57
57
|
|
|
58
58
|
// 1. Download bundle to temp location
|
|
59
|
-
const tmpDir = join(
|
|
59
|
+
const tmpDir = join(tmpdir(), "fit-pathway-update");
|
|
60
60
|
await mkdir(tmpDir, { recursive: true });
|
|
61
61
|
|
|
62
62
|
const tmpBundle = join(tmpDir, bundleName);
|
|
@@ -86,7 +86,7 @@ export async function runUpdateCommand({ dataDir: _dataDir, options }) {
|
|
|
86
86
|
|
|
87
87
|
// 3. Compare versions from bundle's package.json (version manifest)
|
|
88
88
|
const newPkgPath = join(extractDir, "package.json");
|
|
89
|
-
const oldPkgPath = join(
|
|
89
|
+
const oldPkgPath = join(BASE_DIR, "package.json");
|
|
90
90
|
const newPkg = JSON.parse(await readFile(newPkgPath, "utf8"));
|
|
91
91
|
let oldPkg;
|
|
92
92
|
try {
|
|
@@ -102,8 +102,8 @@ export async function runUpdateCommand({ dataDir: _dataDir, options }) {
|
|
|
102
102
|
|
|
103
103
|
// 4. Replace data
|
|
104
104
|
console.log(" Updating data files...");
|
|
105
|
-
await rm(
|
|
106
|
-
await cp(join(extractDir, "data"),
|
|
105
|
+
await rm(INSTALL_DIR, { recursive: true });
|
|
106
|
+
await cp(join(extractDir, "data"), INSTALL_DIR, { recursive: true });
|
|
107
107
|
console.log(" ✓ Data updated");
|
|
108
108
|
|
|
109
109
|
// 5. Update version manifest
|
|
@@ -18,6 +18,7 @@ import { getStageEmoji } from "../stage/shared.js";
|
|
|
18
18
|
* @param {Array} deployment.skills - Agent skills
|
|
19
19
|
* @param {Array} [deployment.roleAgents] - Role variant agents (plan, review)
|
|
20
20
|
* @param {Object} [deployment.claudeCodeSettings] - Claude Code settings to include in download
|
|
21
|
+
* @param {string|null} [deployment.teamInstructions] - Team instructions content for CLAUDE.md
|
|
21
22
|
* @returns {HTMLElement}
|
|
22
23
|
*/
|
|
23
24
|
export function agentDeploymentToDOM({
|
|
@@ -25,6 +26,7 @@ export function agentDeploymentToDOM({
|
|
|
25
26
|
skills,
|
|
26
27
|
roleAgents = [],
|
|
27
28
|
claudeCodeSettings = {},
|
|
29
|
+
teamInstructions = null,
|
|
28
30
|
}) {
|
|
29
31
|
const profileContent = formatAgentProfile(profile);
|
|
30
32
|
const agentName = profile.frontmatter.name;
|
|
@@ -39,6 +41,7 @@ export function agentDeploymentToDOM({
|
|
|
39
41
|
roleAgents,
|
|
40
42
|
claudeCodeSettings,
|
|
41
43
|
agentName,
|
|
44
|
+
teamInstructions,
|
|
42
45
|
),
|
|
43
46
|
|
|
44
47
|
// Profile section
|
|
@@ -92,6 +95,7 @@ export function agentDeploymentToDOM({
|
|
|
92
95
|
* @param {Array} roleAgents - Role variant agents
|
|
93
96
|
* @param {Object} claudeCodeSettings - Claude Code settings to include
|
|
94
97
|
* @param {string} agentName - Agent name for zip filename
|
|
98
|
+
* @param {string|null} teamInstructions - Team instructions content for CLAUDE.md
|
|
95
99
|
* @returns {HTMLElement}
|
|
96
100
|
*/
|
|
97
101
|
function createDownloadButton(
|
|
@@ -100,6 +104,7 @@ function createDownloadButton(
|
|
|
100
104
|
roleAgents,
|
|
101
105
|
claudeCodeSettings,
|
|
102
106
|
agentName,
|
|
107
|
+
teamInstructions,
|
|
103
108
|
) {
|
|
104
109
|
const btn = button(
|
|
105
110
|
{ className: "btn btn-primary download-all-btn" },
|
|
@@ -117,6 +122,7 @@ function createDownloadButton(
|
|
|
117
122
|
roleAgents,
|
|
118
123
|
claudeCodeSettings,
|
|
119
124
|
agentName,
|
|
125
|
+
teamInstructions,
|
|
120
126
|
);
|
|
121
127
|
} finally {
|
|
122
128
|
btn.disabled = false;
|
|
@@ -169,6 +175,7 @@ function createRoleAgentCard(agent) {
|
|
|
169
175
|
* @param {Array} roleAgents - Role variant agents
|
|
170
176
|
* @param {Object} claudeCodeSettings - Claude Code settings to include
|
|
171
177
|
* @param {string} agentName - Agent name for zip filename
|
|
178
|
+
* @param {string|null} teamInstructions - Team instructions content for CLAUDE.md
|
|
172
179
|
*/
|
|
173
180
|
async function downloadAllAsZip(
|
|
174
181
|
profile,
|
|
@@ -176,6 +183,7 @@ async function downloadAllAsZip(
|
|
|
176
183
|
roleAgents,
|
|
177
184
|
claudeCodeSettings,
|
|
178
185
|
agentName,
|
|
186
|
+
teamInstructions,
|
|
179
187
|
) {
|
|
180
188
|
// Dynamically import JSZip
|
|
181
189
|
const JSZip = await importJSZip();
|
|
@@ -185,6 +193,11 @@ async function downloadAllAsZip(
|
|
|
185
193
|
const profileContent = formatAgentProfile(profile);
|
|
186
194
|
zip.file(`.claude/agents/${profile.filename}`, profileContent);
|
|
187
195
|
|
|
196
|
+
// Add team instructions to .claude/CLAUDE.md
|
|
197
|
+
if (teamInstructions) {
|
|
198
|
+
zip.file(".claude/CLAUDE.md", teamInstructions.trim() + "\n");
|
|
199
|
+
}
|
|
200
|
+
|
|
188
201
|
// Add role agent profiles to .claude/agents/ folder
|
|
189
202
|
for (const roleAgent of roleAgents) {
|
|
190
203
|
const roleContent = formatAgentProfile(roleAgent);
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
# Generated by @forwardimpact/pathway v{{{version}}}
|
|
4
4
|
#
|
|
5
5
|
# Installs fit-pathway globally via bun and downloads organization data
|
|
6
|
-
# to ~/.fit/pathway
|
|
6
|
+
# to ~/.fit/data/pathway/.
|
|
7
7
|
#
|
|
8
8
|
# Usage:
|
|
9
9
|
# curl -fsSL {{{siteUrl}}}/install.sh | bash
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
set -euo pipefail
|
|
12
12
|
|
|
13
13
|
SITE_URL="{{{siteUrl}}}"
|
|
14
|
-
INSTALL_DIR="${HOME}/.fit/pathway"
|
|
14
|
+
INSTALL_DIR="${HOME}/.fit/data/pathway"
|
|
15
15
|
|
|
16
16
|
command -v bun >/dev/null 2>&1 || { echo "Error: Bun 1.2+ is required. https://bun.sh"; exit 1; }
|
|
17
17
|
|
|
@@ -19,14 +19,16 @@ command -v bun >/dev/null 2>&1 || { echo "Error: Bun 1.2+ is required. https://b
|
|
|
19
19
|
echo "Installing @forwardimpact/pathway globally..."
|
|
20
20
|
bun install -g @forwardimpact/pathway@{{{version}}}
|
|
21
21
|
|
|
22
|
-
# Download organization data to ~/.fit/pathway/
|
|
23
|
-
echo "Downloading organization data to ${INSTALL_DIR}
|
|
22
|
+
# Download organization data to ~/.fit/data/pathway/
|
|
23
|
+
echo "Downloading organization data to ${INSTALL_DIR}..."
|
|
24
24
|
mkdir -p "${INSTALL_DIR}"
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
trap 'rm -
|
|
28
|
-
curl -fsSL "${SITE_URL}/bundle.tar.gz" -o "$
|
|
29
|
-
tar -xzf "$
|
|
26
|
+
TMPDIR_INSTALL=$(mktemp -d)
|
|
27
|
+
trap 'rm -rf "$TMPDIR_INSTALL"' EXIT
|
|
28
|
+
curl -fsSL "${SITE_URL}/bundle.tar.gz" -o "${TMPDIR_INSTALL}/bundle.tar.gz"
|
|
29
|
+
tar -xzf "${TMPDIR_INSTALL}/bundle.tar.gz" -C "${TMPDIR_INSTALL}" --strip-components=1
|
|
30
|
+
cp -R "${TMPDIR_INSTALL}/data/." "${INSTALL_DIR}/"
|
|
31
|
+
cp "${TMPDIR_INSTALL}/package.json" "${HOME}/.fit/data/package.json" 2>/dev/null || true
|
|
30
32
|
|
|
31
33
|
echo ""
|
|
32
34
|
echo "Done. Usage:"
|