Repository navigation
Expand file tree
/
Copy pathgenerate_patch.js
More file actions
644 lines (572 loc) · 27.9 KB
/
Copy pathgenerate_patch.js
File metadata and controls
644 lines (572 loc) · 27.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
#!/usr/bin/env node
// Generate the new patch for modYarn by modifying node_modules/yarn/lib/cli.js
// and producing a unified diff against cli.js.orig
const { execSync } = require('child_process');
const fs = require('fs');
const path = require('path');
const CLI = path.join(__dirname, 'node_modules', 'yarn', 'lib', 'cli.js');
const ORIG = path.join(__dirname, 'cli.js.orig');
const PATCH = path.join(__dirname, 'patches', 'yarn+1.22.22.patch');
// Read current cli.js (already patched)
let cli = fs.readFileSync(CLI, 'utf8');
// --------------------------------------------------------------- helpers
function replaceAll(str, from, to) {
return str.split(from).join(to);
}
// --------------------------------------------------------------- 1. Add loader blocks for 1045-1047
const oldLoaders = `var _cup;
function _load_cup() {
return _cup = _interopRequireWildcard(__webpack_require__(1044));
}
var _useless;`;
const newLoaders = `var _cup;
function _load_cup() {
return _cup = _interopRequireWildcard(__webpack_require__(1044));
}
var _lockcheck;
function _load_lockcheck() {
return _lockcheck = _interopRequireWildcard(__webpack_require__(1045));
}
var _purge;
function _load_purge() {
return _purge = _interopRequireWildcard(__webpack_require__(1046));
}
var _envdump;
function _load_envdump() {
return _envdump = _interopRequireWildcard(__webpack_require__(1047));
}
var _useless;`;
if (!cli.includes(newLoaders)) {
cli = cli.replace(oldLoaders, newLoaders);
console.log('Injected loader blocks 1045/1046/1047');
}
// --------------------------------------------------------------- 2. Add commands map entries
const oldCmdsMap = ' cup: _cup || _load_cup()\n};';
const newCmdsMap = ' cup: _cup || _load_cup(),\n lockcheck: _lockcheck || _load_lockcheck(),\n purge: _purge || _load_purge(),\n envdump: _envdump || _load_envdump()\n};';
if (cli.includes(oldCmdsMap) && !cli.includes(newCmdsMap)) {
cli = cli.replace(oldCmdsMap, newCmdsMap);
console.log('Injected commands map entries');
}
// --------------------------------------------------------------- 3. Add PROXY_COMMANDS entry for new commands
const oldProxy = ' , cup: 0 // MODYARN: yarn cup — every <params>/<command> pair after `cup` is passed through verbatim\n , CustomParams: 0 // MODYARN: alias for cup; same verbatim passthrough protection\n };';
const newProxy = ' , cup: 0 // MODYARN: yarn cup — every <params>/<command> pair after `cup` is passed through verbatim\n , CustomParams: 0 // MODYARN: alias for cup; same verbatim passthrough protection\n , lockcheck: 0 // MODYARN: yarn lockcheck — no special arg handling needed (pure local check)\n , purge: 0 // MODYARN: yarn purge — no special arg handling needed (runs its own install)\n , envdump: 0 // MODYARN: yarn envdump — pure reporting command\n };';
if (cli.includes(oldProxy) && !cli.includes(newProxy)) {
cli = cli.replace(oldProxy, newProxy);
console.log('Injected PROXY_COMMANDS entries');
}
// --------------------------------------------------------------- 4. Add aliases
const oldAliases = " 'CustomParams': 'cup' // MODYARN: alias for cup (case-insensitive via top-level dispatch)";
const newAliases = " 'CustomParams': 'cup', // MODYARN: alias for cup (case-insensitive via top-level dispatch)\n 'lc': 'lockcheck', // MODYARN: short alias\n 'pg': 'purge', // MODYARN: short alias\n 'ed': 'envdump' // MODYARN: short alias";
if (cli.includes(oldAliases) && !cli.includes(newAliases)) {
cli = cli.replace(oldAliases, newAliases);
console.log('Injected aliases');
}
// --------------------------------------------------------------- 5. Insert module bodies (1045, 1046, 1047) AFTER module 1044
// Find the closing of module 1044
const after1044Marker = '/\* 1044 \*/\n/***/ (function(module, exports, __webpack_require__) {\n';
const endOf1044 = cli.lastIndexOf('exports.hasWrapper = hasWrapper;\n\n/***/ }),\n\n/\\*\\*\\* \\]\\]');
// Simpler: find the line with "/******/ ]);" which closes the modules array
const modulesArrayClose = cli.indexOf('/******] ];');
const afterModulesArrayClose = cli.indexOf('\n', modulesArrayClose) + 1;
// Actually let's find the exact insertion point by looking for the modules array closing
// Pattern: ends with "/******/ ]);" at the very end of file
const tailMatch = cli.match(/\/\*\*\*\/ \]\];\s*$/);
if (!tailMatch) {
console.error('ERROR: Could not find modules array closing');
process.exit(1);
}
const tailIdx = cli.lastIndexOf(tailMatch[0]);
console.log('Modules array closes at byte', tailIdx);
// Module bodies go BEFORE the closing ];
const module1045 = String.raw`
/* 1045 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
// MODYARN extension: `yarn lockcheck` / `yarn lc`
// Quickly check whether yarn.lock is in sync with package.json (dry check).
// -v / --verbose prints a summary of missing/extra entries.
Object.defineProperty(exports, "__esModule", {
value: true
});
var path = __webpack_require__(1);
var fs = __webpack_require__(12);
function run(config, reporter, flags, args) {
var _run = (function() {
var gen = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, args) {
var cwd = config.cwd;
var manifest = yield config.maybeReadManifest(cwd);
if (!manifest) {
reporter.warn('No package.json found in ' + cwd + '; nothing to check.');
return 0;
}
var lockFile = path.join(cwd, 'yarn.lock');
var lockExists = fs.existsSync(lockFile);
if (!lockExists) {
reporter.info('No yarn.lock found. Run "yarn install" first to create one.');
return 0;
}
// Build the set of declared dependency names.
var pkgDeps = {};
['dependencies', 'devDependencies', 'optionalDependencies', 'peerDependencies'].forEach(function(k) {
Object.keys((manifest[k] || {})).forEach(function(n) { pkgDeps[n] = true; });
});
// Parse top-level keys from yarn.lock.
var lockText = fs.readFileSync(lockFile, 'utf8');
var topEntries = lockText.split('\n').filter(function(l) {
return /^[^ \t#].*@(?:.*:|$)/.test(l) && !/^\s/.test(l);
});
var lockNames = {};
topEntries.forEach(function(line) {
var m = line.match(/^([^\s@'"]+?)(?:@\S*)?/);
if (m) lockNames[m[1]] = true;
});
var missing = Object.keys(pkgDeps).filter(function(n) { return !lockNames[n]; });
var extra = Object.keys(lockNames).filter(function(n) { return !pkgDeps[n]; });
if (missing.length === 0 && extra.length === 0) {
reporter.success('lockcheck: yarn.lock is in sync with package.json (' + topEntries.length + ' entries).');
return 0;
}
if (missing.length) {
reporter.warn('lockcheck: ' + missing.length + ' package(s) in package.json are not in yarn.lock:');
missing.slice(0, 20).forEach(function(n) { reporter.log(' +' + n); });
if (missing.length > 20) reporter.log(' ... and ' + (missing.length - 20) + ' more');
}
if (extra.length) {
reporter.log('lockcheck: ' + extra.length + ' package(s) in yarn.lock are not in package.json:');
extra.slice(0, 20).forEach(function(n) { reporter.log(' -' + n); });
if (extra.length > 20) reporter.log(' ... and ' + (extra.length - 20) + ' more');
}
if (flags.verbose || flags.V) {
reporter.info('Run "yarn install" to re-sync the lockfile.');
}
process.exitCode = 1;
return 1;
});
return function run(_x, _x2, _x3, _x4) {
return gen.apply(this, arguments);
};
})();
return _run(config, reporter, flags, args);
}
function setFlags(commander) {
commander.description('Check whether yarn.lock is in sync with package.json. (modyarn extension)');
commander.usage('lockcheck [flags]');
commander.option('-v, --verbose', 'suggest next steps when out of sync');
commander.option('-V', 'alias for -v');
}
function hasWrapper(commander, args) {
return true;
}
var _asyncToGenerator2;
function _load_asyncToGenerator() {
return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2));
}
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
exports.run = run;
exports.setFlags = setFlags;
exports.hasWrapper = hasWrapper;
/***/ }),
/* 1046 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
// MODYARN extension: `yarn purge` / `yarn pg`
// Remove packages from node_modules that are NOT listed in package.json.
// After removal, runs `yarn install` to reconcile. Useful after autoupdate
// leaves redundant version directories behind.
Object.defineProperty(exports, "__esModule", {
value: true
});
var path = __webpack_require__(1);
var fs = __webpack_require__(12);
function run(config, reporter, flags, args) {
var _run = (function() {
var gen = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, args) {
var cwd = config.cwd;
var manifest = yield config.maybeReadManifest(cwd);
if (!manifest) {
reporter.warn('No package.json found; nothing to purge.');
return 0;
}
var nmDir = path.join(cwd, 'node_modules');
if (!fs.existsSync(nmDir)) {
reporter.info('No node_modules directory; nothing to purge.');
return 0;
}
// Build the set of allowed package names.
var allowed = {};
['dependencies', 'devDependencies', 'optionalDependencies'].forEach(function(k) {
Object.keys((manifest[k] || {})).forEach(function(n) { allowed[n] = true; });
});
var entries = fs.readdirSync(nmDir);
var orphaned = [];
entries.forEach(function(name) {
// skip internal dirs
if (name === '.bin' || name === '.cache' || name === '.yarn-integrity' ||
name === '.package-lock.json' || name === '.yarn-lock.json' || name.charAt(0) === '.') return;
if (allowed[name]) return;
// scoped packages live in node_modules/@scope/name
if (name.charAt(0) === '@') {
var scopedDir = path.join(nmDir, name);
if (!fs.statSync(scopedDir).isDirectory()) return;
fs.readdirSync(scopedDir).forEach(function(inner) {
if (allowed[name + '/' + inner]) return;
orphaned.push(name + '/' + inner);
});
} else {
orphaned.push(name);
}
});
if (orphaned.length === 0) {
reporter.success('purge: no orphaned packages found. node_modules is clean.');
return 0;
}
reporter.warn('purge: found ' + orphaned.length + ' orphaned package(s):');
orphaned.slice(0, 25).forEach(function(n) { reporter.log(' ' + n); });
if (orphaned.length > 25) reporter.log(' ... and ' + (orphaned.length - 25) + ' more');
if (flags.dry) {
reporter.info('purge(-dry): not removing anything. Pass without -dry to delete.');
return 0;
}
orphaned.forEach(function(n) {
var p = path.join(nmDir, n);
try {
fs.rmSync(p, { recursive: true, force: true });
reporter.log(' removed ' + n);
} catch (e) {
reporter.warn(' failed to remove ' + n + ': ' + e.message);
}
});
// Re-run install to fix any broken links / bin symlinks.
var install = __webpack_require__(41);
reporter.info('purge: running "yarn install" to reconcile...');
yield install.run(config, reporter, {}, []);
reporter.success('purge: done. Removed ' + orphaned.length + ' orphaned package(s).');
return 0;
});
return function run(_x, _x2, _x3, _x4) {
return gen.apply(this, arguments);
};
})();
return _run(config, reporter, flags, args);
}
function setFlags(commander) {
commander.description('Remove orphaned packages from node_modules. (modyarn extension)');
commander.usage('purge [flags]');
commander.option('-dry, --dry-run', 'list orphaned packages without removing');
}
function hasWrapper(commander, args) {
return true;
}
var _asyncToGenerator2;
function _load_asyncToGenerator() {
return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2));
}
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
exports.run = run;
exports.setFlags = setFlags;
exports.hasWrapper = hasWrapper;
/***/ }),
/* 1047 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
// MODYARN extension: `yarn envdump` / `yarn ed`
// Print all YARN_* environment variables plus key built-in paths and modyarn
// state files, useful when debugging modyarn patches or custom scripts.
Object.defineProperty(exports, "__esModule", {
value: true
});
var os = __webpack_require__(66);
var path = __webpack_require__(1);
var fs = __webpack_require__(12);
function run(config, reporter, flags, args) {
var _run = (function() {
var gen = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, args) {
var lines = [];
// 1) YARN_* env vars + well-known env vars relevant to yarn
var relevant = Object.keys(process.env).filter(function(k) {
return /^YARN_/i.test(k) || /^(COREPACK|SKIP_YARN|CI|NODE_ENV|PATH|HOME|USERPROFILE|APPDATA|TEMP|TMP)$/.test(k);
}).sort();
lines.push('[env vars]');
if (relevant.length === 0) {
lines.push(' (none matching YARN_*/well-known vars)');
}
relevant.forEach(function(k) {
var v = String(process.env[k]);
if (v.length > 120) v = v.slice(0, 117) + '...';
lines.push(' ' + k + '=' + v);
});
// 2) paths
lines.push('[paths]');
lines.push(' cwd = ' + config.cwd);
lines.push(' platform = ' + process.platform + ' (' + os.platform() + ')');
lines.push(' arch = ' + process.arch);
lines.push(' node = ' + process.version);
var home = os.homedir();
lines.push(' home = ' + home);
var globalFolder = process.env.YARN_GLOBAL_FOLDER || path.join(home, '.yarn');
var cacheFolder = process.env.YARN_CACHE_FOLDER || path.join(home, '.yarn', 'cache');
lines.push(' globalFolder = ' + globalFolder);
lines.push(' cacheFolder = ' + cacheFolder);
// 3) modyarn state files
lines.push('[modyarn state]');
var globalScripts = path.join(home, 'yarn-scripts.json');
var globalTmp = path.join(home, 'yarn-scripts-tmp.json');
var projScripts = path.join(config.cwd, '.yarn-scripts.json');
var projTmp = path.join(config.cwd, '.yarn-scripts-tmp.json');
[[globalScripts, 'global longterm'], [globalTmp, 'global tmp'],
[projScripts, 'project longterm'], [projTmp, 'project tmp']].forEach(function(f) {
var exists = fs.existsSync(f[0]);
var count = 0;
if (exists) {
try { count = Object.keys(JSON.parse(fs.readFileSync(f[0], 'utf8'))).length; } catch (e) {}
}
lines.push(' ' + f[1].padEnd(16) + ' : ' + f[0] + ' (' + (exists ? count + ' script(s)' : 'missing') + ')');
});
reporter.log(lines.join('\n'), { force: true });
return 0;
});
return function run(_x, _x2, _x3, _x4) {
return gen.apply(this, arguments);
};
})();
return _run(config, reporter, flags, args);
}
function setFlags(commander) {
commander.description('Dump the effective yarn environment (vars + paths + modyarn state). (modyarn extension)');
commander.usage('envdump [flags]');
}
function hasWrapper(commander, args) {
return true;
}
var _asyncToGenerator2;
function _load_asyncToGenerator() {
return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2));
}
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
exports.run = run;
exports.setFlags = setFlags;
exports.hasWrapper = hasWrapper;
/***/ }),
`;
// Insert before the modules array closing
if (!cli.includes('/* 1045 */')) {
cli = cli.slice(0, tailIdx) + module1045 + cli.slice(tailIdx);
console.log('Injected module bodies 1045/1046/1047');
}
// --------------------------------------------------------------- 6. Update watch module (1041) - add new flags
// Find the watch module and add flags to setFlags
const oldWatchSetFlags = `function setFlags(commander) {
commander.description('Run a script and watch the project, restarting it on file changes. (modyarn extension)');
commander.usage('watch <script> [flags]');
}`;
const newWatchSetFlags = `function setFlags(commander) {
commander.description('Run a script and watch the project, restarting it on file changes. (modyarn extension)');
commander.usage('watch <script> [flags]');
commander.option('-glob <pattern>', 'only restart when filename matches this glob (supports *, **, ?)');
commander.option('-k, --kill-force', 'use SIGKILL instead of SIGTERM when restarting');
commander.option('-onrestart <cmd>', 'run a command before each restart (ignore exit code)');
}`;
if (cli.includes(oldWatchSetFlags) && !cli.includes('commander.option(\'-glob')) {
cli = cli.replace(oldWatchSetFlags, newWatchSetFlags);
console.log('Updated watch setFlags');
}
// --------------------------------------------------------------- 7. Update autoupdate module (1039) - add new flags
const oldAutoSetFlags = `function setFlags(commander) {
commander.description('Auto-update packages / scripts, with dev watching and rollback. (modyarn extension)');
commander.usage('autoupdate [packages...] [flags]');
// Short single-char + long forms; original single-dash spellings also kept.
// These flags are registered by autoupdate only, so they never affect other commands.
commander.option('-P, --Package <pkg>', 'auto-update the given package (comma separated list allowed)', collect, []);
commander.option('-S, --Script <pkg>', 'auto-update the given package, refreshing only its *.js files (patch-aware)', collect, []);
commander.option('-atodev, --atodev', 'after updating, auto enable + watch the dev script; exit after 1 minute when no error');
commander.option('-atorollb, --atorollb', 'catch atodev errors and roll back on package-related errors; without atodev, run a node -e check instead');
}`;
const newAutoSetFlags = `function setFlags(commander) {
commander.description('Auto-update packages / scripts, with dev watching and rollback. (modyarn extension)');
commander.usage('autoupdate [packages...] [flags]');
// Short single-char + long forms; original single-dash spellings also kept.
// These flags are registered by autoupdate only, so they never affect other commands.
commander.option('-P, --Package <pkg>', 'auto-update the given package (comma separated list allowed)', collect, []);
commander.option('-S, --Script <pkg>', 'auto-update the given package, refreshing only its *.js files (patch-aware)', collect, []);
commander.option('-atodev, --atodev', 'after updating, auto enable + watch the dev script; exit after devtime ms when no error');
commander.option('-atorollb, --atorollb', 'catch atodev errors and roll back on package-related errors; without atodev, run a node -e check instead');
commander.option('-Force, --force', 'force-keep the update even if atodev reports an error');
commander.option('-devtime <ms>', 'custom dev-monitor duration in milliseconds (default 60000)');
commander.option('-dry, --dry-run', 'snapshot and print what would be done, but do not run upgrade/install');
}`;
if (cli.includes(oldAutoSetFlags) && !cli.includes('commander.option(\'-Force')) {
cli = cli.replace(oldAutoSetFlags, newAutoSetFlags);
console.log('Updated autoupdate setFlags');
}
// --------------------------------------------------------------- 8. Update autoupdate - add dry run, devtime, Force logic
// Need to insert the new flag parsing and logic in the run() function
// Find the existing run() block for autoupdate
const autoupdateFlagsParse = ` var packageTargets = parseList(getFlag(flags, ['Package', 'P', 'p'])).concat(args.slice());
var scriptTargets = parseList(getFlag(flags, ['Script', 'S', 's']));
var atodev = flagBool(flags, ['atodev', 'Atodev']);
var atorollb = flagBool(flags, ['atorollb', 'Atorollb']);
if (packageTargets.length === 0 && scriptTargets.length === 0 && !atodev) {`;
const newAutoupdateFlagsParse = ` var packageTargets = parseList(getFlag(flags, ['Package', 'P', 'p'])).concat(args.slice());
var scriptTargets = parseList(getFlag(flags, ['Script', 'S', 's']));
var atodev = flagBool(flags, ['atodev', 'Atodev']);
var atorollb = flagBool(flags, ['atorollb', 'Atorollb']);
var forceKeep = flagBool(flags, ['force', 'Force']);
var devTimeMs = Number(getFlag(flags, ['devtime', 'DevTime'])) || 60000;
var dryRun = flagBool(flags, ['dry', 'Dry']);
if (packageTargets.length === 0 && scriptTargets.length === 0 && !atodev && !dryRun) {
reporter.error('autoupdate needs at least one target. Use -Package <pkg> and/or -Script <pkg> (or pass package names as arguments), or use -atodev / -dry.');
process.exitCode = 1;
return 1;
}`;
if (cli.includes(autoupdateFlagsParse) && !cli.includes('var forceKeep')) {
cli = cli.replace(autoupdateFlagsParse, newAutoupdateFlagsParse);
console.log('Updated autoupdate flags parsing');
}
// Add dry-run early-return block after snapshot
const dryRunInsertAfter = ` reporter.info('autoupdate: snapshot stored at ' + snapRoot);
var ok = true;`;
const dryRunBlock = ` reporter.info('autoupdate: snapshot stored at ' + snapRoot);
if (dryRun) {
reporter.info('autoupdate(-dry): snapshot taken, operations below would be performed:');
if (packageTargets.length) reporter.info(' upgrade: ' + packageTargets.join(', '));
if (scriptTargets.length) reporter.info(' js-only-refresh: ' + scriptTargets.join(', '));
if (atodev) {
var manifest = yield config.maybeReadManifest(config.cwd);
var scripts = (manifest && manifest.scripts) || {};
var devKey = Object.keys(scripts).filter(function(k) { return /dev/i.test(k); })[0];
reporter.info(' atodev: would run "' + (devKey || '(none)') + '" for ' + devTimeMs + 'ms');
}
reporter.success('autoupdate(-dry): no changes made.');
try { fs.rmSync(snapRoot, { recursive: true, force: true }); } catch (e) {}
return 0;
}
var ok = true;`;
if (cli.includes(dryRunInsertAfter) && !cli.includes('if (dryRun) {')) {
cli = cli.replace(dryRunInsertAfter, dryRunBlock);
console.log('Injected dry-run early-return');
}
// Update runDevMonitor call to pass devTimeMs
const oldDevMonitorCall = 'yield runDevMonitor(config, reporter, dev, allTargets, errSink);';
const newDevMonitorCall = 'yield runDevMonitor(config, reporter, dev, allTargets, errSink, devTimeMs);';
if (cli.includes(oldDevMonitorCall) && !cli.includes('devTimeMs)')) {
cli = cli.replace(oldDevMonitorCall, newDevMonitorCall);
console.log('Updated runDevMonitor call');
}
// Update runDevMonitor signature to accept durationMs
const oldDevMonitorSig = 'function runDevMonitor(config, reporter, devScript, pkgNames, errSink) {';
const newDevMonitorSig = 'function runDevMonitor(config, reporter, devScript, pkgNames, errSink, durationMs) {';
if (cli.includes(oldDevMonitorSig) && !cli.includes('durationMs')) {
cli = cli.replace(oldDevMonitorSig, newDevMonitorSig);
console.log('Updated runDevMonitor signature');
}
// Update deadline to use durationMs instead of hardcoded 60000
const oldDeadline = ' var deadline = Date.now() + 60000; // 1 minute';
const newDeadline = ' var deadline = Date.now() + (typeof durationMs === \'number\' ? durationMs : 60000);';
if (cli.includes(oldDeadline) && !cli.includes('durationMs')) {
cli = cli.replace(oldDeadline, newDeadline);
console.log('Updated deadline to use durationMs');
}
// Add -Force handling after atodev error check
const oldForceHandling = ` if (atorollb || atodev) {
if (errSink.related) {
reporter.warn('autoupdate(-atorollb): error relates to the updated package(s); rolling back...');
restoreSnapshot(config.cwd, snapRoot, snapshot);
yield install.run(config, reporter, {}, []);
reporter.success('autoupdate: rollback complete.');
ok = false;
} else {
reporter.warn('autoupdate(-atorollb): error does not look related to the updated package(s); keeping the update.');
ok = false;
}
} else {
ok = false;
}`;
const newForceHandling = ` if (forceKeep) {
reporter.warn('autoupdate(-Force): error detected but -Force flag keeps the update.');
ok = false;
} else if (atorollb || atodev) {
if (errSink.related) {
reporter.warn('autoupdate(-atorollb): error relates to the updated package(s); rolling back...');
restoreSnapshot(config.cwd, snapRoot, snapshot);
yield install.run(config, reporter, {}, []);
reporter.success('autoupdate: rollback complete.');
ok = false;
} else {
reporter.warn('autoupdate(-atorollb): error does not look related to the updated package(s); keeping the update.');
ok = false;
}
} else {
ok = false;
}`;
if (cli.includes(oldForceHandling) && !cli.includes('if (forceKeep)')) {
cli = cli.replace(oldForceHandling, newForceHandling);
console.log('Injected -Force handling for atodev errors');
}
// Add -Force handling for -atorollb sanity check failures
const oldSanityHandling = ` if (failed.length) {
reporter.warn('autoupdate(-atorollb): sanity check failed for ' + failed.join(', ') + '; rolling back...');
restoreSnapshot(config.cwd, snapRoot, snapshot);
yield install.run(config, reporter, {}, []);
reporter.success('autoupdate: rollback complete.');
ok = false;
} else {
reporter.success('autoupdate: all sanity checks passed.');
}`;
const newSanityHandling = ` if (failed.length) {
if (forceKeep) {
reporter.warn('autoupdate(-Force): sanity check failed but -Force flag keeps the update.');
ok = false;
} else {
reporter.warn('autoupdate(-atorollb): sanity check failed for ' + failed.join(', ') + '; rolling back...');
restoreSnapshot(config.cwd, snapRoot, snapshot);
yield install.run(config, reporter, {}, []);
reporter.success('autoupdate: rollback complete.');
ok = false;
}
} else {
reporter.success('autoupdate: all sanity checks passed.');
}`;
if (cli.includes(oldSanityHandling) && !cli.includes('if (forceKeep)')) {
cli = cli.replace(oldSanityHandling, newSanityHandling);
console.log('Injected -Force handling for sanity check failures');
}
// --------------------------------------------------------------- Write modified cli.js to a temp file, diff against orig
const tmpCli = path.join(__dirname, 'cli.js.new');
fs.writeFileSync(tmpCli, cli, 'utf8');
console.log('Wrote modified cli.js to', tmpCli, '(' + cli.length + ' bytes)');
// Generate unified diff using git diff --no-index
try {
const diff = execSync(`git diff --no-index --unified=3 "${ORIG}" "${tmpCli}"`, {
encoding: 'utf8',
maxBuffer: 50 * 1024 * 1024
});
fs.mkdirSync(path.dirname(PATCH), { recursive: true });
fs.writeFileSync(PATCH, diff, 'utf8');
console.log('Patch written to', PATCH, '(' + diff.length + ' bytes)');
} catch (e) {
// git diff returns exit code 1 when files differ — that's fine
if (e.status === 1) {
const diff = e.stdout;
fs.mkdirSync(path.dirname(PATCH), { recursive: true });
fs.writeFileSync(PATCH, diff, 'utf8');
console.log('Patch written to', PATCH, '(' + diff.length + ' bytes)');
} else {
console.error('diff failed:', e.message);
process.exit(1);
}
}
// Cleanup
try { fs.unlinkSync(tmpCli); } catch (e) {}
console.log('Done.');