@lbruton/specflow 3.1.0 → 3.2.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.
Files changed (44) hide show
  1. package/README.md +22 -16
  2. package/dist/core/__tests__/convention-detector.test.d.ts +2 -0
  3. package/dist/core/__tests__/convention-detector.test.d.ts.map +1 -0
  4. package/dist/core/__tests__/convention-detector.test.js +199 -0
  5. package/dist/core/__tests__/convention-detector.test.js.map +1 -0
  6. package/dist/core/__tests__/security-utils.test.js +2 -2
  7. package/dist/core/__tests__/security-utils.test.js.map +1 -1
  8. package/dist/core/__tests__/template-generator.test.d.ts +2 -0
  9. package/dist/core/__tests__/template-generator.test.d.ts.map +1 -0
  10. package/dist/core/__tests__/template-generator.test.js +167 -0
  11. package/dist/core/__tests__/template-generator.test.js.map +1 -0
  12. package/dist/core/convention-detector.d.ts +36 -0
  13. package/dist/core/convention-detector.d.ts.map +1 -0
  14. package/dist/core/convention-detector.js +298 -0
  15. package/dist/core/convention-detector.js.map +1 -0
  16. package/dist/core/security-utils.js +2 -2
  17. package/dist/core/security-utils.js.map +1 -1
  18. package/dist/core/template-generator.d.ts +21 -0
  19. package/dist/core/template-generator.d.ts.map +1 -0
  20. package/dist/core/template-generator.js +217 -0
  21. package/dist/core/template-generator.js.map +1 -0
  22. package/dist/markdown/templates/design-template.md +8 -6
  23. package/dist/markdown/templates/tasks-template.md +23 -20
  24. package/dist/prompts/index.d.ts.map +1 -1
  25. package/dist/prompts/index.js +4 -7
  26. package/dist/prompts/index.js.map +1 -1
  27. package/dist/tools/spec-status.d.ts.map +1 -1
  28. package/dist/tools/spec-status.js +35 -8
  29. package/dist/tools/spec-status.js.map +1 -1
  30. package/dist/tools/spec-workflow-guide.js +25 -15
  31. package/dist/tools/spec-workflow-guide.js.map +1 -1
  32. package/package.json +1 -1
  33. package/dist/prompts/audit.d.ts +0 -3
  34. package/dist/prompts/audit.d.ts.map +0 -1
  35. package/dist/prompts/audit.js +0 -267
  36. package/dist/prompts/audit.js.map +0 -1
  37. package/dist/prompts/prime.d.ts +0 -3
  38. package/dist/prompts/prime.d.ts.map +0 -1
  39. package/dist/prompts/prime.js +0 -290
  40. package/dist/prompts/prime.js.map +0 -1
  41. package/dist/prompts/wrap.d.ts +0 -3
  42. package/dist/prompts/wrap.d.ts.map +0 -1
  43. package/dist/prompts/wrap.js +0 -285
  44. 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":"AAAA,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AA0B5B,uDAAuD;AACvD,KAAK,UAAU,YAAY,CAAC,QAAgB;IAC1C,IAAI,CAAC;QACH,OAAO,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,iDAAiD;AACjD,KAAK,UAAU,WAAW,CAAC,OAAe;IACxC,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC;QAC9B,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,8BAA8B;AAC9B,KAAK,UAAU,UAAU,CAAC,QAAgB;IACxC,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC/B,OAAO,CAAC,CAAC,MAAM,EAAE,CAAC;IACpB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,iGAAiG;AACjG,KAAK,UAAU,aAAa,CAAC,WAAmB,EAAE,UAAoB;IACpE,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,MAAM,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC;YACnD,OAAO,SAAS,CAAC;QACnB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,6FAA6F;AAC7F,KAAK,UAAU,aAAa,CAAC,WAAmB;IAC9C,IAAI,SAAS,GAAkB,IAAI,CAAC;IACpC,IAAI,OAAO,GAAkB,IAAI,CAAC;IAClC,IAAI,UAAU,GAAkB,IAAI,CAAC;IACrC,IAAI,OAAO,GAAkB,IAAI,CAAC;IAClC,IAAI,cAAc,GAAG,KAAK,CAAC;IAE3B,+CAA+C;IAE/C,SAAS;IACT,MAAM,aAAa,GAAG;QACpB,kBAAkB,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,mBAAmB;KACjF,CAAC;IACF,MAAM,YAAY,GAAG,MAAM,aAAa,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IACrE,IAAI,YAAY,EAAE,CAAC;QACjB,SAAS,GAAG,QAAQ,CAAC;QACrB,OAAO,GAAG,YAAY,CAAC;QACvB,UAAU,GAAG,YAAY,CAAC;IAC5B,CAAC;IAED,kCAAkC;IAClC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,WAAW,GAAG;YAClB,gBAAgB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,kBAAkB;SAC7F,CAAC;QACF,MAAM,UAAU,GAAG,MAAM,aAAa,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;QACjE,IAAI,UAAU,EAAE,CAAC;YACf,SAAS,GAAG,MAAM,CAAC;YACnB,OAAO,GAAG,UAAU,CAAC;YACrB,UAAU,GAAG,UAAU,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,SAAS;IACT,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,aAAa,GAAG,CAAC,YAAY,EAAE,gBAAgB,EAAE,WAAW,CAAC,CAAC;QACpE,KAAK,MAAM,SAAS,IAAI,aAAa,EAAE,CAAC;YACtC,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC,CAAC;YACjE,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;gBACrB,6DAA6D;gBAC7D,IAAI,SAAS,KAAK,YAAY,EAAE,CAAC;oBAC/B,SAAS,GAAG,QAAQ,CAAC;oBACrB,OAAO,GAAG,QAAQ,CAAC;oBACnB,UAAU,GAAG,SAAS,CAAC;oBACvB,MAAM;gBACR,CAAC;gBACD,IAAI,SAAS,KAAK,gBAAgB,IAAI,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;oBACvE,SAAS,GAAG,QAAQ,CAAC;oBACrB,OAAO,GAAG,QAAQ,CAAC;oBACnB,UAAU,GAAG,SAAS,CAAC;oBACvB,MAAM;gBACR,CAAC;gBACD,IAAI,SAAS,KAAK,WAAW,IAAI,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC;oBACnE,SAAS,GAAG,QAAQ,CAAC;oBACrB,OAAO,GAAG,QAAQ,CAAC;oBACnB,UAAU,GAAG,SAAS,CAAC;oBACvB,MAAM;gBACR,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,6DAA6D;IAC7D,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,YAAY,GAAG,CAAC,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,eAAe,EAAE,cAAc,CAAC,CAAC;QACvG,MAAM,WAAW,GAAG,MAAM,aAAa,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;QACnE,IAAI,WAAW,EAAE,CAAC;YAChB,SAAS,GAAG,OAAO,CAAC;YACpB,OAAO,GAAG,WAAW,CAAC;YACtB,UAAU,GAAG,WAAW,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,qCAAqC;IACrC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,UAAU,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC,CAAC;QACzE,IAAI,UAAU,EAAE,CAAC;YACf,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;gBACnC,MAAM,UAAU,GAAuB,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC;gBAC1D,IAAI,UAAU,EAAE,CAAC;oBACf,2CAA2C;oBAC3C,IAAI,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;wBAClC,SAAS,GAAG,QAAQ,CAAC;wBACrB,UAAU,GAAG,cAAc,CAAC;oBAC9B,CAAC;yBAAM,IAAI,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;wBACvC,SAAS,GAAG,MAAM,CAAC;wBACnB,UAAU,GAAG,cAAc,CAAC;oBAC9B,CAAC;yBAAM,IAAI,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;wBACxC,SAAS,GAAG,OAAO,CAAC;wBACpB,UAAU,GAAG,cAAc,CAAC;oBAC9B,CAAC;yBAAM,IAAI,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;wBACzC,SAAS,GAAG,QAAQ,CAAC;wBACrB,UAAU,GAAG,cAAc,CAAC;oBAC9B,CAAC;oBACD,OAAO,GAAG,UAAU,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC;gBACnE,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,wBAAwB;YAC1B,CAAC;QACH,CAAC;IACH,CAAC;IAED,0CAA0C;IAC1C,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;IACzD,IAAI,MAAM,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC;QAClC,cAAc,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,SAAS,GAAG,SAAS,CAAC;YACtB,OAAO,GAAG,gBAAgB,CAAC;YAC3B,8CAA8C;YAC9C,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC;gBAC1C,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;gBAChE,OAAO,GAAG,qBAAqB,QAAQ,EAAE,CAAC;YAC5C,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,GAAG,UAAU,CAAC;YACvB,CAAC;QACH,CAAC;IACH,CAAC;IAED,yCAAyC;IACzC,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC;QACpE,IAAI,QAAQ,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;YAChF,cAAc,GAAG,IAAI,CAAC;QACxB,CAAC;IACH,CAAC;IAED,mCAAmC;IACnC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,iBAAiB,GAAG;YACxB,eAAe;YACf,QAAQ;YACR,OAAO;YACP,YAAY;SACb,CAAC;QACF,KAAK,MAAM,SAAS,IAAI,iBAAiB,EAAE,CAAC;YAC1C,MAAM,aAAa,GAAG,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC;YACtE,IAAI,MAAM,WAAW,CAAC,aAAa,CAAC,EAAE,CAAC;gBACrC,OAAO,GAAG,SAAS,CAAC;gBACpB,MAAM;YACR,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC;AACrE,CAAC;AAED,qCAAqC;AACrC,KAAK,UAAU,gBAAgB,CAAC,WAAmB;IACjD,IAAI,cAAc,GAAG,KAAK,CAAC;IAC3B,IAAI,QAAQ,GAAkB,IAAI,CAAC;IACnC,IAAI,cAAc,GAAkB,IAAI,CAAC;IACzC,MAAM,iBAAiB,GAAG,KAAK,CAAC;IAEhC,4BAA4B;IAC5B,MAAM,eAAe,GAAG,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAC;IACpE,IAAI,MAAM,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;QACtC,cAAc,GAAG,IAAI,CAAC;QACtB,QAAQ,GAAG,qBAAqB,CAAC;IACnC,CAAC;IAED,6BAA6B;IAC7B,MAAM,UAAU,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC,CAAC;IACzE,IAAI,UAAU,EAAE,CAAC;QACf,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;YACnC,IAAI,GAAG,EAAE,OAAO,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;gBACpD,cAAc,GAAG,GAAG,CAAC,OAAO,CAAC;YAC/B,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,wBAAwB;QAC1B,CAAC;IACH,CAAC;IAED,sBAAsB;IACtB,IAAI,CAAC,cAAc,IAAI,CAAC,cAAc,EAAE,CAAC;QACvC,MAAM,cAAc,GAAG,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;QACrD,MAAM,UAAU,GAAG,MAAM,YAAY,CAAC,cAAc,CAAC,CAAC;QACtD,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;YACxB,cAAc,GAAG,IAAI,CAAC;YACtB,QAAQ,GAAG,UAAU,CAAC;QACxB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,cAAc,EAAE,iBAAiB,EAAE,CAAC;AACzE,CAAC;AAED,4CAA4C;AAC5C,KAAK,UAAU,eAAe,CAAC,WAAmB;IAChD,IAAI,YAAY,GAAG,KAAK,CAAC;IACzB,IAAI,IAAI,GAAkB,IAAI,CAAC;IAC/B,IAAI,MAAM,GAAkB,IAAI,CAAC;IACjC,MAAM,gBAAgB,GAAG,KAAK,CAAC;IAE/B,MAAM,mBAAmB,GAAG,CAAC,cAAc,EAAE,YAAY,EAAE,YAAY,CAAC,CAAC;IACzE,KAAK,MAAM,SAAS,IAAI,mBAAmB,EAAE,CAAC;QAC5C,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC,CAAC;QACjE,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YACrB,YAAY,GAAG,IAAI,CAAC;YACpB,IAAI,GAAG,SAAS,CAAC;YACjB,MAAM,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAC;YACxC,MAAM;QACR,CAAC;IACH,CAAC;IAED,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC;AAC1D,CAAC;AAED,yEAAyE;AACzE,SAAS,qBAAqB,CAAC,OAAe;IAC5C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC/C,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEhC,sFAAsF;IACtF,MAAM,iBAAiB,GAAG,mCAAmC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC3E,MAAM,WAAW,GAAG,0DAA0D,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC5F,IAAI,iBAAiB,IAAI,WAAW,EAAE,CAAC;QACrC,OAAO,gBAAgB,CAAC;IAC1B,CAAC;IACD,+FAA+F;IAC/F,IAAI,iBAAiB,IAAI,qBAAqB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5D,OAAO,gBAAgB,CAAC;IAC1B,CAAC;IAED,0GAA0G;IAC1G,IAAI,oBAAoB,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QACzE,OAAO,cAAc,CAAC;IACxB,CAAC;IAED,iEAAiE;IACjE,IAAI,iBAAiB,EAAE,CAAC;QACtB,OAAO,gBAAgB,CAAC;IAC1B,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,WAAmB;IACzD,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,SAAS,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACzD,aAAa,CAAC,WAAW,CAAC;QAC1B,gBAAgB,CAAC,WAAW,CAAC;QAC7B,eAAe,CAAC,WAAW,CAAC;KAC7B,CAAC,CAAC;IAEH,OAAO;QACL,aAAa,EAAE,CAAC;QAChB,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACpC,OAAO;QACP,UAAU;QACV,SAAS;KACV,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,WAAmB,EAAE,WAA+B;IACzF,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAC;IAChD,IAAI,CAAC;QACH,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,uCAAuC;IACzC,CAAC;IACD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,0BAA0B,CAAC,CAAC;IACvD,MAAM,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;AAClF,CAAC"}
