@cleocode/paths 2026.5.26

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 CLEO Contributors
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.
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Cross-platform absolute path detection.
3
+ *
4
+ * Recognises POSIX absolute paths (`/...`), Windows drive letters (`C:\...`,
5
+ * `D:/...`), and UNC paths (`\\server\share`). Used in path-resolution code
6
+ * that needs to short-circuit when given an already-absolute path without
7
+ * importing the heavier `node:path#isAbsolute`.
8
+ *
9
+ * @task T1883
10
+ */
11
+ /**
12
+ * Check if a path is absolute on any supported platform.
13
+ *
14
+ * @param path - Filesystem path to check.
15
+ * @returns `true` for POSIX absolute, Windows drive-rooted, or UNC paths.
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * isAbsolutePath('/usr/bin'); // true
20
+ * isAbsolutePath('C:\\Users'); // true
21
+ * isAbsolutePath('\\\\srv\\sh'); // true
22
+ * isAbsolutePath('./relative'); // false
23
+ * ```
24
+ *
25
+ * @public
26
+ */
27
+ export declare function isAbsolutePath(path: string): boolean;
28
+ //# sourceMappingURL=abs-path.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"abs-path.d.ts","sourceRoot":"","sources":["../src/abs-path.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAKpD"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Cross-platform absolute path detection.
3
+ *
4
+ * Recognises POSIX absolute paths (`/...`), Windows drive letters (`C:\...`,
5
+ * `D:/...`), and UNC paths (`\\server\share`). Used in path-resolution code
6
+ * that needs to short-circuit when given an already-absolute path without
7
+ * importing the heavier `node:path#isAbsolute`.
8
+ *
9
+ * @task T1883
10
+ */
11
+ const WINDOWS_DRIVE_RE = /^[A-Za-z]:[\\/]/;
12
+ /**
13
+ * Check if a path is absolute on any supported platform.
14
+ *
15
+ * @param path - Filesystem path to check.
16
+ * @returns `true` for POSIX absolute, Windows drive-rooted, or UNC paths.
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * isAbsolutePath('/usr/bin'); // true
21
+ * isAbsolutePath('C:\\Users'); // true
22
+ * isAbsolutePath('\\\\srv\\sh'); // true
23
+ * isAbsolutePath('./relative'); // false
24
+ * ```
25
+ *
26
+ * @public
27
+ */
28
+ export function isAbsolutePath(path) {
29
+ if (path.startsWith('/'))
30
+ return true;
31
+ if (WINDOWS_DRIVE_RE.test(path))
32
+ return true;
33
+ if (path.startsWith('\\\\'))
34
+ return true;
35
+ return false;
36
+ }
37
+ //# sourceMappingURL=abs-path.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"abs-path.js","sourceRoot":"","sources":["../src/abs-path.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,gBAAgB,GAAG,iBAAiB,CAAC;AAE3C;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACtC,IAAI,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7C,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IACzC,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * CLEO-bound platform path helpers.
3
+ *
4
+ * Pre-binds {@link createPlatformPathsResolver} to `(appName='cleo', homeEnvVar='CLEO_HOME')`
5
+ * and exposes the cleo-specific helpers every other CLEO package needs:
6
+ * `getCleoHome`, `getCleoPlatformPaths`, `getCleoSystemInfo`, and
7
+ * `getCleoTemplatesTildePath`.
8
+ *
9
+ * @task T1883
10
+ */
11
+ import { type PlatformPaths, type SystemInfo } from './platform-paths.js';
12
+ /**
13
+ * Get OS-appropriate paths for CLEO's global directories.
14
+ *
15
+ * Linux: `~/.local/share/cleo` | macOS: `~/Library/Application Support/cleo`
16
+ * Windows: `%LOCALAPPDATA%\cleo\Data`
17
+ *
18
+ * The `CLEO_HOME` env var overrides the `data` field. Read fresh on every call.
19
+ *
20
+ * @public
21
+ */
22
+ export declare function getCleoPlatformPaths(): PlatformPaths;
23
+ /**
24
+ * Get the absolute path to CLEO's global data directory.
25
+ *
26
+ * Equivalent to `getCleoPlatformPaths().data` — exposed as a stable named
27
+ * helper because `getCleoHome()` is the most common consumer call.
28
+ *
29
+ * @public
30
+ */
31
+ export declare function getCleoHome(): string;
32
+ /**
33
+ * Get a cached system information snapshot scoped to CLEO.
34
+ *
35
+ * Includes platform, architecture, hostname, Node version, and resolved
36
+ * CLEO paths. Captured once per process and reused — invalidate via
37
+ * {@link _resetCleoPlatformPathsCache} in tests if needed.
38
+ *
39
+ * @public
40
+ */
41
+ export declare function getCleoSystemInfo(): SystemInfo;
42
+ /**
43
+ * Get the CLEO templates directory as a tilde-prefixed path for use in
44
+ * `@`-references (AGENTS.md, CLAUDE.md, etc.). Cross-platform: replaces
45
+ * the user's home directory with `~` so the reference resolves consistently
46
+ * when an LLM provider expands `~` at runtime.
47
+ *
48
+ * @returns Tilde-prefixed path like `"~/.local/share/cleo/templates"` on Linux
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * const ref = `@${getCleoTemplatesTildePath()}/CLEO-INJECTION.md`;
53
+ * // "@~/.local/share/cleo/templates/CLEO-INJECTION.md" (Linux)
54
+ * ```
55
+ *
56
+ * @public
57
+ */
58
+ export declare function getCleoTemplatesTildePath(): string;
59
+ /**
60
+ * Invalidate the cached CLEO system info snapshot. Use in tests after
61
+ * mutating `CLEO_HOME` or related env vars.
62
+ *
63
+ * @internal
64
+ */
65
+ export declare function _resetCleoPlatformPathsCache(): void;
66
+ //# sourceMappingURL=cleo-paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cleo-paths.d.ts","sourceRoot":"","sources":["../src/cleo-paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,UAAU,EAChB,MAAM,qBAAqB,CAAC;AAM7B;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,IAAI,aAAa,CAEpD;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,IAAI,UAAU,CAE9C;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,yBAAyB,IAAI,MAAM,CAQlD;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,IAAI,IAAI,CAEnD"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * CLEO-bound platform path helpers.
3
+ *
4
+ * Pre-binds {@link createPlatformPathsResolver} to `(appName='cleo', homeEnvVar='CLEO_HOME')`
5
+ * and exposes the cleo-specific helpers every other CLEO package needs:
6
+ * `getCleoHome`, `getCleoPlatformPaths`, `getCleoSystemInfo`, and
7
+ * `getCleoTemplatesTildePath`.
8
+ *
9
+ * @task T1883
10
+ */
11
+ import { homedir } from 'node:os';
12
+ import { join } from 'node:path';
13
+ import { createPlatformPathsResolver, } from './platform-paths.js';
14
+ const TEMPLATES_SUBDIR = 'templates';
15
+ const cleoResolver = createPlatformPathsResolver('cleo', 'CLEO_HOME');
16
+ /**
17
+ * Get OS-appropriate paths for CLEO's global directories.
18
+ *
19
+ * Linux: `~/.local/share/cleo` | macOS: `~/Library/Application Support/cleo`
20
+ * Windows: `%LOCALAPPDATA%\cleo\Data`
21
+ *
22
+ * The `CLEO_HOME` env var overrides the `data` field. Read fresh on every call.
23
+ *
24
+ * @public
25
+ */
26
+ export function getCleoPlatformPaths() {
27
+ return cleoResolver.getPlatformPaths();
28
+ }
29
+ /**
30
+ * Get the absolute path to CLEO's global data directory.
31
+ *
32
+ * Equivalent to `getCleoPlatformPaths().data` — exposed as a stable named
33
+ * helper because `getCleoHome()` is the most common consumer call.
34
+ *
35
+ * @public
36
+ */
37
+ export function getCleoHome() {
38
+ return cleoResolver.getPlatformPaths().data;
39
+ }
40
+ /**
41
+ * Get a cached system information snapshot scoped to CLEO.
42
+ *
43
+ * Includes platform, architecture, hostname, Node version, and resolved
44
+ * CLEO paths. Captured once per process and reused — invalidate via
45
+ * {@link _resetCleoPlatformPathsCache} in tests if needed.
46
+ *
47
+ * @public
48
+ */
49
+ export function getCleoSystemInfo() {
50
+ return cleoResolver.getSystemInfo();
51
+ }
52
+ /**
53
+ * Get the CLEO templates directory as a tilde-prefixed path for use in
54
+ * `@`-references (AGENTS.md, CLAUDE.md, etc.). Cross-platform: replaces
55
+ * the user's home directory with `~` so the reference resolves consistently
56
+ * when an LLM provider expands `~` at runtime.
57
+ *
58
+ * @returns Tilde-prefixed path like `"~/.local/share/cleo/templates"` on Linux
59
+ *
60
+ * @example
61
+ * ```typescript
62
+ * const ref = `@${getCleoTemplatesTildePath()}/CLEO-INJECTION.md`;
63
+ * // "@~/.local/share/cleo/templates/CLEO-INJECTION.md" (Linux)
64
+ * ```
65
+ *
66
+ * @public
67
+ */
68
+ export function getCleoTemplatesTildePath() {
69
+ const absPath = join(getCleoHome(), TEMPLATES_SUBDIR);
70
+ const home = homedir();
71
+ if (absPath.startsWith(home)) {
72
+ const relative = absPath.slice(home.length).replace(/\\/g, '/');
73
+ return `~${relative}`;
74
+ }
75
+ return absPath;
76
+ }
77
+ /**
78
+ * Invalidate the cached CLEO system info snapshot. Use in tests after
79
+ * mutating `CLEO_HOME` or related env vars.
80
+ *
81
+ * @internal
82
+ */
83
+ export function _resetCleoPlatformPathsCache() {
84
+ cleoResolver.resetCache();
85
+ }
86
+ //# sourceMappingURL=cleo-paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cleo-paths.js","sourceRoot":"","sources":["../src/cleo-paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EACL,2BAA2B,GAG5B,MAAM,qBAAqB,CAAC;AAE7B,MAAM,gBAAgB,GAAG,WAAW,CAAC;AAErC,MAAM,YAAY,GAAG,2BAA2B,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;AAEtE;;;;;;;;;GASG;AACH,MAAM,UAAU,oBAAoB;IAClC,OAAO,YAAY,CAAC,gBAAgB,EAAE,CAAC;AACzC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW;IACzB,OAAO,YAAY,CAAC,gBAAgB,EAAE,CAAC,IAAI,CAAC;AAC9C,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,YAAY,CAAC,aAAa,EAAE,CAAC;AACtC,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,yBAAyB;IACvC,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,EAAE,gBAAgB,CAAC,CAAC;IACtD,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7B,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAChE,OAAO,IAAI,QAAQ,EAAE,CAAC;IACxB,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,4BAA4B;IAC1C,YAAY,CAAC,UAAU,EAAE,CAAC;AAC5B,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * `@cleocode/paths` — XDG / env-paths SSoT for the CLEO ecosystem.
3
+ *
4
+ * Zero-dep leaf package consumed by `@cleocode/core`, `@cleocode/worktree`,
5
+ * `@cleocode/brain`, `@cleocode/adapters`, and `@cleocode/caamp` to eliminate
6
+ * the env-paths and platform-path duplication that previously existed in
7
+ * each of those packages.
8
+ *
9
+ * Exposes:
10
+ * - {@link createPlatformPathsResolver} — generic factory bindable to any app
11
+ * - CLEO-bound helpers: {@link getCleoHome}, {@link getCleoPlatformPaths},
12
+ * {@link getCleoSystemInfo}, {@link getCleoTemplatesTildePath}
13
+ * - Worktree primitives: {@link computeProjectHash},
14
+ * {@link resolveWorktreeRootForHash}, {@link resolveTaskWorktreePath},
15
+ * {@link getCleoWorktreesRoot}
16
+ * - {@link isAbsolutePath} — cross-platform abs-path check
17
+ *
18
+ * @packageDocumentation
19
+ * @task T1883
20
+ */
21
+ export { isAbsolutePath } from './abs-path.js';
22
+ export { _resetCleoPlatformPathsCache, getCleoHome, getCleoPlatformPaths, getCleoSystemInfo, getCleoTemplatesTildePath, } from './cleo-paths.js';
23
+ export { createPlatformPathsResolver, type PlatformPaths, type PlatformPathsResolver, type SystemInfo, } from './platform-paths.js';
24
+ export { computeProjectHash, getCleoWorktreesRoot, resolveTaskWorktreePath, resolveWorktreeRootForHash, } from './worktree-paths.js';
25
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EACL,4BAA4B,EAC5B,WAAW,EACX,oBAAoB,EACpB,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,2BAA2B,EAC3B,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAC1B,KAAK,UAAU,GAChB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,qBAAqB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,25 @@
1
+ /**
2
+ * `@cleocode/paths` — XDG / env-paths SSoT for the CLEO ecosystem.
3
+ *
4
+ * Zero-dep leaf package consumed by `@cleocode/core`, `@cleocode/worktree`,
5
+ * `@cleocode/brain`, `@cleocode/adapters`, and `@cleocode/caamp` to eliminate
6
+ * the env-paths and platform-path duplication that previously existed in
7
+ * each of those packages.
8
+ *
9
+ * Exposes:
10
+ * - {@link createPlatformPathsResolver} — generic factory bindable to any app
11
+ * - CLEO-bound helpers: {@link getCleoHome}, {@link getCleoPlatformPaths},
12
+ * {@link getCleoSystemInfo}, {@link getCleoTemplatesTildePath}
13
+ * - Worktree primitives: {@link computeProjectHash},
14
+ * {@link resolveWorktreeRootForHash}, {@link resolveTaskWorktreePath},
15
+ * {@link getCleoWorktreesRoot}
16
+ * - {@link isAbsolutePath} — cross-platform abs-path check
17
+ *
18
+ * @packageDocumentation
19
+ * @task T1883
20
+ */
21
+ export { isAbsolutePath } from './abs-path.js';
22
+ export { _resetCleoPlatformPathsCache, getCleoHome, getCleoPlatformPaths, getCleoSystemInfo, getCleoTemplatesTildePath, } from './cleo-paths.js';
23
+ export { createPlatformPathsResolver, } from './platform-paths.js';
24
+ export { computeProjectHash, getCleoWorktreesRoot, resolveTaskWorktreePath, resolveWorktreeRootForHash, } from './worktree-paths.js';
25
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EACL,4BAA4B,EAC5B,WAAW,EACX,oBAAoB,EACpB,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,2BAA2B,GAI5B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,113 @@
1
+ /**
2
+ * OS platform-path resolver factory backed by `env-paths`.
3
+ *
4
+ * The factory is parameterised by `appName` + `homeEnvVar` so a single
5
+ * implementation serves every CLEO package that needs XDG-compliant
6
+ * paths — `cleo`, `agents` (CAAMP), or any future tool — without each
7
+ * package re-implementing the same env-paths wrapper, the same tilde
8
+ * expansion, and the same SystemInfo cache.
9
+ *
10
+ * `getPlatformPaths()` reads fresh on every call: env-paths is microsecond-fast
11
+ * and a process-wide cache would mask XDG / APPDATA env-var changes that test
12
+ * code legitimately makes. `getSystemInfo()` IS cached because hostname /
13
+ * platform / arch don't change during a process lifetime.
14
+ *
15
+ * @packageDocumentation
16
+ * @task T1883
17
+ */
18
+ /**
19
+ * OS-appropriate directory paths for an application.
20
+ *
21
+ * Defaults follow XDG Base Directory on Linux, Apple's File System Programming
22
+ * Guide on macOS, and Microsoft's Known Folders on Windows. The home env-var
23
+ * passed to {@link createPlatformPathsResolver} overrides `data`.
24
+ *
25
+ * @public
26
+ */
27
+ export interface PlatformPaths {
28
+ /** User data dir. Override with the configured home env var. */
29
+ data: string;
30
+ /** OS config dir (XDG_CONFIG_HOME / Library/Preferences / %APPDATA%). */
31
+ config: string;
32
+ /** OS cache dir. */
33
+ cache: string;
34
+ /** OS log dir. */
35
+ log: string;
36
+ /** OS temp dir. */
37
+ temp: string;
38
+ }
39
+ /**
40
+ * Snapshot of the current system environment combined with resolved platform paths.
41
+ *
42
+ * Cached for the process lifetime by {@link PlatformPathsResolver.getSystemInfo}.
43
+ *
44
+ * @public
45
+ */
46
+ export interface SystemInfo {
47
+ /** Operating system platform identifier. */
48
+ platform: NodeJS.Platform;
49
+ /** CPU architecture (e.g. `"x64"`, `"arm64"`). */
50
+ arch: string;
51
+ /** OS kernel release version string. */
52
+ release: string;
53
+ /** Machine hostname. */
54
+ hostname: string;
55
+ /** Node.js version string (e.g. `"v24.0.0"`). */
56
+ nodeVersion: string;
57
+ /** Resolved platform directory paths. */
58
+ paths: PlatformPaths;
59
+ }
60
+ /**
61
+ * A platform-paths resolver bound to one app name + one home env var.
62
+ *
63
+ * Each resolver carries its own `SystemInfo` cache so resolvers for different
64
+ * apps (e.g. `cleo` vs `agents`) stay fully isolated.
65
+ *
66
+ * @public
67
+ */
68
+ export interface PlatformPathsResolver {
69
+ /**
70
+ * Get OS-appropriate paths for the resolver's app directories.
71
+ *
72
+ * Reads fresh on every call. The home env var (when set) overrides the
73
+ * `data` field; `~`, `~/...`, absolute, and relative path values are all
74
+ * accepted and resolved against `homedir()`.
75
+ */
76
+ getPlatformPaths(): PlatformPaths;
77
+ /**
78
+ * Get a cached system information snapshot.
79
+ *
80
+ * Captured once per resolver and reused for the process lifetime. Includes
81
+ * platform, architecture, hostname, Node version, and resolved paths.
82
+ */
83
+ getSystemInfo(): SystemInfo;
84
+ /**
85
+ * Invalidate the cached system info snapshot. Use in tests after mutating
86
+ * the home env var.
87
+ *
88
+ * @internal
89
+ */
90
+ resetCache(): void;
91
+ }
92
+ /**
93
+ * Create a platform-paths resolver bound to a specific app name and home env var.
94
+ *
95
+ * Returns a resolver with its own internal `SystemInfo` cache. Path reads are
96
+ * always fresh (env-paths is fast); only system info is cached.
97
+ *
98
+ * @param appName - The application name passed to `env-paths` (e.g. `"cleo"`,
99
+ * `"agents"`).
100
+ * @param homeEnvVar - The env var name that overrides the data directory
101
+ * (e.g. `"CLEO_HOME"`, `"AGENTS_HOME"`). Tilde-prefixed and relative
102
+ * values are resolved against `homedir()`.
103
+ *
104
+ * @example
105
+ * ```typescript
106
+ * const cleo = createPlatformPathsResolver('cleo', 'CLEO_HOME');
107
+ * cleo.getPlatformPaths().data; // → "/home/user/.local/share/cleo" (Linux, no override)
108
+ * ```
109
+ *
110
+ * @public
111
+ */
112
+ export declare function createPlatformPathsResolver(appName: string, homeEnvVar: string): PlatformPathsResolver;
113
+ //# sourceMappingURL=platform-paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform-paths.d.ts","sourceRoot":"","sources":["../src/platform-paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH;;;;;;;;GAQG;AACH,MAAM,WAAW,aAAa;IAC5B,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAC;IACb,yEAAyE;IACzE,MAAM,EAAE,MAAM,CAAC;IACf,oBAAoB;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,kBAAkB;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;GAMG;AACH,MAAM,WAAW,UAAU;IACzB,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC;IAC1B,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,wCAAwC;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,wBAAwB;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,WAAW,EAAE,MAAM,CAAC;IACpB,yCAAyC;IACzC,KAAK,EAAE,aAAa,CAAC;CACtB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;;;OAMG;IACH,gBAAgB,IAAI,aAAa,CAAC;IAElC;;;;;OAKG;IACH,aAAa,IAAI,UAAU,CAAC;IAE5B;;;;;OAKG;IACH,UAAU,IAAI,IAAI,CAAC;CACpB;AAqBD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACjB,qBAAqB,CAiCvB"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * OS platform-path resolver factory backed by `env-paths`.
3
+ *
4
+ * The factory is parameterised by `appName` + `homeEnvVar` so a single
5
+ * implementation serves every CLEO package that needs XDG-compliant
6
+ * paths — `cleo`, `agents` (CAAMP), or any future tool — without each
7
+ * package re-implementing the same env-paths wrapper, the same tilde
8
+ * expansion, and the same SystemInfo cache.
9
+ *
10
+ * `getPlatformPaths()` reads fresh on every call: env-paths is microsecond-fast
11
+ * and a process-wide cache would mask XDG / APPDATA env-var changes that test
12
+ * code legitimately makes. `getSystemInfo()` IS cached because hostname /
13
+ * platform / arch don't change during a process lifetime.
14
+ *
15
+ * @packageDocumentation
16
+ * @task T1883
17
+ */
18
+ import { arch, homedir, hostname, platform, release } from 'node:os';
19
+ import { isAbsolute, join, resolve } from 'node:path';
20
+ import envPaths from 'env-paths';
21
+ /**
22
+ * Normalize a home-override env var value to an absolute path.
23
+ *
24
+ * Returns `undefined` for absent / blank values so callers fall back to the
25
+ * env-paths default. Accepts `~`, `~/foo`, absolute paths, and relative paths
26
+ * (which are resolved against `homedir()`).
27
+ *
28
+ * @internal
29
+ */
30
+ function resolveHomeOverride(value) {
31
+ if (value === undefined)
32
+ return undefined;
33
+ const trimmed = value.trim();
34
+ if (trimmed.length === 0)
35
+ return undefined;
36
+ if (trimmed === '~')
37
+ return homedir();
38
+ if (trimmed.startsWith('~/'))
39
+ return join(homedir(), trimmed.slice(2));
40
+ if (isAbsolute(trimmed))
41
+ return resolve(trimmed);
42
+ return resolve(homedir(), trimmed);
43
+ }
44
+ /**
45
+ * Create a platform-paths resolver bound to a specific app name and home env var.
46
+ *
47
+ * Returns a resolver with its own internal `SystemInfo` cache. Path reads are
48
+ * always fresh (env-paths is fast); only system info is cached.
49
+ *
50
+ * @param appName - The application name passed to `env-paths` (e.g. `"cleo"`,
51
+ * `"agents"`).
52
+ * @param homeEnvVar - The env var name that overrides the data directory
53
+ * (e.g. `"CLEO_HOME"`, `"AGENTS_HOME"`). Tilde-prefixed and relative
54
+ * values are resolved against `homedir()`.
55
+ *
56
+ * @example
57
+ * ```typescript
58
+ * const cleo = createPlatformPathsResolver('cleo', 'CLEO_HOME');
59
+ * cleo.getPlatformPaths().data; // → "/home/user/.local/share/cleo" (Linux, no override)
60
+ * ```
61
+ *
62
+ * @public
63
+ */
64
+ export function createPlatformPathsResolver(appName, homeEnvVar) {
65
+ let cachedSysInfo = null;
66
+ function readPlatformPaths() {
67
+ const ep = envPaths(appName, { suffix: '' });
68
+ const override = resolveHomeOverride(process.env[homeEnvVar]);
69
+ return {
70
+ data: override ?? ep.data,
71
+ config: ep.config,
72
+ cache: ep.cache,
73
+ log: ep.log,
74
+ temp: ep.temp,
75
+ };
76
+ }
77
+ return {
78
+ getPlatformPaths: readPlatformPaths,
79
+ getSystemInfo() {
80
+ if (cachedSysInfo)
81
+ return cachedSysInfo;
82
+ cachedSysInfo = {
83
+ platform: platform(),
84
+ arch: arch(),
85
+ release: release(),
86
+ hostname: hostname(),
87
+ nodeVersion: process.version,
88
+ paths: readPlatformPaths(),
89
+ };
90
+ return cachedSysInfo;
91
+ },
92
+ resetCache() {
93
+ cachedSysInfo = null;
94
+ },
95
+ };
96
+ }
97
+ //# sourceMappingURL=platform-paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform-paths.js","sourceRoot":"","sources":["../src/platform-paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,QAAQ,MAAM,WAAW,CAAC;AAiFjC;;;;;;;;GAQG;AACH,SAAS,mBAAmB,CAAC,KAAyB;IACpD,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC3C,IAAI,OAAO,KAAK,GAAG;QAAE,OAAO,OAAO,EAAE,CAAC;IACtC,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACvE,IAAI,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC;IACjD,OAAO,OAAO,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC;AACrC,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,2BAA2B,CACzC,OAAe,EACf,UAAkB;IAElB,IAAI,aAAa,GAAsB,IAAI,CAAC;IAE5C,SAAS,iBAAiB;QACxB,MAAM,EAAE,GAAG,QAAQ,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;QAC7C,MAAM,QAAQ,GAAG,mBAAmB,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC;QAC9D,OAAO;YACL,IAAI,EAAE,QAAQ,IAAI,EAAE,CAAC,IAAI;YACzB,MAAM,EAAE,EAAE,CAAC,MAAM;YACjB,KAAK,EAAE,EAAE,CAAC,KAAK;YACf,GAAG,EAAE,EAAE,CAAC,GAAG;YACX,IAAI,EAAE,EAAE,CAAC,IAAI;SACd,CAAC;IACJ,CAAC;IAED,OAAO;QACL,gBAAgB,EAAE,iBAAiB;QACnC,aAAa;YACX,IAAI,aAAa;gBAAE,OAAO,aAAa,CAAC;YACxC,aAAa,GAAG;gBACd,QAAQ,EAAE,QAAQ,EAAE;gBACpB,IAAI,EAAE,IAAI,EAAE;gBACZ,OAAO,EAAE,OAAO,EAAE;gBAClB,QAAQ,EAAE,QAAQ,EAAE;gBACpB,WAAW,EAAE,OAAO,CAAC,OAAO;gBAC5B,KAAK,EAAE,iBAAiB,EAAE;aAC3B,CAAC;YACF,OAAO,aAAa,CAAC;QACvB,CAAC;QACD,UAAU;YACR,aAAa,GAAG,IAAI,CAAC;QACvB,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Worktree path primitives — project hashing + canonical worktree root.
3
+ *
4
+ * Canonical layout per D029:
5
+ * `<cleoHome>/worktrees/<projectHash>/<taskId>/`
6
+ *
7
+ * `cleoHome` is resolved via {@link getCleoHome} (env-paths + `CLEO_HOME` override).
8
+ *
9
+ * @task T1883
10
+ */
11
+ /**
12
+ * Compute a stable 16-character project hash from an absolute project root path.
13
+ *
14
+ * Uses SHA-256 truncated to 16 hex chars. The truncation is consistent with
15
+ * the historical implementation in `branch-lock.ts#resolveAgentWorktreeRoot`
16
+ * (the root cause of the duplicated logic this package consolidates).
17
+ *
18
+ * @param projectRoot - Absolute path to the project root.
19
+ * @returns 16-character lowercase hex string.
20
+ *
21
+ * @public
22
+ */
23
+ export declare function computeProjectHash(projectRoot: string): string;
24
+ /**
25
+ * Resolve the worktrees root directory for a given project hash.
26
+ *
27
+ * Result: `<cleoHome>/worktrees/<projectHash>/`
28
+ *
29
+ * Priority:
30
+ * 1. Explicit `worktreeRoot` arg (used by tests / config overrides)
31
+ * 2. `CLEO_HOME` env var via {@link getCleoHome}
32
+ * 3. env-paths XDG data dir via {@link getCleoHome}
33
+ *
34
+ * @param projectHash - 16-char project hash from {@link computeProjectHash}.
35
+ * @param worktreeRoot - Optional explicit override for the full root path.
36
+ * @returns Absolute path to the project-scoped worktree root directory.
37
+ *
38
+ * @public
39
+ */
40
+ export declare function resolveWorktreeRootForHash(projectHash: string, worktreeRoot?: string): string;
41
+ /**
42
+ * Resolve the worktree directory for a specific task.
43
+ *
44
+ * Result: `<cleoHome>/worktrees/<projectHash>/<taskId>/`
45
+ *
46
+ * @param projectHash - 16-char project hash from {@link computeProjectHash}.
47
+ * @param taskId - The task ID.
48
+ * @param worktreeRoot - Optional override for the worktree root.
49
+ * @returns Absolute path to the task-specific worktree directory.
50
+ *
51
+ * @public
52
+ */
53
+ export declare function resolveTaskWorktreePath(projectHash: string, taskId: string, worktreeRoot?: string): string;
54
+ /**
55
+ * Resolve the canonical worktrees-by-project root for the current process —
56
+ * `<cleoHome>/worktrees/`. Project-agnostic; useful when listing or scanning
57
+ * across all projects.
58
+ *
59
+ * @returns Absolute path to `<cleoHome>/worktrees/`.
60
+ *
61
+ * @public
62
+ */
63
+ export declare function getCleoWorktreesRoot(): string;
64
+ //# sourceMappingURL=worktree-paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree-paths.d.ts","sourceRoot":"","sources":["../src/worktree-paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AASH;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAG7F;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,MAAM,GACpB,MAAM,CAER;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Worktree path primitives — project hashing + canonical worktree root.
3
+ *
4
+ * Canonical layout per D029:
5
+ * `<cleoHome>/worktrees/<projectHash>/<taskId>/`
6
+ *
7
+ * `cleoHome` is resolved via {@link getCleoHome} (env-paths + `CLEO_HOME` override).
8
+ *
9
+ * @task T1883
10
+ */
11
+ import { createHash } from 'node:crypto';
12
+ import { join } from 'node:path';
13
+ import { getCleoHome } from './cleo-paths.js';
14
+ const WORKTREES_SUBDIR = 'worktrees';
15
+ const PROJECT_HASH_LENGTH = 16;
16
+ /**
17
+ * Compute a stable 16-character project hash from an absolute project root path.
18
+ *
19
+ * Uses SHA-256 truncated to 16 hex chars. The truncation is consistent with
20
+ * the historical implementation in `branch-lock.ts#resolveAgentWorktreeRoot`
21
+ * (the root cause of the duplicated logic this package consolidates).
22
+ *
23
+ * @param projectRoot - Absolute path to the project root.
24
+ * @returns 16-character lowercase hex string.
25
+ *
26
+ * @public
27
+ */
28
+ export function computeProjectHash(projectRoot) {
29
+ return createHash('sha256').update(projectRoot).digest('hex').slice(0, PROJECT_HASH_LENGTH);
30
+ }
31
+ /**
32
+ * Resolve the worktrees root directory for a given project hash.
33
+ *
34
+ * Result: `<cleoHome>/worktrees/<projectHash>/`
35
+ *
36
+ * Priority:
37
+ * 1. Explicit `worktreeRoot` arg (used by tests / config overrides)
38
+ * 2. `CLEO_HOME` env var via {@link getCleoHome}
39
+ * 3. env-paths XDG data dir via {@link getCleoHome}
40
+ *
41
+ * @param projectHash - 16-char project hash from {@link computeProjectHash}.
42
+ * @param worktreeRoot - Optional explicit override for the full root path.
43
+ * @returns Absolute path to the project-scoped worktree root directory.
44
+ *
45
+ * @public
46
+ */
47
+ export function resolveWorktreeRootForHash(projectHash, worktreeRoot) {
48
+ if (worktreeRoot)
49
+ return worktreeRoot;
50
+ return join(getCleoHome(), WORKTREES_SUBDIR, projectHash);
51
+ }
52
+ /**
53
+ * Resolve the worktree directory for a specific task.
54
+ *
55
+ * Result: `<cleoHome>/worktrees/<projectHash>/<taskId>/`
56
+ *
57
+ * @param projectHash - 16-char project hash from {@link computeProjectHash}.
58
+ * @param taskId - The task ID.
59
+ * @param worktreeRoot - Optional override for the worktree root.
60
+ * @returns Absolute path to the task-specific worktree directory.
61
+ *
62
+ * @public
63
+ */
64
+ export function resolveTaskWorktreePath(projectHash, taskId, worktreeRoot) {
65
+ return join(resolveWorktreeRootForHash(projectHash, worktreeRoot), taskId);
66
+ }
67
+ /**
68
+ * Resolve the canonical worktrees-by-project root for the current process —
69
+ * `<cleoHome>/worktrees/`. Project-agnostic; useful when listing or scanning
70
+ * across all projects.
71
+ *
72
+ * @returns Absolute path to `<cleoHome>/worktrees/`.
73
+ *
74
+ * @public
75
+ */
76
+ export function getCleoWorktreesRoot() {
77
+ return join(getCleoHome(), WORKTREES_SUBDIR);
78
+ }
79
+ //# sourceMappingURL=worktree-paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree-paths.js","sourceRoot":"","sources":["../src/worktree-paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE9C,MAAM,gBAAgB,GAAG,WAAW,CAAC;AACrC,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAE/B;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,kBAAkB,CAAC,WAAmB;IACpD,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC;AAC9F,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,0BAA0B,CAAC,WAAmB,EAAE,YAAqB;IACnF,IAAI,YAAY;QAAE,OAAO,YAAY,CAAC;IACtC,OAAO,IAAI,CAAC,WAAW,EAAE,EAAE,gBAAgB,EAAE,WAAW,CAAC,CAAC;AAC5D,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,uBAAuB,CACrC,WAAmB,EACnB,MAAc,EACd,YAAqB;IAErB,OAAO,IAAI,CAAC,0BAA0B,CAAC,WAAW,EAAE,YAAY,CAAC,EAAE,MAAM,CAAC,CAAC;AAC7E,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,oBAAoB;IAClC,OAAO,IAAI,CAAC,WAAW,EAAE,EAAE,gBAAgB,CAAC,CAAC;AAC/C,CAAC"}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@cleocode/paths",
3
+ "version": "2026.5.26",
4
+ "private": false,
5
+ "type": "module",
6
+ "description": "CLEO XDG/env-paths SSoT — createPlatformPathsResolver factory, cleo-bound platform paths, project hash + worktree root primitives, isAbsolutePath. Zero-dep leaf package consumed by core, worktree, brain, adapters, and caamp.",
7
+ "main": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist/",
17
+ "README.md"
18
+ ],
19
+ "keywords": [
20
+ "cleo",
21
+ "paths",
22
+ "xdg",
23
+ "env-paths",
24
+ "platform"
25
+ ],
26
+ "engines": {
27
+ "node": ">=24.0.0"
28
+ },
29
+ "author": "CLEO Code <hello@cleocode.dev>",
30
+ "license": "MIT",
31
+ "dependencies": {
32
+ "env-paths": "^4.0.0"
33
+ },
34
+ "devDependencies": {
35
+ "@types/node": "^24.3.0",
36
+ "typescript": "^6.0.2",
37
+ "vitest": "^4.1.4"
38
+ },
39
+ "publishConfig": {
40
+ "access": "public"
41
+ },
42
+ "repository": {
43
+ "type": "git",
44
+ "url": "git+https://github.com/kryptobaseddev/cleo.git",
45
+ "directory": "packages/paths"
46
+ },
47
+ "scripts": {
48
+ "build": "tsc -b",
49
+ "test": "vitest run",
50
+ "test:watch": "vitest"
51
+ }
52
+ }