@bsb/base 9.3.0 → 9.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/lib/base/BSBService.d.ts +1 -1
  2. package/lib/base/EventValidator.d.ts +1 -1
  3. package/lib/base/PluginConfig.d.ts +1 -1
  4. package/lib/base/functions.d.ts +1 -1
  5. package/lib/base/functions.js +1 -1
  6. package/lib/base/functions.js.map +1 -1
  7. package/lib/interfaces/schema-types.d.ts +1 -1
  8. package/lib/interfaces/schema-types.js +1 -1
  9. package/lib/interfaces/schema-types.js.map +1 -1
  10. package/lib/plugins/config-default/index.d.ts +1 -1
  11. package/lib/plugins/config-default/index.js +1 -1
  12. package/lib/plugins/config-default/index.js.map +1 -1
  13. package/lib/plugins/observable-default/index.d.ts +1 -1
  14. package/lib/plugins/observable-default/index.js +1 -1
  15. package/lib/plugins/observable-default/index.js.map +1 -1
  16. package/lib/plugins/service-benchmarkify/index.d.ts +1 -1
  17. package/lib/plugins/service-benchmarkify/index.js +1 -1
  18. package/lib/plugins/service-benchmarkify/index.js.map +1 -1
  19. package/lib/plugins/service-default0/index.d.ts +1 -1
  20. package/lib/plugins/service-default0/index.js +1 -1
  21. package/lib/plugins/service-default0/index.js.map +1 -1
  22. package/lib/plugins/service-default1/index.d.ts +1 -1
  23. package/lib/plugins/service-default1/index.js +1 -1
  24. package/lib/plugins/service-default1/index.js.map +1 -1
  25. package/lib/plugins/service-default2/index.d.ts +1 -1
  26. package/lib/plugins/service-default2/index.js +1 -1
  27. package/lib/plugins/service-default2/index.js.map +1 -1
  28. package/lib/plugins/service-default3/index.d.ts +1 -1
  29. package/lib/plugins/service-default3/index.js +1 -1
  30. package/lib/plugins/service-default3/index.js.map +1 -1
  31. package/lib/plugins/service-default4/index.d.ts +1 -1
  32. package/lib/plugins/service-default4/index.js +1 -1
  33. package/lib/plugins/service-default4/index.js.map +1 -1
  34. package/lib/schemas/config-default.json +1 -1
  35. package/lib/schemas/config-default.plugin.json +1 -1
  36. package/lib/schemas/observable-default.json +1 -1
  37. package/lib/schemas/observable-default.plugin.json +1 -1
  38. package/lib/schemas/service-benchmarkify.json +11 -11
  39. package/lib/schemas/service-default0.json +9 -9
  40. package/lib/schemas/service-default1.json +11 -11
  41. package/lib/schemas/service-default2.json +11 -11
  42. package/lib/schemas/service-default3.json +5 -5
  43. package/lib/schemas/service-default4.json +3 -3
  44. package/lib/scripts/bsb-plugin-cli.js +99 -7
  45. package/lib/scripts/bsb-plugin-cli.js.map +1 -1
  46. package/package.json +2 -2
@@ -7,7 +7,7 @@
7
7
  "description": "Test event with string parameters",
