@lenne.tech/cli 1.10.0 → 1.11.0

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.
@@ -1,250 +0,0 @@
1
- /**
2
- * Diff-generator for the `lt-dev:nest-server-core-updater` agent.
3
- *
4
- * Given a target upstream version, this script:
5
- * 1. Reads VENDOR.md to find the current baseline version and commit
6
- * 2. Clones the upstream nest-server repo into /tmp at both the baseline
7
- * and the target commit
8
- * 3. Produces three diffs:
9
- * - upstream-delta.patch: what changed upstream between baseline and target
10
- * - local-changes.patch: what we changed locally vs the baseline
11
- * - conflicts.json: structured file-level intersection of both diffs
12
- * 4. Writes all output to scripts/vendor/sync-results/<timestamp>/
13
- *
14
- * Usage:
15
- * pnpm run vendor:sync -- --target 11.25.0
16
- * (or direct: ts-node scripts/vendor/sync-from-upstream.ts --target 11.25.0)
17
- *
18
- * The script does NOT modify source files. It only produces the diffs and
19
- * a report for the updater-agent to act on.
20
- */
21
-
22
- import { execSync } from 'node:child_process';
23
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
24
- import { join } from 'node:path';
25
-
26
- const PROJECT_ROOT = join(__dirname, '..', '..');
27
- const VENDOR_DIR = join(PROJECT_ROOT, 'src', 'core');
28
- const VENDOR_MD = join(VENDOR_DIR, 'VENDOR.md');
29
- const OUTPUT_BASE = join(PROJECT_ROOT, 'scripts', 'vendor', 'sync-results');
30
-
31
- const UPSTREAM_REPO = 'https://github.com/lenneTech/nest-server';
32
- const TMP_BASELINE = '/tmp/nest-server-sync-baseline';
33
- const TMP_TARGET = '/tmp/nest-server-sync-target';
34
-
35
- function die(msg: string): never {
36
- process.stderr.write(`ERROR: ${msg}\n`);
37
- process.exit(1);
38
- }
39
-
40
- function sh(cmd: string, opts: { cwd?: string; allowFailure?: boolean } = {}): string {
41
- try {
42
- return execSync(cmd, {
43
- cwd: opts.cwd ?? PROJECT_ROOT,
44
- encoding: 'utf-8',
45
- stdio: ['ignore', 'pipe', 'pipe'],
46
- });
47
- } catch (err: unknown) {
48
- if (opts.allowFailure) {
49
- const e = err as { stdout?: string };
50
- return e.stdout ?? '';
51
- }
52
- throw err;
53
- }
54
- }
55
-
56
- // 1. Parse arguments
57
- const args = process.argv.slice(2);
58
- let targetVersion: string | null = null;
59
- let targetRef: string | null = null;
60
-
61
- for (let i = 0; i < args.length; i++) {
62
- if (args[i] === '--target' && i + 1 < args.length) {
63
- targetVersion = args[++i];
64
- } else if (args[i] === '--ref' && i + 1 < args.length) {
65
- targetRef = args[++i];
66
- }
67
- }
68
-
69
- // 2. Verify vendored state
70
- if (!existsSync(VENDOR_MD)) {
71
- die(`VENDOR.md not found at ${VENDOR_MD}. Not a vendored project.`);
72
- }
73
-
74
- const vendorContent = readFileSync(VENDOR_MD, 'utf-8');
75
- const baselineVersionMatch = vendorContent.match(/Baseline-Version[:*\s]+([\d.]+[\w.-]*)/);
76
- const baselineCommitMatch = vendorContent.match(/Baseline-Commit[:*\s`]+([a-f0-9]{40})/);
77
-
78
- if (!baselineVersionMatch || !baselineCommitMatch) {
79
- die(
80
- `Could not parse Baseline-Version and Baseline-Commit from VENDOR.md. ` +
81
- `Expected "Baseline-Version: X.Y.Z" and "Baseline-Commit: <sha>".`,
82
- );
83
- }
84
-
85
- const baselineVersion = baselineVersionMatch[1];
86
- const baselineCommit = baselineCommitMatch[1];
87
-
88
- // Determine target
89
- if (!targetVersion && !targetRef) {
90
- // Find latest upstream tag
91
- const output = sh(
92
- `git ls-remote --tags ${UPSTREAM_REPO} | awk -F'refs/tags/' '/refs\\/tags\\//{print $2}' | grep -vE '\\^{}$|beta|alpha|rc' | sort -V | tail -1`,
93
- { allowFailure: false },
94
- ).trim();
95
- if (!output) die('Could not determine latest upstream tag.');
96
- targetVersion = output;
97
- }
98
-
99
- const targetIdent = targetRef ?? targetVersion!;
100
-
101
- // 3. Prepare output directory
102
- const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
103
- const outputDir = join(OUTPUT_BASE, timestamp);
104
- mkdirSync(outputDir, { recursive: true });
105
-
106
- process.stdout.write(`Vendor sync analysis\n`);
107
- process.stdout.write(` Baseline: ${baselineVersion} @ ${baselineCommit}\n`);
108
- process.stdout.write(` Target: ${targetIdent}\n`);
109
- process.stdout.write(` Output: ${outputDir}\n\n`);
110
-
111
- // 4. Clone upstream baseline
112
- process.stdout.write(`Cloning upstream baseline...\n`);
113
- sh(`rm -rf ${TMP_BASELINE}`);
114
- sh(`git clone --quiet ${UPSTREAM_REPO} ${TMP_BASELINE}`);
115
- sh(`git checkout --quiet ${baselineCommit}`, { cwd: TMP_BASELINE });
116
-
117
- // 5. Clone upstream target
118
- process.stdout.write(`Cloning upstream target...\n`);
119
- sh(`rm -rf ${TMP_TARGET}`);
120
- sh(`git clone --quiet ${UPSTREAM_REPO} ${TMP_TARGET}`);
121
- sh(`git checkout --quiet ${targetIdent}`, { cwd: TMP_TARGET });
122
- const targetCommit = sh(`git rev-parse HEAD`, { cwd: TMP_TARGET }).trim();
123
-
124
- // 6. Generate diffs
125
- process.stdout.write(`Computing upstream delta...\n`);
126
- const upstreamDelta = sh(
127
- `diff -urN ${TMP_BASELINE}/src ${TMP_TARGET}/src || true`,
128
- { allowFailure: true },
129
- );
130
- writeFileSync(join(outputDir, 'upstream-delta.patch'), upstreamDelta);
131
-
132
- process.stdout.write(`Computing local changes...\n`);
133
- // Compare our flat vendor tree against upstream's src/core subtree for the bulk
134
- // of the framework, plus the top-level files that were flattened.
135
- const localChangesCore = sh(
136
- `diff -urN ${TMP_BASELINE}/src/core ${VENDOR_DIR} --exclude=VENDOR.md --exclude=LICENSE --exclude=test --exclude=templates --exclude=types --exclude=index.ts --exclude=core.module.ts || true`,
137
- { allowFailure: true },
138
- );
139
- const localChangesIndex = sh(
140
- `diff -uN ${TMP_BASELINE}/src/index.ts ${VENDOR_DIR}/index.ts || true`,
141
- { allowFailure: true },
142
- );
143
- const localChangesCoreModule = sh(
144
- `diff -uN ${TMP_BASELINE}/src/core.module.ts ${VENDOR_DIR}/core.module.ts || true`,
145
- { allowFailure: true },
146
- );
147
- const localChangesTest = sh(
148
- `diff -urN ${TMP_BASELINE}/src/test ${VENDOR_DIR}/test || true`,
149
- { allowFailure: true },
150
- );
151
-
152
- writeFileSync(
153
- join(outputDir, 'local-changes.patch'),
154
- [
155
- '### local-changes: src/core (non-flattened files)',
156
- localChangesCore,
157
- '',
158
- '### local-changes: src/index.ts (flattened)',
159
- localChangesIndex,
160
- '',
161
- '### local-changes: src/core.module.ts (flattened)',
162
- localChangesCoreModule,
163
- '',
164
- '### local-changes: src/test (flattened)',
165
- localChangesTest,
166
- ].join('\n'),
167
- );
168
-
169
- // 7. Extract file lists from both diffs to compute conflicts
170
- function extractChangedFiles(diff: string): Set<string> {
171
- const files = new Set<string>();
172
- for (const line of diff.split('\n')) {
173
- // diff -u format: lines like "diff -u file1 file2" or "+++ path/to/file"
174
- const m = line.match(/^(?:diff -[uN]r?N?\s|\+\+\+\s)(.+)$/);
175
- if (m) {
176
- const path = m[1].replace(/^\S+\s+/, '').split('\t')[0].trim();
177
- if (path && path !== '/dev/null') {
178
- // Normalize to upstream-style src/core/... path
179
- const normalized = path
180
- .replace(TMP_BASELINE + '/', '')
181
- .replace(TMP_TARGET + '/', '')
182
- .replace(VENDOR_DIR + '/', 'src/core/');
183
- files.add(normalized);
184
- }
185
- }
186
- }
187
- return files;
188
- }
189
-
190
- const upstreamFiles = extractChangedFiles(upstreamDelta);
191
- const localFiles = extractChangedFiles(
192
- [localChangesCore, localChangesIndex, localChangesCoreModule, localChangesTest].join('\n'),
193
- );
194
- const conflicts = [...upstreamFiles].filter((f) => localFiles.has(f));
195
-
196
- writeFileSync(
197
- join(outputDir, 'conflicts.json'),
198
- JSON.stringify(
199
- {
200
- baselineVersion,
201
- baselineCommit,
202
- targetVersion: targetIdent,
203
- targetCommit,
204
- upstreamChangedFiles: [...upstreamFiles].sort(),
205
- localChangedFiles: [...localFiles].sort(),
206
- conflictingFiles: conflicts.sort(),
207
- },
208
- null,
209
- 2,
210
- ),
211
- );
212
-
213
- // 8. Write human-readable summary
214
- const summary = `# Upstream Sync Analysis
215
-
216
- **Baseline:** ${baselineVersion} (${baselineCommit})
217
- **Target:** ${targetIdent} (${targetCommit})
218
- **Generated:** ${new Date().toISOString()}
219
-
220
- ## Changed Files
221
-
222
- - Upstream delta: ${upstreamFiles.size} files
223
- - Local changes: ${localFiles.size} files
224
- - **Conflicts: ${conflicts.length} files**
225
-
226
- ## Conflicts (need human decision)
227
- ${conflicts.length === 0 ? '_(none)_' : conflicts.map((f) => `- ${f}`).join('\n')}
228
-
229
- ## Next Steps
230
-
231
- The \`lt-dev:nest-server-core-updater\` agent will pick up this directory and:
232
- 1. Parse upstream-delta.patch
233
- 2. Categorize each hunk as clean-pick / conflict / not-applicable
234
- 3. Apply approved changes with flatten-fix reapplication
235
- 4. Run validation loop (tsc / lint / tests)
236
- 5. Update VENDOR.md
237
-
238
- ## Files Generated
239
-
240
- - \`upstream-delta.patch\` — raw diff baseline → target
241
- - \`local-changes.patch\` — raw diff baseline → our vendor
242
- - \`conflicts.json\` — structured conflict list
243
- - \`summary.md\` — this file
244
- `;
245
-
246
- writeFileSync(join(outputDir, 'summary.md'), summary);
247
-
248
- process.stdout.write(`\nDone. Review the summary and run the updater agent:\n`);
249
- process.stdout.write(` cat ${outputDir}/summary.md\n`);
250
- process.stdout.write(` /lt-dev:backend:update-nest-server-core --target ${targetIdent}\n`);