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

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 (165) hide show
  1. package/README.md +167 -72
  2. package/bin/run.js +0 -0
  3. package/dist/cjs/create-package-root.cjs +63 -0
  4. package/dist/cjs/index.cjs +528 -0
  5. package/dist/cjs/locale/en.cjs +93 -0
  6. package/dist/cjs/locale/index.cjs +50 -0
  7. package/dist/cjs/locale/zh.cjs +93 -0
  8. package/dist/cjs/ultramodern-package-source.cjs +135 -0
  9. package/dist/cjs/ultramodern-workspace/add-vertical.cjs +337 -0
  10. package/dist/cjs/ultramodern-workspace/app-files.cjs +223 -0
  11. package/dist/cjs/ultramodern-workspace/contracts.cjs +836 -0
  12. package/dist/cjs/ultramodern-workspace/demo-components.cjs +422 -0
  13. package/dist/cjs/ultramodern-workspace/descriptors.cjs +222 -0
  14. package/dist/cjs/ultramodern-workspace/effect-api.cjs +952 -0
  15. package/dist/cjs/ultramodern-workspace/fs-io.cjs +191 -0
  16. package/dist/cjs/ultramodern-workspace/index.cjs +48 -0
  17. package/dist/cjs/ultramodern-workspace/locales.cjs +173 -0
  18. package/dist/cjs/ultramodern-workspace/module-federation.cjs +487 -0
  19. package/dist/cjs/ultramodern-workspace/naming.cjs +161 -0
  20. package/dist/cjs/ultramodern-workspace/package-json.cjs +406 -0
  21. package/dist/cjs/ultramodern-workspace/package-source.cjs +59 -0
  22. package/dist/cjs/ultramodern-workspace/policy.cjs +248 -0
  23. package/dist/cjs/ultramodern-workspace/public-surface.cjs +268 -0
  24. package/dist/cjs/ultramodern-workspace/routes.cjs +375 -0
  25. package/dist/cjs/ultramodern-workspace/types.cjs +61 -0
  26. package/dist/cjs/ultramodern-workspace/versions.cjs +153 -0
  27. package/dist/cjs/ultramodern-workspace/workspace-scripts.cjs +153 -0
  28. package/dist/cjs/ultramodern-workspace/write-workspace.cjs +175 -0
  29. package/dist/esm/create-package-root.js +14 -0
  30. package/dist/esm/index.js +491 -0
  31. package/dist/esm/locale/en.js +55 -0
  32. package/dist/esm/locale/index.js +9 -0
  33. package/dist/esm/locale/zh.js +55 -0
  34. package/dist/esm/ultramodern-package-source.js +63 -0
  35. package/dist/esm/ultramodern-workspace/add-vertical.js +252 -0
  36. package/dist/esm/ultramodern-workspace/app-files.js +149 -0
  37. package/dist/esm/ultramodern-workspace/contracts.js +741 -0
  38. package/dist/esm/ultramodern-workspace/demo-components.js +363 -0
  39. package/dist/esm/ultramodern-workspace/descriptors.js +133 -0
  40. package/dist/esm/ultramodern-workspace/effect-api.js +854 -0
  41. package/dist/esm/ultramodern-workspace/fs-io.js +90 -0
  42. package/dist/esm/ultramodern-workspace/index.js +3 -0
  43. package/dist/esm/ultramodern-workspace/locales.js +122 -0
  44. package/dist/esm/ultramodern-workspace/module-federation.js +415 -0
  45. package/dist/esm/ultramodern-workspace/naming.js +71 -0
  46. package/dist/esm/ultramodern-workspace/package-json.js +338 -0
  47. package/dist/esm/ultramodern-workspace/package-source.js +21 -0
  48. package/dist/esm/ultramodern-workspace/policy.js +183 -0
  49. package/dist/esm/ultramodern-workspace/public-surface.js +183 -0
  50. package/dist/esm/ultramodern-workspace/routes.js +280 -0
  51. package/dist/esm/ultramodern-workspace/types.js +16 -0
  52. package/dist/esm/ultramodern-workspace/versions.js +34 -0
  53. package/dist/esm/ultramodern-workspace/workspace-scripts.js +91 -0
  54. package/dist/esm/ultramodern-workspace/write-workspace.js +121 -0
  55. package/dist/esm-node/create-package-root.js +15 -0
  56. package/dist/esm-node/index.js +492 -0
  57. package/dist/esm-node/locale/en.js +56 -0
  58. package/dist/esm-node/locale/index.js +10 -0
  59. package/dist/esm-node/locale/zh.js +56 -0
  60. package/dist/esm-node/ultramodern-package-source.js +64 -0
  61. package/dist/esm-node/ultramodern-workspace/add-vertical.js +253 -0
  62. package/dist/esm-node/ultramodern-workspace/app-files.js +150 -0
  63. package/dist/esm-node/ultramodern-workspace/contracts.js +742 -0
  64. package/dist/esm-node/ultramodern-workspace/demo-components.js +364 -0
  65. package/dist/esm-node/ultramodern-workspace/descriptors.js +134 -0
  66. package/dist/esm-node/ultramodern-workspace/effect-api.js +855 -0
  67. package/dist/esm-node/ultramodern-workspace/fs-io.js +91 -0
  68. package/dist/esm-node/ultramodern-workspace/index.js +4 -0
  69. package/dist/esm-node/ultramodern-workspace/locales.js +123 -0
  70. package/dist/esm-node/ultramodern-workspace/module-federation.js +416 -0
  71. package/dist/esm-node/ultramodern-workspace/naming.js +72 -0
  72. package/dist/esm-node/ultramodern-workspace/package-json.js +339 -0
  73. package/dist/esm-node/ultramodern-workspace/package-source.js +22 -0
  74. package/dist/esm-node/ultramodern-workspace/policy.js +184 -0
  75. package/dist/esm-node/ultramodern-workspace/public-surface.js +184 -0
  76. package/dist/esm-node/ultramodern-workspace/routes.js +281 -0
  77. package/dist/esm-node/ultramodern-workspace/types.js +17 -0
  78. package/dist/esm-node/ultramodern-workspace/versions.js +35 -0
  79. package/dist/esm-node/ultramodern-workspace/workspace-scripts.js +92 -0
  80. package/dist/esm-node/ultramodern-workspace/write-workspace.js +122 -0
  81. package/dist/types/create-package-root.d.ts +1 -0
  82. package/dist/types/locale/en.d.ts +8 -9
  83. package/dist/types/locale/index.d.ts +109 -2
  84. package/dist/types/locale/zh.d.ts +8 -9
  85. package/dist/types/ultramodern-package-source.d.ts +28 -0
  86. package/dist/types/ultramodern-workspace/add-vertical.d.ts +19 -0
  87. package/dist/types/ultramodern-workspace/app-files.d.ts +14 -0
  88. package/dist/types/ultramodern-workspace/contracts.d.ts +21 -0
  89. package/dist/types/ultramodern-workspace/demo-components.d.ts +9 -0
  90. package/dist/types/ultramodern-workspace/descriptors.d.ts +39 -0
  91. package/dist/types/ultramodern-workspace/effect-api.d.ts +73 -0
  92. package/dist/types/ultramodern-workspace/fs-io.d.ts +18 -0
  93. package/dist/types/ultramodern-workspace/index.d.ts +4 -0
  94. package/dist/types/ultramodern-workspace/locales.d.ts +183 -0
  95. package/dist/types/ultramodern-workspace/module-federation.d.ts +16 -0
  96. package/dist/types/ultramodern-workspace/naming.d.ts +16 -0
  97. package/dist/types/ultramodern-workspace/package-json.d.ts +12 -0
  98. package/dist/types/ultramodern-workspace/package-source.d.ts +2 -0
  99. package/dist/types/ultramodern-workspace/policy.d.ts +60 -0
  100. package/dist/types/ultramodern-workspace/public-surface.d.ts +37 -0
  101. package/dist/types/ultramodern-workspace/routes.d.ts +25 -0
  102. package/dist/types/ultramodern-workspace/types.d.ts +95 -0
  103. package/dist/types/ultramodern-workspace/versions.d.ts +38 -0
  104. package/dist/types/ultramodern-workspace/workspace-scripts.d.ts +10 -0
  105. package/dist/types/ultramodern-workspace/write-workspace.d.ts +4 -0
  106. package/package.json +34 -15
  107. package/template-workspace/.agents/agent-reference-repos.json +24 -0
  108. package/template-workspace/.agents/skills-lock.json +19 -0
  109. package/template-workspace/.codex/hooks.json +16 -0
  110. package/template-workspace/.github/renovate.json +29 -0
  111. package/template-workspace/.github/workflows/ultramodern-workspace-gates.yml.handlebars +67 -0
  112. package/template-workspace/.gitignore.handlebars +5 -0
  113. package/template-workspace/.mise.toml.handlebars +3 -0
  114. package/template-workspace/AGENTS.md.handlebars +87 -0
  115. package/template-workspace/README.md.handlebars +132 -11
  116. package/template-workspace/lefthook.yml +24 -0
  117. package/template-workspace/oxfmt.config.ts +1 -0
  118. package/template-workspace/oxlint.config.ts +1 -0
  119. package/template-workspace/pnpm-workspace.yaml.handlebars +40 -0
  120. package/template-workspace/scripts/bootstrap-agent-skills.mjs +184 -21
  121. package/template-workspace/scripts/setup-agent-reference-repos.mjs +370 -0
  122. package/templates/app/shell-frame.tsx +49 -0
  123. package/templates/app/ultramodern-route-head.tsx.handlebars +142 -0
  124. package/templates/packages/shared-contracts-index.ts +466 -0
  125. package/templates/workspace-scripts/assert-mf-types.mjs.handlebars +69 -0
  126. package/templates/workspace-scripts/check-ultramodern-i18n-boundaries.mjs +9 -0
  127. package/templates/workspace-scripts/generate-public-surface-assets.mjs +529 -0
  128. package/templates/workspace-scripts/proof-cloudflare-version.mjs +125 -0
  129. package/templates/workspace-scripts/ultramodern-cloudflare-proof.mjs +851 -0
  130. package/templates/workspace-scripts/ultramodern-performance-readiness.config.mjs +7 -0
  131. package/templates/workspace-scripts/ultramodern-performance-readiness.mjs +223 -0
  132. package/templates/workspace-scripts/validate-ultramodern-workspace.mjs.handlebars +593 -0
  133. package/dist/index.js +0 -2626
  134. package/dist/types/ultramodern-workspace.d.ts +0 -20
  135. package/template/.agents/skills-lock.json +0 -34
  136. package/template/.browserslistrc +0 -4
  137. package/template/.github/workflows/ultramodern-gates.yml.handlebars +0 -30
  138. package/template/.gitignore.handlebars +0 -30
  139. package/template/.nvmrc +0 -2
  140. package/template/AGENTS.md +0 -25
  141. package/template/README.md +0 -79
  142. package/template/api/effect/index.ts.handlebars +0 -23
  143. package/template/api/lambda/hello.ts.handlebars +0 -6
  144. package/template/config/public/locales/cs/translation.json +0 -39
  145. package/template/config/public/locales/en/translation.json +0 -39
  146. package/template/modern.config.ts.handlebars +0 -53
  147. package/template/oxfmt.config.ts +0 -8
  148. package/template/oxlint.config.ts +0 -12
  149. package/template/package.json.handlebars +0 -67
  150. package/template/postcss.config.mjs.handlebars +0 -6
  151. package/template/scripts/bootstrap-agent-skills.mjs +0 -95
  152. package/template/scripts/check-i18n-strings.mjs +0 -83
  153. package/template/scripts/validate-ultramodern.mjs.handlebars +0 -178
  154. package/template/shared/effect/api.ts.handlebars +0 -17
  155. package/template/src/modern-app-env.d.ts +0 -1
  156. package/template/src/modern.runtime.ts.handlebars +0 -23
  157. package/template/src/routes/index.css.handlebars +0 -129
  158. package/template/src/routes/layout.tsx.handlebars +0 -9
  159. package/template/src/routes/page.tsx.handlebars +0 -155
  160. package/template/tailwind.config.ts.handlebars +0 -10
  161. package/template/tsconfig.json +0 -120
  162. package/template-workspace/AGENTS.md +0 -50
  163. package/template-workspace/pnpm-workspace.yaml +0 -17
  164. package/template-workspace/scripts/check-i18n-strings.mjs +0 -83
  165. package/template-workspace/scripts/validate-ultramodern-workspace.mjs.handlebars +0 -433
