session-steward 0.5.2 → 0.6.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/CHANGELOG.md +8 -0
- package/README.md +5 -3
- package/bin/session-steward.mjs +8 -7
- package/lib/platform.mjs +178 -0
- package/lib/providers/claude-code/store.mjs +12 -12
- package/lib/providers/codex/store.mjs +3 -15
- package/lib/server.mjs +7 -1
- package/lib/settings.mjs +7 -24
- package/package.json +15 -17
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.6.0] - 2026-08-16
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Windows support, alongside macOS and Linux. Codex and Claude Code sessions are read from your Windows user profile, and Claude Desktop data is found in both the standalone and Microsoft Store locations.
|
|
8
|
+
- Inside WSL, Session Steward manages the sessions stored in your Linux home folder. Run it from Windows to manage the sessions in your Windows profile.
|
|
9
|
+
|
|
3
10
|
## [0.5.2] - 2026-08-13
|
|
4
11
|
|
|
5
12
|
### Changed
|
|
@@ -105,6 +112,7 @@
|
|
|
105
112
|
- Support for custom Codex home folders and a saved folder preference.
|
|
106
113
|
- Streaming and bounded-memory discovery for large session collections and transcripts.
|
|
107
114
|
|
|
115
|
+
[0.6.0]: https://github.com/mallikcheripally/session-steward/compare/v0.5.2...v0.6.0
|
|
108
116
|
[0.5.2]: https://github.com/mallikcheripally/session-steward/compare/v0.5.1...v0.5.2
|
|
109
117
|
[0.5.1]: https://github.com/mallikcheripally/session-steward/compare/v0.5.0...v0.5.1
|
|
110
118
|
[0.5.0]: https://github.com/mallikcheripally/session-steward/compare/v0.4.0...v0.5.0
|
package/README.md
CHANGED
|
@@ -47,7 +47,7 @@ At startup, Session Steward may contact the public npm registry to check for a n
|
|
|
47
47
|
|
|
48
48
|
## Install and get started
|
|
49
49
|
|
|
50
|
-
Session Steward supports macOS and
|
|
50
|
+
Session Steward supports macOS, Linux, and Windows and requires Node.js 24.15 or newer.
|
|
51
51
|
|
|
52
52
|
Install it globally:
|
|
53
53
|
|
|
@@ -67,7 +67,9 @@ Or try it without installing:
|
|
|
67
67
|
npx session-steward@latest
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
-
Session Steward opens in your browser, listens only on `127.0.0.1`, and detects `~/.codex` and `~/.claude` by default. Claude Desktop sessions are detected on macOS; Claude Code CLI
|
|
70
|
+
Session Steward opens in your browser, listens only on `127.0.0.1`, and detects `~/.codex` and `~/.claude` by default. Claude Code CLI and local Claude Desktop sessions are detected on macOS and Windows; the Claude Code CLI is also supported on Linux. On Windows, these resolve to `%USERPROFILE%\.codex` and `%USERPROFILE%\.claude`.
|
|
71
|
+
|
|
72
|
+
When run inside WSL, Session Steward uses the Linux home folder and manages sessions stored there. Run it from Windows to manage sessions in your Windows profile.
|
|
71
73
|
|
|
72
74
|
To clean up sessions:
|
|
73
75
|
|
|
@@ -271,7 +273,7 @@ Results vary with hardware, disk speed, and session layout. Tests and benchmarks
|
|
|
271
273
|
|
|
272
274
|
## Support
|
|
273
275
|
|
|
274
|
-
Codex, Claude Code CLI, and local Claude Code Desktop sessions are supported. Claude Desktop archive is not treated as deletion, and Session Steward never removes its worktrees.
|
|
276
|
+
Codex, Claude Code CLI, and local Claude Code Desktop sessions are supported. Claude Desktop archive is not treated as deletion, and Session Steward never removes its worktrees. On Windows, both the standalone and Microsoft Store Claude Desktop data locations are detected.
|
|
275
277
|
|
|
276
278
|
Use [GitHub Issues](https://github.com/mallikcheripally/session-steward/issues) to report a bug, request a provider, or share a storage format that Session Steward does not recognize.
|
|
277
279
|
|
package/bin/session-steward.mjs
CHANGED
|
@@ -4,6 +4,7 @@ import { parseArgs } from "node:util";
|
|
|
4
4
|
import { spawn } from "node:child_process";
|
|
5
5
|
|
|
6
6
|
import packageMetadata from "../package.json" with { type: "json" };
|
|
7
|
+
import { getBrowserOpenInvocation } from "../lib/platform.mjs";
|
|
7
8
|
import { assertSupportedNode } from "../lib/runtime.mjs";
|
|
8
9
|
import { findAvailableUpdate, formatUpdateNotice } from "../lib/update-check.mjs";
|
|
9
10
|
|
|
@@ -58,14 +59,14 @@ process.stdout.write(`Session Steward is running at http://127.0.0.1:${server.po
|
|
|
58
59
|
|
|
59
60
|
if (!values["no-open"]) {
|
|
60
61
|
const url = `http://127.0.0.1:${server.port}`;
|
|
61
|
-
const
|
|
62
|
-
? "open"
|
|
63
|
-
: process.platform === "linux"
|
|
64
|
-
? "xdg-open"
|
|
65
|
-
: null;
|
|
62
|
+
const invocation = getBrowserOpenInvocation(url);
|
|
66
63
|
|
|
67
|
-
if (
|
|
68
|
-
const opener = spawn(
|
|
64
|
+
if (invocation) {
|
|
65
|
+
const opener = spawn(invocation.command, invocation.args, {
|
|
66
|
+
detached: true,
|
|
67
|
+
stdio: "ignore",
|
|
68
|
+
windowsHide: invocation.windowsHide,
|
|
69
|
+
});
|
|
69
70
|
opener.unref();
|
|
70
71
|
} else {
|
|
71
72
|
process.stdout.write(`Open ${url} in a browser.\n`);
|
package/lib/platform.mjs
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { existsSync, readdirSync } from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
|
|
5
|
+
const WINDOWS_ROOTED = /^(?:[a-z]:[\\/]|[\\/]{2})/iu;
|
|
6
|
+
|
|
7
|
+
function pathApi(platform) {
|
|
8
|
+
if (platform === "win32") {
|
|
9
|
+
return path.win32;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (platform === "darwin" || platform === "linux") {
|
|
13
|
+
return path.posix;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return path;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function isUsableAbsolutePath(value, platform) {
|
|
20
|
+
if (typeof value !== "string" || !pathApi(platform).isAbsolute(value)) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// path.win32.isAbsolute accepts root-relative paths such as "/home/user",
|
|
25
|
+
// which resolve against whichever drive happens to be current.
|
|
26
|
+
return platform !== "win32" || WINDOWS_ROOTED.test(value);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function expandHomePath(value, {
|
|
30
|
+
home = os.homedir(),
|
|
31
|
+
platform = process.platform,
|
|
32
|
+
} = {}) {
|
|
33
|
+
if (value === "~") {
|
|
34
|
+
return home;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (typeof value === "string" && /^~[\\/]/u.test(value)) {
|
|
38
|
+
return pathApi(platform).join(home, value.slice(2));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return value;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function getDefaultConfigDirectory({
|
|
45
|
+
env = process.env,
|
|
46
|
+
home = os.homedir(),
|
|
47
|
+
platform = process.platform,
|
|
48
|
+
} = {}) {
|
|
49
|
+
const paths = pathApi(platform);
|
|
50
|
+
const xdgConfigHome = env.XDG_CONFIG_HOME;
|
|
51
|
+
|
|
52
|
+
if (isUsableAbsolutePath(xdgConfigHome, platform)) {
|
|
53
|
+
return paths.join(xdgConfigHome, "session-steward");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (platform === "darwin") {
|
|
57
|
+
return paths.join(home, "Library", "Application Support", "session-steward");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (platform === "win32") {
|
|
61
|
+
const appData = env.APPDATA;
|
|
62
|
+
return isUsableAbsolutePath(appData, platform)
|
|
63
|
+
? paths.join(appData, "session-steward")
|
|
64
|
+
: paths.join(home, "AppData", "Roaming", "session-steward");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return paths.join(home, ".config", "session-steward");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const desktopDataHomeCache = new Map();
|
|
71
|
+
|
|
72
|
+
export function invalidateClaudeDesktopDataHome() {
|
|
73
|
+
desktopDataHomeCache.clear();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function resolveClaudeDesktopDataHome({ env, fileSystem, home, platform }) {
|
|
77
|
+
const paths = pathApi(platform);
|
|
78
|
+
|
|
79
|
+
if (platform === "darwin") {
|
|
80
|
+
return paths.join(home, "Library", "Application Support", "Claude");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (platform === "win32") {
|
|
84
|
+
const appData = env.APPDATA;
|
|
85
|
+
const standardHome = isUsableAbsolutePath(appData, platform)
|
|
86
|
+
? paths.join(appData, "Claude")
|
|
87
|
+
: paths.join(home, "AppData", "Roaming", "Claude");
|
|
88
|
+
const sessionsName = "claude-code-sessions";
|
|
89
|
+
|
|
90
|
+
if (fileSystem.existsSync(paths.join(standardHome, sessionsName))) {
|
|
91
|
+
return standardHome;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const localAppData = env.LOCALAPPDATA;
|
|
95
|
+
if (isUsableAbsolutePath(localAppData, platform)) {
|
|
96
|
+
const packagesDirectory = paths.join(localAppData, "Packages");
|
|
97
|
+
try {
|
|
98
|
+
const packageEntries = fileSystem.readdirSync(packagesDirectory, { withFileTypes: true });
|
|
99
|
+
for (const entry of packageEntries) {
|
|
100
|
+
if (!entry.isDirectory() || !/^Claude_/iu.test(entry.name)) {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const packageHome = paths.join(
|
|
105
|
+
packagesDirectory,
|
|
106
|
+
entry.name,
|
|
107
|
+
"LocalCache",
|
|
108
|
+
"Roaming",
|
|
109
|
+
"Claude",
|
|
110
|
+
);
|
|
111
|
+
if (fileSystem.existsSync(paths.join(packageHome, sessionsName))) {
|
|
112
|
+
return packageHome;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
} catch {
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return standardHome;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function getClaudeDesktopDataHome({
|
|
126
|
+
env = process.env,
|
|
127
|
+
fileSystem = { existsSync, readdirSync },
|
|
128
|
+
home = os.homedir(),
|
|
129
|
+
platform = process.platform,
|
|
130
|
+
} = {}) {
|
|
131
|
+
// Windows discovery reads the file system, and this runs on every listing.
|
|
132
|
+
const key = `${platform}\0${home}\0${env.APPDATA || ""}\0${env.LOCALAPPDATA || ""}`;
|
|
133
|
+
if (desktopDataHomeCache.has(key)) {
|
|
134
|
+
return desktopDataHomeCache.get(key);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const resolved = resolveClaudeDesktopDataHome({ env, fileSystem, home, platform });
|
|
138
|
+
desktopDataHomeCache.set(key, resolved);
|
|
139
|
+
return resolved;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function getBrowserOpenInvocation(url, {
|
|
143
|
+
env = process.env,
|
|
144
|
+
platform = process.platform,
|
|
145
|
+
} = {}) {
|
|
146
|
+
if (platform === "darwin") {
|
|
147
|
+
return { args: [url], command: "open" };
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (platform === "linux") {
|
|
151
|
+
return { args: [url], command: "xdg-open" };
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (platform === "win32") {
|
|
155
|
+
return {
|
|
156
|
+
args: ["/d", "/s", "/c", "start", "", url],
|
|
157
|
+
command: env.ComSpec || env.COMSPEC || "cmd.exe",
|
|
158
|
+
windowsHide: true,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export function getCommandInvocation(command, args, {
|
|
166
|
+
env = process.env,
|
|
167
|
+
platform = process.platform,
|
|
168
|
+
} = {}) {
|
|
169
|
+
if (platform !== "win32") {
|
|
170
|
+
return { args, command };
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return {
|
|
174
|
+
args: ["/d", "/s", "/c", command, ...args],
|
|
175
|
+
command: env.ComSpec || env.COMSPEC || "cmd.exe",
|
|
176
|
+
windowsHide: true,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
@@ -2,10 +2,14 @@ import { createHash, randomBytes } from "node:crypto";
|
|
|
2
2
|
import { once } from "node:events";
|
|
3
3
|
import { createReadStream, createWriteStream } from "node:fs";
|
|
4
4
|
import { promises as fs } from "node:fs";
|
|
5
|
-
import os from "node:os";
|
|
6
5
|
import path from "node:path";
|
|
7
6
|
import { finished, pipeline } from "node:stream/promises";
|
|
8
7
|
|
|
8
|
+
import {
|
|
9
|
+
expandHomePath,
|
|
10
|
+
getClaudeDesktopDataHome,
|
|
11
|
+
invalidateClaudeDesktopDataHome,
|
|
12
|
+
} from "../../platform.mjs";
|
|
9
13
|
import { measurePath } from "../../storage/files.mjs";
|
|
10
14
|
import { readJsonlEntries, rewriteJsonlFile } from "../../storage/jsonl.mjs";
|
|
11
15
|
|
|
@@ -34,19 +38,11 @@ const SESSION_SORTS = new Set(["created", "cwd", "name", "size", "updated"]);
|
|
|
34
38
|
const discoveryCache = new Map();
|
|
35
39
|
const transcriptActivityCache = new Map();
|
|
36
40
|
|
|
37
|
-
function expandHome(value) {
|
|
38
|
-
if (value === "~") return os.homedir();
|
|
39
|
-
if (value?.startsWith("~/")) return path.join(os.homedir(), value.slice(2));
|
|
40
|
-
return value;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
41
|
function getPaths(claudeHomeInput, desktopDataHomeInput) {
|
|
44
|
-
const claudeHome = path.resolve(
|
|
42
|
+
const claudeHome = path.resolve(expandHomePath(claudeHomeInput || process.env.CLAUDE_CONFIG_DIR || "~/.claude"));
|
|
45
43
|
const desktopDataHome = desktopDataHomeInput
|
|
46
|
-
? path.resolve(
|
|
47
|
-
:
|
|
48
|
-
? path.join(os.homedir(), "Library", "Application Support", "Claude")
|
|
49
|
-
: null;
|
|
44
|
+
? path.resolve(expandHomePath(desktopDataHomeInput))
|
|
45
|
+
: getClaudeDesktopDataHome();
|
|
50
46
|
return {
|
|
51
47
|
backupRoot: path.join(claudeHome, "session-steward-backups"),
|
|
52
48
|
claudeHome,
|
|
@@ -401,6 +397,9 @@ async function discover(claudeHome, desktopDataHome) {
|
|
|
401
397
|
}
|
|
402
398
|
|
|
403
399
|
async function discoverCached(claudeHome, desktopDataHome, { refresh = false } = {}) {
|
|
400
|
+
if (refresh && !desktopDataHome) {
|
|
401
|
+
invalidateClaudeDesktopDataHome();
|
|
402
|
+
}
|
|
404
403
|
const paths = getPaths(claudeHome, desktopDataHome);
|
|
405
404
|
const key = `${paths.claudeHome}\0${paths.desktopDataHome || ""}`;
|
|
406
405
|
const cached = discoveryCache.get(key);
|
|
@@ -416,6 +415,7 @@ async function discoverCached(claudeHome, desktopDataHome, { refresh = false } =
|
|
|
416
415
|
export function invalidateSessionCache({ claudeHome, desktopDataHome }) {
|
|
417
416
|
const paths = getPaths(claudeHome, desktopDataHome);
|
|
418
417
|
discoveryCache.delete(`${paths.claudeHome}\0${paths.desktopDataHome || ""}`);
|
|
418
|
+
invalidateClaudeDesktopDataHome();
|
|
419
419
|
}
|
|
420
420
|
|
|
421
421
|
function filterRecords(records, options) {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { constants as fsConstants, createReadStream } from "node:fs";
|
|
3
3
|
import { promises as fs } from "node:fs";
|
|
4
|
-
import os from "node:os";
|
|
5
4
|
import path from "node:path";
|
|
6
5
|
import readline from "node:readline";
|
|
7
6
|
|
|
@@ -25,18 +24,7 @@ import {
|
|
|
25
24
|
invalidateCodexDatabaseResolution,
|
|
26
25
|
resolveCodexDatabases,
|
|
27
26
|
} from "./database-families.mjs";
|
|
28
|
-
|
|
29
|
-
function expandHome(value) {
|
|
30
|
-
if (!value || value === "~") {
|
|
31
|
-
return os.homedir();
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if (value.startsWith("~/")) {
|
|
35
|
-
return path.join(os.homedir(), value.slice(2));
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return value;
|
|
39
|
-
}
|
|
27
|
+
import { expandHomePath } from "../../platform.mjs";
|
|
40
28
|
|
|
41
29
|
function normalizeText(value) {
|
|
42
30
|
if (typeof value !== "string") {
|
|
@@ -448,7 +436,7 @@ function deriveDisplayName({
|
|
|
448
436
|
}
|
|
449
437
|
|
|
450
438
|
export function getCodexPaths(codexHomeInput, { refresh = false } = {}) {
|
|
451
|
-
const codexHome = path.resolve(
|
|
439
|
+
const codexHome = path.resolve(expandHomePath(codexHomeInput || "~/.codex"));
|
|
452
440
|
const archivedSessionsDirectory = path.join(codexHome, "archived_sessions");
|
|
453
441
|
const sessionsDirectory = path.join(codexHome, "sessions");
|
|
454
442
|
const resolution = resolveCodexDatabases(codexHome, { refresh });
|
|
@@ -1017,7 +1005,7 @@ async function getSessionSizeIndex(paths, { refresh = false } = {}) {
|
|
|
1017
1005
|
}
|
|
1018
1006
|
|
|
1019
1007
|
export function invalidateSessionCache({ codexHome }) {
|
|
1020
|
-
const resolvedHome = path.resolve(
|
|
1008
|
+
const resolvedHome = path.resolve(expandHomePath(codexHome || "~/.codex"));
|
|
1021
1009
|
sessionSizeCache.delete(resolvedHome);
|
|
1022
1010
|
invalidateCodexDatabaseResolution(resolvedHome);
|
|
1023
1011
|
}
|
package/lib/server.mjs
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
} from "./session-event-reader.mjs";
|
|
13
13
|
import { createProviderSettings } from "./settings.mjs";
|
|
14
14
|
import { classifyInstalledVersion } from "./version-support.mjs";
|
|
15
|
+
import { getCommandInvocation } from "./platform.mjs";
|
|
15
16
|
|
|
16
17
|
const MAX_BODY_BYTES = 64 * 1024;
|
|
17
18
|
const ALLOWED_SCOPES = new Set(["core", "deep"]);
|
|
@@ -32,7 +33,12 @@ const staticAssets = new Map([
|
|
|
32
33
|
|
|
33
34
|
function readCommandVersion(command, args) {
|
|
34
35
|
try {
|
|
35
|
-
|
|
36
|
+
const invocation = getCommandInvocation(command, args);
|
|
37
|
+
return execFileSync(invocation.command, invocation.args, {
|
|
38
|
+
encoding: "utf8",
|
|
39
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
40
|
+
windowsHide: invocation.windowsHide,
|
|
41
|
+
}).trim() || null;
|
|
36
42
|
} catch {
|
|
37
43
|
return null;
|
|
38
44
|
}
|
package/lib/settings.mjs
CHANGED
|
@@ -3,6 +3,11 @@ import { promises as fs } from "node:fs";
|
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
|
|
6
|
+
import {
|
|
7
|
+
expandHomePath,
|
|
8
|
+
getDefaultConfigDirectory as resolveDefaultConfigDirectory,
|
|
9
|
+
} from "./platform.mjs";
|
|
10
|
+
|
|
6
11
|
const CONFIG_VERSION = 1;
|
|
7
12
|
const PROVIDERS = {
|
|
8
13
|
codex: {
|
|
@@ -21,24 +26,12 @@ const PROVIDERS = {
|
|
|
21
26
|
},
|
|
22
27
|
};
|
|
23
28
|
|
|
24
|
-
function expandHome(value) {
|
|
25
|
-
if (value === "~") {
|
|
26
|
-
return os.homedir();
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (value.startsWith("~/")) {
|
|
30
|
-
return path.join(os.homedir(), value.slice(2));
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return value;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
29
|
function normalizeHome(value) {
|
|
37
30
|
if (typeof value !== "string" || value.includes("\0")) {
|
|
38
31
|
throw new Error("Enter a valid folder path.");
|
|
39
32
|
}
|
|
40
33
|
|
|
41
|
-
const expanded =
|
|
34
|
+
const expanded = expandHomePath(value.trim());
|
|
42
35
|
|
|
43
36
|
if (!expanded || !path.isAbsolute(expanded)) {
|
|
44
37
|
throw new Error("Enter a full folder path, such as ~/.codex.");
|
|
@@ -58,17 +51,7 @@ function getProviderDefinition(providerId) {
|
|
|
58
51
|
}
|
|
59
52
|
|
|
60
53
|
export function getDefaultConfigDirectory() {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if (xdgConfigHome && path.isAbsolute(xdgConfigHome)) {
|
|
64
|
-
return path.join(xdgConfigHome, "session-steward");
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (process.platform === "darwin") {
|
|
68
|
-
return path.join(os.homedir(), "Library", "Application Support", "session-steward");
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return path.join(os.homedir(), ".config", "session-steward");
|
|
54
|
+
return resolveDefaultConfigDirectory();
|
|
72
55
|
}
|
|
73
56
|
|
|
74
57
|
async function readConfig(configPath) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "session-steward",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.6.0",
|
|
4
|
+
"description": "Codex and Claude Code session manager - browse, back up, and delete old sessions. Local browser UI + CLI.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Mallik Cheripally",
|
|
7
7
|
"type": "module",
|
|
@@ -17,28 +17,25 @@
|
|
|
17
17
|
"bugs": "https://github.com/mallikcheripally/session-steward/issues",
|
|
18
18
|
"keywords": [
|
|
19
19
|
"codex",
|
|
20
|
-
"claude-code",
|
|
21
|
-
"claude-code-sessions",
|
|
22
|
-
"claude-desktop",
|
|
23
20
|
"codex-cli",
|
|
24
|
-
"openai-codex",
|
|
25
21
|
"codex-sessions",
|
|
26
|
-
"codex-session-manager",
|
|
27
|
-
"codex-session-cleanup",
|
|
28
22
|
"codex-cleanup",
|
|
29
|
-
"codex
|
|
30
|
-
"delete-codex-sessions",
|
|
31
|
-
"session-manager",
|
|
32
|
-
"session-cleanup",
|
|
33
|
-
"ai-session-manager",
|
|
23
|
+
"openai-codex",
|
|
34
24
|
"chatgpt-desktop",
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
25
|
+
"claude-code",
|
|
26
|
+
"claude-code-sessions",
|
|
27
|
+
"claude-code-cleanup",
|
|
28
|
+
"claude-desktop",
|
|
29
|
+
"session-cleanup",
|
|
30
|
+
"session-history",
|
|
31
|
+
"session-manager",
|
|
32
|
+
"disk-space",
|
|
33
|
+
"disk-cleanup"
|
|
38
34
|
],
|
|
39
35
|
"os": [
|
|
40
36
|
"darwin",
|
|
41
|
-
"linux"
|
|
37
|
+
"linux",
|
|
38
|
+
"win32"
|
|
42
39
|
],
|
|
43
40
|
"files": [
|
|
44
41
|
"bin",
|
|
@@ -56,6 +53,7 @@
|
|
|
56
53
|
},
|
|
57
54
|
"scripts": {
|
|
58
55
|
"build": "vite build",
|
|
56
|
+
"benchmark:claude-discovery": "node --expose-gc test/benchmarks/claude-discovery.mjs",
|
|
59
57
|
"benchmark:discovery": "node --expose-gc test/benchmarks/codex-discovery.mjs",
|
|
60
58
|
"benchmark:events": "node --expose-gc test/benchmarks/session-events.mjs",
|
|
61
59
|
"benchmark:overview": "node --expose-gc test/benchmarks/codex-overview.mjs",
|