fraim-framework 2.0.27 โ†’ 2.0.33

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 (130) hide show
  1. package/.github/workflows/deploy-fraim.yml +1 -1
  2. package/dist/registry/scripts/build-scripts-generator.js +205 -0
  3. package/dist/registry/scripts/cleanup-branch.js +258 -0
  4. package/dist/registry/scripts/evaluate-code-quality.js +66 -0
  5. package/dist/registry/scripts/exec-with-timeout.js +142 -0
  6. package/dist/registry/scripts/fraim-config.js +61 -0
  7. package/dist/registry/scripts/generate-engagement-emails.js +630 -0
  8. package/dist/registry/scripts/generic-issues-api.js +100 -0
  9. package/dist/registry/scripts/newsletter-helpers.js +731 -0
  10. package/dist/registry/scripts/openapi-generator.js +664 -0
  11. package/{registry/scripts/performance/profile-server.ts โ†’ dist/registry/scripts/performance/profile-server.js} +390 -368
  12. package/dist/registry/scripts/run-thank-you-workflow.js +92 -0
  13. package/dist/registry/scripts/send-newsletter-simple.js +85 -0
  14. package/dist/registry/scripts/send-thank-you-emails.js +54 -0
  15. package/dist/registry/scripts/validate-openapi-limits.js +311 -0
  16. package/dist/registry/scripts/validate-test-coverage.js +262 -0
  17. package/dist/registry/scripts/verify-test-coverage.js +66 -0
  18. package/dist/src/cli/commands/init.js +42 -15
  19. package/dist/src/cli/commands/sync.js +22 -5
  20. package/dist/src/cli/fraim.js +24 -22
  21. package/dist/src/cli/setup/first-run.js +13 -6
  22. package/dist/src/fraim/db-service.js +26 -15
  23. package/dist/src/fraim/issues.js +67 -0
  24. package/dist/src/fraim-mcp-server.js +272 -18
  25. package/dist/src/utils/git-utils.js +1 -1
  26. package/dist/src/utils/script-sync-utils.js +218 -0
  27. package/dist/tests/debug-tools.js +80 -0
  28. package/dist/tests/esm-compat.js +11 -0
  29. package/dist/tests/test-chalk-esm-issue.js +159 -0
  30. package/dist/tests/test-chalk-real-world.js +265 -0
  31. package/dist/tests/test-chalk-regression.js +377 -0
  32. package/dist/tests/test-chalk-resolution-issue.js +304 -0
  33. package/dist/tests/test-cli.js +70 -5
  34. package/dist/tests/test-end-to-end-hybrid-validation.js +349 -0
  35. package/dist/tests/test-first-run-journey.js +43 -3
  36. package/dist/tests/test-fraim-install-chalk-issue.js +254 -0
  37. package/dist/tests/test-fraim-issues.js +59 -0
  38. package/dist/tests/test-genericization.js +1 -1
  39. package/dist/tests/test-hybrid-script-execution.js +369 -0
  40. package/dist/tests/test-mcp-connection.js +166 -0
  41. package/dist/tests/test-mcp-issue-integration.js +152 -0
  42. package/dist/tests/test-mcp-lifecycle-methods.js +312 -0
  43. package/dist/tests/test-node-compatibility.js +93 -0
  44. package/dist/tests/test-npm-install.js +66 -0
  45. package/dist/tests/test-npm-resolution-diagnostic.js +140 -0
  46. package/dist/tests/test-prep-issue.js +4 -1
  47. package/dist/tests/test-script-location-independence.js +173 -0
  48. package/dist/tests/test-script-sync.js +557 -0
  49. package/dist/tests/test-session-rehydration.js +145 -0
  50. package/dist/tests/test-standalone.js +5 -11
  51. package/dist/tests/test-sync-version-update.js +1 -1
  52. package/dist/tests/test-telemetry.js +190 -0
  53. package/dist/tests/test-user-journey.js +8 -4
  54. package/dist/tests/test-utils.js +13 -0
  55. package/dist/tests/test-wizard.js +2 -2
  56. package/package.json +11 -9
  57. package/registry/agent-guardrails.md +62 -54
  58. package/registry/rules/agent-success-criteria.md +52 -0
  59. package/registry/rules/agent-testing-guidelines.md +7 -7
  60. package/registry/rules/communication.md +121 -121
  61. package/registry/rules/continuous-learning.md +54 -54
  62. package/registry/rules/ephemeral-execution.md +39 -24
  63. package/registry/rules/hitl-ppe-record-analysis.md +302 -302
  64. package/registry/rules/local-development.md +7 -5
  65. package/registry/rules/software-development-lifecycle.md +104 -104
  66. package/registry/rules/successful-debugging-patterns.md +29 -16
  67. package/registry/rules/telemetry.md +67 -0
  68. package/registry/scripts/code-quality-check.sh +559 -559
  69. package/registry/scripts/detect-tautological-tests.sh +38 -38
  70. package/registry/scripts/evaluate-code-quality.ts +1 -1
  71. package/registry/scripts/prep-issue.sh +16 -3
  72. package/registry/scripts/validate-openapi-limits.ts +366 -365
  73. package/registry/scripts/validate-test-coverage.ts +280 -280
  74. package/registry/scripts/verify-pr-comments.sh +70 -70
  75. package/registry/scripts/verify-test-coverage.ts +1 -1
  76. package/registry/templates/bootstrap/ARCHITECTURE-TEMPLATE.md +53 -53
  77. package/registry/templates/evidence/Implementation-BugEvidence.md +85 -85
  78. package/registry/templates/evidence/Implementation-FeatureEvidence.md +120 -120
  79. package/registry/templates/marketing/HBR-ARTICLE-TEMPLATE.md +66 -0
  80. package/registry/workflows/bootstrap/create-architecture.md +2 -2
  81. package/registry/workflows/bootstrap/evaluate-code-quality.md +10 -4
  82. package/registry/workflows/bootstrap/verify-test-coverage.md +9 -3
  83. package/registry/workflows/customer-development/insight-analysis.md +156 -156
  84. package/registry/workflows/customer-development/interview-preparation.md +421 -421
  85. package/registry/workflows/customer-development/strategic-brainstorming.md +146 -146
  86. package/registry/workflows/customer-development/thank-customers.md +14 -2
  87. package/registry/workflows/customer-development/weekly-newsletter.md +27 -13
  88. package/registry/workflows/improve-fraim/contribute.md +32 -0
  89. package/registry/workflows/improve-fraim/file-issue.md +32 -0
  90. package/registry/workflows/marketing/hbr-article.md +73 -0
  91. package/registry/workflows/performance/analyze-performance.md +10 -4
  92. package/registry/workflows/product-building/design.md +3 -2
  93. package/registry/workflows/product-building/implement.md +10 -5
  94. package/registry/workflows/product-building/prep-issue.md +16 -18
  95. package/registry/workflows/product-building/resolve.md +8 -3
  96. package/registry/workflows/product-building/retrospect.md +3 -2
  97. package/registry/workflows/product-building/spec.md +5 -4
  98. package/registry/workflows/product-building/test.md +3 -2
  99. package/registry/workflows/quality-assurance/iterative-improvement-cycle.md +562 -562
  100. package/registry/workflows/replicate/replicate-discovery.md +336 -0
  101. package/registry/workflows/replicate/replicate-to-issues.md +319 -0
  102. package/registry/workflows/reviewer/review-implementation-vs-design-spec.md +3 -3
  103. package/registry/workflows/reviewer/review-implementation-vs-feature-spec.md +669 -669
  104. package/tsconfig.json +2 -1
  105. package/.windsurf/rules/windsurf-rules.md +0 -7
  106. package/.windsurf/workflows/resolve-issue.md +0 -6
  107. package/.windsurf/workflows/retrospect.md +0 -6
  108. package/.windsurf/workflows/start-design.md +0 -6
  109. package/.windsurf/workflows/start-impl.md +0 -6
  110. package/.windsurf/workflows/start-spec.md +0 -6
  111. package/.windsurf/workflows/start-tests.md +0 -6
  112. package/bin/fraim.js +0 -23
  113. package/registry/scripts/build-scripts-generator.ts +0 -215
  114. package/registry/scripts/cleanup-branch.ts +0 -284
  115. package/registry/scripts/fraim-config.ts +0 -63
  116. package/registry/scripts/generate-engagement-emails.ts +0 -744
  117. package/registry/scripts/generic-issues-api.ts +0 -150
  118. package/registry/scripts/newsletter-helpers.ts +0 -874
  119. package/registry/scripts/openapi-generator.ts +0 -693
  120. package/registry/scripts/run-thank-you-workflow.ts +0 -122
  121. package/registry/scripts/send-newsletter-simple.ts +0 -104
  122. package/registry/scripts/send-thank-you-emails.ts +0 -57
  123. package/registry/workflows/replicate/re-implementation-strategy.md +0 -226
  124. package/registry/workflows/replicate/use-case-extraction.md +0 -135
  125. package/registry/workflows/replicate/visual-analysis.md +0 -154
  126. package/registry/workflows/replicate/website-discovery-analysis.md +0 -231
  127. package/sample_package.json +0 -18
  128. /package/registry/scripts/{replicate/comprehensive-explorer.py โ†’ comprehensive-explorer.py} +0 -0
  129. /package/registry/scripts/{replicate/interactive-explorer.py โ†’ interactive-explorer.py} +0 -0
  130. /package/registry/scripts/{replicate/scrape-site.py โ†’ scrape-site.py} +0 -0