@@ -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 https://api.staktrakr.com`;
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 https://beta.staktrakr.com http://127.0.0.1:9778;`);
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":"AAAA;;;GAGG;AAGH,OAAO,EAAa,UAAU,EAAE,KAAK,EAAY,MAAM,aAAa,CAAC;AACrE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAG5B,iCAAiC;AACjC,MAAM,CAAC,MAAM,sBAAsB,GAAG,IAAI,CAAC;AAE3C,qDAAqD;AACrD,gFAAgF;AAChF,MAAM,CAAC,MAAM,uBAAuB,GAAmB;IACrD,gBAAgB,EAAE,IAAI;IACtB,kBAAkB,EAAE,GAAG,EAAE,sEAAsE;IAC/F,eAAe,EAAE,IAAI;IACrB,qBAAqB,EAAE,EAAE;IACzB,WAAW,EAAE,IAAI;IACjB,cAAc,EAAE,CAAC,oBAAoB,sBAAsB,EAAE,EAAE,oBAAoB,sBAAsB,EAAE,CAAC;CAC7G,CAAC;AAEF,wEAAwE;AACxE,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,CAAC;AAElC;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAC,IAAY;IACjD,MAAM,OAAO,GAAG,CAAC,oBAAoB,IAAI,EAAE,EAAE,oBAAoB,IAAI,EAAE,EAAE,6BAA6B,CAAC,CAAC;IAExG,gFAAgF;IAChF,mEAAmE;IACnE,uEAAuE;IACvE,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE,CAAC;QAC1C,OAAO,CAAC,IAAI,CAAC,oBAAoB,aAAa,EAAE,EAAE,oBAAoB,aAAa,EAAE,CAAC,CAAC;IACzF,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAe;IAChD,OAAO,OAAO,KAAK,WAAW;QACvB,OAAO,KAAK,KAAK,IAAI,iBAAiB;QACtC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,6CAA6C;AAClF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,UAAoC,EAAE,IAAa;IACnF,MAAM,UAAU,GAAG,IAAI,IAAI,sBAAsB,CAAC;IAElD,sFAAsF;IACtF,MAAM,qBAAqB,GAAG,sBAAsB,CAAC,UAAU,CAAC,CAAC;IAEjE,MAAM,MAAM,GAAG;QACb,GAAG,uBAAuB;QAC1B,cAAc,EAAE,qBAAqB;QACrC,GAAG,UAAU;KACd,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,OAAO,WAAW;IACd,QAAQ,GAA0B,IAAI,GAAG,EAAE,CAAC;IAC5C,MAAM,CAAiB;IAE/B,YAAY,MAAsB;QAChC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QAErB,oCAAoC;QACpC,WAAW,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,KAAK,CAAC,CAAC;IAC3C,CAAC;IAED;;OAEG;IACI,UAAU,CAAC,QAAgB;QAChC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,gBAAgB,EAAE,CAAC;YAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAC3B,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,kBAAkB;QAC1C,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC;QAEnD,6BAA6B;QAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QAEnD,+CAA+C;QAC/C,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,GAAG,SAAS,GAAG,QAAQ,CAAC,CAAC;QAEhF,0BAA0B;QAC1B,IAAI,cAAc,CAAC,MAAM,IAAI,WAAW,EAAE,CAAC;YACzC,MAAM,aAAa,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;YACxC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,aAAa,GAAG,QAAQ,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;YACtE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;QACxC,CAAC;QAED,sBAAsB;QACtB,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;QAE5C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC;IAED;;OAEG;IACI,UAAU;QACf,OAAO,KAAK,EAAE,OAAuB,EAAE,KAAmB,EAAE,EAAE;YAC5D,sCAAsC;YACtC,MAAM,QAAQ,GAAG,OAAO,CAAC,EAAE,IAAI,SAAS,CAAC;YAEzC,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;YAEzC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpB,OAAO,KAAK;qBACT,IAAI,CAAC,GAAG,CAAC;qBACT,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC;qBACtD,IAAI,CAAC;oBACJ,KAAK,EAAE,mBAAmB;oBAC1B,OAAO,EAAE,gCAAgC,IAAI,CAAC,MAAM,CAAC,kBAAkB,uBAAuB;oBAC9F,UAAU,EAAE,MAAM,CAAC,UAAU;iBAC9B,CAAC,CAAC;YACP,CAAC;QACH,CAAC,CAAC;IACJ,CAAC;IAED;;OAEG;IACK,OAAO;QACb,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,QAAQ,GAAG,KAAK,CAAC;QAEvB,KAAK,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC;YAC3D,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,GAAG,SAAS,GAAG,QAAQ,CAAC,CAAC;YAChF,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAChC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YACjC,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;YAC9C,CAAC;QACH,CAAC;IACH,CAAC;CACF;AAcD;;GAEG;AACH,MAAM,OAAO,WAAW;IACd,MAAM,CAAiB;IACvB,OAAO,CAAS;IAExB,YAAY,MAAsB,EAAE,aAAsB;QACxD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QAErB,2BAA2B;QAC3B,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;YACxB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,YAAY,CAAC;QACrC,CAAC;aAAM,IAAI,aAAa,EAAE,CAAC;YACzB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,aAAa,EAAE,gBAAgB,EAAE,WAAW,CAAC,CAAC;QACpE,CAAC;aAAM,CAAC;YACN,6BAA6B;YAC7B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,WAAW,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,UAAU;QACd,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC;YACjC,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;YACxC,MAAM,KAAK,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,iCAAiC,EAAE,KAAK,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,GAAG,CAAC,KAAoB;QAC5B,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC;YACjC,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;YAC7C,MAAM,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QACnD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,KAAK,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IAED;;OAEG;IACH,UAAU;QACR,OAAO,KAAK,EAAE,OAAuB,EAAE,KAAmB,EAAE,EAAE;YAC5D,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAE7B,qFAAqF;YACrF,KAAK,CAAC,IAAI,CACR,GAAG,EAAE;gBACH,MAAM,KAAK,GAAkB;oBAC3B,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;oBACnC,KAAK,EAAE,OAAO,CAAC,EAAE,IAAI,SAAS;oBAC9B,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,EAAE;oBAC1C,QAAQ,EAAE,OAAO,CAAC,GAAG;oBACrB,MAAM,EAAE,KAAK,CAAC,UAAU,GAAG,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,KAAK,GAAG,IAAI,KAAK,CAAC,UAAU,KAAK,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;oBACxH,OAAO,EAAE;wBACP,UAAU,EAAE,KAAK,CAAC,UAAU;wBAC5B,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;wBAChC,SAAS,EAAE,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC;qBACzC;iBACF,CAAC;gBAEF,kDAAkD;gBAClD,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YAClC,CAAC,EACD,GAAG,EAAE,GAAE,CAAC,CAAC,gCAAgC;aAC1C,CAAC;QACJ,CAAC,CAAC;IACJ,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,UAAU,+BAA+B,CAAC,IAAa;IAC3D,MAAM,UAAU,GAAG,IAAI,IAAI,sBAAsB,CAAC;IAElD,uDAAuD;IACvD,IAAI,UAAU,GAAG,yBAAyB,UAAU,mBAAmB,UAAU,4BAA4B,CAAC;IAE9G,yEAAyE;IACzE,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE,CAAC;QAC1C,UAAU,IAAI,mBAAmB,aAAa,mBAAmB,aAAa,EAAE,CAAC;IACnF,CAAC;IAED,OAAO,KAAK,EAAE,OAAuB,EAAE,KAAmB,EAAE,EAAE;QAC5D,uBAAuB;QACvB,KAAK,CAAC,MAAM,CAAC,wBAAwB,EAAE,SAAS,CAAC,CAAC,CAAC,6BAA6B;QAChF,KAAK,CAAC,MAAM,CAAC,iBAAiB,EAAE,YAAY,CAAC,CAAC,CAAC,4BAA4B;QAC3E,KAAK,CAAC,MAAM,CAAC,kBAAkB,EAAE,eAAe,CAAC,CAAC,CAAC,wBAAwB;QAC3E,KAAK,CAAC,MAAM,CAAC,iBAAiB,EAAE,iCAAiC,CAAC,CAAC,CAAC,2BAA2B;QAE/F,oBAAoB;QACpB,yFAAyF;QACzF,+EAA+E;QAC/E,KAAK,CAAC,MAAM,CACV,yBAAyB,EACzB,uJAAuJ,UAAU,0CAA0C,CAC5M,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,MAAsB;IAClD,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;QACxB,OAAO,KAAK,CAAC,CAAC,eAAe;IAC/B,CAAC;IAED,OAAO;QACL,MAAM,EAAE,CAAC,MAAc,EAAE,QAAwD,EAAE,EAAE;YACnF,sDAAsD;YACtD,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;gBACrB,OAAO;YACT,CAAC;YAED,qCAAqC;YACrC,IAAI,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC3C,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YACvB,CAAC;iBAAM,CAAC;gBACN,QAAQ,CAAC,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC,CAAC;YAC7C,CAAC;QACH,CAAC;QACD,WAAW,EAAE,IAAI;QACjB,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,CAAC;QACpD,cAAc,EAAE,CAAC,cAAc,CAAC;KACjC,CAAC;AACJ,CAAC"}
@@ -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