fraim-framework 2.0.34 → 2.0.36

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 (49) hide show
  1. package/bin/fraim.js +52 -5
  2. package/dist/registry/scripts/cleanup-branch.js +62 -33
  3. package/dist/registry/scripts/generate-engagement-emails.js +119 -44
  4. package/dist/registry/scripts/newsletter-helpers.js +208 -268
  5. package/dist/registry/scripts/profile-server.js +387 -0
  6. package/dist/tests/test-chalk-regression.js +18 -2
  7. package/dist/tests/test-client-scripts-validation.js +133 -0
  8. package/dist/tests/test-markdown-to-pdf.js +454 -0
  9. package/dist/tests/test-script-location-independence.js +76 -28
  10. package/package.json +5 -2
  11. package/registry/agent-guardrails.md +62 -62
  12. package/registry/rules/communication.md +121 -121
  13. package/registry/rules/continuous-learning.md +54 -54
  14. package/registry/rules/hitl-ppe-record-analysis.md +302 -302
  15. package/registry/rules/software-development-lifecycle.md +104 -104
  16. package/registry/scripts/cleanup-branch.ts +341 -0
  17. package/registry/scripts/code-quality-check.sh +559 -559
  18. package/registry/scripts/detect-tautological-tests.sh +38 -38
  19. package/registry/scripts/generate-engagement-emails.ts +830 -0
  20. package/registry/scripts/markdown-to-pdf.js +395 -0
  21. package/registry/scripts/newsletter-helpers.ts +777 -0
  22. package/registry/scripts/profile-server.ts +424 -0
  23. package/registry/scripts/run-thank-you-workflow.ts +122 -0
  24. package/registry/scripts/send-newsletter-simple.ts +102 -0
  25. package/registry/scripts/send-thank-you-emails.ts +57 -0
  26. package/registry/scripts/validate-openapi-limits.ts +366 -366
  27. package/registry/scripts/validate-test-coverage.ts +280 -280
  28. package/registry/scripts/verify-pr-comments.sh +70 -70
  29. package/registry/templates/bootstrap/ARCHITECTURE-TEMPLATE.md +53 -53
  30. package/registry/templates/evidence/Implementation-BugEvidence.md +85 -85
  31. package/registry/templates/evidence/Implementation-FeatureEvidence.md +120 -120
  32. package/registry/workflows/convert-to-pdf.md +235 -0
  33. package/registry/workflows/customer-development/insight-analysis.md +156 -156
  34. package/registry/workflows/customer-development/interview-preparation.md +421 -421
  35. package/registry/workflows/customer-development/strategic-brainstorming.md +146 -146
  36. package/registry/workflows/quality-assurance/iterative-improvement-cycle.md +562 -562
  37. package/registry/workflows/reviewer/review-implementation-vs-feature-spec.md +669 -669
  38. package/dist/registry/scripts/build-scripts-generator.js +0 -205
  39. package/dist/registry/scripts/fraim-config.js +0 -61
  40. package/dist/registry/scripts/generic-issues-api.js +0 -100
  41. package/dist/registry/scripts/openapi-generator.js +0 -664
  42. package/dist/registry/scripts/performance/profile-server.js +0 -390
  43. package/dist/test-utils.js +0 -96
  44. package/dist/tests/esm-compat.js +0 -11
  45. package/dist/tests/test-chalk-esm-issue.js +0 -159
  46. package/dist/tests/test-chalk-real-world.js +0 -265
  47. package/dist/tests/test-chalk-resolution-issue.js +0 -304
  48. package/dist/tests/test-fraim-install-chalk-issue.js +0 -254
  49. package/dist/tests/test-npm-resolution-diagnostic.js +0 -140
