session-steward 0.9.0 → 0.10.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 +7 -0
- package/README.md +37 -49
- package/bin/session-steward-mcp.mjs +4 -4
- package/bin/session-steward-scheduler.mjs +61 -0
- package/lib/cleanup-scheduler-service.mjs +205 -0
- package/lib/cleanup-schedules.mjs +439 -0
- package/lib/cli.mjs +145 -117
- package/lib/installed-products.mjs +44 -0
- package/lib/mcp.mjs +426 -416
- package/lib/providers/claude-code/events.mjs +2 -0
- package/lib/providers/claude-code/store.mjs +12 -3
- package/lib/providers/codex/database-families.mjs +1 -1
- package/lib/providers/codex/store.mjs +4 -2
- package/lib/server.mjs +49 -115
- package/lib/session-cleanup.mjs +540 -0
- package/lib/settings.mjs +1 -0
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.10.0] - 2026-08-30
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Added full MCP support for finding, inspecting, cleaning, restoring, and automatically cleaning Codex and Claude Code sessions.
|
|
8
|
+
|
|
3
9
|
## [0.9.0] - 2026-08-27
|
|
4
10
|
|
|
5
11
|
### Added
|
|
@@ -137,6 +143,7 @@
|
|
|
137
143
|
- Support for custom Codex home folders and a saved folder preference.
|
|
138
144
|
- Streaming and bounded-memory discovery for large session collections and transcripts.
|
|
139
145
|
|
|
146
|
+
[0.10.0]: https://github.com/mallikcheripally/session-steward/compare/v0.9.0...v0.10.0
|
|
140
147
|
[0.9.0]: https://github.com/mallikcheripally/session-steward/compare/v0.8.0...v0.9.0
|
|
141
148
|
[0.8.0]: https://github.com/mallikcheripally/session-steward/compare/v0.7.0...v0.8.0
|
|
142
149
|
[0.7.0]: https://github.com/mallikcheripally/session-steward/compare/v0.6.0...v0.7.0
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
[](https://github.com/mallikcheripally/session-steward/actions/workflows/validate.yml)
|
|
5
5
|
[](https://github.com/mallikcheripally/session-steward/blob/main/LICENSE)
|
|
6
6
|
|
|
7
|
-
A local Codex and Claude Code session manager for safely reviewing, backing up, and deleting old sessions from a browser UI or terminal CLI
|
|
7
|
+
A local Codex and Claude Code session manager for safely reviewing, backing up, and deleting old sessions from a browser UI or terminal CLI, or through MCP with ChatGPT or Claude.
|
|
8
8
|
|
|
9
9
|
AI coding tools can accumulate hundreds or thousands of local sessions. A session may leave behind transcripts, history, logs, checkpoints, and linked artifacts, so manual cleanup can easily miss related data.
|
|
10
10
|
|
|
@@ -14,7 +14,7 @@ Session Steward makes session cleanup safer by finding those records, showing wh
|
|
|
14
14
|
|
|
15
15
|
## Manage local Codex and Claude Code sessions
|
|
16
16
|
|
|
17
|
-
- Review sessions
|
|
17
|
+
- Review and clean up sessions from the browser, terminal, ChatGPT, or Claude through MCP.
|
|
18
18
|
- Switch between Codex and Claude Code without installing another package.
|
|
19
19
|
- See session counts and the storage used by recognized session files.
|
|
20
20
|
- Find sessions inactive for 30, 60, or 90 days.
|
|
@@ -22,7 +22,6 @@ Session Steward makes session cleanup safer by finding those records, showing wh
|
|
|
22
22
|
- Inspect session details and affected records before deletion.
|
|
23
23
|
- Read a session timeline of what you asked, what changed, and which commands ran.
|
|
24
24
|
- See how many tokens a session used, split into fresh input, cached input, cache writes, and output.
|
|
25
|
-
- Let compatible local MCP clients inspect sessions and help identify what is worth reviewing.
|
|
26
25
|
- Choose standard or thorough cleanup.
|
|
27
26
|
- Use custom Codex or Claude home folders across browser and terminal sessions.
|
|
28
27
|
|
|
@@ -34,7 +33,7 @@ Session Steward makes session cleanup safer by finding those records, showing wh
|
|
|
34
33
|
- Cleanup is verified before the backup is removed.
|
|
35
34
|
- Unrecognized storage is reported and left untouched.
|
|
36
35
|
- Thorough cleanup is unavailable when the detected storage format is not supported.
|
|
37
|
-
-
|
|
36
|
+
- Cleanup stays local and does not upload session contents.
|
|
38
37
|
|
|
39
38
|
At startup, Session Steward may contact the public npm registry to check for a newer version.
|
|
40
39
|
|
|
@@ -207,34 +206,45 @@ Run `inactive`, `archive`, or `workspace` without a value to clear that filter.
|
|
|
207
206
|
|
|
208
207
|
Use `session-steward-cli --help` to see all available options.
|
|
209
208
|
|
|
210
|
-
##
|
|
209
|
+
## Clean up sessions with ChatGPT or Claude
|
|
211
210
|
|
|
212
|
-
Session Steward
|
|
213
|
-
|
|
214
|
-
|
|
211
|
+
Connect Session Steward once, then ask ChatGPT or Claude to find old or large
|
|
212
|
+
sessions, delete them safely, restore a backup, or clean sessions automatically
|
|
213
|
+
on a schedule.
|
|
215
214
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
- “Find old chats I have not used in 2 months that are over 500 MB.”
|
|
219
|
-
- “Show sessions from project x workspace, sorted by size, inactive for a month.”
|
|
220
|
-
- “Show the timeline and token usage for this session.”
|
|
221
|
-
|
|
222
|
-
Install Session Steward globally first, then register it with the clients you
|
|
223
|
-
use.
|
|
224
|
-
|
|
225
|
-
For Codex:
|
|
215
|
+
Connect it to ChatGPT and Codex:
|
|
226
216
|
|
|
227
217
|
```bash
|
|
228
218
|
codex mcp add session-steward -- session-steward-mcp
|
|
229
219
|
```
|
|
230
220
|
|
|
231
|
-
|
|
221
|
+
Connect it to Claude Code:
|
|
232
222
|
|
|
233
223
|
```bash
|
|
234
224
|
claude mcp add --scope user session-steward -- session-steward-mcp
|
|
235
225
|
```
|
|
236
226
|
|
|
237
|
-
|
|
227
|
+
You can then ask things like:
|
|
228
|
+
|
|
229
|
+
- “Find sessions I have not used in 60 days.”
|
|
230
|
+
- “Show sessions from this workspace, largest first.”
|
|
231
|
+
- “Delete those sessions.”
|
|
232
|
+
- “Every 12 days, delete sessions I have not used in 45 days.”
|
|
233
|
+
- “Restore my latest backup.”
|
|
234
|
+
|
|
235
|
+
Cleanup uses the same local backup and verification checks as the browser and
|
|
236
|
+
terminal. Codex or Claude Code asks for approval before cleanup, restore, or
|
|
237
|
+
schedule changes.
|
|
238
|
+
|
|
239
|
+
Scheduled cleanup continues in the background after you close Codex or Claude
|
|
240
|
+
Code. You can ask to pause, resume, run, change, or remove a schedule. Before
|
|
241
|
+
uninstalling Session Steward, stop scheduled cleanup:
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
session-steward-scheduler --stop
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
Check or remove the MCP connection at any time:
|
|
238
248
|
|
|
239
249
|
```bash
|
|
240
250
|
codex mcp list
|
|
@@ -244,12 +254,7 @@ claude mcp list
|
|
|
244
254
|
claude mcp remove --scope user session-steward
|
|
245
255
|
```
|
|
246
256
|
|
|
247
|
-
|
|
248
|
-
sessions. Use the normal npm uninstall command only if you also want to remove
|
|
249
|
-
the package.
|
|
250
|
-
|
|
251
|
-
For another compatible client, configure a local `stdio` server named
|
|
252
|
-
`session-steward` with `session-steward-mcp` as its command:
|
|
257
|
+
For another MCP client, add a local server named `session-steward`:
|
|
253
258
|
|
|
254
259
|
```json
|
|
255
260
|
{
|
|
@@ -261,31 +266,14 @@ For another compatible client, configure a local `stdio` server named
|
|
|
261
266
|
}
|
|
262
267
|
```
|
|
263
268
|
|
|
264
|
-
|
|
269
|
+
The MCP server uses the same provider folders selected in the browser or
|
|
270
|
+
terminal.
|
|
265
271
|
|
|
266
|
-
|
|
267
|
-
and terminal interfaces. You can override either folder in the MCP command:
|
|
268
|
-
|
|
269
|
-
```bash
|
|
270
|
-
codex mcp add session-steward -- session-steward-mcp \
|
|
271
|
-
--codex-home /path/to/.codex \
|
|
272
|
-
--claude-home /path/to/.claude
|
|
273
|
-
```
|
|
272
|
+
### Privacy
|
|
274
273
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
- Every tool call must choose `codex` or `claude-code`; it does not combine the
|
|
279
|
-
providers silently.
|
|
280
|
-
- Lists and timelines are bounded, and provider database and transcript paths
|
|
281
|
-
are omitted from results.
|
|
282
|
-
- Timeline results can contain session messages, commands, file names, and
|
|
283
|
-
workspace paths. Only request a timeline when that content is appropriate to
|
|
284
|
-
share with the configured client.
|
|
285
|
-
- Session Steward does not upload MCP results itself. Your MCP client may send
|
|
286
|
-
tool results to its AI provider under that product's privacy terms.
|
|
287
|
-
- MCP tools are read-only. Cleanup remains available only through the browser UI
|
|
288
|
-
and terminal CLI, with the existing review, backup, and verification flow.
|
|
274
|
+
The MCP server runs locally. Session details can include messages, commands,
|
|
275
|
+
file names, and workspace paths, and your MCP client may send that information
|
|
276
|
+
to its AI provider.
|
|
289
277
|
|
|
290
278
|
## Use a custom provider folder
|
|
291
279
|
|
|
@@ -20,8 +20,8 @@ const { values } = parseArgs({
|
|
|
20
20
|
if (values.help) {
|
|
21
21
|
process.stdout.write(`Usage: session-steward-mcp [options]
|
|
22
22
|
|
|
23
|
-
Run Session Steward's
|
|
24
|
-
|
|
23
|
+
Run Session Steward's MCP server over stdio. MCP clients start and stop this
|
|
24
|
+
process automatically. Destructive tools use the client's normal approval flow.
|
|
25
25
|
|
|
26
26
|
Options:
|
|
27
27
|
--codex-home <path> Use a custom Codex session folder
|
|
@@ -38,7 +38,7 @@ if (values.version) {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
const { createProviderSettings } = await import("../lib/settings.mjs");
|
|
41
|
-
const {
|
|
41
|
+
const { serveMcp } = await import("../lib/mcp.mjs");
|
|
42
42
|
const providerHomeOverrides = {};
|
|
43
43
|
|
|
44
44
|
if (values["codex-home"] !== undefined) {
|
|
@@ -49,7 +49,7 @@ if (values["claude-home"] !== undefined) {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
const settings = await createProviderSettings({ providerHomeOverrides });
|
|
52
|
-
const handle =
|
|
52
|
+
const handle = serveMcp({
|
|
53
53
|
onerror: (error) => process.stderr.write(`Session Steward MCP error: ${error.message}\n`),
|
|
54
54
|
settings,
|
|
55
55
|
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { parseArgs } from "node:util";
|
|
4
|
+
|
|
5
|
+
import { assertSupportedNode } from "../lib/runtime.mjs";
|
|
6
|
+
|
|
7
|
+
assertSupportedNode();
|
|
8
|
+
|
|
9
|
+
const { values } = parseArgs({
|
|
10
|
+
allowPositionals: false,
|
|
11
|
+
options: {
|
|
12
|
+
"config-directory": { type: "string" },
|
|
13
|
+
help: { short: "h", type: "boolean" },
|
|
14
|
+
"run-due": { type: "boolean" },
|
|
15
|
+
start: { type: "boolean" },
|
|
16
|
+
status: { type: "boolean" },
|
|
17
|
+
stop: { type: "boolean" },
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
if (values.help) {
|
|
22
|
+
process.stdout.write(`Usage: session-steward-scheduler <option>
|
|
23
|
+
|
|
24
|
+
Options:
|
|
25
|
+
--start Start automatic cleanup and enable it after restart
|
|
26
|
+
--stop Stop automatic cleanup and remove its startup task
|
|
27
|
+
--status Show whether automatic cleanup is running
|
|
28
|
+
--run-due Run due cleanup schedules once and exit
|
|
29
|
+
--config-directory <path> Use a specific Session Steward settings folder
|
|
30
|
+
-h, --help Show this help
|
|
31
|
+
`);
|
|
32
|
+
} else if ([values["run-due"], values.start, values.status, values.stop].filter(Boolean).length !== 1) {
|
|
33
|
+
process.stderr.write("Choose exactly one of --start, --stop, --status, or --run-due.\n");
|
|
34
|
+
process.exitCode = 1;
|
|
35
|
+
} else if (values["run-due"]) {
|
|
36
|
+
const { createCleanupScheduleStore, runDueCleanupSchedules } = await import(
|
|
37
|
+
"../lib/cleanup-schedules.mjs"
|
|
38
|
+
);
|
|
39
|
+
const { createProviderSettings } = await import("../lib/settings.mjs");
|
|
40
|
+
const settings = await createProviderSettings({
|
|
41
|
+
configDirectory: values["config-directory"],
|
|
42
|
+
});
|
|
43
|
+
const scheduleStore = createCleanupScheduleStore({
|
|
44
|
+
configDirectory: settings.getConfigDirectory(),
|
|
45
|
+
});
|
|
46
|
+
const results = await runDueCleanupSchedules({ scheduleStore, settings });
|
|
47
|
+
if (results.some((result) => ["failed", "recovery-failed"].includes(result.status))) {
|
|
48
|
+
process.exitCode = 1;
|
|
49
|
+
}
|
|
50
|
+
} else {
|
|
51
|
+
const { createCleanupSchedulerService } = await import(
|
|
52
|
+
"../lib/cleanup-scheduler-service.mjs"
|
|
53
|
+
);
|
|
54
|
+
const service = createCleanupSchedulerService({
|
|
55
|
+
configDirectory: values["config-directory"],
|
|
56
|
+
});
|
|
57
|
+
const status = values.start
|
|
58
|
+
? await service.start()
|
|
59
|
+
: values.stop ? await service.stop() : await service.status();
|
|
60
|
+
process.stdout.write(`Automatic cleanup is ${status.running ? "running" : "stopped"}.\n`);
|
|
61
|
+
}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { execFile as execFileCallback } from "node:child_process";
|
|
2
|
+
import { promises as fs } from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { promisify } from "node:util";
|
|
7
|
+
|
|
8
|
+
import { getDefaultConfigDirectory } from "./platform.mjs";
|
|
9
|
+
|
|
10
|
+
const execFile = promisify(execFileCallback);
|
|
11
|
+
const LABEL = "com.mallikcheripally.session-steward.cleanup";
|
|
12
|
+
const WINDOWS_TASK_NAME = "Session Steward Cleanup";
|
|
13
|
+
const RUNNER_PATH = fileURLToPath(new URL("../bin/session-steward-scheduler.mjs", import.meta.url));
|
|
14
|
+
|
|
15
|
+
function xml(value) {
|
|
16
|
+
return String(value)
|
|
17
|
+
.replaceAll("&", "&")
|
|
18
|
+
.replaceAll("<", "<")
|
|
19
|
+
.replaceAll(">", ">")
|
|
20
|
+
.replaceAll('"', """)
|
|
21
|
+
.replaceAll("'", "'");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function systemdArgument(value) {
|
|
25
|
+
return `"${String(value)
|
|
26
|
+
.replaceAll("%", "%%")
|
|
27
|
+
.replaceAll("\\", "\\\\")
|
|
28
|
+
.replaceAll('"', '\\"')
|
|
29
|
+
.replaceAll("$", "\\$")
|
|
30
|
+
.replaceAll("`", "\\`")}"`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function windowsArgument(value) {
|
|
34
|
+
return `"${String(value).replaceAll(/(\\*)"/gu, "$1$1\\\"").replaceAll(/(\\+)$/gu, "$1$1")}"`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async function writePrivateFile(filePath, contents) {
|
|
38
|
+
await fs.mkdir(path.dirname(filePath), { mode: 0o700, recursive: true });
|
|
39
|
+
await fs.writeFile(filePath, contents, { encoding: "utf8", mode: 0o600 });
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function exists(filePath) {
|
|
43
|
+
try {
|
|
44
|
+
await fs.access(filePath);
|
|
45
|
+
return true;
|
|
46
|
+
} catch {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function createCleanupSchedulerService({
|
|
52
|
+
configDirectory = getDefaultConfigDirectory(),
|
|
53
|
+
environment = process.env,
|
|
54
|
+
execute = execFile,
|
|
55
|
+
home = os.homedir(),
|
|
56
|
+
nodePath = process.execPath,
|
|
57
|
+
platform = process.platform,
|
|
58
|
+
runnerPath = RUNNER_PATH,
|
|
59
|
+
userId = typeof process.getuid === "function" ? process.getuid() : null,
|
|
60
|
+
} = {}) {
|
|
61
|
+
const launchAgentPath = path.join(home, "Library", "LaunchAgents", `${LABEL}.plist`);
|
|
62
|
+
const xdgConfigHome = path.isAbsolute(environment.XDG_CONFIG_HOME || "")
|
|
63
|
+
? environment.XDG_CONFIG_HOME
|
|
64
|
+
: path.join(home, ".config");
|
|
65
|
+
const systemdDirectory = path.join(xdgConfigHome, "systemd", "user");
|
|
66
|
+
const systemdServicePath = path.join(systemdDirectory, "session-steward-cleanup.service");
|
|
67
|
+
const systemdTimerPath = path.join(systemdDirectory, "session-steward-cleanup.timer");
|
|
68
|
+
|
|
69
|
+
async function command(commandName, args, { allowFailure = false } = {}) {
|
|
70
|
+
try {
|
|
71
|
+
await execute(commandName, args, { windowsHide: true });
|
|
72
|
+
return true;
|
|
73
|
+
} catch (error) {
|
|
74
|
+
if (allowFailure) return false;
|
|
75
|
+
throw new Error("Session Steward could not update the automatic cleanup scheduler.", {
|
|
76
|
+
cause: error,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function start() {
|
|
82
|
+
if (platform === "darwin") {
|
|
83
|
+
if (!Number.isSafeInteger(userId)) throw new Error("Session Steward could not identify this user.");
|
|
84
|
+
const target = `gui/${userId}`;
|
|
85
|
+
await writePrivateFile(launchAgentPath, `<?xml version="1.0" encoding="UTF-8"?>
|
|
86
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
87
|
+
<plist version="1.0"><dict>
|
|
88
|
+
<key>Label</key><string>${LABEL}</string>
|
|
89
|
+
<key>ProgramArguments</key><array>
|
|
90
|
+
<string>${xml(nodePath)}</string>
|
|
91
|
+
<string>${xml(runnerPath)}</string>
|
|
92
|
+
<string>--run-due</string>
|
|
93
|
+
<string>--config-directory</string>
|
|
94
|
+
<string>${xml(configDirectory)}</string>
|
|
95
|
+
</array>
|
|
96
|
+
<key>RunAtLoad</key><true/>
|
|
97
|
+
<key>StartInterval</key><integer>900</integer>
|
|
98
|
+
</dict></plist>
|
|
99
|
+
`);
|
|
100
|
+
await command("launchctl", ["bootout", `${target}/${LABEL}`], { allowFailure: true });
|
|
101
|
+
await command("launchctl", ["bootstrap", target, launchAgentPath]);
|
|
102
|
+
await command("launchctl", ["enable", `${target}/${LABEL}`]);
|
|
103
|
+
return status();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (platform === "linux") {
|
|
107
|
+
await writePrivateFile(systemdServicePath, `[Unit]
|
|
108
|
+
Description=Session Steward automatic cleanup
|
|
109
|
+
|
|
110
|
+
[Service]
|
|
111
|
+
Type=oneshot
|
|
112
|
+
ExecStart=${systemdArgument(nodePath)} ${systemdArgument(runnerPath)} --run-due --config-directory ${systemdArgument(configDirectory)}
|
|
113
|
+
`);
|
|
114
|
+
await writePrivateFile(systemdTimerPath, `[Unit]
|
|
115
|
+
Description=Run Session Steward automatic cleanup
|
|
116
|
+
|
|
117
|
+
[Timer]
|
|
118
|
+
OnBootSec=2min
|
|
119
|
+
OnUnitActiveSec=15min
|
|
120
|
+
Persistent=true
|
|
121
|
+
|
|
122
|
+
[Install]
|
|
123
|
+
WantedBy=timers.target
|
|
124
|
+
`);
|
|
125
|
+
await command("systemctl", ["--user", "daemon-reload"]);
|
|
126
|
+
await command("systemctl", ["--user", "enable", "--now", "session-steward-cleanup.timer"]);
|
|
127
|
+
return status();
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (platform === "win32") {
|
|
131
|
+
const taskCommand = [
|
|
132
|
+
nodePath,
|
|
133
|
+
runnerPath,
|
|
134
|
+
"--run-due",
|
|
135
|
+
"--config-directory",
|
|
136
|
+
configDirectory,
|
|
137
|
+
].map(windowsArgument).join(" ");
|
|
138
|
+
await command("schtasks", [
|
|
139
|
+
"/Create", "/F", "/SC", "MINUTE", "/MO", "15",
|
|
140
|
+
"/TN", WINDOWS_TASK_NAME,
|
|
141
|
+
"/TR", taskCommand,
|
|
142
|
+
]);
|
|
143
|
+
return status();
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
throw new Error(`Automatic cleanup is not supported on ${platform}.`);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
async function stop() {
|
|
150
|
+
if (platform === "darwin") {
|
|
151
|
+
if (Number.isSafeInteger(userId)) {
|
|
152
|
+
await command("launchctl", ["bootout", `gui/${userId}/${LABEL}`], {
|
|
153
|
+
allowFailure: true,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
await fs.rm(launchAgentPath, { force: true });
|
|
157
|
+
return status();
|
|
158
|
+
}
|
|
159
|
+
if (platform === "linux") {
|
|
160
|
+
await command("systemctl", ["--user", "disable", "--now", "session-steward-cleanup.timer"], {
|
|
161
|
+
allowFailure: true,
|
|
162
|
+
});
|
|
163
|
+
await Promise.all([
|
|
164
|
+
fs.rm(systemdServicePath, { force: true }),
|
|
165
|
+
fs.rm(systemdTimerPath, { force: true }),
|
|
166
|
+
]);
|
|
167
|
+
await command("systemctl", ["--user", "daemon-reload"], { allowFailure: true });
|
|
168
|
+
return status();
|
|
169
|
+
}
|
|
170
|
+
if (platform === "win32") {
|
|
171
|
+
await command("schtasks", ["/Delete", "/F", "/TN", WINDOWS_TASK_NAME], {
|
|
172
|
+
allowFailure: true,
|
|
173
|
+
});
|
|
174
|
+
return status();
|
|
175
|
+
}
|
|
176
|
+
return { platform, running: false, supported: false };
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async function status() {
|
|
180
|
+
if (platform === "darwin") {
|
|
181
|
+
const running = Number.isSafeInteger(userId)
|
|
182
|
+
? await command("launchctl", ["print", `gui/${userId}/${LABEL}`], { allowFailure: true })
|
|
183
|
+
: false;
|
|
184
|
+
return { platform, running, supported: true };
|
|
185
|
+
}
|
|
186
|
+
if (platform === "linux") {
|
|
187
|
+
const configured = await exists(systemdTimerPath);
|
|
188
|
+
const running = configured
|
|
189
|
+
? await command("systemctl", ["--user", "is-active", "--quiet", "session-steward-cleanup.timer"], {
|
|
190
|
+
allowFailure: true,
|
|
191
|
+
})
|
|
192
|
+
: false;
|
|
193
|
+
return { platform, running, supported: true };
|
|
194
|
+
}
|
|
195
|
+
if (platform === "win32") {
|
|
196
|
+
const running = await command("schtasks", ["/Query", "/TN", WINDOWS_TASK_NAME], {
|
|
197
|
+
allowFailure: true,
|
|
198
|
+
});
|
|
199
|
+
return { platform, running, supported: true };
|
|
200
|
+
}
|
|
201
|
+
return { platform, running: false, supported: false };
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return { start, status, stop };
|
|
205
|
+
}
|