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

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/package.json CHANGED
@@ -21,7 +21,7 @@
21
21
  "engines": {
22
22
  "node": ">=20"
23
23
  },
24
- "version": "3.2.0-ultramodern.20",
24
+ "version": "3.2.0-ultramodern.21",
25
25
  "types": "./dist/types/index.d.ts",
26
26
  "main": "./dist/index.js",
27
27
  "bin": {
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "defaultEnabled": true,
4
+ "strategy": "git-subtree-squash",
4
5
  "installDir": "repos",
5
6
  "repositories": [
6
7
  {
@@ -3,4 +3,3 @@ dist/
3
3
  build/
4
4
  .modernjs/cache/
5
5
  .modernjs/agent-reference-repos-tmp/
6
- repos/
@@ -40,7 +40,7 @@ The installer copies only the allowlisted private skills from `.agents/skills-lo
40
40
 
41
41
  ## Agent Reference Repositories
42
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:
43
+ The workspace installs read-only source references under `repos/` by default during `pnpm install` using `git subtree add --squash`. These repositories are reference material for coding agents, not application source:
44
44
 
45
45
  - `repos/effect` from `Effect-TS/effect`.
46
46
  - `repos/ultramodern.js` from `BleedingDev/ultramodern.js`.
@@ -20,9 +20,9 @@ pnpm ultramodern:check
20
20
  ```
21
21
 
22
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`.
23
+ under `repos/` for Effect and UltraModern.js source lookup using squashed git
24
+ subtrees. Disable this setup with `ULTRAMODERN_SKIP_AGENT_REPOS=1 pnpm install`,
25
+ or rerun it explicitly with `pnpm agents:refs:install`.
26
26
 
27
27
  The topology and ownership metadata are generated under `topology/`. The
28
28
  workspace also ships `.github/workflows/ultramodern-workspace-gates.yml` and
@@ -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
  }
@@ -285,6 +285,10 @@ assert(
285
285
  agentReferenceRepos.defaultEnabled === true,
286
286
  'Agent reference repositories must be enabled by default',
287
287
  );
288
+ assert(
289
+ agentReferenceRepos.strategy === 'git-subtree-squash',
290
+ 'Agent reference repositories must use git subtree squash strategy',
291
+ );
288
292
  assert(
289
293
  agentReferenceRepos.repositories?.some(
290
294
  (repo) =>
@@ -309,6 +313,10 @@ assert(
309
313
  ),
310
314
  'Agent reference repository setup must expose an opt-out environment variable',
311
315
  );
316
+ assert(
317
+ readText('scripts/setup-agent-reference-repos.mjs').includes('git-subtree-dir'),
318
+ 'Agent reference repository setup must validate git subtree evidence',
319
+ );
312
320
  for (const skillName of baselineAgentSkills) {
313
321
  assert(
314
322
  skillsLock.baseline?.some((skill) => skill.name === skillName),