@lbruton/specflow 3.1.0 → 3.2.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 +22 -16
- package/dist/core/__tests__/convention-detector.test.d.ts +2 -0
- package/dist/core/__tests__/convention-detector.test.d.ts.map +1 -0
- package/dist/core/__tests__/convention-detector.test.js +199 -0
- package/dist/core/__tests__/convention-detector.test.js.map +1 -0
- package/dist/core/__tests__/security-utils.test.js +2 -2
- package/dist/core/__tests__/security-utils.test.js.map +1 -1
- package/dist/core/__tests__/template-generator.test.d.ts +2 -0
- package/dist/core/__tests__/template-generator.test.d.ts.map +1 -0
- package/dist/core/__tests__/template-generator.test.js +167 -0
- package/dist/core/__tests__/template-generator.test.js.map +1 -0
- package/dist/core/convention-detector.d.ts +36 -0
- package/dist/core/convention-detector.d.ts.map +1 -0
- package/dist/core/convention-detector.js +298 -0
- package/dist/core/convention-detector.js.map +1 -0
- package/dist/core/security-utils.js +2 -2
- package/dist/core/security-utils.js.map +1 -1
- package/dist/core/template-generator.d.ts +21 -0
- package/dist/core/template-generator.d.ts.map +1 -0
- package/dist/core/template-generator.js +217 -0
- package/dist/core/template-generator.js.map +1 -0
- package/dist/markdown/templates/design-template.md +8 -6
- package/dist/markdown/templates/tasks-template.md +23 -20
- package/dist/prompts/index.d.ts.map +1 -1
- package/dist/prompts/index.js +4 -7
- package/dist/prompts/index.js.map +1 -1
- package/dist/tools/spec-status.d.ts.map +1 -1
- package/dist/tools/spec-status.js +35 -8
- package/dist/tools/spec-status.js.map +1 -1
- package/dist/tools/spec-workflow-guide.js +25 -15
- package/dist/tools/spec-workflow-guide.js.map +1 -1
- package/package.json +1 -1
- package/dist/prompts/audit.d.ts +0 -3
- package/dist/prompts/audit.d.ts.map +0 -1
- package/dist/prompts/audit.js +0 -267
- package/dist/prompts/audit.js.map +0 -1
- package/dist/prompts/prime.d.ts +0 -3
- package/dist/prompts/prime.d.ts.map +0 -1
- package/dist/prompts/prime.js +0 -290
- package/dist/prompts/prime.js.map +0 -1
- package/dist/prompts/wrap.d.ts +0 -3
- package/dist/prompts/wrap.d.ts.map +0 -1
- package/dist/prompts/wrap.js +0 -285
- package/dist/prompts/wrap.js.map +0 -1
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export interface ProjectConventions {
|
|
2
|
+
schemaVersion: 1;
|
|
3
|
+
detectedAt: string;
|
|
4
|
+
testing: {
|
|
5
|
+
framework: string | null;
|
|
6
|
+
command: string | null;
|
|
7
|
+
configFile: string | null;
|
|
8
|
+
testDir: string | null;
|
|
9
|
+
hasBrowserbase: boolean;
|
|
10
|
+
};
|
|
11
|
+
versioning: {
|
|
12
|
+
hasVersionLock: boolean;
|
|
13
|
+
lockFile: string | null;
|
|
14
|
+
packageVersion: string | null;
|
|
15
|
+
userDeclinedSetup: boolean;
|
|
16
|
+
};
|
|
17
|
+
changelog: {
|
|
18
|
+
hasChangelog: boolean;
|
|
19
|
+
file: string | null;
|
|
20
|
+
format: string | null;
|
|
21
|
+
docvaultFallback: boolean;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Scan a project directory and detect its testing, versioning, and changelog conventions.
|
|
26
|
+
*
|
|
27
|
+
* All filesystem errors are handled gracefully — missing files produce null values, never throw.
|
|
28
|
+
* Works on any project directory, including empty ones.
|
|
29
|
+
*/
|
|
30
|
+
export declare function detectConventions(projectPath: string): Promise<ProjectConventions>;
|
|
31
|
+
/**
|
|
32
|
+
* Write detected conventions to `.spec-workflow/project-conventions.json`.
|
|
33
|
+
* Creates the `.spec-workflow` directory if it does not exist.
|
|
34
|
+
*/
|
|
35
|
+
export declare function writeConventions(projectPath: string, conventions: ProjectConventions): Promise<void>;
|
|
36
|
+
//# sourceMappingURL=convention-detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"convention-detector.d.ts","sourceRoot":"","sources":["../../src/core/convention-detector.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,CAAC,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE;QACP,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QACvB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QACvB,cAAc,EAAE,OAAO,CAAC;KACzB,CAAC;IACF,UAAU,EAAE;QACV,cAAc,EAAE,OAAO,CAAC;QACxB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QACxB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,iBAAiB,EAAE,OAAO,CAAC;KAC5B,CAAC;IACF,SAAS,EAAE;QACT,YAAY,EAAE,OAAO,CAAC;QACtB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;QACpB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,gBAAgB,EAAE,OAAO,CAAC;KAC3B,CAAC;CACH;AAyRD;;;;;GAKG;AACH,wBAAsB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAcxF;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAS1G"}
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
import { readFile, readdir, stat, mkdir, writeFile } from 'fs/promises';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
/** Safely read a file, returning null on any error. */
|
|
4
|
+
async function safeReadFile(filePath) {
|
|
5
|
+
try {
|
|
6
|
+
return await readFile(filePath, 'utf-8');
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
/** Check if a path exists and is a directory. */
|
|
13
|
+
async function isDirectory(dirPath) {
|
|
14
|
+
try {
|
|
15
|
+
const s = await stat(dirPath);
|
|
16
|
+
return s.isDirectory();
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/** Check if a file exists. */
|
|
23
|
+
async function fileExists(filePath) {
|
|
24
|
+
try {
|
|
25
|
+
const s = await stat(filePath);
|
|
26
|
+
return s.isFile();
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/** Find the first existing file from a list of candidates. Returns the relative path or null. */
|
|
33
|
+
async function findFirstFile(projectPath, candidates) {
|
|
34
|
+
for (const candidate of candidates) {
|
|
35
|
+
if (await fileExists(join(projectPath, candidate))) {
|
|
36
|
+
return candidate;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
/** Detect testing framework, command, config file, test directory, and browserbase usage. */
|
|
42
|
+
async function detectTesting(projectPath) {
|
|
43
|
+
let framework = null;
|
|
44
|
+
let command = null;
|
|
45
|
+
let configFile = null;
|
|
46
|
+
let testDir = null;
|
|
47
|
+
let hasBrowserbase = false;
|
|
48
|
+
// --- Framework detection (priority order) ---
|
|
49
|
+
// Vitest
|
|
50
|
+
const vitestConfigs = [
|
|
51
|
+
'vitest.config.ts', 'vitest.config.js', 'vitest.config.mts', 'vitest.config.mjs',
|
|
52
|
+
];
|
|
53
|
+
const vitestConfig = await findFirstFile(projectPath, vitestConfigs);
|
|
54
|
+
if (vitestConfig) {
|
|
55
|
+
framework = 'vitest';
|
|
56
|
+
command = 'npx vitest';
|
|
57
|
+
configFile = vitestConfig;
|
|
58
|
+
}
|
|
59
|
+
// Jest (only if vitest not found)
|
|
60
|
+
if (!framework) {
|
|
61
|
+
const jestConfigs = [
|
|
62
|
+
'jest.config.ts', 'jest.config.js', 'jest.config.mjs', 'jest.config.cjs', 'jest.config.json',
|
|
63
|
+
];
|
|
64
|
+
const jestConfig = await findFirstFile(projectPath, jestConfigs);
|
|
65
|
+
if (jestConfig) {
|
|
66
|
+
framework = 'jest';
|
|
67
|
+
command = 'npx jest';
|
|
68
|
+
configFile = jestConfig;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// Pytest
|
|
72
|
+
if (!framework) {
|
|
73
|
+
const pytestConfigs = ['pytest.ini', 'pyproject.toml', 'setup.cfg'];
|
|
74
|
+
for (const candidate of pytestConfigs) {
|
|
75
|
+
const content = await safeReadFile(join(projectPath, candidate));
|
|
76
|
+
if (content !== null) {
|
|
77
|
+
// For pyproject.toml and setup.cfg, check for pytest section
|
|
78
|
+
if (candidate === 'pytest.ini') {
|
|
79
|
+
framework = 'pytest';
|
|
80
|
+
command = 'pytest';
|
|
81
|
+
configFile = candidate;
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
if (candidate === 'pyproject.toml' && content.includes('[tool.pytest')) {
|
|
85
|
+
framework = 'pytest';
|
|
86
|
+
command = 'pytest';
|
|
87
|
+
configFile = candidate;
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
if (candidate === 'setup.cfg' && content.includes('[tool:pytest]')) {
|
|
91
|
+
framework = 'pytest';
|
|
92
|
+
command = 'pytest';
|
|
93
|
+
configFile = candidate;
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// Mocha (check package.json devDependencies or config files)
|
|
100
|
+
if (!framework) {
|
|
101
|
+
const mochaConfigs = ['.mocharc.yml', '.mocharc.yaml', '.mocharc.js', '.mocharc.json', '.mocharc.cjs'];
|
|
102
|
+
const mochaConfig = await findFirstFile(projectPath, mochaConfigs);
|
|
103
|
+
if (mochaConfig) {
|
|
104
|
+
framework = 'mocha';
|
|
105
|
+
command = 'npx mocha';
|
|
106
|
+
configFile = mochaConfig;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// package.json scripts.test fallback
|
|
110
|
+
if (!framework) {
|
|
111
|
+
const pkgContent = await safeReadFile(join(projectPath, 'package.json'));
|
|
112
|
+
if (pkgContent) {
|
|
113
|
+
try {
|
|
114
|
+
const pkg = JSON.parse(pkgContent);
|
|
115
|
+
const testScript = pkg?.scripts?.test;
|
|
116
|
+
if (testScript) {
|
|
117
|
+
// Infer framework from test script content
|
|
118
|
+
if (testScript.includes('vitest')) {
|
|
119
|
+
framework = 'vitest';
|
|
120
|
+
configFile = 'package.json';
|
|
121
|
+
}
|
|
122
|
+
else if (testScript.includes('jest')) {
|
|
123
|
+
framework = 'jest';
|
|
124
|
+
configFile = 'package.json';
|
|
125
|
+
}
|
|
126
|
+
else if (testScript.includes('mocha')) {
|
|
127
|
+
framework = 'mocha';
|
|
128
|
+
configFile = 'package.json';
|
|
129
|
+
}
|
|
130
|
+
else if (testScript.includes('pytest')) {
|
|
131
|
+
framework = 'pytest';
|
|
132
|
+
configFile = 'package.json';
|
|
133
|
+
}
|
|
134
|
+
command = testScript.startsWith('npm') ? testScript : `npm test`;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
// Invalid JSON — ignore
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
// --- Browserbase / bb-test detection ---
|
|
143
|
+
const runbookDir = join(projectPath, 'tests', 'runbook');
|
|
144
|
+
if (await isDirectory(runbookDir)) {
|
|
145
|
+
hasBrowserbase = true;
|
|
146
|
+
if (!framework) {
|
|
147
|
+
framework = 'bb-test';
|
|
148
|
+
testDir = 'tests/runbook/';
|
|
149
|
+
// Count runbook sections for the command hint
|
|
150
|
+
try {
|
|
151
|
+
const entries = await readdir(runbookDir);
|
|
152
|
+
const sections = entries.filter(e => !e.startsWith('.')).length;
|
|
153
|
+
command = `/bb-test sections=${sections}`;
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
command = '/bb-test';
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
// Check CLAUDE.md for bb-test references
|
|
161
|
+
if (!hasBrowserbase) {
|
|
162
|
+
const claudeMd = await safeReadFile(join(projectPath, 'CLAUDE.md'));
|
|
163
|
+
if (claudeMd && (claudeMd.includes('/bb-test') || claudeMd.includes('bb-test'))) {
|
|
164
|
+
hasBrowserbase = true;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// --- Test directory detection ---
|
|
168
|
+
if (!testDir) {
|
|
169
|
+
const testDirCandidates = [
|
|
170
|
+
'src/__tests__',
|
|
171
|
+
'tests/',
|
|
172
|
+
'test/',
|
|
173
|
+
'__tests__/',
|
|
174
|
+
];
|
|
175
|
+
for (const candidate of testDirCandidates) {
|
|
176
|
+
const candidatePath = join(projectPath, candidate.replace(/\/$/, ''));
|
|
177
|
+
if (await isDirectory(candidatePath)) {
|
|
178
|
+
testDir = candidate;
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return { framework, command, configFile, testDir, hasBrowserbase };
|
|
184
|
+
}
|
|
185
|
+
/** Detect versioning conventions. */
|
|
186
|
+
async function detectVersioning(projectPath) {
|
|
187
|
+
let hasVersionLock = false;
|
|
188
|
+
let lockFile = null;
|
|
189
|
+
let packageVersion = null;
|
|
190
|
+
const userDeclinedSetup = false;
|
|
191
|
+
// Check devops/version.lock
|
|
192
|
+
const versionLockPath = join(projectPath, 'devops', 'version.lock');
|
|
193
|
+
if (await fileExists(versionLockPath)) {
|
|
194
|
+
hasVersionLock = true;
|
|
195
|
+
lockFile = 'devops/version.lock';
|
|
196
|
+
}
|
|
197
|
+
// Check package.json version
|
|
198
|
+
const pkgContent = await safeReadFile(join(projectPath, 'package.json'));
|
|
199
|
+
if (pkgContent) {
|
|
200
|
+
try {
|
|
201
|
+
const pkg = JSON.parse(pkgContent);
|
|
202
|
+
if (pkg?.version && typeof pkg.version === 'string') {
|
|
203
|
+
packageVersion = pkg.version;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
catch {
|
|
207
|
+
// Invalid JSON — ignore
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
// Check .version file
|
|
211
|
+
if (!hasVersionLock && !packageVersion) {
|
|
212
|
+
const dotVersionPath = join(projectPath, '.version');
|
|
213
|
+
const dotVersion = await safeReadFile(dotVersionPath);
|
|
214
|
+
if (dotVersion !== null) {
|
|
215
|
+
hasVersionLock = true;
|
|
216
|
+
lockFile = '.version';
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return { hasVersionLock, lockFile, packageVersion, userDeclinedSetup };
|
|
220
|
+
}
|
|
221
|
+
/** Detect changelog presence and format. */
|
|
222
|
+
async function detectChangelog(projectPath) {
|
|
223
|
+
let hasChangelog = false;
|
|
224
|
+
let file = null;
|
|
225
|
+
let format = null;
|
|
226
|
+
const docvaultFallback = false;
|
|
227
|
+
const changelogCandidates = ['CHANGELOG.md', 'CHANGES.md', 'HISTORY.md'];
|
|
228
|
+
for (const candidate of changelogCandidates) {
|
|
229
|
+
const content = await safeReadFile(join(projectPath, candidate));
|
|
230
|
+
if (content !== null) {
|
|
231
|
+
hasChangelog = true;
|
|
232
|
+
file = candidate;
|
|
233
|
+
format = detectChangelogFormat(content);
|
|
234
|
+
break;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return { hasChangelog, file, format, docvaultFallback };
|
|
238
|
+
}
|
|
239
|
+
/** Detect changelog format from file content (reads first ~20 lines). */
|
|
240
|
+
function detectChangelogFormat(content) {
|
|
241
|
+
const lines = content.split('\n').slice(0, 20);
|
|
242
|
+
const header = lines.join('\n');
|
|
243
|
+
// keepachangelog: has ## [Unreleased] or ## [X.Y.Z] with Added/Changed/Fixed sections
|
|
244
|
+
const hasVersionHeaders = /## \[(Unreleased|\d+\.\d+\.\d+)]/i.test(header);
|
|
245
|
+
const hasSections = /(### (Added|Changed|Deprecated|Removed|Fixed|Security))/i.test(header);
|
|
246
|
+
if (hasVersionHeaders && hasSections) {
|
|
247
|
+
return 'keepachangelog';
|
|
248
|
+
}
|
|
249
|
+
// Also match keepachangelog if just the version header pattern is present with the right title
|
|
250
|
+
if (hasVersionHeaders && /keep.?a.?changelog/i.test(header)) {
|
|
251
|
+
return 'keepachangelog';
|
|
252
|
+
}
|
|
253
|
+
// conventional-changelog: typically starts with # followed by version + date and has commit-style entries
|
|
254
|
+
if (/^#+ \d+\.\d+\.\d+/m.test(header) && /\* \*\*\w+:\*\*/m.test(header)) {
|
|
255
|
+
return 'conventional';
|
|
256
|
+
}
|
|
257
|
+
// If it has version headers but doesn't match the above patterns
|
|
258
|
+
if (hasVersionHeaders) {
|
|
259
|
+
return 'keepachangelog';
|
|
260
|
+
}
|
|
261
|
+
return 'custom';
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Scan a project directory and detect its testing, versioning, and changelog conventions.
|
|
265
|
+
*
|
|
266
|
+
* All filesystem errors are handled gracefully — missing files produce null values, never throw.
|
|
267
|
+
* Works on any project directory, including empty ones.
|
|
268
|
+
*/
|
|
269
|
+
export async function detectConventions(projectPath) {
|
|
270
|
+
const [testing, versioning, changelog] = await Promise.all([
|
|
271
|
+
detectTesting(projectPath),
|
|
272
|
+
detectVersioning(projectPath),
|
|
273
|
+
detectChangelog(projectPath),
|
|
274
|
+
]);
|
|
275
|
+
return {
|
|
276
|
+
schemaVersion: 1,
|
|
277
|
+
detectedAt: new Date().toISOString(),
|
|
278
|
+
testing,
|
|
279
|
+
versioning,
|
|
280
|
+
changelog,
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Write detected conventions to `.spec-workflow/project-conventions.json`.
|
|
285
|
+
* Creates the `.spec-workflow` directory if it does not exist.
|
|
286
|
+
*/
|
|
287
|
+
export async function writeConventions(projectPath, conventions) {
|
|
288
|
+
const dir = join(projectPath, '.spec-workflow');
|
|
289
|
+
try {
|
|
290
|
+
await mkdir(dir, { recursive: true });
|
|
291
|
+
}
|
|
292
|
+
catch {
|
|
293
|
+
// Directory may already exist — ignore
|
|
294
|
+
}
|
|
295
|
+
const filePath = join(dir, 'project-conventions.json');
|
|
296
|
+
await writeFile(filePath, JSON.stringify(conventions, null, 2) + '\n', 'utf-8');
|
|
297
|
+
}
|
|
298
|
+
//# sourceMappingURL=convention-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"convention-detector.js","sourceRoot":"","sources":["../../src/core/convention-detector.ts"],"names":[],"mappings":"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"}
|
|
@@ -217,7 +217,7 @@ export class AuditLogger {
|
|
|
217
217
|
export function createSecurityHeadersMiddleware(port) {
|
|
218
218
|
const actualPort = port || DEFAULT_DASHBOARD_PORT;
|
|
219
219
|
// Build connect-src directive with WebSocket endpoints
|
|
220
|
-
let connectSrc = `'self' ws://localhost:${actualPort} ws://127.0.0.1:${actualPort} wss://specdash.lbruton.cc
|
|
220
|
+
let connectSrc = `'self' ws://localhost:${actualPort} ws://127.0.0.1:${actualPort} wss://specdash.lbruton.cc`;
|
|
221
221
|
// In non-production environments, also allow Vite dev server connections
|
|
222
222
|
if (process.env.NODE_ENV !== 'production') {
|
|
223
223
|
connectSrc += ` ws://localhost:${VITE_DEV_PORT} ws://127.0.0.1:${VITE_DEV_PORT}`;
|
|
@@ -231,7 +231,7 @@ export function createSecurityHeadersMiddleware(port) {
|
|
|
231
231
|
// CSP for dashboard
|
|
232
232
|
// Note: cdn.jsdelivr.net is required for highlight.js stylesheets used by the MDX editor
|
|
233
233
|
// connect-src allows WebSocket connections to the dashboard on the actual port
|
|
234
|
-
reply.header('Content-Security-Policy', `default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; img-src 'self' data:; connect-src ${connectSrc}; frame-src https://polldash.lbruton.cc
|
|
234
|
+
reply.header('Content-Security-Policy', `default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; img-src 'self' data:; connect-src ${connectSrc}; frame-src https://polldash.lbruton.cc;`);
|
|
235
235
|
};
|
|
236
236
|
}
|
|
237
237
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"security-utils.js","sourceRoot":"","sources":["../../src/core/security-utils.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"security-utils.js","sourceRoot":"","sources":["../../src/core/security-utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ProjectConventions } from './convention-detector.js';
|
|
2
|
+
export interface GeneratedTemplates {
|
|
3
|
+
designTemplate: string;
|
|
4
|
+
tasksTemplate: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Generate project-specific user-templates from detected conventions.
|
|
8
|
+
*
|
|
9
|
+
* Reads the current default templates (from .spec-workflow/templates/ or bundled fallback),
|
|
10
|
+
* then replaces the Testing Strategy and Standard Closing Tasks sections with
|
|
11
|
+
* project-specific content based on the detected conventions.
|
|
12
|
+
*/
|
|
13
|
+
export declare function generateUserTemplates(projectPath: string, conventions: ProjectConventions): Promise<GeneratedTemplates>;
|
|
14
|
+
/**
|
|
15
|
+
* Write generated user-templates to `.spec-workflow/user-templates/`.
|
|
16
|
+
*
|
|
17
|
+
* IMPORTANT: If user-templates already exist, this function returns early
|
|
18
|
+
* without overwriting them. Users own their user-templates once created.
|
|
19
|
+
*/
|
|
20
|
+
export declare function writeUserTemplates(projectPath: string, templates: GeneratedTemplates): Promise<void>;
|
|
21
|
+
//# sourceMappingURL=template-generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template-generator.d.ts","sourceRoot":"","sources":["../../src/core/template-generator.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAInE,MAAM,WAAW,kBAAkB;IACjC,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;CACvB;AA+LD;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CACzC,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,kBAAkB,GAC9B,OAAO,CAAC,kBAAkB,CAAC,CAU7B;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,kBAAkB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAkBf"}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import { readFile, mkdir, writeFile, stat } from 'fs/promises';
|
|
2
|
+
import { join, dirname } from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
5
|
+
/**
|
|
6
|
+
* Safely read a file, returning null on any error.
|
|
7
|
+
*/
|
|
8
|
+
async function safeReadFile(filePath) {
|
|
9
|
+
try {
|
|
10
|
+
return await readFile(filePath, 'utf-8');
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Check if a file exists.
|
|
18
|
+
*/
|
|
19
|
+
async function fileExists(filePath) {
|
|
20
|
+
try {
|
|
21
|
+
const s = await stat(filePath);
|
|
22
|
+
return s.isFile();
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Read a default template by name, checking the project's .spec-workflow/templates/
|
|
30
|
+
* first, then falling back to the bundled src/markdown/templates/.
|
|
31
|
+
*/
|
|
32
|
+
async function readDefaultTemplate(projectPath, templateName) {
|
|
33
|
+
// Primary: project's copied templates
|
|
34
|
+
const projectTemplate = join(projectPath, '.spec-workflow', 'templates', `${templateName}.md`);
|
|
35
|
+
const content = await safeReadFile(projectTemplate);
|
|
36
|
+
if (content !== null) {
|
|
37
|
+
return content;
|
|
38
|
+
}
|
|
39
|
+
// Fallback: bundled source templates (compiled to dist/core/, so go up to dist/markdown/templates/)
|
|
40
|
+
const bundledTemplate = join(__dirname, '..', 'markdown', 'templates', `${templateName}.md`);
|
|
41
|
+
const bundledContent = await safeReadFile(bundledTemplate);
|
|
42
|
+
if (bundledContent !== null) {
|
|
43
|
+
return bundledContent;
|
|
44
|
+
}
|
|
45
|
+
throw new Error(`Could not find default template "${templateName}.md" in project or bundled sources`);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Generate the Testing Strategy section for browserbase projects.
|
|
49
|
+
*/
|
|
50
|
+
function generateBrowserbaseTestingStrategy() {
|
|
51
|
+
return `### Runbook E2E Tests (Primary)
|
|
52
|
+
- Identify affected \`tests/runbook/\` section(s): [01-page-load, 02-crud, 03-backup-restore, 04-import-export, 05-market, 06-ui-ux, 07-activity-log, 08-spot-prices]
|
|
53
|
+
- New test blocks to write (TDD — before implementation): [describe tests]
|
|
54
|
+
- Run via \`/bb-test sections=NN\` against PR preview URL
|
|
55
|
+
|
|
56
|
+
### Manual Verification
|
|
57
|
+
- [Any flows that require manual testing]`;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Generate the Testing Strategy section for non-browserbase projects.
|
|
61
|
+
*/
|
|
62
|
+
function generateGenericTestingStrategy(conventions) {
|
|
63
|
+
const framework = conventions.testing.framework || 'Not detected — identify manually';
|
|
64
|
+
const command = conventions.testing.command || 'npm test';
|
|
65
|
+
const testDir = conventions.testing.testDir || 'tests/';
|
|
66
|
+
return `### Automated Tests
|
|
67
|
+
- **Test Framework:** ${framework}
|
|
68
|
+
- **Test Command:** \`${command}\`
|
|
69
|
+
- **Test Directory:** \`${testDir}\`
|
|
70
|
+
- **New tests to write (TDD — before implementation):** [describe tests using ${framework}]
|
|
71
|
+
- **Run via:** \`${command}\` after implementation
|
|
72
|
+
|
|
73
|
+
### Manual Verification
|
|
74
|
+
- [Any flows that require manual testing beyond the automated test suite]`;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Replace the Testing Strategy section in the design template with project-specific content.
|
|
78
|
+
*/
|
|
79
|
+
function replaceDesignTestingStrategy(template, conventions) {
|
|
80
|
+
const replacement = conventions.testing.hasBrowserbase
|
|
81
|
+
? generateBrowserbaseTestingStrategy()
|
|
82
|
+
: generateGenericTestingStrategy(conventions);
|
|
83
|
+
// Match the ## Testing Strategy section up to the next ## heading or end of file
|
|
84
|
+
const sectionRegex = /## Testing Strategy\n[\s\S]*?(?=\n## |\n$|$)/;
|
|
85
|
+
if (sectionRegex.test(template)) {
|
|
86
|
+
return template.replace(sectionRegex, `## Testing Strategy\n\n${replacement}`);
|
|
87
|
+
}
|
|
88
|
+
// If no Testing Strategy section found, append it
|
|
89
|
+
return template + `\n\n## Testing Strategy\n\n${replacement}\n`;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Generate the Standard Closing Tasks section for browserbase projects.
|
|
93
|
+
* Reproduces the runbook-specific tasks from the StakTrakr-era template.
|
|
94
|
+
*/
|
|
95
|
+
function generateBrowserbaseClosingTasks() {
|
|
96
|
+
return `## Standard Closing Tasks
|
|
97
|
+
|
|
98
|
+
- [ ] 6. Integration and testing
|
|
99
|
+
- Plan integration approach and identify affected runbook sections for TDD test authoring
|
|
100
|
+
- _Leverage: tests/runbook/*.md, /browserbase-test-maintenance skill_
|
|
101
|
+
- _Requirements: 6.0_
|
|
102
|
+
- _Prompt: Role: Integration Engineer with expertise in system integration and testing strategies | Task: Plan comprehensive integration approach following requirement 6.0. Identify which tests/runbook/ section files are affected by this spec and write new runbook test blocks BEFORE implementation tasks begin (TDD). Use the /browserbase-test-maintenance skill for format guidance and section mapping. | Restrictions: Must consider all system components, ensure proper test coverage, write tests in the standard 7-field runbook format | Success: Integration plan is comprehensive, runbook test blocks are written for all new user-facing behavior, tests are appended to the correct section files_
|
|
103
|
+
|
|
104
|
+
- [ ] 6.1 Write end-to-end runbook tests (TDD — write BEFORE implementation)
|
|
105
|
+
- Write runbook test blocks in tests/runbook/*.md for new user-facing behavior
|
|
106
|
+
- Use the /browserbase-test-maintenance skill for the standard 7-field format
|
|
107
|
+
- Map implementation changes to the correct runbook section file
|
|
108
|
+
- _Leverage: /browserbase-test-maintenance skill, tests/runbook/*.md section files_
|
|
109
|
+
- _Requirements: All_
|
|
110
|
+
- _Prompt: Role: QA Automation Engineer with expertise in Browserbase/Stagehand natural-language browser automation | Task: Write runbook test blocks in tests/runbook/*.md for all new user-facing behavior using the /browserbase-test-maintenance skill. Each test block must use the 7-field format (Test name, Added, Preconditions, Steps, Pass criteria, Tags, Section). Map changes to the correct section file. After implementation, verify by running /bb-test sections=NN against the PR preview URL. | Restrictions: Use the standard runbook format, append to section files (never modify existing tests), act steps must be atomic. No Playwright, no browserless. | Success: All new user-facing behavior has corresponding runbook test blocks, tests pass when run via /bb-test against the PR preview URL_
|
|
111
|
+
|
|
112
|
+
- [ ] 6.2 Verify tests against PR preview
|
|
113
|
+
- Run /bb-test sections=NN against PR preview URL to verify all new tests pass
|
|
114
|
+
- _Leverage: /bb-test skill, PR preview URL from gh pr checks_
|
|
115
|
+
- _Requirements: All_
|
|
116
|
+
- _Prompt: Role: QA Automation Engineer | Task: Run /bb-test sections=NN against the PR preview URL to verify all new runbook tests pass. Get the preview URL with: gh pr checks <PR_NUMBER> --json name,state,targetUrl. For 1-3 tests, consider manual verification via Chrome DevTools instead of a full Browserbase session. | Restrictions: Do NOT use Playwright or browserless. | Success: All new tests pass against the PR preview URL_
|
|
117
|
+
|
|
118
|
+
- [ ] 6.3 Final integration and cleanup
|
|
119
|
+
- Integrate all components
|
|
120
|
+
- Fix any integration issues
|
|
121
|
+
- Clean up code and documentation
|
|
122
|
+
- _Leverage: src/utils/cleanup.ts, docs/templates/_
|
|
123
|
+
- _Requirements: All_
|
|
124
|
+
- _Prompt: Role: Senior Developer with expertise in code quality and system integration | Task: Complete final integration of all components and perform comprehensive cleanup covering all requirements, using cleanup utilities and documentation templates | Restrictions: Must not break existing functionality, ensure code quality standards are met, maintain documentation consistency | Success: All components are fully integrated and working together, code is clean and well-documented, system meets all requirements and quality standards_`;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Generate the Standard Closing Tasks section for non-browserbase projects.
|
|
128
|
+
* Uses the generic test command from detected conventions.
|
|
129
|
+
*/
|
|
130
|
+
function generateGenericClosingTasks(conventions) {
|
|
131
|
+
const command = conventions.testing.command || 'npm test';
|
|
132
|
+
const framework = conventions.testing.framework || 'the project test framework';
|
|
133
|
+
return `## Standard Closing Tasks
|
|
134
|
+
|
|
135
|
+
- [ ] 6. Run project test suite and verify baseline
|
|
136
|
+
- Run \`${command}\` to establish a passing baseline before changes
|
|
137
|
+
- If no test suite exists, flag this and discuss with the user
|
|
138
|
+
- _Leverage: Project test configuration (package.json scripts, vitest.config, jest.config, etc.)_
|
|
139
|
+
- _Requirements: All_
|
|
140
|
+
- _Prompt: Role: QA Engineer | Task: Run the project's established test suite (\`${command}\`) to verify a passing baseline before implementation. If no test suite exists, flag this to the user. | Restrictions: Use the project's existing test framework, do not introduce a new one. | Success: Test suite runs and baseline results are recorded._
|
|
141
|
+
|
|
142
|
+
- [ ] 6.1 Write tests for new behavior (TDD — write BEFORE implementation)
|
|
143
|
+
- Write failing tests using ${framework} for all new behavior
|
|
144
|
+
- Tests should cover the acceptance criteria from requirements.md
|
|
145
|
+
- _Leverage: Project test framework, requirements.md acceptance criteria_
|
|
146
|
+
- _Requirements: All_
|
|
147
|
+
- _Prompt: Role: QA Engineer | Task: Write failing tests for all new behavior described in requirements.md using ${framework}. Follow TDD - tests must fail before implementation, pass after. | Restrictions: Use the project's existing test framework. Tests must be runnable with \`${command}\`. | Success: Failing tests exist for all new acceptance criteria._
|
|
148
|
+
|
|
149
|
+
- [ ] 6.2 Verify all tests pass after implementation
|
|
150
|
+
- Run \`${command}\` after all implementation tasks are complete
|
|
151
|
+
- All new tests must pass; no existing tests may regress
|
|
152
|
+
- _Leverage: Project test command_
|
|
153
|
+
- _Requirements: All_
|
|
154
|
+
- _Prompt: Role: QA Engineer | Task: Run \`${command}\`. Verify all new tests pass and no existing tests regressed. | Restrictions: Do not skip or disable failing tests. | Success: Full test suite passes with zero regressions._
|
|
155
|
+
|
|
156
|
+
- [ ] 6.3 Final integration and cleanup
|
|
157
|
+
- Integrate all components
|
|
158
|
+
- Verify no lint or type errors
|
|
159
|
+
- Clean up temporary code and documentation
|
|
160
|
+
- _Leverage: Project lint/build commands_
|
|
161
|
+
- _Requirements: All_
|
|
162
|
+
- _Prompt: Role: Senior Developer | Task: Complete final integration of all components and perform comprehensive cleanup. Run lint and type checks. Remove any temporary code or debug statements. | Restrictions: Must not break existing functionality. Ensure code quality standards are met. | Success: All components integrated, no lint or type errors, code is clean._`;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Replace the Standard Closing Tasks section in the tasks template with project-specific content.
|
|
166
|
+
*/
|
|
167
|
+
function replaceTasksClosingSection(template, conventions) {
|
|
168
|
+
const replacement = conventions.testing.hasBrowserbase
|
|
169
|
+
? generateBrowserbaseClosingTasks()
|
|
170
|
+
: generateGenericClosingTasks(conventions);
|
|
171
|
+
// Match the ## Standard Closing Tasks section to end of file
|
|
172
|
+
const sectionRegex = /## Standard Closing Tasks\n[\s\S]*$/;
|
|
173
|
+
if (sectionRegex.test(template)) {
|
|
174
|
+
return template.replace(sectionRegex, replacement.replace(/^## Standard Closing Tasks\n/, '## Standard Closing Tasks\n'));
|
|
175
|
+
}
|
|
176
|
+
// If no Standard Closing Tasks section found, append it
|
|
177
|
+
return template + '\n\n' + replacement + '\n';
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Generate project-specific user-templates from detected conventions.
|
|
181
|
+
*
|
|
182
|
+
* Reads the current default templates (from .spec-workflow/templates/ or bundled fallback),
|
|
183
|
+
* then replaces the Testing Strategy and Standard Closing Tasks sections with
|
|
184
|
+
* project-specific content based on the detected conventions.
|
|
185
|
+
*/
|
|
186
|
+
export async function generateUserTemplates(projectPath, conventions) {
|
|
187
|
+
const [designRaw, tasksRaw] = await Promise.all([
|
|
188
|
+
readDefaultTemplate(projectPath, 'design-template'),
|
|
189
|
+
readDefaultTemplate(projectPath, 'tasks-template'),
|
|
190
|
+
]);
|
|
191
|
+
const designTemplate = replaceDesignTestingStrategy(designRaw, conventions);
|
|
192
|
+
const tasksTemplate = replaceTasksClosingSection(tasksRaw, conventions);
|
|
193
|
+
return { designTemplate, tasksTemplate };
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Write generated user-templates to `.spec-workflow/user-templates/`.
|
|
197
|
+
*
|
|
198
|
+
* IMPORTANT: If user-templates already exist, this function returns early
|
|
199
|
+
* without overwriting them. Users own their user-templates once created.
|
|
200
|
+
*/
|
|
201
|
+
export async function writeUserTemplates(projectPath, templates) {
|
|
202
|
+
const userTemplatesDir = join(projectPath, '.spec-workflow', 'user-templates');
|
|
203
|
+
const designPath = join(userTemplatesDir, 'design-template.md');
|
|
204
|
+
const tasksPath = join(userTemplatesDir, 'tasks-template.md');
|
|
205
|
+
// Check if either user-template already exists — if so, do not overwrite
|
|
206
|
+
if (await fileExists(designPath) || await fileExists(tasksPath)) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
// Create directory if needed
|
|
210
|
+
await mkdir(userTemplatesDir, { recursive: true });
|
|
211
|
+
// Write both templates
|
|
212
|
+
await Promise.all([
|
|
213
|
+
writeFile(designPath, templates.designTemplate, 'utf-8'),
|
|
214
|
+
writeFile(tasksPath, templates.tasksTemplate, 'utf-8'),
|
|
215
|
+
]);
|
|
216
|
+
}
|
|
217
|
+
//# sourceMappingURL=template-generator.js.map
|