@@ -7,26 +7,122 @@ const root = process.cwd();
7
7
  const lockPath = path.join(root, '.agents/skills-lock.json');
8
8
  const checkOnly = process.argv.includes('--check');
9
9
  const force = process.argv.includes('--force');
10
+ const postinstall = process.argv.includes('--postinstall');
11
+ const truthy = value => /^(1|true|yes|on)$/i.test(String(value ?? ''));
12
+ const falsy = value => /^(0|false|no|off)$/i.test(String(value ?? ''));
13
+ const skipRequested =
14
+ truthy(process.env.ULTRAMODERN_SKIP_AGENT_SKILLS) ||
15
+ falsy(process.env.ULTRAMODERN_AGENT_SKILLS);
16
+ const cloneTimeoutMs = Number.parseInt(
17
+ process.env.ULTRAMODERN_AGENT_SKILLS_CLONE_TIMEOUT_MS ?? '60000',
18
+ 10,
19
+ );
10
20
 
11
- const readJson = (filePath) => JSON.parse(fs.readFileSync(filePath, 'utf-8'));
21
+ const readJson = filePath => JSON.parse(fs.readFileSync(filePath, 'utf-8'));
12
22
 
13
23
  const run = (command, args, options = {}) =>
14
24
  execFileSync(command, args, {
15
25
  cwd: options.cwd ?? root,
16
26
  encoding: 'utf-8',
17
27
  stdio: options.stdio ?? ['ignore', 'pipe', 'pipe'],
28
+ timeout: options.timeout,
29
+ });
30
+
31
+ const commandExists = command => {
32
+ try {
33
+ run(command, ['--version'], { stdio: 'ignore' });
34
+ return true;
35
+ } catch {
36
+ return false;
37
+ }
38
+ };
39
+
40
+ const requireGit = () => {
41
+ if (commandExists('git')) {
42
+ return;
43
+ }
44
+
45
+ throw new Error(
46
+ 'Git is required to install agent skills. Install git yourself (for example "brew install git" or "sudo apt-get install git") and run pnpm skills:install again. This script never installs system packages on your behalf.',
47
+ );
48
+ };
49
+
50
+ const isInsideGitWorkTree = () => {
51
+ try {
52
+ return run('git', ['rev-parse', '--is-inside-work-tree']).trim() === 'true';
53
+ } catch {
54
+ return false;
55
+ }
56
+ };
57
+
58
+ const initializeGitRepository = () => {
59
+ if (isInsideGitWorkTree()) {
60
+ return;
61
+ }
62
+
63
+ try {
64
+ run('git', ['init', '-b', 'main'], { stdio: 'inherit' });
65
+ } catch {
66
+ run('git', ['init'], { stdio: 'inherit' });
67
+ run('git', ['branch', '-M', 'main'], { stdio: 'inherit' });
68
+ }
69
+ };
70
+
71
+ const installLefthook = () => {
72
+ try {
73
+ run('lefthook', ['install'], { stdio: 'inherit' });
74
+ } catch (error) {
75
+ console.warn(`Unable to install lefthook hooks: ${error.message}`);
76
+ }
77
+ };
78
+
79
+ const removeTree = dir =>
80
+ fs.rmSync(dir, {
81
+ force: true,
82
+ maxRetries: 5,
83
+ recursive: true,
84
+ retryDelay: 100,
18
85
  });
