mover-os 4.5.0 → 4.5.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/install.js +72 -5
- package/package.json +1 -1
package/install.js
CHANGED
|
@@ -954,7 +954,7 @@ function compareVersions(a, b) {
|
|
|
954
954
|
// ─── Change detection (update mode) ─────────────────────────────────────────
|
|
955
955
|
function detectChanges(bundleDir, vaultPath, selectedAgentIds) {
|
|
956
956
|
const home = os.homedir();
|
|
957
|
-
const result = { workflows: [], hooks: [], rules: null, templates: [] };
|
|
957
|
+
const result = { workflows: [], hooks: [], rules: null, templates: [], skills: [], statusline: "unchanged" };
|
|
958
958
|
|
|
959
959
|
// --- Workflows: compare source vs first installed destination ---
|
|
960
960
|
const wfSrc = path.join(bundleDir, "src", "workflows");
|
|
@@ -1046,6 +1046,49 @@ function detectChanges(bundleDir, vaultPath, selectedAgentIds) {
|
|
|
1046
1046
|
walkTemplates(structDir, "");
|
|
1047
1047
|
}
|
|
1048
1048
|
|
|
1049
|
+
// --- Skills: compare source vs installed ---
|
|
1050
|
+
const skillsSrc = path.join(bundleDir, "src", "skills");
|
|
1051
|
+
const skillsDests = [
|
|
1052
|
+
selectedAgentIds.includes("claude-code") && path.join(home, ".claude", "skills"),
|
|
1053
|
+
selectedAgentIds.includes("cursor") && path.join(home, ".cursor", "skills"),
|
|
1054
|
+
selectedAgentIds.includes("cline") && path.join(home, ".cline", "skills"),
|
|
1055
|
+
].filter(Boolean);
|
|
1056
|
+
const skillsDest = skillsDests.find((d) => fs.existsSync(d));
|
|
1057
|
+
if (fs.existsSync(skillsSrc) && skillsDest) {
|
|
1058
|
+
const walkSkills = (dir) => {
|
|
1059
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
1060
|
+
const full = path.join(dir, entry.name);
|
|
1061
|
+
if (entry.isDirectory()) {
|
|
1062
|
+
const skillFile = path.join(full, "SKILL.md");
|
|
1063
|
+
if (fs.existsSync(skillFile)) {
|
|
1064
|
+
const srcContent = fs.readFileSync(skillFile, "utf8");
|
|
1065
|
+
const destSkill = path.join(skillsDest, entry.name, "SKILL.md");
|
|
1066
|
+
if (!fs.existsSync(destSkill)) {
|
|
1067
|
+
result.skills.push({ file: entry.name, status: "new" });
|
|
1068
|
+
} else {
|
|
1069
|
+
const destContent = fs.readFileSync(destSkill, "utf8");
|
|
1070
|
+
result.skills.push({ file: entry.name, status: srcContent === destContent ? "unchanged" : "changed" });
|
|
1071
|
+
}
|
|
1072
|
+
} else {
|
|
1073
|
+
walkSkills(full);
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
};
|
|
1078
|
+
walkSkills(skillsSrc);
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
// --- Statusline ---
|
|
1082
|
+
const slSrc = path.join(bundleDir, "src", "hooks", "statusline.js");
|
|
1083
|
+
const slDest = path.join(home, ".claude", "statusline.js");
|
|
1084
|
+
if (fs.existsSync(slSrc) && fs.existsSync(slDest) && selectedAgentIds.includes("claude-code")) {
|
|
1085
|
+
const srcSl = fs.readFileSync(slSrc, "utf8").replace(/\r\n/g, "\n");
|
|
1086
|
+
const destSl = fs.readFileSync(slDest, "utf8").replace(/\r\n/g, "\n");
|
|
1087
|
+
result.statusline = srcSl === destSl ? "unchanged" : "changed";
|
|
1088
|
+
} else if (fs.existsSync(slSrc) && !fs.existsSync(slDest) && selectedAgentIds.includes("claude-code")) {
|
|
1089
|
+
result.statusline = "new";
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1049
1092
|
return result;
|
|
1050
1093
|
}
|
|
1051
1094
|
|
|
@@ -1055,6 +1098,8 @@ function countChanges(changes) {
|
|
|
1055
1098
|
n += changes.hooks.filter((f) => f.status !== "unchanged").length;
|
|
1056
1099
|
if (changes.rules === "changed") n++;
|
|
1057
1100
|
n += changes.templates.filter((f) => f.status !== "unchanged").length;
|
|
1101
|
+
n += (changes.skills || []).filter((f) => f.status !== "unchanged").length;
|
|
1102
|
+
if (changes.statusline === "changed" || changes.statusline === "new") n++;
|
|
1058
1103
|
return n;
|
|
1059
1104
|
}
|
|
1060
1105
|
|
|
@@ -1102,6 +1147,22 @@ function displayChangeSummary(changes, installedVersion, newVersion) {
|
|
|
1102
1147
|
} else {
|
|
1103
1148
|
barLn(` Templates: ${dim("unchanged")}`);
|
|
1104
1149
|
}
|
|
1150
|
+
|
|
1151
|
+
// Skills
|
|
1152
|
+
const skChanged = (changes.skills || []).filter((f) => f.status === "changed");
|
|
1153
|
+
const skNew = (changes.skills || []).filter((f) => f.status === "new");
|
|
1154
|
+
const skUnchanged = (changes.skills || []).filter((f) => f.status === "unchanged");
|
|
1155
|
+
if (skChanged.length > 0 || skNew.length > 0 || skUnchanged.length > 0) {
|
|
1156
|
+
barLn(` Skills ${dim(`(${skChanged.length + skNew.length} changed, ${skUnchanged.length} unchanged)`)}:`);
|
|
1157
|
+
for (const f of skChanged) barLn(` ${yellow("✦")} ${f.file}`);
|
|
1158
|
+
for (const f of skNew) barLn(` ${green("+")} ${f.file} ${dim("(new)")}`);
|
|
1159
|
+
if (skChanged.length === 0 && skNew.length === 0) barLn(` ${dim("all up to date")}`);
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
// Statusline
|
|
1163
|
+
if (changes.statusline === "changed") barLn(` Statusline: ${yellow("changed")}`);
|
|
1164
|
+
else if (changes.statusline === "new") barLn(` Statusline: ${green("new")}`);
|
|
1165
|
+
|
|
1105
1166
|
barLn();
|
|
1106
1167
|
}
|
|
1107
1168
|
|
|
@@ -4575,17 +4636,22 @@ async function cmdUpdateComprehensive(opts, bundleDir, startTime) {
|
|
|
4575
4636
|
try { updateKey = JSON.parse(fs.readFileSync(cfgPath, "utf8")).licenseKey; } catch {}
|
|
4576
4637
|
}
|
|
4577
4638
|
}
|
|
4639
|
+
const keyFromConfig = !!updateKey;
|
|
4578
4640
|
if (!updateKey) {
|
|
4579
4641
|
updateKey = await textInput({ label: "License key", mask: "\u25AA", placeholder: "MOVER-XXXX-XXXX" });
|
|
4580
4642
|
if (!updateKey) return;
|
|
4581
4643
|
}
|
|
4582
4644
|
const sp1 = spinner("Validating license");
|
|
4583
|
-
|
|
4645
|
+
const keyValid = await validateKey(updateKey);
|
|
4646
|
+
if (!keyValid && keyFromConfig) {
|
|
4647
|
+
sp1.stop(dim("License check skipped (offline — using stored key)"));
|
|
4648
|
+
} else if (!keyValid) {
|
|
4584
4649
|
sp1.stop(red("Invalid key"));
|
|
4585
4650
|
outro(red("Valid license key required."));
|
|
4586
4651
|
process.exit(1);
|
|
4652
|
+
} else {
|
|
4653
|
+
sp1.stop(green("License verified"));
|
|
4587
4654
|
}
|
|
4588
|
-
sp1.stop(green("License verified"));
|
|
4589
4655
|
barLn();
|
|
4590
4656
|
|
|
4591
4657
|
// Download payload if not bundled
|
|
@@ -4715,7 +4781,7 @@ async function cmdUpdateComprehensive(opts, bundleDir, startTime) {
|
|
|
4715
4781
|
if (fs.existsSync(cfgPath)) {
|
|
4716
4782
|
try { currentAgents = JSON.parse(fs.readFileSync(cfgPath, "utf8")).agents || []; } catch {}
|
|
4717
4783
|
}
|
|
4718
|
-
const preSelectedAgents =
|
|
4784
|
+
const preSelectedAgents = [...new Set([...detectedIds, ...currentAgents])];
|
|
4719
4785
|
|
|
4720
4786
|
question(`Agents ${dim("(add or remove)")}`);
|
|
4721
4787
|
barLn();
|
|
@@ -5101,7 +5167,8 @@ async function main() {
|
|
|
5101
5167
|
barLn(dim(" Use " + bold("moveros update") + " to refresh agents, rules, and skills."));
|
|
5102
5168
|
barLn(dim(" Use " + bold("moveros uninstall") + " to remove Mover OS."));
|
|
5103
5169
|
barLn();
|
|
5104
|
-
|
|
5170
|
+
barLn(dim(" esc to exit"));
|
|
5171
|
+
await waitForEsc();
|
|
5105
5172
|
return;
|
|
5106
5173
|
}
|
|
5107
5174
|
|