magic-spec 1.4.1 → 1.4.2
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/CHANGELOG.md +1 -1
- package/installers/config.json +8 -0
- package/installers/node/index.js +46 -50
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
-
## [1.4.
|
|
8
|
+
## [1.4.2] - 2026-03-01
|
|
9
9
|
|
|
10
10
|
### Fixed
|
|
11
11
|
|
package/installers/config.json
CHANGED
|
@@ -65,5 +65,13 @@
|
|
|
65
65
|
"CHANGELOG.md"
|
|
66
66
|
],
|
|
67
67
|
"docsDir": "docs"
|
|
68
|
+
},
|
|
69
|
+
"tests": {
|
|
70
|
+
"sandboxDir": "installers/tests/sandbox",
|
|
71
|
+
"adaptersJson": "installers/adapters.json",
|
|
72
|
+
"pythonInstaller": "installers/python/magic_spec/__main__.py",
|
|
73
|
+
"nodeInstaller": "installers/node/index.js",
|
|
74
|
+
"testDir": "installers/tests",
|
|
75
|
+
"testPattern": "test_*.py"
|
|
68
76
|
}
|
|
69
77
|
}
|
package/installers/node/index.js
CHANGED
|
@@ -116,6 +116,7 @@ const isInfo = args.includes('info');
|
|
|
116
116
|
const isListEnvs = args.includes('--list-envs');
|
|
117
117
|
const isEject = args.includes('--eject');
|
|
118
118
|
const isFallbackMain = args.includes('--fallback-main');
|
|
119
|
+
const isLocal = args.includes('--local');
|
|
119
120
|
const autoAccept = args.includes('--yes') || args.includes('-y');
|
|
120
121
|
|
|
121
122
|
function parseCsvValues(raw) {
|
|
@@ -331,16 +332,20 @@ function runInfo() {
|
|
|
331
332
|
}
|
|
332
333
|
console.log(`Installed version : ${installedVersion} (.magic/.version)`);
|
|
333
334
|
|
|
334
|
-
const
|
|
335
|
-
let
|
|
336
|
-
if (fs.existsSync(
|
|
335
|
+
const ADAPTERS_PATH = path.join(__dirname, '..', 'adapters.json');
|
|
336
|
+
let activeEnvs = [];
|
|
337
|
+
if (fs.existsSync(ADAPTERS_PATH)) {
|
|
337
338
|
try {
|
|
338
|
-
const
|
|
339
|
-
|
|
339
|
+
const adapters = JSON.parse(fs.readFileSync(ADAPTERS_PATH, 'utf8'));
|
|
340
|
+
activeEnvs = detectEnvironments(adapters);
|
|
340
341
|
} catch (e) { }
|
|
341
342
|
}
|
|
342
|
-
console.log(`Active env : ${activeEnv}`);
|
|
343
343
|
|
|
344
|
+
if (activeEnvs.length === 0) {
|
|
345
|
+
console.log(`Active env : default (${AGENT_DIR}/)`);
|
|
346
|
+
} else {
|
|
347
|
+
console.log(`Active envs : ${activeEnvs.join(', ')}`);
|
|
348
|
+
}
|
|
344
349
|
const enginePresent = fs.existsSync(path.join(cwd, ENGINE_DIR));
|
|
345
350
|
console.log(`Engine : ${ENGINE_DIR}/ ${enginePresent ? '✅ present' : '❌ missing'}`);
|
|
346
351
|
|
|
@@ -431,18 +436,17 @@ async function runEject() {
|
|
|
431
436
|
}
|
|
432
437
|
}
|
|
433
438
|
|
|
434
|
-
function
|
|
439
|
+
function detectEnvironments(adapters) {
|
|
440
|
+
const detected = [];
|
|
435
441
|
for (const env in adapters) {
|
|
436
442
|
const marker = adapters[env].marker;
|
|
437
|
-
if (marker && fs.existsSync(path.join(cwd, marker)))
|
|
443
|
+
if (marker && fs.existsSync(path.join(cwd, marker))) {
|
|
444
|
+
detected.push(env);
|
|
445
|
+
}
|
|
438
446
|
}
|
|
439
|
-
return
|
|
447
|
+
return detected;
|
|
440
448
|
}
|
|
441
449
|
|
|
442
|
-
function saveMagicRc(config) {
|
|
443
|
-
const magicrcFile = path.join(cwd, '.magicrc');
|
|
444
|
-
fs.writeFileSync(magicrcFile, JSON.stringify(config, null, 2), 'utf8');
|
|
445
|
-
}
|
|
446
450
|
|
|
447
451
|
function getFileChecksum(filePath) {
|
|
448
452
|
if (!fs.existsSync(filePath)) return null;
|
|
@@ -662,6 +666,7 @@ async function main() {
|
|
|
662
666
|
console.log(" --env <adapter> Specify environment adapter");
|
|
663
667
|
console.log(" --<adapter> Shortcut for --env <adapter> (e.g. --cursor)");
|
|
664
668
|
console.log(" --update Update engine files only");
|
|
669
|
+
console.log(" --local Use local project files instead of GitHub");
|
|
665
670
|
console.log(" --fallback-main Pull payload from main branch");
|
|
666
671
|
console.log(" --yes, -y Auto-accept prompts");
|
|
667
672
|
process.exit(0);
|
|
@@ -676,18 +681,16 @@ async function main() {
|
|
|
676
681
|
const versionToFetch = isFallbackMain ? 'main' : version;
|
|
677
682
|
let sourceRoot = null;
|
|
678
683
|
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
try {
|
|
684
|
-
magicrc = JSON.parse(fs.readFileSync(magicrcFile, 'utf8'));
|
|
685
|
-
} catch (e) { }
|
|
684
|
+
if (isLocal) {
|
|
685
|
+
// In local mode, source root is the parent of 'installers' folder
|
|
686
|
+
sourceRoot = path.resolve(__dirname, '..', '..');
|
|
687
|
+
console.log(`🏠 Using local project files from: ${sourceRoot}`);
|
|
686
688
|
}
|
|
687
689
|
|
|
688
690
|
try {
|
|
689
|
-
|
|
690
|
-
|
|
691
|
+
if (!isLocal) {
|
|
692
|
+
sourceRoot = await downloadPayload(versionToFetch);
|
|
693
|
+
}
|
|
691
694
|
let ADAPTERS = {};
|
|
692
695
|
try {
|
|
693
696
|
ADAPTERS = JSON.parse(fs.readFileSync(path.join(sourceRoot, 'installers', 'adapters.json'), 'utf8'));
|
|
@@ -706,29 +709,32 @@ async function main() {
|
|
|
706
709
|
}
|
|
707
710
|
}
|
|
708
711
|
|
|
709
|
-
let selectedEnvResolved = null;
|
|
710
712
|
if (envValues.length > 0) {
|
|
711
713
|
selectedEnvResolved = envValues[0];
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
if (envValues.length === 0 && !isUpdate) {
|
|
717
|
+
const detected = detectEnvironments(ADAPTERS);
|
|
718
|
+
if (detected.length > 0) {
|
|
719
|
+
// If only one detected, we can suggest it. If multiple, we need user choice or explicit flags.
|
|
720
|
+
if (detected.length === 1) {
|
|
721
|
+
const env = detected[0];
|
|
722
|
+
const adapterName = ADAPTERS[env].description || env;
|
|
723
|
+
console.log(`\n💡 Detected ${adapterName} (${ADAPTERS[env].marker}/ directory found).`);
|
|
724
|
+
let shouldAdopt = autoAccept;
|
|
725
|
+
if (!shouldAdopt) {
|
|
726
|
+
const answer = await askQuestion(` Install ${env} adapter instead of default? (y/N): `);
|
|
727
|
+
shouldAdopt = answer.toLowerCase() === 'y';
|
|
728
|
+
}
|
|
729
|
+
if (shouldAdopt) {
|
|
730
|
+
selectedEnvResolved = env;
|
|
731
|
+
}
|
|
732
|
+
} else {
|
|
733
|
+
console.log(`\n💡 Multiple environments detected: ${detected.join(', ')}`);
|
|
734
|
+
console.log(` Use --env <name> or --<name> to target specific one.`);
|
|
728
735
|
}
|
|
729
736
|
}
|
|
730
737
|
}
|
|
731
|
-
|
|
732
738
|
let conflictsToSkip = [];
|
|
733
739
|
if (isUpdate) {
|
|
734
740
|
const conflictResult = await handleConflicts(cwd);
|
|
@@ -842,16 +848,6 @@ async function main() {
|
|
|
842
848
|
console.warn(`⚠️ Failed to write .magic/.version: ${vErr.message}`);
|
|
843
849
|
}
|
|
844
850
|
|
|
845
|
-
// 5. Update .magicrc - [T-2C02]
|
|
846
|
-
try {
|
|
847
|
-
const newConfig = {
|
|
848
|
-
env: selectedEnvResolved || magicrc.env || 'default',
|
|
849
|
-
version: version
|
|
850
|
-
};
|
|
851
|
-
saveMagicRc(newConfig);
|
|
852
|
-
} catch (rcErr) {
|
|
853
|
-
console.warn(`⚠️ Failed to update .magicrc: ${rcErr.message}`);
|
|
854
|
-
}
|
|
855
851
|
|
|
856
852
|
// 6. Save checksums - [T-2C03]
|
|
857
853
|
try {
|