19
86
 
20
87
  const cloneSource = (source, targetDir) => {
88
+ if (source.commit) {
89
+ run('git', ['init', targetDir], { timeout: 30000 });
90
+ run('git', ['remote', 'add', 'origin', source.repository], {
91
+ cwd: targetDir,
92
+ timeout: 30000,
93
+ });
94
+ run('git', ['fetch', '--depth', '1', '--quiet', 'origin', source.commit], {
95
+ cwd: targetDir,
96
+ timeout: cloneTimeoutMs,
97
+ });
98
+ run(
99
+ 'git',
100
+ [
101
+ '-c',
102
+ 'advice.detachedHead=false',
103
+ 'checkout',
104
+ '--detach',
105
+ '--quiet',
106
+ 'FETCH_HEAD',
107
+ ],
108
+ { cwd: targetDir, timeout: 30000 },
109
+ );
110
+ return;
111
+ }
112
+
21
113
  const repo = source.repository.replace(/^https:\/\/github.com\//u, '');
22
114
  try {
23
- run('gh', ['repo', 'clone', repo, targetDir, '--', '--depth', '1'], {
24
- stdio: 'inherit',
25
- });
115
+ run(
116
+ 'gh',
117
+ ['repo', 'clone', repo, targetDir, '--', '--depth', '1', '--quiet'],
118
+ { timeout: cloneTimeoutMs },
119
+ );
26
120
  } catch {
27
- run('git', ['clone', '--depth', '1', source.repository, targetDir], {
28
- stdio: 'inherit',
29
- });
121
+ run(
122
+ 'git',
123
+ ['clone', '--depth', '1', '--quiet', source.repository, targetDir],
124
+ { timeout: cloneTimeoutMs },
125
+ );
30
126
  }
31
127
  };
32
128
 
@@ -37,7 +133,9 @@ const resolveSkillDir = (sourceRoot, skillName) => {
37
133
  path.join(sourceRoot, 'skills', 'engineering', skillName),
38
134
  path.join(sourceRoot, 'skills', 'productivity', skillName),
39
135
  ];
40
- return candidates.find((candidate) => fs.existsSync(path.join(candidate, 'SKILL.md')));
136
+ return candidates.find(candidate =>
137
+ fs.existsSync(path.join(candidate, 'SKILL.md')),
138
+ );
41
139
  };
