@bleedingdev/modern-js-create 3.5.0-ultramodern.0 → 3.5.0-ultramodern.2

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 (28) hide show
  1. package/README.md +24 -0
  2. package/dist/cjs/ultramodern-tooling/commands.cjs +246 -0
  3. package/dist/cjs/ultramodern-workspace/contracts.cjs +1 -0
  4. package/dist/cjs/ultramodern-workspace/module-federation.cjs +6 -0
  5. package/dist/cjs/ultramodern-workspace/package-json.cjs +1 -0
  6. package/dist/cjs/ultramodern-workspace/versions.cjs +12 -2
  7. package/dist/cjs/ultramodern-workspace/workspace-scripts.cjs +1 -0
  8. package/dist/cjs/ultramodern-workspace/write-workspace.cjs +2 -0
  9. package/dist/esm/ultramodern-tooling/commands.js +246 -0
  10. package/dist/esm/ultramodern-workspace/contracts.js +1 -0
  11. package/dist/esm/ultramodern-workspace/module-federation.js +6 -0
  12. package/dist/esm/ultramodern-workspace/package-json.js +1 -0
  13. package/dist/esm/ultramodern-workspace/versions.js +7 -3
  14. package/dist/esm/ultramodern-workspace/workspace-scripts.js +1 -0
  15. package/dist/esm/ultramodern-workspace/write-workspace.js +3 -1
  16. package/dist/esm-node/ultramodern-tooling/commands.js +246 -0
  17. package/dist/esm-node/ultramodern-workspace/contracts.js +1 -0
  18. package/dist/esm-node/ultramodern-workspace/module-federation.js +6 -0
  19. package/dist/esm-node/ultramodern-workspace/package-json.js +1 -0
  20. package/dist/esm-node/ultramodern-workspace/versions.js +7 -3
  21. package/dist/esm-node/ultramodern-workspace/workspace-scripts.js +1 -0
  22. package/dist/esm-node/ultramodern-workspace/write-workspace.js +3 -1
  23. package/dist/types/ultramodern-workspace/versions.d.ts +6 -2
  24. package/package.json +6 -6
  25. package/template-workspace/README.md.handlebars +40 -1
  26. package/template-workspace/pnpm-workspace.yaml.handlebars +3 -0
  27. package/templates/workspace-scripts/check-ultramodern-api-boundaries.mts +30 -8
  28. package/templates/workspace-scripts/validate-ultramodern-workspace.mjs.handlebars +2 -0
