@bleedingdev/modern-js-create 3.2.0-ultramodern.20 → 3.2.0-ultramodern.22

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,44 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+
4
+ const root = process.cwd();
5
+ const defaultAppDirs = [
6
+ 'apps/remotes/remote-commerce',
7
+ 'apps/remotes/remote-identity',
8
+ 'apps/remotes/remote-design-system',
9
+ ];
10
+
11
+ const candidateDirs = process.argv.slice(2);
12
+ const appDirs = candidateDirs.length
13
+ ? candidateDirs
14
+ : fs.existsSync(path.join(root, 'module-federation.config.ts'))
15
+ ? ['.']
16
+ : defaultAppDirs;
17
+
18
+ for (const appDir of appDirs) {
19
+ const configPath = path.join(root, appDir, 'module-federation.config.ts');
20
+ if (!fs.existsSync(configPath)) {
21
+ throw new Error(
22
+ `Missing Module Federation config: ${path.relative(root, configPath)}`,
23
+ );
24
+ }
25
+
26
+ const config = fs.readFileSync(configPath, 'utf-8');
27
+ if (!config.includes('exposes:') || config.includes('dts: false')) {
28
+ continue;
29
+ }
30
+
31
+ const typesArchivePath = path.join(root, appDir, 'dist/@mf-types.zip');
32
+ if (!fs.existsSync(typesArchivePath)) {
33
+ throw new Error(
34
+ `Missing Module Federation DTS archive: ${path.relative(root, typesArchivePath)}`,
35
+ );
36
+ }
37
+
38
+ const stats = fs.statSync(typesArchivePath);
39
+ if (stats.size === 0) {
40
+ throw new Error(
41
+ `Empty Module Federation DTS archive: ${path.relative(root, typesArchivePath)}`,
42
+ );
43
+ }
44
+ }
@@ -8,7 +8,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
10
 
11
- const readJson = (filePath) => JSON.parse(fs.readFileSync(filePath, 'utf-8'));
11
+ const readJson = filePath => JSON.parse(fs.readFileSync(filePath, 'utf-8'));
12
12
 
13
13
  const run = (command, args, options = {}) =>
14
14
  execFileSync(command, args, {
@@ -28,6 +28,23 @@ const cloneSource = (source, targetDir) => {
28
28
  stdio: 'inherit',
29
29
  });
30
30
  }
31
+ if (source.commit) {
32
+ try {
33
+ run('git', ['checkout', source.commit], {
34
+ cwd: targetDir,
35
+ stdio: 'inherit',
36
+ });
37
+ } catch {
38
+ run('git', ['fetch', '--depth', '1', 'origin', source.commit], {
39
+ cwd: targetDir,
40
+ stdio: 'inherit',
41
+ });
42
+ run('git', ['checkout', source.commit], {
43
+ cwd: targetDir,
44
+ stdio: 'inherit',
45
+ });
46
+ }
47
+ }
31
48
  };
32
49
 
33
50
  const resolveSkillDir = (sourceRoot, skillName) => {
@@ -37,7 +54,9 @@ const resolveSkillDir = (sourceRoot, skillName) => {
37
54
  path.join(sourceRoot, 'skills', 'engineering', skillName),
38
55
  path.join(sourceRoot, 'skills', 'productivity', skillName),
39
56
  ];
40
- return candidates.find((candidate) => fs.existsSync(path.join(candidate, 'SKILL.md')));
57
+ return candidates.find(candidate =>
58
+ fs.existsSync(path.join(candidate, 'SKILL.md')),
59
+ );
41
60
  };
42
61
 
