@bleedingdev/modern-js-create 3.2.0-ultramodern.10 → 3.2.0-ultramodern.12

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.
@@ -0,0 +1,83 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+
4
+ const root = process.cwd();
5
+ const scanRoots = ['apps'].map((scanRoot) => path.join(root, scanRoot));
6
+ const ignoredDirectories = new Set(['.modern', '.modernjs', 'dist', 'node_modules']);
7
+ const visibleAttributePattern =
8
+ /\s(?:aria-label|alt|placeholder|title)=["']([^"']*[A-Za-z][^"']*)["']/gu;
9
+ const jsxTextPattern = />([^<>{}]*[A-Za-z][^<>{}]*)</gu;
10
+
11
+ const collectFiles = (directory) => {
12
+ if (!fs.existsSync(directory)) {
13
+ return [];
14
+ }
15
+
16
+ const files = [];
17
+ for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
18
+ if (entry.isDirectory()) {
19
+ if (!ignoredDirectories.has(entry.name)) {
20
+ files.push(...collectFiles(path.join(directory, entry.name)));
21
+ }
22
+ continue;
23
+ }
24
+
25
+ if (entry.isFile() && /\.(jsx|tsx)$/u.test(entry.name) && !entry.name.endsWith('.d.ts')) {
26
+ files.push(path.join(directory, entry.name));
27
+ }
28
+ }
29
+ return files;
30
+ };
31
+
32
+ const lineNumberForIndex = (content, index) => content.slice(0, index).split('\n').length;
33
+ const isIgnoredLine = (content, index) => {
34
+ const lineStart = content.lastIndexOf('\n', index) + 1;
35
+ const lineEnd = content.indexOf('\n', index);
36
+ const currentLineEnd = lineEnd === -1 ? content.length : lineEnd;
37
+ const previousLineStart = content.lastIndexOf('\n', Math.max(0, lineStart - 2)) + 1;
38
+ const nextLineEnd = content.indexOf('\n', currentLineEnd + 1);
39
+ const context = content.slice(
40
+ previousLineStart,
41
+ nextLineEnd === -1 ? content.length : nextLineEnd,
42
+ );
43
+ return /i18n-ignore/u.test(context);
44
+ };
45
+
46
+ const violations = [];
47
+ for (const filePath of scanRoots.flatMap(collectFiles)) {
48
+ const content = fs.readFileSync(filePath, 'utf-8');
49
+ for (const match of content.matchAll(visibleAttributePattern)) {
50
+ if (!isIgnoredLine(content, match.index ?? 0)) {
51
+ violations.push({
52
+ filePath,
53
+ line: lineNumberForIndex(content, match.index ?? 0),
54
+ text: match[1].trim(),
55
+ });
56
+ }
57
+ }
58
+
59
+ for (const match of content.matchAll(jsxTextPattern)) {
60
+ const text = match[1].replaceAll(/\s+/gu, ' ').trim();
61
+ if (text && !isIgnoredLine(content, match.index ?? 0)) {
62
+ violations.push({
63
+ filePath,
64
+ line: lineNumberForIndex(content, match.index ?? 0),
65
+ text,
66
+ });
67
+ }
68
+ }
69
+ }
70
+
71
+ if (violations.length > 0) {
72
+ console.error('Hardcoded user-visible JSX strings found. Move copy to locale JSON files.');
73
+ for (const violation of violations) {
74
+ console.error(
75
+ `${path.relative(root, violation.filePath)}:${violation.line} ${JSON.stringify(
76
+ violation.text,
77
+ )}`,
78
+ );
79
+ }
80
+ process.exit(1);
81
+ }
82
+
83
+ console.log('No hardcoded user-visible JSX strings found.');
@@ -4,11 +4,11 @@ import path from 'node:path';
4
4
  const root = process.cwd();
5
5
  const packageScope = '{{packageScope}}';
6
6
  const tanstackVersion = '1.170.1';
7
- const rstackAgentSkillsCommit =
8
- '61c948b42512e223bad44b83af4080eba48b2677';
7
+ const rstackAgentSkillsCommit = '61c948b42512e223bad44b83af4080eba48b2677';
9
8
  const modernPackages = [
10
9
  '@modern-js/app-tools',
11
10
  '@modern-js/plugin-bff',
11
+ '@modern-js/plugin-i18n',
12
12
  '@modern-js/plugin-tanstack',
13
13
  '@modern-js/runtime',
14
14
  ];