42
140
 
43
141
  if (!fs.existsSync(lockPath)) {
@@ -47,36 +145,99 @@ if (!fs.existsSync(lockPath)) {
47
145
 
48
146
  const lock = readJson(lockPath);
49
147
  const installDir = path.join(root, lock.installDir ?? '.agents/skills');
50
- const privateSources = (lock.sources ?? []).filter(
51
- (source) => source.install === 'clone-if-authorized',
148
+ const sources = lock.sources ?? [];
149
+ const requiredCloneSources = sources.filter(
150
+ source => source.install === 'clone',
151
+ );
152
+ const optionalCloneSources = sources.filter(
153
+ source => source.install === 'clone-if-authorized',
154
+ );
155
+ const cloneSourceSkillNames = new Set(
156
+ [...requiredCloneSources, ...optionalCloneSources].flatMap(source =>
157
+ (source.baseline ?? []).map(skill => skill.name),
158
+ ),
52
159
  );
160
+ const vendoredRequiredSkills = (lock.baseline ?? []).filter(
161
+ skill => !cloneSourceSkillNames.has(skill.name),
162
+ );
163
+ const cloneOptIn = truthy(process.env.ULTRAMODERN_AGENT_SKILLS);
164
+
165
+ if (skipRequested) {
166
+ const reason = 'agent skills bootstrap skipped by environment';
167
+ if (checkOnly) {
168
+ console.log(reason);
169
+ process.exit(0);
170
+ }
171
+ console.log(reason);
172
+ installLefthook();
173
+ process.exit(0);
174
+ }
53
175
 
54
176
  if (checkOnly) {
55
- const missing = privateSources.flatMap((source) =>
177
+ const missingVendored = vendoredRequiredSkills
178
+ .map(skill => skill.name)
179
+ .filter(
180
+ skillName => !fs.existsSync(path.join(installDir, skillName, 'SKILL.md')),
181
+ );
182
+ const missingCloneInstalled = [
183
+ ...requiredCloneSources,
184
+ ...optionalCloneSources,
185
+ ].flatMap(source =>
56
186
  (source.baseline ?? [])
57
- .map((skill) => skill.name)
58
- .filter((skillName) => !fs.existsSync(path.join(installDir, skillName, 'SKILL.md'))),
187
+ .map(skill => skill.name)
188
+ .filter(
189
+ skillName =>
190
+ !fs.existsSync(path.join(installDir, skillName, 'SKILL.md')),
191
+ ),
59
192
  );
60
- if (missing.length > 0) {
193
+
194
+ if (missingVendored.length > 0) {
195
+ console.error(
196
+ `Required agent skills not installed: ${missingVendored.join(', ')}. Run pnpm skills:install.`,
197
+ );
198
+ process.exit(1);
199
+ }
200
+
201
+ if (missingCloneInstalled.length > 0) {
61
202
  console.warn(
62
- `Private skills not installed: ${missing.join(', ')}. Run pnpm skills:install if you have access.`,
203
+ `Clone-installed agent skills not present: ${missingCloneInstalled.join(', ')}. Run pnpm skills:install to fetch them.`,
63
204
  );
64
205
  } else {
65
- console.log('Agent skills are installed.');
206
+ console.log('All pinned agent skills are installed.');
66
207
  }
67
208
  process.exit(0);
68
209
  }
69
210
 
211
+ if (postinstall && !cloneOptIn) {
212
+ console.log(
213
+ 'Skipping agent skill repository clones during postinstall. Run pnpm skills:install (or set ULTRAMODERN_AGENT_SKILLS=1 before installing) to fetch them.',
214
+ );
215
+ installLefthook();
216
+ process.exit(0);
217
+ }
218
+
70
219
  fs.mkdirSync(installDir, { recursive: true });
220
+ requireGit();
221
+ initializeGitRepository();
71
222
 
72
- for (const source of privateSources) {
223
+ for (const source of [...requiredCloneSources, ...optionalCloneSources]) {
73
224
  const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ultramodern-skills-'));
74
225
  try {
75
- cloneSource(source, tempDir);
226
+ try {
227
+ cloneSource(source, tempDir);
228
+ } catch (error) {
229
+ if (source.install === 'clone-if-authorized' || postinstall) {
230
+ console.warn(`Skipping ${source.repository}; ${error.message}`);
231
+ continue;
232
+ }
233
+ throw error;
234
+ }
76
235
  for (const skill of source.baseline ?? []) {
77
236
  const sourceSkillDir = resolveSkillDir(tempDir, skill.name);
78
237
  if (!sourceSkillDir) {
79
- throw new Error(`Skill ${skill.name} not found in ${source.repository}`);
238
+ throw new Error(
239
+ `Skill ${skill.name} not found in ${source.repository}`,
240
+ );
80
241
  }
81
242
  const targetSkillDir = path.join(installDir, skill.name);
82
243
  if (fs.existsSync(targetSkillDir)) {
@@ -84,12 +245,14 @@ for (const source of privateSources) {
84
245
  console.log(`Skipping existing ${skill.name}`);
85
246
  continue;
86
247
  }
87
- fs.rmSync(targetSkillDir, { force: true, recursive: true });
248
+ removeTree(targetSkillDir);
88
249
  }
89
250
  fs.cpSync(sourceSkillDir, targetSkillDir, { recursive: true });
90
251
  console.log(`Installed ${skill.name}`);
91
252
  }
92
253
  } finally {
93
- fs.rmSync(tempDir, { force: true, recursive: true });
254
+ removeTree(tempDir);
94
255
  }
95
256
  }
257
+
258
+ installLefthook();
@@ -0,0 +1,370 @@
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
+
11
+ const truthy = value => /^(1|true|yes|on)$/i.test(String(value ?? ''));
12
+ const falsy = value => /^(0|false|no|off)$/i.test(String(value ?? ''));
13
+
14
+ const skipRequested =
15
+ truthy(process.env.ULTRAMODERN_SKIP_AGENT_REPOS) ||
16
+ falsy(process.env.ULTRAMODERN_AGENT_REPOS);
17
+ const required = truthy(process.env.ULTRAMODERN_AGENT_REPOS_REQUIRED);
18
+ const refresh = truthy(process.env.ULTRAMODERN_AGENT_REPOS_REFRESH);
19
+
20
+ const gitIdentityEnv = {
21
+ GIT_AUTHOR_NAME:
22
+ process.env.GIT_AUTHOR_NAME || 'UltraModern Agent Reference Setup',
23
+ GIT_AUTHOR_EMAIL:
24
+ process.env.GIT_AUTHOR_EMAIL || 'ultramodern-agent-refs@local',
25
+ GIT_COMMITTER_NAME:
26
+ process.env.GIT_COMMITTER_NAME || 'UltraModern Agent Reference Setup',
27
+ GIT_COMMITTER_EMAIL:
28
+ process.env.GIT_COMMITTER_EMAIL || 'ultramodern-agent-refs@local',
29
+ };
30
+
31
+ const log = message => console.log(`[agent-reference-repos] ${message}`);
32
+ const warn = message => console.warn(`[agent-reference-repos] ${message}`);
33
+
34
+ function fail(message) {
35
+ if (required || checkOnly) {
36
+ throw new Error(message);
37
+ }
38
+ warn(message);
39
+ }
40
+
41
+ function readJson(filePath) {
42
+ return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
43
+ }
44
+
45
+ function run(command, commandArgs, options = {}) {
46
+ const result = spawnSync(command, commandArgs, {
47
+ cwd: options.cwd ?? root,
48
+ encoding: 'utf-8',
49
+ env: {
50
+ ...process.env,
51
+ ...gitIdentityEnv,
52
+ ...(options.env ?? {}),
53
+ },
54
+ stdio: options.stdio ?? ['ignore', 'pipe', 'pipe'],
55
+ timeout: options.timeout ?? 120000,
56
+ });
57
+
58
+ if (result.error) {
59
+ throw result.error;
60
+ }
61
+ if (result.status !== 0) {
62
+ const stderr = result.stderr?.trim();
63
+ throw new Error(
64
+ `${command} ${commandArgs.join(' ')} failed${
65
+ stderr ? `: ${stderr}` : ''
66
+ }`,
67
+ );
68
+ }
69
+ return result.stdout?.trim() ?? '';
70
+ }
71
+
72
+ function assertSafeRepoPath(relativePath) {
73
+ if (
74
+ typeof relativePath !== 'string' ||
75
+ relativePath.length === 0 ||
76
+ path.isAbsolute(relativePath) ||
77
+ relativePath.split(/[\\/]+/).includes('..') ||
78
+ !relativePath.startsWith('repos/')
79
+ ) {
80
+ throw new Error(`Unsafe reference repository path: ${relativePath}`);
81
+ }
82
+ }
83
+
84
+ function hasGit() {
85
+ const result = spawnSync('git', ['--version'], {
86
+ encoding: 'utf-8',
87
+ stdio: ['ignore', 'pipe', 'pipe'],
88
+ });
89
+ return result.status === 0;
90
+ }
91
+
92
+ function hasGitSubtree() {
93
+ const result = spawnSync('git', ['subtree', '-h'], {
94
+ encoding: 'utf-8',
95
+ stdio: ['ignore', 'pipe', 'pipe'],
96
+ });
97
+ return (
98
+ (result.status === 0 || result.status === 129) &&
99
+ result.stdout.includes('usage: git subtree')
100
+ );
101
+ }
102
+
103
+ function isGitWorkTree() {
104
+ const result = spawnSync('git', ['rev-parse', '--is-inside-work-tree'], {
105
+ cwd: root,
106
+ encoding: 'utf-8',
107
+ stdio: ['ignore', 'pipe', 'pipe'],
108
+ });
109
+ return result.status === 0 && result.stdout.trim() === 'true';
110
+ }
111
+
112
+ function hasCommits() {
113
+ const result = spawnSync('git', ['rev-parse', '--verify', 'HEAD'], {
114
+ cwd: root,
115
+ encoding: 'utf-8',
116
+ stdio: ['ignore', 'pipe', 'pipe'],
117
+ });
118
+ return result.status === 0;
119
+ }
120
+
121
+ function porcelainStatus() {
122
+ return run('git', ['status', '--porcelain'], { timeout: 30000 });
123
+ }
124
+
125
+ function commitInstallerChanges(message) {
126
+ run('git', ['commit', '--no-verify', '-m', message], {
127
+ timeout: 120000,
128
+ });
129
+ }
130
+
131
+ function ensureGitRepository() {
132
+ if (!isGitWorkTree()) {
133
+ if (checkOnly) {
134
+ fail('workspace is not a git repository');
135
+ return false;
136
+ }
137
+ log('initializing git repository for agent reference subtrees');
138
+ run('git', ['init'], { timeout: 30000 });
139
+ }
140
+
141
+ if (!hasCommits()) {
142
+ if (checkOnly) {
143
+ fail('workspace has no initial git commit');
144
+ return false;
145
+ }
146
+ log('creating initial workspace commit before adding reference subtrees');
147
+ run('git', ['add', '-A'], { timeout: 30000 });
148
+ commitInstallerChanges('Initialize UltraModern workspace');
149
+ return true;
150
+ }
151
+
152
+ const status = porcelainStatus();
153
+ if (status) {
154
+ fail(
155
+ 'workspace has uncommitted changes; commit or stash them before installing reference subtrees',
156
+ );
157
+ return false;
158
+ }
159
+
160
+ return true;
161
+ }
162
+
163
+ function remoteCommit(repo) {
164
+ let output = run('git', ['ls-remote', repo.url, `refs/heads/${repo.ref}`], {
165
+ timeout: 120000,
166
+ });
167
+ if (!output) {
168
+ output = run('git', ['ls-remote', repo.url, repo.ref], {
169
+ timeout: 120000,
170
+ });
171
+ }
172
+ const [commit] = output.split(/\s+/);
173
+ if (!/^[a-f0-9]{40}$/i.test(commit ?? '')) {
174
+ throw new Error(`Could not resolve ${repo.url}#${repo.ref}`);
175
+ }
176
+ return commit;
177
+ }
178
+
179
+ function subtreeCommitExists(repo) {
180
+ const result = spawnSync(
181
+ 'git',
182
+ [
183
+ 'log',
184
+ '--grep',
185
+ `git-subtree-dir: ${repo.path}`,
186
+ '--format=%H',
187
+ '-n',
188
+ '1',
189
+ ],
190
+ {
191
+ cwd: root,
192
+ encoding: 'utf-8',
193
+ stdio: ['ignore', 'pipe', 'pipe'],
194
+ },
195
+ );
196
+ return result.status === 0 && result.stdout.trim().length > 0;
197
+ }
198
+
199
+ function installedManifestEntry(repo) {
200
+ if (!fs.existsSync(manifestPath)) {
201
+ return undefined;
202
+ }
203
+ try {
204
+ const manifest = readJson(manifestPath);
205
+ return manifest.repositories?.find(entry => entry.id === repo.id);
206
+ } catch {
207
+ return undefined;
208
+ }
209
+ }
210
+
211
+ function assertSubtreePresent(repo) {
212
+ assertSafeRepoPath(repo.path);
213
+ const targetPath = path.join(root, repo.path);
214
+ if (!fs.existsSync(targetPath)) {
215
+ fail(`${repo.path} is missing`);
216
+ return undefined;
217
+ }
218
+ if (!subtreeCommitExists(repo)) {
219
+ fail(`${repo.path} is present but has no git-subtree commit evidence`);
220
+ return undefined;
221
+ }
222
+ return (
223
+ installedManifestEntry(repo) ?? {
224
+ id: repo.id,
225
+ name: repo.name,
226
+ url: repo.url,
227
+ ref: repo.ref,
228
+ path: repo.path,
229
+ readOnly: repo.readOnly !== false,
230
+ status: 'present',
231
+ strategy: 'git-subtree-squash',
232
+ }
233
+ );
234
+ }
235
+
236
+ function addSubtree(repo) {
237
+ assertSafeRepoPath(repo.path);
238
+ const targetPath = path.join(root, repo.path);
239
+ const existing = fs.existsSync(targetPath);
240
+
241
+ if (existing && !refresh) {
242
+ return assertSubtreePresent(repo);
243
+ }
244
+
245
+ if (existing && refresh) {
246
+ fail(
247
+ `${repo.path} already exists; refresh for subtree references is intentionally manual`,
248
+ );
249
+ return undefined;
250
+ }
251
+
252
+ if (checkOnly) {
253
+ fail(`${repo.path} is missing`);
254
+ return undefined;
255
+ }
256
+
257
+ const commit = remoteCommit(repo);
258
+ log(`adding ${repo.name} as git subtree at ${repo.path} (${commit})`);
259
+ run('git', ['fetch', '--depth', '1', repo.url, repo.ref], {
260
+ timeout: 300000,
261
+ });
262
+ run(
263
+ 'git',
264
+ [
265
+ 'subtree',
266
+ 'add',
267
+ '--prefix',
268
+ repo.path,
269
+ 'FETCH_HEAD',
270
+ '--squash',
271
+ '-m',
272
+ `Add ${repo.name} agent reference repo`,
273
+ ],
274
+ { timeout: 600000 },
275
+ );
276
+
277
+ return {
278
+ schemaVersion: 1,
279
+ id: repo.id,
280
+ name: repo.name,
281
+ url: repo.url,
282
+ ref: repo.ref,
283
+ commit,
284
+ path: repo.path,
285
+ readOnly: repo.readOnly !== false,
286
+ strategy: 'git-subtree-squash',
287
+ status: 'installed',
288
+ installedAt: new Date().toISOString(),
289
+ };
290
+ }
291
+
292
+ function writeManifest(entries) {
293
+ fs.mkdirSync(path.dirname(manifestPath), { recursive: true });
294
+ fs.writeFileSync(
295
+ manifestPath,
296
+ `${JSON.stringify(
297
+ {
298
+ schemaVersion: 1,
299
+ generatedAt: new Date().toISOString(),
300
+ strategy: 'git-subtree-squash',
301
+ installDir: 'repos',
302
+ repositories: entries,
303
+ },
304
+ null,
305
+ 2,
306
+ )}\n`,
307
+ );
308
+ }
309
+
310
+ function commitManifestIfChanged() {
311
+ const status = run('git', ['status', '--porcelain', '--', manifestPath], {
312
+ timeout: 30000,
313
+ });
314
+ if (!status) {
315
+ return;
316
+ }
317
+ run('git', ['add', manifestPath], { timeout: 30000 });
318
+ commitInstallerChanges('Record agent reference repo manifest');
319
+ }
320
+
321
+ function main() {
322
+ if (!fs.existsSync(configPath)) {
323
+ fail('Missing .agents/agent-reference-repos.json');
324
+ return;
325
+ }
326
+
327
+ const config = readJson(configPath);
328
+ const enabled = config.defaultEnabled !== false && !skipRequested;
329
+
330
+ if (!enabled) {
331
+ log('setup skipped; set ULTRAMODERN_SKIP_AGENT_REPOS=0 to enable it again');
332
+ return;
333
+ }
334
+
335
+ if (!hasGit()) {
336
+ fail('git is required to install agent reference repositories');
337
+ return;
338
+ }
339
+ if (!hasGitSubtree()) {
340
+ fail('git subtree is required to install agent reference repositories');
341
+ return;
342
+ }
343
+ if (!ensureGitRepository()) {
344
+ return;
345
+ }
346
+
347
+ const entries = [];
348
+ for (const repo of config.repositories ?? []) {
349
+ const result = checkOnly ? assertSubtreePresent(repo) : addSubtree(repo);
350
+ if (result) {
351
+ entries.push(result);
352
+ }
353
+ }
354
+
355
+ if (!checkOnly) {
356
+ writeManifest(entries);
357
+ commitManifestIfChanged();
358
+ }
359
+ }
360
+
361
+ try {
362
+ main();
363
+ } catch (error) {
364
+ if (required || checkOnly) {
365
+ console.error(`[agent-reference-repos] ${error.message}`);
366
+ process.exitCode = 1;
367
+ } else {
368
+ warn(error.message);
369
+ }
370
+ }
@@ -0,0 +1,49 @@
1
+ import { useLocalizedLocation, useModernI18n } from '@modern-js/plugin-i18n/runtime';
2
+ import type { ReactNode } from 'react';
3
+ import { Header, StatusBadge } from './vertical-components';
4
+
5
+ interface ShellFrameProps {
6
+ children: ReactNode;
7
+ }
8
+
9
+ export default function ShellFrame({ children }: ShellFrameProps) {
10
+ const { i18nInstance, language } = useModernI18n();
11
+ const t = i18nInstance['t'].bind(i18nInstance);
12
+ const { alternates } = useLocalizedLocation();
13
+
14
+ return (
15
+ <main className="shell:min-h-screen shell:bg-um-canvas shell:px-4 shell:py-5 shell:text-um-foreground shell:sm:px-6 shell:lg:px-12">
16
+ <div className="shell:mx-auto shell:flex shell:min-h-20 shell:max-w-7xl shell:flex-col shell:items-start shell:gap-3 shell:bg-white/90 shell:px-4 shell:py-3 shell:shadow-xl shell:shadow-stone-900/10 shell:sm:px-6 shell:md:flex-row shell:md:flex-wrap shell:md:items-center shell:md:justify-between">
17
+ <Header />
18
+ <div className="shell:flex shell:min-w-0 shell:flex-wrap shell:items-center shell:gap-2 shell:md:ml-auto">
19
+ <label className="shell:sr-only" htmlFor="ultramodern-language">
20
+ {t('shell.language.switcher')}
21
+ </label>
22
+ <select
23
+ aria-label={t('shell.language.switcher')}
24
+ className="shell:h-10 shell:w-10 shell:cursor-pointer shell:appearance-none shell:border-0 shell:bg-transparent shell:p-0 shell:text-center shell:text-3xl shell:font-black shell:leading-none shell:text-stone-950 shell:shadow-none shell:[appearance:none] shell:[text-align-last:center] shell:focus-visible:rounded-md shell:focus-visible:outline-3 shell:focus-visible:outline-offset-2 shell:focus-visible:outline-emerald-700/40 shell:[&::-ms-expand]:hidden shell:[&::picker-icon]:hidden shell:[&_option]:text-xl"
25
+ id="ultramodern-language"
26
+ name="language"
27
+ onChange={event => {
28
+ const nextLanguage = event.currentTarget.value;
29
+ const targetHref = alternates[nextLanguage];
30
+ if (targetHref !== undefined) {
31
+ window.location.assign(targetHref);
32
+ }
33
+ }}
34
+ value={language}
35
+ >
36
+ <option aria-label={t('shell.language.en')} value="en">
37
+ 🇬🇧
38
+ </option>
39
+ <option aria-label={t('shell.language.cs')} value="cs">
40
+ 🇨🇿
41
+ </option>
42
+ </select>
43
+ <StatusBadge />
44
+ </div>
45
+ </div>
46
+ {children}
47
+ </main>
48
+ );
49
+ }