@@ -179,6 +179,7 @@ function createRootPackageJson(scope, packageSource, remotes = [], bridge) {
179
179
  'agents:refs:check': "node ./scripts/setup-agent-reference-repos.mts --check",
180
180
  'mf:types': "node ./scripts/assert-mf-types.mts",
181
181
  'performance:readiness': "node ./scripts/ultramodern-performance-readiness.mts",
182
+ 'migrate:strict-effect': "node ./scripts/migrate-strict-effect.mts",
182
183
  'contract:check': "node ./scripts/validate-ultramodern-workspace.mts",
183
184
  'api:check': "node ./scripts/check-ultramodern-api-boundaries.mts",
184
185
  'i18n:boundaries': "node ./scripts/check-ultramodern-i18n-boundaries.mts",
@@ -9,12 +9,14 @@ const CLOUDFLARE_COMPATIBILITY_DATE = '2026-06-02';
9
9
  const TAILWIND_VERSION = '4.3.1';
10
10
  const TAILWIND_POSTCSS_VERSION = '4.3.1';
11
11
  const POSTCSS_VERSION = '8.5.15';
12
+ const EFFECT_VERSION = '4.0.0-beta.91';
13
+ const EFFECT_VITEST_VERSION = '4.0.0-beta.91';
12
14
  const EFFECT_TSGO_VERSION = '0.14.6';
13
15
  const TYPESCRIPT_STABLE_VERSION = '6.0.3';
14
- const TYPESCRIPT_NATIVE_PREVIEW_VERSION = '7.0.0-dev.20260624.1';
16
+ const TYPESCRIPT_NATIVE_PREVIEW_VERSION = '7.0.0-dev.20260628.1';
15
17
  const TYPESCRIPT_VERSION = TYPESCRIPT_STABLE_VERSION;
16
18
  const OXLINT_VERSION = '1.71.0';
17
- const OXFMT_VERSION = '0.55.0';
19
+ const OXFMT_VERSION = '0.56.0';
18
20
  const ULTRACITE_VERSION = '7.8.3';
19
21
  const LEFTHOOK_VERSION = '^2.1.9';
20
22
  const I18NEXT_VERSION = '26.3.1';
@@ -32,7 +34,9 @@ const ultramodernWorkspaceVersions = {
32
34
  tanstackRouter: TANSTACK_ROUTER_VERSION,
33
35
  tanstackRouterCore: TANSTACK_ROUTER_CORE_VERSION,
34
36
  moduleFederation: MODULE_FEDERATION_VERSION,
37
+ effect: EFFECT_VERSION,
38
+ effectVitest: EFFECT_VITEST_VERSION,
35
39
  tailwind: TAILWIND_VERSION,
36
40
  tailwindPostcss: TAILWIND_POSTCSS_VERSION
37
41
  };
38
- export { CLOUDFLARE_COMPATIBILITY_DATE, EFFECT_TSGO_VERSION, I18NEXT_VERSION, LEFTHOOK_VERSION, MODULE_FEDERATION_AGENT_SKILLS_COMMIT, MODULE_FEDERATION_VERSION, NODE_FETCH_VERSION, NODE_VERSION, OXFMT_VERSION, OXLINT_VERSION, PNPM_VERSION, POSTCSS_VERSION, REACT_DOM_VERSION, REACT_ROUTER_VERSION, REACT_VERSION, RSTACK_AGENT_SKILLS_COMMIT, TAILWIND_POSTCSS_VERSION, TAILWIND_VERSION, TANSTACK_ROUTER_CORE_VERSION, TANSTACK_ROUTER_VERSION, TYPESCRIPT_NATIVE_PREVIEW_VERSION, TYPESCRIPT_STABLE_VERSION, TYPESCRIPT_VERSION, TYPES_REACT_DOM_VERSION, TYPES_REACT_VERSION, ULTRACITE_VERSION, WRANGLER_VERSION, ZEPHYR_AGENT_VERSION, ZEPHYR_RSPACK_PLUGIN_VERSION, ultramodernWorkspaceVersions };
42
+ export { CLOUDFLARE_COMPATIBILITY_DATE, EFFECT_TSGO_VERSION, EFFECT_VERSION, EFFECT_VITEST_VERSION, I18NEXT_VERSION, LEFTHOOK_VERSION, MODULE_FEDERATION_AGENT_SKILLS_COMMIT, MODULE_FEDERATION_VERSION, NODE_FETCH_VERSION, NODE_VERSION, OXFMT_VERSION, OXLINT_VERSION, PNPM_VERSION, POSTCSS_VERSION, REACT_DOM_VERSION, REACT_ROUTER_VERSION, REACT_VERSION, RSTACK_AGENT_SKILLS_COMMIT, TAILWIND_POSTCSS_VERSION, TAILWIND_VERSION, TANSTACK_ROUTER_CORE_VERSION, TANSTACK_ROUTER_VERSION, TYPESCRIPT_NATIVE_PREVIEW_VERSION, TYPESCRIPT_STABLE_VERSION, TYPESCRIPT_VERSION, TYPES_REACT_DOM_VERSION, TYPES_REACT_VERSION, ULTRACITE_VERSION, WRANGLER_VERSION, ZEPHYR_AGENT_VERSION, ZEPHYR_RSPACK_PLUGIN_VERSION, ultramodernWorkspaceVersions };
@@ -163,6 +163,7 @@ function writeGeneratedWorkspaceScripts(targetDir, _scope, _enableTailwind, _rem
163
163
  writeWorkspaceOwnedMtsScript(targetDir, 'proof-cloudflare-version', createToolWrapperScript('cloudflare-proof'));
164
164
  writeFileReplacing(targetDir, "scripts/ultramodern-performance-readiness.config.mjs", createPerformanceReadinessConfigScript());
165
165
  writeWorkspaceOwnedMtsScript(targetDir, 'ultramodern-performance-readiness', createToolWrapperScript('performance-readiness'));
166
+ writeWorkspaceOwnedMtsScript(targetDir, 'migrate-strict-effect', createToolWrapperScript('migrate-strict-effect'));
166
167
  writeWorkspaceOwnedMtsScript(targetDir, 'ultramodern-typecheck', createToolWrapperScript('typecheck'));
167
168
  writeWorkspaceOwnedMtsScript(targetDir, 'bootstrap-agent-skills', createSkillsToolWrapperScript());
168
169
  migrateCopiedWorkspaceScriptToMts(targetDir, 'setup-agent-reference-repos');
@@ -15,7 +15,7 @@ import { runCodeSmithOverlays } from "./overlays.js";
15
15
  import { createAppMfTypesTsConfig, createAppPackage, createAppTsConfig, createRootPackageJson, createRootTsConfig, createSharedContractsIndex, createSharedPackage, createSharedPackageTsConfig, createTsConfigBase } from "./package-json.js";
16
16
  import { resolvePackageSource } from "./package-source.js";
17
17
  import { createPublicWebAppArtifacts } from "./public-surface.js";
18
- import { NODE_FETCH_VERSION, NODE_VERSION, PNPM_VERSION, TANSTACK_ROUTER_CORE_VERSION, TANSTACK_ROUTER_VERSION, TYPESCRIPT_VERSION } from "./versions.js";
18
+ import { EFFECT_VERSION, EFFECT_VITEST_VERSION, NODE_FETCH_VERSION, NODE_VERSION, PNPM_VERSION, TANSTACK_ROUTER_CORE_VERSION, TANSTACK_ROUTER_VERSION, TYPESCRIPT_VERSION } from "./versions.js";
19
19
  import { writeGeneratedWorkspaceScripts } from "./workspace-scripts.js";
20
20
  function writeApp(targetDir, scope, app, packageSource, enableTailwind, remotes = [], bridge) {
21
21
  const resolvedApp = 'shell' === app.kind ? createShellHost(remotes) : app;
@@ -131,6 +131,8 @@ function generateUltramodernWorkspace(options) {
131
131
  nodeVersion: NODE_VERSION,
132
132
  pnpmVersion: PNPM_VERSION,
133
133
  nodeFetchVersion: NODE_FETCH_VERSION,
134
+ effectVersion: EFFECT_VERSION,
135
+ effectVitestVersion: EFFECT_VITEST_VERSION,
134
136
  tanstackRouterCoreVersion: TANSTACK_ROUTER_CORE_VERSION,
135
137
  tanstackRouterVersion: TANSTACK_ROUTER_VERSION,
136
138
  typescriptVersion: TYPESCRIPT_VERSION,
@@ -13,12 +13,14 @@ export declare const CLOUDFLARE_COMPATIBILITY_DATE = "2026-06-02";
13
13
  export declare const TAILWIND_VERSION = "4.3.1";
14
14
  export declare const TAILWIND_POSTCSS_VERSION = "4.3.1";
15
15
  export declare const POSTCSS_VERSION = "8.5.15";
16
+ export declare const EFFECT_VERSION = "4.0.0-beta.91";
17
+ export declare const EFFECT_VITEST_VERSION = "4.0.0-beta.91";
16
18
  export declare const EFFECT_TSGO_VERSION = "0.14.6";
17
19
  export declare const TYPESCRIPT_STABLE_VERSION = "6.0.3";
18
- export declare const TYPESCRIPT_NATIVE_PREVIEW_VERSION = "7.0.0-dev.20260624.1";
20
+ export declare const TYPESCRIPT_NATIVE_PREVIEW_VERSION = "7.0.0-dev.20260628.1";
19
21
  export declare const TYPESCRIPT_VERSION = "6.0.3";
20
22
  export declare const OXLINT_VERSION = "1.71.0";
21
- export declare const OXFMT_VERSION = "0.55.0";
23
+ export declare const OXFMT_VERSION = "0.56.0";
22
24
  export declare const ULTRACITE_VERSION = "7.8.3";
23
25
  export declare const LEFTHOOK_VERSION = "^2.1.9";
24
26
  export declare const I18NEXT_VERSION = "26.3.1";
@@ -36,6 +38,8 @@ export declare const ultramodernWorkspaceVersions: {
36
38
  tanstackRouter: string;
37
39
  tanstackRouterCore: string;
38
40
  moduleFederation: string;
41
+ effect: string;
42
+ effectVitest: string;
39
43
  tailwind: string;
40
44
  tailwindPostcss: string;
41
45
  };
package/package.json CHANGED
@@ -21,7 +21,7 @@
21
21
  "engines": {
22
22
  "node": ">=20"
23
23
  },
24
- "version": "3.5.0-ultramodern.0",
24
+ "version": "3.5.0-ultramodern.2",
25
25
  "types": "./dist/types/index.d.ts",
26
26
  "main": "./dist/esm-node/index.js",
27
27
  "bin": {
@@ -75,14 +75,14 @@
75
75
  ],
76
76
  "dependencies": {
77
77
  "@modern-js/codesmith": "2.6.9",
78
- "oxfmt": "0.55.0",
78
+ "oxfmt": "0.56.0",
79
79
  "ultracite": "7.8.3",
80
- "@modern-js/i18n-utils": "npm:@bleedingdev/modern-js-i18n-utils@3.5.0-ultramodern.0"
80
+ "@modern-js/i18n-utils": "npm:@bleedingdev/modern-js-i18n-utils@3.5.0-ultramodern.2"
81
81
  },
82
82
  "devDependencies": {
83
- "@rslib/core": "0.23.0",
83
+ "@rslib/core": "0.23.1",
84
84
  "@types/node": "^26.0.1",
85
- "@typescript/native-preview": "7.0.0-dev.20260624.1",
85
+ "@typescript/native-preview": "7.0.0-dev.20260628.1",
86
86
  "tsx": "^4.22.4",
87
87
  "typescript": "^6.0.3",
88
88
  "@scripts/rstest-config": "2.66.0"
@@ -99,6 +99,6 @@
99
99
  "test": "rm -rf dist && rslib build -c rslibconfig.mts && rstest --passWithNoTests"
100
100
  },
101
101
  "ultramodern": {
102
- "frameworkVersion": "3.5.0-ultramodern.0"
102
+ "frameworkVersion": "3.5.0-ultramodern.2"
103
103
  }
104
104
  }
@@ -69,7 +69,7 @@ typecheck, skills, i18n boundary validation, contract validation, and build as
69
69
  separate matrix jobs so failures are isolated and parallelizable.
70
70
 
71
71
  Type checking is TS7-first. `pnpm typecheck` runs
72
- `scripts/ultramodern-typecheck.mjs` in TS-Go build mode over
72
+ `scripts/ultramodern-typecheck.mts` in TS-Go build mode over
73
73
  `tsconfig.json` project references, with native-preview `--checkers` and
74
74
  `--builders` enabled by default. `@typescript/native-preview` is the TS7 latest
75
75
  dev compiler lane. The classic `typescript` package is pinned to latest TS6
@@ -147,11 +147,50 @@ ULTRAMODERN_PUBLIC_URL_SHELL_SUPER_APP=https://shell-super-app.example.workers.d
147
147
  pnpm cloudflare:proof -- --require-public-urls
148
148
  ```
149
149
 
150
+ ## Strict Effect API
151
+
152
+ Generated HTTP APIs use the direct strict Effect topology only:
153
+
154
+ - API contracts live at `shared/api.ts`.
155
+ - Runtime entries live at `api/index.ts`.
156
+ - Browser clients live under `src/api/*-client.ts`.
157
+ - `modern.config.ts` uses `bff.runtimeFramework: 'effect'`,
158
+ `bff.effect.entry: './api/index'`, and
159
+ `bff.effect.strictEffectApproach: true`.
160
+
161
+ Do not add `api/effect`, `api/lambda`, `shared/effect`, `src/effect`, Hono
162
+ server imports, raw request handlers, manual `request.json()` parsing, or
163
+ manual `new Response(...)` construction inside generated API modules.
164
+ `pnpm api:check` and Oxlint enforce this. Model requests, responses, and typed
165
+ errors with concrete Effect `Schema` values; generic JSON shortcuts such as
166
+ `Schema.UnknownFromJsonString`, `Schema.Unknown`, and `Schema.Any` are rejected
167
+ in API modules.
168
+
169
+ Generated pnpm overrides pin the framework-compatible Effect cohort. Keep
170
+ `effect` and `@effect/vitest` aligned with `pnpm-workspace.yaml`; do not add
171
+ new direct package-level Effect versions unless the whole UltraModern cohort is
172
+ upgraded.
173
+
174
+ For older generated workspaces, run the framework migration command first:
175
+
176
+ ```bash
177
+ pnpm dlx @bleedingdev/modern-js-create@3.5.0-ultramodern.2 ultramodern \
178
+ migrate-strict-effect --version 3.5.0-ultramodern.2
179
+ pnpm api:check
180
+ pnpm contract:check
181
+ ```
182
+
183
+ The command updates generated package-source metadata, Modern package aliases,
184
+ direct API topology metadata, and the lockfile. Remaining failures are source
185
+ migration work; fix the owning API files instead of adding compatibility shims.
186
+
150
187
  ## Troubleshooting
151
188
 
152
189
  | Symptom | Current check | Owner |
153
190
  | --- | --- | --- |
154
191
  | Package cohort mismatch | Regenerate with one package source strategy, run `mise install`, then rerun `pnpm install` from the activated shell. | Generated workspace package source metadata |
192
+ | Effect runtime cohort mismatch | Keep `effect` and `@effect/vitest` on the generated pnpm override versions, then rerun `pnpm install`. | Generated workspace dependency policy |
193
+ | Old nested API path | Run `pnpm api:check`, move code to `api/index.ts`, `shared/api.ts`, and `src/api/*`, then delete `api/effect`, `api/lambda`, `shared/effect`, and `src/effect`. | API owner |
155
194
  | Install failure | Check the active Node/pnpm from `mise install`; rerun `pnpm install` after the shell sees the pinned versions. | Toolchain setup |
156
195
  | Build failure | Run the matching primitive gate (`pnpm lint`, `pnpm typecheck`, `pnpm i18n:boundaries`, `pnpm contract:check`) before `pnpm build`; fix the owning failure first. | Owning package or generated contract |
157
196
  | Missing public URL | Set the app public URL env key recorded in `.modernjs/ultramodern.json`, for example `ULTRAMODERN_PUBLIC_URL_SHELL_SUPER_APP`. | Deployment operator |
@@ -37,11 +37,14 @@ peerDependencyRules:
37
37
  '@module-federation/enhanced>typescript': '{{typescriptVersion}}'
38
38
  '@module-federation/modern-js-v3>typescript': '{{typescriptVersion}}'
39
39
  '@module-federation/rspack>typescript': '{{typescriptVersion}}'
40
+ '@effect/vitest>effect': '{{effectVersion}}'
40
41
  'i18next>typescript': '{{typescriptVersion}}'
41
42
 
42
43
  overrides:
43
44
  '@tanstack/react-router': {{tanstackRouterVersion}}
44
45
  '@tanstack/router-core': {{tanstackRouterCoreVersion}}
46
+ '@effect/vitest': {{effectVitestVersion}}
47
+ effect: {{effectVersion}}
45
48
  node-fetch: '{{nodeFetchVersion}}'
46
49
 
47
50
  allowBuilds:
@@ -97,7 +97,12 @@ function assertNotContains(relativePath, content, pattern, message) {
97
97
  }
98
98
 
99
99
  for (const forbiddenPath of [
100
- 'apps/shell-super-app/src/effect',
100
+ ...listDirectories('apps').flatMap(appPath => [
101
+ `${appPath}/api/effect`,
102
+ `${appPath}/api/lambda`,
103
+ `${appPath}/shared/effect`,
104
+ `${appPath}/src/effect`,
105
+ ]),
101
106
  ...listDirectories('verticals').flatMap(verticalPath => [
102
107
  `${verticalPath}/api/effect`,
103
108
  `${verticalPath}/api/lambda`,
@@ -148,6 +153,12 @@ for (const file of textFiles) {
148
153
  /\bcreateHandler\s*[:=]\s*(?!defineEffectBff\b)/u,
149
154
  'API modules must not define unbranded handler factories; use defineEffectBff(...).',
150
155
  );
156
+ assertNotContains(
157
+ file,
158
+ content,
159
+ /\bSchema\.(?:UnknownFromJsonString|Unknown|Any)\b/u,
160
+ 'API modules must use concrete request, response and error schemas; Schema.UnknownFromJsonString, Schema.Unknown and Schema.Any are forbidden in UltraModern API code.',
161
+ );
151
162
  }
152
163
 
153
164
  assertNotContains(
@@ -170,17 +181,18 @@ for (const file of textFiles) {
170
181
  );
171
182
  }
172
183
 
184
+ const verticalDirectories = listDirectories('verticals');
173
185
  const shellClient = 'apps/shell-super-app/src/api/vertical-clients.ts';
174
- if (exists('apps/shell-super-app')) {
186
+ if (exists('apps/shell-super-app') && verticalDirectories.length > 0) {
175
187
  assert(exists(shellClient), `${shellClient} must aggregate vertical API clients.`);
176
188
  }
177
189
 
178
- for (const verticalPath of listDirectories('verticals')) {
179
- const apiEntry = `${verticalPath}/api/index.ts`;
180
- const sharedApi = `${verticalPath}/shared/api.ts`;
181
- const srcApiDirectory = `${verticalPath}/src/api`;
182
- const modernConfig = `${verticalPath}/modern.config.ts`;
183
- const packageJsonPath = `${verticalPath}/package.json`;
190
+ function assertApiSurface(appPath) {
191
+ const apiEntry = `${appPath}/api/index.ts`;
192
+ const sharedApi = `${appPath}/shared/api.ts`;
193
+ const srcApiDirectory = `${appPath}/src/api`;
194
+ const modernConfig = `${appPath}/modern.config.ts`;
195
+ const packageJsonPath = `${appPath}/package.json`;
184
196
 
185
197
  assert(exists(apiEntry), `${apiEntry} is required.`);
186
198
  assert(exists(sharedApi), `${sharedApi} is required.`);
@@ -288,6 +300,16 @@ for (const verticalPath of listDirectories('verticals')) {
288
300
  }
289
301
  }
290
302
 
303
+ for (const appPath of listDirectories('apps')) {
304
+ if (exists(`${appPath}/api/index.ts`) || exists(`${appPath}/shared/api.ts`)) {
305
+ assertApiSurface(appPath);
306
+ }
307
+ }
308
+
309
+ for (const verticalPath of verticalDirectories) {
310
+ assertApiSurface(verticalPath);
311
+ }
312
+
291
313
  if (exists('apps/shell-super-app/package.json')) {
292
314
  const shellPackageJson = JSON.parse(
293
315
  readText('apps/shell-super-app/package.json'),
@@ -1701,6 +1701,7 @@ assert(
1701
1701
  assert(rootPackage.scripts?.['mf:types'] === 'node ./scripts/assert-mf-types.mts', 'Root must expose mf:types');
1702
1702
  assert(rootPackage.scripts?.['cloudflare:deploy'] === expectedCloudflareDeployScript, 'Root must expose cloudflare:deploy');
1703
1703
  assert(rootPackage.scripts?.['cloudflare:proof'] === 'node ./scripts/proof-cloudflare-version.mts --out .codex/reports/cloudflare-version-proof/public-url-proof.json', 'Root must expose cloudflare:proof');
1704
+ assert(rootPackage.scripts?.['migrate:strict-effect'] === 'node ./scripts/migrate-strict-effect.mts', 'Root must expose migrate:strict-effect');
1704
1705
  assert(rootPackage.scripts?.['skills:install'] === 'node ./scripts/bootstrap-agent-skills.mts', 'Root must expose skills:install');
1705
1706
  assert(rootPackage.scripts?.['skills:check'] === 'node ./scripts/bootstrap-agent-skills.mts --check', 'Root must expose skills:check');
1706
1707
  assert(rootPackage.scripts?.postinstall === "oxfmt . '!repos/**' && node ./scripts/bootstrap-agent-skills.mts --postinstall", 'Root postinstall must format, run the default-on Codex skills bootstrap, and leave reference repository installs explicit');
@@ -1709,6 +1710,7 @@ const agentSkillsBootstrap = readText('scripts/bootstrap-agent-skills.mts');
1709
1710
  assertToolWrapper('scripts/assert-mf-types.mts', 'mf-types');
1710
1711
  assertToolWrapper('scripts/generate-public-surface-assets.mts', 'public-surface');
1711
1712
  assertToolWrapper('scripts/proof-cloudflare-version.mts', 'cloudflare-proof');
1713
+ assertToolWrapper('scripts/migrate-strict-effect.mts', 'migrate-strict-effect');
1712
1714
  assertToolWrapper('scripts/bootstrap-agent-skills.mts', 'skills');
1713
1715
  assert(!agentSkillsBootstrap.includes("run('brew'") && !agentSkillsBootstrap.includes('runShell('), 'Agent skills bootstrap must never invoke system package managers');
1714
1716
  const agentReferenceRepoSetup = readText('scripts/setup-agent-reference-repos.mts');