dotswitch 1.0.0 → 1.1.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.
package/README.md CHANGED
@@ -4,7 +4,10 @@
4
4
 
5
5
  [![CI](https://github.com/natterstefan/dotswitch/actions/workflows/ci.yml/badge.svg)](https://github.com/natterstefan/dotswitch/actions/workflows/ci.yml)
6
6
 
7
- Quickly switch between `.env` files. Copies `.env.<environment>` to `.env.local` (or a custom target) and tracks the active environment via a header comment. Works with Next.js, Vite, Remix, and any project that uses `.env` files.
7
+ Quickly switch between `.env` files. Copies
8
+ `.env.<environment>` to `.env.local` (or a custom target) and
9
+ tracks the active environment via a header comment. Works with
10
+ Next.js, Vite, Remix, and any project that uses `.env` files.
8
11
 
9
12
  ## Install
10
13
 
@@ -121,7 +124,9 @@ All commands support:
121
124
 
122
125
  ## Configuration
123
126
 
124
- Create a `.dotswitchrc.json` in your project root to customize behavior. Everything is optional — dotswitch works out of the box without a config file.
127
+ Create a `.dotswitchrc.json` in your project root to customize
128
+ behavior. Everything is optional — dotswitch works out of the
129
+ box without a config file.
125
130
 
126
131
  ```json
127
132
  {
@@ -143,7 +148,9 @@ Create a `.dotswitchrc.json` in your project root to customize behavior. Everyth
143
148
 
144
149
  ### Custom target file
145
150
 
146
- By default dotswitch writes to `.env.local`, but some frameworks use `.env` directly. Set the `target` field to change this:
151
+ By default dotswitch writes to `.env.local`, but some
152
+ frameworks use `.env` directly. Set the `target` field to
153
+ change this:
147
154
 
148
155
  ```json
149
156
  {
@@ -175,7 +182,8 @@ Automatically switch environments when you check out a branch.
175
182
  dotswitch hook install
176
183
  ```
177
184
 
178
- Now `git checkout staging/feat-login` will automatically run `dotswitch use staging`.
185
+ Now `git checkout staging/feat-login` will automatically run
186
+ `dotswitch use staging`.
179
187
 
180
188
  ### Patterns
181
189
 
@@ -203,6 +211,29 @@ dotswitch ls --path "./packages/*"
203
211
 
204
212
  Each directory is processed independently with labeled output.
205
213
 
214
+ ## Git worktree support
215
+
216
+ dotswitch works transparently in
217
+ [git worktrees](https://git-scm.com/docs/git-worktree). When
218
+ you run any command from a worktree, it automatically resolves
219
+ back to the main repo where your `.env.*` files and
220
+ `.dotswitchrc.json` live.
221
+
222
+ ```bash
223
+ # From a worktree, all commands operate on the main repo
224
+ cd /path/to/my-worktree
225
+ dotswitch ls # lists envs from the main repo
226
+ dotswitch use staging # switches in the main repo
227
+ dotswitch hook install # installs hook in the shared .git/hooks
228
+ ```
229
+
230
+ Explicit `--path` arguments are rebased automatically, so
231
+ monorepo globs also work from worktrees:
232
+
233
+ ```bash
234
+ dotswitch use staging --path "./apps/*"
235
+ ```
236
+
206
237
  ## How it works
207
238
 
208
239
  When you run `dotswitch use staging`, it:
@@ -211,7 +242,8 @@ When you run `dotswitch use staging`, it:
211
242
  2. Copies `.env.staging` to `.env.local`
212
243
  3. Prepends a `# dotswitch:staging` header to track the active environment
213
244
 
214
- The header comment is how `dotswitch ls` and `dotswitch current` know which environment is active.
245
+ The header comment is how `dotswitch ls` and
246
+ `dotswitch current` know which environment is active.
215
247
 
216
248
  ## Programmatic API
217
249
 
@@ -226,6 +258,7 @@ import {
226
258
  loadConfig,
227
259
  parseEnvContent,
228
260
  diffEnvMaps,
261
+ resolveProjectRoot,
229
262
  } from "dotswitch";
230
263
 
231
264
  const files = listEnvFiles(process.cwd());
@@ -233,6 +266,14 @@ const active = getActiveEnv(process.cwd());
233
266
  switchEnv(process.cwd(), "staging", { backup: true });
234
267
  ```
235
268
 
269
+ In worktree-aware scripts, resolve the project root first:
270
+
271
+ ```ts
272
+ const projectRoot = resolveProjectRoot(process.cwd());
273
+ const files = listEnvFiles(projectRoot);
274
+ switchEnv(projectRoot, "staging", { backup: true });
275
+ ```
276
+
236
277
  ## Requirements
237
278
 
238
279
  - Node.js >= 20
package/dist/cli.js CHANGED
@@ -1,10 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from "node:module";
3
- import { Command } from "commander";
4
3
  import fs from "node:fs";
5
4
  import path from "node:path";
5
+ import { Command } from "commander";
6
6
  import pc from "picocolors";
7
7
  import select from "@inquirer/select";
8
+ import { execFileSync } from "node:child_process";
8
9
 
9
10
  //#region src/lib/constants.ts
10
11
  const ENV_LOCAL = ".env.local";
@@ -54,7 +55,7 @@ const logger = {
54
55
  console.log(pc.cyan(message));
55
56
  },
56
57
  warn(message) {
57
- console.log(pc.yellow(`⚠ ${message}`));
58
+ console.error(pc.yellow(`⚠ ${message}`));
58
59
  },
59
60
  error(message) {
60
61
  console.error(pc.red(`✗ ${message}`));
@@ -421,6 +422,66 @@ function diffCommand(env1, env2, options) {
421
422
  }
422
423
  }
423
424
 
425
+ //#endregion
426
+ //#region src/lib/git.ts
427
+ function git(dir, ...args) {
428
+ try {
429
+ return execFileSync("git", [
430
+ "-C",
431
+ dir,
432
+ ...args
433
+ ], {
434
+ encoding: "utf-8",
435
+ stdio: [
436
+ "pipe",
437
+ "pipe",
438
+ "pipe"
439
+ ]
440
+ }).trim();
441
+ } catch (error) {
442
+ const stderr = error instanceof Error && "stderr" in error ? String(error.stderr).trim() : "";
443
+ if (stderr) logger.warn(`git ${args.join(" ")}: ${stderr}`);
444
+ return null;
445
+ }
446
+ }
447
+ /**
448
+ * Resolve the common (shared) git directory for a project.
449
+ * - Regular repos: returns <dir>/.git
450
+ * - Worktrees: returns the main repo's .git directory
451
+ * - Non-git directories: returns null
452
+ */
453
+ function resolveCommonGitDir(dir) {
454
+ const gitPath = path.join(dir, ".git");
455
+ try {
456
+ if (fs.statSync(gitPath).isDirectory()) return gitPath;
457
+ } catch {
458
+ return null;
459
+ }
460
+ const result = git(dir, "rev-parse", "--git-common-dir");
461
+ if (!result) return null;
462
+ return path.isAbsolute(result) ? result : path.resolve(dir, result);
463
+ }
464
+ /**
465
+ * Resolve the project root directory.
466
+ * In a worktree, this returns the main repo's root (parent of its .git dir).
467
+ * Otherwise returns the given directory as-is.
468
+ */
469
+ function resolveProjectRoot(dir) {
470
+ const gitPath = path.join(dir, ".git");
471
+ let stats;
472
+ try {
473
+ stats = fs.statSync(gitPath);
474
+ } catch {
475
+ return dir;
476
+ }
477
+ if (stats.isDirectory()) return dir;
478
+ if (stats.isFile()) {
479
+ const commonGitDir = resolveCommonGitDir(dir);
480
+ if (commonGitDir) return path.dirname(commonGitDir);
481
+ }
482
+ return dir;
483
+ }
484
+
424
485
  //#endregion
425
486
  //#region src/lib/hooks.ts
426
487
  const HOOK_FILENAME = "post-checkout";
@@ -436,8 +497,8 @@ fi
436
497
  ${HOOK_MARKER_END}`;
437
498
  }
438
499
  function getHooksDir(dir) {
439
- const gitDir = path.join(dir, ".git");
440
- if (!fs.existsSync(gitDir)) return null;
500
+ const gitDir = resolveCommonGitDir(dir);
501
+ if (!gitDir) return null;
441
502
  return path.join(gitDir, "hooks");
442
503
  }
443
504
  function installHook(dir) {
@@ -537,48 +598,79 @@ function hookBranchCommand(branch, options) {
537
598
  //#endregion
538
599
  //#region src/cli.ts
539
600
  const pkg = createRequire(import.meta.url)("../package.json");
601
+ /**
602
+ * Check whether a directory contains any `.env.*` source files
603
+ * (i.e. files that dotswitch would operate on, excluding standard non-source files).
604
+ */
605
+ function hasEnvFiles(dir) {
606
+ try {
607
+ return fs.readdirSync(dir).some((name) => name.startsWith(".env.") && !EXCLUDED_ENV_FILES.has(name));
608
+ } catch {
609
+ return false;
610
+ }
611
+ }
612
+ /**
613
+ * Resolve the effective path for a command.
614
+ * - No --path given: if in a worktree with local env files, operate locally;
615
+ * otherwise resolve to the main repo root.
616
+ * - Explicit --path: rebase it relative to the main repo when in a worktree,
617
+ * so glob patterns like "./apps/*" expand against the main repo.
618
+ */
619
+ function resolveCommandPath(explicitPath) {
620
+ const cwd = process.cwd();
621
+ const projectRoot = resolveProjectRoot(cwd);
622
+ if (!explicitPath) {
623
+ if (projectRoot !== cwd && hasEnvFiles(cwd)) return cwd;
624
+ return projectRoot;
625
+ }
626
+ if (projectRoot === cwd) return explicitPath;
627
+ const absolute = path.resolve(explicitPath);
628
+ const relative = path.relative(cwd, absolute);
629
+ return path.resolve(projectRoot, relative);
630
+ }
540
631
  const program = new Command();
541
632
  program.name("dotswitch").description("Quickly switch between .env files").version(pkg.version);
542
- program.command("use [env]").description("Switch to a .env.<env> file (interactive if no env given)").option("-f, --force", "skip confirmation if already active", false).option("--no-backup", "skip .env.local backup").option("-n, --dry-run", "show what would happen without making changes", false).option("-p, --path <dir>", "project directory", process.cwd()).option("--hook-branch <branch>", "internal: auto-switch by branch name").action(async (env, opts) => {
633
+ program.command("use [env]").description("Switch to a .env.<env> file (interactive if no env given)").option("-f, --force", "skip confirmation if already active", false).option("--no-backup", "skip .env.local backup").option("-n, --dry-run", "show what would happen without making changes", false).option("-p, --path <dir>", "project directory").option("--hook-branch <branch>", "internal: auto-switch by branch name").action(async (env, opts) => {
634
+ const projectPath = resolveCommandPath(opts.path);
543
635
  if (opts.hookBranch) {
544
- hookBranchCommand(opts.hookBranch, { path: opts.path });
636
+ hookBranchCommand(opts.hookBranch, { path: projectPath });
545
637
  return;
546
638
  }
547
639
  await useCommand(env, {
548
640
  force: opts.force,
549
641
  backup: opts.backup,
550
642
  dryRun: opts.dryRun,
551
- path: opts.path
643
+ path: projectPath
552
644
  });
553
645
  });
554
- program.command("ls").description("List available .env.* files").option("-p, --path <dir>", "project directory", process.cwd()).option("--json", "output as JSON", false).action((opts) => {
646
+ program.command("ls").description("List available .env.* files").option("-p, --path <dir>", "project directory").option("--json", "output as JSON", false).action((opts) => {
555
647
  lsCommand({
556
- path: opts.path,
648
+ path: resolveCommandPath(opts.path),
557
649
  json: opts.json
558
650
  });
559
651
  });
560
- program.command("current").description("Show the currently active environment").option("-p, --path <dir>", "project directory", process.cwd()).option("--json", "output as JSON", false).action((opts) => {
652
+ program.command("current").description("Show the currently active environment").option("-p, --path <dir>", "project directory").option("--json", "output as JSON", false).action((opts) => {
561
653
  currentCommand({
562
- path: opts.path,
654
+ path: resolveCommandPath(opts.path),
563
655
  json: opts.json
564
656
  });
565
657
  });
566
- program.command("restore").description("Restore .env.local from the backup file").option("-p, --path <dir>", "project directory", process.cwd()).action((opts) => {
567
- restoreCommand({ path: opts.path });
658
+ program.command("restore").description("Restore .env.local from the backup file").option("-p, --path <dir>", "project directory").action((opts) => {
659
+ restoreCommand({ path: resolveCommandPath(opts.path) });
568
660
  });
569
- program.command("diff <env1> [env2]").description("Compare keys between two env files (defaults: .env.local vs env1)").option("-p, --path <dir>", "project directory", process.cwd()).option("--show-values", "show actual values in the diff", false).option("--json", "output as JSON", false).action((env1, env2, opts) => {
661
+ program.command("diff <env1> [env2]").description("Compare keys between two env files (defaults: .env.local vs env1)").option("-p, --path <dir>", "project directory").option("--show-values", "show actual values in the diff", false).option("--json", "output as JSON", false).action((env1, env2, opts) => {
570
662
  diffCommand(env1, env2, {
571
- path: opts.path,
663
+ path: resolveCommandPath(opts.path),
572
664
  showValues: opts.showValues,
573
665
  json: opts.json
574
666
  });
575
667
  });
576
668
  const hookCmd = program.command("hook").description("Manage git post-checkout hook for auto-switching");
577
- hookCmd.command("install").description("Install the post-checkout git hook").option("-p, --path <dir>", "project directory", process.cwd()).action((opts) => {
578
- hookInstallCommand({ path: opts.path });
669
+ hookCmd.command("install").description("Install the post-checkout git hook").option("-p, --path <dir>", "project directory").action((opts) => {
670
+ hookInstallCommand({ path: resolveCommandPath(opts.path) });
579
671
  });
580
- hookCmd.command("remove").description("Remove the post-checkout git hook").option("-p, --path <dir>", "project directory", process.cwd()).action((opts) => {
581
- hookRemoveCommand({ path: opts.path });
672
+ hookCmd.command("remove").description("Remove the post-checkout git hook").option("-p, --path <dir>", "project directory").action((opts) => {
673
+ hookRemoveCommand({ path: resolveCommandPath(opts.path) });
582
674
  });
583
675
  program.parse();
584
676
 
package/dist/index.cjs CHANGED
@@ -32,6 +32,7 @@ let node_path = require("node:path");
32
32
  node_path = __toESM(node_path);
33
33
  let picocolors = require("picocolors");
34
34
  picocolors = __toESM(picocolors);
35
+ let node_child_process = require("node:child_process");
35
36
 
36
37
  //#region src/lib/constants.ts
37
38
  const TRACKER_PREFIX = "# dotswitch:";
@@ -80,7 +81,7 @@ const logger = {
80
81
  console.log(picocolors.default.cyan(message));
81
82
  },
82
83
  warn(message) {
83
- console.log(picocolors.default.yellow(`⚠ ${message}`));
84
+ console.error(picocolors.default.yellow(`⚠ ${message}`));
84
85
  },
85
86
  error(message) {
86
87
  console.error(picocolors.default.red(`✗ ${message}`));
@@ -229,6 +230,66 @@ function diffEnvMaps(from, to) {
229
230
  };
230
231
  }
231
232
 
233
+ //#endregion
234
+ //#region src/lib/git.ts
235
+ function git(dir, ...args) {
236
+ try {
237
+ return (0, node_child_process.execFileSync)("git", [
238
+ "-C",
239
+ dir,
240
+ ...args
241
+ ], {
242
+ encoding: "utf-8",
243
+ stdio: [
244
+ "pipe",
245
+ "pipe",
246
+ "pipe"
247
+ ]
248
+ }).trim();
249
+ } catch (error) {
250
+ const stderr = error instanceof Error && "stderr" in error ? String(error.stderr).trim() : "";
251
+ if (stderr) logger.warn(`git ${args.join(" ")}: ${stderr}`);
252
+ return null;
253
+ }
254
+ }
255
+ /**
256
+ * Resolve the common (shared) git directory for a project.
257
+ * - Regular repos: returns <dir>/.git
258
+ * - Worktrees: returns the main repo's .git directory
259
+ * - Non-git directories: returns null
260
+ */
261
+ function resolveCommonGitDir(dir) {
262
+ const gitPath = node_path.default.join(dir, ".git");
263
+ try {
264
+ if (node_fs.default.statSync(gitPath).isDirectory()) return gitPath;
265
+ } catch {
266
+ return null;
267
+ }
268
+ const result = git(dir, "rev-parse", "--git-common-dir");
269
+ if (!result) return null;
270
+ return node_path.default.isAbsolute(result) ? result : node_path.default.resolve(dir, result);
271
+ }
272
+ /**
273
+ * Resolve the project root directory.
274
+ * In a worktree, this returns the main repo's root (parent of its .git dir).
275
+ * Otherwise returns the given directory as-is.
276
+ */
277
+ function resolveProjectRoot(dir) {
278
+ const gitPath = node_path.default.join(dir, ".git");
279
+ let stats;
280
+ try {
281
+ stats = node_fs.default.statSync(gitPath);
282
+ } catch {
283
+ return dir;
284
+ }
285
+ if (stats.isDirectory()) return dir;
286
+ if (stats.isFile()) {
287
+ const commonGitDir = resolveCommonGitDir(dir);
288
+ if (commonGitDir) return node_path.default.dirname(commonGitDir);
289
+ }
290
+ return dir;
291
+ }
292
+
232
293
  //#endregion
233
294
  exports.addTrackerHeader = addTrackerHeader;
234
295
  exports.backupEnvLocal = backupEnvLocal;
@@ -242,5 +303,7 @@ exports.loadConfig = loadConfig;
242
303
  exports.parseEnvContent = parseEnvContent;
243
304
  exports.parseTrackerHeader = parseTrackerHeader;
244
305
  exports.removeTrackerHeader = removeTrackerHeader;
306
+ exports.resolveCommonGitDir = resolveCommonGitDir;
307
+ exports.resolveProjectRoot = resolveProjectRoot;
245
308
  exports.restoreEnvLocal = restoreEnvLocal;
246
309
  exports.switchEnv = switchEnv;
package/dist/index.d.cts CHANGED
@@ -66,4 +66,19 @@ interface EnvDiff {
66
66
  */
67
67
  declare function diffEnvMaps(from: Map<string, string>, to: Map<string, string>): EnvDiff;
68
68
  //#endregion
69
- export { type CommonOptions, type DotswitchConfig, type EnvDiff, type EnvFile, type UseOptions, addTrackerHeader, backupEnvLocal, createTrackerHeader, diffEnvMaps, getActiveEnv, getBackupFile, getTargetFile, listEnvFiles, loadConfig, parseEnvContent, parseTrackerHeader, removeTrackerHeader, restoreEnvLocal, switchEnv };
69
+ //#region src/lib/git.d.ts
70
+ /**
71
+ * Resolve the common (shared) git directory for a project.
72
+ * - Regular repos: returns <dir>/.git
73
+ * - Worktrees: returns the main repo's .git directory
74
+ * - Non-git directories: returns null
75
+ */
76
+ declare function resolveCommonGitDir(dir: string): string | null;
77
+ /**
78
+ * Resolve the project root directory.
79
+ * In a worktree, this returns the main repo's root (parent of its .git dir).
80
+ * Otherwise returns the given directory as-is.
81
+ */
82
+ declare function resolveProjectRoot(dir: string): string;
83
+ //#endregion
84
+ export { type CommonOptions, type DotswitchConfig, type EnvDiff, type EnvFile, type UseOptions, addTrackerHeader, backupEnvLocal, createTrackerHeader, diffEnvMaps, getActiveEnv, getBackupFile, getTargetFile, listEnvFiles, loadConfig, parseEnvContent, parseTrackerHeader, removeTrackerHeader, resolveCommonGitDir, resolveProjectRoot, restoreEnvLocal, switchEnv };
package/dist/index.d.mts CHANGED
@@ -66,4 +66,19 @@ interface EnvDiff {
66
66
  */
67
67
  declare function diffEnvMaps(from: Map<string, string>, to: Map<string, string>): EnvDiff;
68
68
  //#endregion
69
- export { type CommonOptions, type DotswitchConfig, type EnvDiff, type EnvFile, type UseOptions, addTrackerHeader, backupEnvLocal, createTrackerHeader, diffEnvMaps, getActiveEnv, getBackupFile, getTargetFile, listEnvFiles, loadConfig, parseEnvContent, parseTrackerHeader, removeTrackerHeader, restoreEnvLocal, switchEnv };
69
+ //#region src/lib/git.d.ts
70
+ /**
71
+ * Resolve the common (shared) git directory for a project.
72
+ * - Regular repos: returns <dir>/.git
73
+ * - Worktrees: returns the main repo's .git directory
74
+ * - Non-git directories: returns null
75
+ */
76
+ declare function resolveCommonGitDir(dir: string): string | null;
77
+ /**
78
+ * Resolve the project root directory.
79
+ * In a worktree, this returns the main repo's root (parent of its .git dir).
80
+ * Otherwise returns the given directory as-is.
81
+ */
82
+ declare function resolveProjectRoot(dir: string): string;
83
+ //#endregion
84
+ export { type CommonOptions, type DotswitchConfig, type EnvDiff, type EnvFile, type UseOptions, addTrackerHeader, backupEnvLocal, createTrackerHeader, diffEnvMaps, getActiveEnv, getBackupFile, getTargetFile, listEnvFiles, loadConfig, parseEnvContent, parseTrackerHeader, removeTrackerHeader, resolveCommonGitDir, resolveProjectRoot, restoreEnvLocal, switchEnv };
package/dist/index.mjs CHANGED
@@ -1,6 +1,7 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import pc from "picocolors";
4
+ import { execFileSync } from "node:child_process";
4
5
 
5
6
  //#region src/lib/constants.ts
6
7
  const TRACKER_PREFIX = "# dotswitch:";
@@ -49,7 +50,7 @@ const logger = {
49
50
  console.log(pc.cyan(message));
50
51
  },
51
52
  warn(message) {
52
- console.log(pc.yellow(`⚠ ${message}`));
53
+ console.error(pc.yellow(`⚠ ${message}`));
53
54
  },
54
55
  error(message) {
55
56
  console.error(pc.red(`✗ ${message}`));
@@ -199,4 +200,64 @@ function diffEnvMaps(from, to) {
199
200
  }
200
201
 
201
202
  //#endregion
202
- export { addTrackerHeader, backupEnvLocal, createTrackerHeader, diffEnvMaps, getActiveEnv, getBackupFile, getTargetFile, listEnvFiles, loadConfig, parseEnvContent, parseTrackerHeader, removeTrackerHeader, restoreEnvLocal, switchEnv };
203
+ //#region src/lib/git.ts
204
+ function git(dir, ...args) {
205
+ try {
206
+ return execFileSync("git", [
207
+ "-C",
208
+ dir,
209
+ ...args
210
+ ], {
211
+ encoding: "utf-8",
212
+ stdio: [
213
+ "pipe",
214
+ "pipe",
215
+ "pipe"
216
+ ]
217
+ }).trim();
218
+ } catch (error) {
219
+ const stderr = error instanceof Error && "stderr" in error ? String(error.stderr).trim() : "";
220
+ if (stderr) logger.warn(`git ${args.join(" ")}: ${stderr}`);
221
+ return null;
222
+ }
223
+ }
224
+ /**
225
+ * Resolve the common (shared) git directory for a project.
226
+ * - Regular repos: returns <dir>/.git
227
+ * - Worktrees: returns the main repo's .git directory
228
+ * - Non-git directories: returns null
229
+ */
230
+ function resolveCommonGitDir(dir) {
231
+ const gitPath = path.join(dir, ".git");
232
+ try {
233
+ if (fs.statSync(gitPath).isDirectory()) return gitPath;
234
+ } catch {
235
+ return null;
236
+ }
237
+ const result = git(dir, "rev-parse", "--git-common-dir");
238
+ if (!result) return null;
239
+ return path.isAbsolute(result) ? result : path.resolve(dir, result);
240
+ }
241
+ /**
242
+ * Resolve the project root directory.
243
+ * In a worktree, this returns the main repo's root (parent of its .git dir).
244
+ * Otherwise returns the given directory as-is.
245
+ */
246
+ function resolveProjectRoot(dir) {
247
+ const gitPath = path.join(dir, ".git");
248
+ let stats;
249
+ try {
250
+ stats = fs.statSync(gitPath);
251
+ } catch {
252
+ return dir;
253
+ }
254
+ if (stats.isDirectory()) return dir;
255
+ if (stats.isFile()) {
256
+ const commonGitDir = resolveCommonGitDir(dir);
257
+ if (commonGitDir) return path.dirname(commonGitDir);
258
+ }
259
+ return dir;
260
+ }
261
+
262
+ //#endregion
263
+ export { addTrackerHeader, backupEnvLocal, createTrackerHeader, diffEnvMaps, getActiveEnv, getBackupFile, getTargetFile, listEnvFiles, loadConfig, parseEnvContent, parseTrackerHeader, removeTrackerHeader, resolveCommonGitDir, resolveProjectRoot, restoreEnvLocal, switchEnv };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dotswitch",
3
- "version": "1.0.0",
3
+ "version": "1.1.1",
4
4
  "description": "Quickly switch between .env files",
5
5
  "type": "module",
6
6
  "bin": {