permachine 0.5.0 → 0.5.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.
Files changed (2) hide show
  1. package/dist/cli.js +384 -174
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -5934,6 +5934,10 @@ function matchFilters(filename, context) {
5934
5934
  function getBaseFilename(filename) {
5935
5935
  return parseFilters(filename).baseFilename;
5936
5936
  }
5937
+ function isBaseFile(filename) {
5938
+ const basename = filename.includes("/") || filename.includes("\\") ? filename.split(/[/\\]/).pop() || filename : filename;
5939
+ return basename.includes(".base.") || basename.endsWith(".base");
5940
+ }
5937
5941
  function isLegacyFilename(filename, machineName) {
5938
5942
  const middlePattern = new RegExp(`\\.${machineName}\\.`, "i");
5939
5943
  const endPattern = new RegExp(`\\.${machineName}$`, "i");
@@ -5943,6 +5947,8 @@ function isLegacyFilename(filename, machineName) {
5943
5947
  // src/core/file-scanner.ts
5944
5948
  async function scanForMergeOperations(machineName, cwd = process.cwd()) {
5945
5949
  const operations = [];
5950
+ const processedOutputs = new Set;
5951
+ const baseFilesWithMachineFiles = new Set;
5946
5952
  const patterns = [
5947
5953
  "**/*{*}*",
5948
5954
  `**/*.${machineName}.*`,
@@ -5965,25 +5971,93 @@ async function scanForMergeOperations(machineName, cwd = process.cwd()) {
5965
5971
  const context = createCustomContext({ machine: machineName });
5966
5972
  for (const file of uniqueFiles) {
5967
5973
  const basename = path2.basename(file);
5968
- if (basename.includes(".base.") || basename.includes(".base")) {
5974
+ if (isBaseFile(basename)) {
5969
5975
  continue;
5970
5976
  }
5971
5977
  let shouldProcess = false;
5972
5978
  if (hasFilters(basename)) {
5973
5979
  const result = matchFilters(basename, context);
5974
5980
  shouldProcess = result.matches;
5981
+ const operation = createMergeOperation(file, machineName, cwd);
5982
+ if (operation && operation.basePath) {
5983
+ baseFilesWithMachineFiles.add(operation.basePath);
5984
+ }
5975
5985
  } else if (isLegacyFilename(basename, machineName)) {
5976
5986
  shouldProcess = true;
5987
+ const operation = createMergeOperation(file, machineName, cwd);
5988
+ if (operation && operation.basePath) {
5989
+ baseFilesWithMachineFiles.add(operation.basePath);
5990
+ }
5977
5991
  }
5978
5992
  if (shouldProcess) {
5979
5993
  const operation = createMergeOperation(file, machineName, cwd);
5980
5994
  if (operation) {
5981
5995
  operations.push(operation);
5996
+ processedOutputs.add(operation.outputPath);
5982
5997
  }
5983
5998
  }
5984
5999
  }
6000
+ const basePatterns = [
6001
+ "**/*.base.json",
6002
+ "**/.*.base",
6003
+ "**/.*.base.*"
6004
+ ];
6005
+ for (const pattern of basePatterns) {
6006
+ try {
6007
+ const baseFiles = await glob(pattern, {
6008
+ cwd,
6009
+ ignore: ["node_modules/**", ".git/**", "dist/**"],
6010
+ dot: true,
6011
+ nodir: true
6012
+ });
6013
+ for (const baseFile of baseFiles) {
6014
+ const fullPath = path2.join(cwd, baseFile);
6015
+ if (baseFilesWithMachineFiles.has(fullPath)) {
6016
+ continue;
6017
+ }
6018
+ const operation = createBaseOnlyMergeOperation(baseFile, cwd);
6019
+ if (operation && !processedOutputs.has(operation.outputPath)) {
6020
+ operations.push(operation);
6021
+ processedOutputs.add(operation.outputPath);
6022
+ }
6023
+ }
6024
+ } catch (error) {}
6025
+ }
5985
6026
  return operations;
5986
6027
  }
6028
+ function createBaseOnlyMergeOperation(baseFile, cwd) {
6029
+ const dir = path2.dirname(baseFile);
6030
+ const fullBasename = path2.basename(baseFile);
6031
+ let type;
6032
+ let ext2;
6033
+ if (fullBasename.endsWith(".json") || fullBasename.includes(".base.json") || fullBasename.includes(".{base}.json")) {
6034
+ type = "json";
6035
+ ext2 = ".json";
6036
+ } else if (fullBasename.startsWith(".env")) {
6037
+ type = "env";
6038
+ ext2 = "";
6039
+ } else {
6040
+ type = "unknown";
6041
+ ext2 = path2.extname(baseFile);
6042
+ }
6043
+ if (type === "unknown") {
6044
+ return null;
6045
+ }
6046
+ let outputName;
6047
+ if (type === "env") {
6048
+ outputName = fullBasename.replace(".base", "").replace(".{base}", "");
6049
+ } else {
6050
+ outputName = fullBasename.replace(".base", "").replace(".{base}", "");
6051
+ }
6052
+ const basePath = path2.join(cwd, baseFile);
6053
+ const outputPath = path2.join(cwd, dir, outputName);
6054
+ return {
6055
+ basePath,
6056
+ machinePath: "",
6057
+ outputPath,
6058
+ type
6059
+ };
6060
+ }
5987
6061
  function createMergeOperation(machineFile, machineName, cwd) {
5988
6062
  const dir = path2.dirname(machineFile);
5989
6063
  const fullBasename = path2.basename(machineFile);
@@ -6458,6 +6532,142 @@ async function isFileTrackedByGit(filePath, cwd) {
6458
6532
  }
6459
6533
  }
6460
6534
 
6535
+ // src/core/git-hooks.ts
6536
+ import fs3 from "node:fs/promises";
6537
+ import path6 from "node:path";
6538
+ import { exec as exec2 } from "node:child_process";
6539
+ import { promisify as promisify2 } from "node:util";
6540
+ import { fileURLToPath as fileURLToPath3 } from "node:url";
6541
+ var execAsync2 = promisify2(exec2);
6542
+ var __filename2 = fileURLToPath3(import.meta.url);
6543
+ var __dirname2 = path6.dirname(__filename2);
6544
+ var HOOK_NAMES = ["post-checkout", "post-merge", "post-commit"];
6545
+ var HOOKS_DIR = ".permachine/hooks";
6546
+ async function installHooks(options = {}) {
6547
+ const warnings = [];
6548
+ if (!await isGitRepository()) {
6549
+ throw new Error('Not a git repository. Run "git init" first.');
6550
+ }
6551
+ const cwd = process.cwd();
6552
+ const existingHooksPath = await getGitConfig("core.hooksPath");
6553
+ if (existingHooksPath && existingHooksPath !== HOOKS_DIR && !options.legacy) {
6554
+ warnings.push(`Git core.hooksPath is already set to: ${existingHooksPath}`, "Use --legacy flag to install hooks in .git/hooks instead");
6555
+ }
6556
+ const useLegacy = options.legacy || existingHooksPath && existingHooksPath !== HOOKS_DIR;
6557
+ if (useLegacy) {
6558
+ return await installLegacyHooks(warnings);
6559
+ } else {
6560
+ return await installHooksPathMethod(warnings);
6561
+ }
6562
+ }
6563
+ async function installHooksPathMethod(warnings) {
6564
+ const cwd = process.cwd();
6565
+ const hooksDir = path6.join(cwd, HOOKS_DIR);
6566
+ await fs3.mkdir(hooksDir, { recursive: true });
6567
+ let templatesDir = path6.join(__dirname2, "../../templates/hooks");
6568
+ if (!await fileExists2(path6.join(templatesDir, "post-checkout"))) {
6569
+ templatesDir = path6.join(__dirname2, "../templates/hooks");
6570
+ }
6571
+ const installedHooks = [];
6572
+ for (const hookName of HOOK_NAMES) {
6573
+ const templatePath = path6.join(templatesDir, hookName);
6574
+ const hookPath = path6.join(hooksDir, hookName);
6575
+ const content = await fs3.readFile(templatePath, "utf-8");
6576
+ await fs3.writeFile(hookPath, content, { mode: 493 });
6577
+ installedHooks.push(hookName);
6578
+ }
6579
+ await setGitConfig("core.hooksPath", HOOKS_DIR);
6580
+ logger.success(`Installed git hooks via core.hooksPath`);
6581
+ return {
6582
+ method: "hooksPath",
6583
+ hooksInstalled: installedHooks,
6584
+ warnings
6585
+ };
6586
+ }
6587
+ async function installLegacyHooks(warnings) {
6588
+ const cwd = process.cwd();
6589
+ const gitHooksDir = path6.join(cwd, ".git/hooks");
6590
+ const installedHooks = [];
6591
+ for (const hookName of HOOK_NAMES) {
6592
+ const hookPath = path6.join(gitHooksDir, hookName);
6593
+ const backupPath = path6.join(gitHooksDir, `${hookName}.pre-mcs`);
6594
+ const hookExists = await fileExists2(hookPath);
6595
+ if (hookExists) {
6596
+ await fs3.rename(hookPath, backupPath);
6597
+ }
6598
+ const hookContent = `#!/bin/sh
6599
+ # Auto-generated by permachine (legacy mode)
6600
+
6601
+ permachine merge --silent
6602
+
6603
+ # Call original hook if it existed
6604
+ if [ -f "${backupPath}" ]; then
6605
+ "${backupPath}" "$@"
6606
+ fi
6607
+
6608
+ exit 0
6609
+ `;
6610
+ await fs3.writeFile(hookPath, hookContent, { mode: 493 });
6611
+ installedHooks.push(hookName);
6612
+ }
6613
+ logger.success("Installed git hooks via legacy .git/hooks wrapping");
6614
+ return {
6615
+ method: "legacy",
6616
+ hooksInstalled: installedHooks,
6617
+ warnings
6618
+ };
6619
+ }
6620
+ async function uninstallHooks() {
6621
+ const cwd = process.cwd();
6622
+ const hooksPath = await getGitConfig("core.hooksPath");
6623
+ if (hooksPath === HOOKS_DIR) {
6624
+ await execAsync2("git config --unset core.hooksPath");
6625
+ const hooksDir = path6.join(cwd, HOOKS_DIR);
6626
+ await fs3.rm(hooksDir, { recursive: true, force: true });
6627
+ logger.success("Uninstalled git hooks (removed core.hooksPath)");
6628
+ } else {
6629
+ const gitHooksDir = path6.join(cwd, ".git/hooks");
6630
+ for (const hookName of HOOK_NAMES) {
6631
+ const hookPath = path6.join(gitHooksDir, hookName);
6632
+ const backupPath = path6.join(gitHooksDir, `${hookName}.pre-mcs`);
6633
+ if (await fileExists2(hookPath)) {
6634
+ await fs3.unlink(hookPath);
6635
+ }
6636
+ if (await fileExists2(backupPath)) {
6637
+ await fs3.rename(backupPath, hookPath);
6638
+ }
6639
+ }
6640
+ logger.success("Uninstalled git hooks (restored original hooks)");
6641
+ }
6642
+ }
6643
+ async function isGitRepository() {
6644
+ try {
6645
+ await execAsync2("git rev-parse --git-dir");
6646
+ return true;
6647
+ } catch {
6648
+ return false;
6649
+ }
6650
+ }
6651
+ async function getGitConfig(key) {
6652
+ try {
6653
+ const { stdout } = await execAsync2(`git config --get ${key}`);
6654
+ return stdout.trim() || null;
6655
+ } catch {
6656
+ return null;
6657
+ }
6658
+ }
6659
+ async function setGitConfig(key, value) {
6660
+ await execAsync2(`git config ${key} "${value}"`);
6661
+ }
6662
+ async function fileExists2(filePath) {
6663
+ try {
6664
+ await fs3.access(filePath);
6665
+ return true;
6666
+ } catch {
6667
+ return false;
6668
+ }
6669
+ }
6670
+
6461
6671
  // node_modules/chokidar/index.js
6462
6672
  import { EventEmitter as EventEmitter2 } from "node:events";
6463
6673
  import { stat as statcb, Stats } from "node:fs";
@@ -6549,7 +6759,7 @@ class ReaddirpStream extends Readable {
6549
6759
  this._directoryFilter = normalizeFilter(opts.directoryFilter);
6550
6760
  const statMethod = opts.lstat ? lstat2 : stat;
6551
6761
  if (wantBigintFsStats) {
6552
- this._stat = (path6) => statMethod(path6, { bigint: true });
6762
+ this._stat = (path7) => statMethod(path7, { bigint: true });
6553
6763
  } else {
6554
6764
  this._stat = statMethod;
6555
6765
  }
@@ -6574,8 +6784,8 @@ class ReaddirpStream extends Readable {
6574
6784
  const par = this.parent;
6575
6785
  const fil = par && par.files;
6576
6786
  if (fil && fil.length > 0) {
6577
- const { path: path6, depth } = par;
6578
- const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path6));
6787
+ const { path: path7, depth } = par;
6788
+ const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path7));
6579
6789
  const awaited = await Promise.all(slice);
6580
6790
  for (const entry of awaited) {
6581
6791
  if (!entry)
@@ -6615,20 +6825,20 @@ class ReaddirpStream extends Readable {
6615
6825
  this.reading = false;
6616
6826
  }
6617
6827
  }
6618
- async _exploreDir(path6, depth) {
6828
+ async _exploreDir(path7, depth) {
6619
6829
  let files;
6620
6830
  try {
6621
- files = await readdir2(path6, this._rdOptions);
6831
+ files = await readdir2(path7, this._rdOptions);
6622
6832
  } catch (error) {
6623
6833
  this._onError(error);
6624
6834
  }
6625
- return { files, depth, path: path6 };
6835
+ return { files, depth, path: path7 };
6626
6836
  }
6627
- async _formatEntry(dirent, path6) {
6837
+ async _formatEntry(dirent, path7) {
6628
6838
  let entry;
6629
6839
  const basename = this._isDirent ? dirent.name : dirent;
6630
6840
  try {
6631
- const fullPath = presolve(pjoin(path6, basename));
6841
+ const fullPath = presolve(pjoin(path7, basename));
6632
6842
  entry = { path: prelative(this._root, fullPath), fullPath, basename };
6633
6843
  entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
6634
6844
  } catch (err) {
@@ -7027,16 +7237,16 @@ var delFromSet = (main, prop, item) => {
7027
7237
  };
7028
7238
  var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
7029
7239
  var FsWatchInstances = new Map;
7030
- function createFsWatchInstance(path6, options, listener, errHandler, emitRaw) {
7240
+ function createFsWatchInstance(path7, options, listener, errHandler, emitRaw) {
7031
7241
  const handleEvent = (rawEvent, 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));
7242
+ listener(path7);
7243
+ emitRaw(rawEvent, evPath, { watchedPath: path7 });
7244
+ if (evPath && path7 !== evPath) {
7245
+ fsWatchBroadcast(sp.resolve(path7, evPath), KEY_LISTENERS, sp.join(path7, evPath));
7036
7246
  }
7037
7247
  };
7038
7248
  try {
7039
- return fs_watch(path6, {
7249
+ return fs_watch(path7, {
7040
7250
  persistent: options.persistent
7041
7251
  }, handleEvent);
7042
7252
  } catch (error) {
@@ -7052,12 +7262,12 @@ var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
7052
7262
  listener(val1, val2, val3);
7053
7263
  });
7054
7264
  };
7055
- var setFsWatchListener = (path6, fullPath, options, handlers) => {
7265
+ var setFsWatchListener = (path7, fullPath, options, handlers) => {
7056
7266
  const { listener, errHandler, rawEmitter } = handlers;
7057
7267
  let cont = FsWatchInstances.get(fullPath);
7058
7268
  let watcher;
7059
7269
  if (!options.persistent) {
7060
- watcher = createFsWatchInstance(path6, options, listener, errHandler, rawEmitter);
7270
+ watcher = createFsWatchInstance(path7, options, listener, errHandler, rawEmitter);
7061
7271
  if (!watcher)
7062
7272
  return;
7063
7273
  return watcher.close.bind(watcher);
@@ -7067,7 +7277,7 @@ var setFsWatchListener = (path6, fullPath, options, handlers) => {
7067
7277
  addAndConvert(cont, KEY_ERR, errHandler);
7068
7278
  addAndConvert(cont, KEY_RAW, rawEmitter);
7069
7279
  } else {
7070
- watcher = createFsWatchInstance(path6, options, fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS), errHandler, fsWatchBroadcast.bind(null, fullPath, KEY_RAW));
7280
+ watcher = createFsWatchInstance(path7, options, fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS), errHandler, fsWatchBroadcast.bind(null, fullPath, KEY_RAW));
7071
7281
  if (!watcher)
7072
7282
  return;
7073
7283
  watcher.on(EV.ERROR, async (error) => {
@@ -7076,7 +7286,7 @@ var setFsWatchListener = (path6, fullPath, options, handlers) => {
7076
7286
  cont.watcherUnusable = true;
7077
7287
  if (isWindows && error.code === "EPERM") {
7078
7288
  try {
7079
- const fd = await open(path6, "r");
7289
+ const fd = await open(path7, "r");
7080
7290
  await fd.close();
7081
7291
  broadcastErr(error);
7082
7292
  } catch (err) {}
@@ -7106,7 +7316,7 @@ var setFsWatchListener = (path6, fullPath, options, handlers) => {
7106
7316
  };
7107
7317
  };
7108
7318
  var FsWatchFileInstances = new Map;
7109
- var setFsWatchFileListener = (path6, fullPath, options, handlers) => {
7319
+ var setFsWatchFileListener = (path7, fullPath, options, handlers) => {
7110
7320
  const { listener, rawEmitter } = handlers;
7111
7321
  let cont = FsWatchFileInstances.get(fullPath);
7112
7322
  const copts = cont && cont.options;
@@ -7128,7 +7338,7 @@ var setFsWatchFileListener = (path6, fullPath, options, handlers) => {
7128
7338
  });
7129
7339
  const currmtime = curr.mtimeMs;
7130
7340
  if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
7131
- foreach(cont.listeners, (listener2) => listener2(path6, curr));
7341
+ foreach(cont.listeners, (listener2) => listener2(path7, curr));
7132
7342
  }
7133
7343
  })
7134
7344
  };
@@ -7153,13 +7363,13 @@ class NodeFsHandler {
7153
7363
  this.fsw = fsW;
7154
7364
  this._boundHandleError = (error) => fsW._handleError(error);
7155
7365
  }
7156
- _watchWithNodeFs(path6, listener) {
7366
+ _watchWithNodeFs(path7, listener) {
7157
7367
  const opts = this.fsw.options;
7158
- const directory = sp.dirname(path6);
7159
- const basename2 = sp.basename(path6);
7368
+ const directory = sp.dirname(path7);
7369
+ const basename2 = sp.basename(path7);
7160
7370
  const parent = this.fsw._getWatchedDir(directory);
7161
7371
  parent.add(basename2);
7162
- const absolutePath = sp.resolve(path6);
7372
+ const absolutePath = sp.resolve(path7);
7163
7373
  const options = {
7164
7374
  persistent: opts.persistent
7165
7375
  };
@@ -7169,12 +7379,12 @@ class NodeFsHandler {
7169
7379
  if (opts.usePolling) {
7170
7380
  const enableBin = opts.interval !== opts.binaryInterval;
7171
7381
  options.interval = enableBin && isBinaryPath(basename2) ? opts.binaryInterval : opts.interval;
7172
- closer = setFsWatchFileListener(path6, absolutePath, options, {
7382
+ closer = setFsWatchFileListener(path7, absolutePath, options, {
7173
7383
  listener,
7174
7384
  rawEmitter: this.fsw._emitRaw
7175
7385
  });
7176
7386
  } else {
7177
- closer = setFsWatchListener(path6, absolutePath, options, {
7387
+ closer = setFsWatchListener(path7, absolutePath, options, {
7178
7388
  listener,
7179
7389
  errHandler: this._boundHandleError,
7180
7390
  rawEmitter: this.fsw._emitRaw
@@ -7192,7 +7402,7 @@ class NodeFsHandler {
7192
7402
  let prevStats = stats;
7193
7403
  if (parent.has(basename2))
7194
7404
  return;
7195
- const listener = async (path6, newStats) => {
7405
+ const listener = async (path7, newStats) => {
7196
7406
  if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
7197
7407
  return;
7198
7408
  if (!newStats || newStats.mtimeMs === 0) {
@@ -7206,11 +7416,11 @@ class NodeFsHandler {
7206
7416
  this.fsw._emit(EV.CHANGE, file, newStats2);
7207
7417
  }
7208
7418
  if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
7209
- this.fsw._closeFile(path6);
7419
+ this.fsw._closeFile(path7);
7210
7420
  prevStats = newStats2;
7211
7421
  const closer2 = this._watchWithNodeFs(file, listener);
7212
7422
  if (closer2)
7213
- this.fsw._addPathCloser(path6, closer2);
7423
+ this.fsw._addPathCloser(path7, closer2);
7214
7424
  } else {
7215
7425
  prevStats = newStats2;
7216
7426
  }
@@ -7234,7 +7444,7 @@ class NodeFsHandler {
7234
7444
  }
7235
7445
  return closer;
7236
7446
  }
7237
- async _handleSymlink(entry, directory, path6, item) {
7447
+ async _handleSymlink(entry, directory, path7, item) {
7238
7448
  if (this.fsw.closed) {
7239
7449
  return;
7240
7450
  }
@@ -7244,7 +7454,7 @@ class NodeFsHandler {
7244
7454
  this.fsw._incrReadyCount();
7245
7455
  let linkPath;
7246
7456
  try {
7247
- linkPath = await fsrealpath(path6);
7457
+ linkPath = await fsrealpath(path7);
7248
7458
  } catch (e) {
7249
7459
  this.fsw._emitReady();
7250
7460
  return true;
@@ -7254,12 +7464,12 @@ class NodeFsHandler {
7254
7464
  if (dir.has(item)) {
7255
7465
  if (this.fsw._symlinkPaths.get(full) !== linkPath) {
7256
7466
  this.fsw._symlinkPaths.set(full, linkPath);
7257
- this.fsw._emit(EV.CHANGE, path6, entry.stats);
7467
+ this.fsw._emit(EV.CHANGE, path7, entry.stats);
7258
7468
  }
7259
7469
  } else {
7260
7470
  dir.add(item);
7261
7471
  this.fsw._symlinkPaths.set(full, linkPath);
7262
- this.fsw._emit(EV.ADD, path6, entry.stats);
7472
+ this.fsw._emit(EV.ADD, path7, entry.stats);
7263
7473
  }
7264
7474
  this.fsw._emitReady();
7265
7475
  return true;
@@ -7289,9 +7499,9 @@ class NodeFsHandler {
7289
7499
  return;
7290
7500
  }
7291
7501
  const item = entry.path;
7292
- let path6 = sp.join(directory, item);
7502
+ let path7 = sp.join(directory, item);
7293
7503
  current.add(item);
7294
- if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path6, item)) {
7504
+ if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path7, item)) {
7295
7505
  return;
7296
7506
  }
7297
7507
  if (this.fsw.closed) {
@@ -7300,8 +7510,8 @@ class NodeFsHandler {
7300
7510
  }
7301
7511
  if (item === target || !target && !previous.has(item)) {
7302
7512
  this.fsw._incrReadyCount();
7303
- path6 = sp.join(dir, sp.relative(dir, path6));
7304
- this._addToNodeFs(path6, initialAdd, wh, depth + 1);
7513
+ path7 = sp.join(dir, sp.relative(dir, path7));
7514
+ this._addToNodeFs(path7, initialAdd, wh, depth + 1);
7305
7515
  }
7306
7516
  }).on(EV.ERROR, this._boundHandleError);
7307
7517
  return new Promise((resolve2, reject) => {
@@ -7350,13 +7560,13 @@ class NodeFsHandler {
7350
7560
  }
7351
7561
  return closer;
7352
7562
  }
7353
- async _addToNodeFs(path6, initialAdd, priorWh, depth, target) {
7563
+ async _addToNodeFs(path7, initialAdd, priorWh, depth, target) {
7354
7564
  const ready = this.fsw._emitReady;
7355
- if (this.fsw._isIgnored(path6) || this.fsw.closed) {
7565
+ if (this.fsw._isIgnored(path7) || this.fsw.closed) {
7356
7566
  ready();
7357
7567
  return false;
7358
7568
  }
7359
- const wh = this.fsw._getWatchHelpers(path6);
7569
+ const wh = this.fsw._getWatchHelpers(path7);
7360
7570
  if (priorWh) {
7361
7571
  wh.filterPath = (entry) => priorWh.filterPath(entry);
7362
7572
  wh.filterDir = (entry) => priorWh.filterDir(entry);
@@ -7372,8 +7582,8 @@ class NodeFsHandler {
7372
7582
  const follow = this.fsw.options.followSymlinks;
7373
7583
  let closer;
7374
7584
  if (stats.isDirectory()) {
7375
- const absPath = sp.resolve(path6);
7376
- const targetPath = follow ? await fsrealpath(path6) : path6;
7585
+ const absPath = sp.resolve(path7);
7586
+ const targetPath = follow ? await fsrealpath(path7) : path7;
7377
7587
  if (this.fsw.closed)
7378
7588
  return;
7379
7589
  closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
@@ -7383,29 +7593,29 @@ class NodeFsHandler {
7383
7593
  this.fsw._symlinkPaths.set(absPath, targetPath);
7384
7594
  }
7385
7595
  } else if (stats.isSymbolicLink()) {
7386
- const targetPath = follow ? await fsrealpath(path6) : path6;
7596
+ const targetPath = follow ? await fsrealpath(path7) : path7;
7387
7597
  if (this.fsw.closed)
7388
7598
  return;
7389
7599
  const parent = sp.dirname(wh.watchPath);
7390
7600
  this.fsw._getWatchedDir(parent).add(wh.watchPath);
7391
7601
  this.fsw._emit(EV.ADD, wh.watchPath, stats);
7392
- closer = await this._handleDir(parent, stats, initialAdd, depth, path6, wh, targetPath);
7602
+ closer = await this._handleDir(parent, stats, initialAdd, depth, path7, wh, targetPath);
7393
7603
  if (this.fsw.closed)
7394
7604
  return;
7395
7605
  if (targetPath !== undefined) {
7396
- this.fsw._symlinkPaths.set(sp.resolve(path6), targetPath);
7606
+ this.fsw._symlinkPaths.set(sp.resolve(path7), targetPath);
7397
7607
  }
7398
7608
  } else {
7399
7609
  closer = this._handleFile(wh.watchPath, stats, initialAdd);
7400
7610
  }
7401
7611
  ready();
7402
7612
  if (closer)
7403
- this.fsw._addPathCloser(path6, closer);
7613
+ this.fsw._addPathCloser(path7, closer);
7404
7614
  return false;
7405
7615
  } catch (error) {
7406
7616
  if (this.fsw._handleError(error)) {
7407
7617
  ready();
7408
- return path6;
7618
+ return path7;
7409
7619
  }
7410
7620
  }
7411
7621
  }
@@ -7449,24 +7659,24 @@ function createPattern(matcher) {
7449
7659
  }
7450
7660
  return () => false;
7451
7661
  }
7452
- function normalizePath(path6) {
7453
- if (typeof path6 !== "string")
7662
+ function normalizePath(path7) {
7663
+ if (typeof path7 !== "string")
7454
7664
  throw new Error("string expected");
7455
- path6 = sp2.normalize(path6);
7456
- path6 = path6.replace(/\\/g, "/");
7665
+ path7 = sp2.normalize(path7);
7666
+ path7 = path7.replace(/\\/g, "/");
7457
7667
  let prepend = false;
7458
- if (path6.startsWith("//"))
7668
+ if (path7.startsWith("//"))
7459
7669
  prepend = true;
7460
- path6 = path6.replace(DOUBLE_SLASH_RE, "/");
7670
+ path7 = path7.replace(DOUBLE_SLASH_RE, "/");
7461
7671
  if (prepend)
7462
- path6 = "/" + path6;
7463
- return path6;
7672
+ path7 = "/" + path7;
7673
+ return path7;
7464
7674
  }
7465
7675
  function matchPatterns(patterns, testString, stats) {
7466
- const path6 = normalizePath(testString);
7676
+ const path7 = normalizePath(testString);
7467
7677
  for (let index = 0;index < patterns.length; index++) {
7468
7678
  const pattern = patterns[index];
7469
- if (pattern(path6, stats)) {
7679
+ if (pattern(path7, stats)) {
7470
7680
  return true;
7471
7681
  }
7472
7682
  }
@@ -7504,19 +7714,19 @@ var toUnix = (string) => {
7504
7714
  }
7505
7715
  return str;
7506
7716
  };
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));
7717
+ var normalizePathToUnix = (path7) => toUnix(sp2.normalize(toUnix(path7)));
7718
+ var normalizeIgnored = (cwd = "") => (path7) => {
7719
+ if (typeof path7 === "string") {
7720
+ return normalizePathToUnix(sp2.isAbsolute(path7) ? path7 : sp2.join(cwd, path7));
7511
7721
  } else {
7512
- return path6;
7722
+ return path7;
7513
7723
  }
7514
7724
  };
7515
- var getAbsolutePath = (path6, cwd) => {
7516
- if (sp2.isAbsolute(path6)) {
7517
- return path6;
7725
+ var getAbsolutePath = (path7, cwd) => {
7726
+ if (sp2.isAbsolute(path7)) {
7727
+ return path7;
7518
7728
  }
7519
- return sp2.join(cwd, path6);
7729
+ return sp2.join(cwd, path7);
7520
7730
  };
7521
7731
  var EMPTY_SET = Object.freeze(new Set);
7522
7732
 
@@ -7583,10 +7793,10 @@ class WatchHelper {
7583
7793
  dirParts;
7584
7794
  followSymlinks;
7585
7795
  statMethod;
7586
- constructor(path6, follow, fsw) {
7796
+ constructor(path7, follow, fsw) {
7587
7797
  this.fsw = fsw;
7588
- const watchPath = path6;
7589
- this.path = path6 = path6.replace(REPLACER_RE, "");
7798
+ const watchPath = path7;
7799
+ this.path = path7 = path7.replace(REPLACER_RE, "");
7590
7800
  this.watchPath = watchPath;
7591
7801
  this.fullWatchPath = sp2.resolve(watchPath);
7592
7802
  this.dirParts = [];
@@ -7717,20 +7927,20 @@ class FSWatcher extends EventEmitter2 {
7717
7927
  this._closePromise = undefined;
7718
7928
  let paths = unifyPaths(paths_);
7719
7929
  if (cwd) {
7720
- paths = paths.map((path6) => {
7721
- const absPath = getAbsolutePath(path6, cwd);
7930
+ paths = paths.map((path7) => {
7931
+ const absPath = getAbsolutePath(path7, cwd);
7722
7932
  return absPath;
7723
7933
  });
7724
7934
  }
7725
- paths.forEach((path6) => {
7726
- this._removeIgnoredPath(path6);
7935
+ paths.forEach((path7) => {
7936
+ this._removeIgnoredPath(path7);
7727
7937
  });
7728
7938
  this._userIgnored = undefined;
7729
7939
  if (!this._readyCount)
7730
7940
  this._readyCount = 0;
7731
7941
  this._readyCount += paths.length;
7732
- Promise.all(paths.map(async (path6) => {
7733
- const res = await this._nodeFsHandler._addToNodeFs(path6, !_internal, undefined, 0, _origAdd);
7942
+ Promise.all(paths.map(async (path7) => {
7943
+ const res = await this._nodeFsHandler._addToNodeFs(path7, !_internal, undefined, 0, _origAdd);
7734
7944
  if (res)
7735
7945
  this._emitReady();
7736
7946
  return res;
@@ -7749,17 +7959,17 @@ class FSWatcher extends EventEmitter2 {
7749
7959
  return this;
7750
7960
  const paths = unifyPaths(paths_);
7751
7961
  const { cwd } = this.options;
7752
- paths.forEach((path6) => {
7753
- if (!sp2.isAbsolute(path6) && !this._closers.has(path6)) {
7962
+ paths.forEach((path7) => {
7963
+ if (!sp2.isAbsolute(path7) && !this._closers.has(path7)) {
7754
7964
  if (cwd)
7755
- path6 = sp2.join(cwd, path6);
7756
- path6 = sp2.resolve(path6);
7965
+ path7 = sp2.join(cwd, path7);
7966
+ path7 = sp2.resolve(path7);
7757
7967
  }
7758
- this._closePath(path6);
7759
- this._addIgnoredPath(path6);
7760
- if (this._watched.has(path6)) {
7968
+ this._closePath(path7);
7969
+ this._addIgnoredPath(path7);
7970
+ if (this._watched.has(path7)) {
7761
7971
  this._addIgnoredPath({
7762
- path: path6,
7972
+ path: path7,
7763
7973
  recursive: true
7764
7974
  });
7765
7975
  }
@@ -7808,38 +8018,38 @@ class FSWatcher extends EventEmitter2 {
7808
8018
  if (event !== EVENTS.ERROR)
7809
8019
  this.emit(EVENTS.ALL, event, ...args);
7810
8020
  }
7811
- async _emit(event, path6, stats) {
8021
+ async _emit(event, path7, stats) {
7812
8022
  if (this.closed)
7813
8023
  return;
7814
8024
  const opts = this.options;
7815
8025
  if (isWindows)
7816
- path6 = sp2.normalize(path6);
8026
+ path7 = sp2.normalize(path7);
7817
8027
  if (opts.cwd)
7818
- path6 = sp2.relative(opts.cwd, path6);
7819
- const args = [path6];
8028
+ path7 = sp2.relative(opts.cwd, path7);
8029
+ const args = [path7];
7820
8030
  if (stats != null)
7821
8031
  args.push(stats);
7822
8032
  const awf = opts.awaitWriteFinish;
7823
8033
  let pw;
7824
- if (awf && (pw = this._pendingWrites.get(path6))) {
8034
+ if (awf && (pw = this._pendingWrites.get(path7))) {
7825
8035
  pw.lastChange = new Date;
7826
8036
  return this;
7827
8037
  }
7828
8038
  if (opts.atomic) {
7829
8039
  if (event === EVENTS.UNLINK) {
7830
- this._pendingUnlinks.set(path6, [event, ...args]);
8040
+ this._pendingUnlinks.set(path7, [event, ...args]);
7831
8041
  setTimeout(() => {
7832
- this._pendingUnlinks.forEach((entry, path7) => {
8042
+ this._pendingUnlinks.forEach((entry, path8) => {
7833
8043
  this.emit(...entry);
7834
8044
  this.emit(EVENTS.ALL, ...entry);
7835
- this._pendingUnlinks.delete(path7);
8045
+ this._pendingUnlinks.delete(path8);
7836
8046
  });
7837
8047
  }, typeof opts.atomic === "number" ? opts.atomic : 100);
7838
8048
  return this;
7839
8049
  }
7840
- if (event === EVENTS.ADD && this._pendingUnlinks.has(path6)) {
8050
+ if (event === EVENTS.ADD && this._pendingUnlinks.has(path7)) {
7841
8051
  event = EVENTS.CHANGE;
7842
- this._pendingUnlinks.delete(path6);
8052
+ this._pendingUnlinks.delete(path7);
7843
8053
  }
7844
8054
  }
7845
8055
  if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
@@ -7857,16 +8067,16 @@ class FSWatcher extends EventEmitter2 {
7857
8067
  this.emitWithAll(event, args);
7858
8068
  }
7859
8069
  };
7860
- this._awaitWriteFinish(path6, awf.stabilityThreshold, event, awfEmit);
8070
+ this._awaitWriteFinish(path7, awf.stabilityThreshold, event, awfEmit);
7861
8071
  return this;
7862
8072
  }
7863
8073
  if (event === EVENTS.CHANGE) {
7864
- const isThrottled = !this._throttle(EVENTS.CHANGE, path6, 50);
8074
+ const isThrottled = !this._throttle(EVENTS.CHANGE, path7, 50);
7865
8075
  if (isThrottled)
7866
8076
  return this;
7867
8077
  }
7868
8078
  if (opts.alwaysStat && stats === undefined && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
7869
- const fullPath = opts.cwd ? sp2.join(opts.cwd, path6) : path6;
8079
+ const fullPath = opts.cwd ? sp2.join(opts.cwd, path7) : path7;
7870
8080
  let stats2;
7871
8081
  try {
7872
8082
  stats2 = await stat3(fullPath);
@@ -7885,23 +8095,23 @@ class FSWatcher extends EventEmitter2 {
7885
8095
  }
7886
8096
  return error || this.closed;
7887
8097
  }
7888
- _throttle(actionType, path6, timeout) {
8098
+ _throttle(actionType, path7, timeout) {
7889
8099
  if (!this._throttled.has(actionType)) {
7890
8100
  this._throttled.set(actionType, new Map);
7891
8101
  }
7892
8102
  const action = this._throttled.get(actionType);
7893
8103
  if (!action)
7894
8104
  throw new Error("invalid throttle");
7895
- const actionPath = action.get(path6);
8105
+ const actionPath = action.get(path7);
7896
8106
  if (actionPath) {
7897
8107
  actionPath.count++;
7898
8108
  return false;
7899
8109
  }
7900
8110
  let timeoutObject;
7901
8111
  const clear = () => {
7902
- const item = action.get(path6);
8112
+ const item = action.get(path7);
7903
8113
  const count = item ? item.count : 0;
7904
- action.delete(path6);
8114
+ action.delete(path7);
7905
8115
  clearTimeout(timeoutObject);
7906
8116
  if (item)
7907
8117
  clearTimeout(item.timeoutObject);
@@ -7909,50 +8119,50 @@ class FSWatcher extends EventEmitter2 {
7909
8119
  };
7910
8120
  timeoutObject = setTimeout(clear, timeout);
7911
8121
  const thr = { timeoutObject, clear, count: 0 };
7912
- action.set(path6, thr);
8122
+ action.set(path7, thr);
7913
8123
  return thr;
7914
8124
  }
7915
8125
  _incrReadyCount() {
7916
8126
  return this._readyCount++;
7917
8127
  }
7918
- _awaitWriteFinish(path6, threshold, event, awfEmit) {
8128
+ _awaitWriteFinish(path7, threshold, event, awfEmit) {
7919
8129
  const awf = this.options.awaitWriteFinish;
7920
8130
  if (typeof awf !== "object")
7921
8131
  return;
7922
8132
  const pollInterval = awf.pollInterval;
7923
8133
  let timeoutHandler;
7924
- let fullPath = path6;
7925
- if (this.options.cwd && !sp2.isAbsolute(path6)) {
7926
- fullPath = sp2.join(this.options.cwd, path6);
8134
+ let fullPath = path7;
8135
+ if (this.options.cwd && !sp2.isAbsolute(path7)) {
8136
+ fullPath = sp2.join(this.options.cwd, path7);
7927
8137
  }
7928
8138
  const now = new Date;
7929
8139
  const writes = this._pendingWrites;
7930
8140
  function awaitWriteFinishFn(prevStat) {
7931
8141
  statcb(fullPath, (err, curStat) => {
7932
- if (err || !writes.has(path6)) {
8142
+ if (err || !writes.has(path7)) {
7933
8143
  if (err && err.code !== "ENOENT")
7934
8144
  awfEmit(err);
7935
8145
  return;
7936
8146
  }
7937
8147
  const now2 = Number(new Date);
7938
8148
  if (prevStat && curStat.size !== prevStat.size) {
7939
- writes.get(path6).lastChange = now2;
8149
+ writes.get(path7).lastChange = now2;
7940
8150
  }
7941
- const pw = writes.get(path6);
8151
+ const pw = writes.get(path7);
7942
8152
  const df = now2 - pw.lastChange;
7943
8153
  if (df >= threshold) {
7944
- writes.delete(path6);
8154
+ writes.delete(path7);
7945
8155
  awfEmit(undefined, curStat);
7946
8156
  } else {
7947
8157
  timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
7948
8158
  }
7949
8159
  });
7950
8160
  }
7951
- if (!writes.has(path6)) {
7952
- writes.set(path6, {
8161
+ if (!writes.has(path7)) {
8162
+ writes.set(path7, {
7953
8163
  lastChange: now,
7954
8164
  cancelWait: () => {
7955
- writes.delete(path6);
8165
+ writes.delete(path7);
7956
8166
  clearTimeout(timeoutHandler);
7957
8167
  return event;
7958
8168
  }
@@ -7960,8 +8170,8 @@ class FSWatcher extends EventEmitter2 {
7960
8170
  timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval);
7961
8171
  }
7962
8172
  }
7963
- _isIgnored(path6, stats) {
7964
- if (this.options.atomic && DOT_RE.test(path6))
8173
+ _isIgnored(path7, stats) {
8174
+ if (this.options.atomic && DOT_RE.test(path7))
7965
8175
  return true;
7966
8176
  if (!this._userIgnored) {
7967
8177
  const { cwd } = this.options;
@@ -7971,13 +8181,13 @@ class FSWatcher extends EventEmitter2 {
7971
8181
  const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
7972
8182
  this._userIgnored = anymatch(list, undefined);
7973
8183
  }
7974
- return this._userIgnored(path6, stats);
8184
+ return this._userIgnored(path7, stats);
7975
8185
  }
7976
- _isntIgnored(path6, stat4) {
7977
- return !this._isIgnored(path6, stat4);
8186
+ _isntIgnored(path7, stat4) {
8187
+ return !this._isIgnored(path7, stat4);
7978
8188
  }
7979
- _getWatchHelpers(path6) {
7980
- return new WatchHelper(path6, this.options.followSymlinks, this);
8189
+ _getWatchHelpers(path7) {
8190
+ return new WatchHelper(path7, this.options.followSymlinks, this);
7981
8191
  }
7982
8192
  _getWatchedDir(directory) {
7983
8193
  const dir = sp2.resolve(directory);
@@ -7991,57 +8201,57 @@ class FSWatcher extends EventEmitter2 {
7991
8201
  return Boolean(Number(stats.mode) & 256);
7992
8202
  }
7993
8203
  _remove(directory, item, isDirectory) {
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))
8204
+ const path7 = sp2.join(directory, item);
8205
+ const fullPath = sp2.resolve(path7);
8206
+ isDirectory = isDirectory != null ? isDirectory : this._watched.has(path7) || this._watched.has(fullPath);
8207
+ if (!this._throttle("remove", path7, 100))
7998
8208
  return;
7999
8209
  if (!isDirectory && this._watched.size === 1) {
8000
8210
  this.add(directory, item, true);
8001
8211
  }
8002
- const wp = this._getWatchedDir(path6);
8212
+ const wp = this._getWatchedDir(path7);
8003
8213
  const nestedDirectoryChildren = wp.getChildren();
8004
- nestedDirectoryChildren.forEach((nested) => this._remove(path6, nested));
8214
+ nestedDirectoryChildren.forEach((nested) => this._remove(path7, nested));
8005
8215
  const parent = this._getWatchedDir(directory);
8006
8216
  const wasTracked = parent.has(item);
8007
8217
  parent.remove(item);
8008
8218
  if (this._symlinkPaths.has(fullPath)) {
8009
8219
  this._symlinkPaths.delete(fullPath);
8010
8220
  }
8011
- let relPath = path6;
8221
+ let relPath = path7;
8012
8222
  if (this.options.cwd)
8013
- relPath = sp2.relative(this.options.cwd, path6);
8223
+ relPath = sp2.relative(this.options.cwd, path7);
8014
8224
  if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
8015
8225
  const event = this._pendingWrites.get(relPath).cancelWait();
8016
8226
  if (event === EVENTS.ADD)
8017
8227
  return;
8018
8228
  }
8019
- this._watched.delete(path6);
8229
+ this._watched.delete(path7);
8020
8230
  this._watched.delete(fullPath);
8021
8231
  const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
8022
- if (wasTracked && !this._isIgnored(path6))
8023
- this._emit(eventName, path6);
8024
- this._closePath(path6);
8232
+ if (wasTracked && !this._isIgnored(path7))
8233
+ this._emit(eventName, path7);
8234
+ this._closePath(path7);
8025
8235
  }
8026
- _closePath(path6) {
8027
- this._closeFile(path6);
8028
- const dir = sp2.dirname(path6);
8029
- this._getWatchedDir(dir).remove(sp2.basename(path6));
8236
+ _closePath(path7) {
8237
+ this._closeFile(path7);
8238
+ const dir = sp2.dirname(path7);
8239
+ this._getWatchedDir(dir).remove(sp2.basename(path7));
8030
8240
  }
8031
- _closeFile(path6) {
8032
- const closers = this._closers.get(path6);
8241
+ _closeFile(path7) {
8242
+ const closers = this._closers.get(path7);
8033
8243
  if (!closers)
8034
8244
  return;
8035
8245
  closers.forEach((closer) => closer());
8036
- this._closers.delete(path6);
8246
+ this._closers.delete(path7);
8037
8247
  }
8038
- _addPathCloser(path6, closer) {
8248
+ _addPathCloser(path7, closer) {
8039
8249
  if (!closer)
8040
8250
  return;
8041
- let list = this._closers.get(path6);
8251
+ let list = this._closers.get(path7);
8042
8252
  if (!list) {
8043
8253
  list = [];
8044
- this._closers.set(path6, list);
8254
+ this._closers.set(path7, list);
8045
8255
  }
8046
8256
  list.push(closer);
8047
8257
  }
@@ -8071,7 +8281,7 @@ function watch(paths, options = {}) {
8071
8281
  var chokidar_default = { watch, FSWatcher };
8072
8282
 
8073
8283
  // src/core/watcher.ts
8074
- import path6 from "node:path";
8284
+ import path7 from "node:path";
8075
8285
  function formatTime() {
8076
8286
  const now = new Date;
8077
8287
  const hours = String(now.getHours()).padStart(2, "0");
@@ -8104,7 +8314,7 @@ function getWatchPaths(operations) {
8104
8314
  return Array.from(paths);
8105
8315
  }
8106
8316
  async function handleFileChange(changedPath, state, options) {
8107
- const relPath = path6.relative(options.cwd || process.cwd(), changedPath);
8317
+ const relPath = path7.relative(options.cwd || process.cwd(), changedPath);
8108
8318
  if (!logger.isSilent() && !options.verbose) {
8109
8319
  console.log(`[${formatTime()}] Changed: ${relPath}`);
8110
8320
  }
@@ -8118,9 +8328,9 @@ async function handleFileChange(changedPath, state, options) {
8118
8328
  for (const op of affectedOps) {
8119
8329
  const result = await performMerge(op);
8120
8330
  if (result.success && result.changed) {
8121
- const baseFile = op.basePath ? path6.basename(op.basePath) : "";
8122
- const machineFile = path6.basename(op.machinePath);
8123
- const outputFile = path6.basename(op.outputPath);
8331
+ const baseFile = op.basePath ? path7.basename(op.basePath) : "";
8332
+ const machineFile = path7.basename(op.machinePath);
8333
+ const outputFile = path7.basename(op.outputPath);
8124
8334
  if (!logger.isSilent()) {
8125
8335
  if (baseFile) {
8126
8336
  console.log(`[${formatTime()}] Merged ${baseFile} + ${machineFile} → ${outputFile}`);
@@ -8131,7 +8341,7 @@ async function handleFileChange(changedPath, state, options) {
8131
8341
  } else if (!result.success && result.error) {
8132
8342
  logger.error(`Failed to merge: ${result.error.message}`);
8133
8343
  } else if (options.verbose && !result.changed) {
8134
- logger.info(`No changes needed for ${path6.basename(op.outputPath)}`);
8344
+ logger.info(`No changes needed for ${path7.basename(op.outputPath)}`);
8135
8345
  }
8136
8346
  }
8137
8347
  if (!logger.isSilent() && !options.verbose) {
@@ -8162,7 +8372,7 @@ async function startWatcher(machineName, options = {}) {
8162
8372
  if (!logger.isSilent()) {
8163
8373
  console.log(`✓ Watching ${watchPaths.length} file(s) for changes...`);
8164
8374
  for (const watchPath of watchPaths) {
8165
- console.log(` - ${path6.relative(cwd, watchPath)}`);
8375
+ console.log(` - ${path7.relative(cwd, watchPath)}`);
8166
8376
  }
8167
8377
  console.log("");
8168
8378
  }
@@ -8175,9 +8385,9 @@ async function startWatcher(machineName, options = {}) {
8175
8385
  }
8176
8386
  });
8177
8387
  watcher.on("change", (changedPath) => {
8178
- const absolutePath = path6.resolve(cwd, changedPath);
8388
+ const absolutePath = path7.resolve(cwd, changedPath);
8179
8389
  if (options.verbose) {
8180
- logger.info(`File changed: ${path6.relative(cwd, absolutePath)}`);
8390
+ logger.info(`File changed: ${path7.relative(cwd, absolutePath)}`);
8181
8391
  }
8182
8392
  const existingTimer = state.debounceTimers.get(absolutePath);
8183
8393
  if (existingTimer) {
@@ -8190,9 +8400,9 @@ async function startWatcher(machineName, options = {}) {
8190
8400
  state.debounceTimers.set(absolutePath, timer);
8191
8401
  });
8192
8402
  watcher.on("add", async (addedPath) => {
8193
- const absolutePath = path6.resolve(cwd, addedPath);
8403
+ const absolutePath = path7.resolve(cwd, addedPath);
8194
8404
  if (options.verbose) {
8195
- logger.info(`File added: ${path6.relative(cwd, absolutePath)}`);
8405
+ logger.info(`File added: ${path7.relative(cwd, absolutePath)}`);
8196
8406
  }
8197
8407
  const newOperations = await scanForMergeOperations(machineName, cwd);
8198
8408
  state.operations = newOperations;
@@ -8201,7 +8411,7 @@ async function startWatcher(machineName, options = {}) {
8201
8411
  });
8202
8412
  watcher.on("unlink", (deletedPath) => {
8203
8413
  if (options.verbose) {
8204
- const relPath = path6.relative(cwd, deletedPath);
8414
+ const relPath = path7.relative(cwd, deletedPath);
8205
8415
  logger.warn(`File deleted: ${relPath}`);
8206
8416
  logger.info("Run merge manually or restart watch to update operations");
8207
8417
  }
@@ -8222,17 +8432,17 @@ async function startWatcher(machineName, options = {}) {
8222
8432
  }
8223
8433
 
8224
8434
  // src/cli.ts
8225
- import fs3 from "node:fs/promises";
8226
- import path7 from "node:path";
8227
- import { fileURLToPath as fileURLToPath3 } from "node:url";
8435
+ import fs4 from "node:fs/promises";
8436
+ import path8 from "node:path";
8437
+ import { fileURLToPath as fileURLToPath4 } from "node:url";
8228
8438
  import { createInterface } from "node:readline";
8229
- var __filename2 = fileURLToPath3(import.meta.url);
8230
- var __dirname2 = path7.dirname(__filename2);
8439
+ var __filename3 = fileURLToPath4(import.meta.url);
8440
+ var __dirname3 = path8.dirname(__filename3);
8231
8441
  async function checkExistingOutputFiles(operations) {
8232
8442
  const existing = [];
8233
8443
  for (const op of operations) {
8234
8444
  try {
8235
- await fs3.access(op.outputPath);
8445
+ await fs4.access(op.outputPath);
8236
8446
  existing.push(op.outputPath);
8237
8447
  } catch {}
8238
8448
  }
@@ -8243,8 +8453,8 @@ async function checkTrackedOutputFiles(operations) {
8243
8453
  const cwd = process.cwd();
8244
8454
  for (const op of operations) {
8245
8455
  try {
8246
- await fs3.access(op.outputPath);
8247
- const relativePath = path7.relative(cwd, op.outputPath);
8456
+ await fs4.access(op.outputPath);
8457
+ const relativePath = path8.relative(cwd, op.outputPath);
8248
8458
  const isTracked = await isFileTrackedByGit(relativePath, cwd);
8249
8459
  if (isTracked) {
8250
8460
  tracked.push(op.outputPath);
@@ -8324,7 +8534,7 @@ async function handleInit(argv) {
8324
8534
  if (trackedFiles.length > 0 && !argv["no-gitignore"]) {
8325
8535
  logger.warn("⚠️ Warning: The following files will be overwritten and untracked from git:");
8326
8536
  for (const file of trackedFiles) {
8327
- logger.warn(` - ${path7.relative(process.cwd(), file)}`);
8537
+ logger.warn(` - ${path8.relative(process.cwd(), file)}`);
8328
8538
  }
8329
8539
  logger.info("");
8330
8540
  const confirmed = argv.yes || await promptConfirmation("Do you want to continue?");
@@ -8392,7 +8602,7 @@ async function handleMerge(argv) {
8392
8602
  if (trackedFiles.length > 0) {
8393
8603
  logger.warn("⚠️ Warning: The following files will be overwritten and untracked from git:");
8394
8604
  for (const file of trackedFiles) {
8395
- logger.warn(` - ${path7.relative(process.cwd(), file)}`);
8605
+ logger.warn(` - ${path8.relative(process.cwd(), file)}`);
8396
8606
  }
8397
8607
  logger.info("");
8398
8608
  const confirmed = argv.yes || await promptConfirmation("Do you want to continue?");
@@ -8430,11 +8640,11 @@ async function handleInfo(argv) {
8430
8640
  const operations = await scanForMergeOperations(machineName);
8431
8641
  console.log(`Machine name: ${machineName}`);
8432
8642
  console.log(`Repository: ${process.cwd()}`);
8433
- const { exec: exec2 } = await import("node:child_process");
8434
- const { promisify: promisify2 } = await import("node:util");
8435
- const execAsync2 = promisify2(exec2);
8643
+ const { exec: exec3 } = await import("node:child_process");
8644
+ const { promisify: promisify3 } = await import("node:util");
8645
+ const execAsync3 = promisify3(exec3);
8436
8646
  try {
8437
- const { stdout } = await execAsync2("git config --get core.hooksPath");
8647
+ const { stdout } = await execAsync3("git config --get core.hooksPath");
8438
8648
  const hooksPath = stdout.trim();
8439
8649
  if (hooksPath) {
8440
8650
  console.log(`Hooks method: core.hooksPath`);
@@ -8447,9 +8657,9 @@ async function handleInfo(argv) {
8447
8657
  }
8448
8658
  console.log(`Tracked patterns: ${operations.length}`);
8449
8659
  for (const op of operations) {
8450
- const baseName = op.basePath ? path7.basename(op.basePath) : "(none)";
8451
- const machineName2 = path7.basename(op.machinePath);
8452
- const outputName = path7.basename(op.outputPath);
8660
+ const baseName = op.basePath ? path8.basename(op.basePath) : "(none)";
8661
+ const machineName2 = path8.basename(op.machinePath);
8662
+ const outputName = path8.basename(op.outputPath);
8453
8663
  console.log(` - ${baseName} + ${machineName2} → ${outputName}`);
8454
8664
  }
8455
8665
  if (operations.length > 0) {
@@ -8459,7 +8669,7 @@ async function handleInfo(argv) {
8459
8669
  if (existingFiles.length > 0) {
8460
8670
  console.log("Existing output files:");
8461
8671
  for (const file of existingFiles) {
8462
- console.log(` - ${path7.relative(process.cwd(), file)}`);
8672
+ console.log(` - ${path8.relative(process.cwd(), file)}`);
8463
8673
  }
8464
8674
  }
8465
8675
  }
@@ -8542,8 +8752,8 @@ DOCUMENTATION:
8542
8752
  }
8543
8753
  async function showVersion() {
8544
8754
  try {
8545
- const packageJsonPath = path7.join(__dirname2, "../package.json");
8546
- const packageJson = JSON.parse(await fs3.readFile(packageJsonPath, "utf-8"));
8755
+ const packageJsonPath = path8.join(__dirname3, "../package.json");
8756
+ const packageJson = JSON.parse(await fs4.readFile(packageJsonPath, "utf-8"));
8547
8757
  console.log(packageJson.version);
8548
8758
  } catch {
8549
8759
  console.log("unknown");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "permachine",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "Automatically merge machine-specific config files with base configs using git hooks",
5
5
  "type": "module",
6
6
  "bin": {