@oh-my-pi/pi-utils 18.4.10 → 18.4.11
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 +10 -0
- package/dist/types/dirs.d.ts +5 -1
- package/package.json +2 -2
- package/src/dirs.ts +68 -9
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [18.4.11] - 2026-10-02
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Added XDG-aware utility paths for skill descriptions and prediction state, with automatic adoption of legacy data when XDG locations are first resolved.
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- Fixed machine-global daemon runtime paths so brokers such as text prediction use the shared XDG state location across profiles and custom agent directories.
|
|
14
|
+
|
|
5
15
|
## [18.4.10] - 2026-10-02
|
|
6
16
|
|
|
7
17
|
### Added
|
package/dist/types/dirs.d.ts
CHANGED
|
@@ -277,6 +277,10 @@ export declare function getTinyModelsCacheDir(agentDir?: string): string;
|
|
|
277
277
|
export declare function getDocumentConversionCacheDir(agentDir?: string): string;
|
|
278
278
|
/** Get the composer speculative cache database (~/.omp/agent/cache/composer.db; XDG default: $XDG_CACHE_HOME/omp/cache/composer.db). */
|
|
279
279
|
export declare function getComposerCacheDbPath(agentDir?: string): string;
|
|
280
|
+
/** Get the skill descriptions database (~/.omp/agent/skill-descriptions.db; XDG default: $XDG_DATA_HOME/omp/skill-descriptions.db). */
|
|
281
|
+
export declare function getSkillDescriptionsDbPath(agentDir?: string): string;
|
|
282
|
+
/** Get the text-predict engine state directory (~/.omp/agent/predict/<method>; XDG default: $XDG_DATA_HOME/omp/predict/<method>). Adopts legacy engine state on first XDG resolution. */
|
|
283
|
+
export declare function getPredictStateDir(agentDir: string | undefined, method: string): string;
|
|
280
284
|
/** Get the sessions directory (~/.omp/agent/sessions). */
|
|
281
285
|
export declare function getSessionsDir(agentDir?: string): string;
|
|
282
286
|
/** Get the content-addressed blob store directory (~/.omp/agent/blobs). */
|
|
@@ -314,7 +318,7 @@ export declare function getTinyWorkerRuntimeDir(): string;
|
|
|
314
318
|
export declare function getDaemonRuntimeRoot(): string;
|
|
315
319
|
/** Get the daemon runtime directory for a project (~/.omp/run/daemons/<hash>; XDG default: $XDG_STATE_HOME/omp/run/daemons/<hash>). */
|
|
316
320
|
export declare function getDaemonRuntimeDir(projectDir: string): string;
|
|
317
|
-
/** Root directory containing every machine-global daemon service scope. */
|
|
321
|
+
/** Root directory containing every machine-global daemon service scope (~/.omp/run/daemons/global; XDG default: $XDG_STATE_HOME/omp/run/daemons/global). Shared across profiles. */
|
|
318
322
|
export declare function getGlobalDaemonRuntimeRoot(): string;
|
|
319
323
|
/** Get a profile-independent runtime directory for a machine-global daemon service. */
|
|
320
324
|
export declare function getGlobalDaemonRuntimeDir(service: string): string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oh-my-pi/pi-utils",
|
|
3
|
-
"version": "18.4.
|
|
3
|
+
"version": "18.4.11",
|
|
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.4.
|
|
60
|
+
"@oh-my-pi/pi-natives": "18.4.11"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
63
|
"@types/bun": "^1.3.14"
|
package/src/dirs.ts
CHANGED
|
@@ -334,6 +334,7 @@ class DirResolver {
|
|
|
334
334
|
// With XDG on Linux, they point to $XDG_*_HOME/omp/.
|
|
335
335
|
readonly #rootDirs: Record<XdgCategory, string>;
|
|
336
336
|
readonly #agentDirs: Record<XdgCategory, string>;
|
|
337
|
+
readonly #baseRootDirs: Record<XdgCategory, string>;
|
|
337
338
|
|
|
338
339
|
readonly #rootCache = new Map<string, string>();
|
|
339
340
|
readonly #agentCache = new Map<string, string>();
|
|
@@ -362,7 +363,8 @@ class DirResolver {
|
|
|
362
363
|
let xdgData: string | undefined;
|
|
363
364
|
let xdgState: string | undefined;
|
|
364
365
|
let xdgCache: string | undefined;
|
|
365
|
-
|
|
366
|
+
const xdgPlatform = process.platform === "linux" || process.platform === "darwin";
|
|
367
|
+
if (xdgPlatform && isDefault) {
|
|
366
368
|
const resolveIf = (envVar: string) => {
|
|
367
369
|
const value = process.env[envVar];
|
|
368
370
|
if (!value) return undefined;
|
|
@@ -370,14 +372,10 @@ class DirResolver {
|
|
|
370
372
|
const appRoot = path.join(value, APP_NAME);
|
|
371
373
|
if (profile) {
|
|
372
374
|
const profilePath = path.join(appRoot, "profiles", profile);
|
|
373
|
-
if (fs.existsSync(profilePath))
|
|
374
|
-
return profilePath;
|
|
375
|
-
}
|
|
375
|
+
if (fs.existsSync(profilePath)) return profilePath;
|
|
376
376
|
return undefined;
|
|
377
377
|
}
|
|
378
|
-
|
|
379
|
-
return appRoot;
|
|
380
|
-
}
|
|
378
|
+
return fs.existsSync(appRoot) ? appRoot : undefined;
|
|
381
379
|
} catch {}
|
|
382
380
|
return undefined;
|
|
383
381
|
};
|
|
@@ -386,6 +384,22 @@ class DirResolver {
|
|
|
386
384
|
xdgCache = resolveIf("XDG_CACHE_HOME");
|
|
387
385
|
}
|
|
388
386
|
|
|
387
|
+
// XDG choice for machine-global paths (daemon scopes shared by every
|
|
388
|
+
// process): keyed only on the base app root, independent of both the
|
|
389
|
+
// profile and any agent-dir override, so every omp process on the machine
|
|
390
|
+
// agrees on one location. These hold process-scoped runtime state
|
|
391
|
+
// (sockets, tokens), so there is no migration to protect.
|
|
392
|
+
const resolveBase = (envVar: string) => {
|
|
393
|
+
if (!xdgPlatform) return undefined;
|
|
394
|
+
const value = process.env[envVar];
|
|
395
|
+
if (!value) return undefined;
|
|
396
|
+
try {
|
|
397
|
+
const appRoot = path.join(value, APP_NAME);
|
|
398
|
+
return fs.existsSync(appRoot) ? appRoot : undefined;
|
|
399
|
+
} catch {}
|
|
400
|
+
return undefined;
|
|
401
|
+
};
|
|
402
|
+
|
|
389
403
|
this.#rootDirs = {
|
|
390
404
|
data: xdgData ?? this.configRoot,
|
|
391
405
|
state: xdgState ?? this.configRoot,
|
|
@@ -397,6 +411,17 @@ class DirResolver {
|
|
|
397
411
|
state: xdgState ?? this.agentDir,
|
|
398
412
|
cache: xdgCache ?? this.agentDir,
|
|
399
413
|
};
|
|
414
|
+
const baseRoot = getBaseConfigRoot();
|
|
415
|
+
this.#baseRootDirs = {
|
|
416
|
+
data: resolveBase("XDG_DATA_HOME") ?? baseRoot,
|
|
417
|
+
state: resolveBase("XDG_STATE_HOME") ?? baseRoot,
|
|
418
|
+
cache: resolveBase("XDG_CACHE_HOME") ?? baseRoot,
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/** Profile-independent config-root subdirectory, with optional XDG override. Shared across profiles. */
|
|
423
|
+
baseRootSubdir(subdir: string, xdg?: XdgCategory): string {
|
|
424
|
+
return path.join(xdg ? this.#baseRootDirs[xdg] : getBaseConfigRoot(), subdir);
|
|
400
425
|
}
|
|
401
426
|
|
|
402
427
|
/** Config-root subdirectory, with optional XDG override. */
|
|
@@ -915,6 +940,17 @@ export function getDocumentConversionCacheDir(agentDir?: string): string {
|
|
|
915
940
|
export function getComposerCacheDbPath(agentDir?: string): string {
|
|
916
941
|
return dirs.agentSubdir(agentDir, path.join("cache", "composer.db"), "cache");
|
|
917
942
|
}
|
|
943
|
+
/** Get the skill descriptions database (~/.omp/agent/skill-descriptions.db; XDG default: $XDG_DATA_HOME/omp/skill-descriptions.db). */
|
|
944
|
+
export function getSkillDescriptionsDbPath(agentDir?: string): string {
|
|
945
|
+
return dirs.agentSubdir(agentDir, "skill-descriptions.db", "data");
|
|
946
|
+
}
|
|
947
|
+
/** Get the text-predict engine state directory (~/.omp/agent/predict/<method>; XDG default: $XDG_DATA_HOME/omp/predict/<method>). Adopts legacy engine state on first XDG resolution. */
|
|
948
|
+
export function getPredictStateDir(agentDir: string | undefined, method: string): string {
|
|
949
|
+
const subdir = path.join("predict", method);
|
|
950
|
+
const stateDir = dirs.agentSubdir(agentDir, subdir, "data");
|
|
951
|
+
adoptLegacyDir(path.join(agentDir ?? dirs.agentDir, subdir), stateDir);
|
|
952
|
+
return stateDir;
|
|
953
|
+
}
|
|
918
954
|
|
|
919
955
|
/** Get the sessions directory (~/.omp/agent/sessions). */
|
|
920
956
|
export function getSessionsDir(agentDir?: string): string {
|
|
@@ -1000,6 +1036,29 @@ function adoptLegacyFile(legacyPath: string, targetPath: string): void {
|
|
|
1000
1036
|
}
|
|
1001
1037
|
}
|
|
1002
1038
|
|
|
1039
|
+
/**
|
|
1040
|
+
* Best-effort one-time copy of a legacy directory to its redirected XDG
|
|
1041
|
+
* location, so learned state survives enabling XDG. The copy is staged next to
|
|
1042
|
+
* the target and renamed into place, so a reader never sees a partial tree and
|
|
1043
|
+
* a concurrent adopter cannot clobber a finished one. The legacy directory is
|
|
1044
|
+
* left in place for older omp versions sharing the profile.
|
|
1045
|
+
*/
|
|
1046
|
+
function adoptLegacyDir(legacyPath: string, targetPath: string): void {
|
|
1047
|
+
if (targetPath === legacyPath) return;
|
|
1048
|
+
const staging = `${targetPath}.adopt-${process.pid}`;
|
|
1049
|
+
try {
|
|
1050
|
+
if (fs.existsSync(targetPath) || !fs.statSync(legacyPath, { throwIfNoEntry: false })?.isDirectory()) return;
|
|
1051
|
+
fs.mkdirSync(path.dirname(targetPath), { recursive: true });
|
|
1052
|
+
fs.rmSync(staging, { recursive: true, force: true });
|
|
1053
|
+
fs.cpSync(legacyPath, staging, { recursive: true });
|
|
1054
|
+
fs.renameSync(staging, targetPath);
|
|
1055
|
+
} catch {
|
|
1056
|
+
// Opportunistic: a lost race or unwritable XDG dir falls back to fresh
|
|
1057
|
+
// state at the new path — the pre-adoption behavior.
|
|
1058
|
+
fs.rmSync(staging, { recursive: true, force: true });
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1003
1062
|
/** Get the secret placeholder key path (~/.omp/agent/secret-placeholder.key; XDG default: $XDG_STATE_HOME/omp/secret-placeholder.key). Adopts a legacy key on first XDG resolution. */
|
|
1004
1063
|
export function getSecretPlaceholderKeyPath(): string {
|
|
1005
1064
|
const keyPath = dirs.agentSubdir(undefined, "secret-placeholder.key", "state");
|
|
@@ -1023,9 +1082,9 @@ export function getDaemonRuntimeDir(projectDir: string): string {
|
|
|
1023
1082
|
return path.join(getDaemonRuntimeRoot(), key);
|
|
1024
1083
|
}
|
|
1025
1084
|
|
|
1026
|
-
/** Root directory containing every machine-global daemon service scope. */
|
|
1085
|
+
/** Root directory containing every machine-global daemon service scope (~/.omp/run/daemons/global; XDG default: $XDG_STATE_HOME/omp/run/daemons/global). Shared across profiles. */
|
|
1027
1086
|
export function getGlobalDaemonRuntimeRoot(): string {
|
|
1028
|
-
return path.join(
|
|
1087
|
+
return dirs.baseRootSubdir(path.join("run", "daemons", "global"), "state");
|
|
1029
1088
|
}
|
|
1030
1089
|
|
|
1031
1090
|
/** Get a profile-independent runtime directory for a machine-global daemon service. */
|