@@ -0,0 +1,454 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const node_child_process_1 = require("node:child_process");
7
+ const test_utils_1 = require("./test-utils");
8
+ const node_assert_1 = __importDefault(require("node:assert"));
9
+ const fs_1 = __importDefault(require("fs"));
10
+ const path_1 = __importDefault(require("path"));
11
+ const os_1 = __importDefault(require("os"));
12
+ async function testScriptExists() {
13
+ console.log(' 🚀 Testing Script Exists...');
14
+ try {
15
+ const scriptPath = (0, test_utils_1.resolveProjectPath)('registry/scripts/markdown-to-pdf.js');
16
+ // Check if script file exists
17
+ node_assert_1.default.ok(fs_1.default.existsSync(scriptPath), 'markdown-to-pdf.js script should exist');
18
+ // Check if script is readable
19
+ const stats = fs_1.default.statSync(scriptPath);
20
+ node_assert_1.default.ok(stats.isFile(), 'Script should be a file');
21
+ node_assert_1.default.ok(stats.size > 0, 'Script should not be empty');
22
+ // Check script content has required components
23
+ const scriptContent = fs_1.default.readFileSync(scriptPath, 'utf-8');
24
+ node_assert_1.default.ok(scriptContent.includes('markdownToHtml'), 'Script should contain markdownToHtml function');
25
+ node_assert_1.default.ok(scriptContent.includes('htmlToPdf'), 'Script should contain htmlToPdf function');
26
+ node_assert_1.default.ok(scriptContent.includes('parseArgs'), 'Script should contain parseArgs function');
27
+ node_assert_1.default.ok(scriptContent.includes('#!/usr/bin/env node'), 'Script should have proper shebang');
28
+ node_assert_1.default.ok(scriptContent.includes('process.cwd()'), 'Script should use process.cwd() for project directory');
29
+ node_assert_1.default.ok(scriptContent.includes('.fraim/config.json'), 'Script should read from .fraim/config.json');
30
+ console.log(' ✅ Script exists and follows dev tooling principles!');
31
+ return true;
32
+ }
33
+ catch (error) {
34
+ console.error(' ❌ Script existence test failed:', error);
35
+ return false;
36
+ }
37
+ }
38
+ async function testScriptHelp() {
39
+ console.log(' 🚀 Testing Script Help...');
40
+ const tempDir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'fraim-pdf-help-test-'));
41
+ try {
42
+ const scriptPath = (0, test_utils_1.resolveProjectPath)('registry/scripts/markdown-to-pdf.js');
43
+ // Test help command
44
+ const helpResult = await runNodeScript(scriptPath, ['--help'], tempDir);
45
+ // Should exit with code 0 for help, or 1 if dependencies missing
46
+ if (helpResult.code === 1 && (helpResult.stderr + helpResult.stdout).includes('Missing required packages')) {
47
+ console.log(' ⚠️ Dependencies not available, help shows dependency error (expected)');
48
+ return true;
49
+ }
50
+ node_assert_1.default.strictEqual(helpResult.code, 0, 'Help command should exit with code 0');
51
+ // Should contain usage information
52
+ node_assert_1.default.ok(helpResult.stdout.includes('Usage:'), 'Help should contain usage information');
53
+ node_assert_1.default.ok(helpResult.stdout.includes('Options:'), 'Help should contain options information');
54
+ node_assert_1.default.ok(helpResult.stdout.includes('Examples:'), 'Help should contain examples');
55
+ node_assert_1.default.ok(helpResult.stdout.includes('--format'), 'Help should mention format option');
56
+ node_assert_1.default.ok(helpResult.stdout.includes('--margin'), 'Help should mention margin option');
57
+ console.log(' ✅ Script help functionality verified!');
58
+ return true;
59
+ }
60
+ catch (error) {
61
+ console.error(' ❌ Script help test failed:', error);
62
+ return false;
63
+ }
64
+ finally {
65
+ try {
66
+ fs_1.default.rmSync(tempDir, { recursive: true, force: true });
67
+ }
68
+ catch (e) { }
69
+ }
70
+ }
71
+ async function testDependencyCheck() {
72
+ console.log(' 🚀 Testing Dependency Check...');
73
+ const tempDir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'fraim-pdf-deps-test-'));
74
+ try {
75
+ const scriptPath = (0, test_utils_1.resolveProjectPath)('registry/scripts/markdown-to-pdf.js');
76
+ // Create a simple test markdown file
77
+ const testMarkdown = '# Test\n\nThis is a test document.';
78
+ const inputFile = path_1.default.join(tempDir, 'test.md');
79
+ fs_1.default.writeFileSync(inputFile, testMarkdown);
80
+ // Try to run script (will fail if dependencies missing, but should give clear error)
81
+ const result = await runNodeScript(scriptPath, [inputFile], tempDir);
82
+ // If dependencies are missing, should get specific error message
83
+ if (result.code !== 0) {
84
+ // Check for dependency error message
85
+ const output = result.stderr + result.stdout;
86
+ if (output.includes('Missing required packages')) {
87
+ console.log(' ⚠️ Dependencies not installed (expected in test environment)');
88
+ node_assert_1.default.ok(output.includes('npm install'), 'Should suggest npm install command');
89
+ return true;
90
+ }
91
+ }
92
+ else {
93
+ // If successful, verify PDF was created
94
+ const outputFile = path_1.default.join(tempDir, 'test.pdf');
95
+ if (fs_1.default.existsSync(outputFile)) {
96
+ console.log(' ✅ Dependencies available and conversion successful!');
97
+ return true;
98
+ }
99
+ }
100
+ console.log(' ✅ Dependency check behavior verified!');
101
+ return true;
102
+ }
103
+ catch (error) {
104
+ console.error(' ❌ Dependency check test failed:', error);
105
+ return false;
106
+ }
107
+ finally {
108
+ try {
109
+ fs_1.default.rmSync(tempDir, { recursive: true, force: true });
110
+ }
111
+ catch (e) { }
112
+ }
113
+ }
114
+ async function testArgumentParsing() {
115
+ console.log(' 🚀 Testing Argument Parsing...');
116
+ try {
117
+ const scriptPath = (0, test_utils_1.resolveProjectPath)('registry/scripts/markdown-to-pdf.js');
118
+ // Test the parseArgs function by requiring the module
119
+ // Note: This tests the function directly without running the full script
120
+ const scriptModule = require(scriptPath);
121
+ // Mock process.argv for testing
122
+ const originalArgv = process.argv;
123
+ const originalCwd = process.cwd;
124
+ try {
125
+ // Mock process.cwd to return a test directory
126
+ process.cwd = () => '/test/project';
127
+ // Test basic input/output parsing
128
+ process.argv = ['node', 'script.js', 'input.md'];
129
+ let config = scriptModule.parseArgs();
130
+ node_assert_1.default.ok(config.input.endsWith('input.md'), 'Should parse input file');
131
+ node_assert_1.default.ok(config.output.endsWith('.pdf'), 'Should generate PDF output name');
132
+ // Test with explicit output
133
+ process.argv = ['node', 'script.js', 'input.md', 'output.pdf'];
134
+ config = scriptModule.parseArgs();
135
+ node_assert_1.default.ok(config.input.endsWith('input.md'), 'Should parse input file');
136
+ node_assert_1.default.ok(config.output.endsWith('output.pdf'), 'Should parse output file');
137
+ // Test with options
138
+ process.argv = ['node', 'script.js', 'input.md', '--format', 'Letter', '--margin', '1'];
139
+ config = scriptModule.parseArgs();
140
+ node_assert_1.default.strictEqual(config.format, 'Letter', 'Should parse format option');
141
+ node_assert_1.default.strictEqual(config.margin, '1', 'Should parse margin option');
142
+ // Test landscape option
143
+ process.argv = ['node', 'script.js', 'input.md', '--landscape'];
144
+ config = scriptModule.parseArgs();
145
+ node_assert_1.default.strictEqual(config.landscape, true, 'Should parse landscape option');
146
+ // Test no-background option
147
+ process.argv = ['node', 'script.js', 'input.md', '--no-background'];
148
+ config = scriptModule.parseArgs();
149
+ node_assert_1.default.strictEqual(config.background, false, 'Should parse no-background option');
150
+ }
151
+ finally {
152
+ process.argv = originalArgv;
153
+ process.cwd = originalCwd;
154
+ }
155
+ console.log(' ✅ Argument parsing verified!');
156
+ return true;
157
+ }
158
+ catch (error) {
159
+ console.error(' ❌ Argument parsing test failed:', error);
160
+ return false;
161
+ }
162
+ }
163
+ async function testMarkdownToHtml() {
164
+ console.log(' 🚀 Testing Markdown to HTML Conversion...');
165
+ try {
166
+ // Skip this test if dependencies are not available
167
+ try {
168
+ require.resolve('markdown-it');
169
+ require.resolve('markdown-it-highlightjs');
170
+ }
171
+ catch (error) {
172
+ console.log(' ⚠️ Dependencies not available, skipping HTML conversion test');
173
+ return true;
174
+ }
175
+ const scriptPath = (0, test_utils_1.resolveProjectPath)('registry/scripts/markdown-to-pdf.js');
176
+ // Test the markdownToHtml function directly
177
+ const scriptModule = require(scriptPath);
178
+ // Test basic markdown conversion
179
+ const basicMarkdown = '# Test Header\n\nThis is **bold** and *italic* text.\n\n```javascript\nconsole.log("Hello");\n```';
180
+ const html = await scriptModule.markdownToHtml(basicMarkdown);
181
+ // Verify HTML structure
182
+ node_assert_1.default.ok(html.includes('<!DOCTYPE html>'), 'Should generate complete HTML document');
183
+ node_assert_1.default.ok(html.includes('<h1>Test Header</h1>'), 'Should convert headers');
184
+ node_assert_1.default.ok(html.includes('<strong>bold</strong>'), 'Should convert bold text');
185
+ node_assert_1.default.ok(html.includes('<em>italic</em>'), 'Should convert italic text');
186
+ node_assert_1.default.ok(html.includes('<pre>'), 'Should convert code blocks');
187
+ node_assert_1.default.ok(html.includes('<style>'), 'Should include CSS styles');
188
+ // Test table conversion
189
+ const tableMarkdown = '| Name | Age |\n|------|-----|\n| John | 30 |\n| Jane | 25 |';
190
+ const tableHtml = await scriptModule.markdownToHtml(tableMarkdown);
191
+ node_assert_1.default.ok(tableHtml.includes('<table>'), 'Should convert tables');
192
+ node_assert_1.default.ok(tableHtml.includes('<th>Name</th>'), 'Should convert table headers');
193
+ node_assert_1.default.ok(tableHtml.includes('<td>John</td>'), 'Should convert table cells');
194
+ console.log(' ✅ Markdown to HTML conversion verified!');
195
+ return true;
196
+ }
197
+ catch (error) {
198
+ console.error(' ❌ Markdown to HTML test failed:', error);
199
+ return false;
200
+ }
201
+ }
202
+ async function testFileValidation() {
203
+ console.log(' 🚀 Testing File Validation...');
204
+ const tempDir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'fraim-pdf-validation-test-'));
205
+ try {
206
+ const scriptPath = (0, test_utils_1.resolveProjectPath)('registry/scripts/markdown-to-pdf.js');
207
+ // Test with non-existent file
208
+ const nonExistentFile = 'nonexistent.md';
209
+ const result1 = await runNodeScript(scriptPath, [nonExistentFile], tempDir);
210
+ node_assert_1.default.notStrictEqual(result1.code, 0, 'Should fail with non-existent file');
211
+ const output1 = result1.stderr + result1.stdout;
212
+ // Check for either file not found or dependency missing error
213
+ const hasFileError = output1.includes('not found') || output1.includes('ENOENT');
214
+ const hasDependencyError = output1.includes('Missing required packages');
215
+ node_assert_1.default.ok(hasFileError || hasDependencyError, 'Should indicate file not found or dependency missing');
216
+ // Test with empty file
217
+ const emptyFile = path_1.default.join(tempDir, 'empty.md');
218
+ fs_1.default.writeFileSync(emptyFile, '');
219
+ const result2 = await runNodeScript(scriptPath, ['empty.md'], tempDir);
220
+ // Empty file should either succeed (creating empty PDF) or fail gracefully
221
+ if (result2.code !== 0) {
222
+ console.log(' ⚠️ Empty file handling varies by environment');
223
+ }
224
+ // Test with valid markdown file
225
+ const validFile = path_1.default.join(tempDir, 'valid.md');
226
+ fs_1.default.writeFileSync(validFile, '# Valid Document\n\nThis is valid markdown.');
227
+ const result3 = await runNodeScript(scriptPath, ['valid.md'], tempDir);
228
+ // Should either succeed or fail due to missing dependencies
229
+ if (result3.code !== 0) {
230
+ const output3 = result3.stderr + result3.stdout;
231
+ if (!output3.includes('Missing required packages')) {
232
+ console.log(' ⚠️ Unexpected error with valid file:', output3);
233
+ }
234
+ }
235
+ console.log(' ✅ File validation behavior verified!');
236
+ return true;
237
+ }
238
+ catch (error) {
239
+ console.error(' ❌ File validation test failed:', error);
240
+ return false;
241
+ }
242
+ finally {
243
+ try {
244
+ fs_1.default.rmSync(tempDir, { recursive: true, force: true });
245
+ }
246
+ catch (e) { }
247
+ }
248
+ }
249
+ async function testOutputDirectoryCreation() {
250
+ console.log(' 🚀 Testing Output Directory Creation...');
251
+ const tempDir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'fraim-pdf-output-test-'));
252
+ try {
253
+ const scriptPath = (0, test_utils_1.resolveProjectPath)('registry/scripts/markdown-to-pdf.js');
254
+ // Create test markdown file
255
+ const inputFile = path_1.default.join(tempDir, 'test.md');
256
+ fs_1.default.writeFileSync(inputFile, '# Test\n\nTest content.');
257
+ // Test output to nested directory that doesn't exist
258
+ const nestedOutputDir = path_1.default.join(tempDir, 'output', 'pdfs');
259
+ const outputFile = path_1.default.join(nestedOutputDir, 'test.pdf');
260
+ const result = await runNodeScript(scriptPath, [inputFile, outputFile], tempDir);
261
+ // Should either succeed (creating directories) or fail due to dependencies
262
+ if (result.code === 0) {
263
+ // If successful, verify directory was created
264
+ node_assert_1.default.ok(fs_1.default.existsSync(nestedOutputDir), 'Should create output directory');
265
+ node_assert_1.default.ok(fs_1.default.existsSync(outputFile), 'Should create output file');
266
+ }
267
+ else {
268
+ // If failed due to dependencies, that's expected
269
+ const output = result.stderr + result.stdout;
270
+ if (output.includes('Missing required packages')) {
271
+ console.log(' ⚠️ Dependencies not available (expected in test environment)');
272
+ }
273
+ else {
274
+ // Other errors might indicate directory creation issues
275
+ console.log(' ⚠️ Output directory test inconclusive due to environment');
276
+ }
277
+ }
278
+ console.log(' ✅ Output directory creation behavior verified!');
279
+ return true;
280
+ }
281
+ catch (error) {
282
+ console.error(' ❌ Output directory test failed:', error);
283
+ return false;
284
+ }
285
+ finally {
286
+ try {
287
+ fs_1.default.rmSync(tempDir, { recursive: true, force: true });
288
+ }
289
+ catch (e) { }
290
+ }
291
+ }
292
+ async function testCrossPlatformCompatibility() {
293
+ console.log(' 🚀 Testing Cross-Platform Compatibility...');
294
+ const tempDir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'fraim-pdf-platform-test-'));
295
+ try {
296
+ const scriptPath = (0, test_utils_1.resolveProjectPath)('registry/scripts/markdown-to-pdf.js');
297
+ // Create test file with platform-specific path handling
298
+ const inputFile = path_1.default.join(tempDir, 'platform-test.md');
299
+ const markdownContent = `# Platform Test
300
+
301
+ This is a test for platform compatibility.
302
+
303
+ ## Platform Info
304
+ - OS: ${process.platform}
305
+ - Architecture: ${process.arch}
306
+ - Node Version: ${process.version}
307
+
308
+ ## Path Handling
309
+ Input file: ${inputFile}
310
+ Temp directory: ${tempDir}
311
+ `;
312
+ fs_1.default.writeFileSync(inputFile, markdownContent);
313
+ // Test with different path formats
314
+ const outputFile = path_1.default.join(tempDir, 'platform-test.pdf');
315
+ const result = await runNodeScript(scriptPath, [inputFile, outputFile], tempDir);
316
+ // Verify script handles paths correctly regardless of platform
317
+ if (result.code === 0) {
318
+ console.log(' ✅ Cross-platform conversion successful!');
319
+ }
320
+ else {
321
+ const output = result.stderr + result.stdout;
322
+ if (output.includes('Missing required packages')) {
323
+ console.log(' ⚠️ Dependencies not available (expected in test environment)');
324
+ }
325
+ else {
326
+ // Check for platform-specific issues
327
+ node_assert_1.default.ok(!output.includes('ENOTDIR'), 'Should handle directory paths correctly');
328
+ node_assert_1.default.ok(!output.includes('Invalid path'), 'Should handle path formats correctly');
329
+ }
330
+ }
331
+ console.log(' ✅ Cross-platform compatibility verified!');
332
+ return true;
333
+ }
334
+ catch (error) {
335
+ console.error(' ❌ Cross-platform test failed:', error);
336
+ return false;
337
+ }
338
+ finally {
339
+ try {
340
+ fs_1.default.rmSync(tempDir, { recursive: true, force: true });
341
+ }
342
+ catch (e) { }
343
+ }
344
+ }
345
+ async function testErrorHandling() {
346
+ console.log(' 🚀 Testing Error Handling...');
347
+ const tempDir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'fraim-pdf-error-test-'));
348
+ try {
349
+ const scriptPath = (0, test_utils_1.resolveProjectPath)('registry/scripts/markdown-to-pdf.js');
350
+ // Test with invalid arguments
351
+ const result1 = await runNodeScript(scriptPath, [], tempDir);
352
+ node_assert_1.default.notStrictEqual(result1.code, 0, 'Should fail with no arguments');
353
+ // Test with invalid format
354
+ const inputFile = path_1.default.join(tempDir, 'test.md');
355
+ fs_1.default.writeFileSync(inputFile, '# Test');
356
+ const result2 = await runNodeScript(scriptPath, [inputFile, '--format', 'InvalidFormat'], tempDir);
357
+ // Should either handle gracefully or fail with clear error
358
+ // Test with invalid margin
359
+ const result3 = await runNodeScript(scriptPath, [inputFile, '--margin', 'invalid'], tempDir);
360
+ // Should either handle gracefully or fail with clear error
361
+ // Test with non-existent CSS file
362
+ const result4 = await runNodeScript(scriptPath, [inputFile, '--css', 'nonexistent.css'], tempDir);
363
+ // Should either handle gracefully or fail with clear error
364
+ console.log(' ✅ Error handling behavior verified!');
365
+ return true;
366
+ }
367
+ catch (error) {
368
+ console.error(' ❌ Error handling test failed:', error);
369
+ return false;
370
+ }
371
+ finally {
372
+ try {
373
+ fs_1.default.rmSync(tempDir, { recursive: true, force: true });
374
+ }
375
+ catch (e) { }
376
+ }
377
+ }
378
+ // Helper function to run Node.js script
379
+ function runNodeScript(scriptPath, args, cwd) {
380
+ return new Promise((resolve) => {
381
+ const ps = (0, node_child_process_1.spawn)('node', [scriptPath, ...args], {
382
+ cwd,
383
+ env: process.env,
384
+ shell: true
385
+ });
386
+ let stdout = '';
387
+ let stderr = '';
388
+ ps.stdout.on('data', d => stdout += d.toString());
389
+ ps.stderr.on('data', d => stderr += d.toString());
390
+ ps.on('close', (code) => {
391
+ resolve({ stdout, stderr, code });
392
+ });
393
+ });
394
+ }
395
+ async function runMarkdownToPdfTest(testCase) {
396
+ return await testCase.testFunction();
397
+ }
398
+ const testCases = [
399
+ {
400
+ name: 'Script Exists',
401
+ description: 'Tests that the markdown-to-pdf script exists and has required components',
402
+ testFunction: testScriptExists,
403
+ tags: ['markdown-to-pdf', 'basic']
404
+ },
405
+ {
406
+ name: 'Script Help',
407
+ description: 'Tests that the script provides helpful usage information',
408
+ testFunction: testScriptHelp,
409
+ tags: ['markdown-to-pdf', 'help']
410
+ },
411
+ {
412
+ name: 'Dependency Check',
413
+ description: 'Tests that the script properly checks for required dependencies',
414
+ testFunction: testDependencyCheck,
415
+ tags: ['markdown-to-pdf', 'dependencies']
416
+ },
417
+ {
418
+ name: 'Argument Parsing',
419
+ description: 'Tests that command line arguments are parsed correctly',
420
+ testFunction: testArgumentParsing,
421
+ tags: ['markdown-to-pdf', 'args']
422
+ },
423
+ {
424
+ name: 'Markdown to HTML',
425
+ description: 'Tests that markdown is converted to HTML correctly',
426
+ testFunction: testMarkdownToHtml,
427
+ tags: ['markdown-to-pdf', 'conversion']
428
+ },
429
+ {
430
+ name: 'File Validation',
431
+ description: 'Tests that input file validation works correctly',
432
+ testFunction: testFileValidation,
433
+ tags: ['markdown-to-pdf', 'validation']
434
+ },
435
+ {
436
+ name: 'Output Directory Creation',
437
+ description: 'Tests that output directories are created when needed',
438
+ testFunction: testOutputDirectoryCreation,
439
+ tags: ['markdown-to-pdf', 'output']
440
+ },
441
+ {
442
+ name: 'Cross-Platform Compatibility',
443
+ description: 'Tests that the script works across different operating systems',
444
+ testFunction: testCrossPlatformCompatibility,
445
+ tags: ['markdown-to-pdf', 'cross-platform']
446
+ },
447
+ {
448
+ name: 'Error Handling',
449
+ description: 'Tests that errors are handled gracefully with clear messages',
450
+ testFunction: testErrorHandling,
451
+ tags: ['markdown-to-pdf', 'error-handling']
452
+ }
453
+ ];
454
+ (0, test_utils_1.runTests)(testCases, runMarkdownToPdfTest, 'Markdown to PDF Script Tests');
@@ -89,24 +89,47 @@ async function testScriptLocationIndependence() {
89
89
  if (fs_1.default.existsSync(prepIssueScript)) {
90
90
  try {
91
91
  const { execSync } = await Promise.resolve().then(() => __importStar(require('child_process')));
92
- // Use Git Bash on Windows, regular bash on Unix
93
- const bashCommand = process.platform === 'win32'
94
- ? `"C:\\Program Files\\Git\\bin\\bash.exe" "${prepIssueScript}" --help`
95
- : `"${prepIssueScript}" --help`;
96
- const output = execSync(bashCommand, {
97
- cwd: tempProjectDir,
98
- encoding: 'utf-8',
99
- timeout: 10000
100
- });
92
+ // On Windows, we need to check if Git Bash is available
93
+ if (process.platform === 'win32') {
94
+ const gitBashPaths = [
95
+ 'C:\\Program Files\\Git\\bin\\bash.exe',
96
+ 'C:\\Program Files (x86)\\Git\\bin\\bash.exe'
97
+ ];
98
+ let bashPath = null;
99
+ for (const path of gitBashPaths) {
100
+ if (fs_1.default.existsSync(path)) {
101
+ bashPath = path;
102
+ break;
103
+ }
104
+ }
105
+ if (!bashPath) {
106
+ console.log(' ⚠️ Git Bash not found on Windows, skipping bash script tests');
107
+ console.log(' ✅ Script location independence test completed (Windows limitation)');
108
+ return true;
109
+ }
110
+ const bashCommand = `"${bashPath}" "${prepIssueScript}" --help`;
111
+ const output = execSync(bashCommand, {
112
+ cwd: tempProjectDir,
113
+ encoding: 'utf-8',
114
+ timeout: 10000
115
+ });
116
+ }
117
+ else {
118
+ // Unix systems
119
+ const output = execSync(`"${prepIssueScript}" --help`, {
120
+ cwd: tempProjectDir,
121
+ encoding: 'utf-8',
122
+ timeout: 10000
123
+ });
124
+ }
101
125
  // If we get here, the script at least started successfully
102
126
  console.log(' ✅ prep-issue.sh executed successfully from user directory');
103
127
  }
104
128
  catch (error) {
105
129
  // The script may fail due to missing repo, but as long as it started, that's OK
106
- if (process.platform === 'win32' && error.message.includes('not recognized')) {
107
- console.log(' ⚠️ Git Bash not found on Windows, skipping prep-issue test');
108
- }
109
- else if (error.message.includes('Repository not found') || error.message.includes('fatal: repository')) {
130
+ if (error.message.includes('Repository not found') ||
131
+ error.message.includes('fatal: repository') ||
132
+ error.message.includes('not a git repository')) {
110
133
  // This is expected - the test repo doesn't exist, but the script ran
111
134
  console.log(' ✅ prep-issue.sh executed from user directory (repo not found is expected)');
112
135
  }
@@ -116,31 +139,56 @@ async function testScriptLocationIndependence() {
116
139
  }
117
140
  }
118
141
  }
142
+ else {
143
+ console.log(' ⚠️ prep-issue.sh not found, skipping test');
144
+ }
119
145
  // Test 2: Try to execute code-quality-check.sh (this will likely fail due to dependencies)
120
146
  console.log(' Testing code-quality-check.sh execution from user directory...');
121
147
  const qualityCheckScript = path_1.default.join(userScriptsDir, 'code-quality-check.sh');
122
148
  if (fs_1.default.existsSync(qualityCheckScript)) {
123
149
  try {
124
150
  const { execSync } = await Promise.resolve().then(() => __importStar(require('child_process')));
125
- const bashCommand = process.platform === 'win32'
126
- ? `"C:\\Program Files\\Git\\bin\\bash.exe" "${qualityCheckScript}" --help`
127
- : `"${qualityCheckScript}" --help`;
128
- const output = execSync(bashCommand, {
129
- cwd: tempProjectDir,
130
- encoding: 'utf-8',
131
- timeout: 10000
132
- });
133
- console.log(' ✅ code-quality-check.sh executed successfully from user directory');
134
- }
135
- catch (error) {
136
- if (process.platform === 'win32' && error.message.includes('not recognized')) {
137
- console.log(' ⚠️ Git Bash not found on Windows, skipping quality check test');
151
+ if (process.platform === 'win32') {
152
+ const gitBashPaths = [
153
+ 'C:\\Program Files\\Git\\bin\\bash.exe',
154
+ 'C:\\Program Files (x86)\\Git\\bin\\bash.exe'
155
+ ];
156
+ let bashPath = null;
157
+ for (const path of gitBashPaths) {
158
+ if (fs_1.default.existsSync(path)) {
159
+ bashPath = path;
160
+ break;
161
+ }
162
+ }
163
+ if (!bashPath) {
164
+ console.log(' ⚠️ Git Bash not found on Windows, skipping quality check test');
165
+ }
166
+ else {
167
+ const bashCommand = `"${bashPath}" "${qualityCheckScript}" --help`;
168
+ const output = execSync(bashCommand, {
169
+ cwd: tempProjectDir,
170
+ encoding: 'utf-8',
171
+ timeout: 10000
172
+ });
173
+ console.log(' ✅ code-quality-check.sh executed successfully from user directory');
174
+ }
138
175
  }
139
176
  else {
140
- console.log(' ❌ code-quality-check.sh failed (expected due to dependencies):', error.message);
141
- // This is expected to fail - we'll document this as a known issue
177
+ const output = execSync(`"${qualityCheckScript}" --help`, {
178
+ cwd: tempProjectDir,
179
+ encoding: 'utf-8',
180
+ timeout: 10000
181
+ });
182
+ console.log(' ✅ code-quality-check.sh executed successfully from user directory');
142
183
  }
143
184
  }
185
+ catch (error) {
186
+ console.log(' ❌ code-quality-check.sh failed (expected due to dependencies):', error.message);
187
+ // This is expected to fail - we'll document this as a known issue
188
+ }
189
+ }
190
+ else {
191
+ console.log(' ⚠️ code-quality-check.sh not found, skipping test');
144
192
  }
145
193
  console.log(' ✅ Script location independence test completed');
146
194
  return true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fraim-framework",
3
- "version": "2.0.34",
3
+ "version": "2.0.36",
4
4
  "description": "FRAIM v2: Framework for Rigor-based AI Management - Transform from solo developer to AI manager orchestrating production-ready code with enterprise-grade discipline",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -11,7 +11,7 @@
11
11
  "setup": "node setup.js",
12
12
  "dev": "tsx --watch src/fraim-mcp-server.ts",
13
13
  "build": "tsc && npm run validate:registry",
14
- "test": "tsx --test tests/**/*.ts > test.log 2>&1",
14
+ "test": "tsx --test > test.log 2>&1",
15
15
  "start:fraim": "tsx src/fraim-mcp-server.ts",
16
16
  "dev:fraim": "tsx --watch src/fraim-mcp-server.ts",
17
17
  "watch:fraimlogs": "tsx scripts/watch-fraim-logs.ts",
@@ -88,8 +88,11 @@
88
88
  "cors": "^2.8.5",
89
89
  "dotenv": "^16.4.7",
90
90
  "express": "^5.2.1",
91
+ "markdown-it": "^14.1.0",
92
+ "markdown-it-highlightjs": "^4.2.0",
91
93
  "mongodb": "^7.0.0",
92
94
  "prompts": "^2.4.2",
95
+ "puppeteer": "^24.35.0",
93
96
  "tree-kill": "^1.2.2"
94
97
  }
95
98
  }