8
8
  "inputSchema": {
9
9
  "anyvaliVersion": "1.0",
10
- "schemaVersion": "1",
10
+ "schemaVersion": "1.1",
11
11
  "root": {
12
12
  "kind": "object",
13
13
  "properties": {
@@ -39,7 +39,7 @@
39
39
  "description": "Handle system startup notification",
40
40
  "inputSchema": {
41
41
  "anyvaliVersion": "1.0",
42
- "schemaVersion": "1",
42
+ "schemaVersion": "1.1",
43
43
  "root": {
44
44
  "kind": "object",
45
45
  "properties": {
@@ -72,7 +72,7 @@
72
72
  "description": "Calculate with two numbers",
73
73
  "inputSchema": {
74
74
  "anyvaliVersion": "1.0",
75
- "schemaVersion": "1",
75
+ "schemaVersion": "1.1",
76
76
  "root": {
77
77
  "kind": "object",
78
78
  "properties": {
@@ -100,7 +100,7 @@
100
100
  },
101
101
  "outputSchema": {
102
102
  "anyvaliVersion": "1.0",
103
- "schemaVersion": "1",
103
+ "schemaVersion": "1.1",
104
104
  "root": {
105
105
  "kind": "number"
106
106
  },
@@ -118,7 +118,7 @@
118
118
  "description": "Validate data against a schema",
119
119
  "inputSchema": {
120
120
  "anyvaliVersion": "1.0",
121
- "schemaVersion": "1",
121
+ "schemaVersion": "1.1",
122
122
  "root": {
123
123
  "kind": "object",
124
124
  "properties": {
@@ -144,7 +144,7 @@
144
144
  },
145
145
  "outputSchema": {
146
146
  "anyvaliVersion": "1.0",
147
- "schemaVersion": "1",
147
+ "schemaVersion": "1.1",
148
148
  "root": {
149
149
  "kind": "object",
150
150
  "properties": {
@@ -178,7 +178,7 @@
178
178
  "description": "System-wide alert broadcast",
179
179
  "inputSchema": {
180
180
  "anyvaliVersion": "1.0",
181
- "schemaVersion": "1",
181
+ "schemaVersion": "1.1",
182
182
  "root": {
183
183
  "kind": "object",
184
184
  "properties": {
@@ -225,7 +225,7 @@
225
225
  "description": "Listen for system shutdown broadcasts",
226
226
  "inputSchema": {
227
227
  "anyvaliVersion": "1.0",
228
- "schemaVersion": "1",
228
+ "schemaVersion": "1.1",
229
229
  "root": {
230
230
  "kind": "object",
231
231
  "properties": {
@@ -256,7 +256,7 @@
256
256
  "pluginType": "service",
257
257
  "configSchema": {
258
258
  "anyvaliVersion": "1.0",
259
- "schemaVersion": "1",
259
+ "schemaVersion": "1.1",
260
260
  "root": {
261
261
  "kind": "object",
262
262
  "properties": {
@@ -7,7 +7,7 @@
7
7
  "description": "Emitted when data processing is complete",
8
8
  "inputSchema": {
9
9
  "anyvaliVersion": "1.0",
10
- "schemaVersion": "1",
10
+ "schemaVersion": "1.1",
11
11
  "root": {
12
12
  "kind": "object",
13
13
  "properties": {
@@ -43,7 +43,7 @@
43
43
  "description": "Handle incoming data for processing",
44
44
  "inputSchema": {
45
45
  "anyvaliVersion": "1.0",
46
- "schemaVersion": "1",
46
+ "schemaVersion": "1.1",
47
47
  "root": {
48
48
  "kind": "object",
49
49
  "properties": {
@@ -79,7 +79,7 @@
79
79
  "description": "Request calculation from external service",
80
80
  "inputSchema": {
81
81
  "anyvaliVersion": "1.0",
82
- "schemaVersion": "1",
82
+ "schemaVersion": "1.1",
83
83
  "root": {
84
84
  "kind": "object",
85
85
  "properties": {
@@ -115,7 +115,7 @@
115
115
  },
116
116
  "outputSchema": {
117
117
  "anyvaliVersion": "1.0",
118
- "schemaVersion": "1",
118
+ "schemaVersion": "1.1",
119
119
  "root": {
120
120
  "kind": "number"
121
121
  },
@@ -133,7 +133,7 @@
133
133
  "description": "Transform text according to specified operation",
134
134
  "inputSchema": {
135
135
  "anyvaliVersion": "1.0",
136
- "schemaVersion": "1",
136
+ "schemaVersion": "1.1",
137
137
  "root": {
138
138
  "kind": "object",
139
139
  "properties": {
@@ -165,7 +165,7 @@
165
165
  },
166
166
  "outputSchema": {
167
167
  "anyvaliVersion": "1.0",
168
- "schemaVersion": "1",
168
+ "schemaVersion": "1.1",
169
169
  "root": {
170
170
  "kind": "string"
171
171
  },
@@ -183,7 +183,7 @@
183
183
  "description": "Calculate with two numbers",
184
184
  "inputSchema": {
185
185
  "anyvaliVersion": "1.0",
186
- "schemaVersion": "1",
186
+ "schemaVersion": "1.1",
187
187
  "root": {
188
188
  "kind": "object",
189
189
  "properties": {
@@ -209,7 +209,7 @@
209
209
  },
210
210
  "outputSchema": {
211
211
  "anyvaliVersion": "1.0",
212
- "schemaVersion": "1",
212
+ "schemaVersion": "1.1",
213
213
  "root": {
214
214
  "kind": "number"
215
215
  },
@@ -227,7 +227,7 @@
227
227
  "description": "Broadcast service status updates",
228
228
  "inputSchema": {
229
229
  "anyvaliVersion": "1.0",
230
- "schemaVersion": "1",
230
+ "schemaVersion": "1.1",
231
231
  "root": {
232
232
  "kind": "object",
233
233
  "properties": {
@@ -272,7 +272,7 @@
272
272
  "description": "Listen for configuration update broadcasts",
273
273
  "inputSchema": {
274
274
  "anyvaliVersion": "1.0",
275
- "schemaVersion": "1",
275
+ "schemaVersion": "1.1",
276
276
  "root": {
277
277
  "kind": "object",
278
278
  "properties": {
@@ -310,7 +310,7 @@
310
310
  "pluginType": "service",
311
311
  "configSchema": {
312
312
  "anyvaliVersion": "1.0",
313
- "schemaVersion": "1",
313
+ "schemaVersion": "1.1",
314
314
  "root": {
315
315
  "kind": "optional",
316
316
  "inner": {
@@ -7,7 +7,7 @@
7
7
  "description": "Emitted when a task is completed",
8
8
  "inputSchema": {
9
9
  "anyvaliVersion": "1.0",
10
- "schemaVersion": "1",
10
+ "schemaVersion": "1.1",
11
11
  "root": {
12
12
  "kind": "object",
13
13
  "properties": {
@@ -43,7 +43,7 @@
43
43
  "description": "Handle new task assignments",
44
44
  "inputSchema": {
45
45
  "anyvaliVersion": "1.0",
46
- "schemaVersion": "1",
46
+ "schemaVersion": "1.1",
47
47
  "root": {
48
48
  "kind": "object",
49
49
  "properties": {
@@ -85,7 +85,7 @@
85
85
  "description": "Request resource allocation",
86
86
  "inputSchema": {
87
87
  "anyvaliVersion": "1.0",
88
- "schemaVersion": "1",
88
+ "schemaVersion": "1.1",
89
89
  "root": {
90
90
  "kind": "object",
91
91
  "properties": {
@@ -117,7 +117,7 @@
117
117
  },
118
118
  "outputSchema": {
119
119
  "anyvaliVersion": "1.0",
120
- "schemaVersion": "1",
120
+ "schemaVersion": "1.1",
121
121
  "root": {
122
122
  "kind": "object",
123
123
  "properties": {
@@ -156,7 +156,7 @@
156
156
  "description": "Calculate with two numbers",
157
157
  "inputSchema": {
158
158
  "anyvaliVersion": "1.0",
159
- "schemaVersion": "1",
159
+ "schemaVersion": "1.1",
160
160
  "root": {
161
161
  "kind": "object",
162
162
  "properties": {
@@ -182,7 +182,7 @@
182
182
  },
183
183
  "outputSchema": {
184
184
  "anyvaliVersion": "1.0",
185
- "schemaVersion": "1",
185
+ "schemaVersion": "1.1",
186
186
  "root": {
187
187
  "kind": "number"
188
188
  },
@@ -200,7 +200,7 @@
200
200
  "description": "Perform health check",
201
201
  "inputSchema": {
202
202
  "anyvaliVersion": "1.0",
203
- "schemaVersion": "1",
203
+ "schemaVersion": "1.1",
204
204
  "root": {
205
205
  "kind": "object",
206
206
  "properties": {
@@ -222,7 +222,7 @@
222
222
  },
223
223
  "outputSchema": {
224
224
  "anyvaliVersion": "1.0",
225
- "schemaVersion": "1",
225
+ "schemaVersion": "1.1",
226
226
  "root": {
227
227
  "kind": "object",
228
228
  "properties": {
@@ -267,7 +267,7 @@
267
267
  "description": "Broadcast performance metrics",
268
268
  "inputSchema": {
269
269
  "anyvaliVersion": "1.0",
270
- "schemaVersion": "1",
270
+ "schemaVersion": "1.1",
271
271
  "root": {
272
272
  "kind": "object",
273
273
  "properties": {
@@ -307,7 +307,7 @@
307
307
  "description": "Listen for emergency stop broadcasts",
308
308
  "inputSchema": {
309
309
  "anyvaliVersion": "1.0",
310
- "schemaVersion": "1",
310
+ "schemaVersion": "1.1",
311
311
  "root": {
312
312
  "kind": "object",
313
313
  "properties": {
@@ -338,7 +338,7 @@
338
338
  "pluginType": "service",
339
339
  "configSchema": {
340
340
  "anyvaliVersion": "1.0",
341
- "schemaVersion": "1",
341
+ "schemaVersion": "1.1",
342
342
  "root": {
343
343
  "kind": "optional",
344
344
  "inner": {
@@ -7,7 +7,7 @@
7
7
  "description": "Calculate with two numbers",
8
8
  "inputSchema": {
9
9
  "anyvaliVersion": "1.0",
10
- "schemaVersion": "1",
10
+ "schemaVersion": "1.1",
11
11
  "root": {
12
12
  "kind": "object",
13
13
  "properties": {
@@ -33,7 +33,7 @@
33
33
  },
34
34
  "outputSchema": {
35
35
  "anyvaliVersion": "1.0",
36
- "schemaVersion": "1",
36
+ "schemaVersion": "1.1",
37
37
  "root": {
38
38
  "kind": "number"
39
39
  },
@@ -51,7 +51,7 @@
51
51
  "description": "Reverse a string",
52
52
  "inputSchema": {
53
53
  "anyvaliVersion": "1.0",
54
- "schemaVersion": "1",
54
+ "schemaVersion": "1.1",
55
55
  "root": {
56
56
  "kind": "object",
57
57
  "properties": {
@@ -73,7 +73,7 @@
73
73
  },
74
74
  "outputSchema": {
75
75
  "anyvaliVersion": "1.0",
76
- "schemaVersion": "1",
76
+ "schemaVersion": "1.1",
77
77
  "root": {
78
78
  "kind": "string"
79
79
  },
@@ -90,7 +90,7 @@
90
90
  "pluginType": "service",
91
91
  "configSchema": {
92
92
  "anyvaliVersion": "1.0",
93
- "schemaVersion": "1",
93
+ "schemaVersion": "1.1",
94
94
  "root": {
95
95
  "kind": "optional",
96
96
  "inner": {
@@ -7,7 +7,7 @@
7
7
  "description": "Reverse text string",
8
8
  "inputSchema": {
9
9
  "anyvaliVersion": "1.0",
10
- "schemaVersion": "1",
10
+ "schemaVersion": "1.1",
11
11
  "root": {
12
12
  "kind": "object",
13
13
  "properties": {
@@ -29,7 +29,7 @@
29
29
  },
30
30
  "outputSchema": {
31
31
  "anyvaliVersion": "1.0",
32
- "schemaVersion": "1",
32
+ "schemaVersion": "1.1",
33
33
  "root": {
34
34
  "kind": "string"
35
35
  },
@@ -46,7 +46,7 @@
46
46
  "pluginType": "service",
47
47
  "configSchema": {
48
48
  "anyvaliVersion": "1.0",
49
- "schemaVersion": "1",
49
+ "schemaVersion": "1.1",
50
50
  "root": {
51
51
  "kind": "optional",
52
52
  "inner": {
@@ -117,7 +117,9 @@ function collectFilesRecursive(dirPath, predicate) {
117
117
  for (const entry of entries) {
118
118
  const fullPath = path.join(current, entry.name);
119
119
  if (entry.isDirectory()) {
120
- stack.push(fullPath);
120
+ if (!entry.name.startsWith('.')) {
121
+ stack.push(fullPath);
122
+ }
121
123
  }
122
124
  else if (entry.isFile() && predicate(fullPath)) {
123
125
  files.push(fullPath);
@@ -289,6 +291,94 @@ function resolveBsbBasePath() {
289
291
  return null;
290
292
  }
291
293
  }
294
+ const RESTRICTED_PATTERNS = [
295
+ { pattern: /\bprocess\.env\b/, name: 'process.env', message: 'Use BSB config system instead', skipForPluginType: 'config' },
296
+ { pattern: /\bprocess\.exit\b/, name: 'process.exit', message: 'Throw an error instead — BSB manages the process lifecycle' },
297
+ { pattern: /\bprocess\.cwd\b/, name: 'process.cwd', message: 'Use the cwd provided by BSB constructor args' },
298
+ { pattern: /\bprocess\.argv\b/, name: 'process.argv', message: 'CLI arguments are managed by BSB' },
299
+ { pattern: /\b__dirname\b/, name: '__dirname', message: 'Use BSB-provided paths from constructor args' },
300
+ { pattern: /\b__filename\b/, name: '__filename', message: 'Use BSB-provided paths from constructor args' },
301
+ { pattern: /\bconsole\.\w+/, name: 'console', message: 'Use this.log (BSB observable) instead', skipForPluginType: 'observable' },
302
+ { pattern: /['"](?:node:)?child_process['"]/, name: 'child_process', message: 'Spawning child processes is not allowed in BSB plugins' },
303
+ { pattern: /['"](?:node:)?cluster['"]/, name: 'cluster', message: 'Cluster management is handled by BSB' },
304
+ { pattern: /\beval\s*\(/, name: 'eval()', message: 'eval() is not allowed in BSB plugins' },
305
+ { pattern: /\bnew\s+Function\s*\(/, name: 'new Function()', message: 'Dynamic function construction is not allowed in BSB plugins' },
306
+ { pattern: /\bglobal\.\w/, name: 'global', message: 'Global state mutation is not allowed in BSB plugins' },
307
+ { pattern: /\bglobalThis\.\w/, name: 'globalThis', message: 'Global state mutation is not allowed in BSB plugins' },
308
+ { pattern: /\brequire\s*\(/, name: 'require()', message: 'Use ESM imports instead', allowKey: 'require' },
309
+ { pattern: /['"](?:node:)?worker_threads['"]/, name: 'worker_threads', message: 'Worker threads are managed by BSB', allowKey: 'worker_threads' },
310
+ ];
311
+ function validateRestrictedAPIs(plugins) {
312
+ const packageJson = readPackageJson();
313
+ const allowList = Array.isArray(packageJson.bsb?.allow) ? packageJson.bsb.allow : [];
314
+ const allowedKeys = new Set(allowList.filter((k) => k === 'require' || k === 'worker_threads'));
315
+ const activePatterns = RESTRICTED_PATTERNS.filter((p) => !p.allowKey || !allowedKeys.has(p.allowKey));
316
+ if (activePatterns.length === 0) {
317
+ return;
318
+ }
319
+ const violations = [];
320
+ for (const plugin of plugins) {
321
+ const pluginType = plugin.name.startsWith('observable-') ? 'observable' :
322
+ plugin.name.startsWith('config-') ? 'config' : 'other';
323
+ const pluginPatterns = activePatterns.filter((p) => !p.skipForPluginType || p.skipForPluginType !== pluginType);
324
+ const tsFiles = collectFilesRecursive(plugin.srcDir, (filePath) => {
325
+ const ext = path.extname(filePath).toLowerCase();
326
+ return ext === '.ts' || ext === '.tsx';
327
+ });
328
+ for (const filePath of tsFiles) {
329
+ const content = fs.readFileSync(filePath, 'utf-8');
330
+ const lines = content.split('\n');
331
+ let inBlockComment = false;
332
+ for (let i = 0; i < lines.length; i++) {
333
+ let line = lines[i];
334
+ if (inBlockComment) {
335
+ const endIdx = line.indexOf('*/');
336
+ if (endIdx === -1)
337
+ continue;
338
+ line = line.slice(endIdx + 2);
339
+ inBlockComment = false;
340
+ }
341
+ const blockStart = line.indexOf('/*');
342
+ if (blockStart !== -1) {
343
+ const blockEnd = line.indexOf('*/', blockStart + 2);
344
+ if (blockEnd !== -1) {
345
+ line = line.slice(0, blockStart) + line.slice(blockEnd + 2);
346
+ }
347
+ else {
348
+ line = line.slice(0, blockStart);
349
+ inBlockComment = true;
350
+ }
351
+ }
352
+ const trimmed = line.trim();
353
+ if (trimmed.startsWith('//'))
354
+ continue;
355
+ if (trimmed.startsWith('import type '))
356
+ continue;
357
+ const relPath = normalizePath(path.relative(CWD, filePath));
358
+ for (const restricted of pluginPatterns) {
359
+ if (restricted.pattern.test(line)) {
360
+ violations.push({
361
+ file: relPath,
362
+ line: i + 1,
363
+ name: restricted.name,
364
+ message: restricted.message,
365
+ });
366
+ }
367
+ }
368
+ }
369
+ }
370
+ }
371
+ if (violations.length > 0) {
372
+ log('\n=== Restricted API Usage Detected ===\n', 'red');
373
+ for (const v of violations) {
374
+ log(` ${v.file}:${v.line} — ${v.name}`, 'red');
375
+ log(` ${v.message}`, 'yellow');
376
+ }
377
+ log(`\n${violations.length} violation(s) found. BSB plugins cannot use these APIs.\n`, 'red');
378
+ process.exit(1);
379
+ }
380
+ success('Source validation passed (no restricted API usage)');
381
+ }
292
382
  // Detect plugin structure
293
383
  function detectPluginStructure() {
294
384
  const srcDir = path.join(CWD, 'src');
@@ -812,9 +902,11 @@ async function build(options = {}) {
812
902
  else {
813
903
  info('Skipping clean for incremental rebuild');
814
904
  }
905
+ // Step 5: Validate restricted API usage in plugin source
906
+ validateRestrictedAPIs(plugins);
815
907
  // Hook: beforeCompile
816
908
  runHook('beforeCompile');
817
- // Step 5: Compile TypeScript (virtual clients in src/.bsb/clients/ compile with the project)
909
+ // Step 6: Compile TypeScript (virtual clients in src/.bsb/clients/ compile with the project)
818
910
  if (options.incremental) {
819
911
  exec(`npx tsc --incremental --tsBuildInfoFile "${normalizePath(TSC_BUILD_INFO_PATH)}"`, 'Compiling TypeScript incrementally');
820
912
  }
@@ -823,7 +915,7 @@ async function build(options = {}) {
823
915
  }
824
916
  // Hook: afterCompile
825
917
  runHook('afterCompile');
826
- // Step 6: Copy non-TypeScript assets for each plugin
918
+ // Step 7: Copy non-TypeScript assets for each plugin
827
919
  const shouldCopyAllAssets = !options.changedPaths || changedPaths.length === 0 || assetChanged || !fs.existsSync(path.join(CWD, 'lib'));
828
920
  if (shouldCopyAllAssets) {
829
921
  for (const plugin of plugins) {
@@ -833,7 +925,7 @@ async function build(options = {}) {
833
925
  else {
834
926
  info('Skipping asset copy (unchanged)');
835
927
  }
836
- // Step 7: Copy extracted schemas to lib/schemas/
928
+ // Step 8: Copy extracted schemas to lib/schemas/
837
929
  const shouldCopySchemas = runSchemaPipeline || !hasLibSchemas();
838
930
  if (shouldCopySchemas) {
839
931
  copySchemasToLib();
@@ -841,7 +933,7 @@ async function build(options = {}) {
841
933
  else {
842
934
  info('Skipping schema copy (unchanged)');
843
935
  }
844
- // Step 8: Generate per-plugin metadata JSON (needs compiled JS for Config.metadata)
936
+ // Step 9: Generate per-plugin metadata JSON (needs compiled JS for Config.metadata)
845
937
  const shouldGenerateMetadata = runSchemaPipeline ||
846
938
  packageChanged ||
847
939
  cache.metadataInputsHash !== metadataInputsHash ||
@@ -854,14 +946,14 @@ async function build(options = {}) {
854
946
  else {
855
947
  info('Skipping plugin metadata generation (unchanged)');
856
948
  }
857
- // Step 9: Generate root bsb-plugin.json (aggregates all per-plugin metadata)
949
+ // Step 10: Generate root bsb-plugin.json (aggregates all per-plugin metadata)
858
950
  if (shouldGenerateMetadata || !fs.existsSync(path.join(CWD, 'bsb-plugin.json'))) {
859
951
  generateRootPluginJson();
860
952
  }
861
953
  else {
862
954
  info('Skipping bsb-plugin.json generation (unchanged)');
863
955
  }
864
- // Step 10: Generate root bsb-tests.json (default ignore entries)
956
+ // Step 11: Generate root bsb-tests.json (default ignore entries)
865
957
  if (shouldGenerateMetadata || !fs.existsSync(path.join(CWD, 'bsb-tests.json'))) {
866
958
  generateRootTestsJson(plugins.map(p => ({ id: p.name })));
867
959
  }