@oh-my-pi/pi-utils 18.3.4 → 18.4.0
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/dist/types/dirs.d.ts +5 -0
- package/dist/types/postmortem.d.ts +9 -5
- package/package.json +2 -2
- package/src/dirs.ts +24 -4
- package/src/postmortem.ts +18 -6
package/dist/types/dirs.d.ts
CHANGED
|
@@ -228,6 +228,11 @@ export declare function getGithubCacheDbPath(): string;
|
|
|
228
228
|
* Honors `OMP_COMMIT_CACHE_DB` so tests and operators can isolate the cache.
|
|
229
229
|
*/
|
|
230
230
|
export declare function getCommitCacheDbPath(): string;
|
|
231
|
+
/**
|
|
232
|
+
* Get the judgment answer cache database path (~/.omp/cache/judgment-cache.db).
|
|
233
|
+
* Honors `OMP_JUDGMENT_CACHE_DB` so tests and operators can isolate the cache.
|
|
234
|
+
*/
|
|
235
|
+
export declare function getJudgmentCacheDbPath(): string;
|
|
231
236
|
/** Get the legacy Pi extension parse cache database path. */
|
|
232
237
|
export declare function getLegacyPiExtensionCacheDbPath(): string;
|
|
233
238
|
/**
|
|
@@ -126,13 +126,17 @@ export declare function registerStdioDisconnectHandling(): () => void;
|
|
|
126
126
|
* `--bytecode` builds. When a one-shot command awaits a promise that never
|
|
127
127
|
* settles and holds no live handle, the loop drains and Bun exits 0 without
|
|
128
128
|
* output: an unfinished command reported as success. `beforeExit` fires in
|
|
129
|
-
*
|
|
129
|
+
* that state; explicit exits (`process.exit`, {@link quit},
|
|
130
130
|
* {@link exitProcess}, the signal handlers) never emit it.
|
|
131
131
|
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
132
|
+
* `beforeExit` alone is not the verdict: on Windows Bun emits it while I/O is
|
|
133
|
+
* still in flight and then keeps running the loop, so a command that goes on
|
|
134
|
+
* to complete must keep its own exit code (#13470). The verdict is taken at
|
|
135
|
+
* `exit` instead, and only when the last `beforeExit` was final: an unref'd
|
|
136
|
+
* timer armed there runs only if the loop turns again, clearing the mark
|
|
137
|
+
* before a later explicit exit. Any later drain emits `beforeExit` again and
|
|
138
|
+
* re-arms it, so other `beforeExit` listeners (LSP shutdown) still run before
|
|
139
|
+
* the process exits 1.
|
|
136
140
|
*
|
|
137
141
|
* `describe` names what was running (e.g. the resolved subcommand) at report
|
|
138
142
|
* time; it must return only a command name, never user arguments.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oh-my-pi/pi-utils",
|
|
3
|
-
"version": "18.
|
|
3
|
+
"version": "18.4.0",
|
|
4
4
|
"description": "Shared utilities for pi packages",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"fmt": "oxfmt --no-error-on-unmatched-pattern 'src/**/*.{ts,tsx}' '{test,bench,examples,scripts}/**/*.ts' '*.ts'"
|
|
58
58
|
},
|
|
59
59
|
"dependencies": {
|
|
60
|
-
"@oh-my-pi/pi-natives": "18.
|
|
60
|
+
"@oh-my-pi/pi-natives": "18.4.0"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
63
|
"@types/bun": "^1.3.14"
|
package/src/dirs.ts
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
import * as fs from "node:fs";
|
|
15
15
|
import * as os from "node:os";
|
|
16
16
|
import * as path from "node:path";
|
|
17
|
+
import { expandWindowsLongPath } from "@oh-my-pi/pi-natives/path";
|
|
17
18
|
import { engines, version } from "../package.json" with { type: "json" };
|
|
18
19
|
import { isEnoent, isEnotdir } from "./fs-error";
|
|
19
20
|
|
|
@@ -154,6 +155,11 @@ function standardizeMacOSPath(p: string): string {
|
|
|
154
155
|
return p;
|
|
155
156
|
}
|
|
156
157
|
|
|
158
|
+
/** Keep the current directory's spelling while expanding Windows 8.3 aliases. */
|
|
159
|
+
function standardizeProjectPath(p: string): string {
|
|
160
|
+
return process.platform === "win32" ? expandWindowsLongPath(p) : standardizeMacOSPath(p);
|
|
161
|
+
}
|
|
162
|
+
|
|
157
163
|
export function resolveEquivalentPath(inputPath: string): string {
|
|
158
164
|
const resolvedPath = path.resolve(inputPath);
|
|
159
165
|
try {
|
|
@@ -200,29 +206,33 @@ let projectDir: string | undefined;
|
|
|
200
206
|
/** Get the project directory. */
|
|
201
207
|
export function getProjectDir(): string {
|
|
202
208
|
if (projectDir === undefined) {
|
|
209
|
+
let cwd: string | undefined;
|
|
203
210
|
try {
|
|
204
|
-
|
|
211
|
+
cwd = process.cwd();
|
|
205
212
|
} catch {
|
|
206
213
|
const candidates = [process.env.PWD, os.homedir(), os.tmpdir()];
|
|
207
214
|
for (const candidate of candidates) {
|
|
208
215
|
if (!candidate || !path.isAbsolute(candidate)) continue;
|
|
209
216
|
try {
|
|
210
217
|
process.chdir(candidate);
|
|
211
|
-
|
|
218
|
+
cwd = candidate;
|
|
212
219
|
break;
|
|
213
220
|
} catch {}
|
|
214
221
|
}
|
|
215
|
-
if (
|
|
222
|
+
if (cwd === undefined) {
|
|
216
223
|
throw new Error("Unable to determine an accessible working directory");
|
|
217
224
|
}
|
|
218
225
|
}
|
|
226
|
+
// Normalize outside the fallback: a native-addon failure is not an inaccessible cwd,
|
|
227
|
+
// and must surface as itself instead of relocating the process.
|
|
228
|
+
projectDir = standardizeProjectPath(cwd);
|
|
219
229
|
}
|
|
220
230
|
return projectDir;
|
|
221
231
|
}
|
|
222
232
|
|
|
223
233
|
/** Set the project directory. */
|
|
224
234
|
export function setProjectDir(dir: string): void {
|
|
225
|
-
const resolved =
|
|
235
|
+
const resolved = standardizeProjectPath(path.resolve(dir));
|
|
226
236
|
process.chdir(resolved);
|
|
227
237
|
projectDir = resolved;
|
|
228
238
|
}
|
|
@@ -787,6 +797,16 @@ export function getCommitCacheDbPath(): string {
|
|
|
787
797
|
return dirs.rootSubdir(path.join("cache", "commit-inference.db"), "cache");
|
|
788
798
|
}
|
|
789
799
|
|
|
800
|
+
/**
|
|
801
|
+
* Get the judgment answer cache database path (~/.omp/cache/judgment-cache.db).
|
|
802
|
+
* Honors `OMP_JUDGMENT_CACHE_DB` so tests and operators can isolate the cache.
|
|
803
|
+
*/
|
|
804
|
+
export function getJudgmentCacheDbPath(): string {
|
|
805
|
+
const override = process.env.OMP_JUDGMENT_CACHE_DB;
|
|
806
|
+
if (override) return override;
|
|
807
|
+
return dirs.rootSubdir(path.join("cache", "judgment-cache.db"), "cache");
|
|
808
|
+
}
|
|
809
|
+
|
|
790
810
|
/** Get the legacy Pi extension parse cache database path. */
|
|
791
811
|
export function getLegacyPiExtensionCacheDbPath(): string {
|
|
792
812
|
return dirs.rootSubdir(path.join("cache", "legacy-pi-extension-cache.db"), "cache");
|
package/src/postmortem.ts
CHANGED
|
@@ -376,26 +376,38 @@ export function registerStdioDisconnectHandling(): () => void {
|
|
|
376
376
|
* `--bytecode` builds. When a one-shot command awaits a promise that never
|
|
377
377
|
* settles and holds no live handle, the loop drains and Bun exits 0 without
|
|
378
378
|
* output: an unfinished command reported as success. `beforeExit` fires in
|
|
379
|
-
*
|
|
379
|
+
* that state; explicit exits (`process.exit`, {@link quit},
|
|
380
380
|
* {@link exitProcess}, the signal handlers) never emit it.
|
|
381
381
|
*
|
|
382
|
-
*
|
|
383
|
-
*
|
|
384
|
-
*
|
|
385
|
-
*
|
|
382
|
+
* `beforeExit` alone is not the verdict: on Windows Bun emits it while I/O is
|
|
383
|
+
* still in flight and then keeps running the loop, so a command that goes on
|
|
384
|
+
* to complete must keep its own exit code (#13470). The verdict is taken at
|
|
385
|
+
* `exit` instead, and only when the last `beforeExit` was final: an unref'd
|
|
386
|
+
* timer armed there runs only if the loop turns again, clearing the mark
|
|
387
|
+
* before a later explicit exit. Any later drain emits `beforeExit` again and
|
|
388
|
+
* re-arms it, so other `beforeExit` listeners (LSP shutdown) still run before
|
|
389
|
+
* the process exits 1.
|
|
386
390
|
*
|
|
387
391
|
* `describe` names what was running (e.g. the resolved subcommand) at report
|
|
388
392
|
* time; it must return only a command name, never user arguments.
|
|
389
393
|
*/
|
|
390
394
|
export function reportUnsettledEntry(work: Promise<unknown>, describe?: () => string | undefined): void {
|
|
391
395
|
let pending = true;
|
|
396
|
+
let drained = false;
|
|
392
397
|
const settled = (): void => {
|
|
393
398
|
pending = false;
|
|
394
399
|
};
|
|
395
400
|
// Observe both outcomes without claiming the rejection: the caller's `.catch` still owns it.
|
|
396
401
|
void work.then(settled, settled);
|
|
397
|
-
process.
|
|
402
|
+
process.on("beforeExit", () => {
|
|
398
403
|
if (!pending) return;
|
|
404
|
+
drained = true;
|
|
405
|
+
setTimeout(() => {
|
|
406
|
+
drained = false;
|
|
407
|
+
}, 0).unref();
|
|
408
|
+
});
|
|
409
|
+
process.once("exit", () => {
|
|
410
|
+
if (!pending || !drained) return;
|
|
399
411
|
const command = describe?.();
|
|
400
412
|
const subject = command ? `\`${APP_NAME} ${command}\`` : "command";
|
|
401
413
|
const message = `${subject} ended before completing: the event loop drained while it was still pending (rerun with PI_DEBUG_STARTUP=1 to see the last phase reached)`;
|