@gadmin2n/cli 0.0.112 → 0.0.114
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/actions/update.action.js
CHANGED
|
@@ -19,7 +19,6 @@ const child_process_1 = require("child_process");
|
|
|
19
19
|
const abstract_action_1 = require("./abstract.action");
|
|
20
20
|
const self_update_action_1 = require("./self-update.action");
|
|
21
21
|
const version_check_1 = require("../lib/version-check");
|
|
22
|
-
const schematics_root_1 = require("../lib/schematics-root");
|
|
23
22
|
const executable_paths_1 = require("../lib/executable-paths");
|
|
24
23
|
const merge3way_1 = require("../lib/template-merge/merge3way");
|
|
25
24
|
const binary_detect_1 = require("../lib/template-merge/binary-detect");
|
|
@@ -48,28 +47,6 @@ function formatMaterializeError(schematicsVersion, err) {
|
|
|
48
47
|
const m = (_a = err === null || err === void 0 ? void 0 : err.message) !== null && _a !== void 0 ? _a : String(err);
|
|
49
48
|
return `\n❌ Failed to materialize base @ schematics ${schematicsVersion}: ${m}\n`;
|
|
50
49
|
}
|
|
51
|
-
/* ------------------------------------------------------------------ *
|
|
52
|
-
* Template config / path resolution
|
|
53
|
-
* ------------------------------------------------------------------ */
|
|
54
|
-
function resolveTemplatePath(templateName) {
|
|
55
|
-
const schematicsRoot = (0, schematics_root_1.findSchematicsRoot)();
|
|
56
|
-
const nameVariants = [templateName];
|
|
57
|
-
if (templateName.startsWith('gadmin2n-')) {
|
|
58
|
-
nameVariants.push(templateName.replace('gadmin2n-', 'gadmin2-'));
|
|
59
|
-
}
|
|
60
|
-
else if (templateName.startsWith('gadmin2-')) {
|
|
61
|
-
nameVariants.push(templateName.replace('gadmin2-', 'gadmin2n-'));
|
|
62
|
-
}
|
|
63
|
-
for (const name of nameVariants) {
|
|
64
|
-
const distPath = path.join(schematicsRoot, 'dist/lib/application/files', name);
|
|
65
|
-
const srcPath = path.join(schematicsRoot, 'src/lib/application/files', name);
|
|
66
|
-
if (fs.existsSync(distPath))
|
|
67
|
-
return distPath;
|
|
68
|
-
if (fs.existsSync(srcPath))
|
|
69
|
-
return srcPath;
|
|
70
|
-
}
|
|
71
|
-
throw new Error(`Template directory not found for "${templateName}" in ${schematicsRoot}`);
|
|
72
|
-
}
|
|
73
50
|
/* ------------------------------------------------------------------ *
|
|
74
51
|
* .claude context sync (from remote git repo)
|
|
75
52
|
* ------------------------------------------------------------------ */
|
|
@@ -223,9 +200,18 @@ function syncClaudeContext(instanceDir, dryRun, source) {
|
|
|
223
200
|
console.info(`${chalk.gray('Source: ')} ${source.repo} (${source.branch}) :: ${CLAUDE_SOURCE_SUBDIR}/`);
|
|
224
201
|
console.info(`${chalk.gray('Targets:')} ${CLAUDE_TARGET_DIRS.map((d) => `${d}/`).join(', ')}\n`);
|
|
225
202
|
if (dryRun) {
|
|
226
|
-
console.info(chalk.gray('(dry-run
|
|
203
|
+
console.info(chalk.gray('(dry-run — no files written. The real run would:'));
|
|
204
|
+
console.info(chalk.gray(` 1. git clone ${source.repo} --branch ${source.branch} --depth 1 (into tmp dir)`));
|
|
205
|
+
console.info(chalk.gray(` 2. Copy <tmp>/${CLAUDE_SOURCE_SUBDIR}/** → each target dir, OVERWRITING same-named files`));
|
|
206
|
+
console.info(chalk.gray(' 3. Files only present in target dirs (instance-only) are kept untouched)\n'));
|
|
227
207
|
return;
|
|
228
208
|
}
|
|
209
|
+
// Real run: warn the user that same-named files will be overwritten before
|
|
210
|
+
// we actually do it. They've already accepted the protocol prompt at this
|
|
211
|
+
// point, so we don't ask for further confirmation — just make the behaviour
|
|
212
|
+
// visible so changes to the local copy aren't silently clobbered.
|
|
213
|
+
console.info(chalk.yellow('⚠️ Same-named files in target dirs will be overwritten by the remote version.'));
|
|
214
|
+
console.info(chalk.gray(' Instance-only files (only present locally) are kept untouched.\n'));
|
|
229
215
|
const claudeSrc = fetchClaudeContextRepo(source.repo, source.branch);
|
|
230
216
|
if (!claudeSrc) {
|
|
231
217
|
return;
|
|
@@ -466,7 +452,7 @@ function handleBinary(rel, baseRoot, oursRoot, theirsRoot, opts, conflicts) {
|
|
|
466
452
|
detail: `binary differs three-ways. To accept template: cp "${theirsPath}" "${oursPath}"`,
|
|
467
453
|
});
|
|
468
454
|
console.warn(chalk.yellow(` ⚠️ binary conflict (cannot 3-way merge): ${rel}`));
|
|
469
|
-
console.warn(chalk.gray(` template: ${theirsPath}`));
|
|
455
|
+
console.warn(chalk.gray(` template(theirs): ${theirsPath}`));
|
|
470
456
|
console.warn(chalk.gray(` base: ${basePath}`));
|
|
471
457
|
}
|
|
472
458
|
function applyPlan(plan, baseRoot, oursRoot, theirsRoot, opts) {
|
|
@@ -789,7 +775,17 @@ class UpdateAction extends abstract_action_1.AbstractAction {
|
|
|
789
775
|
...((_b = cfg.templateExcludes) !== null && _b !== void 0 ? _b : []),
|
|
790
776
|
...((_d = (_c = cfg.templateUpdate) === null || _c === void 0 ? void 0 : _c.excludes) !== null && _d !== void 0 ? _d : []),
|
|
791
777
|
];
|
|
792
|
-
|
|
778
|
+
let theirsHandle;
|
|
779
|
+
try {
|
|
780
|
+
theirsHandle = (0, materialize_1.materializeLatest)(cfg.template);
|
|
781
|
+
}
|
|
782
|
+
catch (err) {
|
|
783
|
+
console.error(chalk.red(`\n❌ ${err.message}\n`));
|
|
784
|
+
process.exit(1);
|
|
785
|
+
return; // unreachable; satisfies TS
|
|
786
|
+
}
|
|
787
|
+
const theirsRoot = theirsHandle.dir;
|
|
788
|
+
const theirsVersion = theirsHandle.version;
|
|
793
789
|
const metaExists = fs.existsSync((0, base_store_1.metaPath)(instanceDir));
|
|
794
790
|
let baseHandle = null;
|
|
795
791
|
let baseRoot;
|
|
@@ -801,6 +797,7 @@ class UpdateAction extends abstract_action_1.AbstractAction {
|
|
|
801
797
|
baseRoot = baseHandle.dir;
|
|
802
798
|
}
|
|
803
799
|
catch (err) {
|
|
800
|
+
theirsHandle.cleanup();
|
|
804
801
|
console.error(chalk.red(formatMaterializeError((_e = meta === null || meta === void 0 ? void 0 : meta.schematicsVersion) !== null && _e !== void 0 ? _e : '?', err)));
|
|
805
802
|
process.exit(1);
|
|
806
803
|
}
|
|
@@ -811,8 +808,8 @@ class UpdateAction extends abstract_action_1.AbstractAction {
|
|
|
811
808
|
baseRoot = path.join(instanceDir, '.gadmin/__nonexistent__');
|
|
812
809
|
}
|
|
813
810
|
try {
|
|
814
|
-
console.info(`\n${chalk.gray('Template:')}
|
|
815
|
-
console.info(`${chalk.gray('Instance:')} ${instanceDir}`);
|
|
811
|
+
console.info(`\n${chalk.gray('Template(Theirs):')} @gadmin2n/schematics@${theirsVersion} (latest)`);
|
|
812
|
+
console.info(`${chalk.gray('Instance(Ours):')} ${instanceDir}`);
|
|
816
813
|
console.info(`${chalk.gray('Base: ')} ${metaExists
|
|
817
814
|
? `(materialized from schematics ${meta.schematicsVersion})`
|
|
818
815
|
: '(not yet established — run `gadmin2 update` once to bootstrap)'}`);
|
|
@@ -857,6 +854,7 @@ class UpdateAction extends abstract_action_1.AbstractAction {
|
|
|
857
854
|
finally {
|
|
858
855
|
if (baseHandle)
|
|
859
856
|
baseHandle.cleanup();
|
|
857
|
+
theirsHandle.cleanup();
|
|
860
858
|
}
|
|
861
859
|
});
|
|
862
860
|
}
|
|
@@ -886,17 +884,18 @@ class UpdateAction extends abstract_action_1.AbstractAction {
|
|
|
886
884
|
console.error(chalk.red(err.message + '\n'));
|
|
887
885
|
process.exit(2);
|
|
888
886
|
}
|
|
889
|
-
console.info(`Template: ${cfg.template} @ schematics ${meta.schematicsVersion}`);
|
|
887
|
+
console.info(`Template(Theirs): ${cfg.template} @ schematics ${meta.schematicsVersion}`);
|
|
890
888
|
const allExcludes = [...excludes_1.HARDCODED_EXCLUDES, ...excludes_1.DEFAULT_EXCLUDES, ...userExcludes];
|
|
891
889
|
const instanceFiles = (0, excludes_1.collectFiles)(instanceDir, allExcludes);
|
|
892
890
|
const residual = (0, residual_scan_1.scanResidualMarkers)(instanceDir, instanceFiles);
|
|
893
|
-
let
|
|
891
|
+
let theirsHandle;
|
|
894
892
|
try {
|
|
895
|
-
|
|
893
|
+
theirsHandle = (0, materialize_1.materializeLatest)(cfg.template);
|
|
896
894
|
}
|
|
897
895
|
catch (err) {
|
|
898
896
|
console.error(chalk.red(err.message + '\n'));
|
|
899
897
|
process.exit(2);
|
|
898
|
+
return; // unreachable
|
|
900
899
|
}
|
|
901
900
|
let baseHandle = null;
|
|
902
901
|
try {
|
|
@@ -907,7 +906,7 @@ class UpdateAction extends abstract_action_1.AbstractAction {
|
|
|
907
906
|
console.error(chalk.red(formatMaterializeError(meta.schematicsVersion, err)));
|
|
908
907
|
process.exit(2);
|
|
909
908
|
}
|
|
910
|
-
const plan = (0, classify_1.classifyAll)(baseHandle.dir, instanceDir,
|
|
909
|
+
const plan = (0, classify_1.classifyAll)(baseHandle.dir, instanceDir, theirsHandle.dir, userExcludes);
|
|
911
910
|
const structural = [
|
|
912
911
|
...plan.addAddConflict.map((p) => ({ kind: 'add/add', path: p })),
|
|
913
912
|
...plan.modifyDeleteConflict.map((p) => ({ kind: 'modify/delete', path: p })),
|
|
@@ -943,6 +942,7 @@ class UpdateAction extends abstract_action_1.AbstractAction {
|
|
|
943
942
|
finally {
|
|
944
943
|
if (baseHandle)
|
|
945
944
|
baseHandle.cleanup();
|
|
945
|
+
theirsHandle.cleanup();
|
|
946
946
|
}
|
|
947
947
|
});
|
|
948
948
|
}
|
|
@@ -956,13 +956,15 @@ class UpdateAction extends abstract_action_1.AbstractAction {
|
|
|
956
956
|
const templateEnabled = ((_e = options.find((o) => o.name === 'template')) === null || _e === void 0 ? void 0 : _e.value) !== false;
|
|
957
957
|
const claudeEnabled = ((_f = options.find((o) => o.name === 'coding-context')) === null || _f === void 0 ? void 0 : _f.value) !== false;
|
|
958
958
|
if (!templateEnabled && !claudeEnabled) {
|
|
959
|
-
|
|
959
|
+
// Should never happen under the opt-in selector — kept as a safety net.
|
|
960
|
+
console.error(chalk.red('\nNothing to do: neither stage was selected.\n'));
|
|
960
961
|
process.exit(1);
|
|
961
962
|
}
|
|
962
963
|
const mergeOpts = { ours, theirs };
|
|
963
964
|
let pkgSnapshots = null;
|
|
964
965
|
let preflight = null;
|
|
965
966
|
let baseHandle = null;
|
|
967
|
+
let theirsHandle = null;
|
|
966
968
|
try {
|
|
967
969
|
if (templateEnabled) {
|
|
968
970
|
try {
|
|
@@ -973,20 +975,31 @@ class UpdateAction extends abstract_action_1.AbstractAction {
|
|
|
973
975
|
process.exit(1);
|
|
974
976
|
}
|
|
975
977
|
const { instanceDir, templateName, userExcludes } = preflight;
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
978
|
+
// Pull the latest schematics tarball from npm to use as `theirs`.
|
|
979
|
+
// Fail-hard: if the registry is unreachable, abort the update — we
|
|
980
|
+
// don't want to silently fall back to a stale local copy.
|
|
981
|
+
try {
|
|
982
|
+
theirsHandle = (0, materialize_1.materializeLatest)(templateName);
|
|
983
|
+
}
|
|
984
|
+
catch (err) {
|
|
985
|
+
console.error(chalk.red(`\n❌ ${err.message}\n`));
|
|
986
|
+
process.exit(1);
|
|
987
|
+
return; // unreachable
|
|
988
|
+
}
|
|
989
|
+
const theirsRoot = theirsHandle.dir;
|
|
990
|
+
const schematicsVersion = theirsHandle.version;
|
|
991
|
+
console.info(`\n${chalk.gray('Template(Theirs):')} @gadmin2n/schematics@${schematicsVersion} (latest)`);
|
|
992
|
+
console.info(`${chalk.gray('Instance(Ours):')} ${instanceDir}\n`);
|
|
979
993
|
// Snapshot package.json before any writes (for stage 3 install)
|
|
980
994
|
pkgSnapshots = [
|
|
981
995
|
snapshotPackageJson(instanceDir, '(root)'),
|
|
982
996
|
snapshotPackageJson(path.join(instanceDir, 'web'), 'web'),
|
|
983
997
|
snapshotPackageJson(path.join(instanceDir, 'server'), 'server'),
|
|
984
998
|
];
|
|
985
|
-
const schematicsVersion = (0, schematics_root_1.getSchematicsVersion)(instanceDir);
|
|
986
999
|
// First-time bootstrap: meta absent → write meta + README, exit.
|
|
987
1000
|
if (!fs.existsSync((0, base_store_1.metaPath)(instanceDir))) {
|
|
988
1001
|
if (dryRun) {
|
|
989
|
-
console.info(chalk.gray('(dry-run: would write .gadmin/.meta.json pinned to
|
|
1002
|
+
console.info(chalk.gray('(dry-run: would write .gadmin/.meta.json pinned to latest schematics version, then exit)\n'));
|
|
990
1003
|
}
|
|
991
1004
|
else {
|
|
992
1005
|
(0, base_store_1.writeMeta)(instanceDir, {
|
|
@@ -995,7 +1008,7 @@ class UpdateAction extends abstract_action_1.AbstractAction {
|
|
|
995
1008
|
});
|
|
996
1009
|
(0, base_store_1.writeReadme)(instanceDir);
|
|
997
1010
|
console.info(chalk.green('✅ Baseline established at .gadmin/.meta.json'));
|
|
998
|
-
console.info(chalk.gray(` Pinned to schematics ${schematicsVersion}.`));
|
|
1011
|
+
console.info(chalk.gray(` Pinned to schematics ${schematicsVersion} (latest from npm).`));
|
|
999
1012
|
console.info(chalk.gray(' The next `gadmin2 update` will perform a real 3-way merge.'));
|
|
1000
1013
|
}
|
|
1001
1014
|
// Skip the rest of stage 1 — nothing to merge yet.
|
|
@@ -1085,7 +1098,7 @@ class UpdateAction extends abstract_action_1.AbstractAction {
|
|
|
1085
1098
|
}
|
|
1086
1099
|
}
|
|
1087
1100
|
else {
|
|
1088
|
-
console.info(chalk.gray('\nSkipping template update (
|
|
1101
|
+
console.info(chalk.gray('\nSkipping template update (not selected).\n'));
|
|
1089
1102
|
}
|
|
1090
1103
|
// Stage 2: .claude context sync — UNCHANGED.
|
|
1091
1104
|
if (claudeEnabled) {
|
|
@@ -1096,11 +1109,11 @@ class UpdateAction extends abstract_action_1.AbstractAction {
|
|
|
1096
1109
|
yield syncClaudeContext(process.cwd(), dryRun, claudeSource);
|
|
1097
1110
|
}
|
|
1098
1111
|
else {
|
|
1099
|
-
console.info(chalk.gray('\nSkipping .claude context sync (per user choice
|
|
1112
|
+
console.info(chalk.gray('\nSkipping .claude context sync (per user choice).\n'));
|
|
1100
1113
|
}
|
|
1101
1114
|
}
|
|
1102
1115
|
else {
|
|
1103
|
-
console.info(chalk.gray('\nSkipping .claude context sync (
|
|
1116
|
+
console.info(chalk.gray('\nSkipping .claude context sync (not selected).\n'));
|
|
1104
1117
|
}
|
|
1105
1118
|
// Stage 3: Install changed deps — UNCHANGED.
|
|
1106
1119
|
if (pkgSnapshots) {
|
|
@@ -1110,6 +1123,8 @@ class UpdateAction extends abstract_action_1.AbstractAction {
|
|
|
1110
1123
|
finally {
|
|
1111
1124
|
if (baseHandle)
|
|
1112
1125
|
baseHandle.cleanup();
|
|
1126
|
+
if (theirsHandle)
|
|
1127
|
+
theirsHandle.cleanup();
|
|
1113
1128
|
if (preflight)
|
|
1114
1129
|
preflight.releaseLock();
|
|
1115
1130
|
}
|
|
@@ -25,23 +25,32 @@ class UpdateCommand extends abstract_command_1.AbstractCommand {
|
|
|
25
25
|
' Conflict resolution:\n' +
|
|
26
26
|
' Conflicts are written into source files as <<<<<<< INSTANCE / >>>>>>> TEMPLATE markers.\n' +
|
|
27
27
|
' Resolve them in your editor, verify with `gadmin2 update status`, then commit.\n\n' +
|
|
28
|
-
' Stage
|
|
29
|
-
' --
|
|
30
|
-
' --
|
|
28
|
+
' Stage selection (opt-in selector — when omitted, both stages run):\n' +
|
|
29
|
+
' --template Run only the template merge + deps install stage.\n' +
|
|
30
|
+
' --coding-context Run only the .claude context sync stage.\n' +
|
|
31
|
+
' (pass both / neither) Run both stages.\n')
|
|
31
32
|
.option('--no-content', '[diff] Only show file list, skip inline diff content.')
|
|
32
33
|
.option('-d, --dry-run', '[update] Show what would be updated without making changes.')
|
|
33
|
-
.option('-y, --yes', '[update] Skip interactive prompts (
|
|
34
|
+
.option('-y, --yes', '[update] Skip interactive prompts (template confirm, .claude protocol).')
|
|
34
35
|
.option('--ours', '[update] Resolve all conflicts by keeping the instance side (mutually exclusive with --theirs).')
|
|
35
36
|
.option('--theirs', '[update] Resolve all conflicts by taking the template side (mutually exclusive with --ours).')
|
|
36
37
|
.option('--no-version-check', '[update | diff] Skip the npm registry version check at startup.')
|
|
37
38
|
.option('--coding-context-repo <url>', '[update] Fully override the .claude context repo URL.')
|
|
38
39
|
.option('--coding-context-protocol <proto>', '[update] One of: https | ssh | skip.')
|
|
39
|
-
.option('--
|
|
40
|
-
.option('--
|
|
40
|
+
.option('--template', '[update] Run only the template merge + deps install stage.')
|
|
41
|
+
.option('--coding-context', '[update] Run only the .claude context sync stage.')
|
|
41
42
|
.action((subcommand, arg, command) => __awaiter(this, void 0, void 0, function* () {
|
|
42
43
|
const inputs = [];
|
|
43
44
|
inputs.push({ name: 'subcommand', value: subcommand || '' });
|
|
44
45
|
inputs.push({ name: 'subcommand-arg', value: arg || '' });
|
|
46
|
+
// Opt-in stage selector: when neither --template nor --coding-context
|
|
47
|
+
// is passed, run both stages (default). When at least one is passed,
|
|
48
|
+
// run only the stage(s) explicitly requested.
|
|
49
|
+
const tplFlag = !!command.template;
|
|
50
|
+
const ctxFlag = !!command.codingContext;
|
|
51
|
+
const anySelector = tplFlag || ctxFlag;
|
|
52
|
+
const templateEnabled = anySelector ? tplFlag : true;
|
|
53
|
+
const codingContextEnabled = anySelector ? ctxFlag : true;
|
|
45
54
|
const options = [];
|
|
46
55
|
options.push({ name: 'no-content', value: !command.content });
|
|
47
56
|
options.push({ name: 'dry-run', value: !!command.dryRun });
|
|
@@ -51,8 +60,8 @@ class UpdateCommand extends abstract_command_1.AbstractCommand {
|
|
|
51
60
|
options.push({ name: 'version-check', value: command.versionCheck !== false });
|
|
52
61
|
options.push({ name: 'coding-context-repo', value: command.codingContextRepo || '' });
|
|
53
62
|
options.push({ name: 'coding-context-protocol', value: command.codingContextProtocol || '' });
|
|
54
|
-
options.push({ name: 'coding-context', value:
|
|
55
|
-
options.push({ name: 'template', value:
|
|
63
|
+
options.push({ name: 'coding-context', value: codingContextEnabled });
|
|
64
|
+
options.push({ name: 'template', value: templateEnabled });
|
|
56
65
|
yield this.action.handle(inputs, options);
|
|
57
66
|
}));
|
|
58
67
|
}
|
|
@@ -4,6 +4,10 @@ export interface MaterializedBase {
|
|
|
4
4
|
/** Idempotent cleanup of any temp dirs created. */
|
|
5
5
|
cleanup: () => void;
|
|
6
6
|
}
|
|
7
|
+
export interface MaterializedLatest extends MaterializedBase {
|
|
8
|
+
/** Resolved version string (whatever the registry / env override returned). */
|
|
9
|
+
version: string;
|
|
10
|
+
}
|
|
7
11
|
/**
|
|
8
12
|
* Materialize a base reference for 3-way merge.
|
|
9
13
|
*
|
|
@@ -16,3 +20,26 @@ export interface MaterializedBase {
|
|
|
16
20
|
* Returned `cleanup()` removes any tmp dir we created.
|
|
17
21
|
*/
|
|
18
22
|
export declare function materializeBase(schematicsVersion: string, templateName: string): MaterializedBase;
|
|
23
|
+
/**
|
|
24
|
+
* Resolve the latest published version of `@gadmin2n/schematics`.
|
|
25
|
+
*
|
|
26
|
+
* Sources, in priority order:
|
|
27
|
+
* 1. `GADMIN2_LATEST_VERSION` env var — used by tests and `--use-version=X`
|
|
28
|
+
* style overrides.
|
|
29
|
+
* 2. `npm view @gadmin2n/schematics version --json` — production. Hard
|
|
30
|
+
* timeout via npm's own behaviour; we do not catch ENOENT here because a
|
|
31
|
+
* missing `npm` is a fatal config error.
|
|
32
|
+
*
|
|
33
|
+
* Throws on any failure (fail-hard per design decision: theirs must always be
|
|
34
|
+
* truly latest, callers should not silently fall back to a stale local copy).
|
|
35
|
+
*/
|
|
36
|
+
export declare function resolveLatestVersion(): string;
|
|
37
|
+
/**
|
|
38
|
+
* Materialize the LATEST published template as the `theirs` side of a
|
|
39
|
+
* 3-way merge. Equivalent to `materializeBase(resolveLatestVersion(), ...)`
|
|
40
|
+
* with the resolved version returned alongside the handle.
|
|
41
|
+
*
|
|
42
|
+
* Per design (fail-hard on network failure): if either step throws, the
|
|
43
|
+
* caller is expected to surface the error and abort the update.
|
|
44
|
+
*/
|
|
45
|
+
export declare function materializeLatest(templateName: string): MaterializedLatest;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.materializeBase = void 0;
|
|
3
|
+
exports.materializeLatest = exports.resolveLatestVersion = exports.materializeBase = void 0;
|
|
4
4
|
// cli/lib/template-merge/materialize.ts
|
|
5
5
|
const fs = require("fs");
|
|
6
6
|
const os = require("os");
|
|
@@ -127,3 +127,60 @@ function copyTreeRecursive(src, dst) {
|
|
|
127
127
|
// symlinks / sockets: skip
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* Resolve the latest published version of `@gadmin2n/schematics`.
|
|
132
|
+
*
|
|
133
|
+
* Sources, in priority order:
|
|
134
|
+
* 1. `GADMIN2_LATEST_VERSION` env var — used by tests and `--use-version=X`
|
|
135
|
+
* style overrides.
|
|
136
|
+
* 2. `npm view @gadmin2n/schematics version --json` — production. Hard
|
|
137
|
+
* timeout via npm's own behaviour; we do not catch ENOENT here because a
|
|
138
|
+
* missing `npm` is a fatal config error.
|
|
139
|
+
*
|
|
140
|
+
* Throws on any failure (fail-hard per design decision: theirs must always be
|
|
141
|
+
* truly latest, callers should not silently fall back to a stale local copy).
|
|
142
|
+
*/
|
|
143
|
+
function resolveLatestVersion() {
|
|
144
|
+
var _a, _b, _c, _d;
|
|
145
|
+
const envOverride = process.env.GADMIN2_LATEST_VERSION;
|
|
146
|
+
if (envOverride)
|
|
147
|
+
return envOverride.trim();
|
|
148
|
+
try {
|
|
149
|
+
const out = (0, child_process_1.execFileSync)('npm', ['view', SCHEMATICS_PKG, 'version', '--json'], { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'] });
|
|
150
|
+
const trimmed = out.trim();
|
|
151
|
+
// `--json` wraps the value in quotes for plain strings.
|
|
152
|
+
const parsed = trimmed.startsWith('"') ? JSON.parse(trimmed) : trimmed;
|
|
153
|
+
if (typeof parsed !== 'string' || parsed.length === 0) {
|
|
154
|
+
throw new Error(`unexpected npm view output: ${out}`);
|
|
155
|
+
}
|
|
156
|
+
return parsed;
|
|
157
|
+
}
|
|
158
|
+
catch (err) {
|
|
159
|
+
if (err && err.code === 'ENOENT') {
|
|
160
|
+
throw new Error('npm not in PATH — required to resolve the latest @gadmin2n/schematics version. ' +
|
|
161
|
+
'Install Node.js / npm and retry.');
|
|
162
|
+
}
|
|
163
|
+
const stderr = (_c = (_b = (_a = err === null || err === void 0 ? void 0 : err.stderr) === null || _a === void 0 ? void 0 : _a.toString) === null || _b === void 0 ? void 0 : _b.call(_a)) !== null && _c !== void 0 ? _c : '';
|
|
164
|
+
const message = (_d = err === null || err === void 0 ? void 0 : err.message) !== null && _d !== void 0 ? _d : String(err);
|
|
165
|
+
throw new Error(`Failed to resolve latest @gadmin2n/schematics version from npm registry.\n` +
|
|
166
|
+
` ${message.split('\n').join('\n ')}` +
|
|
167
|
+
(stderr ? `\n ${stderr.trim().split('\n').join('\n ')}` : '') +
|
|
168
|
+
`\n Check your network / npm registry config and retry, ` +
|
|
169
|
+
`or set GADMIN2_LATEST_VERSION=<version> to pin a specific version.`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
exports.resolveLatestVersion = resolveLatestVersion;
|
|
173
|
+
/**
|
|
174
|
+
* Materialize the LATEST published template as the `theirs` side of a
|
|
175
|
+
* 3-way merge. Equivalent to `materializeBase(resolveLatestVersion(), ...)`
|
|
176
|
+
* with the resolved version returned alongside the handle.
|
|
177
|
+
*
|
|
178
|
+
* Per design (fail-hard on network failure): if either step throws, the
|
|
179
|
+
* caller is expected to surface the error and abort the update.
|
|
180
|
+
*/
|
|
181
|
+
function materializeLatest(templateName) {
|
|
182
|
+
const version = resolveLatestVersion();
|
|
183
|
+
const handle = materializeBase(version, templateName);
|
|
184
|
+
return Object.assign(Object.assign({}, handle), { version });
|
|
185
|
+
}
|
|
186
|
+
exports.materializeLatest = materializeLatest;
|