@@ -21,31 +21,18 @@ const baselineAgentSkills = [
21
21
  'rslib-modern-package',
22
22
  'rstest-best-practices',
23
23
  ];
24
- const privateAgentSkills = [
25
- 'plan-graph',
26
- 'dag',
27
- 'subagent-graph',
28
- 'helm',
29
- 'debugger-mode',
30
- ];
31
-
32
- function readText(relativePath) {
33
- return fs.readFileSync(path.join(root, relativePath), 'utf-8');
34
- }
24
+ const privateAgentSkills = ['plan-graph', 'dag', 'subagent-graph', 'helm', 'debugger-mode'];
35
25
 
36
- function readJson(relativePath) {
37
- return JSON.parse(readText(relativePath));
38
- }
39
-
40
- function assert(condition, message) {
26
+ const readText = (relativePath) => fs.readFileSync(path.join(root, relativePath), 'utf-8');
27
+ const readJson = (relativePath) => JSON.parse(readText(relativePath));
28
+ const assert = (condition, message) => {
41
29
  if (!condition) {
42
30
  throw new Error(message);
43
31
  }
44
- }
45
-
46
- function assertExists(relativePath) {
32
+ };
33
+ const assertExists = (relativePath) => {
47
34
  assert(fs.existsSync(path.join(root, relativePath)), `Missing ${relativePath}`);
48
- }
35
+ };
49
36
 
