@oh-my-pi/pi-utils 18.1.17 → 18.1.19

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
@@ -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.17",
3
+ "version": "18.1.19",
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.17"
57
+ "@oh-my-pi/pi-natives": "18.1.19"
58
58
  },
59
59
  "devDependencies": {
60
60
  "@types/bun": "^1.3.14"
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 {