mover-os 4.5.2 → 4.5.3
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 +149 -64
- package/package.json +1 -1
package/install.js
CHANGED
|
@@ -92,17 +92,10 @@ function waveGradient(text, frame, totalFrames) {
|
|
|
92
92
|
// ─── TUI: Alternate screen buffer ────────────────────────────────────────────
|
|
93
93
|
let _inAltScreen = false;
|
|
94
94
|
function enterAltScreen() {
|
|
95
|
-
|
|
96
|
-
w("\x1b[?1049h"); // Enter alternate screen
|
|
97
|
-
w("\x1b[2J\x1b[H"); // Clear + cursor home
|
|
98
|
-
w(S.hide);
|
|
99
|
-
_inAltScreen = true;
|
|
95
|
+
// Disabled: keep output in terminal scrollback history
|
|
100
96
|
}
|
|
101
97
|
function exitAltScreen() {
|
|
102
|
-
|
|
103
|
-
w("\x1b[?1049l"); // Restore original screen
|
|
104
|
-
w(S.show);
|
|
105
|
-
_inAltScreen = false;
|
|
98
|
+
// Disabled: no alt screen to exit
|
|
106
99
|
}
|
|
107
100
|
function clearContent() {
|
|
108
101
|
w("\x1b[2J\x1b[H"); // Clear screen + cursor to top
|
|
@@ -956,12 +949,15 @@ function detectChanges(bundleDir, vaultPath, selectedAgentIds) {
|
|
|
956
949
|
const home = os.homedir();
|
|
957
950
|
const result = { workflows: [], hooks: [], rules: null, templates: [], skills: [], statusline: "unchanged" };
|
|
958
951
|
|
|
952
|
+
// Expand selection IDs to target IDs (e.g. "gemini-cli" → includes "antigravity")
|
|
953
|
+
const targetIds = expandTargetIds(selectedAgentIds);
|
|
954
|
+
|
|
959
955
|
// --- Workflows: compare source vs first installed destination ---
|
|
960
956
|
const wfSrc = path.join(bundleDir, "src", "workflows");
|
|
961
957
|
const wfDests = [
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
958
|
+
targetIds.includes("claude-code") && path.join(home, ".claude", "commands"),
|
|
959
|
+
targetIds.includes("cursor") && path.join(home, ".cursor", "commands"),
|
|
960
|
+
targetIds.includes("antigravity") && path.join(home, ".gemini", "antigravity", "global_workflows"),
|
|
965
961
|
].filter(Boolean);
|
|
966
962
|
const wfDest = wfDests.find((d) => fs.existsSync(d));
|
|
967
963
|
|
|
@@ -984,7 +980,7 @@ function detectChanges(bundleDir, vaultPath, selectedAgentIds) {
|
|
|
984
980
|
// --- Hooks: compare with CRLF normalization ---
|
|
985
981
|
const hooksSrc = path.join(bundleDir, "src", "hooks");
|
|
986
982
|
const hooksDest = path.join(home, ".claude", "hooks");
|
|
987
|
-
if (fs.existsSync(hooksSrc) &&
|
|
983
|
+
if (fs.existsSync(hooksSrc) && targetIds.includes("claude-code")) {
|
|
988
984
|
for (const file of fs.readdirSync(hooksSrc).filter((f) => f.endsWith(".sh") || f.endsWith(".md"))) {
|
|
989
985
|
const srcContent = fs.readFileSync(path.join(hooksSrc, file), "utf8")
|
|
990
986
|
.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
@@ -1005,9 +1001,9 @@ function detectChanges(bundleDir, vaultPath, selectedAgentIds) {
|
|
|
1005
1001
|
// --- Rules: compare source vs first installed destination ---
|
|
1006
1002
|
const rulesSrc = path.join(bundleDir, "src", "system", "Mover_Global_Rules.md");
|
|
1007
1003
|
const rulesDests = [
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1004
|
+
targetIds.includes("claude-code") && path.join(home, ".claude", "CLAUDE.md"),
|
|
1005
|
+
targetIds.includes("cursor") && path.join(home, ".cursor", "rules", "mover-os.mdc"),
|
|
1006
|
+
targetIds.includes("gemini-cli") && path.join(home, ".gemini", "GEMINI.md"),
|
|
1011
1007
|
].filter(Boolean);
|
|
1012
1008
|
const rulesDest = rulesDests.find((d) => fs.existsSync(d));
|
|
1013
1009
|
if (fs.existsSync(rulesSrc) && rulesDest) {
|
|
@@ -1049,9 +1045,9 @@ function detectChanges(bundleDir, vaultPath, selectedAgentIds) {
|
|
|
1049
1045
|
// --- Skills: compare source vs installed ---
|
|
1050
1046
|
const skillsSrc = path.join(bundleDir, "src", "skills");
|
|
1051
1047
|
const skillsDests = [
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1048
|
+
targetIds.includes("claude-code") && path.join(home, ".claude", "skills"),
|
|
1049
|
+
targetIds.includes("cursor") && path.join(home, ".cursor", "skills"),
|
|
1050
|
+
targetIds.includes("cline") && path.join(home, ".cline", "skills"),
|
|
1055
1051
|
].filter(Boolean);
|
|
1056
1052
|
const skillsDest = skillsDests.find((d) => fs.existsSync(d));
|
|
1057
1053
|
if (fs.existsSync(skillsSrc) && skillsDest) {
|
|
@@ -1081,11 +1077,11 @@ function detectChanges(bundleDir, vaultPath, selectedAgentIds) {
|
|
|
1081
1077
|
// --- Statusline ---
|
|
1082
1078
|
const slSrc = path.join(bundleDir, "src", "hooks", "statusline.js");
|
|
1083
1079
|
const slDest = path.join(home, ".claude", "statusline.js");
|
|
1084
|
-
if (fs.existsSync(slSrc) && fs.existsSync(slDest) &&
|
|
1080
|
+
if (fs.existsSync(slSrc) && fs.existsSync(slDest) && targetIds.includes("claude-code")) {
|
|
1085
1081
|
const srcSl = fs.readFileSync(slSrc, "utf8").replace(/\r\n/g, "\n");
|
|
1086
1082
|
const destSl = fs.readFileSync(slDest, "utf8").replace(/\r\n/g, "\n");
|
|
1087
1083
|
result.statusline = srcSl === destSl ? "unchanged" : "changed";
|
|
1088
|
-
} else if (fs.existsSync(slSrc) && !fs.existsSync(slDest) &&
|
|
1084
|
+
} else if (fs.existsSync(slSrc) && !fs.existsSync(slDest) && targetIds.includes("claude-code")) {
|
|
1089
1085
|
result.statusline = "new";
|
|
1090
1086
|
}
|
|
1091
1087
|
|
|
@@ -1627,6 +1623,17 @@ const AGENTS = AGENT_SELECTIONS.map((s) => ({
|
|
|
1627
1623
|
detect: AGENT_REGISTRY[s.targets[0]].detect,
|
|
1628
1624
|
}));
|
|
1629
1625
|
|
|
1626
|
+
// Expand selection IDs to install target IDs (e.g. "gemini-cli" → ["gemini-cli", "antigravity"])
|
|
1627
|
+
function expandTargetIds(selectionIds) {
|
|
1628
|
+
const result = [];
|
|
1629
|
+
for (const id of selectionIds) {
|
|
1630
|
+
const sel = AGENT_SELECTIONS.find((s) => s.id === id);
|
|
1631
|
+
if (sel) { for (const t of sel.targets) result.push(t); }
|
|
1632
|
+
else result.push(id);
|
|
1633
|
+
}
|
|
1634
|
+
return [...new Set(result)];
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1630
1637
|
// ─── Utility functions ──────────────────────────────────────────────────────
|
|
1631
1638
|
function cmdExists(cmd) {
|
|
1632
1639
|
try {
|
|
@@ -2113,6 +2120,8 @@ function writeMoverConfig(vaultPath, agentIds, licenseKey, opts = {}) {
|
|
|
2113
2120
|
if (existing.settings) config.settings = { ...existing.settings };
|
|
2114
2121
|
// Preserve prayer_times fallback
|
|
2115
2122
|
if (existing.prayer_times) config.prayer_times = existing.prayer_times;
|
|
2123
|
+
// Preserve frecency data
|
|
2124
|
+
if (existing.cli_usage) config.cli_usage = existing.cli_usage;
|
|
2116
2125
|
config.updatedAt = new Date().toISOString();
|
|
2117
2126
|
} catch {}
|
|
2118
2127
|
}
|
|
@@ -3031,7 +3040,8 @@ async function cmdDoctor(opts) {
|
|
|
3031
3040
|
// Per-agent checks
|
|
3032
3041
|
barLn();
|
|
3033
3042
|
barLn(dim(" Agents:"));
|
|
3034
|
-
|
|
3043
|
+
let cfgData = {};
|
|
3044
|
+
if (fs.existsSync(cfg)) { try { cfgData = JSON.parse(fs.readFileSync(cfg, "utf8")); } catch { statusLine("warn", "Config", "corrupt JSON"); } }
|
|
3035
3045
|
const installedAgents = cfgData.agents || [];
|
|
3036
3046
|
if (installedAgents.length === 0) {
|
|
3037
3047
|
barLn(dim(" No agents recorded in config."));
|
|
@@ -3057,7 +3067,7 @@ async function cmdDoctor(opts) {
|
|
|
3057
3067
|
const hasCmds = fs.existsSync(cp) && fs.readdirSync(cp).length > 0;
|
|
3058
3068
|
checks.push(hasCmds ? "commands" : dim("no commands"));
|
|
3059
3069
|
}
|
|
3060
|
-
const allOk = checks.every((c) =>
|
|
3070
|
+
const allOk = checks.every((c) => c === strip(c)); // styled text = problem
|
|
3061
3071
|
statusLine(allOk ? "ok" : "warn", ` ${reg.name}`, checks.join(", "));
|
|
3062
3072
|
}
|
|
3063
3073
|
|
|
@@ -3102,7 +3112,7 @@ async function cmdPulse(opts) {
|
|
|
3102
3112
|
const focusMatch = ac.match(/\*\*Focus:\*\*\s*(.+)/i) || ac.match(/Single Test:\s*(.+)/i);
|
|
3103
3113
|
if (focusMatch) focus = focusMatch[1].trim();
|
|
3104
3114
|
// Blockers
|
|
3105
|
-
const blockerSection = ac.match(/##.*Blocker[s]?[\s\S]*?(?=\n##|\n
|
|
3115
|
+
const blockerSection = ac.match(/##.*Blocker[s]?[\s\S]*?(?=\n##|\n---|$)/i);
|
|
3106
3116
|
if (blockerSection) {
|
|
3107
3117
|
const lines = blockerSection[0].split("\n").filter((l) => l.trim().startsWith("-") || l.trim().startsWith("*"));
|
|
3108
3118
|
blockers = lines.map((l) => l.replace(/^[\s*-]+/, "").trim()).filter(Boolean).slice(0, 3);
|
|
@@ -3491,7 +3501,7 @@ async function cmdReplay(opts) {
|
|
|
3491
3501
|
const daily = fs.readFileSync(dailyPath, "utf8");
|
|
3492
3502
|
|
|
3493
3503
|
// Extract session log entries
|
|
3494
|
-
const logMatch = daily.match(/##\s*Session Log[\s\S]*?(?=\n## [^#]
|
|
3504
|
+
const logMatch = daily.match(/##\s*Session Log[\s\S]*?(?=\n## [^#]|$)/i);
|
|
3495
3505
|
if (!logMatch) {
|
|
3496
3506
|
barLn(dim(" No session log found in this Daily Note."));
|
|
3497
3507
|
return;
|
|
@@ -4046,10 +4056,11 @@ async function cmdRestore(opts) {
|
|
|
4046
4056
|
const archivesDir = path.join(vault, "04_Archives");
|
|
4047
4057
|
if (!fs.existsSync(archivesDir)) { barLn(yellow(" No archives found.")); return; }
|
|
4048
4058
|
|
|
4059
|
+
const backupPrefixes = ["Backup_", "Engine_Backup_", "Areas_Backup_", "Agent_Backup_"];
|
|
4049
4060
|
const backups = fs.readdirSync(archivesDir)
|
|
4050
4061
|
.filter((d) => {
|
|
4051
4062
|
const full = path.join(archivesDir, d);
|
|
4052
|
-
return fs.statSync(full).isDirectory() &&
|
|
4063
|
+
return fs.statSync(full).isDirectory() && backupPrefixes.some((p) => d.startsWith(p));
|
|
4053
4064
|
})
|
|
4054
4065
|
.sort()
|
|
4055
4066
|
.reverse();
|
|
@@ -4077,25 +4088,67 @@ async function cmdRestore(opts) {
|
|
|
4077
4088
|
|
|
4078
4089
|
const backupPath = path.join(archivesDir, selected);
|
|
4079
4090
|
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
if (
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4091
|
+
let totalRestored = 0;
|
|
4092
|
+
|
|
4093
|
+
if (selected.startsWith("Areas_Backup_")) {
|
|
4094
|
+
// Areas backup: restore entire 02_Areas folder
|
|
4095
|
+
const areasTarget = path.join(vault, "02_Areas");
|
|
4096
|
+
copyDirRecursive(backupPath, areasTarget);
|
|
4097
|
+
statusLine("ok", "Areas", "folder restored");
|
|
4098
|
+
totalRestored++;
|
|
4099
|
+
} else if (selected.startsWith("Agent_Backup_")) {
|
|
4100
|
+
// Agent backup: restore rules/skills per agent
|
|
4101
|
+
let agentCount = 0;
|
|
4102
|
+
for (const agDir of fs.readdirSync(backupPath).filter((d) => fs.statSync(path.join(backupPath, d)).isDirectory())) {
|
|
4103
|
+
const reg = AGENT_REGISTRY[agDir];
|
|
4104
|
+
if (!reg) continue;
|
|
4105
|
+
const srcDir = path.join(backupPath, agDir);
|
|
4106
|
+
// Restore rules file
|
|
4107
|
+
if (reg.rules && reg.rules.dest) {
|
|
4108
|
+
const rulesFile = fs.readdirSync(srcDir).find((f) => !f.startsWith("skills") && fs.statSync(path.join(srcDir, f)).isFile());
|
|
4109
|
+
if (rulesFile) {
|
|
4110
|
+
try {
|
|
4111
|
+
const dest = reg.rules.dest(vault);
|
|
4112
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
4113
|
+
fs.copyFileSync(path.join(srcDir, rulesFile), dest);
|
|
4114
|
+
agentCount++;
|
|
4115
|
+
} catch {}
|
|
4116
|
+
}
|
|
4117
|
+
}
|
|
4118
|
+
// Restore skills directory
|
|
4119
|
+
const skillsSrc = path.join(srcDir, "skills");
|
|
4120
|
+
if (fs.existsSync(skillsSrc) && reg.skills && reg.skills.dest) {
|
|
4121
|
+
try {
|
|
4122
|
+
copyDirRecursive(skillsSrc, reg.skills.dest(vault));
|
|
4123
|
+
agentCount++;
|
|
4124
|
+
} catch {}
|
|
4125
|
+
}
|
|
4088
4126
|
}
|
|
4089
|
-
statusLine("ok", "
|
|
4127
|
+
statusLine("ok", "Agents", `${agentCount} items restored`);
|
|
4128
|
+
totalRestored = agentCount;
|
|
4090
4129
|
} else {
|
|
4091
|
-
//
|
|
4092
|
-
const
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4130
|
+
// Engine backup (Engine_Backup_ or legacy Backup_)
|
|
4131
|
+
const engPath = path.join(backupPath, "engine");
|
|
4132
|
+
if (fs.existsSync(engPath)) {
|
|
4133
|
+
const engineDir = path.join(vault, "02_Areas", "Engine");
|
|
4134
|
+
let restored = 0;
|
|
4135
|
+
for (const f of fs.readdirSync(engPath).filter((f) => fs.statSync(path.join(engPath, f)).isFile())) {
|
|
4136
|
+
fs.copyFileSync(path.join(engPath, f), path.join(engineDir, f));
|
|
4137
|
+
restored++;
|
|
4138
|
+
}
|
|
4139
|
+
statusLine("ok", "Engine", `${restored} files restored`);
|
|
4140
|
+
totalRestored = restored;
|
|
4141
|
+
} else {
|
|
4142
|
+
// Legacy backup format (files directly in backup dir)
|
|
4143
|
+
const engineDir = path.join(vault, "02_Areas", "Engine");
|
|
4144
|
+
let restored = 0;
|
|
4145
|
+
for (const f of fs.readdirSync(backupPath).filter((f) => f.endsWith(".md") && f !== ".backup-manifest.json")) {
|
|
4146
|
+
fs.copyFileSync(path.join(backupPath, f), path.join(engineDir, f));
|
|
4147
|
+
restored++;
|
|
4148
|
+
}
|
|
4149
|
+
if (restored > 0) statusLine("ok", "Engine", `${restored} files restored`);
|
|
4150
|
+
totalRestored = restored;
|
|
4097
4151
|
}
|
|
4098
|
-
if (restored > 0) statusLine("ok", "Engine", `${restored} files restored`);
|
|
4099
4152
|
}
|
|
4100
4153
|
|
|
4101
4154
|
barLn();
|
|
@@ -4692,14 +4745,20 @@ async function cmdUpdateComprehensive(opts, bundleDir, startTime) {
|
|
|
4692
4745
|
createVaultStructure(vaultPath);
|
|
4693
4746
|
installTemplateFiles(bundleDir, vaultPath);
|
|
4694
4747
|
const writtenFiles = new Set();
|
|
4695
|
-
const skillOpts = { install: true, categories: null, workflows: null };
|
|
4748
|
+
const skillOpts = { install: true, categories: null, workflows: null, statusLine: changes.statusline !== "unchanged" };
|
|
4696
4749
|
for (const agent of detectedAgents) {
|
|
4697
|
-
const
|
|
4698
|
-
|
|
4699
|
-
const
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
4750
|
+
const sel = AGENT_SELECTIONS.find((s) => s.id === agent.id);
|
|
4751
|
+
const targets = sel ? sel.targets : [agent.id];
|
|
4752
|
+
for (const targetId of targets) {
|
|
4753
|
+
const fn = AGENT_INSTALLERS[targetId];
|
|
4754
|
+
if (!fn) continue;
|
|
4755
|
+
const targetReg = AGENT_REGISTRY[targetId];
|
|
4756
|
+
const displayName = targetReg ? targetReg.name : agent.name;
|
|
4757
|
+
const sp = spinner(displayName);
|
|
4758
|
+
const steps = fn(bundleDir, vaultPath, skillOpts, writtenFiles, targetId);
|
|
4759
|
+
await sleep(200);
|
|
4760
|
+
sp.stop(steps.length > 0 ? `${displayName} ${dim(steps.join(", "))}` : `${displayName} ${dim("configured")}`);
|
|
4761
|
+
}
|
|
4703
4762
|
}
|
|
4704
4763
|
fs.writeFileSync(path.join(vaultPath, ".mover-version"), `${require("./package.json").version}\n`, "utf8");
|
|
4705
4764
|
writeMoverConfig(vaultPath, selectedIds);
|
|
@@ -4758,15 +4817,36 @@ async function cmdUpdateComprehensive(opts, bundleDir, startTime) {
|
|
|
4758
4817
|
fs.mkdirSync(agentBackupDir, { recursive: true });
|
|
4759
4818
|
let agentsBacked = 0;
|
|
4760
4819
|
for (const ag of AGENTS.filter((a) => a.detect())) {
|
|
4761
|
-
const
|
|
4762
|
-
|
|
4763
|
-
for (const
|
|
4764
|
-
|
|
4765
|
-
|
|
4820
|
+
const sel = AGENT_SELECTIONS.find((s) => s.id === ag.id);
|
|
4821
|
+
const targets = sel ? sel.targets : [ag.id];
|
|
4822
|
+
for (const targetId of targets) {
|
|
4823
|
+
const reg = AGENT_REGISTRY[targetId];
|
|
4824
|
+
if (!reg) continue;
|
|
4825
|
+
const agDir = path.join(agentBackupDir, targetId);
|
|
4826
|
+
fs.mkdirSync(agDir, { recursive: true });
|
|
4827
|
+
// Back up rules file
|
|
4828
|
+
if (reg.rules && reg.rules.dest) {
|
|
4829
|
+
try {
|
|
4830
|
+
const rulesPath = reg.rules.dest(vaultPath);
|
|
4831
|
+
if (fs.existsSync(rulesPath)) {
|
|
4832
|
+
fs.copyFileSync(rulesPath, path.join(agDir, path.basename(rulesPath)));
|
|
4833
|
+
agentsBacked++;
|
|
4834
|
+
}
|
|
4835
|
+
} catch {}
|
|
4836
|
+
}
|
|
4837
|
+
// Back up skills directory
|
|
4838
|
+
if (reg.skills && reg.skills.dest) {
|
|
4839
|
+
try {
|
|
4840
|
+
const skillsDir = reg.skills.dest(vaultPath);
|
|
4841
|
+
if (fs.existsSync(skillsDir)) {
|
|
4842
|
+
copyDirRecursive(skillsDir, path.join(agDir, "skills"));
|
|
4843
|
+
agentsBacked++;
|
|
4844
|
+
}
|
|
4845
|
+
} catch {}
|
|
4766
4846
|
}
|
|
4767
4847
|
}
|
|
4768
4848
|
}
|
|
4769
|
-
statusLine("ok", "Backed up", `${agentsBacked} agent config
|
|
4849
|
+
statusLine("ok", "Backed up", `${agentsBacked} agent config items`);
|
|
4770
4850
|
} catch (err) { barLn(yellow(` Agent backup failed: ${err.message}`)); }
|
|
4771
4851
|
}
|
|
4772
4852
|
}
|
|
@@ -4867,7 +4947,7 @@ async function cmdUpdateComprehensive(opts, bundleDir, startTime) {
|
|
|
4867
4947
|
}
|
|
4868
4948
|
|
|
4869
4949
|
const writtenFiles = new Set();
|
|
4870
|
-
const skillOpts = { install: true, categories: null, workflows: selectedWorkflows, skipHooks, skipRules, skipTemplates };
|
|
4950
|
+
const skillOpts = { install: true, categories: null, workflows: selectedWorkflows, skipHooks, skipRules, skipTemplates, statusLine: changes.statusline !== "unchanged" };
|
|
4871
4951
|
for (const agent of selectedAgents) {
|
|
4872
4952
|
const sel = AGENT_SELECTIONS.find((s) => s.id === agent.id);
|
|
4873
4953
|
const targets = sel ? sel.targets : [agent.id];
|
|
@@ -4900,8 +4980,12 @@ async function cmdUpdateComprehensive(opts, bundleDir, startTime) {
|
|
|
4900
4980
|
const catSet = new Set(selectedCatIds);
|
|
4901
4981
|
const refreshOpts = { install: true, categories: catSet, workflows: null };
|
|
4902
4982
|
for (const agent of selectedAgents) {
|
|
4903
|
-
const
|
|
4904
|
-
|
|
4983
|
+
const sel = AGENT_SELECTIONS.find((s) => s.id === agent.id);
|
|
4984
|
+
const targets = sel ? sel.targets : [agent.id];
|
|
4985
|
+
for (const targetId of targets) {
|
|
4986
|
+
const fn = AGENT_INSTALLERS[targetId];
|
|
4987
|
+
if (fn) fn(bundleDir, vaultPath, refreshOpts, writtenFiles, targetId);
|
|
4988
|
+
}
|
|
4905
4989
|
}
|
|
4906
4990
|
const skillCount = allSkills.filter((s) => s.category === "tools" || catSet.has(s.category)).length;
|
|
4907
4991
|
statusLine("ok", "Skills refreshed", `${skillCount} across ${selectedAgents.length} agent(s)`);
|
|
@@ -5284,8 +5368,8 @@ async function main() {
|
|
|
5284
5368
|
],
|
|
5285
5369
|
{ multi: false, defaultIndex: 1 }
|
|
5286
5370
|
);
|
|
5287
|
-
if (!ptChoice)
|
|
5288
|
-
if (ptChoice === "yes") {
|
|
5371
|
+
if (!ptChoice || ptChoice === "no") { /* skip prayer setup */ }
|
|
5372
|
+
else if (ptChoice === "yes") {
|
|
5289
5373
|
prayerSetup = true;
|
|
5290
5374
|
barLn();
|
|
5291
5375
|
question("How would you like to set up prayer times?");
|
|
@@ -5299,7 +5383,9 @@ async function main() {
|
|
|
5299
5383
|
],
|
|
5300
5384
|
{ multi: false, defaultIndex: 0 }
|
|
5301
5385
|
);
|
|
5302
|
-
if (!method || method === "later") {
|
|
5386
|
+
if (!method || method === "later") {
|
|
5387
|
+
// User cancelled method pick — still enable the setting, no timetable
|
|
5388
|
+
} else {
|
|
5303
5389
|
|
|
5304
5390
|
const moverDir = path.join(os.homedir(), ".mover");
|
|
5305
5391
|
if (!fs.existsSync(moverDir)) fs.mkdirSync(moverDir, { recursive: true, mode: 0o700 });
|
|
@@ -5351,9 +5437,7 @@ async function main() {
|
|
|
5351
5437
|
} else if (method === "fetch") {
|
|
5352
5438
|
barLn();
|
|
5353
5439
|
const city = await textInput({ label: "City (e.g. London, Watford, Istanbul)", placeholder: "London" });
|
|
5354
|
-
|
|
5355
|
-
const country = await textInput({ label: "Country", placeholder: "United Kingdom" });
|
|
5356
|
-
if (country === null) return;
|
|
5440
|
+
const country = city ? await textInput({ label: "Country", placeholder: "United Kingdom" }) : null;
|
|
5357
5441
|
barLn();
|
|
5358
5442
|
|
|
5359
5443
|
if (city && country) {
|
|
@@ -5371,6 +5455,7 @@ async function main() {
|
|
|
5371
5455
|
}
|
|
5372
5456
|
}
|
|
5373
5457
|
// method === "later" → just enable the setting, no timetable yet
|
|
5458
|
+
} // end if method !== "later"
|
|
5374
5459
|
}
|
|
5375
5460
|
}
|
|
5376
5461
|
|