permachine 0.4.0 → 0.4.1

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.
Files changed (2) hide show
  1. package/dist/cli.js +199 -320
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -6376,148 +6376,12 @@ async function performAllMerges(operations) {
6376
6376
  return results;
6377
6377
  }
6378
6378
 
6379
- // src/core/git-hooks.ts
6379
+ // src/core/gitignore-manager.ts
6380
6380
  import fs2 from "node:fs/promises";
6381
6381
  import path5 from "node:path";
6382
6382
  import { exec } from "node:child_process";
6383
6383
  import { promisify } from "node:util";
6384
- import { fileURLToPath as fileURLToPath3 } from "node:url";
6385
6384
  var execAsync = promisify(exec);
6386
- var __filename2 = fileURLToPath3(import.meta.url);
6387
- var __dirname2 = path5.dirname(__filename2);
6388
- var HOOK_NAMES = ["post-checkout", "post-merge", "post-commit"];
6389
- var HOOKS_DIR = ".permachine/hooks";
6390
- async function installHooks(options = {}) {
6391
- const warnings = [];
6392
- if (!await isGitRepository()) {
6393
- throw new Error('Not a git repository. Run "git init" first.');
6394
- }
6395
- const cwd = process.cwd();
6396
- const existingHooksPath = await getGitConfig("core.hooksPath");
6397
- if (existingHooksPath && existingHooksPath !== HOOKS_DIR && !options.legacy) {
6398
- warnings.push(`Git core.hooksPath is already set to: ${existingHooksPath}`, "Use --legacy flag to install hooks in .git/hooks instead");
6399
- }
6400
- const useLegacy = options.legacy || existingHooksPath && existingHooksPath !== HOOKS_DIR;
6401
- if (useLegacy) {
6402
- return await installLegacyHooks(warnings);
6403
- } else {
6404
- return await installHooksPathMethod(warnings);
6405
- }
6406
- }
6407
- async function installHooksPathMethod(warnings) {
6408
- const cwd = process.cwd();
6409
- const hooksDir = path5.join(cwd, HOOKS_DIR);
6410
- await fs2.mkdir(hooksDir, { recursive: true });
6411
- let templatesDir = path5.join(__dirname2, "../../templates/hooks");
6412
- if (!await fileExists2(path5.join(templatesDir, "post-checkout"))) {
6413
- templatesDir = path5.join(__dirname2, "../templates/hooks");
6414
- }
6415
- const installedHooks = [];
6416
- for (const hookName of HOOK_NAMES) {
6417
- const templatePath = path5.join(templatesDir, hookName);
6418
- const hookPath = path5.join(hooksDir, hookName);
6419
- const content = await fs2.readFile(templatePath, "utf-8");
6420
- await fs2.writeFile(hookPath, content, { mode: 493 });
6421
- installedHooks.push(hookName);
6422
- }
6423
- await setGitConfig("core.hooksPath", HOOKS_DIR);
6424
- logger.success(`Installed git hooks via core.hooksPath`);
6425
- return {
6426
- method: "hooksPath",
6427
- hooksInstalled: installedHooks,
6428
- warnings
6429
- };
6430
- }
6431
- async function installLegacyHooks(warnings) {
6432
- const cwd = process.cwd();
6433
- const gitHooksDir = path5.join(cwd, ".git/hooks");
6434
- const installedHooks = [];
6435
- for (const hookName of HOOK_NAMES) {
6436
- const hookPath = path5.join(gitHooksDir, hookName);
6437
- const backupPath = path5.join(gitHooksDir, `${hookName}.pre-mcs`);
6438
- const hookExists = await fileExists2(hookPath);
6439
- if (hookExists) {
6440
- await fs2.rename(hookPath, backupPath);
6441
- }
6442
- const hookContent = `#!/bin/sh
6443
- # Auto-generated by permachine (legacy mode)
6444
-
6445
- permachine merge --silent
6446
-
6447
- # Call original hook if it existed
6448
- if [ -f "${backupPath}" ]; then
6449
- "${backupPath}" "$@"
6450
- fi
6451
-
6452
- exit 0
6453
- `;
6454
- await fs2.writeFile(hookPath, hookContent, { mode: 493 });
6455
- installedHooks.push(hookName);
6456
- }
6457
- logger.success("Installed git hooks via legacy .git/hooks wrapping");
6458
- return {
6459
- method: "legacy",
6460
- hooksInstalled: installedHooks,
6461
- warnings
6462
- };
6463
- }
6464
- async function uninstallHooks() {
6465
- const cwd = process.cwd();
6466
- const hooksPath = await getGitConfig("core.hooksPath");
6467
- if (hooksPath === HOOKS_DIR) {
6468
- await execAsync("git config --unset core.hooksPath");
6469
- const hooksDir = path5.join(cwd, HOOKS_DIR);
6470
- await fs2.rm(hooksDir, { recursive: true, force: true });
6471
- logger.success("Uninstalled git hooks (removed core.hooksPath)");
6472
- } else {
6473
- const gitHooksDir = path5.join(cwd, ".git/hooks");
6474
- for (const hookName of HOOK_NAMES) {
6475
- const hookPath = path5.join(gitHooksDir, hookName);
6476
- const backupPath = path5.join(gitHooksDir, `${hookName}.pre-mcs`);
6477
- if (await fileExists2(hookPath)) {
6478
- await fs2.unlink(hookPath);
6479
- }
6480
- if (await fileExists2(backupPath)) {
6481
- await fs2.rename(backupPath, hookPath);
6482
- }
6483
- }
6484
- logger.success("Uninstalled git hooks (restored original hooks)");
6485
- }
6486
- }
6487
- async function isGitRepository() {
6488
- try {
6489
- await execAsync("git rev-parse --git-dir");
6490
- return true;
6491
- } catch {
6492
- return false;
6493
- }
6494
- }
6495
- async function getGitConfig(key) {
6496
- try {
6497
- const { stdout } = await execAsync(`git config --get ${key}`);
6498
- return stdout.trim() || null;
6499
- } catch {
6500
- return null;
6501
- }
6502
- }
6503
- async function setGitConfig(key, value) {
6504
- await execAsync(`git config ${key} "${value}"`);
6505
- }
6506
- async function fileExists2(filePath) {
6507
- try {
6508
- await fs2.access(filePath);
6509
- return true;
6510
- } catch {
6511
- return false;
6512
- }
6513
- }
6514
-
6515
- // src/core/gitignore-manager.ts
6516
- import fs3 from "node:fs/promises";
6517
- import path6 from "node:path";
6518
- import { exec as exec2 } from "node:child_process";
6519
- import { promisify as promisify2 } from "node:util";
6520
- var execAsync2 = promisify2(exec2);
6521
6385
  async function manageGitignore(outputPaths, options = {}) {
6522
6386
  const result = {
6523
6387
  added: [],
@@ -6528,13 +6392,13 @@ async function manageGitignore(outputPaths, options = {}) {
6528
6392
  return result;
6529
6393
  }
6530
6394
  const cwd = options.cwd || process.cwd();
6531
- const gitignorePath = path6.join(cwd, ".gitignore");
6395
+ const gitignorePath = path5.join(cwd, ".gitignore");
6532
6396
  try {
6533
- const relativePaths = outputPaths.map((p) => path6.relative(cwd, p).replace(/\\/g, "/"));
6397
+ const relativePaths = outputPaths.map((p) => path5.relative(cwd, p).replace(/\\/g, "/"));
6534
6398
  let gitignoreContent = "";
6535
6399
  let gitignoreExists = false;
6536
6400
  try {
6537
- gitignoreContent = await fs3.readFile(gitignorePath, "utf-8");
6401
+ gitignoreContent = await fs2.readFile(gitignorePath, "utf-8");
6538
6402
  gitignoreExists = true;
6539
6403
  } catch (error) {
6540
6404
  if (error.code !== "ENOENT") {
@@ -6561,7 +6425,7 @@ async function manageGitignore(outputPaths, options = {}) {
6561
6425
  ` : newEntries.join(`
6562
6426
  `) + `
6563
6427
  `;
6564
- await fs3.writeFile(gitignorePath, updatedContent, "utf-8");
6428
+ await fs2.writeFile(gitignorePath, updatedContent, "utf-8");
6565
6429
  if (!gitignoreExists) {
6566
6430
  logger.info("Created .gitignore");
6567
6431
  }
@@ -6570,7 +6434,7 @@ async function manageGitignore(outputPaths, options = {}) {
6570
6434
  try {
6571
6435
  const isTracked = await isFileTrackedByGit(relPath, cwd);
6572
6436
  if (isTracked) {
6573
- await execAsync2(`git rm --cached "${relPath}"`, { cwd });
6437
+ await execAsync(`git rm --cached "${relPath}"`, { cwd });
6574
6438
  result.removed.push(relPath);
6575
6439
  logger.info(`Removed ${relPath} from git tracking`);
6576
6440
  }
@@ -6587,7 +6451,7 @@ async function manageGitignore(outputPaths, options = {}) {
6587
6451
  }
6588
6452
  async function isFileTrackedByGit(filePath, cwd) {
6589
6453
  try {
6590
- await execAsync2(`git ls-files --error-unmatch "${filePath}"`, { cwd });
6454
+ await execAsync(`git ls-files --error-unmatch "${filePath}"`, { cwd });
6591
6455
  return true;
6592
6456
  } catch {
6593
6457
  return false;
@@ -6685,7 +6549,7 @@ class ReaddirpStream extends Readable {
6685
6549
  this._directoryFilter = normalizeFilter(opts.directoryFilter);
6686
6550
  const statMethod = opts.lstat ? lstat2 : stat;
6687
6551
  if (wantBigintFsStats) {
6688
- this._stat = (path7) => statMethod(path7, { bigint: true });
6552
+ this._stat = (path6) => statMethod(path6, { bigint: true });
6689
6553
  } else {
6690
6554
  this._stat = statMethod;
6691
6555
  }
@@ -6710,8 +6574,8 @@ class ReaddirpStream extends Readable {
6710
6574
  const par = this.parent;
6711
6575
  const fil = par && par.files;
6712
6576
  if (fil && fil.length > 0) {
6713
- const { path: path7, depth } = par;
6714
- const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path7));
6577
+ const { path: path6, depth } = par;
6578
+ const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path6));
6715
6579
  const awaited = await Promise.all(slice);
6716
6580
  for (const entry of awaited) {
6717
6581
  if (!entry)
@@ -6751,20 +6615,20 @@ class ReaddirpStream extends Readable {
6751
6615
  this.reading = false;
6752
6616
  }
6753
6617
  }
6754
- async _exploreDir(path7, depth) {
6618
+ async _exploreDir(path6, depth) {
6755
6619
  let files;
6756
6620
  try {
6757
- files = await readdir2(path7, this._rdOptions);
6621
+ files = await readdir2(path6, this._rdOptions);
6758
6622
  } catch (error) {
6759
6623
  this._onError(error);
6760
6624
  }
6761
- return { files, depth, path: path7 };
6625
+ return { files, depth, path: path6 };
6762
6626
  }
6763
- async _formatEntry(dirent, path7) {
6627
+ async _formatEntry(dirent, path6) {
6764
6628
  let entry;
6765
6629
  const basename = this._isDirent ? dirent.name : dirent;
6766
6630
  try {
6767
- const fullPath = presolve(pjoin(path7, basename));
6631
+ const fullPath = presolve(pjoin(path6, basename));
6768
6632
  entry = { path: prelative(this._root, fullPath), fullPath, basename };
6769
6633
  entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
6770
6634
  } catch (err) {
@@ -7163,16 +7027,16 @@ var delFromSet = (main, prop, item) => {
7163
7027
  };
7164
7028
  var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
7165
7029
  var FsWatchInstances = new Map;
7166
- function createFsWatchInstance(path7, options, listener, errHandler, emitRaw) {
7030
+ function createFsWatchInstance(path6, options, listener, errHandler, emitRaw) {
7167
7031
  const handleEvent = (rawEvent, evPath) => {
7168
- listener(path7);
7169
- emitRaw(rawEvent, evPath, { watchedPath: path7 });
7170
- if (evPath && path7 !== evPath) {
7171
- fsWatchBroadcast(sp.resolve(path7, evPath), KEY_LISTENERS, sp.join(path7, evPath));
7032
+ listener(path6);
7033
+ emitRaw(rawEvent, evPath, { watchedPath: path6 });
7034
+ if (evPath && path6 !== evPath) {
7035
+ fsWatchBroadcast(sp.resolve(path6, evPath), KEY_LISTENERS, sp.join(path6, evPath));
7172
7036
  }
7173
7037
  };
7174
7038
  try {
7175
- return fs_watch(path7, {
7039
+ return fs_watch(path6, {
7176
7040
  persistent: options.persistent
7177
7041
  }, handleEvent);
7178
7042
  } catch (error) {
@@ -7188,12 +7052,12 @@ var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
7188
7052
  listener(val1, val2, val3);
7189
7053
  });
7190
7054
  };
7191
- var setFsWatchListener = (path7, fullPath, options, handlers) => {
7055
+ var setFsWatchListener = (path6, fullPath, options, handlers) => {
7192
7056
  const { listener, errHandler, rawEmitter } = handlers;
7193
7057
  let cont = FsWatchInstances.get(fullPath);
7194
7058
  let watcher;
7195
7059
  if (!options.persistent) {
7196
- watcher = createFsWatchInstance(path7, options, listener, errHandler, rawEmitter);
7060
+ watcher = createFsWatchInstance(path6, options, listener, errHandler, rawEmitter);
7197
7061
  if (!watcher)
7198
7062
  return;
7199
7063
  return watcher.close.bind(watcher);
@@ -7203,7 +7067,7 @@ var setFsWatchListener = (path7, fullPath, options, handlers) => {
7203
7067
  addAndConvert(cont, KEY_ERR, errHandler);
7204
7068
  addAndConvert(cont, KEY_RAW, rawEmitter);
7205
7069
  } else {
7206
- watcher = createFsWatchInstance(path7, options, fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS), errHandler, fsWatchBroadcast.bind(null, fullPath, KEY_RAW));
7070
+ watcher = createFsWatchInstance(path6, options, fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS), errHandler, fsWatchBroadcast.bind(null, fullPath, KEY_RAW));
7207
7071
  if (!watcher)
7208
7072
  return;
7209
7073
  watcher.on(EV.ERROR, async (error) => {
@@ -7212,7 +7076,7 @@ var setFsWatchListener = (path7, fullPath, options, handlers) => {
7212
7076
  cont.watcherUnusable = true;
7213
7077
  if (isWindows && error.code === "EPERM") {
7214
7078
  try {
7215
- const fd = await open(path7, "r");
7079
+ const fd = await open(path6, "r");
7216
7080
  await fd.close();
7217
7081
  broadcastErr(error);
7218
7082
  } catch (err) {}
@@ -7242,7 +7106,7 @@ var setFsWatchListener = (path7, fullPath, options, handlers) => {
7242
7106
  };
7243
7107
  };
7244
7108
  var FsWatchFileInstances = new Map;
7245
- var setFsWatchFileListener = (path7, fullPath, options, handlers) => {
7109
+ var setFsWatchFileListener = (path6, fullPath, options, handlers) => {
7246
7110
  const { listener, rawEmitter } = handlers;
7247
7111
  let cont = FsWatchFileInstances.get(fullPath);
7248
7112
  const copts = cont && cont.options;
@@ -7264,7 +7128,7 @@ var setFsWatchFileListener = (path7, fullPath, options, handlers) => {
7264
7128
  });
7265
7129
  const currmtime = curr.mtimeMs;
7266
7130
  if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
7267
- foreach(cont.listeners, (listener2) => listener2(path7, curr));
7131
+ foreach(cont.listeners, (listener2) => listener2(path6, curr));
7268
7132
  }
7269
7133
  })
7270
7134
  };
@@ -7289,13 +7153,13 @@ class NodeFsHandler {
7289
7153
  this.fsw = fsW;
7290
7154
  this._boundHandleError = (error) => fsW._handleError(error);
7291
7155
  }
7292
- _watchWithNodeFs(path7, listener) {
7156
+ _watchWithNodeFs(path6, listener) {
7293
7157
  const opts = this.fsw.options;
7294
- const directory = sp.dirname(path7);
7295
- const basename2 = sp.basename(path7);
7158
+ const directory = sp.dirname(path6);
7159
+ const basename2 = sp.basename(path6);
7296
7160
  const parent = this.fsw._getWatchedDir(directory);
7297
7161
  parent.add(basename2);
7298
- const absolutePath = sp.resolve(path7);
7162
+ const absolutePath = sp.resolve(path6);
7299
7163
  const options = {
7300
7164
  persistent: opts.persistent
7301
7165
  };
@@ -7305,12 +7169,12 @@ class NodeFsHandler {
7305
7169
  if (opts.usePolling) {
7306
7170
  const enableBin = opts.interval !== opts.binaryInterval;
7307
7171
  options.interval = enableBin && isBinaryPath(basename2) ? opts.binaryInterval : opts.interval;
7308
- closer = setFsWatchFileListener(path7, absolutePath, options, {
7172
+ closer = setFsWatchFileListener(path6, absolutePath, options, {
7309
7173
  listener,
7310
7174
  rawEmitter: this.fsw._emitRaw
7311
7175
  });
7312
7176
  } else {
7313
- closer = setFsWatchListener(path7, absolutePath, options, {
7177
+ closer = setFsWatchListener(path6, absolutePath, options, {
7314
7178
  listener,
7315
7179
  errHandler: this._boundHandleError,
7316
7180
  rawEmitter: this.fsw._emitRaw
@@ -7328,7 +7192,7 @@ class NodeFsHandler {
7328
7192
  let prevStats = stats;
7329
7193
  if (parent.has(basename2))
7330
7194
  return;
7331
- const listener = async (path7, newStats) => {
7195
+ const listener = async (path6, newStats) => {
7332
7196
  if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
7333
7197
  return;
7334
7198
  if (!newStats || newStats.mtimeMs === 0) {
@@ -7342,11 +7206,11 @@ class NodeFsHandler {
7342
7206
  this.fsw._emit(EV.CHANGE, file, newStats2);
7343
7207
  }
7344
7208
  if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
7345
- this.fsw._closeFile(path7);
7209
+ this.fsw._closeFile(path6);
7346
7210
  prevStats = newStats2;
7347
7211
  const closer2 = this._watchWithNodeFs(file, listener);
7348
7212
  if (closer2)
7349
- this.fsw._addPathCloser(path7, closer2);
7213
+ this.fsw._addPathCloser(path6, closer2);
7350
7214
  } else {
7351
7215
  prevStats = newStats2;
7352
7216
  }
@@ -7370,7 +7234,7 @@ class NodeFsHandler {
7370
7234
  }
7371
7235
  return closer;
7372
7236
  }
7373
- async _handleSymlink(entry, directory, path7, item) {
7237
+ async _handleSymlink(entry, directory, path6, item) {
7374
7238
  if (this.fsw.closed) {
7375
7239
  return;
7376
7240
  }
@@ -7380,7 +7244,7 @@ class NodeFsHandler {
7380
7244
  this.fsw._incrReadyCount();
7381
7245
  let linkPath;
7382
7246
  try {
7383
- linkPath = await fsrealpath(path7);
7247
+ linkPath = await fsrealpath(path6);
7384
7248
  } catch (e) {
7385
7249
  this.fsw._emitReady();
7386
7250
  return true;
@@ -7390,12 +7254,12 @@ class NodeFsHandler {
7390
7254
  if (dir.has(item)) {
7391
7255
  if (this.fsw._symlinkPaths.get(full) !== linkPath) {
7392
7256
  this.fsw._symlinkPaths.set(full, linkPath);
7393
- this.fsw._emit(EV.CHANGE, path7, entry.stats);
7257
+ this.fsw._emit(EV.CHANGE, path6, entry.stats);
7394
7258
  }
7395
7259
  } else {
7396
7260
  dir.add(item);
7397
7261
  this.fsw._symlinkPaths.set(full, linkPath);
7398
- this.fsw._emit(EV.ADD, path7, entry.stats);
7262
+ this.fsw._emit(EV.ADD, path6, entry.stats);
7399
7263
  }
7400
7264
  this.fsw._emitReady();
7401
7265
  return true;
@@ -7425,9 +7289,9 @@ class NodeFsHandler {
7425
7289
  return;
7426
7290
  }
7427
7291
  const item = entry.path;
7428
- let path7 = sp.join(directory, item);
7292
+ let path6 = sp.join(directory, item);
7429
7293
  current.add(item);
7430
- if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path7, item)) {
7294
+ if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path6, item)) {
7431
7295
  return;
7432
7296
  }
7433
7297
  if (this.fsw.closed) {
@@ -7436,8 +7300,8 @@ class NodeFsHandler {
7436
7300
  }
7437
7301
  if (item === target || !target && !previous.has(item)) {
7438
7302
  this.fsw._incrReadyCount();
7439
- path7 = sp.join(dir, sp.relative(dir, path7));
7440
- this._addToNodeFs(path7, initialAdd, wh, depth + 1);
7303
+ path6 = sp.join(dir, sp.relative(dir, path6));
7304
+ this._addToNodeFs(path6, initialAdd, wh, depth + 1);
7441
7305
  }
7442
7306
  }).on(EV.ERROR, this._boundHandleError);
7443
7307
  return new Promise((resolve2, reject) => {
@@ -7486,13 +7350,13 @@ class NodeFsHandler {
7486
7350
  }
7487
7351
  return closer;
7488
7352
  }
7489
- async _addToNodeFs(path7, initialAdd, priorWh, depth, target) {
7353
+ async _addToNodeFs(path6, initialAdd, priorWh, depth, target) {
7490
7354
  const ready = this.fsw._emitReady;
7491
- if (this.fsw._isIgnored(path7) || this.fsw.closed) {
7355
+ if (this.fsw._isIgnored(path6) || this.fsw.closed) {
7492
7356
  ready();
7493
7357
  return false;
7494
7358
  }
7495
- const wh = this.fsw._getWatchHelpers(path7);
7359
+ const wh = this.fsw._getWatchHelpers(path6);
7496
7360
  if (priorWh) {
7497
7361
  wh.filterPath = (entry) => priorWh.filterPath(entry);
7498
7362
  wh.filterDir = (entry) => priorWh.filterDir(entry);
@@ -7508,8 +7372,8 @@ class NodeFsHandler {
7508
7372
  const follow = this.fsw.options.followSymlinks;
7509
7373
  let closer;
7510
7374
  if (stats.isDirectory()) {
7511
- const absPath = sp.resolve(path7);
7512
- const targetPath = follow ? await fsrealpath(path7) : path7;
7375
+ const absPath = sp.resolve(path6);
7376
+ const targetPath = follow ? await fsrealpath(path6) : path6;
7513
7377
  if (this.fsw.closed)
7514
7378
  return;
7515
7379
  closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
@@ -7519,29 +7383,29 @@ class NodeFsHandler {
7519
7383
  this.fsw._symlinkPaths.set(absPath, targetPath);
7520
7384
  }
7521
7385
  } else if (stats.isSymbolicLink()) {
7522
- const targetPath = follow ? await fsrealpath(path7) : path7;
7386
+ const targetPath = follow ? await fsrealpath(path6) : path6;
7523
7387
  if (this.fsw.closed)
7524
7388
  return;
7525
7389
  const parent = sp.dirname(wh.watchPath);
7526
7390
  this.fsw._getWatchedDir(parent).add(wh.watchPath);
7527
7391
  this.fsw._emit(EV.ADD, wh.watchPath, stats);
7528
- closer = await this._handleDir(parent, stats, initialAdd, depth, path7, wh, targetPath);
7392
+ closer = await this._handleDir(parent, stats, initialAdd, depth, path6, wh, targetPath);
7529
7393
  if (this.fsw.closed)
7530
7394
  return;
7531
7395
  if (targetPath !== undefined) {
7532
- this.fsw._symlinkPaths.set(sp.resolve(path7), targetPath);
7396
+ this.fsw._symlinkPaths.set(sp.resolve(path6), targetPath);
7533
7397
  }
7534
7398
  } else {
7535
7399
  closer = this._handleFile(wh.watchPath, stats, initialAdd);
7536
7400
  }
7537
7401
  ready();
7538
7402
  if (closer)
7539
- this.fsw._addPathCloser(path7, closer);
7403
+ this.fsw._addPathCloser(path6, closer);
7540
7404
  return false;
7541
7405
  } catch (error) {
7542
7406
  if (this.fsw._handleError(error)) {
7543
7407
  ready();
7544
- return path7;
7408
+ return path6;
7545
7409
  }
7546
7410
  }
7547
7411
  }
@@ -7585,24 +7449,24 @@ function createPattern(matcher) {
7585
7449
  }
7586
7450
  return () => false;
7587
7451
  }
7588
- function normalizePath(path7) {
7589
- if (typeof path7 !== "string")
7452
+ function normalizePath(path6) {
7453
+ if (typeof path6 !== "string")
7590
7454
  throw new Error("string expected");
7591
- path7 = sp2.normalize(path7);
7592
- path7 = path7.replace(/\\/g, "/");
7455
+ path6 = sp2.normalize(path6);
7456
+ path6 = path6.replace(/\\/g, "/");
7593
7457
  let prepend = false;
7594
- if (path7.startsWith("//"))
7458
+ if (path6.startsWith("//"))
7595
7459
  prepend = true;
7596
- path7 = path7.replace(DOUBLE_SLASH_RE, "/");
7460
+ path6 = path6.replace(DOUBLE_SLASH_RE, "/");
7597
7461
  if (prepend)
7598
- path7 = "/" + path7;
7599
- return path7;
7462
+ path6 = "/" + path6;
7463
+ return path6;
7600
7464
  }
7601
7465
  function matchPatterns(patterns, testString, stats) {
7602
- const path7 = normalizePath(testString);
7466
+ const path6 = normalizePath(testString);
7603
7467
  for (let index = 0;index < patterns.length; index++) {
7604
7468
  const pattern = patterns[index];
7605
- if (pattern(path7, stats)) {
7469
+ if (pattern(path6, stats)) {
7606
7470
  return true;
7607
7471
  }
7608
7472
  }
@@ -7640,19 +7504,19 @@ var toUnix = (string) => {
7640
7504
  }
7641
7505
  return str;
7642
7506
  };
7643
- var normalizePathToUnix = (path7) => toUnix(sp2.normalize(toUnix(path7)));
7644
- var normalizeIgnored = (cwd = "") => (path7) => {
7645
- if (typeof path7 === "string") {
7646
- return normalizePathToUnix(sp2.isAbsolute(path7) ? path7 : sp2.join(cwd, path7));
7507
+ var normalizePathToUnix = (path6) => toUnix(sp2.normalize(toUnix(path6)));
7508
+ var normalizeIgnored = (cwd = "") => (path6) => {
7509
+ if (typeof path6 === "string") {
7510
+ return normalizePathToUnix(sp2.isAbsolute(path6) ? path6 : sp2.join(cwd, path6));
7647
7511
  } else {
7648
- return path7;
7512
+ return path6;
7649
7513
  }
7650
7514
  };
7651
- var getAbsolutePath = (path7, cwd) => {
7652
- if (sp2.isAbsolute(path7)) {
7653
- return path7;
7515
+ var getAbsolutePath = (path6, cwd) => {
7516
+ if (sp2.isAbsolute(path6)) {
7517
+ return path6;
7654
7518
  }
7655
- return sp2.join(cwd, path7);
7519
+ return sp2.join(cwd, path6);
7656
7520
  };
7657
7521
  var EMPTY_SET = Object.freeze(new Set);
7658
7522
 
@@ -7719,10 +7583,10 @@ class WatchHelper {
7719
7583
  dirParts;
7720
7584
  followSymlinks;
7721
7585
  statMethod;
7722
- constructor(path7, follow, fsw) {
7586
+ constructor(path6, follow, fsw) {
7723
7587
  this.fsw = fsw;
7724
- const watchPath = path7;
7725
- this.path = path7 = path7.replace(REPLACER_RE, "");
7588
+ const watchPath = path6;
7589
+ this.path = path6 = path6.replace(REPLACER_RE, "");
7726
7590
  this.watchPath = watchPath;
7727
7591
  this.fullWatchPath = sp2.resolve(watchPath);
7728
7592
  this.dirParts = [];
@@ -7853,20 +7717,20 @@ class FSWatcher extends EventEmitter2 {
7853
7717
  this._closePromise = undefined;
7854
7718
  let paths = unifyPaths(paths_);
7855
7719
  if (cwd) {
7856
- paths = paths.map((path7) => {
7857
- const absPath = getAbsolutePath(path7, cwd);
7720
+ paths = paths.map((path6) => {
7721
+ const absPath = getAbsolutePath(path6, cwd);
7858
7722
  return absPath;
7859
7723
  });
7860
7724
  }
7861
- paths.forEach((path7) => {
7862
- this._removeIgnoredPath(path7);
7725
+ paths.forEach((path6) => {
7726
+ this._removeIgnoredPath(path6);
7863
7727
  });
7864
7728
  this._userIgnored = undefined;
7865
7729
  if (!this._readyCount)
7866
7730
  this._readyCount = 0;
7867
7731
  this._readyCount += paths.length;
7868
- Promise.all(paths.map(async (path7) => {
7869
- const res = await this._nodeFsHandler._addToNodeFs(path7, !_internal, undefined, 0, _origAdd);
7732
+ Promise.all(paths.map(async (path6) => {
7733
+ const res = await this._nodeFsHandler._addToNodeFs(path6, !_internal, undefined, 0, _origAdd);
7870
7734
  if (res)
7871
7735
  this._emitReady();
7872
7736
  return res;
@@ -7885,17 +7749,17 @@ class FSWatcher extends EventEmitter2 {
7885
7749
  return this;
7886
7750
  const paths = unifyPaths(paths_);
7887
7751
  const { cwd } = this.options;
7888
- paths.forEach((path7) => {
7889
- if (!sp2.isAbsolute(path7) && !this._closers.has(path7)) {
7752
+ paths.forEach((path6) => {
7753
+ if (!sp2.isAbsolute(path6) && !this._closers.has(path6)) {
7890
7754
  if (cwd)
7891
- path7 = sp2.join(cwd, path7);
7892
- path7 = sp2.resolve(path7);
7755
+ path6 = sp2.join(cwd, path6);
7756
+ path6 = sp2.resolve(path6);
7893
7757
  }
7894
- this._closePath(path7);
7895
- this._addIgnoredPath(path7);
7896
- if (this._watched.has(path7)) {
7758
+ this._closePath(path6);
7759
+ this._addIgnoredPath(path6);
7760
+ if (this._watched.has(path6)) {
7897
7761
  this._addIgnoredPath({
7898
- path: path7,
7762
+ path: path6,
7899
7763
  recursive: true
7900
7764
  });
7901
7765
  }
@@ -7944,38 +7808,38 @@ class FSWatcher extends EventEmitter2 {
7944
7808
  if (event !== EVENTS.ERROR)
7945
7809
  this.emit(EVENTS.ALL, event, ...args);
7946
7810
  }
7947
- async _emit(event, path7, stats) {
7811
+ async _emit(event, path6, stats) {
7948
7812
  if (this.closed)
7949
7813
  return;
7950
7814
  const opts = this.options;
7951
7815
  if (isWindows)
7952
- path7 = sp2.normalize(path7);
7816
+ path6 = sp2.normalize(path6);
7953
7817
  if (opts.cwd)
7954
- path7 = sp2.relative(opts.cwd, path7);
7955
- const args = [path7];
7818
+ path6 = sp2.relative(opts.cwd, path6);
7819
+ const args = [path6];
7956
7820
  if (stats != null)
7957
7821
  args.push(stats);
7958
7822
  const awf = opts.awaitWriteFinish;
7959
7823
  let pw;
7960
- if (awf && (pw = this._pendingWrites.get(path7))) {
7824
+ if (awf && (pw = this._pendingWrites.get(path6))) {
7961
7825
  pw.lastChange = new Date;
7962
7826
  return this;
7963
7827
  }
7964
7828
  if (opts.atomic) {
7965
7829
  if (event === EVENTS.UNLINK) {
7966
- this._pendingUnlinks.set(path7, [event, ...args]);
7830
+ this._pendingUnlinks.set(path6, [event, ...args]);
7967
7831
  setTimeout(() => {
7968
- this._pendingUnlinks.forEach((entry, path8) => {
7832
+ this._pendingUnlinks.forEach((entry, path7) => {
7969
7833
  this.emit(...entry);
7970
7834
  this.emit(EVENTS.ALL, ...entry);
7971
- this._pendingUnlinks.delete(path8);
7835
+ this._pendingUnlinks.delete(path7);
7972
7836
  });
7973
7837
  }, typeof opts.atomic === "number" ? opts.atomic : 100);
7974
7838
  return this;
7975
7839
  }
7976
- if (event === EVENTS.ADD && this._pendingUnlinks.has(path7)) {
7840
+ if (event === EVENTS.ADD && this._pendingUnlinks.has(path6)) {
7977
7841
  event = EVENTS.CHANGE;
7978
- this._pendingUnlinks.delete(path7);
7842
+ this._pendingUnlinks.delete(path6);
7979
7843
  }
7980
7844
  }
7981
7845
  if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
@@ -7993,16 +7857,16 @@ class FSWatcher extends EventEmitter2 {
7993
7857
  this.emitWithAll(event, args);
7994
7858
  }
7995
7859
  };
7996
- this._awaitWriteFinish(path7, awf.stabilityThreshold, event, awfEmit);
7860
+ this._awaitWriteFinish(path6, awf.stabilityThreshold, event, awfEmit);
7997
7861
  return this;
7998
7862
  }
7999
7863
  if (event === EVENTS.CHANGE) {
8000
- const isThrottled = !this._throttle(EVENTS.CHANGE, path7, 50);
7864
+ const isThrottled = !this._throttle(EVENTS.CHANGE, path6, 50);
8001
7865
  if (isThrottled)
8002
7866
  return this;
8003
7867
  }
8004
7868
  if (opts.alwaysStat && stats === undefined && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
8005
- const fullPath = opts.cwd ? sp2.join(opts.cwd, path7) : path7;
7869
+ const fullPath = opts.cwd ? sp2.join(opts.cwd, path6) : path6;
8006
7870
  let stats2;
8007
7871
  try {
8008
7872
  stats2 = await stat3(fullPath);
@@ -8021,23 +7885,23 @@ class FSWatcher extends EventEmitter2 {
8021
7885
  }
8022
7886
  return error || this.closed;
8023
7887
  }
8024
- _throttle(actionType, path7, timeout) {
7888
+ _throttle(actionType, path6, timeout) {
8025
7889
  if (!this._throttled.has(actionType)) {
8026
7890
  this._throttled.set(actionType, new Map);
8027
7891
  }
8028
7892
  const action = this._throttled.get(actionType);
8029
7893
  if (!action)
8030
7894
  throw new Error("invalid throttle");
8031
- const actionPath = action.get(path7);
7895
+ const actionPath = action.get(path6);
8032
7896
  if (actionPath) {
8033
7897
  actionPath.count++;
8034
7898
  return false;
8035
7899
  }
8036
7900
  let timeoutObject;
8037
7901
  const clear = () => {
8038
- const item = action.get(path7);
7902
+ const item = action.get(path6);
8039
7903
  const count = item ? item.count : 0;
8040
- action.delete(path7);
7904
+ action.delete(path6);
8041
7905
  clearTimeout(timeoutObject);
8042
7906
  if (item)
8043
7907
  clearTimeout(item.timeoutObject);
@@ -8045,50 +7909,50 @@ class FSWatcher extends EventEmitter2 {
8045
7909
  };
8046
7910
  timeoutObject = setTimeout(clear, timeout);
8047
7911
  const thr = { timeoutObject, clear, count: 0 };
8048
- action.set(path7, thr);
7912
+ action.set(path6, thr);
8049
7913
  return thr;
8050
7914
  }
8051
7915
  _incrReadyCount() {
8052
7916
  return this._readyCount++;
8053
7917
  }
8054
- _awaitWriteFinish(path7, threshold, event, awfEmit) {
7918
+ _awaitWriteFinish(path6, threshold, event, awfEmit) {
8055
7919
  const awf = this.options.awaitWriteFinish;
8056
7920
  if (typeof awf !== "object")
8057
7921
  return;
8058
7922
  const pollInterval = awf.pollInterval;
8059
7923
  let timeoutHandler;
8060
- let fullPath = path7;
8061
- if (this.options.cwd && !sp2.isAbsolute(path7)) {
8062
- fullPath = sp2.join(this.options.cwd, path7);
7924
+ let fullPath = path6;
7925
+ if (this.options.cwd && !sp2.isAbsolute(path6)) {
7926
+ fullPath = sp2.join(this.options.cwd, path6);
8063
7927
  }
8064
7928
  const now = new Date;
8065
7929
  const writes = this._pendingWrites;
8066
7930
  function awaitWriteFinishFn(prevStat) {
8067
7931
  statcb(fullPath, (err, curStat) => {
8068
- if (err || !writes.has(path7)) {
7932
+ if (err || !writes.has(path6)) {
8069
7933
  if (err && err.code !== "ENOENT")
8070
7934
  awfEmit(err);
8071
7935
  return;
8072
7936
  }
8073
7937
  const now2 = Number(new Date);
8074
7938
  if (prevStat && curStat.size !== prevStat.size) {
8075
- writes.get(path7).lastChange = now2;
7939
+ writes.get(path6).lastChange = now2;
8076
7940
  }
8077
- const pw = writes.get(path7);
7941
+ const pw = writes.get(path6);
8078
7942
  const df = now2 - pw.lastChange;
8079
7943
  if (df >= threshold) {
8080
- writes.delete(path7);
7944
+ writes.delete(path6);
8081
7945
  awfEmit(undefined, curStat);
8082
7946
  } else {
8083
7947
  timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
8084
7948
  }
8085
7949
  });
8086
7950
  }
8087
- if (!writes.has(path7)) {
8088
- writes.set(path7, {
7951
+ if (!writes.has(path6)) {
7952
+ writes.set(path6, {
8089
7953
  lastChange: now,
8090
7954
  cancelWait: () => {
8091
- writes.delete(path7);
7955
+ writes.delete(path6);
8092
7956
  clearTimeout(timeoutHandler);
8093
7957
  return event;
8094
7958
  }
@@ -8096,8 +7960,8 @@ class FSWatcher extends EventEmitter2 {
8096
7960
  timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval);
8097
7961
  }
8098
7962
  }
8099
- _isIgnored(path7, stats) {
8100
- if (this.options.atomic && DOT_RE.test(path7))
7963
+ _isIgnored(path6, stats) {
7964
+ if (this.options.atomic && DOT_RE.test(path6))
8101
7965
  return true;
8102
7966
  if (!this._userIgnored) {
8103
7967
  const { cwd } = this.options;
@@ -8107,13 +7971,13 @@ class FSWatcher extends EventEmitter2 {
8107
7971
  const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
8108
7972
  this._userIgnored = anymatch(list, undefined);
8109
7973
  }
8110
- return this._userIgnored(path7, stats);
7974
+ return this._userIgnored(path6, stats);
8111
7975
  }
8112
- _isntIgnored(path7, stat4) {
8113
- return !this._isIgnored(path7, stat4);
7976
+ _isntIgnored(path6, stat4) {
7977
+ return !this._isIgnored(path6, stat4);
8114
7978
  }
8115
- _getWatchHelpers(path7) {
8116
- return new WatchHelper(path7, this.options.followSymlinks, this);
7979
+ _getWatchHelpers(path6) {
7980
+ return new WatchHelper(path6, this.options.followSymlinks, this);
8117
7981
  }
8118
7982
  _getWatchedDir(directory) {
8119
7983
  const dir = sp2.resolve(directory);
@@ -8127,57 +7991,57 @@ class FSWatcher extends EventEmitter2 {
8127
7991
  return Boolean(Number(stats.mode) & 256);
8128
7992
  }
8129
7993
  _remove(directory, item, isDirectory) {
8130
- const path7 = sp2.join(directory, item);
8131
- const fullPath = sp2.resolve(path7);
8132
- isDirectory = isDirectory != null ? isDirectory : this._watched.has(path7) || this._watched.has(fullPath);
8133
- if (!this._throttle("remove", path7, 100))
7994
+ const path6 = sp2.join(directory, item);
7995
+ const fullPath = sp2.resolve(path6);
7996
+ isDirectory = isDirectory != null ? isDirectory : this._watched.has(path6) || this._watched.has(fullPath);
7997
+ if (!this._throttle("remove", path6, 100))
8134
7998
  return;
8135
7999
  if (!isDirectory && this._watched.size === 1) {
8136
8000
  this.add(directory, item, true);
8137
8001
  }
8138
- const wp = this._getWatchedDir(path7);
8002
+ const wp = this._getWatchedDir(path6);
8139
8003
  const nestedDirectoryChildren = wp.getChildren();
8140
- nestedDirectoryChildren.forEach((nested) => this._remove(path7, nested));
8004
+ nestedDirectoryChildren.forEach((nested) => this._remove(path6, nested));
8141
8005
  const parent = this._getWatchedDir(directory);
8142
8006
  const wasTracked = parent.has(item);
8143
8007
  parent.remove(item);
8144
8008
  if (this._symlinkPaths.has(fullPath)) {
8145
8009
  this._symlinkPaths.delete(fullPath);
8146
8010
  }
8147
- let relPath = path7;
8011
+ let relPath = path6;
8148
8012
  if (this.options.cwd)
8149
- relPath = sp2.relative(this.options.cwd, path7);
8013
+ relPath = sp2.relative(this.options.cwd, path6);
8150
8014
  if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
8151
8015
  const event = this._pendingWrites.get(relPath).cancelWait();
8152
8016
  if (event === EVENTS.ADD)
8153
8017
  return;
8154
8018
  }
8155
- this._watched.delete(path7);
8019
+ this._watched.delete(path6);
8156
8020
  this._watched.delete(fullPath);
8157
8021
  const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
8158
- if (wasTracked && !this._isIgnored(path7))
8159
- this._emit(eventName, path7);
8160
- this._closePath(path7);
8022
+ if (wasTracked && !this._isIgnored(path6))
8023
+ this._emit(eventName, path6);
8024
+ this._closePath(path6);
8161
8025
  }
8162
- _closePath(path7) {
8163
- this._closeFile(path7);
8164
- const dir = sp2.dirname(path7);
8165
- this._getWatchedDir(dir).remove(sp2.basename(path7));
8026
+ _closePath(path6) {
8027
+ this._closeFile(path6);
8028
+ const dir = sp2.dirname(path6);
8029
+ this._getWatchedDir(dir).remove(sp2.basename(path6));
8166
8030
  }
8167
- _closeFile(path7) {
8168
- const closers = this._closers.get(path7);
8031
+ _closeFile(path6) {
8032
+ const closers = this._closers.get(path6);
8169
8033
  if (!closers)
8170
8034
  return;
8171
8035
  closers.forEach((closer) => closer());
8172
- this._closers.delete(path7);
8036
+ this._closers.delete(path6);
8173
8037
  }
8174
- _addPathCloser(path7, closer) {
8038
+ _addPathCloser(path6, closer) {
8175
8039
  if (!closer)
8176
8040
  return;
8177
- let list = this._closers.get(path7);
8041
+ let list = this._closers.get(path6);
8178
8042
  if (!list) {
8179
8043
  list = [];
8180
- this._closers.set(path7, list);
8044
+ this._closers.set(path6, list);
8181
8045
  }
8182
8046
  list.push(closer);
8183
8047
  }
@@ -8207,7 +8071,7 @@ function watch(paths, options = {}) {
8207
8071
  var chokidar_default = { watch, FSWatcher };
8208
8072
 
8209
8073
  // src/core/watcher.ts
8210
- import path7 from "node:path";
8074
+ import path6 from "node:path";
8211
8075
  function formatTime() {
8212
8076
  const now = new Date;
8213
8077
  const hours = String(now.getHours()).padStart(2, "0");
@@ -8240,7 +8104,7 @@ function getWatchPaths(operations) {
8240
8104
  return Array.from(paths);
8241
8105
  }
8242
8106
  async function handleFileChange(changedPath, state, options) {
8243
- const relPath = path7.relative(options.cwd || process.cwd(), changedPath);
8107
+ const relPath = path6.relative(options.cwd || process.cwd(), changedPath);
8244
8108
  if (!logger.isSilent() && !options.verbose) {
8245
8109
  console.log(`[${formatTime()}] Changed: ${relPath}`);
8246
8110
  }
@@ -8254,9 +8118,9 @@ async function handleFileChange(changedPath, state, options) {
8254
8118
  for (const op of affectedOps) {
8255
8119
  const result = await performMerge(op);
8256
8120
  if (result.success && result.changed) {
8257
- const baseFile = op.basePath ? path7.basename(op.basePath) : "";
8258
- const machineFile = path7.basename(op.machinePath);
8259
- const outputFile = path7.basename(op.outputPath);
8121
+ const baseFile = op.basePath ? path6.basename(op.basePath) : "";
8122
+ const machineFile = path6.basename(op.machinePath);
8123
+ const outputFile = path6.basename(op.outputPath);
8260
8124
  if (!logger.isSilent()) {
8261
8125
  if (baseFile) {
8262
8126
  console.log(`[${formatTime()}] Merged ${baseFile} + ${machineFile} → ${outputFile}`);
@@ -8267,7 +8131,7 @@ async function handleFileChange(changedPath, state, options) {
8267
8131
  } else if (!result.success && result.error) {
8268
8132
  logger.error(`Failed to merge: ${result.error.message}`);
8269
8133
  } else if (options.verbose && !result.changed) {
8270
- logger.info(`No changes needed for ${path7.basename(op.outputPath)}`);
8134
+ logger.info(`No changes needed for ${path6.basename(op.outputPath)}`);
8271
8135
  }
8272
8136
  }
8273
8137
  if (!logger.isSilent() && !options.verbose) {
@@ -8298,7 +8162,7 @@ async function startWatcher(machineName, options = {}) {
8298
8162
  if (!logger.isSilent()) {
8299
8163
  console.log(`✓ Watching ${watchPaths.length} file(s) for changes...`);
8300
8164
  for (const watchPath of watchPaths) {
8301
- console.log(` - ${path7.relative(cwd, watchPath)}`);
8165
+ console.log(` - ${path6.relative(cwd, watchPath)}`);
8302
8166
  }
8303
8167
  console.log("");
8304
8168
  }
@@ -8311,9 +8175,9 @@ async function startWatcher(machineName, options = {}) {
8311
8175
  }
8312
8176
  });
8313
8177
  watcher.on("change", (changedPath) => {
8314
- const absolutePath = path7.resolve(cwd, changedPath);
8178
+ const absolutePath = path6.resolve(cwd, changedPath);
8315
8179
  if (options.verbose) {
8316
- logger.info(`File changed: ${path7.relative(cwd, absolutePath)}`);
8180
+ logger.info(`File changed: ${path6.relative(cwd, absolutePath)}`);
8317
8181
  }
8318
8182
  const existingTimer = state.debounceTimers.get(absolutePath);
8319
8183
  if (existingTimer) {
@@ -8326,9 +8190,9 @@ async function startWatcher(machineName, options = {}) {
8326
8190
  state.debounceTimers.set(absolutePath, timer);
8327
8191
  });
8328
8192
  watcher.on("add", async (addedPath) => {
8329
- const absolutePath = path7.resolve(cwd, addedPath);
8193
+ const absolutePath = path6.resolve(cwd, addedPath);
8330
8194
  if (options.verbose) {
8331
- logger.info(`File added: ${path7.relative(cwd, absolutePath)}`);
8195
+ logger.info(`File added: ${path6.relative(cwd, absolutePath)}`);
8332
8196
  }
8333
8197
  const newOperations = await scanForMergeOperations(machineName, cwd);
8334
8198
  state.operations = newOperations;
@@ -8337,7 +8201,7 @@ async function startWatcher(machineName, options = {}) {
8337
8201
  });
8338
8202
  watcher.on("unlink", (deletedPath) => {
8339
8203
  if (options.verbose) {
8340
- const relPath = path7.relative(cwd, deletedPath);
8204
+ const relPath = path6.relative(cwd, deletedPath);
8341
8205
  logger.warn(`File deleted: ${relPath}`);
8342
8206
  logger.info("Run merge manually or restart watch to update operations");
8343
8207
  }
@@ -8358,22 +8222,37 @@ async function startWatcher(machineName, options = {}) {
8358
8222
  }
8359
8223
 
8360
8224
  // src/cli.ts
8361
- import fs4 from "node:fs/promises";
8362
- import path8 from "node:path";
8363
- import { fileURLToPath as fileURLToPath4 } from "node:url";
8225
+ import fs3 from "node:fs/promises";
8226
+ import path7 from "node:path";
8227
+ import { fileURLToPath as fileURLToPath3 } from "node:url";
8364
8228
  import { createInterface } from "node:readline";
8365
- var __filename3 = fileURLToPath4(import.meta.url);
8366
- var __dirname3 = path8.dirname(__filename3);
8229
+ var __filename2 = fileURLToPath3(import.meta.url);
8230
+ var __dirname2 = path7.dirname(__filename2);
8367
8231
  async function checkExistingOutputFiles(operations) {
8368
8232
  const existing = [];
8369
8233
  for (const op of operations) {
8370
8234
  try {
8371
- await fs4.access(op.outputPath);
8235
+ await fs3.access(op.outputPath);
8372
8236
  existing.push(op.outputPath);
8373
8237
  } catch {}
8374
8238
  }
8375
8239
  return existing;
8376
8240
  }
8241
+ async function checkTrackedOutputFiles(operations) {
8242
+ const tracked = [];
8243
+ const cwd = process.cwd();
8244
+ for (const op of operations) {
8245
+ try {
8246
+ await fs3.access(op.outputPath);
8247
+ const relativePath = path7.relative(cwd, op.outputPath);
8248
+ const isTracked = await isFileTrackedByGit(relativePath, cwd);
8249
+ if (isTracked) {
8250
+ tracked.push(op.outputPath);
8251
+ }
8252
+ } catch {}
8253
+ }
8254
+ return tracked;
8255
+ }
8377
8256
  async function promptConfirmation(message) {
8378
8257
  const rl = createInterface({
8379
8258
  input: process.stdin,
@@ -8440,11 +8319,11 @@ async function handleInit(argv) {
8440
8319
  const operations = await scanForMergeOperations(machineName);
8441
8320
  if (operations.length > 0) {
8442
8321
  logger.info(`Found ${operations.length} machine-specific file(s)`);
8443
- const existingFiles = await checkExistingOutputFiles(operations);
8444
- if (existingFiles.length > 0 && !argv["no-gitignore"]) {
8322
+ const trackedFiles = await checkTrackedOutputFiles(operations);
8323
+ if (trackedFiles.length > 0 && !argv["no-gitignore"]) {
8445
8324
  logger.warn("⚠️ Warning: The following files will be overwritten and untracked from git:");
8446
- for (const file of existingFiles) {
8447
- logger.warn(` - ${path8.relative(process.cwd(), file)}`);
8325
+ for (const file of trackedFiles) {
8326
+ logger.warn(` - ${path7.relative(process.cwd(), file)}`);
8448
8327
  }
8449
8328
  logger.info("");
8450
8329
  const confirmed = await promptConfirmation("Do you want to continue?");
@@ -8508,11 +8387,11 @@ async function handleMerge(argv) {
8508
8387
  return;
8509
8388
  }
8510
8389
  if (!argv.silent && !argv["no-gitignore"]) {
8511
- const existingFiles = await checkExistingOutputFiles(operations);
8512
- if (existingFiles.length > 0) {
8390
+ const trackedFiles = await checkTrackedOutputFiles(operations);
8391
+ if (trackedFiles.length > 0) {
8513
8392
  logger.warn("⚠️ Warning: The following files will be overwritten and untracked from git:");
8514
- for (const file of existingFiles) {
8515
- logger.warn(` - ${path8.relative(process.cwd(), file)}`);
8393
+ for (const file of trackedFiles) {
8394
+ logger.warn(` - ${path7.relative(process.cwd(), file)}`);
8516
8395
  }
8517
8396
  logger.info("");
8518
8397
  const confirmed = await promptConfirmation("Do you want to continue?");
@@ -8550,11 +8429,11 @@ async function handleInfo(argv) {
8550
8429
  const operations = await scanForMergeOperations(machineName);
8551
8430
  console.log(`Machine name: ${machineName}`);
8552
8431
  console.log(`Repository: ${process.cwd()}`);
8553
- const { exec: exec3 } = await import("node:child_process");
8554
- const { promisify: promisify3 } = await import("node:util");
8555
- const execAsync3 = promisify3(exec3);
8432
+ const { exec: exec2 } = await import("node:child_process");
8433
+ const { promisify: promisify2 } = await import("node:util");
8434
+ const execAsync2 = promisify2(exec2);
8556
8435
  try {
8557
- const { stdout } = await execAsync3("git config --get core.hooksPath");
8436
+ const { stdout } = await execAsync2("git config --get core.hooksPath");
8558
8437
  const hooksPath = stdout.trim();
8559
8438
  if (hooksPath) {
8560
8439
  console.log(`Hooks method: core.hooksPath`);
@@ -8567,9 +8446,9 @@ async function handleInfo(argv) {
8567
8446
  }
8568
8447
  console.log(`Tracked patterns: ${operations.length}`);
8569
8448
  for (const op of operations) {
8570
- const baseName = op.basePath ? path8.basename(op.basePath) : "(none)";
8571
- const machineName2 = path8.basename(op.machinePath);
8572
- const outputName = path8.basename(op.outputPath);
8449
+ const baseName = op.basePath ? path7.basename(op.basePath) : "(none)";
8450
+ const machineName2 = path7.basename(op.machinePath);
8451
+ const outputName = path7.basename(op.outputPath);
8573
8452
  console.log(` - ${baseName} + ${machineName2} → ${outputName}`);
8574
8453
  }
8575
8454
  if (operations.length > 0) {
@@ -8579,7 +8458,7 @@ async function handleInfo(argv) {
8579
8458
  if (existingFiles.length > 0) {
8580
8459
  console.log("Existing output files:");
8581
8460
  for (const file of existingFiles) {
8582
- console.log(` - ${path8.relative(process.cwd(), file)}`);
8461
+ console.log(` - ${path7.relative(process.cwd(), file)}`);
8583
8462
  }
8584
8463
  }
8585
8464
  }
@@ -8660,8 +8539,8 @@ DOCUMENTATION:
8660
8539
  }
8661
8540
  async function showVersion() {
8662
8541
  try {
8663
- const packageJsonPath = path8.join(__dirname3, "../package.json");
8664
- const packageJson = JSON.parse(await fs4.readFile(packageJsonPath, "utf-8"));
8542
+ const packageJsonPath = path7.join(__dirname2, "../package.json");
8543
+ const packageJson = JSON.parse(await fs3.readFile(packageJsonPath, "utf-8"));
8665
8544
  console.log(packageJson.version);
8666
8545
  } catch {
8667
8546
  console.log("unknown");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "permachine",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Automatically merge machine-specific config files with base configs using git hooks",
5
5
  "type": "module",
6
6
  "bin": {