mover-os 4.3.0 → 4.3.1
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/install.js +45 -1
- package/package.json +1 -1
package/install.js
CHANGED
|
@@ -12,6 +12,7 @@ const readline = require("readline");
|
|
|
12
12
|
const fs = require("fs");
|
|
13
13
|
const path = require("path");
|
|
14
14
|
const os = require("os");
|
|
15
|
+
const crypto = require("crypto");
|
|
15
16
|
const { execSync } = require("child_process");
|
|
16
17
|
|
|
17
18
|
const VERSION = "4";
|
|
@@ -1349,6 +1350,7 @@ function writeMoverConfig(vaultPath, agentIds, licenseKey) {
|
|
|
1349
1350
|
const existing = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
1350
1351
|
if (existing.installedAt) config.installedAt = existing.installedAt;
|
|
1351
1352
|
if (existing.licenseKey && !licenseKey) config.licenseKey = existing.licenseKey;
|
|
1353
|
+
if (existing.feedbackWebhook) config.feedbackWebhook = existing.feedbackWebhook;
|
|
1352
1354
|
config.updatedAt = new Date().toISOString();
|
|
1353
1355
|
} catch {}
|
|
1354
1356
|
}
|
|
@@ -1519,17 +1521,52 @@ function installRules(bundleDir, destPath, agentId) {
|
|
|
1519
1521
|
return true;
|
|
1520
1522
|
}
|
|
1521
1523
|
|
|
1524
|
+
function computeSkillHash(dirPath) {
|
|
1525
|
+
const hash = crypto.createHash("sha256");
|
|
1526
|
+
const entries = fs.readdirSync(dirPath, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
1527
|
+
for (const entry of entries) {
|
|
1528
|
+
const full = path.join(dirPath, entry.name);
|
|
1529
|
+
if (entry.isFile()) {
|
|
1530
|
+
hash.update(entry.name);
|
|
1531
|
+
hash.update(fs.readFileSync(full));
|
|
1532
|
+
} else if (entry.isDirectory()) {
|
|
1533
|
+
hash.update(entry.name + "/");
|
|
1534
|
+
hash.update(computeSkillHash(full));
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
return hash.digest("hex");
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1522
1540
|
function installSkillPacks(bundleDir, destDir, selectedCategories) {
|
|
1523
1541
|
const skills = findSkills(bundleDir);
|
|
1524
1542
|
fs.mkdirSync(destDir, { recursive: true });
|
|
1525
1543
|
const installedNames = new Set();
|
|
1526
1544
|
let count = 0;
|
|
1545
|
+
let skipped = 0;
|
|
1546
|
+
|
|
1547
|
+
// Load existing manifest for change detection
|
|
1548
|
+
const manifestPath = path.join(destDir, ".skill-manifest.json");
|
|
1549
|
+
let manifest = { skills: {} };
|
|
1550
|
+
try {
|
|
1551
|
+
if (fs.existsSync(manifestPath)) manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
|
|
1552
|
+
} catch {}
|
|
1553
|
+
|
|
1527
1554
|
for (const skill of skills) {
|
|
1528
1555
|
// Filter by category if categories were selected (tools always installed)
|
|
1529
1556
|
if (selectedCategories && skill.category !== "tools" && !selectedCategories.has(skill.category)) continue;
|
|
1530
1557
|
const dest = path.join(destDir, skill.name);
|
|
1558
|
+
|
|
1559
|
+
// Skip unchanged skills
|
|
1560
|
+
const sourceHash = computeSkillHash(skill.path);
|
|
1561
|
+
if (manifest.skills[skill.name]?.hash === sourceHash && fs.existsSync(dest)) {
|
|
1562
|
+
installedNames.add(skill.name);
|
|
1563
|
+
skipped++;
|
|
1564
|
+
continue;
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1531
1567
|
if (fs.existsSync(dest)) fs.rmSync(dest, { recursive: true, force: true });
|
|
1532
1568
|
copyDirRecursive(skill.path, dest);
|
|
1569
|
+
manifest.skills[skill.name] = { hash: sourceHash, installedAt: new Date().toISOString() };
|
|
1533
1570
|
installedNames.add(skill.name);
|
|
1534
1571
|
count++;
|
|
1535
1572
|
}
|
|
@@ -1549,6 +1586,11 @@ function installSkillPacks(bundleDir, destDir, selectedCategories) {
|
|
|
1549
1586
|
}
|
|
1550
1587
|
} catch (e) { /* skip */ }
|
|
1551
1588
|
}
|
|
1589
|
+
|
|
1590
|
+
// Write manifest for next run's change detection
|
|
1591
|
+
try { fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + "\n"); } catch {}
|
|
1592
|
+
|
|
1593
|
+
if (skipped > 0) ln(` ${dim(`${skipped} skills unchanged, skipped`)}`);
|
|
1552
1594
|
return count;
|
|
1553
1595
|
}
|
|
1554
1596
|
|
|
@@ -2080,6 +2122,7 @@ async function main() {
|
|
|
2080
2122
|
}
|
|
2081
2123
|
|
|
2082
2124
|
if (!key) {
|
|
2125
|
+
let validated = false;
|
|
2083
2126
|
let attempts = 0;
|
|
2084
2127
|
while (attempts < 3) {
|
|
2085
2128
|
key = await textInput({
|
|
@@ -2093,6 +2136,7 @@ async function main() {
|
|
|
2093
2136
|
if (valid) {
|
|
2094
2137
|
sp.stop(green("License verified"));
|
|
2095
2138
|
await activateKey(key);
|
|
2139
|
+
validated = true;
|
|
2096
2140
|
break;
|
|
2097
2141
|
}
|
|
2098
2142
|
|
|
@@ -2105,7 +2149,7 @@ async function main() {
|
|
|
2105
2149
|
}
|
|
2106
2150
|
}
|
|
2107
2151
|
|
|
2108
|
-
if (!
|
|
2152
|
+
if (!validated) {
|
|
2109
2153
|
barLn(red("Invalid license key."));
|
|
2110
2154
|
barLn();
|
|
2111
2155
|
barLn(dim("Get a key at https://moveros.dev"));
|