mover-os 4.4.0 → 4.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/install.js +114 -12
- package/package.json +1 -1
package/install.js
CHANGED
|
@@ -343,7 +343,16 @@ function textInput({ label = "", initial = "", mask = null, placeholder = "" })
|
|
|
343
343
|
value = value.slice(0, pos) + value.slice(pos + 1);
|
|
344
344
|
}
|
|
345
345
|
}
|
|
346
|
-
else if (data
|
|
346
|
+
else if (data === "\x1b") {
|
|
347
|
+
// Escape — cancel input
|
|
348
|
+
stdin.removeListener("data", handler);
|
|
349
|
+
stdin.setRawMode(false);
|
|
350
|
+
stdin.pause();
|
|
351
|
+
ln();
|
|
352
|
+
resolve(null);
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
else if (data.startsWith("\x1b")) { /* ignore other escape sequences */ }
|
|
347
356
|
else {
|
|
348
357
|
for (const ch of data) {
|
|
349
358
|
if (ch.charCodeAt(0) >= 32) {
|
|
@@ -420,8 +429,8 @@ function interactiveSelect(items, { multi = false, preSelected = [], defaultInde
|
|
|
420
429
|
lines++;
|
|
421
430
|
|
|
422
431
|
const hint = multi
|
|
423
|
-
? dim(" ↑↓ navigate space select a all enter confirm")
|
|
424
|
-
: dim(" ↑↓ navigate enter select");
|
|
432
|
+
? dim(" ↑↓ navigate space select a all enter confirm esc back")
|
|
433
|
+
: dim(" ↑↓ navigate enter select esc back");
|
|
425
434
|
w(`\x1b[2K${BAR_COLOR}│${S.reset}${hint}\n`);
|
|
426
435
|
lines++;
|
|
427
436
|
|
|
@@ -467,6 +476,20 @@ function interactiveSelect(items, { multi = false, preSelected = [], defaultInde
|
|
|
467
476
|
}
|
|
468
477
|
return;
|
|
469
478
|
}
|
|
479
|
+
else if (data === "\x1b" || data === "\x1b\x1b" || (!multi && data === "q")) {
|
|
480
|
+
// Escape — go back / cancel
|
|
481
|
+
stdin.removeListener("data", handler);
|
|
482
|
+
stdin.setRawMode(false);
|
|
483
|
+
stdin.pause();
|
|
484
|
+
if (prevLines > 0) {
|
|
485
|
+
w(`\x1b[${prevLines}A`);
|
|
486
|
+
for (let i = 0; i < prevLines; i++) w("\x1b[2K\n");
|
|
487
|
+
w(`\x1b[${prevLines}A`);
|
|
488
|
+
}
|
|
489
|
+
w(S.show);
|
|
490
|
+
resolve(null);
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
470
493
|
else if (data === "\x03") { cleanup(); ln(); process.exit(0); }
|
|
471
494
|
|
|
472
495
|
render();
|
|
@@ -655,6 +678,7 @@ function parseArgs() {
|
|
|
655
678
|
if (a === "--key" && args[i + 1]) { opts.key = args[++i]; continue; }
|
|
656
679
|
// Backward compat: --update / -u → command 'update'
|
|
657
680
|
if (a === "--update" || a === "-u") { opts.command = "update"; continue; }
|
|
681
|
+
if (a === "--_self-updated") { opts._selfUpdated = true; continue; }
|
|
658
682
|
if (a === "--help" || a === "-h") {
|
|
659
683
|
ln();
|
|
660
684
|
ln(` ${bold("moveros")} ${dim("— the Mover OS companion CLI")}`);
|
|
@@ -708,6 +732,17 @@ function detectObsidianVaults() {
|
|
|
708
732
|
}
|
|
709
733
|
}
|
|
710
734
|
|
|
735
|
+
function compareVersions(a, b) {
|
|
736
|
+
const pa = a.split(".").map(Number);
|
|
737
|
+
const pb = b.split(".").map(Number);
|
|
738
|
+
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
739
|
+
const va = pa[i] || 0, vb = pb[i] || 0;
|
|
740
|
+
if (va > vb) return 1;
|
|
741
|
+
if (va < vb) return -1;
|
|
742
|
+
}
|
|
743
|
+
return 0;
|
|
744
|
+
}
|
|
745
|
+
|
|
711
746
|
// ─── Change detection (update mode) ─────────────────────────────────────────
|
|
712
747
|
function detectChanges(bundleDir, vaultPath, selectedAgentIds) {
|
|
713
748
|
const home = os.homedir();
|
|
@@ -2995,8 +3030,10 @@ async function cmdCapture(opts) {
|
|
|
2995
3030
|
{ id: "link", name: "Link", tier: "URL with optional note" },
|
|
2996
3031
|
{ id: "dump", name: "Brain dump", tier: "Free-form text" },
|
|
2997
3032
|
], { multi: false });
|
|
3033
|
+
if (!type) return;
|
|
2998
3034
|
}
|
|
2999
3035
|
content = await textInput({ label: `Enter ${type}:` });
|
|
3036
|
+
if (content === null) return;
|
|
3000
3037
|
}
|
|
3001
3038
|
if (!type) type = "task";
|
|
3002
3039
|
|
|
@@ -3052,6 +3089,7 @@ async function cmdWho(opts) {
|
|
|
3052
3089
|
{ id: "yes", name: "Create stub", tier: `Creates ${name}.md in People/` },
|
|
3053
3090
|
{ id: "no", name: "Skip", tier: "" },
|
|
3054
3091
|
], { multi: false });
|
|
3092
|
+
if (!create) return;
|
|
3055
3093
|
if (create === "yes") {
|
|
3056
3094
|
const peopleDir = path.join(entitiesDir, "People");
|
|
3057
3095
|
fs.mkdirSync(peopleDir, { recursive: true });
|
|
@@ -3503,10 +3541,14 @@ async function cmdPrayer(opts) {
|
|
|
3503
3541
|
barLn();
|
|
3504
3542
|
const choice = await interactiveSelect(items, { multi: false });
|
|
3505
3543
|
|
|
3544
|
+
if (!choice || choice === "back") return;
|
|
3545
|
+
|
|
3506
3546
|
if (choice === "fetch") {
|
|
3507
3547
|
barLn();
|
|
3508
3548
|
const city = await textInput({ label: "City", placeholder: "London" });
|
|
3549
|
+
if (city === null) return;
|
|
3509
3550
|
const country = await textInput({ label: "Country", placeholder: "United Kingdom" });
|
|
3551
|
+
if (country === null) return;
|
|
3510
3552
|
barLn();
|
|
3511
3553
|
|
|
3512
3554
|
if (city && country) {
|
|
@@ -3532,7 +3574,7 @@ async function cmdPrayer(opts) {
|
|
|
3532
3574
|
barLn(dim(" Format examples:"));
|
|
3533
3575
|
barLn(dim(" 2026-03-08 05:20 13:00 16:15 18:01 19:45"));
|
|
3534
3576
|
barLn(dim(" March 8: Fajr 05:20, Dhuhr 13:00, Asr 16:15, Maghrib 18:01, Isha 19:45"));
|
|
3535
|
-
barLn(dim(" Type 'done' on
|
|
3577
|
+
barLn(dim(" Type 'done' or press Enter on empty line to finish. 'back' to cancel."));
|
|
3536
3578
|
barLn();
|
|
3537
3579
|
|
|
3538
3580
|
const lines = [];
|
|
@@ -3540,7 +3582,14 @@ async function cmdPrayer(opts) {
|
|
|
3540
3582
|
await new Promise((resolve) => {
|
|
3541
3583
|
const ask = () => {
|
|
3542
3584
|
rl.question(`${BAR_COLOR}\u2502${S.reset} `, (line) => {
|
|
3543
|
-
|
|
3585
|
+
const t = line.trim().toLowerCase();
|
|
3586
|
+
if (t === "done" || t === "") {
|
|
3587
|
+
rl.close();
|
|
3588
|
+
resolve();
|
|
3589
|
+
return;
|
|
3590
|
+
}
|
|
3591
|
+
if (t === "back" || t === "cancel") {
|
|
3592
|
+
lines.length = 0; // clear
|
|
3544
3593
|
rl.close();
|
|
3545
3594
|
resolve();
|
|
3546
3595
|
return;
|
|
@@ -3649,7 +3698,7 @@ async function cmdBackup(opts) {
|
|
|
3649
3698
|
];
|
|
3650
3699
|
|
|
3651
3700
|
const choices = await interactiveSelect(items, { multi: true, preSelected: ["engine"] });
|
|
3652
|
-
if (choices.length === 0) { barLn(dim(" Cancelled.")); return; }
|
|
3701
|
+
if (!choices || choices.length === 0) { barLn(dim(" Cancelled.")); return; }
|
|
3653
3702
|
|
|
3654
3703
|
const now = new Date();
|
|
3655
3704
|
const ts = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}_${String(now.getHours()).padStart(2, "0")}${String(now.getMinutes()).padStart(2, "0")}`;
|
|
@@ -4215,6 +4264,39 @@ async function main() {
|
|
|
4215
4264
|
process.exit(1);
|
|
4216
4265
|
}
|
|
4217
4266
|
|
|
4267
|
+
// ── CLI self-update check ──
|
|
4268
|
+
if (opts.command === "update" && !opts._selfUpdated) {
|
|
4269
|
+
try {
|
|
4270
|
+
const localVer = require("./package.json").version;
|
|
4271
|
+
const npmVer = execSync("npm view mover-os version", { encoding: "utf8", timeout: 10000 }).trim();
|
|
4272
|
+
if (npmVer && npmVer !== localVer && compareVersions(npmVer, localVer) > 0) {
|
|
4273
|
+
barLn(`${yellow("CLI update available:")} ${dim(localVer)} ${dim("\u2192")} ${green(npmVer)}`);
|
|
4274
|
+
const sp = spinner("Updating CLI");
|
|
4275
|
+
try {
|
|
4276
|
+
execSync("npm i -g mover-os", { stdio: "ignore", timeout: 60000 });
|
|
4277
|
+
sp.stop(`CLI updated to ${npmVer}`);
|
|
4278
|
+
barLn(dim(" Re-running with updated CLI..."));
|
|
4279
|
+
barLn();
|
|
4280
|
+
// Re-exec with new code — pass args through, add flag to prevent loop
|
|
4281
|
+
const args = process.argv.slice(2).concat("--_self-updated");
|
|
4282
|
+
const { spawnSync } = require("child_process");
|
|
4283
|
+
const result = spawnSync(process.argv[0], [process.argv[1], ...args], {
|
|
4284
|
+
stdio: "inherit", cwd: process.cwd(),
|
|
4285
|
+
});
|
|
4286
|
+
process.exit(result.status || 0);
|
|
4287
|
+
} catch (e) {
|
|
4288
|
+
sp.stop(yellow(`CLI self-update failed: ${e.message}`));
|
|
4289
|
+
barLn(dim(" Continuing with current version..."));
|
|
4290
|
+
}
|
|
4291
|
+
} else {
|
|
4292
|
+
barLn(`${green("\u2713")} ${dim("CLI is up to date")} ${dim(`(${localVer})`)}`);
|
|
4293
|
+
}
|
|
4294
|
+
} catch {
|
|
4295
|
+
barLn(dim(" Could not check for CLI updates (offline?)"));
|
|
4296
|
+
}
|
|
4297
|
+
barLn();
|
|
4298
|
+
}
|
|
4299
|
+
|
|
4218
4300
|
// ── Headless quick update ──
|
|
4219
4301
|
if (opts.command === "update") {
|
|
4220
4302
|
// Validate stored key
|
|
@@ -4347,6 +4429,7 @@ async function main() {
|
|
|
4347
4429
|
mask: "\u25AA",
|
|
4348
4430
|
placeholder: "MOVER-XXXX-XXXX",
|
|
4349
4431
|
});
|
|
4432
|
+
if (key === null) return;
|
|
4350
4433
|
|
|
4351
4434
|
const sp = spinner("Validating...");
|
|
4352
4435
|
const valid = await validateKey(key);
|
|
@@ -4433,12 +4516,14 @@ async function main() {
|
|
|
4433
4516
|
});
|
|
4434
4517
|
|
|
4435
4518
|
const selected = await interactiveSelect(vaultItems, { multi: false });
|
|
4519
|
+
if (!selected) return;
|
|
4436
4520
|
|
|
4437
4521
|
if (selected === "__manual__") {
|
|
4438
4522
|
vaultPath = await textInput({
|
|
4439
4523
|
label: "Where is your Obsidian vault?",
|
|
4440
4524
|
initial: path.join(os.homedir(), "Mover-OS"),
|
|
4441
4525
|
});
|
|
4526
|
+
if (vaultPath === null) return;
|
|
4442
4527
|
} else {
|
|
4443
4528
|
vaultPath = selected;
|
|
4444
4529
|
}
|
|
@@ -4447,6 +4532,7 @@ async function main() {
|
|
|
4447
4532
|
label: "Where is your Obsidian vault?",
|
|
4448
4533
|
initial: path.join(os.homedir(), "Mover-OS"),
|
|
4449
4534
|
});
|
|
4535
|
+
if (vaultPath === null) return;
|
|
4450
4536
|
}
|
|
4451
4537
|
} else {
|
|
4452
4538
|
barLn(dim(`Vault: ${vaultPath}`));
|
|
@@ -4483,6 +4569,7 @@ async function main() {
|
|
|
4483
4569
|
],
|
|
4484
4570
|
{ multi: false, defaultIndex: 0 }
|
|
4485
4571
|
);
|
|
4572
|
+
if (!installMode) return;
|
|
4486
4573
|
}
|
|
4487
4574
|
|
|
4488
4575
|
// ── Uninstall flow ──
|
|
@@ -4522,7 +4609,7 @@ async function main() {
|
|
|
4522
4609
|
preSelected: ["engine"],
|
|
4523
4610
|
});
|
|
4524
4611
|
|
|
4525
|
-
if (backupChoices.length > 0 && !(backupChoices.length === 1 && backupChoices.includes("skip"))) {
|
|
4612
|
+
if (backupChoices && backupChoices.length > 0 && !(backupChoices.length === 1 && backupChoices.includes("skip"))) {
|
|
4526
4613
|
const now = new Date();
|
|
4527
4614
|
const ts = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}_${String(now.getHours()).padStart(2, "0")}${String(now.getMinutes()).padStart(2, "0")}`;
|
|
4528
4615
|
const archivesDir = path.join(vaultPath, "04_Archives");
|
|
@@ -4685,12 +4772,13 @@ async function main() {
|
|
|
4685
4772
|
multi: true,
|
|
4686
4773
|
preSelected: detectedIds,
|
|
4687
4774
|
});
|
|
4775
|
+
if (!selectedIds) return;
|
|
4688
4776
|
const selectedAgents = AGENTS.filter((a) => selectedIds.includes(a.id));
|
|
4689
4777
|
|
|
4690
4778
|
if (selectedAgents.length === 0) {
|
|
4691
4779
|
barLn(yellow("No agents selected."));
|
|
4692
4780
|
outro("Cancelled.");
|
|
4693
|
-
|
|
4781
|
+
return;
|
|
4694
4782
|
}
|
|
4695
4783
|
|
|
4696
4784
|
// ── Change detection + selection (update mode only) ──
|
|
@@ -4735,9 +4823,9 @@ async function main() {
|
|
|
4735
4823
|
{ multi: false, defaultIndex: 0 }
|
|
4736
4824
|
);
|
|
4737
4825
|
|
|
4738
|
-
if (applyChoice === "cancel") {
|
|
4826
|
+
if (!applyChoice || applyChoice === "cancel") {
|
|
4739
4827
|
outro("Cancelled.");
|
|
4740
|
-
|
|
4828
|
+
return;
|
|
4741
4829
|
}
|
|
4742
4830
|
|
|
4743
4831
|
if (applyChoice === "select") {
|
|
@@ -4771,6 +4859,7 @@ async function main() {
|
|
|
4771
4859
|
multi: true,
|
|
4772
4860
|
preSelected: changedPreSelected,
|
|
4773
4861
|
});
|
|
4862
|
+
if (!selectedFileIds) return;
|
|
4774
4863
|
|
|
4775
4864
|
// Build workflow filter Set
|
|
4776
4865
|
const selectedWfFiles = selectedFileIds
|
|
@@ -4817,6 +4906,7 @@ async function main() {
|
|
|
4817
4906
|
multi: true,
|
|
4818
4907
|
preSelected,
|
|
4819
4908
|
});
|
|
4909
|
+
if (!selectedCatIds) return;
|
|
4820
4910
|
|
|
4821
4911
|
installSkills = selectedCatIds.length > 0;
|
|
4822
4912
|
if (installSkills) {
|
|
@@ -4843,6 +4933,7 @@ async function main() {
|
|
|
4843
4933
|
],
|
|
4844
4934
|
{ multi: false, defaultIndex: 0 }
|
|
4845
4935
|
);
|
|
4936
|
+
if (!slChoice) return;
|
|
4846
4937
|
installStatusLine = slChoice === "yes";
|
|
4847
4938
|
}
|
|
4848
4939
|
|
|
@@ -4862,6 +4953,7 @@ async function main() {
|
|
|
4862
4953
|
],
|
|
4863
4954
|
{ multi: false, defaultIndex: 1 }
|
|
4864
4955
|
);
|
|
4956
|
+
if (!ptChoice) return;
|
|
4865
4957
|
if (ptChoice === "yes") {
|
|
4866
4958
|
prayerSetup = true;
|
|
4867
4959
|
barLn();
|
|
@@ -4876,6 +4968,7 @@ async function main() {
|
|
|
4876
4968
|
],
|
|
4877
4969
|
{ multi: false, defaultIndex: 0 }
|
|
4878
4970
|
);
|
|
4971
|
+
if (!method || method === "later") { /* skip */ }
|
|
4879
4972
|
|
|
4880
4973
|
const moverDir = path.join(os.homedir(), ".mover");
|
|
4881
4974
|
if (!fs.existsSync(moverDir)) fs.mkdirSync(moverDir, { recursive: true, mode: 0o700 });
|
|
@@ -4887,7 +4980,7 @@ async function main() {
|
|
|
4887
4980
|
barLn(dim(" 2026-03-08 05:20 13:00 16:15 18:01 19:45"));
|
|
4888
4981
|
barLn(dim(" March 8: Fajr 05:20, Dhuhr 13:00, Asr 16:15, Maghrib 18:01, Isha 19:45"));
|
|
4889
4982
|
barLn(dim(" Or paste a whole table — the system will parse it."));
|
|
4890
|
-
barLn(dim("
|
|
4983
|
+
barLn(dim(" Type 'done' or press Enter on empty line to finish. 'back' to cancel."));
|
|
4891
4984
|
barLn();
|
|
4892
4985
|
|
|
4893
4986
|
const lines = [];
|
|
@@ -4895,7 +4988,14 @@ async function main() {
|
|
|
4895
4988
|
await new Promise((resolve) => {
|
|
4896
4989
|
const ask = () => {
|
|
4897
4990
|
rl.question(`${BAR_COLOR}\u2502${S.reset} `, (line) => {
|
|
4898
|
-
|
|
4991
|
+
const t = line.trim().toLowerCase();
|
|
4992
|
+
if (t === "done" || t === "") {
|
|
4993
|
+
rl.close();
|
|
4994
|
+
resolve();
|
|
4995
|
+
return;
|
|
4996
|
+
}
|
|
4997
|
+
if (t === "back" || t === "cancel") {
|
|
4998
|
+
lines.length = 0;
|
|
4899
4999
|
rl.close();
|
|
4900
5000
|
resolve();
|
|
4901
5001
|
return;
|
|
@@ -4920,7 +5020,9 @@ async function main() {
|
|
|
4920
5020
|
} else if (method === "fetch") {
|
|
4921
5021
|
barLn();
|
|
4922
5022
|
const city = await textInput({ label: "City (e.g. London, Watford, Istanbul)", placeholder: "London" });
|
|
5023
|
+
if (city === null) break;
|
|
4923
5024
|
const country = await textInput({ label: "Country", placeholder: "United Kingdom" });
|
|
5025
|
+
if (country === null) break;
|
|
4924
5026
|
barLn();
|
|
4925
5027
|
|
|
4926
5028
|
if (city && country) {
|