50
37
  const requiredPaths = [
51
38
  'AGENTS.md',
@@ -72,18 +59,31 @@ const requiredPaths = [
72
59
  '.modernjs/ultramodern-workspace-template-manifest.json',
73
60
  '.modernjs/ultramodern-package-source.json',
74
61
  'scripts/bootstrap-agent-skills.mjs',
62
+ 'scripts/check-i18n-strings.mjs',
75
63
  'apps/shell-super-app/package.json',
64
+ 'apps/shell-super-app/config/public/locales/en/translation.json',
65
+ 'apps/shell-super-app/config/public/locales/cs/translation.json',
76
66
  'apps/shell-super-app/modern.config.ts',
77
67
  'apps/shell-super-app/module-federation.config.ts',
68
+ 'apps/shell-super-app/src/modern.runtime.ts',
78
69
  'apps/remotes/remote-commerce/package.json',
70
+ 'apps/remotes/remote-commerce/config/public/locales/en/translation.json',
71
+ 'apps/remotes/remote-commerce/config/public/locales/cs/translation.json',
79
72
  'apps/remotes/remote-commerce/modern.config.ts',
80
73
  'apps/remotes/remote-commerce/module-federation.config.ts',
74
+ 'apps/remotes/remote-commerce/src/modern.runtime.ts',
81
75
  'apps/remotes/remote-identity/package.json',
76
+ 'apps/remotes/remote-identity/config/public/locales/en/translation.json',
77
+ 'apps/remotes/remote-identity/config/public/locales/cs/translation.json',
82
78
  'apps/remotes/remote-identity/modern.config.ts',
83
79
  'apps/remotes/remote-identity/module-federation.config.ts',
80
+ 'apps/remotes/remote-identity/src/modern.runtime.ts',
84
81
  'apps/remotes/remote-design-system/package.json',
82
+ 'apps/remotes/remote-design-system/config/public/locales/en/translation.json',
83
+ 'apps/remotes/remote-design-system/config/public/locales/cs/translation.json',
85
84
  'apps/remotes/remote-design-system/modern.config.ts',
86
85
  'apps/remotes/remote-design-system/module-federation.config.ts',
86
+ 'apps/remotes/remote-design-system/src/modern.runtime.ts',
87
87
  'services/service-recommendations-effect/package.json',
88
88
  'services/service-recommendations-effect/modern.config.ts',
89
89
  'services/service-recommendations-effect/api/effect/index.ts',
@@ -101,11 +101,9 @@ const rootPackage = readJson('package.json');
101
101
  const packageSource = readJson('.modernjs/ultramodern-package-source.json');
102
102
  const skillsLock = readJson('.agents/skills-lock.json');
103
103
  const expectedModernSpecifier =
104
- packageSource.strategy === 'install'
105
- ? packageSource.modernPackages?.specifier
106
- : 'workspace:*';
104
+ packageSource.strategy === 'install' ? packageSource.modernPackages?.specifier : 'workspace:*';
107
105
 
108
- function expectedModernDependency(packageName) {
106
+ const expectedModernDependency = (packageName) => {
109
107
  if (packageSource.strategy !== 'install') {
110
108
  return 'workspace:*';
111
109
  }
@@ -114,15 +112,14 @@ function expectedModernDependency(packageName) {
114
112
  return aliasPackageName
115
113
  ? `npm:${aliasPackageName}@${expectedModernSpecifier}`
116
114
  : expectedModernSpecifier;
117
- }
115
+ };
118
116
 
119
117
  assert(rootPackage.private === true, 'Root package must be private');
120
118
  assert(rootPackage.modernjs?.preset === 'presetUltramodern', 'Root must declare presetUltramodern');
121
119
  assert(rootPackage.packageManager === 'pnpm@11.1.2', 'Root must pin pnpm 11.1.2');
122
120
  assert(rootPackage.engines?.pnpm === '>=11.0.0', 'Root must require pnpm >=11');
123
121
  assert(
124
- rootPackage.modernjs?.packageSource?.config ===
125
- './.modernjs/ultramodern-package-source.json',
122
+ rootPackage.modernjs?.packageSource?.config === './.modernjs/ultramodern-package-source.json',
126
123
  'Root must point to the UltraModern package source metadata',
127
124
  );
128
125
  assert(
@@ -138,46 +135,39 @@ assert(
138
135
  'Generated shared packages must keep workspace:* links',
139
136
  );
140
137
  assert(
141
- modernPackages.every(packageName =>
138
+ modernPackages.every((packageName) =>
142
139
  packageSource.modernPackages?.packages?.includes(packageName),
143
140
  ),
144
141
  'Package source metadata must list all Modern runtime/tooling packages',
145
142
  );
146
143
  assert(
147
- expectedModernSpecifier &&
148
- packageSource.modernPackages?.specifier === expectedModernSpecifier,
144
+ expectedModernSpecifier && packageSource.modernPackages?.specifier === expectedModernSpecifier,
149
145
  'Package source metadata must provide a Modern package specifier',
150
146
  );
151
- assert(
152
- rootPackage.scripts?.['ultramodern:check'] ===
153
- 'node ./scripts/validate-ultramodern-workspace.mjs',
154
- 'Root must expose the ultramodern:check script',
155
- );
147
+
156
148
  const requiredRootScripts = {
157
149
  format: 'oxfmt .',
158
150
  'format:check': 'oxfmt --check .',
151
+ 'i18n:check': 'node ./scripts/check-i18n-strings.mjs',
159
152
  lint: 'oxlint .',
160
153
  'lint:fix': 'oxlint . --fix',
161
- 'skills:install': 'node ./scripts/bootstrap-agent-skills.mjs',
162
154
  'skills:check': 'node ./scripts/bootstrap-agent-skills.mjs --check',
155
+ 'skills:install': 'node ./scripts/bootstrap-agent-skills.mjs',
156
+ typecheck: `pnpm -r --filter "@${packageScope}/*" typecheck`,
157
+ 'ultramodern:check': 'node ./scripts/validate-ultramodern-workspace.mjs',
163
158
  };
164
159
  for (const [scriptName, scriptCommand] of Object.entries(requiredRootScripts)) {
165
- assert(
166
- rootPackage.scripts?.[scriptName] === scriptCommand,
167
- `Root must expose ${scriptName}`,
168
- );
160
+ assert(rootPackage.scripts?.[scriptName] === scriptCommand, `Root must expose ${scriptName}`);
169
161
  }
162
+
170
163
  for (const dependency of [
171
164
  '@effect/tsgo',
172
165
  '@typescript/native-preview',
173
- 'oxlint',
174
166
  'oxfmt',
167
+ 'oxlint',
175
168
  'ultracite',
176
169
  ]) {
177
- assert(
178
- rootPackage.devDependencies?.[dependency],
179
- `Root must depend on ${dependency}`,
180
- );
170
+ assert(rootPackage.devDependencies?.[dependency], `Root must depend on ${dependency}`);
181
171
  }
182
172
 
183
173
  const agentsInstructions = readText('AGENTS.md');
@@ -200,17 +190,17 @@ assert(
200
190
  );
201
191
  for (const skillName of baselineAgentSkills) {
202
192
  assert(
203
- skillsLock.baseline?.some(skill => skill.name === skillName),
193
+ skillsLock.baseline?.some((skill) => skill.name === skillName),
204
194
  `Agent skills lock must include ${skillName}`,
205
195
  );
206
- const skillContent = readText(`.agents/skills/${skillName}/SKILL.md`);
207
196
  assert(
208
- skillContent.includes(`name: ${skillName}`),
197
+ readText(`.agents/skills/${skillName}/SKILL.md`).includes(`name: ${skillName}`),
209
198
  `${skillName} must contain matching skill metadata`,
210
199
  );
211
200
  }
201
+
212
202
  const privateSource = skillsLock.sources?.find(
213
- source => source.repository === 'https://github.com/TechsioCZ/skills',
203
+ (source) => source.repository === 'https://github.com/TechsioCZ/skills',
214
204
  );
215
205
  assert(
216
206
  privateSource?.install === 'clone-if-authorized',
@@ -218,7 +208,7 @@ assert(
218
208
  );
219
209
  for (const skillName of privateAgentSkills) {
220
210
  assert(
221
- privateSource.baseline?.some(skill => skill.name === skillName),
211
+ privateSource.baseline?.some((skill) => skill.name === skillName),
222
212
  `Agent skills lock must allowlist private skill ${skillName}`,
223
213
  );
224
214
  }
@@ -232,31 +222,47 @@ const appPackagePaths = [
232
222
 
233
223
  for (const packagePath of appPackagePaths) {
234
224
  const packageJson = readJson(packagePath);
225
+ assert(
226
+ packageJson.dependencies?.['@modern-js/plugin-i18n'] ===
227
+ expectedModernDependency('@modern-js/plugin-i18n'),
228
+ `${packagePath} must use @modern-js/plugin-i18n through ${expectedModernDependency(
229
+ '@modern-js/plugin-i18n',
230
+ )}`,
231
+ );
235
232
  assert(
236
233
  packageJson.dependencies?.['@modern-js/plugin-tanstack'] ===
237
234
  expectedModernDependency('@modern-js/plugin-tanstack'),
238
- `${packagePath} must depend on @modern-js/plugin-tanstack through ${expectedModernDependency('@modern-js/plugin-tanstack')}`,
235
+ `${packagePath} must use @modern-js/plugin-tanstack through ${expectedModernDependency(
236
+ '@modern-js/plugin-tanstack',
237
+ )}`,
239
238
  );
240
239
  assert(
241
240
  packageJson.dependencies?.['@modern-js/runtime'] ===
242
241
  expectedModernDependency('@modern-js/runtime'),
243
- `${packagePath} must depend on @modern-js/runtime through ${expectedModernDependency('@modern-js/runtime')}`,
242
+ `${packagePath} must use @modern-js/runtime through ${expectedModernDependency(
243
+ '@modern-js/runtime',
244
+ )}`,
244
245
  );
245
246
  assert(
246
247
  packageJson.devDependencies?.['@modern-js/app-tools'] ===
247
248
  expectedModernDependency('@modern-js/app-tools'),
248
- `${packagePath} must depend on @modern-js/app-tools through ${expectedModernDependency('@modern-js/app-tools')}`,
249
+ `${packagePath} must use @modern-js/app-tools through ${expectedModernDependency(
250
+ '@modern-js/app-tools',
251
+ )}`,
249
252
  );
250
253
  assert(
251
- packageJson.dependencies?.[`@${packageScope}/shared-contracts`] ===
252
- 'workspace:*',
254
+ packageJson.dependencies?.[`@${packageScope}/shared-contracts`] === 'workspace:*',
253
255
  `${packagePath} must link generated shared contracts through workspace:*`,
254
256
  );
255
257
  assert(
256
- packageJson.dependencies?.[`@${packageScope}/shared-design-tokens`] ===
257
- 'workspace:*',
258
+ packageJson.dependencies?.[`@${packageScope}/shared-design-tokens`] === 'workspace:*',
258
259
  `${packagePath} must link generated shared design tokens through workspace:*`,
259
260
  );
261
+ assert(packageJson.dependencies?.i18next === '26.2.0', `${packagePath} must include i18next`);
262
+ assert(
263
+ packageJson.dependencies?.['react-i18next'] === '17.0.8',
264
+ `${packagePath} must include react-i18next`,
265
+ );
260
266
  assert(
261
267
  packageJson.dependencies?.['@tanstack/react-router'] === tanstackVersion,
262
268
  `${packagePath} must use @tanstack/react-router ${tanstackVersion}`,
@@ -279,57 +285,85 @@ for (const configPath of [
279
285
  ]) {
280
286
  const config = readText(configPath);
281
287
  assert(config.includes('presetUltramodern('), `${configPath} must use presetUltramodern`);
288
+ assert(config.includes('i18nPlugin('), `${configPath} must enable plugin-i18n`);
282
289
  assert(config.includes('tanstackRouterPlugin()'), `${configPath} must enable plugin-tanstack`);
283
- assert(config.includes('moduleFederationPlugin()'), `${configPath} must enable Module Federation`);
290
+ assert(
291
+ config.includes('moduleFederationPlugin()'),
292
+ `${configPath} must enable Module Federation`,
293
+ );
284
294
  }
285
295
 
286
296
  const shellMf = readText('apps/shell-super-app/module-federation.config.ts');
287
297
  assert(shellMf.includes("name: 'shellSuperApp'"), 'Shell MF config must name the shell');
288
- assert(shellMf.includes('remoteCommerce@http://localhost:3021/mf-manifest.json'), 'Shell must reference commerce remote');
289
- assert(shellMf.includes('remoteIdentity@http://localhost:3022/mf-manifest.json'), 'Shell must reference identity remote');
290
- assert(shellMf.includes('remoteDesignSystem@http://localhost:3023/mf-manifest.json'), 'Shell must reference design-system remote');
298
+ assert(
299
+ shellMf.includes('remoteCommerce@http://localhost:3021/mf-manifest.json'),
300
+ 'Shell must reference commerce remote',
301
+ );
302
+ assert(
303
+ shellMf.includes('remoteIdentity@http://localhost:3022/mf-manifest.json'),
304
+ 'Shell must reference identity remote',
305
+ );
306
+ assert(
307
+ shellMf.includes('remoteDesignSystem@http://localhost:3023/mf-manifest.json'),
308
+ 'Shell must reference design-system remote',
309
+ );
291
310
 
292
311
  const commerceMf = readText('apps/remotes/remote-commerce/module-federation.config.ts');
293
312
  assert(commerceMf.includes("name: 'remoteCommerce'"), 'Commerce remote MF name is missing');
294
- assert(commerceMf.includes('"./Widget"'), 'Commerce remote must expose a widget');
313
+ assert(commerceMf.includes("'./Widget'"), 'Commerce remote must expose a widget');
295
314
 
296
315
  const designMf = readText('apps/remotes/remote-design-system/module-federation.config.ts');
297
316
  assert(designMf.includes("name: 'remoteDesignSystem'"), 'Design-system remote MF name is missing');
298
- assert(designMf.includes('"./Button"'), 'Design-system remote must expose Button');
299
- assert(designMf.includes('"./tokens"'), 'Design-system remote must expose tokens');
317
+ assert(designMf.includes("'./Button'"), 'Design-system remote must expose Button');
318
+ assert(designMf.includes("'./tokens'"), 'Design-system remote must expose tokens');
300
319
 
301
320
  const servicePackage = readJson('services/service-recommendations-effect/package.json');
302
321
  assert(
303
322
  servicePackage.dependencies?.['@modern-js/runtime'] ===
304
323
  expectedModernDependency('@modern-js/runtime'),
305
- `Effect service must use @modern-js/runtime through ${expectedModernDependency('@modern-js/runtime')}`,
324
+ `Effect service must use @modern-js/runtime through ${expectedModernDependency(
325
+ '@modern-js/runtime',
326
+ )}`,
306
327
  );
307
328
  assert(
308
329
  servicePackage.devDependencies?.['@modern-js/app-tools'] ===
309
330
  expectedModernDependency('@modern-js/app-tools'),
310
- `Effect service must use @modern-js/app-tools through ${expectedModernDependency('@modern-js/app-tools')}`,
331
+ `Effect service must use @modern-js/app-tools through ${expectedModernDependency(
332
+ '@modern-js/app-tools',
333
+ )}`,
311
334
  );
312
335
  assert(
313
336
  servicePackage.devDependencies?.['@modern-js/plugin-bff'] ===
314
337
  expectedModernDependency('@modern-js/plugin-bff'),
315
- `Effect service must use @modern-js/plugin-bff through ${expectedModernDependency('@modern-js/plugin-bff')}`,
338
+ `Effect service must use @modern-js/plugin-bff through ${expectedModernDependency(
339
+ '@modern-js/plugin-bff',
340
+ )}`,
316
341
  );
317
342
  assert(
318
- servicePackage.dependencies?.[`@${packageScope}/shared-effect-api`] ===
319
- 'workspace:*',
343
+ servicePackage.dependencies?.[`@${packageScope}/shared-effect-api`] === 'workspace:*',
320
344
  'Effect service must link generated shared Effect API through workspace:*',
321
345
  );
322
346
 
323
347
  const serviceConfig = readText('services/service-recommendations-effect/modern.config.ts');
324
- assert(serviceConfig.includes("runtimeFramework: 'effect'"), 'Effect service must use Effect runtime');
348
+ assert(
349
+ serviceConfig.includes("runtimeFramework: 'effect'"),
350
+ 'Effect service must use Effect runtime',
351
+ );
325
352
  assert(serviceConfig.includes('bffPlugin()'), 'Effect service must enable bffPlugin');
326
353
 
327
354
  const serviceEntry = readText('services/service-recommendations-effect/api/effect/index.ts');
328
- assert(serviceEntry.includes('defineEffectBff'), 'Effect service must expose defineEffectBff placeholder');
329
- assert(serviceEntry.includes('recommendationsEffectApi'), 'Effect service must use shared recommendations API');
330
-
331
- const serviceApi = readText('services/service-recommendations-effect/shared/effect/api.ts');
332
- assert(serviceApi.includes('HttpApi.make'), 'Effect shared API placeholder must define HttpApi');
355
+ assert(
356
+ serviceEntry.includes('defineEffectBff'),
357
+ 'Effect service must expose defineEffectBff placeholder',
358
+ );
359
+ assert(
360
+ serviceEntry.includes('recommendationsEffectApi'),
361
+ 'Effect service must use shared recommendations API',
362
+ );
363
+ assert(
364
+ readText('services/service-recommendations-effect/shared/effect/api.ts').includes('HttpApi.make'),
365
+ 'Effect shared API placeholder must define HttpApi',
366
+ );
333
367
 
334
368
  const topology = readJson('topology/reference-topology.json');
335
369
  assert(topology.preset === 'presetUltramodern', 'Topology must reference presetUltramodern');
@@ -338,27 +372,26 @@ assert(topology.shell?.remoteRefs?.length === 3, 'Topology shell must reference
338
372
  assert(topology.remotes?.length === 3, 'Topology must contain three remotes');
339
373
  assert(
340
374
  topology.remotes.some(
341
- remote =>
342
- remote.id === 'remote-design-system' &&
343
- remote.kind === 'horizontal-design-system',
375
+ (remote) => remote.id === 'remote-design-system' && remote.kind === 'horizontal-design-system',
344
376
  ),
345
377
  'Topology must contain the horizontal design-system remote',
346
378
  );
347
- assert(topology.effectServices?.[0]?.runtime === 'effect', 'Topology must contain an Effect service');
379
+ assert(
380
+ topology.effectServices?.[0]?.runtime === 'effect',
381
+ 'Topology must contain an Effect service',
382
+ );
348
383
  assert(topology.sharedPackages?.length === 3, 'Topology must contain shared package placeholders');
349
384
 
350
385
  const ownership = readJson('topology/ownership.json');
351
386
  assert(
352
387
  ownership.owners?.some(
353
- owner =>
354
- owner.id === 'remote-commerce' &&
355
- owner.ownership?.team === 'commerce-experience',
388
+ (owner) => owner.id === 'remote-commerce' && owner.ownership?.team === 'commerce-experience',
356
389
  ),
357
390
  'Ownership metadata must retain commerce owner',
358
391
  );
359
392
  assert(
360
393
  ownership.owners?.some(
361
- owner =>
394
+ (owner) =>
362
395
  owner.id === 'service-recommendations-effect' &&
363
396
  owner.package === `@${packageScope}/service-recommendations-effect`,
364
397
  ),
@@ -379,18 +412,15 @@ assert(
379
412
  'Template manifest must retain the Rstack agent skills commit',
380
413
  );
381
414
  assert(
382
- baselineAgentSkills.every(skillName =>
383
- manifest.agentSkills?.baseline?.includes(skillName),
384
- ),
415
+ baselineAgentSkills.every((skillName) => manifest.agentSkills?.baseline?.includes(skillName)),
385
416
  'Template manifest must list every baseline agent skill',
386
417
  );
387
418
  assert(
388
- manifest.agentSkills?.privateSource?.repository ===
389
- 'https://github.com/TechsioCZ/skills',
419
+ manifest.agentSkills?.privateSource?.repository === 'https://github.com/TechsioCZ/skills',
390
420
  'Template manifest must retain the private TechsioCZ skill source',
391
421
  );
392
422
  assert(
393
- privateAgentSkills.every(skillName =>
423
+ privateAgentSkills.every((skillName) =>
394
424
  manifest.agentSkills?.privateSource?.baseline?.includes(skillName),
395
425
  ),
396
426
  'Template manifest must list every private agent skill allowlist entry',