@hydraharness/harness-home-paths 0.1.1-rc.10
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/LICENSE +21 -0
- package/README.md +28 -0
- package/lib/index.js +97 -0
- package/lib/invariant.js +23 -0
- package/lib/types/index.d.ts +64 -0
- package/lib/types/invariant.d.ts +16 -0
- package/package.json +42 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DeepSeek
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# @hydraharness/harness-home-paths
|
|
2
|
+
|
|
3
|
+
Shared filesystem path helpers for Hydra harness user data.
|
|
4
|
+
|
|
5
|
+
## Hydra home
|
|
6
|
+
|
|
7
|
+
`resolveHydraHome()` resolves the single-root Hydra harness home. Precedence, highest first: an explicit configured path, `$HYDRA_HOME`, then `~/.hydra`. The harness keeps all user data under one root.
|
|
8
|
+
|
|
9
|
+
`hydraHomePath(...segments)` joins child segments onto that resolved home with Node's platform path rules. With no segments it returns the home itself.
|
|
10
|
+
|
|
11
|
+
`hydraHomeDisplay()` names an active root symbolically for user-facing paths: `~/.hydra` for the default home, `$HYDRA_HOME` for any configured home. It never leaks an absolute machine path.
|
|
12
|
+
|
|
13
|
+
`HYDRA_HOME_DIR_NAME` owns the default user-data directory name: `.hydra`.
|
|
14
|
+
|
|
15
|
+
`defaultHydraHome()` returns the default Hydra harness home by joining the operating-system home directory with `.hydra`, using Node's platform path rules.
|
|
16
|
+
|
|
17
|
+
`expandHomePath()` expands `~`, `~/...`, and Windows-style `~\...` prefixes against the operating-system home directory. It leaves non-tilde paths and `~user/...` untouched.
|
|
18
|
+
|
|
19
|
+
## Watch paths
|
|
20
|
+
|
|
21
|
+
`canonicalizeWatchPath()` gives a native filesystem watcher one stable spelling of its target. It resolves the deepest existing ancestor through `fs.realpath()` and restores any missing suffix, so a file or directory may still be watched before it is created. In particular, Windows 8.3 aliases cannot be mixed with the long paths emitted by the native watcher backend.
|
|
22
|
+
|
|
23
|
+
This package is intentionally small and harness-dep-free so product packages can share user-data path conventions without depending on one another.
|
|
24
|
+
|
|
25
|
+
## Known Limitations and Deferred Work
|
|
26
|
+
|
|
27
|
+
- **Expansion is deliberately narrow** — only bare `~`, `~/...`, and `~\...` use the current operating-system home; named-user forms such as `~alice/...`, environment variables, and shell expressions remain unchanged.
|
|
28
|
+
- **Canonicalization reads but never mutates** — `canonicalizeWatchPath()` performs `realpath` probes and propagates errors other than absence; callers still own directory creation, permissions, and trust policy for the resulting path.
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { opendir, realpath } from "node:fs/promises";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
4
|
+
//#region lib/types/index.js
|
|
5
|
+
/**
|
|
6
|
+
* Shared filesystem path helpers for Hydra harness user data.
|
|
7
|
+
*
|
|
8
|
+
* @module @hydraharness/harness-home-paths
|
|
9
|
+
*/
|
|
10
|
+
/** Directory name for the default Hydra harness home under the OS home. */
|
|
11
|
+
const HYDRA_HOME_DIR_NAME = ".hydra";
|
|
12
|
+
/** Stable user-facing display form for the default Hydra harness home. */
|
|
13
|
+
const DEFAULT_HYDRA_HOME_DISPLAY = `~/${HYDRA_HOME_DIR_NAME}`;
|
|
14
|
+
/** Environment variable that overrides the default Hydra harness home. */
|
|
15
|
+
const HYDRA_HOME_ENV = "HYDRA_HOME";
|
|
16
|
+
/**
|
|
17
|
+
* Give a native filesystem watcher one canonical spelling of a path, even
|
|
18
|
+
* when its final components do not exist yet. The deepest existing ancestor
|
|
19
|
+
* is resolved through {@link realpath}; when a suffix is missing, that
|
|
20
|
+
* ancestor is also proved to be an enumerable directory before the suffix is
|
|
21
|
+
* restored. This prevents Windows from treating a regular-file ancestor as
|
|
22
|
+
* ordinary absence, and prevents short-name aliases from being mixed with
|
|
23
|
+
* long paths emitted by the native watcher backend.
|
|
24
|
+
* @param path - Watch target or root, resolved against the current directory.
|
|
25
|
+
* @returns the target with its existing ancestor canonicalized.
|
|
26
|
+
* @throws when ancestor traversal encounters an error other than absence, or
|
|
27
|
+
* the existing ancestor of a missing suffix is not an enumerable directory.
|
|
28
|
+
*/
|
|
29
|
+
async function canonicalizeWatchPath(path) {
|
|
30
|
+
let current = resolve(path);
|
|
31
|
+
const missing = [];
|
|
32
|
+
while (true) try {
|
|
33
|
+
const canonical = await realpath(current);
|
|
34
|
+
if (missing.length > 0) await (await opendir(canonical)).close();
|
|
35
|
+
return join(canonical, ...missing.reverse());
|
|
36
|
+
} catch (error) {
|
|
37
|
+
if (error.code !== "ENOENT") throw error;
|
|
38
|
+
const parent = dirname(current);
|
|
39
|
+
/* v8 ignore next -- a filesystem root exists, so traversal resolves before this guard */
|
|
40
|
+
if (parent === current) throw error;
|
|
41
|
+
missing.push(basename(current));
|
|
42
|
+
current = parent;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Resolve the default Hydra harness home using Node's platform path rules.
|
|
47
|
+
* @returns the absolute default harness home path.
|
|
48
|
+
*/
|
|
49
|
+
function defaultHydraHome() {
|
|
50
|
+
return join(homedir(), HYDRA_HOME_DIR_NAME);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Expand supported tilde prefixes against the operating-system home.
|
|
54
|
+
* @param path - configured path that may begin with `~`, `~/`, or `~\`.
|
|
55
|
+
* @returns the expanded path, or the original value when no supported prefix is present.
|
|
56
|
+
*/
|
|
57
|
+
function expandHomePath(path) {
|
|
58
|
+
if (path === "~") return homedir();
|
|
59
|
+
if (path.startsWith("~/") || path.startsWith("~\\")) return join(homedir(), path.slice(2));
|
|
60
|
+
return path;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Resolve the single-root Hydra harness home.
|
|
64
|
+
*
|
|
65
|
+
* Precedence, highest first: an explicit configured path, `$HYDRA_HOME`, then
|
|
66
|
+
* `~/.hydra`. The harness keeps all user data under one root. An empty or
|
|
67
|
+
* whitespace-only `$HYDRA_HOME` is treated as unset, so a blank override never
|
|
68
|
+
* resolves the home to the current working directory.
|
|
69
|
+
* @param configured - explicit harness-home override, which has highest precedence.
|
|
70
|
+
* @param env - environment mapping used to read `HYDRA_HOME`.
|
|
71
|
+
* @returns the normalized absolute harness home path.
|
|
72
|
+
*/
|
|
73
|
+
function resolveHydraHome(configured, env = process.env) {
|
|
74
|
+
const fromEnv = env[HYDRA_HOME_ENV];
|
|
75
|
+
return resolve(expandHomePath(configured ?? (fromEnv !== void 0 && fromEnv.trim().length > 0 ? fromEnv : defaultHydraHome())));
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Join path segments onto the resolved Hydra harness home.
|
|
79
|
+
* @param segments - path segments appended to the Harness home; an empty list returns the home itself.
|
|
80
|
+
* @returns the normalized absolute joined path.
|
|
81
|
+
*/
|
|
82
|
+
function hydraHomePath(...segments) {
|
|
83
|
+
return join(resolveHydraHome(), ...segments);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Describe a resolved harness home symbolically for user-facing display.
|
|
87
|
+
*
|
|
88
|
+
* It never returns an absolute machine path: the default home is labelled
|
|
89
|
+
* `~/.hydra`, and any configured home is labelled `$HYDRA_HOME`.
|
|
90
|
+
* @param resolvedHome - the absolute path returned by {@link resolveHydraHome}.
|
|
91
|
+
* @returns `~/.hydra` for the default home, otherwise `$HYDRA_HOME`.
|
|
92
|
+
*/
|
|
93
|
+
function hydraHomeDisplay(resolvedHome) {
|
|
94
|
+
return resolvedHome === resolve(defaultHydraHome()) ? DEFAULT_HYDRA_HOME_DISPLAY : `$${HYDRA_HOME_ENV}`;
|
|
95
|
+
}
|
|
96
|
+
//#endregion
|
|
97
|
+
export { DEFAULT_HYDRA_HOME_DISPLAY, HYDRA_HOME_DIR_NAME, HYDRA_HOME_ENV, canonicalizeWatchPath, defaultHydraHome, expandHomePath, hydraHomeDisplay, hydraHomePath, resolveHydraHome };
|
package/lib/invariant.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region lib/types/invariant.js
|
|
2
|
+
/**
|
|
3
|
+
* Package-owned invariant companion for `@hydraharness/harness-home-paths`.
|
|
4
|
+
* @module @hydraharness/harness-home-paths/invariant
|
|
5
|
+
*/
|
|
6
|
+
const PACKAGE_NAME = "@hydraharness/harness-home-paths";
|
|
7
|
+
/** Cordis companion plugin name. */
|
|
8
|
+
const name = "home-paths-invariant";
|
|
9
|
+
/** Service required before the companion can reserve package ownership. */
|
|
10
|
+
const inject = ["invariants"];
|
|
11
|
+
/**
|
|
12
|
+
* No runtime invariant: this pure utility owns no event stream or mutable runtime data; its value
|
|
13
|
+
* algebra is enforced by unit tests.
|
|
14
|
+
*/
|
|
15
|
+
const install = () => {};
|
|
16
|
+
/**
|
|
17
|
+
* Register this package's invariant companion.
|
|
18
|
+
* @param ctx - Cordis context carrying the invariant service.
|
|
19
|
+
* @returns the installed registration's disposer after setup succeeds.
|
|
20
|
+
*/
|
|
21
|
+
const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
|
|
22
|
+
//#endregion
|
|
23
|
+
export { apply, inject, name };
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared filesystem path helpers for Hydra harness user data.
|
|
3
|
+
*
|
|
4
|
+
* @module @hydraharness/harness-home-paths
|
|
5
|
+
*/
|
|
6
|
+
/** Directory name for the default Hydra harness home under the OS home. */
|
|
7
|
+
export declare const HYDRA_HOME_DIR_NAME = ".hydra";
|
|
8
|
+
/** Stable user-facing display form for the default Hydra harness home. */
|
|
9
|
+
export declare const DEFAULT_HYDRA_HOME_DISPLAY = "~/.hydra";
|
|
10
|
+
/** Environment variable that overrides the default Hydra harness home. */
|
|
11
|
+
export declare const HYDRA_HOME_ENV = "HYDRA_HOME";
|
|
12
|
+
/**
|
|
13
|
+
* Give a native filesystem watcher one canonical spelling of a path, even
|
|
14
|
+
* when its final components do not exist yet. The deepest existing ancestor
|
|
15
|
+
* is resolved through {@link realpath}; when a suffix is missing, that
|
|
16
|
+
* ancestor is also proved to be an enumerable directory before the suffix is
|
|
17
|
+
* restored. This prevents Windows from treating a regular-file ancestor as
|
|
18
|
+
* ordinary absence, and prevents short-name aliases from being mixed with
|
|
19
|
+
* long paths emitted by the native watcher backend.
|
|
20
|
+
* @param path - Watch target or root, resolved against the current directory.
|
|
21
|
+
* @returns the target with its existing ancestor canonicalized.
|
|
22
|
+
* @throws when ancestor traversal encounters an error other than absence, or
|
|
23
|
+
* the existing ancestor of a missing suffix is not an enumerable directory.
|
|
24
|
+
*/
|
|
25
|
+
export declare function canonicalizeWatchPath(path: string): Promise<string>;
|
|
26
|
+
/**
|
|
27
|
+
* Resolve the default Hydra harness home using Node's platform path rules.
|
|
28
|
+
* @returns the absolute default harness home path.
|
|
29
|
+
*/
|
|
30
|
+
export declare function defaultHydraHome(): string;
|
|
31
|
+
/**
|
|
32
|
+
* Expand supported tilde prefixes against the operating-system home.
|
|
33
|
+
* @param path - configured path that may begin with `~`, `~/`, or `~\`.
|
|
34
|
+
* @returns the expanded path, or the original value when no supported prefix is present.
|
|
35
|
+
*/
|
|
36
|
+
export declare function expandHomePath(path: string): string;
|
|
37
|
+
/**
|
|
38
|
+
* Resolve the single-root Hydra harness home.
|
|
39
|
+
*
|
|
40
|
+
* Precedence, highest first: an explicit configured path, `$HYDRA_HOME`, then
|
|
41
|
+
* `~/.hydra`. The harness keeps all user data under one root. An empty or
|
|
42
|
+
* whitespace-only `$HYDRA_HOME` is treated as unset, so a blank override never
|
|
43
|
+
* resolves the home to the current working directory.
|
|
44
|
+
* @param configured - explicit harness-home override, which has highest precedence.
|
|
45
|
+
* @param env - environment mapping used to read `HYDRA_HOME`.
|
|
46
|
+
* @returns the normalized absolute harness home path.
|
|
47
|
+
*/
|
|
48
|
+
export declare function resolveHydraHome(configured?: string, env?: Record<string, string | undefined>): string;
|
|
49
|
+
/**
|
|
50
|
+
* Join path segments onto the resolved Hydra harness home.
|
|
51
|
+
* @param segments - path segments appended to the Harness home; an empty list returns the home itself.
|
|
52
|
+
* @returns the normalized absolute joined path.
|
|
53
|
+
*/
|
|
54
|
+
export declare function hydraHomePath(...segments: string[]): string;
|
|
55
|
+
/**
|
|
56
|
+
* Describe a resolved harness home symbolically for user-facing display.
|
|
57
|
+
*
|
|
58
|
+
* It never returns an absolute machine path: the default home is labelled
|
|
59
|
+
* `~/.hydra`, and any configured home is labelled `$HYDRA_HOME`.
|
|
60
|
+
* @param resolvedHome - the absolute path returned by {@link resolveHydraHome}.
|
|
61
|
+
* @returns `~/.hydra` for the default home, otherwise `$HYDRA_HOME`.
|
|
62
|
+
*/
|
|
63
|
+
export declare function hydraHomeDisplay(resolvedHome: string): string;
|
|
64
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package-owned invariant companion for `@hydraharness/harness-home-paths`.
|
|
3
|
+
* @module @hydraharness/harness-home-paths/invariant
|
|
4
|
+
*/
|
|
5
|
+
import type { Context } from '@hydraharness/cordis';
|
|
6
|
+
/** Cordis companion plugin name. */
|
|
7
|
+
export declare const name = "home-paths-invariant";
|
|
8
|
+
/** Service required before the companion can reserve package ownership. */
|
|
9
|
+
export declare const inject: string[];
|
|
10
|
+
/**
|
|
11
|
+
* Register this package's invariant companion.
|
|
12
|
+
* @param ctx - Cordis context carrying the invariant service.
|
|
13
|
+
* @returns the installed registration's disposer after setup succeeds.
|
|
14
|
+
*/
|
|
15
|
+
export declare const apply: (ctx: Context) => Promise<() => void>;
|
|
16
|
+
//# sourceMappingURL=invariant.d.ts.map
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hydraharness/harness-home-paths",
|
|
3
|
+
"description": "Shared filesystem path helpers for the Hydra harness",
|
|
4
|
+
"version": "0.1.1-rc.10",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/MaiHongPhong2010/Hydra-Harness.git",
|
|
11
|
+
"directory": "packages/util/home-paths"
|
|
12
|
+
},
|
|
13
|
+
"type": "module",
|
|
14
|
+
"main": "lib/index.js",
|
|
15
|
+
"types": "lib/types/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./lib/types/index.d.ts",
|
|
19
|
+
"default": "./lib/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./invariant": {
|
|
22
|
+
"types": "./lib/types/invariant.d.ts",
|
|
23
|
+
"default": "./lib/invariant.js"
|
|
24
|
+
},
|
|
25
|
+
"./src/*": "./src/*",
|
|
26
|
+
"./package.json": "./package.json"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"lib/index.js",
|
|
30
|
+
"lib/invariant.js",
|
|
31
|
+
"lib/types/**/*.d.ts"
|
|
32
|
+
],
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"@hydraharness/harness-invariants": "^0.1.1-rc.10",
|
|
36
|
+
"@hydraharness/cordis": "^4.0.2"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@hydraharness/harness-invariants": "^0.1.1-rc.10",
|
|
40
|
+
"@hydraharness/cordis": "^4.0.2"
|
|
41
|
+
}
|
|
42
|
+
}
|