@bleedingdev/modern-js-create 3.2.0-ultramodern.17 → 3.2.0-ultramodern.19

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.
package/dist/index.js CHANGED
@@ -556,6 +556,7 @@ const ultramodern_workspace_dirname = node_path.dirname(fileURLToPath(import.met
556
556
  const workspaceTemplateDir = node_path.resolve(ultramodern_workspace_dirname, '..', 'template-workspace');
557
557
  const TANSTACK_ROUTER_VERSION = '1.170.1';
558
558
  const MODULE_FEDERATION_VERSION = '2.4.0';
559
+ const ZEPHYR_MODERNJS_PLUGIN_VERSION = '1.1.1';
559
560
  const EFFECT_TSGO_VERSION = '0.7.3';
560
561
  const TYPESCRIPT_NATIVE_PREVIEW_VERSION = '7.0.0-dev.20260518.1';
561
562
  const OXLINT_VERSION = '1.65.0';
@@ -926,6 +927,7 @@ function appDependencies(scope, packageSource) {
926
927
  '@module-federation/modern-js-v3': MODULE_FEDERATION_VERSION,
927
928
  '@module-federation/runtime': MODULE_FEDERATION_VERSION,
928
929
  '@tanstack/react-router': TANSTACK_ROUTER_VERSION,
930
+ 'zephyr-modernjs-plugin': ZEPHYR_MODERNJS_PLUGIN_VERSION,
929
931
  [ultramodern_workspace_packageName(scope, 'shared-contracts')]: WORKSPACE_PACKAGE_VERSION,
930
932
  [ultramodern_workspace_packageName(scope, 'shared-design-tokens')]: WORKSPACE_PACKAGE_VERSION,
931
933
  i18next: I18NEXT_VERSION,
@@ -967,7 +969,10 @@ function createRootPackageJson(scope, packageSource) {
967
969
  typecheck: `pnpm -r --filter "@${scope}/*" typecheck`,
968
970
  'skills:install': "node ./scripts/bootstrap-agent-skills.mjs",
969
971
  'skills:check': "node ./scripts/bootstrap-agent-skills.mjs --check",
972
+ 'agents:refs:install': "node ./scripts/setup-agent-reference-repos.mjs",
973
+ 'agents:refs:check': "node ./scripts/setup-agent-reference-repos.mjs --check",
970
974
  'ultramodern:check': "node ./scripts/validate-ultramodern-workspace.mjs",
975
+ postinstall: "node ./scripts/setup-agent-reference-repos.mjs",
971
976
  check: 'pnpm format:check && pnpm lint && pnpm typecheck && pnpm i18n:check && pnpm skills:check && pnpm ultramodern:check'
972
977
  },
973
978
  engines: {
@@ -1136,6 +1141,7 @@ import { appTools, defineConfig, presetUltramodern } from '@modern-js/app-tools'
1136
1141
  import { i18nPlugin } from '@modern-js/plugin-i18n';
1137
1142
  import { tanstackRouterPlugin } from '@modern-js/plugin-tanstack';
1138
1143
  import { moduleFederationPlugin } from '@module-federation/modern-js-v3';
1144
+ import { withZephyr } from 'zephyr-modernjs-plugin';
1139
1145
 
1140
1146
  const appId = '${app.id}';
1141
1147
  const port = Number(process.env['${app.portEnv}'] ?? ${app.port});
@@ -1157,11 +1163,19 @@ export default defineConfig(
1157
1163
  {
1158
1164
  output: {
1159
1165
  disableTsChecker: true,
1166
+ distPath: {
1167
+ html: './',
1168
+ },
1160
1169
  polyfill: 'off',
1161
1170
  splitRouteChunks: false,
1162
1171
  },
1172
+ html: {
1173
+ outputStructure: 'flat',
1174
+ },
1163
1175
  plugins: [
1164
- appTools(),
1176
+ appTools({
1177
+ bundler: 'rspack',
1178
+ }),
1165
1179
  i18nPlugin({
1166
1180
  localeDetection: {
1167
1181
  fallbackLanguage: 'en',
@@ -1171,6 +1185,7 @@ export default defineConfig(
1171
1185
  }),
1172
1186
  tanstackRouterPlugin(),
1173
1187
  moduleFederationPlugin(),
1188
+ withZephyr(),
1174
1189
  ],
1175
1190
  server: {
1176
1191
  port,
@@ -1180,6 +1195,7 @@ export default defineConfig(
1180
1195
  },
1181
1196
  },
1182
1197
  source: {
1198
+ mainEntryName: 'index',
1183
1199
  globalVars: {
1184
1200
  ULTRAMODERN_SITE_URL: siteUrl,
1185
1201
  },
@@ -1855,6 +1871,8 @@ function createTemplateManifest(modernVersion, packageSource) {
1855
1871
  targetRoot: 'generated-project-root',
1856
1872
  allowedPaths: [
1857
1873
  '.agents/**',
1874
+ '.github/**',
1875
+ '.gitignore',
1858
1876
  '.modernjs/**',
1859
1877
  'AGENTS.md',
1860
1878
  'README.md',
@@ -1871,7 +1889,6 @@ function createTemplateManifest(modernVersion, packageSource) {
1871
1889
  ],
1872
1890
  deniedPaths: [
1873
1891
  '.git/**',
1874
- '.github/**',
1875
1892
  '.npmrc',
1876
1893
  '.yarnrc',
1877
1894
  '.env',
@@ -1919,6 +1936,7 @@ function createTemplateManifest(modernVersion, packageSource) {
1919
1936
  ],
1920
1937
  postMaterializationValidation: [
1921
1938
  'ultramodern-workspace-contract-check',
1939
+ 'github-workflow-security-enforced',
1922
1940
  'pnpm-11-policy-enforced',
1923
1941
  'template-manifest-retained'
1924
1942
  ],
@@ -2259,6 +2277,7 @@ function createBuiltinTemplateManifest(version) {
2259
2277
  postMaterializationValidation: [
2260
2278
  'ultramodern-contract-check',
2261
2279
  'dependency-install-with-lifecycle-deny',
2280
+ 'github-workflow-security-enforced',
2262
2281
  'package-source-retained',
2263
2282
  'pnpm-11-policy-enforced',
2264
2283
  'rstest-smoke-tests',
package/package.json CHANGED
@@ -21,7 +21,7 @@
21
21
  "engines": {
22
22
  "node": ">=20"
23
23
  },
24
- "version": "3.2.0-ultramodern.17",
24
+ "version": "3.2.0-ultramodern.19",
25
25
  "types": "./dist/types/index.d.ts",
26
26
  "main": "./dist/index.js",
27
27
  "bin": {
@@ -0,0 +1,53 @@
1
+ {
2
+ "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3
+ "extends": [
4
+ "config:recommended",
5
+ "helpers:pinGitHubActionDigests"
6
+ ],
7
+ "dependencyDashboard": true,
8
+ "minimumReleaseAge": "1 day",
9
+ "prConcurrentLimit": 5,
10
+ "prHourlyLimit": 2,
11
+ "rangeStrategy": "bump",
12
+ "schedule": [
13
+ "before 5am on monday"
14
+ ],
15
+ "timezone": "Etc/UTC",
16
+ "packageRules": [
17
+ {
18
+ "matchManagers": [
19
+ "github-actions"
20
+ ],
21
+ "groupName": "github-actions",
22
+ "labels": [
23
+ "dependencies",
24
+ "github-actions",
25
+ "security"
26
+ ]
27
+ },
28
+ {
29
+ "matchManagers": [
30
+ "npm"
31
+ ],
32
+ "matchUpdateTypes": [
33
+ "patch",
34
+ "minor"
35
+ ],
36
+ "groupName": "npm minor and patch updates",
37
+ "labels": [
38
+ "dependencies",
39
+ "npm"
40
+ ]
41
+ },
42
+ {
43
+ "matchUpdateTypes": [
44
+ "major"
45
+ ],
46
+ "dependencyDashboardApproval": true,
47
+ "labels": [
48
+ "dependencies",
49
+ "major"
50
+ ]
51
+ }
52
+ ]
53
+ }
@@ -4,27 +4,49 @@ on:
4
4
  push:
5
5
  pull_request:
6
6
 
7
+ permissions:
8
+ contents: read
9
+
10
+ defaults:
11
+ run:
12
+ shell: bash
13
+
14
+ concurrency:
15
+ group: ultramodern-gates-${{ github.workflow }}-${{ github.ref }}
16
+ cancel-in-progress: true
17
+
7
18
  jobs:
8
19
  ultramodern-gates:
9
20
  runs-on: ubuntu-latest
21
+ timeout-minutes: 20
10
22
  steps:
23
+ - name: Harden Runner
24
+ uses: step-security/harden-runner@ab7a9404c0f3da075243ca237b5fac12c98deaa5 # v2
25
+ with:
26
+ egress-policy: audit
27
+
11
28
  - name: Checkout
12
- uses: actions/checkout@v4
29
+ uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
30
+ with:
31
+ fetch-depth: 1
32
+ persist-credentials: false
13
33
 
14
34
  - name: Setup pnpm
15
- uses: pnpm/action-setup@v4
35
+ uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4
16
36
 
17
37
  - name: Setup Node.js
18
- uses: actions/setup-node@v4
38
+ uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
19
39
  with:
20
40
  node-version: 20
21
41
  cache: pnpm
22
42
 
23
43
  - name: Install Dependencies
24
- run: pnpm install
44
+ run: pnpm install --frozen-lockfile
25
45
 
26
46
  - name: Validate Ultramodern Contract
27
47
  run: pnpm run ultramodern:check
28
48
 
29
49
  - name: Build
50
+ env:
51
+ MODERN_PUBLIC_SITE_URL: http://localhost:8080
30
52
  run: pnpm run build
@@ -36,9 +36,13 @@ MODERN_BASELINE_ENABLE_BFF_REQUEST_ID=false
36
36
  MODERN_BASELINE_ENABLE_TELEMETRY_EXPORTERS=false
37
37
  ```
38
38
 
39
- The generated starter also includes `.github/workflows/ultramodern-gates.yml`.
40
- That workflow runs `pnpm run ultramodern:check` and `pnpm run build` on every
41
- push and pull request so the `presetUltramodern(...)` contract stays explicit.
39
+ The generated starter also includes `.github/workflows/ultramodern-gates.yml`
40
+ and `.github/renovate.json`. The workflow runs `pnpm run ultramodern:check` and
41
+ `pnpm run build` on every push and pull request with read-only permissions,
42
+ commit-pinned actions, frozen installs, and StepSecurity audit-mode runner
43
+ hardening. Renovate is configured for dependency dashboard review, one-day
44
+ release age, grouped updates, action digest pinning, and manual approval for
45
+ major upgrades.
42
46
 
43
47
  ## Micro Vertical Workspaces
44
48
 
@@ -52,6 +52,7 @@ const requiredDeniedPaths = [
52
52
  const requiredPostMaterialization = [
53
53
  'ultramodern-contract-check',
54
54
  'dependency-install-with-lifecycle-deny',
55
+ 'github-workflow-security-enforced',
55
56
  'package-source-retained',
56
57
  'pnpm-11-policy-enforced',
57
58
  'rstest-smoke-tests',
@@ -61,6 +62,7 @@ const requiredPaths = [
61
62
  {{#unless isSubproject}}
62
63
  'AGENTS.md',
63
64
  '.agents/skills-lock.json',
65
+ '.github/renovate.json',
64
66
  '.github/workflows/ultramodern-gates.yml',
65
67
  'oxlint.config.ts',
66
68
  'oxfmt.config.ts',
@@ -90,6 +92,53 @@ if (fs.existsSync(path.resolve(process.cwd(), 'src/routes/page.tsx'))) {
90
92
  process.exit(1);
91
93
  }
92
94
 
95
+ {{#unless isSubproject}}
96
+ const workflowContent = fs.readFileSync(
97
+ path.resolve(process.cwd(), '.github/workflows/ultramodern-gates.yml'),
98
+ 'utf-8',
99
+ );
100
+ const renovateConfig = JSON.parse(
101
+ fs.readFileSync(path.resolve(process.cwd(), '.github/renovate.json'), 'utf-8'),
102
+ );
103
+ for (const requiredSnippet of [
104
+ 'permissions:\n contents: read',
105
+ 'pull_request:',
106
+ 'persist-credentials: false',
107
+ 'pnpm install --frozen-lockfile',
108
+ 'MODERN_PUBLIC_SITE_URL: http://localhost:8080',
109
+ 'timeout-minutes:',
110
+ 'egress-policy: audit',
111
+ ]) {
112
+ if (!workflowContent.includes(requiredSnippet)) {
113
+ console.error(`Generated workflow must retain ${requiredSnippet.split('\n')[0]}`);
114
+ process.exit(1);
115
+ }
116
+ }
117
+ if (workflowContent.includes('pull_request_target')) {
118
+ console.error('Generated workflow must not use pull_request_target');
119
+ process.exit(1);
120
+ }
121
+ for (const match of workflowContent.matchAll(/^\s*uses:\s*([^@\s]+)@([^\s#]+)/gmu)) {
122
+ const [, actionName, actionRef] = match;
123
+ if (!/^[a-f0-9]{40}$/u.test(actionRef)) {
124
+ console.error(`Generated workflow must pin ${actionName}@${actionRef} to a commit SHA`);
125
+ process.exit(1);
126
+ }
127
+ }
128
+ if (
129
+ renovateConfig.dependencyDashboard !== true ||
130
+ renovateConfig.minimumReleaseAge !== '1 day' ||
131
+ !renovateConfig.extends?.includes('helpers:pinGitHubActionDigests') ||
132
+ !renovateConfig.packageRules?.some(
133
+ (rule) =>
134
+ rule.dependencyDashboardApproval === true && rule.matchUpdateTypes?.includes('major'),
135
+ )
136
+ ) {
137
+ console.error('Generated Renovate config must retain dashboard, release-age, action pinning, and major-approval policy');
138
+ process.exit(1);
139
+ }
140
+ {{/unless}}
141
+
93
142
  const pageContent = fs.readFileSync(
94
143
  path.resolve(process.cwd(), 'src/routes/[lang]/page.tsx'),
95
144
  'utf-8',
@@ -0,0 +1,23 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "defaultEnabled": true,
4
+ "installDir": "repos",
5
+ "repositories": [
6
+ {
7
+ "id": "effect",
8
+ "name": "Effect",
9
+ "url": "https://github.com/Effect-TS/effect.git",
10
+ "ref": "main",
11
+ "path": "repos/effect",
12
+ "readOnly": true
13
+ },
14
+ {
15
+ "id": "ultramodern-js",
16
+ "name": "UltraModern.js",
17
+ "url": "https://github.com/BleedingDev/ultramodern.js.git",
18
+ "ref": "main-ultramodern",
19
+ "path": "repos/ultramodern.js",
20
+ "readOnly": true
21
+ }
22
+ ]
23
+ }
@@ -0,0 +1,29 @@
1
+ {
2
+ "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3
+ "extends": ["config:recommended", "helpers:pinGitHubActionDigests"],
4
+ "dependencyDashboard": true,
5
+ "minimumReleaseAge": "1 day",
6
+ "prConcurrentLimit": 5,
7
+ "prHourlyLimit": 2,
8
+ "rangeStrategy": "bump",
9
+ "schedule": ["before 5am on monday"],
10
+ "timezone": "Etc/UTC",
11
+ "packageRules": [
12
+ {
13
+ "matchManagers": ["github-actions"],
14
+ "groupName": "github-actions",
15
+ "labels": ["dependencies", "github-actions", "security"]
16
+ },
17
+ {
18
+ "matchManagers": ["npm"],
19
+ "matchUpdateTypes": ["patch", "minor"],
20
+ "groupName": "npm minor and patch updates",
21
+ "labels": ["dependencies", "npm"]
22
+ },
23
+ {
24
+ "matchUpdateTypes": ["major"],
25
+ "dependencyDashboardApproval": true,
26
+ "labels": ["dependencies", "major"]
27
+ }
28
+ ]
29
+ }
@@ -0,0 +1,52 @@
1
+ name: Ultramodern Workspace Gates
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ defaults:
11
+ run:
12
+ shell: bash
13
+
14
+ concurrency:
15
+ group: ultramodern-workspace-gates-${{ github.workflow }}-${{ github.ref }}
16
+ cancel-in-progress: true
17
+
18
+ jobs:
19
+ ultramodern-workspace-gates:
20
+ runs-on: ubuntu-latest
21
+ timeout-minutes: 30
22
+ steps:
23
+ - name: Harden Runner
24
+ uses: step-security/harden-runner@ab7a9404c0f3da075243ca237b5fac12c98deaa5 # v2
25
+ with:
26
+ egress-policy: audit
27
+
28
+ - name: Checkout
29
+ uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
30
+ with:
31
+ fetch-depth: 1
32
+ persist-credentials: false
33
+
34
+ - name: Setup pnpm
35
+ uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4
36
+
37
+ - name: Setup Node.js
38
+ uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
39
+ with:
40
+ node-version: 20
41
+ cache: pnpm
42
+
43
+ - name: Install Dependencies
44
+ run: pnpm install --frozen-lockfile
45
+
46
+ - name: Validate Ultramodern Workspace Contract
47
+ run: pnpm run ultramodern:check
48
+
49
+ - name: Build Workspace Apps
50
+ env:
51
+ MODERN_PUBLIC_SITE_URL: http://localhost:8080
52
+ run: pnpm -r --filter "./apps/**" run build
@@ -38,6 +38,15 @@ pnpm skills:install
38
38
 
39
39
  The installer copies only the allowlisted private skills from `.agents/skills-lock.json`: `plan-graph`, `dag`, `subagent-graph`, `helm`, and `debugger-mode`.
40
40
 
41
+ ## Agent Reference Repositories
42
+
43
+ The workspace installs read-only source snapshots under `repos/` by default during `pnpm install`. These repositories are reference material for coding agents, not application source:
44
+
45
+ - `repos/effect` from `Effect-TS/effect`.
46
+ - `repos/ultramodern.js` from `BleedingDev/ultramodern.js`.
47
+
48
+ Agents may read files under `repos/` to understand upstream patterns, APIs, and project conventions. Do not edit files under `repos/`, import from them, or make production code depend on them. To skip this setup, run installs with `ULTRAMODERN_SKIP_AGENT_REPOS=1`.
49
+
41
50
  ## Project Priorities
42
51
 
43
52
  - Keep `presetUltramodern` as the single preset.
@@ -19,7 +19,17 @@ Run the scaffold validator before adding business code:
19
19
  pnpm ultramodern:check
20
20
  ```
21
21
 
22
- The topology and ownership metadata are generated under `topology/`.
22
+ By default, `pnpm install` also prepares read-only agent reference repositories
23
+ under `repos/` for Effect and UltraModern.js source lookup. Disable this setup
24
+ with `ULTRAMODERN_SKIP_AGENT_REPOS=1 pnpm install`, or rerun it explicitly with
25
+ `pnpm agents:refs:install`.
26
+
27
+ The topology and ownership metadata are generated under `topology/`. The
28
+ workspace also ships `.github/workflows/ultramodern-workspace-gates.yml` and
29
+ `.github/renovate.json` with read-only workflow permissions, commit-pinned
30
+ actions, frozen installs, StepSecurity audit-mode runner hardening, dependency
31
+ dashboard review, one-day release age, grouped updates, and manual approval for
32
+ major upgrades.
23
33
 
24
34
  Package source metadata is generated at
25
35
  `.modernjs/ultramodern-package-source.json`. The default strategy keeps
@@ -0,0 +1,217 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+
5
+ const root = process.cwd();
6
+ const args = new Set(process.argv.slice(2));
7
+ const checkOnly = args.has('--check');
8
+ const configPath = path.join(root, '.agents', 'agent-reference-repos.json');
9
+ const manifestPath = path.join(root, '.modernjs', 'agent-reference-repos.json');
10
+ const tempRoot = path.join(root, '.modernjs', 'agent-reference-repos-tmp');
11
+
12
+ const truthy = value => /^(1|true|yes|on)$/i.test(String(value ?? ''));
13
+ const falsy = value => /^(0|false|no|off)$/i.test(String(value ?? ''));
14
+
15
+ const skipRequested =
16
+ truthy(process.env.ULTRAMODERN_SKIP_AGENT_REPOS) ||
17
+ falsy(process.env.ULTRAMODERN_AGENT_REPOS);
18
+ const required = truthy(process.env.ULTRAMODERN_AGENT_REPOS_REQUIRED);
19
+ const refresh = truthy(process.env.ULTRAMODERN_AGENT_REPOS_REFRESH);
20
+
21
+ const log = message => console.log(`[agent-reference-repos] ${message}`);
22
+ const warn = message => console.warn(`[agent-reference-repos] ${message}`);
23
+
24
+ function fail(message) {
25
+ if (required || checkOnly) {
26
+ throw new Error(message);
27
+ }
28
+ warn(message);
29
+ }
30
+
31
+ function readJson(filePath) {
32
+ return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
33
+ }
34
+
35
+ function run(command, commandArgs, options = {}) {
36
+ const result = spawnSync(command, commandArgs, {
37
+ cwd: options.cwd ?? root,
38
+ encoding: 'utf-8',
39
+ stdio: options.stdio ?? ['ignore', 'pipe', 'pipe'],
40
+ timeout: options.timeout ?? 120000,
41
+ });
42
+
43
+ if (result.error) {
44
+ throw result.error;
45
+ }
46
+ if (result.status !== 0) {
47
+ const stderr = result.stderr?.trim();
48
+ throw new Error(
49
+ `${command} ${commandArgs.join(' ')} failed${
50
+ stderr ? `: ${stderr}` : ''
51
+ }`,
52
+ );
53
+ }
54
+ return result.stdout?.trim() ?? '';
55
+ }
56
+
57
+ function assertSafeRepoPath(relativePath) {
58
+ if (
59
+ typeof relativePath !== 'string' ||
60
+ relativePath.length === 0 ||
61
+ path.isAbsolute(relativePath) ||
62
+ relativePath.split(/[\\/]+/).includes('..') ||
63
+ !relativePath.startsWith('repos/')
64
+ ) {
65
+ throw new Error(`Unsafe reference repository path: ${relativePath}`);
66
+ }
67
+ }
68
+
69
+ function hasGit() {
70
+ const result = spawnSync('git', ['--version'], {
71
+ encoding: 'utf-8',
72
+ stdio: ['ignore', 'pipe', 'pipe'],
73
+ });
74
+ return result.status === 0;
75
+ }
76
+
77
+ function existingReference(targetPath, repo) {
78
+ const markerPath = path.join(targetPath, '.ultramodern-reference-repo.json');
79
+ if (!fs.existsSync(markerPath)) {
80
+ return undefined;
81
+ }
82
+ try {
83
+ const marker = readJson(markerPath);
84
+ if (marker.url === repo.url && marker.ref === repo.ref) {
85
+ return marker;
86
+ }
87
+ } catch {
88
+ return undefined;
89
+ }
90
+ return undefined;
91
+ }
92
+
93
+ function materializeRepository(repo) {
94
+ assertSafeRepoPath(repo.path);
95
+ const targetPath = path.join(root, repo.path);
96
+ const existing = existingReference(targetPath, repo);
97
+
98
+ if (existing && !refresh) {
99
+ log(`${repo.id} already present at ${repo.path} (${existing.commit})`);
100
+ return { ...existing, status: 'present' };
101
+ }
102
+
103
+ if (fs.existsSync(targetPath)) {
104
+ if (!refresh) {
105
+ fail(`${repo.path} exists but is not a managed reference repo`);
106
+ return undefined;
107
+ }
108
+ fs.rmSync(targetPath, { recursive: true, force: true });
109
+ }
110
+
111
+ if (checkOnly) {
112
+ fail(`${repo.path} is missing`);
113
+ return undefined;
114
+ }
115
+
116
+ fs.mkdirSync(tempRoot, { recursive: true });
117
+ const tempPath = fs.mkdtempSync(path.join(tempRoot, `${repo.id}-`));
118
+
119
+ try {
120
+ log(`cloning ${repo.name} from ${repo.url}#${repo.ref}`);
121
+ run(
122
+ 'git',
123
+ [
124
+ 'clone',
125
+ '--depth',
126
+ '1',
127
+ '--single-branch',
128
+ '--branch',
129
+ repo.ref,
130
+ '--filter=blob:none',
131
+ repo.url,
132
+ tempPath,
133
+ ],
134
+ { timeout: 300000 },
135
+ );
136
+ const commit = run('git', ['-C', tempPath, 'rev-parse', 'HEAD']);
137
+ fs.rmSync(path.join(tempPath, '.git'), { recursive: true, force: true });
138
+ fs.mkdirSync(path.dirname(targetPath), { recursive: true });
139
+ fs.renameSync(tempPath, targetPath);
140
+
141
+ const marker = {
142
+ schemaVersion: 1,
143
+ id: repo.id,
144
+ name: repo.name,
145
+ url: repo.url,
146
+ ref: repo.ref,
147
+ commit,
148
+ path: repo.path,
149
+ readOnly: repo.readOnly !== false,
150
+ installedAt: new Date().toISOString(),
151
+ };
152
+ fs.writeFileSync(
153
+ path.join(targetPath, '.ultramodern-reference-repo.json'),
154
+ `${JSON.stringify(marker, null, 2)}\n`,
155
+ );
156
+ log(`${repo.id} installed at ${repo.path} (${commit})`);
157
+ return { ...marker, status: 'installed' };
158
+ } catch (error) {
159
+ fs.rmSync(tempPath, { recursive: true, force: true });
160
+ fail(`Could not install ${repo.id}: ${error.message}`);
161
+ return undefined;
162
+ }
163
+ }
164
+
165
+ function main() {
166
+ if (!fs.existsSync(configPath)) {
167
+ fail('Missing .agents/agent-reference-repos.json');
168
+ return;
169
+ }
170
+
171
+ const config = readJson(configPath);
172
+ const enabled = config.defaultEnabled !== false && !skipRequested;
173
+
174
+ if (!enabled) {
175
+ log('setup skipped; set ULTRAMODERN_SKIP_AGENT_REPOS=0 to enable it again');
176
+ return;
177
+ }
178
+
179
+ if (!hasGit()) {
180
+ fail('git is required to install agent reference repositories');
181
+ return;
182
+ }
183
+
184
+ const installed = [];
185
+ for (const repo of config.repositories ?? []) {
186
+ const result = materializeRepository(repo);
187
+ if (result) {
188
+ installed.push(result);
189
+ }
190
+ }
191
+
192
+ if (!checkOnly) {
193
+ fs.mkdirSync(path.dirname(manifestPath), { recursive: true });
194
+ fs.writeFileSync(
195
+ manifestPath,
196
+ `${JSON.stringify(
197
+ {
198
+ schemaVersion: 1,
199
+ generatedAt: new Date().toISOString(),
200
+ installDir: config.installDir ?? 'repos',
201
+ repositories: installed,
202
+ },
203
+ null,
204
+ 2,
205
+ )}\n`,
206
+ );
207
+ }
208
+ }
209
+
210
+ try {
211
+ main();
212
+ } catch (error) {
213
+ console.error(`[agent-reference-repos] ${error.message}`);
214
+ process.exitCode = 1;
215
+ } finally {
216
+ fs.rmSync(tempRoot, { recursive: true, force: true });
217
+ }
@@ -36,12 +36,16 @@ const assertExists = (relativePath) => {
36
36
 
37
37
  const requiredPaths = [
38
38
  'AGENTS.md',
39
+ '.gitignore',
39
40
  'package.json',
40
41
  'pnpm-workspace.yaml',
41
42
  'tsconfig.base.json',
42
43
  'oxlint.config.ts',
43
44
  'oxfmt.config.ts',
45
+ '.github/renovate.json',
46
+ '.github/workflows/ultramodern-workspace-gates.yml',
44
47
  '.agents/skills-lock.json',
48
+ '.agents/agent-reference-repos.json',
45
49
  '.agents/rstackjs-agent-skills-LICENSE',
46
50
  '.agents/skills/rsbuild-best-practices/SKILL.md',
47
51
  '.agents/skills/rspack-best-practices/SKILL.md',
@@ -59,6 +63,7 @@ const requiredPaths = [
59
63
  '.modernjs/ultramodern-workspace-template-manifest.json',
60
64
  '.modernjs/ultramodern-package-source.json',
61
65
  'scripts/bootstrap-agent-skills.mjs',
66
+ 'scripts/setup-agent-reference-repos.mjs',
62
67
  'scripts/check-i18n-strings.mjs',
63
68
  'apps/shell-super-app/package.json',
64
69
  'apps/shell-super-app/config/public/locales/en/translation.json',
@@ -120,7 +125,10 @@ for (const appDirectory of [
120
125
  const rootPackage = readJson('package.json');
121
126
  const packageSource = readJson('.modernjs/ultramodern-package-source.json');
122
127
  const skillsLock = readJson('.agents/skills-lock.json');
128
+ const agentReferenceRepos = readJson('.agents/agent-reference-repos.json');
123
129
  const pnpmWorkspace = readText('pnpm-workspace.yaml');
130
+ const workflowContent = readText('.github/workflows/ultramodern-workspace-gates.yml');
131
+ const renovateConfig = readJson('.github/renovate.json');
124
132
  const deprecatedTanstackRuntime = '@modern-js/runtime/' + 'tanstack-router';
125
133
  const expectedModernSpecifier =
126
134
  packageSource.strategy === 'install' ? packageSource.modernPackages?.specifier : 'workspace:*';
@@ -164,6 +172,42 @@ assert(
164
172
  !pnpmWorkspace.includes('onlyBuiltDependencies'),
165
173
  'pnpm-workspace.yaml must use pnpm 11 allowBuilds instead of onlyBuiltDependencies',
166
174
  );
175
+ for (const requiredSnippet of [
176
+ 'permissions:\n contents: read',
177
+ 'pull_request:',
178
+ 'persist-credentials: false',
179
+ 'pnpm install --frozen-lockfile',
180
+ 'pnpm -r --filter "./apps/**" run build',
181
+ 'MODERN_PUBLIC_SITE_URL: http://localhost:8080',
182
+ 'timeout-minutes:',
183
+ 'egress-policy: audit',
184
+ ]) {
185
+ assert(
186
+ workflowContent.includes(requiredSnippet),
187
+ `Generated workspace workflow must retain ${requiredSnippet.split('\n')[0]}`,
188
+ );
189
+ }
190
+ assert(
191
+ !workflowContent.includes('pull_request_target'),
192
+ 'Generated workspace workflow must not use pull_request_target',
193
+ );
194
+ for (const match of workflowContent.matchAll(/^\s*uses:\s*([^@\s]+)@([^\s#]+)/gmu)) {
195
+ const [, actionName, actionRef] = match;
196
+ assert(
197
+ /^[a-f0-9]{40}$/u.test(actionRef),
198
+ `Generated workspace workflow must pin ${actionName}@${actionRef} to a commit SHA`,
199
+ );
200
+ }
201
+ assert(
202
+ renovateConfig.dependencyDashboard === true &&
203
+ renovateConfig.minimumReleaseAge === '1 day' &&
204
+ renovateConfig.extends?.includes('helpers:pinGitHubActionDigests') &&
205
+ renovateConfig.packageRules?.some(
206
+ (rule) =>
207
+ rule.dependencyDashboardApproval === true && rule.matchUpdateTypes?.includes('major'),
208
+ ),
209
+ 'Generated workspace Renovate config must retain dashboard, release-age, action pinning, and major-approval policy',
210
+ );
167
211
  assert(
168
212
  rootPackage.modernjs?.packageSource?.config === './.modernjs/ultramodern-package-source.json',
169
213
  'Root must point to the UltraModern package source metadata',
@@ -197,6 +241,9 @@ const requiredRootScripts = {
197
241
  'i18n:check': 'node ./scripts/check-i18n-strings.mjs',
198
242
  lint: 'oxlint .',
199
243
  'lint:fix': 'oxlint . --fix',
244
+ 'agents:refs:check': 'node ./scripts/setup-agent-reference-repos.mjs --check',
245
+ 'agents:refs:install': 'node ./scripts/setup-agent-reference-repos.mjs',
246
+ postinstall: 'node ./scripts/setup-agent-reference-repos.mjs',
200
247
  'skills:check': 'node ./scripts/bootstrap-agent-skills.mjs --check',
201
248
  'skills:install': 'node ./scripts/bootstrap-agent-skills.mjs',
202
249
  typecheck: `pnpm -r --filter "@${packageScope}/*" typecheck`,
@@ -234,6 +281,34 @@ assert(
234
281
  skillsLock.installDir === '.agents/skills',
235
282
  'Agent skills lock must use .agents/skills as installDir',
236
283
  );
284
+ assert(
285
+ agentReferenceRepos.defaultEnabled === true,
286
+ 'Agent reference repositories must be enabled by default',
287
+ );
288
+ assert(
289
+ agentReferenceRepos.repositories?.some(
290
+ (repo) =>
291
+ repo.id === 'effect' &&
292
+ repo.url === 'https://github.com/Effect-TS/effect.git' &&
293
+ repo.path === 'repos/effect',
294
+ ),
295
+ 'Agent reference repositories must include Effect',
296
+ );
297
+ assert(
298
+ agentReferenceRepos.repositories?.some(
299
+ (repo) =>
300
+ repo.id === 'ultramodern-js' &&
301
+ repo.url === 'https://github.com/BleedingDev/ultramodern.js.git' &&
302
+ repo.path === 'repos/ultramodern.js',
303
+ ),
304
+ 'Agent reference repositories must include UltraModern.js',
305
+ );
306
+ assert(
307
+ readText('scripts/setup-agent-reference-repos.mjs').includes(
308
+ 'ULTRAMODERN_SKIP_AGENT_REPOS',
309
+ ),
310
+ 'Agent reference repository setup must expose an opt-out environment variable',
311
+ );
237
312
  for (const skillName of baselineAgentSkills) {
238
313
  assert(
239
314
  skillsLock.baseline?.some((skill) => skill.name === skillName),
@@ -317,6 +392,10 @@ for (const packagePath of appPackagePaths) {
317
392
  packageJson.dependencies?.['@module-federation/modern-js-v3'] === '2.4.0',
318
393
  `${packagePath} must include the Module Federation plugin`,
319
394
  );
395
+ assert(
396
+ packageJson.dependencies?.['zephyr-modernjs-plugin'] === '1.1.1',
397
+ `${packagePath} must include the official Zephyr Modern.js plugin`,
398
+ );
320
399
  assert(
321
400
  packageJson.modernjs?.preset === 'presetUltramodern',
322
401
  `${packagePath} must keep presetUltramodern metadata`,
@@ -343,6 +422,27 @@ for (const configPath of [
343
422
  config.includes('moduleFederationPlugin()'),
344
423
  `${configPath} must enable Module Federation`,
345
424
  );
425
+ assert(
426
+ config.includes("from 'zephyr-modernjs-plugin'"),
427
+ `${configPath} must import the official Zephyr Modern.js plugin`,
428
+ );
429
+ assert(config.includes('withZephyr()'), `${configPath} must enable Zephyr through plugins`);
430
+ assert(
431
+ config.includes("bundler: 'rspack'"),
432
+ `${configPath} must keep appTools on the rspack bundler for Zephyr`,
433
+ );
434
+ assert(
435
+ config.includes("html: './'"),
436
+ `${configPath} must keep Modern.js output.distPath.html compatible with Zephyr`,
437
+ );
438
+ assert(
439
+ config.includes("outputStructure: 'flat'"),
440
+ `${configPath} must keep Modern.js HTML output flat for Zephyr`,
441
+ );
442
+ assert(
443
+ config.includes("mainEntryName: 'index'"),
444
+ `${configPath} must keep Modern.js source.mainEntryName compatible with Zephyr`,
445
+ );
346
446
  }
347
447
 
348
448
  for (const routePath of [
@@ -506,5 +606,9 @@ assert(
506
606
  manifest.validation?.postMaterializationValidation?.includes('pnpm-11-policy-enforced'),
507
607
  'Template manifest must document pnpm 11 policy validation',
508
608
  );
609
+ assert(
610
+ manifest.validation?.postMaterializationValidation?.includes('github-workflow-security-enforced'),
611
+ 'Template manifest must document generated workflow security validation',
612
+ );
509
613
 
510
614
  console.log('UltraModern workspace scaffold validated');