@@ -0,0 +1,377 @@
1
+ "use strict";
2
+ /**
3
+ * Regression test for chalk ESM issue
4
+ *
5
+ * This test ensures that fraim-framework can be installed alongside
6
+ * chalk v5 without getting ERR_REQUIRE_ESM errors.
7
+ *
8
+ * Run with: npx tsx tests/test-chalk-regression.ts
9
+ */
10
+ var __importDefault = (this && this.__importDefault) || function (mod) {
11
+ return (mod && mod.__esModule) ? mod : { "default": mod };
12
+ };
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ const node_child_process_1 = require("node:child_process");
15
+ const test_utils_1 = require("./test-utils");
16
+ const fs_1 = __importDefault(require("fs"));
17
+ const path_1 = __importDefault(require("path"));
18
+ const os_1 = __importDefault(require("os"));
19
+ async function runCommand(command, args, cwd) {
20
+ return new Promise((resolve) => {
21
+ const proc = (0, node_child_process_1.spawn)(command, args, {
22
+ cwd,
23
+ stdio: 'pipe',
24
+ shell: true
25
+ });
26
+ let stdout = '';
27
+ let stderr = '';
28
+ proc.stdout?.on('data', (data) => {
29
+ stdout += data.toString();
30
+ });
31
+ proc.stderr?.on('data', (data) => {
32
+ stderr += data.toString();
33
+ });
34
+ proc.on('close', (code) => {
35
+ resolve({ code, stdout, stderr });
36
+ });
37
+ });
38
+ }
39
+ async function testChalkConflictScenario() {
40
+ console.log(' ๐Ÿงช Testing chalk conflict scenario (regression test)...');
41
+ console.log(' This ensures pinned chalk v4 works even with chalk v5 present\n');
42
+ const tempDir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'chalk-regression-'));
43
+ console.log(` ๐Ÿ“‚ Temp dir: ${tempDir}`);
44
+ let tarballPath = null;
45
+ try {
46
+ // 1. Pack fraim-framework
47
+ console.log(' ๐Ÿ“ฆ Packing fraim-framework...');
48
+ const projectRoot = process.cwd();
49
+ // Clean up any existing tarballs first
50
+ const existingTarballs = fs_1.default.readdirSync(projectRoot).filter(f => f.startsWith('fraim-framework-') && f.endsWith('.tgz'));
51
+ for (const tarball of existingTarballs) {
52
+ try {
53
+ fs_1.default.unlinkSync(path_1.default.join(projectRoot, tarball));
54
+ }
55
+ catch (e) {
56
+ // Ignore cleanup errors
57
+ }
58
+ }
59
+ const packResult = (0, node_child_process_1.execSync)('npm pack', {
60
+ cwd: projectRoot,
61
+ encoding: 'utf-8'
62
+ });
63
+ const tarballName = packResult.trim().split('\n').pop()?.trim();
64
+ if (!tarballName) {
65
+ console.log(' โŒ Failed to create tarball');
66
+ return false;
67
+ }
68
+ tarballPath = path_1.default.join(projectRoot, tarballName);
69
+ console.log(` โœ… Created: ${tarballName}`);
70
+ // 2. Create test project with chalk v5
71
+ console.log(' ๐Ÿ“ Creating test project with chalk v5...');
72
+ const testPackageJson = {
73
+ name: 'chalk-regression-test',
74
+ version: '1.0.0',
75
+ dependencies: {
76
+ 'chalk': '^5.0.0'
77
+ }
78
+ };
79
+ fs_1.default.writeFileSync(path_1.default.join(tempDir, 'package.json'), JSON.stringify(testPackageJson, null, 2));
80
+ // 3. Install chalk v5
81
+ console.log(' ๐Ÿ“ฅ Installing chalk v5 first...');
82
+ const installChalkResult = await runCommand('npm', ['install', '--silent'], tempDir);
83
+ if (installChalkResult.code !== 0) {
84
+ console.log(' โš ๏ธ Failed to install chalk v5');
85
+ }
86
+ // 4. Install fraim-framework
87
+ console.log(' ๐Ÿ“ฅ Installing fraim-framework...');
88
+ const installFraimResult = await runCommand('npm', ['install', tarballPath, '--silent'], tempDir);
89
+ if (installFraimResult.code !== 0) {
90
+ console.log(' โš ๏ธ npm install had issues');
91
+ }
92
+ // 5. Check chalk versions
93
+ console.log(' ๐Ÿ“‹ Checking chalk versions...');
94
+ const lsResult = await runCommand('npm', ['ls', 'chalk'], tempDir);
95
+ console.log(lsResult.stdout);
96
+ // Verify fraim has its own chalk v4
97
+ const fraimChalkPath = path_1.default.join(tempDir, 'node_modules', 'fraim-framework', 'node_modules', 'chalk', 'package.json');
98
+ const rootChalkPath = path_1.default.join(tempDir, 'node_modules', 'chalk', 'package.json');
99
+ let fraimChalkVersion = null;
100
+ let rootChalkVersion = null;
101
+ if (fs_1.default.existsSync(rootChalkPath)) {
102
+ const pkg = JSON.parse(fs_1.default.readFileSync(rootChalkPath, 'utf-8'));
103
+ rootChalkVersion = pkg.version;
104
+ console.log(` ๐Ÿ“Œ Root chalk: ${rootChalkVersion}`);
105
+ }
106
+ if (fs_1.default.existsSync(fraimChalkPath)) {
107
+ const pkg = JSON.parse(fs_1.default.readFileSync(fraimChalkPath, 'utf-8'));
108
+ fraimChalkVersion = pkg.version;
109
+ console.log(` ๐Ÿ“Œ fraim-framework's chalk: ${fraimChalkVersion}`);
110
+ }
111
+ else {
112
+ console.log(' โš ๏ธ fraim-framework has no separate chalk');
113
+ }
114
+ // 6. Test if fraim CLI can be required
115
+ console.log(' ๐Ÿš€ Testing if fraim CLI can be required...');
116
+ // Create a test that explicitly checks for ERR_REQUIRE_ESM
117
+ const testScript = `
118
+ try {
119
+ const chalk = require('chalk');
120
+ console.log('โœ“ Chalk loaded successfully');
121
+ } catch (error) {
122
+ console.error('โœ— Failed to load chalk: ' + error.message);
123
+ process.exit(2);
124
+ }
125
+
126
+ try {
127
+ const fraimCli = require('./node_modules/fraim-framework/dist/src/cli/fraim.js');
128
+ console.log('โœ“ FRAIM CLI loaded successfully');
129
+ console.log('โœ“ No ERR_REQUIRE_ESM error');
130
+ process.exit(0);
131
+ } catch (error) {
132
+ if (error.code === 'ERR_REQUIRE_ESM') {
133
+ console.error('โœ— ERR_REQUIRE_ESM: ' + error.message);
134
+ process.exit(1);
135
+ } else {
136
+ console.error('โœ— Other error: ' + error.message);
137
+ process.exit(2);
138
+ }
139
+ }
140
+ `;
141
+ fs_1.default.writeFileSync(path_1.default.join(tempDir, 'test.js'), testScript);
142
+ const testResult = await runCommand('node', ['test.js'], tempDir);
143
+ console.log(' Output:');
144
+ testResult.stdout.split('\n').forEach(line => {
145
+ if (line.trim())
146
+ console.log(` ${line}`);
147
+ });
148
+ // Only show stderr if there was an actual error (non-zero exit code)
149
+ if (testResult.code !== 0 && testResult.stderr) {
150
+ console.log(' Errors:');
151
+ testResult.stderr.split('\n').forEach(line => {
152
+ if (line.trim())
153
+ console.log(` ${line}`);
154
+ });
155
+ }
156
+ // 7. Evaluate result
157
+ // The CLI will show help and exit with non-zero code when loaded without args
158
+ // We need to check if it actually loaded (no ERR_REQUIRE_ESM) vs failed to load
159
+ const hasERR_REQUIRE_ESM = testResult.stderr.includes('ERR_REQUIRE_ESM') || testResult.stdout.includes('ERR_REQUIRE_ESM');
160
+ const cliLoaded = testResult.stdout.includes('โœ“ FRAIM CLI loaded successfully') || testResult.stderr.includes('Usage: fraim');
161
+ // Also check if fraim-framework has its own chalk v4
162
+ const hasNestedChalk = fraimChalkVersion && fraimChalkVersion.startsWith('4.');
163
+ if (cliLoaded && !hasERR_REQUIRE_ESM) {
164
+ console.log(' โœ… SUCCESS: fraim CLI loaded without ERR_REQUIRE_ESM');
165
+ console.log(' โœ… Pinned chalk v4 works even with chalk v5 present');
166
+ // Verify fraim has its own chalk v4
167
+ if (hasNestedChalk) {
168
+ console.log(' โœ… fraim-framework correctly has chalk v4');
169
+ }
170
+ else {
171
+ console.log(' โš ๏ธ WARNING: fraim-framework has no nested chalk v4');
172
+ console.log(' โš ๏ธ This might cause issues in some environments');
173
+ console.log(' โš ๏ธ But CLI loaded successfully, so test passes');
174
+ }
175
+ if (tarballPath && fs_1.default.existsSync(tarballPath)) {
176
+ fs_1.default.unlinkSync(tarballPath);
177
+ }
178
+ return true;
179
+ }
180
+ else if (hasERR_REQUIRE_ESM) {
181
+ console.log(' โŒ REGRESSION: Got ERR_REQUIRE_ESM error!');
182
+ console.log(' โŒ The chalk fix is broken');
183
+ if (!hasNestedChalk) {
184
+ console.log(' โŒ fraim-framework has no nested chalk v4 - using root v5');
185
+ }
186
+ else {
187
+ console.log(' โŒ fraim-framework has chalk v4 but still got error (unexpected)');
188
+ }
189
+ if (tarballPath && fs_1.default.existsSync(tarballPath)) {
190
+ fs_1.default.unlinkSync(tarballPath);
191
+ }
192
+ return false;
193
+ }
194
+ else {
195
+ console.log(' โŒ Got unexpected error (exit code: ' + testResult.code + ')');
196
+ console.log(' โŒ Check the error output above');
197
+ if (tarballPath && fs_1.default.existsSync(tarballPath)) {
198
+ fs_1.default.unlinkSync(tarballPath);
199
+ }
200
+ return false;
201
+ }
202
+ }
203
+ catch (error) {
204
+ console.error(' โŒ Conflict scenario test failed with exception:', error);
205
+ console.error(' โŒ This is likely a test infrastructure issue, not a chalk issue');
206
+ if (tarballPath && fs_1.default.existsSync(tarballPath)) {
207
+ try {
208
+ fs_1.default.unlinkSync(tarballPath);
209
+ }
210
+ catch (e) {
211
+ // Ignore cleanup errors
212
+ }
213
+ }
214
+ return false;
215
+ }
216
+ finally {
217
+ try {
218
+ fs_1.default.rmSync(tempDir, { recursive: true, force: true });
219
+ console.log(' ๐Ÿงน Cleaned up temp directory');
220
+ }
221
+ catch (e) {
222
+ console.log(' โš ๏ธ Could not clean up temp directory');
223
+ }
224
+ }
225
+ }
226
+ async function testFreshInstall() {
227
+ console.log(' ๐Ÿงช Testing fresh install (no conflicts)...');
228
+ console.log(' This simulates: npx fraim-framework init\n');
229
+ const tempDir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'chalk-fresh-'));
230
+ console.log(` ๐Ÿ“‚ Temp dir: ${tempDir}`);
231
+ let tarballPath = null;
232
+ try {
233
+ // 1. Pack fraim-framework
234
+ console.log(' ๐Ÿ“ฆ Packing fraim-framework...');
235
+ const projectRoot = process.cwd();
236
+ // Clean up any existing tarballs first
237
+ const existingTarballs = fs_1.default.readdirSync(projectRoot).filter(f => f.startsWith('fraim-framework-') && f.endsWith('.tgz'));
238
+ for (const tarball of existingTarballs) {
239
+ try {
240
+ fs_1.default.unlinkSync(path_1.default.join(projectRoot, tarball));
241
+ }
242
+ catch (e) {
243
+ // Ignore cleanup errors
244
+ }
245
+ }
246
+ const packResult = (0, node_child_process_1.execSync)('npm pack', {
247
+ cwd: projectRoot,
248
+ encoding: 'utf-8'
249
+ });
250
+ const tarballName = packResult.trim().split('\n').pop()?.trim();
251
+ if (!tarballName) {
252
+ console.log(' โŒ Failed to create tarball');
253
+ return false;
254
+ }
255
+ tarballPath = path_1.default.join(projectRoot, tarballName);
256
+ console.log(` โœ… Created: ${tarballName}`);
257
+ // 2. Create empty project
258
+ console.log(' ๐Ÿ“ Creating empty project...');
259
+ const testPackageJson = {
260
+ name: 'fresh-install-test',
261
+ version: '1.0.0'
262
+ };
263
+ fs_1.default.writeFileSync(path_1.default.join(tempDir, 'package.json'), JSON.stringify(testPackageJson, null, 2));
264
+ // 3. Install fraim-framework
265
+ console.log(' ๐Ÿ“ฅ Installing fraim-framework...');
266
+ await runCommand('npm', ['install', tarballPath, '--silent'], tempDir);
267
+ // 4. Check chalk version
268
+ const chalkPath = path_1.default.join(tempDir, 'node_modules', 'chalk', 'package.json');
269
+ if (fs_1.default.existsSync(chalkPath)) {
270
+ const pkg = JSON.parse(fs_1.default.readFileSync(chalkPath, 'utf-8'));
271
+ console.log(` ๐Ÿ“Œ Installed chalk: ${pkg.version}`);
272
+ if (!pkg.version.startsWith('4.')) {
273
+ console.log(` โŒ Wrong chalk version! Expected 4.x, got ${pkg.version}`);
274
+ fs_1.default.unlinkSync(tarballPath);
275
+ return false;
276
+ }
277
+ }
278
+ // 5. Test if fraim CLI can be required
279
+ console.log(' ๐Ÿš€ Testing if fraim CLI can be required...');
280
+ const testScript = `
281
+ try {
282
+ const fraimCli = require('./node_modules/fraim-framework/dist/src/cli/fraim.js');
283
+ console.log('โœ“ FRAIM CLI loaded successfully');
284
+ process.exit(0);
285
+ } catch (error) {
286
+ if (error.code === 'ERR_REQUIRE_ESM') {
287
+ console.error('โœ— ERR_REQUIRE_ESM: ' + error.message);
288
+ process.exit(1);
289
+ } else {
290
+ console.error('โœ— Other error: ' + error.message);
291
+ process.exit(2);
292
+ }
293
+ }
294
+ `;
295
+ fs_1.default.writeFileSync(path_1.default.join(tempDir, 'test.js'), testScript);
296
+ const testResult = await runCommand('node', ['test.js'], tempDir);
297
+ console.log(' Output:');
298
+ testResult.stdout.split('\n').forEach(line => {
299
+ if (line.trim())
300
+ console.log(` ${line}`);
301
+ });
302
+ // Only show stderr if there was an actual error
303
+ if (testResult.code !== 0 && testResult.stderr) {
304
+ console.log(' Errors:');
305
+ testResult.stderr.split('\n').forEach(line => {
306
+ if (line.trim())
307
+ console.log(` ${line}`);
308
+ });
309
+ }
310
+ // Check if CLI loaded successfully
311
+ // The CLI will show help when loaded without args, which goes to stderr
312
+ const hasERR_REQUIRE_ESM = testResult.stderr.includes('ERR_REQUIRE_ESM') || testResult.stdout.includes('ERR_REQUIRE_ESM');
313
+ const cliLoaded = testResult.stdout.includes('โœ“ FRAIM CLI loaded successfully') || testResult.stderr.includes('Usage: fraim');
314
+ if (cliLoaded && !hasERR_REQUIRE_ESM) {
315
+ console.log(' โœ… SUCCESS: Fresh install works correctly');
316
+ if (tarballPath && fs_1.default.existsSync(tarballPath)) {
317
+ fs_1.default.unlinkSync(tarballPath);
318
+ }
319
+ return true;
320
+ }
321
+ else if (hasERR_REQUIRE_ESM) {
322
+ console.log(' โŒ REGRESSION: Got ERR_REQUIRE_ESM error!');
323
+ if (tarballPath && fs_1.default.existsSync(tarballPath)) {
324
+ fs_1.default.unlinkSync(tarballPath);
325
+ }
326
+ return false;
327
+ }
328
+ else {
329
+ console.log(' โŒ Got unexpected error (exit code: ' + testResult.code + ')');
330
+ console.log(' โŒ Check the error output above');
331
+ if (tarballPath && fs_1.default.existsSync(tarballPath)) {
332
+ fs_1.default.unlinkSync(tarballPath);
333
+ }
334
+ return false;
335
+ }
336
+ }
337
+ catch (error) {
338
+ console.error(' โŒ Fresh install test failed with exception:', error);
339
+ console.error(' โŒ This is likely a test infrastructure issue, not a chalk issue');
340
+ if (tarballPath && fs_1.default.existsSync(tarballPath)) {
341
+ try {
342
+ fs_1.default.unlinkSync(tarballPath);
343
+ }
344
+ catch (e) {
345
+ // Ignore cleanup errors
346
+ }
347
+ }
348
+ return false;
349
+ }
350
+ finally {
351
+ try {
352
+ fs_1.default.rmSync(tempDir, { recursive: true, force: true });
353
+ console.log(' ๐Ÿงน Cleaned up temp directory');
354
+ }
355
+ catch (e) {
356
+ console.log(' โš ๏ธ Could not clean up temp directory');
357
+ }
358
+ }
359
+ }
360
+ async function runChalkRegressionTest(testCase) {
361
+ return await testCase.testFunction();
362
+ }
363
+ const testCases = [
364
+ {
365
+ name: 'Fresh Install Test',
366
+ description: 'Verifies fraim-framework installs with correct chalk version in fresh project',
367
+ testFunction: testFreshInstall,
368
+ tags: ['regression', 'chalk', 'fresh-install']
369
+ },
370
+ {
371
+ name: 'Chalk Conflict Scenario',
372
+ description: 'Verifies fraim-framework works when chalk v5 is present (regression test)',
373
+ testFunction: testChalkConflictScenario,
374
+ tags: ['regression', 'chalk', 'conflict']
375
+ }
376
+ ];
377
+ (0, test_utils_1.runTests)(testCases, runChalkRegressionTest, 'Chalk ESM Regression Test');
@@ -0,0 +1,304 @@
1
+ "use strict";
2
+ /**
3
+ * Test to reproduce and verify the fix for the chalk v5 resolution issue
4
+ *
5
+ * This test creates a scenario where npm might resolve chalk to v5 by:
6
+ * 1. Creating a dependency that requires chalk v5
7
+ * 2. Testing if fraim-framework with ^4.1.2 gets upgraded
8
+ * 3. Testing if fraim-framework with 4.1.2 (pinned) stays at v4
9
+ */
10
+ var __importDefault = (this && this.__importDefault) || function (mod) {
11
+ return (mod && mod.__esModule) ? mod : { "default": mod };
12
+ };
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ const node_child_process_1 = require("node:child_process");
15
+ const test_utils_1 = require("./test-utils");
16
+ const fs_1 = __importDefault(require("fs"));
17
+ const path_1 = __importDefault(require("path"));
18
+ const os_1 = __importDefault(require("os"));
19
+ async function runCommand(command, args, cwd) {
20
+ return new Promise((resolve) => {
21
+ const proc = (0, node_child_process_1.spawn)(command, args, {
22
+ cwd,
23
+ stdio: 'pipe',
24
+ shell: true
25
+ });
26
+ let stdout = '';
27
+ let stderr = '';
28
+ proc.stdout?.on('data', (data) => {
29
+ stdout += data.toString();
30
+ });
31
+ proc.stderr?.on('data', (data) => {
32
+ stderr += data.toString();
33
+ });
34
+ proc.on('close', (code) => {
35
+ resolve({ code, stdout, stderr });
36
+ });
37
+ });
38
+ }
39
+ async function testChalkResolutionWithConflict() {
40
+ console.log(' ๐Ÿงช Testing chalk resolution with conflicting dependency...');
41
+ const tempDir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'chalk-conflict-'));
42
+ console.log(` ๐Ÿ“‚ Created temp dir: ${tempDir}`);
43
+ try {
44
+ // 1. Create a package that depends on chalk v5
45
+ console.log(' ๐Ÿ“ฆ Creating fake package that requires chalk v5...');
46
+ const fakePackageDir = path_1.default.join(tempDir, 'fake-chalk5-package');
47
+ fs_1.default.mkdirSync(fakePackageDir, { recursive: true });
48
+ const fakePackageJson = {
49
+ name: 'fake-chalk5-package',
50
+ version: '1.0.0',
51
+ dependencies: {
52
+ 'chalk': '^5.0.0'
53
+ }
54
+ };
55
+ fs_1.default.writeFileSync(path_1.default.join(fakePackageDir, 'package.json'), JSON.stringify(fakePackageJson, null, 2));
56
+ // Create a simple index.js that uses chalk
57
+ fs_1.default.writeFileSync(path_1.default.join(fakePackageDir, 'index.js'), 'export { default as chalk } from "chalk";\n');
58
+ // 2. Pack fraim-framework with ^4.1.2 (unpinned)
59
+ console.log(' ๐Ÿ“ฆ Packing fraim-framework with ^4.1.2...');
60
+ const projectRoot = process.cwd();
61
+ const packageJsonPath = path_1.default.join(projectRoot, 'package.json');
62
+ const originalPackageJson = fs_1.default.readFileSync(packageJsonPath, 'utf-8');
63
+ const packageJson = JSON.parse(originalPackageJson);
64
+ // Temporarily change to ^4.1.2
65
+ packageJson.dependencies.chalk = '^4.1.2';
66
+ fs_1.default.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
67
+ const packResult = (0, node_child_process_1.execSync)('npm pack', {
68
+ cwd: projectRoot,
69
+ encoding: 'utf-8'
70
+ });
71
+ const tarballName = packResult.trim().split('\n').pop()?.trim();
72
+ if (!tarballName) {
73
+ fs_1.default.writeFileSync(packageJsonPath, originalPackageJson);
74
+ return false;
75
+ }
76
+ const tarballPath = path_1.default.join(projectRoot, tarballName);
77
+ // Restore original package.json
78
+ fs_1.default.writeFileSync(packageJsonPath, originalPackageJson);
79
+ // 3. Create test project that depends on BOTH packages
80
+ console.log(' ๐Ÿ”ง Creating test project with conflicting dependencies...');
81
+ const testPackageJson = {
82
+ name: 'chalk-conflict-test',
83
+ version: '1.0.0',
84
+ dependencies: {
85
+ 'fake-chalk5-package': 'file:./fake-chalk5-package',
86
+ 'fraim-framework': `file:${tarballPath}`
87
+ }
88
+ };
89
+ fs_1.default.writeFileSync(path_1.default.join(tempDir, 'package.json'), JSON.stringify(testPackageJson, null, 2));
90
+ // 4. Install dependencies - npm will try to resolve chalk
91
+ console.log(' ๐Ÿ“ฅ Installing with conflicting chalk requirements...');
92
+ console.log(' โš ๏ธ fake-chalk5-package wants chalk ^5.0.0');
93
+ console.log(' โš ๏ธ fraim-framework wants chalk ^4.1.2');
94
+ const installResult = await runCommand('npm', ['install'], tempDir);
95
+ if (installResult.code !== 0) {
96
+ console.log(' โš ๏ธ npm install failed (might be expected)');
97
+ console.log(` stderr: ${installResult.stderr.substring(0, 300)}`);
98
+ }
99
+ // 5. Check what version of chalk was installed for fraim-framework
100
+ const fraimChalkPath = path_1.default.join(tempDir, 'node_modules', 'fraim-framework', 'node_modules', 'chalk', 'package.json');
101
+ const rootChalkPath = path_1.default.join(tempDir, 'node_modules', 'chalk', 'package.json');
102
+ let fraimChalkVersion = null;
103
+ let rootChalkVersion = null;
104
+ if (fs_1.default.existsSync(fraimChalkPath)) {
105
+ const chalkPkg = JSON.parse(fs_1.default.readFileSync(fraimChalkPath, 'utf-8'));
106
+ fraimChalkVersion = chalkPkg.version;
107
+ console.log(` ๐Ÿ“‹ fraim-framework's chalk: ${fraimChalkVersion}`);
108
+ }
109
+ if (fs_1.default.existsSync(rootChalkPath)) {
110
+ const chalkPkg = JSON.parse(fs_1.default.readFileSync(rootChalkPath, 'utf-8'));
111
+ rootChalkVersion = chalkPkg.version;
112
+ console.log(` ๐Ÿ“‹ Root chalk: ${rootChalkVersion}`);
113
+ }
114
+ // 6. Try to load fraim CLI
115
+ console.log(' ๐Ÿš€ Testing if fraim CLI loads...');
116
+ const testScript = `
117
+ try {
118
+ const fraimCli = require('./node_modules/fraim-framework/dist/src/cli/fraim.js');
119
+ console.log('SUCCESS: fraim CLI loaded');
120
+ process.exit(0);
121
+ } catch (error) {
122
+ if (error.code === 'ERR_REQUIRE_ESM') {
123
+ console.log('ERROR: ERR_REQUIRE_ESM - chalk v5 was used!');
124
+ console.log('Chalk version caused issue:', error.message);
125
+ process.exit(1);
126
+ } else {
127
+ console.log('ERROR: Other error:', error.message);
128
+ process.exit(2);
129
+ }
130
+ }
131
+ `;
132
+ fs_1.default.writeFileSync(path_1.default.join(tempDir, 'test.js'), testScript);
133
+ const testResult = await runCommand('node', ['test.js'], tempDir);
134
+ if (testResult.code === 1) {
135
+ console.log(' โŒ REPRODUCED THE BUG! npm resolved chalk to v5');
136
+ console.log(' โŒ fraim-framework with ^4.1.2 got chalk v5 due to conflict');
137
+ console.log(' โœ… This proves the issue exists with ^4.1.2');
138
+ // Cleanup
139
+ fs_1.default.unlinkSync(tarballPath);
140
+ return true; // We successfully reproduced the bug!
141
+ }
142
+ else if (testResult.code === 0) {
143
+ console.log(' โ„น๏ธ fraim CLI loaded successfully');
144
+ console.log(' โ„น๏ธ npm resolved the conflict without upgrading to v5');
145
+ console.log(' โ„น๏ธ This scenario didn\'t trigger the bug, but it could in other environments');
146
+ }
147
+ else {
148
+ console.log(' โš ๏ธ Got unexpected error');
149
+ console.log(` stdout: ${testResult.stdout}`);
150
+ }
151
+ // Cleanup
152
+ fs_1.default.unlinkSync(tarballPath);
153
+ return true;
154
+ }
155
+ catch (error) {
156
+ console.error(' โŒ Test failed with error:', error);
157
+ return false;
158
+ }
159
+ finally {
160
+ try {
161
+ fs_1.default.rmSync(tempDir, { recursive: true, force: true });
162
+ console.log(' ๐Ÿงน Cleaned up temp directory');
163
+ }
164
+ catch (e) {
165
+ console.log(' โš ๏ธ Could not clean up temp directory');
166
+ }
167
+ }
168
+ }
169
+ async function testChalkResolutionWithPinnedVersion() {
170
+ console.log(' ๐Ÿงช Testing chalk resolution with PINNED version (4.1.2)...');
171
+ const tempDir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'chalk-pinned-'));
172
+ console.log(` ๐Ÿ“‚ Created temp dir: ${tempDir}`);
173
+ try {
174
+ // 1. Create a package that depends on chalk v5
175
+ console.log(' ๐Ÿ“ฆ Creating fake package that requires chalk v5...');
176
+ const fakePackageDir = path_1.default.join(tempDir, 'fake-chalk5-package');
177
+ fs_1.default.mkdirSync(fakePackageDir, { recursive: true });
178
+ const fakePackageJson = {
179
+ name: 'fake-chalk5-package',
180
+ version: '1.0.0',
181
+ dependencies: {
182
+ 'chalk': '^5.0.0'
183
+ }
184
+ };
185
+ fs_1.default.writeFileSync(path_1.default.join(fakePackageDir, 'package.json'), JSON.stringify(fakePackageJson, null, 2));
186
+ fs_1.default.writeFileSync(path_1.default.join(fakePackageDir, 'index.js'), 'export { default as chalk } from "chalk";\n');
187
+ // 2. Pack fraim-framework with 4.1.2 (PINNED - current state)
188
+ console.log(' ๐Ÿ“ฆ Packing fraim-framework with pinned 4.1.2...');
189
+ const projectRoot = process.cwd();
190
+ const packResult = (0, node_child_process_1.execSync)('npm pack', {
191
+ cwd: projectRoot,
192
+ encoding: 'utf-8'
193
+ });
194
+ const tarballName = packResult.trim().split('\n').pop()?.trim();
195
+ if (!tarballName) {
196
+ return false;
197
+ }
198
+ const tarballPath = path_1.default.join(projectRoot, tarballName);
199
+ // 3. Create test project with conflicting dependencies
200
+ console.log(' ๐Ÿ”ง Creating test project with conflicting dependencies...');
201
+ const testPackageJson = {
202
+ name: 'chalk-pinned-test',
203
+ version: '1.0.0',
204
+ dependencies: {
205
+ 'fake-chalk5-package': 'file:./fake-chalk5-package',
206
+ 'fraim-framework': `file:${tarballPath}`
207
+ }
208
+ };
209
+ fs_1.default.writeFileSync(path_1.default.join(tempDir, 'package.json'), JSON.stringify(testPackageJson, null, 2));
210
+ // 4. Install dependencies
211
+ console.log(' ๐Ÿ“ฅ Installing with conflicting chalk requirements...');
212
+ console.log(' โš ๏ธ fake-chalk5-package wants chalk ^5.0.0');
213
+ console.log(' โœ… fraim-framework wants chalk 4.1.2 (PINNED)');
214
+ const installResult = await runCommand('npm', ['install'], tempDir);
215
+ if (installResult.code !== 0) {
216
+ console.log(' โš ๏ธ npm install failed');
217
+ }
218
+ // 5. Check chalk versions
219
+ const fraimChalkPath = path_1.default.join(tempDir, 'node_modules', 'fraim-framework', 'node_modules', 'chalk', 'package.json');
220
+ const rootChalkPath = path_1.default.join(tempDir, 'node_modules', 'chalk', 'package.json');
221
+ let fraimChalkVersion = null;
222
+ let rootChalkVersion = null;
223
+ if (fs_1.default.existsSync(fraimChalkPath)) {
224
+ const chalkPkg = JSON.parse(fs_1.default.readFileSync(fraimChalkPath, 'utf-8'));
225
+ fraimChalkVersion = chalkPkg.version;
226
+ console.log(` ๐Ÿ“‹ fraim-framework's chalk: ${fraimChalkVersion}`);
227
+ }
228
+ if (fs_1.default.existsSync(rootChalkPath)) {
229
+ const chalkPkg = JSON.parse(fs_1.default.readFileSync(rootChalkPath, 'utf-8'));
230
+ rootChalkVersion = chalkPkg.version;
231
+ console.log(` ๐Ÿ“‹ Root chalk: ${rootChalkVersion}`);
232
+ }
233
+ // Verify fraim has v4
234
+ if (fraimChalkVersion && !fraimChalkVersion.startsWith('4.')) {
235
+ console.log(` โŒ PINNED version failed! Got chalk ${fraimChalkVersion}`);
236
+ fs_1.default.unlinkSync(tarballPath);
237
+ return false;
238
+ }
239
+ // 6. Try to load fraim CLI
240
+ console.log(' ๐Ÿš€ Testing if fraim CLI loads...');
241
+ const testScript = `
242
+ try {
243
+ const fraimCli = require('./node_modules/fraim-framework/dist/src/cli/fraim.js');
244
+ console.log('SUCCESS: fraim CLI loaded with pinned chalk');
245
+ process.exit(0);
246
+ } catch (error) {
247
+ if (error.code === 'ERR_REQUIRE_ESM') {
248
+ console.log('ERROR: ERR_REQUIRE_ESM even with pinned version!');
249
+ process.exit(1);
250
+ } else {
251
+ console.log('ERROR: Other error:', error.message);
252
+ process.exit(2);
253
+ }
254
+ }
255
+ `;
256
+ fs_1.default.writeFileSync(path_1.default.join(tempDir, 'test.js'), testScript);
257
+ const testResult = await runCommand('node', ['test.js'], tempDir);
258
+ if (testResult.code === 0) {
259
+ console.log(' โœ… SUCCESS! Pinned version prevents chalk v5 upgrade');
260
+ console.log(' โœ… fraim CLI works even with chalk v5 dependency nearby');
261
+ console.log(' โœ… This proves the fix works!');
262
+ }
263
+ else if (testResult.code === 1) {
264
+ console.log(' โŒ FAILED! Even pinned version got chalk v5');
265
+ console.log(' โŒ The fix doesn\'t work!');
266
+ fs_1.default.unlinkSync(tarballPath);
267
+ return false;
268
+ }
269
+ // Cleanup
270
+ fs_1.default.unlinkSync(tarballPath);
271
+ return true;
272
+ }
273
+ catch (error) {
274
+ console.error(' โŒ Test failed with error:', error);
275
+ return false;
276
+ }
277
+ finally {
278
+ try {
279
+ fs_1.default.rmSync(tempDir, { recursive: true, force: true });
280
+ console.log(' ๐Ÿงน Cleaned up temp directory');
281
+ }
282
+ catch (e) {
283
+ console.log(' โš ๏ธ Could not clean up temp directory');
284
+ }
285
+ }
286
+ }
287
+ async function runChalkResolutionTest(testCase) {
288
+ return await testCase.testFunction();
289
+ }
290
+ const testCases = [
291
+ {
292
+ name: 'Chalk Resolution with Conflict (^4.1.2)',
293
+ description: 'Tests if ^4.1.2 allows npm to upgrade to chalk v5 when there\'s a conflicting dependency',
294
+ testFunction: testChalkResolutionWithConflict,
295
+ tags: ['chalk', 'resolution', 'conflict']
296
+ },
297
+ {
298
+ name: 'Chalk Resolution with Pinned Version (4.1.2)',
299
+ description: 'Tests if pinned 4.1.2 prevents npm from upgrading to chalk v5',
300
+ testFunction: testChalkResolutionWithPinnedVersion,
301
+ tags: ['chalk', 'resolution', 'pinned', 'fix']
302
+ }
303
+ ];
304
+ (0, test_utils_1.runTests)(testCases, runChalkResolutionTest, 'Chalk Resolution Issue Test');