@oh-my-pi/pi-utils 18.1.18 → 18.1.20

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/CHANGELOG.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [18.1.19] - 2026-09-12
6
+
7
+ ### Added
8
+
9
+ - Added public `acquireFileLock()` and `FileLockHandle` APIs for holding and explicitly releasing exclusive OS-backed file locks.
10
+
11
+ ### Fixed
12
+
13
+ - Child-shell environment filtering now tolerates a removed process working directory by retaining the resolved project directory ([#11828](https://github.com/can1357/oh-my-pi/issues/11828)).
14
+
5
15
  ## [18.1.16] - 2026-09-09
6
16
 
7
17
  ### Fixed
@@ -40,6 +40,8 @@ export declare function normalizeProfileName(profile: string | undefined): strin
40
40
  * {@link normalizeProfileName} (which throws on a syntactically invalid value).
41
41
  */
42
42
  export declare function resolveProfileEnv(omp: string | undefined, pi: string | undefined): string | undefined;
43
+ /** Profile-independent config root (~/.omp), shared by every omp profile. */
44
+ export declare function getBaseConfigRoot(): string;
43
45
  export declare function resolveEquivalentPath(inputPath: string): string;
44
46
  export declare function normalizePathForComparison(inputPath: string): string;
45
47
  export declare function pathIsWithin(root: string, candidate: string): boolean;
@@ -6,8 +6,14 @@ export interface FileLockOptions {
6
6
  /** Delay between acquisition attempts. */
7
7
  retryDelayMs?: number;
8
8
  }
9
+ /** An exclusive OS-backed lease. Releasing an already released handle is safe. */
10
+ export interface FileLockHandle {
11
+ release(): void;
12
+ }
9
13
  declare function getLockPath(filePath: string): string;
10
14
  declare function tryAcquireLock(lockPath: string): NativeFileLock | null;
15
+ /** Acquire an exclusive lease; callers must release it when their operation ends. */
16
+ export declare function acquireFileLock(filePath: string, options?: FileLockOptions): Promise<FileLockHandle>;
11
17
  /** Run `fn` while holding an OS-backed exclusive lock for `filePath`. */
12
18
  export declare function withFileLock<T>(filePath: string, fn: () => Promise<T>, options?: FileLockOptions): Promise<T>;
13
19
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oh-my-pi/pi-utils",
3
- "version": "18.1.18",
3
+ "version": "18.1.20",
4
4
  "description": "Shared utilities for pi packages",
5
5
  "keywords": [
6
6
  "cli",
@@ -54,7 +54,7 @@
54
54
  "fmt": "oxfmt --no-error-on-unmatched-pattern 'src/**/*.{ts,tsx}' '{test,bench,examples,scripts}/**/*.ts' '*.ts'"
55
55
  },
56
56
  "dependencies": {
57
- "@oh-my-pi/pi-natives": "18.1.18"
57
+ "@oh-my-pi/pi-natives": "18.1.20"
58
58
  },
59
59
  "devDependencies": {
60
60
  "@types/bun": "^1.3.14"
package/src/dirs.ts CHANGED
@@ -107,7 +107,8 @@ function readProfileFromEnvSafe(): string | undefined {
107
107
  }
108
108
  }
109
109
 
110
- function getBaseConfigRoot(): string {
110
+ /** Profile-independent config root (~/.omp), shared by every omp profile. */
111
+ export function getBaseConfigRoot(): string {
111
112
  return path.join(os.homedir(), getConfigDirName());
112
113
  }
113
114
 
package/src/env.ts CHANGED
@@ -110,7 +110,7 @@ function expandDotenvValues(values: Record<string, string>, env: Record<string,
110
110
  /** Filters process env for child shells without launch-cwd dotenv values. */
111
111
  export function filterChildShellEnv(
112
112
  env: Record<string, string | undefined>,
113
- cwd: string = process.cwd(),
113
+ cwd: string = getProjectDir(),
114
114
  ): Record<string, string> {
115
115
  const runtimeLaunchEnvValues = env === Bun.env || env === process.env ? launchEnvValues : undefined;
116
116
  const result = filterProcessEnv(env);
package/src/file-lock.ts CHANGED
@@ -15,6 +15,11 @@ export interface FileLockOptions {
15
15
  retryDelayMs?: number;
16
16
  }
17
17
 
18
+ /** An exclusive OS-backed lease. Releasing an already released handle is safe. */
19
+ export interface FileLockHandle {
20
+ release(): void;
21
+ }
22
+
18
23
  const DEFAULT_OPTIONS: Required<FileLockOptions> = {
19
24
  retries: 50,
20
25
  retryDelayMs: 100,
@@ -29,7 +34,8 @@ function tryAcquireLock(lockPath: string): NativeFileLock | null {
29
34
  return lock.acquired ? lock : null;
30
35
  }
31
36
 
32
- async function acquireLock(filePath: string, options: FileLockOptions = {}): Promise<NativeFileLock> {
37
+ /** Acquire an exclusive lease; callers must release it when their operation ends. */
38
+ export async function acquireFileLock(filePath: string, options: FileLockOptions = {}): Promise<FileLockHandle> {
33
39
  const opts = { ...DEFAULT_OPTIONS, ...options };
34
40
  const lockPath = getLockPath(filePath);
35
41
 
@@ -48,7 +54,7 @@ export async function withFileLock<T>(
48
54
  fn: () => Promise<T>,
49
55
  options: FileLockOptions = {},
50
56
  ): Promise<T> {
51
- const lock = await acquireLock(filePath, options);
57
+ const lock = await acquireFileLock(filePath, options);
52
58
  try {
53
59
  return await fn();
54
60
  } finally {