diff --git a/lib/config.js b/lib/config.js index 2785644..58b51c9 100644 --- a/lib/config.js +++ b/lib/config.js @@ -170,12 +170,86 @@ function ensureConfigDir() { } } // external-triggers/ - if (fs.existsSync(OLD_EXTERNAL_TRIGGERS_DIR) && !fs.existsSync(EXTERNAL_TRIGGERS_DIR)) { - try { - fs.cpSync(OLD_EXTERNAL_TRIGGERS_DIR, EXTERNAL_TRIGGERS_DIR, { recursive: true }); - console.warn("[config] Migrated external-triggers/ → " + EXTERNAL_TRIGGERS_DIR); - } catch (e) { - console.error("[config] Migration of external-triggers/ failed (non-fatal):", e.message); + // Use lstatSync (not existsSync) so a pre-existing symlink at the old path is + // detected and skipped — we only act on a real directory. + var _oldTriggersIsRealDir = false; + try { + var _oldStat = fs.lstatSync(OLD_EXTERNAL_TRIGGERS_DIR); + _oldTriggersIsRealDir = _oldStat.isDirectory() && !_oldStat.isSymbolicLink(); + } catch (_) {} + if (_oldTriggersIsRealDir) { + if (!fs.existsSync(EXTERNAL_TRIGGERS_DIR)) { + // Case 1: new dir absent — simple copy (existing behavior). + try { + fs.cpSync(OLD_EXTERNAL_TRIGGERS_DIR, EXTERNAL_TRIGGERS_DIR, { recursive: true }); + console.warn("[config] Migrated external-triggers/ → " + EXTERNAL_TRIGGERS_DIR); + } catch (e) { + console.error("[config] Migration of external-triggers/ failed (non-fatal):", e.message); + } + } else { + // Case 2: both old and new exist — merge .json files from old that are not + // already present in new (by filename), then replace the old dir with a + // symlink → EXTERNAL_TRIGGERS_DIR so stale writers (e.g. an un-updated relay + // binary still writing to the old root path) are silently redirected. + try { + // Merge top-level .json files. + var _oldFiles = fs.readdirSync(OLD_EXTERNAL_TRIGGERS_DIR); + for (var _oi = 0; _oi < _oldFiles.length; _oi++) { + var _oldFile = _oldFiles[_oi]; + if (_oldFile === "processed") continue; // handled separately below + if (path.extname(_oldFile) !== ".json") continue; + var _oldFilePath = path.join(OLD_EXTERNAL_TRIGGERS_DIR, _oldFile); + var _newFilePath = path.join(EXTERNAL_TRIGGERS_DIR, _oldFile); + if (!fs.existsSync(_newFilePath)) { + try { + fs.copyFileSync(_oldFilePath, _newFilePath); + console.warn("[config] Merged external-triggers/" + _oldFile + " → " + _newFilePath); + } catch (_ce) { + console.error("[config] Merge of " + _oldFile + " failed (non-fatal):", _ce.message); + } + } + } + // Merge processed/ subdir files. + var _oldProcessedDir = path.join(OLD_EXTERNAL_TRIGGERS_DIR, "processed"); + var _newProcessedDir = path.join(EXTERNAL_TRIGGERS_DIR, "processed"); + if (fs.existsSync(_oldProcessedDir)) { + try { fs.mkdirSync(_newProcessedDir, { recursive: true }); } catch (_) {} + var _oldProcessed = fs.readdirSync(_oldProcessedDir); + for (var _pi = 0; _pi < _oldProcessed.length; _pi++) { + var _pf = _oldProcessed[_pi]; + if (path.extname(_pf) !== ".json") continue; + var _oldPfPath = path.join(_oldProcessedDir, _pf); + var _newPfPath = path.join(_newProcessedDir, _pf); + if (!fs.existsSync(_newPfPath)) { + try { + fs.copyFileSync(_oldPfPath, _newPfPath); + console.warn("[config] Merged external-triggers/processed/" + _pf + " → " + _newPfPath); + } catch (_ce2) { + console.error("[config] Merge of processed/" + _pf + " failed (non-fatal):", _ce2.message); + } + } + } + } + // Replace old dir with a symlink → EXTERNAL_TRIGGERS_DIR. Rename to a temp + // name first, create the symlink, then remove the temp. Non-fatal: on any + // failure we best-effort restore the original name and leave for manual cleanup. + var _oldTriggersTmp = OLD_EXTERNAL_TRIGGERS_DIR + ".migration-tmp"; + try { + fs.renameSync(OLD_EXTERNAL_TRIGGERS_DIR, _oldTriggersTmp); + fs.symlinkSync(EXTERNAL_TRIGGERS_DIR, OLD_EXTERNAL_TRIGGERS_DIR); + fs.rmSync(_oldTriggersTmp, { recursive: true, force: true }); + console.warn("[config] Replaced " + OLD_EXTERNAL_TRIGGERS_DIR + " with symlink → " + EXTERNAL_TRIGGERS_DIR); + } catch (_se) { + console.error("[config] Symlink replacement of external-triggers/ failed (non-fatal):", _se.message); + try { + if (!fs.existsSync(OLD_EXTERNAL_TRIGGERS_DIR)) { + fs.renameSync(_oldTriggersTmp, OLD_EXTERNAL_TRIGGERS_DIR); + } + } catch (_re) {} + } + } catch (e) { + console.error("[config] Migration merge of external-triggers/ failed (non-fatal):", e.message); + } } } // daemon.json / daemon-dev.json (lr-eb5a: moved into console/)