43
62
  if (!fs.existsSync(lockPath)) {
@@ -47,36 +66,77 @@ if (!fs.existsSync(lockPath)) {
47
66
 
48
67
  const lock = readJson(lockPath);
49
68
  const installDir = path.join(root, lock.installDir ?? '.agents/skills');
50
- const privateSources = (lock.sources ?? []).filter(
51
- (source) => source.install === 'clone-if-authorized',
69
+ const sources = lock.sources ?? [];
70
+ const requiredCloneSources = sources.filter(
71
+ source => source.install === 'clone',
72
+ );
73
+ const optionalCloneSources = sources.filter(
74
+ source => source.install === 'clone-if-authorized',
75
+ );
76
+ const requiredSkills = [
77
+ ...(lock.baseline ?? []),
78
+ ...requiredCloneSources.flatMap(source => source.baseline ?? []),
79
+ ].filter(
80
+ (skill, index, skills) =>
81
+ skills.findIndex(candidate => candidate.name === skill.name) === index,
52
82
  );
53
83
 
54
84
  if (checkOnly) {
55
- const missing = privateSources.flatMap((source) =>
85
+ const missingRequired = requiredSkills
86
+ .map(skill => skill.name)
87
+ .filter(
88
+ skillName => !fs.existsSync(path.join(installDir, skillName, 'SKILL.md')),
89
+ );
90
+ const missingOptional = optionalCloneSources.flatMap(source =>
56
91
  (source.baseline ?? [])
57
- .map((skill) => skill.name)
58
- .filter((skillName) => !fs.existsSync(path.join(installDir, skillName, 'SKILL.md'))),
92
+ .map(skill => skill.name)
93
+ .filter(
94
+ skillName =>
95
+ !fs.existsSync(path.join(installDir, skillName, 'SKILL.md')),
96
+ ),
59
97
  );
60
- if (missing.length > 0) {
98
+
99
+ if (missingRequired.length > 0) {
100
+ console.error(
101
+ `Required agent skills not installed: ${missingRequired.join(', ')}. Run pnpm skills:install.`,
102
+ );
103
+ process.exit(1);
104
+ }
105
+
106
+ if (missingOptional.length > 0) {
61
107
  console.warn(
62
- `Private skills not installed: ${missing.join(', ')}. Run pnpm skills:install if you have access.`,
108
+ `Private skills not installed: ${missingOptional.join(', ')}. Run pnpm skills:install if you have access.`,
63
109
  );
64
110
  } else {
65
- console.log('Agent skills are installed.');
111
+ console.log('Required and private agent skills are installed.');
112
+ process.exit(0);
66
113
  }
114
+ console.log('Required agent skills are installed.');
67
115
  process.exit(0);
68
116
  }
69
117
 
70
118
  fs.mkdirSync(installDir, { recursive: true });
71
119
 
72
- for (const source of privateSources) {
120
+ for (const source of [...requiredCloneSources, ...optionalCloneSources]) {
73
121
  const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ultramodern-skills-'));
74
122
  try {
75
- cloneSource(source, tempDir);
123
+ try {
124
+ cloneSource(source, tempDir);
125
+ } catch (error) {
126
+ if (source.install === 'clone-if-authorized') {
127
+ console.warn(
128
+ `Skipping ${source.repository}; current developer may not have access.`,
129
+ );
130
+ continue;
131
+ }
132
+ throw error;
133
+ }
76
134
  for (const skill of source.baseline ?? []) {
77
135
  const sourceSkillDir = resolveSkillDir(tempDir, skill.name);
78
136
  if (!sourceSkillDir) {
79
- throw new Error(`Skill ${skill.name} not found in ${source.repository}`);
137
+ throw new Error(
138
+ `Skill ${skill.name} not found in ${source.repository}`,
139
+ );
80
140
  }
81
141
  const targetSkillDir = path.join(installDir, skill.name);
82
142
  if (fs.existsSync(targetSkillDir)) {
@@ -7,7 +7,6 @@ const args = new Set(process.argv.slice(2));
7
7
  const checkOnly = args.has('--check');
8
8
  const configPath = path.join(root, '.agents', 'agent-reference-repos.json');
9
9
  const manifestPath = path.join(root, '.modernjs', 'agent-reference-repos.json');
10
- const tempRoot = path.join(root, '.modernjs', 'agent-reference-repos-tmp');
11
10
 
12
11
  const truthy = value => /^(1|true|yes|on)$/i.test(String(value ?? ''));
13
12
  const falsy = value => /^(0|false|no|off)$/i.test(String(value ?? ''));
@@ -18,6 +17,17 @@ const skipRequested =
18
17
  const required = truthy(process.env.ULTRAMODERN_AGENT_REPOS_REQUIRED);
19
18
  const refresh = truthy(process.env.ULTRAMODERN_AGENT_REPOS_REFRESH);
20
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
+
21
31
  const log = message => console.log(`[agent-reference-repos] ${message}`);
22
32
  const warn = message => console.warn(`[agent-reference-repos] ${message}`);
23
33
 
@@ -36,6 +46,11 @@ function run(command, commandArgs, options = {}) {
36
46
  const result = spawnSync(command, commandArgs, {
37
47
  cwd: options.cwd ?? root,
38
48
  encoding: 'utf-8',
49
+ env: {
50
+ ...process.env,
51
+ ...gitIdentityEnv,
52
+ ...(options.env ?? {}),
53
+ },
39
54
  stdio: options.stdio ?? ['ignore', 'pipe', 'pipe'],
40
55
  timeout: options.timeout ?? 120000,
41
56
  });
@@ -74,38 +89,160 @@ function hasGit() {
74
89
  return result.status === 0;
75
90
  }
76
91
 
77
- function existingReference(targetPath, repo) {
78
- const markerPath = path.join(targetPath, '.ultramodern-reference-repo.json');
79
- if (!fs.existsSync(markerPath)) {
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 ensureGitRepository() {
126
+ if (!isGitWorkTree()) {
127
+ if (checkOnly) {
128
+ fail('workspace is not a git repository');
129
+ return false;
130
+ }
131
+ log('initializing git repository for agent reference subtrees');
132
+ run('git', ['init'], { timeout: 30000 });
133
+ }
134
+
135
+ if (!hasCommits()) {
136
+ if (checkOnly) {
137
+ fail('workspace has no initial git commit');
138
+ return false;
139
+ }
140
+ log('creating initial workspace commit before adding reference subtrees');
141
+ run('git', ['add', '-A'], { timeout: 30000 });
142
+ run('git', ['commit', '-m', 'Initialize UltraModern workspace'], {
143
+ timeout: 120000,
144
+ });
145
+ return true;
146
+ }
147
+
148
+ const status = porcelainStatus();
149
+ if (status) {
150
+ fail(
151
+ 'workspace has uncommitted changes; commit or stash them before installing reference subtrees',
152
+ );
153
+ return false;
154
+ }
155
+
156
+ return true;
157
+ }
158
+
159
+ function remoteCommit(repo) {
160
+ let output = run('git', ['ls-remote', repo.url, `refs/heads/${repo.ref}`], {
161
+ timeout: 120000,
162
+ });
163
+ if (!output) {
164
+ output = run('git', ['ls-remote', repo.url, repo.ref], {
165
+ timeout: 120000,
166
+ });
167
+ }
168
+ const [commit] = output.split(/\s+/);
169
+ if (!/^[a-f0-9]{40}$/i.test(commit ?? '')) {
170
+ throw new Error(`Could not resolve ${repo.url}#${repo.ref}`);
171
+ }
172
+ return commit;
173
+ }
174
+
175
+ function subtreeCommitExists(repo) {
176
+ const result = spawnSync(
177
+ 'git',
178
+ [
179
+ 'log',
180
+ '--grep',
181
+ `git-subtree-dir: ${repo.path}`,
182
+ '--format=%H',
183
+ '-n',
184
+ '1',
185
+ ],
186
+ {
187
+ cwd: root,
188
+ encoding: 'utf-8',
189
+ stdio: ['ignore', 'pipe', 'pipe'],
190
+ },
191
+ );
192
+ return result.status === 0 && result.stdout.trim().length > 0;
193
+ }
194
+
195
+ function installedManifestEntry(repo) {
196
+ if (!fs.existsSync(manifestPath)) {
80
197
  return undefined;
81
198
  }
82
199
  try {
83
- const marker = readJson(markerPath);
84
- if (marker.url === repo.url && marker.ref === repo.ref) {
85
- return marker;
86
- }
200
+ const manifest = readJson(manifestPath);
201
+ return manifest.repositories?.find(entry => entry.id === repo.id);
87
202
  } catch {
88
203
  return undefined;
89
204
  }
90
- return undefined;
91
205
  }
92
206
 
93
- function materializeRepository(repo) {
207
+ function assertSubtreePresent(repo) {
94
208
  assertSafeRepoPath(repo.path);
95
209
  const targetPath = path.join(root, repo.path);
96
- const existing = existingReference(targetPath, repo);
210
+ if (!fs.existsSync(targetPath)) {
211
+ fail(`${repo.path} is missing`);
212
+ return undefined;
213
+ }
214
+ if (!subtreeCommitExists(repo)) {
215
+ fail(`${repo.path} is present but has no git-subtree commit evidence`);
216
+ return undefined;
217
+ }
218
+ return (
219
+ installedManifestEntry(repo) ?? {
220
+ id: repo.id,
221
+ name: repo.name,
222
+ url: repo.url,
223
+ ref: repo.ref,
224
+ path: repo.path,
225
+ readOnly: repo.readOnly !== false,
226
+ status: 'present',
227
+ strategy: 'git-subtree-squash',
228
+ }
229
+ );
230
+ }
231
+
232
+ function addSubtree(repo) {
233
+ assertSafeRepoPath(repo.path);
234
+ const targetPath = path.join(root, repo.path);
235
+ const existing = fs.existsSync(targetPath);
97
236
 
98
237
  if (existing && !refresh) {
99
- log(`${repo.id} already present at ${repo.path} (${existing.commit})`);
100
- return { ...existing, status: 'present' };
238
+ return assertSubtreePresent(repo);
101
239
  }
102
240
 
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 });
241
+ if (existing && refresh) {
242
+ fail(
243
+ `${repo.path} already exists; refresh for subtree references is intentionally manual`,
244
+ );
245
+ return undefined;
109
246
  }
110
247
 
111
248
  if (checkOnly) {
@@ -113,53 +250,70 @@ function materializeRepository(repo) {
113
250
  return undefined;
114
251
  }
115
252
 
116
- fs.mkdirSync(tempRoot, { recursive: true });
117
- const tempPath = fs.mkdtempSync(path.join(tempRoot, `${repo.id}-`));
253
+ const commit = remoteCommit(repo);
254
+ log(`adding ${repo.name} as git subtree at ${repo.path} (${commit})`);
255
+ run('git', ['fetch', '--depth', '1', repo.url, repo.ref], {
256
+ timeout: 300000,
257
+ });
258
+ run(
259
+ 'git',
260
+ [
261
+ 'subtree',
262
+ 'add',
263
+ '--prefix',
264
+ repo.path,
265
+ 'FETCH_HEAD',
266
+ '--squash',
267
+ '-m',
268
+ `Add ${repo.name} agent reference repo`,
269
+ ],
270
+ { timeout: 600000 },
271
+ );
118
272
 
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);
273
+ return {
274
+ schemaVersion: 1,
275
+ id: repo.id,
276
+ name: repo.name,
277
+ url: repo.url,
278
+ ref: repo.ref,
279
+ commit,
280
+ path: repo.path,
281
+ readOnly: repo.readOnly !== false,
282
+ strategy: 'git-subtree-squash',
283
+ status: 'installed',
284
+ installedAt: new Date().toISOString(),
285
+ };
286
+ }
140
287
 
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;
288
+ function writeManifest(entries) {
289
+ fs.mkdirSync(path.dirname(manifestPath), { recursive: true });
290
+ fs.writeFileSync(
291
+ manifestPath,
292
+ `${JSON.stringify(
293
+ {
294
+ schemaVersion: 1,
295
+ generatedAt: new Date().toISOString(),
296
+ strategy: 'git-subtree-squash',
297
+ installDir: 'repos',
298
+ repositories: entries,
299
+ },
300
+ null,
301
+ 2,
302
+ )}\n`,
303
+ );
304
+ }
305
+
306
+ function commitManifestIfChanged() {
307
+ const status = run('git', ['status', '--porcelain', '--', manifestPath], {
308
+ timeout: 30000,
309
+ });
310
+ if (!status) {
311
+ return;
162
312
  }
313
+ run('git', ['add', manifestPath], { timeout: 30000 });
314
+ run('git', ['commit', '-m', 'Record agent reference repo manifest'], {
315
+ timeout: 120000,
316
+ });
163
317
  }
164
318
 
165
319
  function main() {
@@ -180,30 +334,25 @@ function main() {
180
334
  fail('git is required to install agent reference repositories');
181
335
  return;
182
336
  }
337
+ if (!hasGitSubtree()) {
338
+ fail('git subtree is required to install agent reference repositories');
339
+ return;
340
+ }
341
+ if (!ensureGitRepository()) {
342
+ return;
343
+ }
183
344
 
184
- const installed = [];
345
+ const entries = [];
185
346
  for (const repo of config.repositories ?? []) {
186
- const result = materializeRepository(repo);
347
+ const result = checkOnly ? assertSubtreePresent(repo) : addSubtree(repo);
187
348
  if (result) {
188
- installed.push(result);
349
+ entries.push(result);
189
350
  }
190
351
  }
191
352
 
192
353
  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
- );
354
+ writeManifest(entries);
355
+ commitManifestIfChanged();
207
356
  }
208
357
  }
209
358
 
@@ -212,6 +361,4 @@ try {
212
361
  } catch (error) {
213
362
  console.error(`[agent-reference-repos] ${error.message}`);
214
363
  process.exitCode = 1;
215
- } finally {
216
- fs.rmSync(tempRoot, { recursive: true, force: true });
217
364
  }