mover-os 4.7.3 → 4.7.4
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 +42 -11
- package/package.json +1 -1
package/install.js
CHANGED
|
@@ -17,6 +17,18 @@ const { execSync } = require("child_process");
|
|
|
17
17
|
|
|
18
18
|
const VERSION = "4";
|
|
19
19
|
|
|
20
|
+
// ─── Windows path normalization ─────────────────────────────────────────────
|
|
21
|
+
// Git Bash / MSYS / WSL surface paths like "/c/Users/foo" inside terminals
|
|
22
|
+
// that Node treats as drive-less when run from PowerShell or cmd. path.resolve
|
|
23
|
+
// then prepends the *current* drive, producing "C:\c\Users\foo". Convert
|
|
24
|
+
// "/c/Users/foo" → "C:\Users\foo" before any path.join(vaultPath, ...) call.
|
|
25
|
+
function normalizeWinPath(p) {
|
|
26
|
+
if (process.platform !== "win32" || !p) return p;
|
|
27
|
+
const m = p.match(/^\/([a-zA-Z])\/(.*)$/);
|
|
28
|
+
if (m) return `${m[1].toUpperCase()}:\\${m[2].replace(/\//g, "\\")}`;
|
|
29
|
+
return p;
|
|
30
|
+
}
|
|
31
|
+
|
|
20
32
|
// ─── JSON output helper ──────────────────────────────────────────────────────
|
|
21
33
|
function jsonOut(command, data, ok = true) {
|
|
22
34
|
const envelope = {
|
|
@@ -1053,12 +1065,14 @@ function detectChanges(bundleDir, vaultPath, selectedAgentIds) {
|
|
|
1053
1065
|
|
|
1054
1066
|
if (fs.existsSync(wfSrc)) {
|
|
1055
1067
|
for (const file of fs.readdirSync(wfSrc).filter((f) => f.endsWith(".md"))) {
|
|
1056
|
-
const srcContent = fs.readFileSync(path.join(wfSrc, file), "utf8")
|
|
1068
|
+
const srcContent = fs.readFileSync(path.join(wfSrc, file), "utf8")
|
|
1069
|
+
.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
1057
1070
|
const destFile = wfDest && path.join(wfDest, file);
|
|
1058
1071
|
if (!destFile || !fs.existsSync(destFile)) {
|
|
1059
1072
|
result.workflows.push({ file, status: "new" });
|
|
1060
1073
|
} else {
|
|
1061
|
-
const destContent = fs.readFileSync(destFile, "utf8")
|
|
1074
|
+
const destContent = fs.readFileSync(destFile, "utf8")
|
|
1075
|
+
.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
1062
1076
|
result.workflows.push({
|
|
1063
1077
|
file,
|
|
1064
1078
|
status: srcContent === destContent ? "unchanged" : "changed",
|
|
@@ -1097,8 +1111,10 @@ function detectChanges(bundleDir, vaultPath, selectedAgentIds) {
|
|
|
1097
1111
|
].filter(Boolean);
|
|
1098
1112
|
const rulesDest = rulesDests.find((d) => fs.existsSync(d));
|
|
1099
1113
|
if (fs.existsSync(rulesSrc) && rulesDest) {
|
|
1100
|
-
const srcContent = fs.readFileSync(rulesSrc, "utf8")
|
|
1101
|
-
|
|
1114
|
+
const srcContent = fs.readFileSync(rulesSrc, "utf8")
|
|
1115
|
+
.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
1116
|
+
const destContent = fs.readFileSync(rulesDest, "utf8")
|
|
1117
|
+
.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
1102
1118
|
result.rules = srcContent === destContent ? "unchanged" : "changed";
|
|
1103
1119
|
} else {
|
|
1104
1120
|
result.rules = "unchanged";
|
|
@@ -1115,12 +1131,14 @@ function detectChanges(bundleDir, vaultPath, selectedAgentIds) {
|
|
|
1115
1131
|
} else {
|
|
1116
1132
|
const relNorm = entryRel.replace(/\\/g, "/");
|
|
1117
1133
|
if (relNorm.includes("02_Areas") && relNorm.includes("Engine")) continue;
|
|
1118
|
-
const srcContent = fs.readFileSync(path.join(dir, entry.name), "utf8")
|
|
1134
|
+
const srcContent = fs.readFileSync(path.join(dir, entry.name), "utf8")
|
|
1135
|
+
.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
1119
1136
|
const destFile = path.join(vaultPath, entryRel);
|
|
1120
1137
|
if (!fs.existsSync(destFile)) {
|
|
1121
1138
|
result.templates.push({ file: entryRel, status: "new" });
|
|
1122
1139
|
} else {
|
|
1123
|
-
const destContent = fs.readFileSync(destFile, "utf8")
|
|
1140
|
+
const destContent = fs.readFileSync(destFile, "utf8")
|
|
1141
|
+
.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
1124
1142
|
result.templates.push({
|
|
1125
1143
|
file: entryRel,
|
|
1126
1144
|
status: srcContent === destContent ? "unchanged" : "changed",
|
|
@@ -1147,12 +1165,14 @@ function detectChanges(bundleDir, vaultPath, selectedAgentIds) {
|
|
|
1147
1165
|
if (entry.isDirectory()) {
|
|
1148
1166
|
const skillFile = path.join(full, "SKILL.md");
|
|
1149
1167
|
if (fs.existsSync(skillFile)) {
|
|
1150
|
-
const srcContent = fs.readFileSync(skillFile, "utf8")
|
|
1168
|
+
const srcContent = fs.readFileSync(skillFile, "utf8")
|
|
1169
|
+
.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
1151
1170
|
const destSkill = path.join(skillsDest, entry.name, "SKILL.md");
|
|
1152
1171
|
if (!fs.existsSync(destSkill)) {
|
|
1153
1172
|
result.skills.push({ file: entry.name, status: "new" });
|
|
1154
1173
|
} else {
|
|
1155
|
-
const destContent = fs.readFileSync(destSkill, "utf8")
|
|
1174
|
+
const destContent = fs.readFileSync(destSkill, "utf8")
|
|
1175
|
+
.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
1156
1176
|
result.skills.push({ file: entry.name, status: srcContent === destContent ? "unchanged" : "changed" });
|
|
1157
1177
|
}
|
|
1158
1178
|
} else {
|
|
@@ -5280,8 +5300,12 @@ async function cmdUpdateComprehensive(opts, bundleDir, startTime) {
|
|
|
5280
5300
|
}
|
|
5281
5301
|
}
|
|
5282
5302
|
fs.writeFileSync(path.join(vaultPath, ".mover-version"), `${require("./package.json").version}\n`, "utf8");
|
|
5283
|
-
writeMoverConfig(vaultPath, selectedIds);
|
|
5303
|
+
writeMoverConfig(vaultPath, selectedIds, updateKey);
|
|
5284
5304
|
barLn();
|
|
5305
|
+
if (totalChanged > 0) {
|
|
5306
|
+
barLn(dim(" Restart your AI session to load updated rules and skills."));
|
|
5307
|
+
barLn();
|
|
5308
|
+
}
|
|
5285
5309
|
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
5286
5310
|
await successAnimation(`${totalChanged} files updated in ${elapsed}s.`);
|
|
5287
5311
|
return;
|
|
@@ -5610,7 +5634,7 @@ async function cmdUpdateComprehensive(opts, bundleDir, startTime) {
|
|
|
5610
5634
|
}
|
|
5611
5635
|
}
|
|
5612
5636
|
saveUpdateManifest(newManifest);
|
|
5613
|
-
writeMoverConfig(vaultPath, selectedIds);
|
|
5637
|
+
writeMoverConfig(vaultPath, selectedIds, updateKey);
|
|
5614
5638
|
|
|
5615
5639
|
// ── Summary ──
|
|
5616
5640
|
barLn();
|
|
@@ -5630,6 +5654,10 @@ async function cmdUpdateComprehensive(opts, bundleDir, startTime) {
|
|
|
5630
5654
|
}
|
|
5631
5655
|
|
|
5632
5656
|
barLn();
|
|
5657
|
+
if (updated.length > 0 || autoMerged.length > 0) {
|
|
5658
|
+
barLn(dim(" Restart your AI session to load updated rules and skills."));
|
|
5659
|
+
barLn();
|
|
5660
|
+
}
|
|
5633
5661
|
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
5634
5662
|
if (needsUpdate) {
|
|
5635
5663
|
outro(`System updated. Run ${bold("/update")} to resolve ${conflicts.length} conflict${conflicts.length > 1 ? "s" : ""}. ${dim(`(${elapsed}s)`)}`);
|
|
@@ -5643,13 +5671,15 @@ function resolveVaultPath(explicitVault) {
|
|
|
5643
5671
|
if (explicitVault) {
|
|
5644
5672
|
let v = explicitVault;
|
|
5645
5673
|
if (v.startsWith("~")) v = path.join(os.homedir(), v.slice(1));
|
|
5674
|
+
v = normalizeWinPath(v);
|
|
5646
5675
|
return path.resolve(v);
|
|
5647
5676
|
}
|
|
5648
5677
|
// Try config.json
|
|
5649
5678
|
const cfgPath = path.join(os.homedir(), ".mover", "config.json");
|
|
5650
5679
|
if (fs.existsSync(cfgPath)) {
|
|
5651
5680
|
try {
|
|
5652
|
-
|
|
5681
|
+
let v = JSON.parse(fs.readFileSync(cfgPath, "utf8")).vaultPath;
|
|
5682
|
+
v = normalizeWinPath(v);
|
|
5653
5683
|
if (v && fs.existsSync(v)) return v;
|
|
5654
5684
|
} catch {}
|
|
5655
5685
|
}
|
|
@@ -5913,6 +5943,7 @@ async function main() {
|
|
|
5913
5943
|
}
|
|
5914
5944
|
|
|
5915
5945
|
if (vaultPath.startsWith("~")) vaultPath = path.join(os.homedir(), vaultPath.slice(1));
|
|
5946
|
+
vaultPath = normalizeWinPath(vaultPath);
|
|
5916
5947
|
vaultPath = path.resolve(vaultPath);
|
|
5917
5948
|
|
|
5918
5949
|
// ── Fresh install only — redirect if existing ──
|