bmad-studio 0.2.0 → 1.0.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/README.md +6 -0
- package/package.json +12 -3
- package/packages/client/dist/assets/index-CWL4J-eZ.css +1 -0
- package/packages/client/dist/assets/index-DBqsFqD5.js +535 -0
- package/packages/client/dist/index.html +2 -2
- package/packages/server/dist/app.d.ts +1 -0
- package/packages/server/dist/app.d.ts.map +1 -1
- package/packages/server/dist/app.js +9 -0
- package/packages/server/dist/app.js.map +1 -1
- package/packages/server/dist/core/ide-skill-generator.d.ts +58 -0
- package/packages/server/dist/core/ide-skill-generator.d.ts.map +1 -0
- package/packages/server/dist/core/ide-skill-generator.js +270 -0
- package/packages/server/dist/core/ide-skill-generator.js.map +1 -0
- package/packages/server/dist/core/ide-skill-generator.test.d.ts +2 -0
- package/packages/server/dist/core/ide-skill-generator.test.d.ts.map +1 -0
- package/packages/server/dist/core/ide-skill-generator.test.js +257 -0
- package/packages/server/dist/core/ide-skill-generator.test.js.map +1 -0
- package/packages/server/dist/core/module-installer.d.ts +165 -0
- package/packages/server/dist/core/module-installer.d.ts.map +1 -0
- package/packages/server/dist/core/module-installer.js +445 -0
- package/packages/server/dist/core/module-installer.js.map +1 -0
- package/packages/server/dist/core/module-installer.test.d.ts +2 -0
- package/packages/server/dist/core/module-installer.test.d.ts.map +1 -0
- package/packages/server/dist/core/module-installer.test.js +509 -0
- package/packages/server/dist/core/module-installer.test.js.map +1 -0
- package/packages/server/dist/core/module-registry.d.ts +5 -0
- package/packages/server/dist/core/module-registry.d.ts.map +1 -0
- package/packages/server/dist/core/module-registry.js +109 -0
- package/packages/server/dist/core/module-registry.js.map +1 -0
- package/packages/server/dist/core/module-registry.test.d.ts +2 -0
- package/packages/server/dist/core/module-registry.test.d.ts.map +1 -0
- package/packages/server/dist/core/module-registry.test.js +280 -0
- package/packages/server/dist/core/module-registry.test.js.map +1 -0
- package/packages/server/dist/core/write-service.d.ts +20 -0
- package/packages/server/dist/core/write-service.d.ts.map +1 -1
- package/packages/server/dist/core/write-service.js +113 -1
- package/packages/server/dist/core/write-service.js.map +1 -1
- package/packages/server/dist/core/write-service.test.js +93 -6
- package/packages/server/dist/core/write-service.test.js.map +1 -1
- package/packages/server/dist/index.js +46 -1
- package/packages/server/dist/index.js.map +1 -1
- package/packages/server/dist/parsers/module-yaml-parser.d.ts +16 -0
- package/packages/server/dist/parsers/module-yaml-parser.d.ts.map +1 -0
- package/packages/server/dist/parsers/module-yaml-parser.js +62 -0
- package/packages/server/dist/parsers/module-yaml-parser.js.map +1 -0
- package/packages/server/dist/parsers/module-yaml-parser.test.d.ts +2 -0
- package/packages/server/dist/parsers/module-yaml-parser.test.d.ts.map +1 -0
- package/packages/server/dist/parsers/module-yaml-parser.test.js +156 -0
- package/packages/server/dist/parsers/module-yaml-parser.test.js.map +1 -0
- package/packages/server/dist/parsers/skill-parser.d.ts.map +1 -1
- package/packages/server/dist/parsers/skill-parser.js +41 -4
- package/packages/server/dist/parsers/skill-parser.js.map +1 -1
- package/packages/server/dist/parsers/skill-parser.test.js +4 -3
- package/packages/server/dist/parsers/skill-parser.test.js.map +1 -1
- package/packages/server/dist/plugins/agents-plugin.d.ts.map +1 -1
- package/packages/server/dist/plugins/agents-plugin.js +9 -1
- package/packages/server/dist/plugins/agents-plugin.js.map +1 -1
- package/packages/server/dist/plugins/modules-plugin.d.ts.map +1 -1
- package/packages/server/dist/plugins/modules-plugin.js +882 -100
- package/packages/server/dist/plugins/modules-plugin.js.map +1 -1
- package/packages/server/dist/plugins/modules-plugin.test.js +1894 -3
- package/packages/server/dist/plugins/modules-plugin.test.js.map +1 -1
- package/packages/server/dist/plugins/overview-plugin.js +1 -1
- package/packages/server/dist/plugins/overview-plugin.js.map +1 -1
- package/packages/server/dist/plugins/settings-plugin.d.ts.map +1 -1
- package/packages/server/dist/plugins/settings-plugin.js +25 -1
- package/packages/server/dist/plugins/settings-plugin.js.map +1 -1
- package/packages/server/dist/plugins/settings-plugin.test.js +72 -0
- package/packages/server/dist/plugins/settings-plugin.test.js.map +1 -1
- package/packages/server/dist/plugins/teams-plugin.d.ts.map +1 -1
- package/packages/server/dist/plugins/teams-plugin.js +6 -6
- package/packages/server/dist/plugins/teams-plugin.js.map +1 -1
- package/packages/server/dist/plugins/teams-plugin.test.js +43 -0
- package/packages/server/dist/plugins/teams-plugin.test.js.map +1 -1
- package/packages/server/dist/plugins/workflows-plugin.d.ts.map +1 -1
- package/packages/server/dist/plugins/workflows-plugin.js +14 -6
- package/packages/server/dist/plugins/workflows-plugin.js.map +1 -1
- package/packages/shared/src/config.ts +26 -0
- package/packages/shared/src/index.ts +12 -0
- package/packages/shared/src/modules.ts +42 -0
- package/packages/shared/src/registry.ts +26 -0
- package/packages/shared/src/types.test.ts +37 -1
- package/packages/client/dist/assets/index-5nXyrx_3.css +0 -1
- package/packages/client/dist/assets/index-DxN3uabX.js +0 -521
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import yaml from 'js-yaml';
|
|
6
|
+
import { writeFile, isLikelyText } from './write-service.js';
|
|
7
|
+
// TEXT_FILE_EXTENSIONS and isLikelyText moved to write-service.ts in Story 15.7
|
|
8
|
+
// (so the new deleteFile/deleteDirectory primitives can share them without an
|
|
9
|
+
// import cycle). Re-exported here for any callers that imported from this file.
|
|
10
|
+
export { TEXT_FILE_EXTENSIONS, isLikelyText } from './write-service.js';
|
|
11
|
+
/**
|
|
12
|
+
* Walk a source directory and copy every file into a destination.
|
|
13
|
+
*
|
|
14
|
+
* Text files (per TEXT_FILE_EXTENSIONS) are routed through WriteService so snapshots are written.
|
|
15
|
+
* Binary files are copied via fs.copyFileSync — no snapshot, no corruption (see TD-16).
|
|
16
|
+
*
|
|
17
|
+
* Replaces the legacy fs.copyFileSync-based copyDirRecursive helper that lived in modules-plugin.ts.
|
|
18
|
+
*/
|
|
19
|
+
export function copyDirThroughWriteService(src, dest, studioDir, fileStore) {
|
|
20
|
+
if (!fs.existsSync(src))
|
|
21
|
+
return { ok: true, textCount: 0, binaryCount: 0 };
|
|
22
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
23
|
+
let textCount = 0;
|
|
24
|
+
let binaryCount = 0;
|
|
25
|
+
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
26
|
+
const srcPath = path.join(src, entry.name);
|
|
27
|
+
const destPath = path.join(dest, entry.name);
|
|
28
|
+
if (entry.isDirectory()) {
|
|
29
|
+
const sub = copyDirThroughWriteService(srcPath, destPath, studioDir, fileStore);
|
|
30
|
+
if (!sub.ok)
|
|
31
|
+
return sub;
|
|
32
|
+
textCount += sub.textCount;
|
|
33
|
+
binaryCount += sub.binaryCount;
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (isLikelyText(srcPath)) {
|
|
37
|
+
// Text path — read as utf-8 string, write via WriteService for snapshot + atomicity.
|
|
38
|
+
const content = fs.readFileSync(srcPath, 'utf-8');
|
|
39
|
+
fileStore.markPendingWrite(destPath);
|
|
40
|
+
const result = writeFile(destPath, content, studioDir);
|
|
41
|
+
fileStore.clearPendingWrite(destPath);
|
|
42
|
+
if (!result.ok)
|
|
43
|
+
return { ok: false, error: result.error };
|
|
44
|
+
textCount++;
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
// Binary path — straight byte copy. Never decode. Never snapshot. (TD-16)
|
|
48
|
+
try {
|
|
49
|
+
fs.copyFileSync(srcPath, destPath);
|
|
50
|
+
binaryCount++;
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
return {
|
|
54
|
+
ok: false,
|
|
55
|
+
error: `Binary copy failed for ${srcPath}: ${err instanceof Error ? err.message : String(err)}`,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return { ok: true, textCount, binaryCount };
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Read manifest.yaml; null-safe for missing files.
|
|
64
|
+
*/
|
|
65
|
+
export function readManifestSafe(manifestPath) {
|
|
66
|
+
if (!fs.existsSync(manifestPath))
|
|
67
|
+
return null;
|
|
68
|
+
const content = fs.readFileSync(manifestPath, 'utf-8');
|
|
69
|
+
return yaml.load(content);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Write manifest.yaml through WriteService so changes are snapshot.
|
|
73
|
+
*/
|
|
74
|
+
export function writeManifestThroughWriteService(manifestPath, manifest, studioDir, fileStore) {
|
|
75
|
+
const yamlText = yaml.dump(manifest, { lineWidth: -1 });
|
|
76
|
+
fileStore.markPendingWrite(manifestPath);
|
|
77
|
+
const result = writeFile(manifestPath, yamlText, studioDir);
|
|
78
|
+
fileStore.clearPendingWrite(manifestPath);
|
|
79
|
+
return result.ok ? { ok: true } : { ok: false, error: result.error };
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Verify a local path looks like a module — has a module.yaml OR contains at least
|
|
83
|
+
* one of the standard entity directories.
|
|
84
|
+
*/
|
|
85
|
+
export function isPlausibleModuleDir(dir) {
|
|
86
|
+
if (!fs.existsSync(dir))
|
|
87
|
+
return false;
|
|
88
|
+
if (fs.existsSync(path.join(dir, 'module.yaml')))
|
|
89
|
+
return true;
|
|
90
|
+
return ['agents', 'skills', 'workflows', 'tasks'].some((sub) => fs.existsSync(path.join(dir, sub)));
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Lenient parser for GitHub source strings. Accepts any of:
|
|
94
|
+
* owner/repo
|
|
95
|
+
* owner/repo/subpath
|
|
96
|
+
* owner/repo/nested/subpath
|
|
97
|
+
* owner/repo@branch
|
|
98
|
+
* owner/repo/subpath@branch
|
|
99
|
+
* https://github.com/owner/repo
|
|
100
|
+
* https://github.com/owner/repo/tree/branch
|
|
101
|
+
* https://github.com/owner/repo/tree/branch/subpath
|
|
102
|
+
*
|
|
103
|
+
* Throws plain Error on invalid input — the install handler is responsible for
|
|
104
|
+
* catching and converting to ValidationError.
|
|
105
|
+
*/
|
|
106
|
+
export function parseGithubSource(input) {
|
|
107
|
+
// Strip protocol/host if a full URL was pasted
|
|
108
|
+
let s = input.trim();
|
|
109
|
+
const urlMatch = s.match(/^https?:\/\/github\.com\/(.+)$/i);
|
|
110
|
+
if (urlMatch)
|
|
111
|
+
s = urlMatch[1];
|
|
112
|
+
// Strip trailing slashes/whitespace
|
|
113
|
+
s = s.replace(/\/+$/, '');
|
|
114
|
+
// Handle the /tree/{branch}/subpath form (URL or shorthand)
|
|
115
|
+
const treeMatch = s.match(/^([^/]+)\/([^/]+)\/tree\/([^/]+)(?:\/(.+))?$/);
|
|
116
|
+
if (treeMatch) {
|
|
117
|
+
return {
|
|
118
|
+
owner: treeMatch[1],
|
|
119
|
+
repo: treeMatch[2],
|
|
120
|
+
branch: treeMatch[3],
|
|
121
|
+
subpath: treeMatch[4] ?? null,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
// Handle owner/repo[/subpath][@branch]
|
|
125
|
+
let branch = null;
|
|
126
|
+
const atIdx = s.lastIndexOf('@');
|
|
127
|
+
if (atIdx > 0) {
|
|
128
|
+
branch = s.slice(atIdx + 1);
|
|
129
|
+
s = s.slice(0, atIdx);
|
|
130
|
+
}
|
|
131
|
+
const parts = s.split('/').filter(Boolean);
|
|
132
|
+
if (parts.length < 2) {
|
|
133
|
+
throw new Error(`Invalid GitHub source "${input}" — expected owner/repo[/subpath][@branch]`);
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
owner: parts[0],
|
|
137
|
+
repo: parts[1],
|
|
138
|
+
subpath: parts.length > 2 ? parts.slice(2).join('/') : null,
|
|
139
|
+
branch,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Download a GitHub repo tarball into a temp dir, extract, and return the
|
|
144
|
+
* extracted root path along with the branch that was actually used.
|
|
145
|
+
*
|
|
146
|
+
* Tries `main` first then `master` if no branch is given (per Q5). Honours
|
|
147
|
+
* GITHUB_TOKEN / BMAD_GITHUB_TOKEN env vars for private repos. Throws
|
|
148
|
+
* immediately on 401/403 (token errors don't fix themselves on `master`).
|
|
149
|
+
*
|
|
150
|
+
* The caller is responsible for cleaning up `tmpDir` after consuming
|
|
151
|
+
* `extractedRoot` (typically in a `try { ... } finally { fs.rmSync(tmpDir) }`).
|
|
152
|
+
*/
|
|
153
|
+
export async function downloadGithubTarball(source) {
|
|
154
|
+
// TD-20 — realpathSync resolves the macOS /var → /private/var symlink so paths
|
|
155
|
+
// returned from this function are stable for the caller's existsSync checks.
|
|
156
|
+
const tmpDir = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), 'bmad-github-')));
|
|
157
|
+
const tarballPath = path.join(tmpDir, 'repo.tar.gz');
|
|
158
|
+
const token = process.env.GITHUB_TOKEN ?? process.env.BMAD_GITHUB_TOKEN ?? null;
|
|
159
|
+
const branchesToTry = source.branch ? [source.branch] : ['main', 'master'];
|
|
160
|
+
let lastError = 'unknown error';
|
|
161
|
+
let extractedRoot = null;
|
|
162
|
+
let resolvedBranch = null;
|
|
163
|
+
for (const branch of branchesToTry) {
|
|
164
|
+
const url = `https://api.github.com/repos/${source.owner}/${source.repo}/tarball/${branch}`;
|
|
165
|
+
const headers = { 'User-Agent': 'bmad-studio' };
|
|
166
|
+
if (token)
|
|
167
|
+
headers['Authorization'] = `Bearer ${token}`;
|
|
168
|
+
const response = await fetch(url, { headers, redirect: 'follow' });
|
|
169
|
+
if (response.status === 404) {
|
|
170
|
+
lastError = `Branch "${branch}" not found in ${source.owner}/${source.repo}`;
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
if (response.status === 401 || response.status === 403) {
|
|
174
|
+
// Token errors don't fix themselves on master — bail immediately.
|
|
175
|
+
try {
|
|
176
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
/* ignore */
|
|
180
|
+
}
|
|
181
|
+
throw new Error(`Cannot access ${source.owner}/${source.repo}. If this is a private repository, set GITHUB_TOKEN in your environment before starting BMAD Studio.`);
|
|
182
|
+
}
|
|
183
|
+
if (!response.ok) {
|
|
184
|
+
lastError = `GitHub API ${response.status}: ${response.statusText}`;
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
const buffer = Buffer.from(await response.arrayBuffer());
|
|
188
|
+
fs.writeFileSync(tarballPath, buffer);
|
|
189
|
+
// Extract via execSync — TD-4, consistent with the existing npm install path.
|
|
190
|
+
const extractDir = path.join(tmpDir, 'extracted');
|
|
191
|
+
fs.mkdirSync(extractDir, { recursive: true });
|
|
192
|
+
execSync(`tar -xzf "${tarballPath}" -C "${extractDir}"`, {
|
|
193
|
+
stdio: 'pipe',
|
|
194
|
+
timeout: 60000,
|
|
195
|
+
});
|
|
196
|
+
// GitHub tarballs always extract to a single subdir like {owner}-{repo}-{sha}/
|
|
197
|
+
const entries = fs.readdirSync(extractDir, { withFileTypes: true });
|
|
198
|
+
const rootEntry = entries.find((e) => e.isDirectory());
|
|
199
|
+
if (!rootEntry) {
|
|
200
|
+
try {
|
|
201
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
/* ignore */
|
|
205
|
+
}
|
|
206
|
+
throw new Error('GitHub tarball extracted to an empty directory');
|
|
207
|
+
}
|
|
208
|
+
extractedRoot = path.join(extractDir, rootEntry.name);
|
|
209
|
+
resolvedBranch = branch;
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
212
|
+
if (!extractedRoot || !resolvedBranch) {
|
|
213
|
+
try {
|
|
214
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
215
|
+
}
|
|
216
|
+
catch {
|
|
217
|
+
/* ignore */
|
|
218
|
+
}
|
|
219
|
+
throw new Error(lastError);
|
|
220
|
+
}
|
|
221
|
+
return { extractedRoot, tmpDir, resolvedBranch };
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Extract a multipart-uploaded zip into a temp dir and return the module root.
|
|
225
|
+
*
|
|
226
|
+
* `adm-zip` is loaded via dynamic import (TD-5) so users who never upload a zip
|
|
227
|
+
* pay zero startup cost. The first call pays the ~10ms parse, subsequent calls
|
|
228
|
+
* hit the Node.js module cache for free.
|
|
229
|
+
*
|
|
230
|
+
* Includes inline zip-slip mitigation (finding #22): every entry in the zip is
|
|
231
|
+
* checked to ensure its resolved path stays inside extractDir BEFORE extraction.
|
|
232
|
+
* The entire upload is rejected on any escape attempt, and no file is written
|
|
233
|
+
* to disk.
|
|
234
|
+
*
|
|
235
|
+
* If the zip's top-level contains exactly one directory, that directory is
|
|
236
|
+
* returned as `extractedRoot` (the "wrapper dir" case — most zip exports include
|
|
237
|
+
* one). Otherwise the extract dir itself is returned.
|
|
238
|
+
*
|
|
239
|
+
* The caller is responsible for cleaning up `tmpDir` after consuming
|
|
240
|
+
* `extractedRoot` (typically in a `try { ... } finally { fs.rmSync(tmpDir) }`).
|
|
241
|
+
*/
|
|
242
|
+
export async function extractZipUpload(zipBuffer) {
|
|
243
|
+
// TD-5 — dynamic import keeps adm-zip out of the cold-start path.
|
|
244
|
+
// adm-zip is a CJS module exporting its constructor as the default export.
|
|
245
|
+
const AdmZip = (await import('adm-zip')).default;
|
|
246
|
+
// TD-20 — realpathSync resolves the macOS /var → /private/var symlink so paths
|
|
247
|
+
// returned from this function are stable for the caller's existsSync checks.
|
|
248
|
+
const tmpDir = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), 'bmad-zip-')));
|
|
249
|
+
const extractDir = path.join(tmpDir, 'extracted');
|
|
250
|
+
fs.mkdirSync(extractDir, { recursive: true });
|
|
251
|
+
try {
|
|
252
|
+
const zip = new AdmZip(zipBuffer);
|
|
253
|
+
// Zip-slip mitigation (AC-15.4.7). Walk every entry and validate that its
|
|
254
|
+
// resolved target path stays inside extractDir BEFORE calling extractAllTo.
|
|
255
|
+
// Reject the entire upload on any escape attempt — no file written to disk.
|
|
256
|
+
const realExtractDir = fs.realpathSync(extractDir) + path.sep;
|
|
257
|
+
for (const entry of zip.getEntries()) {
|
|
258
|
+
const target = path.resolve(extractDir, entry.entryName);
|
|
259
|
+
// The target must either be exactly extractDir (the dir itself, no trailing sep)
|
|
260
|
+
// or live inside extractDir (with trailing sep prefix match).
|
|
261
|
+
if (!target.startsWith(realExtractDir) && target + path.sep !== realExtractDir) {
|
|
262
|
+
throw new Error(`Zip entry "${entry.entryName}" attempts to write outside the extraction directory — aborting`);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
zip.extractAllTo(extractDir, /* overwrite */ true);
|
|
266
|
+
}
|
|
267
|
+
catch (err) {
|
|
268
|
+
// Clean up on any failure (malformed zip, zip-slip rejection, adm-zip exception).
|
|
269
|
+
try {
|
|
270
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
271
|
+
}
|
|
272
|
+
catch {
|
|
273
|
+
/* ignore cleanup errors */
|
|
274
|
+
}
|
|
275
|
+
throw new Error(`Failed to extract zip: ${err instanceof Error ? err.message : String(err)}`);
|
|
276
|
+
}
|
|
277
|
+
// Locate the module root: either the extract dir itself, or its sole child
|
|
278
|
+
// if the zip has one wrapper directory (the common GitHub-export pattern).
|
|
279
|
+
const entries = fs.readdirSync(extractDir, { withFileTypes: true });
|
|
280
|
+
const extractedRoot = entries.length === 1 && entries[0].isDirectory()
|
|
281
|
+
? path.join(extractDir, entries[0].name)
|
|
282
|
+
: extractDir;
|
|
283
|
+
return { extractedRoot, tmpDir };
|
|
284
|
+
}
|
|
285
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
286
|
+
// Variable substitution — Story 15.5
|
|
287
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
288
|
+
// Files with these extensions are scanned for placeholder substitution after install.
|
|
289
|
+
// NARROWER than TEXT_FILE_EXTENSIONS — only user-readable template formats where
|
|
290
|
+
// substitution makes semantic sense. Substituting inside a .ts source file would
|
|
291
|
+
// break syntax if the value lands inside an identifier.
|
|
292
|
+
export const SUBSTITUTABLE_EXTENSIONS = new Set([
|
|
293
|
+
'.md',
|
|
294
|
+
'.markdown',
|
|
295
|
+
'.yaml',
|
|
296
|
+
'.yml',
|
|
297
|
+
'.csv',
|
|
298
|
+
'.txt',
|
|
299
|
+
]);
|
|
300
|
+
// Variable values must be plain text — no YAML/CSV/JSON special characters that would
|
|
301
|
+
// break the surrounding file format. Allowed: Unicode letters, digits, marks, single
|
|
302
|
+
// spaces (NOT tabs/newlines — those break YAML), and . _ - / : characters.
|
|
303
|
+
// Empty strings are valid.
|
|
304
|
+
const SAFE_VAR_VALUE = /^[\p{L}\p{N}\p{M} ._\-/:]*$/u;
|
|
305
|
+
/**
|
|
306
|
+
* Validate that all variable values are safe to substitute into text/yaml/csv files.
|
|
307
|
+
* Returns the FIRST violation as an error message naming the offending variable.
|
|
308
|
+
*/
|
|
309
|
+
export function validateVariables(variables) {
|
|
310
|
+
for (const [key, value] of Object.entries(variables)) {
|
|
311
|
+
if (!SAFE_VAR_VALUE.test(value)) {
|
|
312
|
+
return {
|
|
313
|
+
ok: false,
|
|
314
|
+
error: `Variable "${key}" contains characters that could break installed files. Allowed: letters, digits, spaces, and . _ - / : characters. Got: ${JSON.stringify(value)}`,
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
return { ok: true };
|
|
319
|
+
}
|
|
320
|
+
function applySubstitutions(content, ctx) {
|
|
321
|
+
let out = content;
|
|
322
|
+
// Static placeholders (single braces)
|
|
323
|
+
out = out.replaceAll('{project-root}', ctx.projectRoot);
|
|
324
|
+
out = out.replaceAll('{module-code}', ctx.moduleCode);
|
|
325
|
+
out = out.replaceAll('{output_folder}', ctx.outputFolder);
|
|
326
|
+
// {{var}} placeholders (double braces) — values pre-validated by validateVariables
|
|
327
|
+
for (const [key, value] of Object.entries(ctx.variables)) {
|
|
328
|
+
out = out.replaceAll(`{{${key}}}`, value);
|
|
329
|
+
}
|
|
330
|
+
return out;
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Walk a destination directory and substitute placeholders in files matching
|
|
334
|
+
* SUBSTITUTABLE_EXTENSIONS. Files without any matching placeholder are left
|
|
335
|
+
* untouched (no spurious snapshots). Substitution writes go through WriteService.
|
|
336
|
+
*
|
|
337
|
+
* Returns the count of files actually patched (a no-placeholder file does not count).
|
|
338
|
+
*/
|
|
339
|
+
export function runVariableSubstitution(destDir, ctx, studioDir, fileStore) {
|
|
340
|
+
let filesPatched = 0;
|
|
341
|
+
const walk = (dir) => {
|
|
342
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
343
|
+
const full = path.join(dir, entry.name);
|
|
344
|
+
if (entry.isDirectory()) {
|
|
345
|
+
const sub = walk(full);
|
|
346
|
+
if (!sub.ok)
|
|
347
|
+
return sub;
|
|
348
|
+
continue;
|
|
349
|
+
}
|
|
350
|
+
const ext = path.extname(entry.name).toLowerCase();
|
|
351
|
+
if (!SUBSTITUTABLE_EXTENSIONS.has(ext))
|
|
352
|
+
continue;
|
|
353
|
+
const content = fs.readFileSync(full, 'utf-8');
|
|
354
|
+
const patched = applySubstitutions(content, ctx);
|
|
355
|
+
if (patched === content)
|
|
356
|
+
continue; // AC-15.5.5 — no spurious snapshot
|
|
357
|
+
fileStore.markPendingWrite(full);
|
|
358
|
+
const result = writeFile(full, patched, studioDir);
|
|
359
|
+
fileStore.clearPendingWrite(full);
|
|
360
|
+
if (!result.ok)
|
|
361
|
+
return { ok: false, error: result.error };
|
|
362
|
+
filesPatched++;
|
|
363
|
+
}
|
|
364
|
+
return { ok: true };
|
|
365
|
+
};
|
|
366
|
+
const r = walk(destDir);
|
|
367
|
+
if (!r.ok)
|
|
368
|
+
return r;
|
|
369
|
+
return { ok: true, filesPatched };
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Read the project's `output_folder` setting from `_bmad/_config/config.yaml`.
|
|
373
|
+
* Returns `<projectRoot>/_bmad-output` as the default if the file is missing,
|
|
374
|
+
* malformed, or doesn't declare the field.
|
|
375
|
+
*/
|
|
376
|
+
export function readOutputFolder(projectRoot) {
|
|
377
|
+
const configPath = path.join(projectRoot, '_bmad', '_config', 'config.yaml');
|
|
378
|
+
if (!fs.existsSync(configPath)) {
|
|
379
|
+
return path.join(projectRoot, '_bmad-output');
|
|
380
|
+
}
|
|
381
|
+
try {
|
|
382
|
+
const config = yaml.load(fs.readFileSync(configPath, 'utf-8'));
|
|
383
|
+
const raw = config?.output_folder ?? '{project-root}/_bmad-output';
|
|
384
|
+
return raw.replaceAll('{project-root}', projectRoot);
|
|
385
|
+
}
|
|
386
|
+
catch {
|
|
387
|
+
return path.join(projectRoot, '_bmad-output');
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Scan the FileStore entity index for cross-module references to a target
|
|
392
|
+
* module's agents. Used by the remove preview endpoint to warn users about
|
|
393
|
+
* broken references after removal.
|
|
394
|
+
*
|
|
395
|
+
* **TD-19 scope (v1):** only scans two signals:
|
|
396
|
+
* 1. Teams whose `agentIds[]` contains any target-module agent ID
|
|
397
|
+
* 2. Workflow steps whose `step.agent` matches a target-module agent ID
|
|
398
|
+
*
|
|
399
|
+
* **Explicitly NOT scanned in v1:**
|
|
400
|
+
* - `agent.menu[].route` — holds a relative file path from the XML `exec=`
|
|
401
|
+
* attribute, not a workflow ID. `Set<workflowId>.has(filepath)` always
|
|
402
|
+
* returns false, so the check would be dead code.
|
|
403
|
+
* - `agent.skills[]` — hardcoded to `[]` in `agent-parser.ts:93`. Dead field.
|
|
404
|
+
*
|
|
405
|
+
* Both will be revisited in v2 with proper graph extraction.
|
|
406
|
+
*
|
|
407
|
+
* Returns an array of `{ ownerModule, reason }` entries, deduplicated by
|
|
408
|
+
* owner+reason. The target module itself is never included. Unattributed
|
|
409
|
+
* entities (edge case) are reported under `"(unattributed)"`.
|
|
410
|
+
*/
|
|
411
|
+
export function findCrossReferences(index, targetModule) {
|
|
412
|
+
const targetAgentIds = new Set(index.agents.filter((a) => a.module === targetModule).map((a) => a.id));
|
|
413
|
+
const refs = new Map();
|
|
414
|
+
const add = (owner, reason) => {
|
|
415
|
+
// Unattributed entities (rare — index-builder.ts:107-110 attributes everything
|
|
416
|
+
// inside _bmad/) are reported under a placeholder owner so the user knows to
|
|
417
|
+
// investigate manually. We do NOT silently drop them.
|
|
418
|
+
const ownerKey = owner ?? '(unattributed)';
|
|
419
|
+
if (ownerKey === targetModule)
|
|
420
|
+
return;
|
|
421
|
+
if (!refs.has(ownerKey))
|
|
422
|
+
refs.set(ownerKey, new Set());
|
|
423
|
+
refs.get(ownerKey).add(reason);
|
|
424
|
+
};
|
|
425
|
+
// Signal 1: teams whose agentIds[] includes any target-module agent
|
|
426
|
+
for (const team of index.teams) {
|
|
427
|
+
if (team.module === targetModule)
|
|
428
|
+
continue;
|
|
429
|
+
const hits = team.agentIds.filter((id) => targetAgentIds.has(id));
|
|
430
|
+
if (hits.length > 0) {
|
|
431
|
+
add(team.module, `team "${team.id}" references ${hits.length} agent(s)`);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
// Signal 2: workflow steps whose step.agent matches a target-module agent
|
|
435
|
+
for (const wf of index.workflows) {
|
|
436
|
+
if (wf.module === targetModule)
|
|
437
|
+
continue;
|
|
438
|
+
const hits = wf.steps.filter((s) => s.agent && targetAgentIds.has(s.agent));
|
|
439
|
+
if (hits.length > 0) {
|
|
440
|
+
add(wf.module, `workflow "${wf.id}" references ${hits.length} agent(s)`);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
return Array.from(refs.entries()).flatMap(([owner, reasons]) => Array.from(reasons).map((reason) => ({ ownerModule: owner, reason })));
|
|
444
|
+
}
|
|
445
|
+
//# sourceMappingURL=module-installer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module-installer.js","sourceRoot":"","sources":["../../src/core/module-installer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module-installer.test.d.ts","sourceRoot":"","sources":["../../src/core/module-installer.test.ts"],"names":[],"mappings":""}
|