pi-session-cleanup 1.1.2 → 1.1.4
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 +12 -0
- package/package.json +66 -66
- package/src/index.ts +102 -10
- package/src/session-sort.ts +17 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [Unreleased]
|
|
4
|
+
|
|
5
|
+
## [1.1.4] - 2026-06-16
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- Added round-trip date validation for parsed calendar timestamps so invalid dates (e.g., month 13 or day 32) no longer produce false-positive sort keys.
|
|
9
|
+
|
|
10
|
+
## 1.1.3 - 2026-06-01
|
|
11
|
+
|
|
12
|
+
- Deferred command module loading for `/session-cleanup` and `/nix` handlers while preserving inline completions.
|
|
13
|
+
- Widened Pi coding-agent and Pi TUI peer dependency ranges to include `^0.77.0 || ^0.78.0`.
|
|
14
|
+
|
|
3
15
|
## 1.1.2 - 2026-05-26
|
|
4
16
|
|
|
5
17
|
- Widened peer dependency ranges to `^0.74.0 || ^0.75.0`.
|
package/package.json
CHANGED
|
@@ -1,66 +1,66 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "pi-session-cleanup",
|
|
3
|
-
"version": "1.1.
|
|
4
|
-
"description": "Pi extension for interactive batch session cleanup and safe deletion.",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "./index.ts",
|
|
7
|
-
"exports": {
|
|
8
|
-
".": "./index.ts"
|
|
9
|
-
},
|
|
10
|
-
"files": [
|
|
11
|
-
"index.ts",
|
|
12
|
-
"src",
|
|
13
|
-
"config/config.example.json",
|
|
14
|
-
"README.md",
|
|
15
|
-
"CHANGELOG.md",
|
|
16
|
-
"LICENSE"
|
|
17
|
-
],
|
|
18
|
-
"scripts": {
|
|
19
|
-
"build": "npx --yes -p typescript@5.7.3 tsc -p tsconfig.json --noCheck",
|
|
20
|
-
"lint": "npm run build",
|
|
21
|
-
"test:clean": "node -e \"require('node:fs').rmSync('.test-dist', { recursive: true, force: true })\"",
|
|
22
|
-
"pretest": "npm run test:clean",
|
|
23
|
-
"test": "npx --yes -p typescript@5.7.3 tsc -p tsconfig.test.json && node --test .test-dist/test/*.test.js",
|
|
24
|
-
"posttest": "npm run test:clean",
|
|
25
|
-
"check": "npm run lint && npm run test",
|
|
26
|
-
"package:dry-run": "npm pack --dry-run"
|
|
27
|
-
},
|
|
28
|
-
"keywords": [
|
|
29
|
-
"pi-package",
|
|
30
|
-
"pi",
|
|
31
|
-
"pi-extension",
|
|
32
|
-
"session",
|
|
33
|
-
"cleanup",
|
|
34
|
-
"delete",
|
|
35
|
-
"pi-coding-agent",
|
|
36
|
-
"pi-tui",
|
|
37
|
-
"session-management",
|
|
38
|
-
"tui",
|
|
39
|
-
"safe-delete"
|
|
40
|
-
],
|
|
41
|
-
"author": "MasuRii",
|
|
42
|
-
"license": "MIT",
|
|
43
|
-
"engines": {
|
|
44
|
-
"node": ">=20"
|
|
45
|
-
},
|
|
46
|
-
"publishConfig": {
|
|
47
|
-
"access": "public"
|
|
48
|
-
},
|
|
49
|
-
"pi": {
|
|
50
|
-
"extensions": [
|
|
51
|
-
"./index.ts"
|
|
52
|
-
]
|
|
53
|
-
},
|
|
54
|
-
"peerDependencies": {
|
|
55
|
-
"@earendil-works/pi-coding-agent": "^0.74.0 || ^0.75.0",
|
|
56
|
-
"@earendil-works/pi-tui": "^0.74.0 || ^0.75.0"
|
|
57
|
-
},
|
|
58
|
-
"repository": {
|
|
59
|
-
"type": "git",
|
|
60
|
-
"url": "git+https://github.com/MasuRii/pi-session-cleanup.git"
|
|
61
|
-
},
|
|
62
|
-
"bugs": {
|
|
63
|
-
"url": "https://github.com/MasuRii/pi-session-cleanup/issues"
|
|
64
|
-
},
|
|
65
|
-
"homepage": "https://github.com/MasuRii/pi-session-cleanup#readme"
|
|
66
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "pi-session-cleanup",
|
|
3
|
+
"version": "1.1.4",
|
|
4
|
+
"description": "Pi extension for interactive batch session cleanup and safe deletion.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./index.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./index.ts"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"index.ts",
|
|
12
|
+
"src",
|
|
13
|
+
"config/config.example.json",
|
|
14
|
+
"README.md",
|
|
15
|
+
"CHANGELOG.md",
|
|
16
|
+
"LICENSE"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "npx --yes -p typescript@5.7.3 tsc -p tsconfig.json --noCheck",
|
|
20
|
+
"lint": "npm run build",
|
|
21
|
+
"test:clean": "node -e \"require('node:fs').rmSync('.test-dist', { recursive: true, force: true })\"",
|
|
22
|
+
"pretest": "npm run test:clean",
|
|
23
|
+
"test": "npx --yes -p typescript@5.7.3 tsc -p tsconfig.test.json && node --test .test-dist/test/*.test.js",
|
|
24
|
+
"posttest": "npm run test:clean",
|
|
25
|
+
"check": "npm run lint && npm run test",
|
|
26
|
+
"package:dry-run": "npm pack --dry-run"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"pi-package",
|
|
30
|
+
"pi",
|
|
31
|
+
"pi-extension",
|
|
32
|
+
"session",
|
|
33
|
+
"cleanup",
|
|
34
|
+
"delete",
|
|
35
|
+
"pi-coding-agent",
|
|
36
|
+
"pi-tui",
|
|
37
|
+
"session-management",
|
|
38
|
+
"tui",
|
|
39
|
+
"safe-delete"
|
|
40
|
+
],
|
|
41
|
+
"author": "MasuRii",
|
|
42
|
+
"license": "MIT",
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=20"
|
|
45
|
+
},
|
|
46
|
+
"publishConfig": {
|
|
47
|
+
"access": "public"
|
|
48
|
+
},
|
|
49
|
+
"pi": {
|
|
50
|
+
"extensions": [
|
|
51
|
+
"./index.ts"
|
|
52
|
+
]
|
|
53
|
+
},
|
|
54
|
+
"peerDependencies": {
|
|
55
|
+
"@earendil-works/pi-coding-agent": "^0.74.0 || ^0.75.0 || ^0.78.0 || ^0.79.0",
|
|
56
|
+
"@earendil-works/pi-tui": "^0.74.0 || ^0.75.0 || ^0.78.0 || ^0.79.0"
|
|
57
|
+
},
|
|
58
|
+
"repository": {
|
|
59
|
+
"type": "git",
|
|
60
|
+
"url": "git+https://github.com/MasuRii/pi-session-cleanup.git"
|
|
61
|
+
},
|
|
62
|
+
"bugs": {
|
|
63
|
+
"url": "https://github.com/MasuRii/pi-session-cleanup/issues"
|
|
64
|
+
},
|
|
65
|
+
"homepage": "https://github.com/MasuRii/pi-session-cleanup#readme"
|
|
66
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,16 +1,104 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
|
|
3
3
|
import { SESSION_CLEANUP_COMMAND, SESSION_NIX_COMMAND } from "./constants.js";
|
|
4
|
-
import {
|
|
5
|
-
getSessionCleanupArgumentCompletions,
|
|
6
|
-
handleSessionCleanupCommand,
|
|
7
|
-
} from "./session-cleanup-command.js";
|
|
8
|
-
import {
|
|
9
|
-
getSessionNixArgumentCompletions,
|
|
10
|
-
handleSessionNixCommand,
|
|
11
|
-
} from "./session-nix-command.js";
|
|
12
4
|
import { flushScheduledSessionDeletionForQuit } from "./session-quit-shutdown.js";
|
|
13
5
|
|
|
6
|
+
type SessionCleanupCommandModule = typeof import("./session-cleanup-command.js");
|
|
7
|
+
type SessionNixCommandModule = typeof import("./session-nix-command.js");
|
|
8
|
+
type CommandCompletion = {
|
|
9
|
+
value: string;
|
|
10
|
+
label: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const SESSION_CLEANUP_ARGUMENT_COMPLETIONS = [
|
|
15
|
+
{
|
|
16
|
+
value: "current",
|
|
17
|
+
label: "current",
|
|
18
|
+
description: "List sessions from the current working directory only",
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
value: "all",
|
|
22
|
+
label: "all",
|
|
23
|
+
description: "List sessions across every working directory",
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
value: "help",
|
|
27
|
+
label: "help",
|
|
28
|
+
description: "Show usage",
|
|
29
|
+
},
|
|
30
|
+
] as const satisfies readonly CommandCompletion[];
|
|
31
|
+
|
|
32
|
+
const SESSION_NIX_ARGUMENT_COMPLETIONS = [
|
|
33
|
+
{
|
|
34
|
+
value: "quit",
|
|
35
|
+
label: "quit",
|
|
36
|
+
description: "Delete the current session and quit Pi immediately",
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
value: "agent",
|
|
40
|
+
label: "agent",
|
|
41
|
+
description: "Start a fresh session with a selected target agent",
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
value: "help",
|
|
45
|
+
label: "help",
|
|
46
|
+
description: "Show usage",
|
|
47
|
+
},
|
|
48
|
+
] as const satisfies readonly CommandCompletion[];
|
|
49
|
+
|
|
50
|
+
let sessionCleanupCommandModule: SessionCleanupCommandModule | undefined;
|
|
51
|
+
let sessionCleanupCommandModulePromise: Promise<SessionCleanupCommandModule> | undefined;
|
|
52
|
+
let sessionNixCommandModule: SessionNixCommandModule | undefined;
|
|
53
|
+
let sessionNixCommandModulePromise: Promise<SessionNixCommandModule> | undefined;
|
|
54
|
+
|
|
55
|
+
function loadSessionCleanupCommandModule(): Promise<SessionCleanupCommandModule> {
|
|
56
|
+
if (sessionCleanupCommandModule) {
|
|
57
|
+
return Promise.resolve(sessionCleanupCommandModule);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
sessionCleanupCommandModulePromise ??= import("./session-cleanup-command.js").then(
|
|
61
|
+
(module) => {
|
|
62
|
+
sessionCleanupCommandModule = module;
|
|
63
|
+
return module;
|
|
64
|
+
},
|
|
65
|
+
);
|
|
66
|
+
return sessionCleanupCommandModulePromise;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function loadSessionNixCommandModule(): Promise<SessionNixCommandModule> {
|
|
70
|
+
if (sessionNixCommandModule) {
|
|
71
|
+
return Promise.resolve(sessionNixCommandModule);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
sessionNixCommandModulePromise ??= import("./session-nix-command.js").then(
|
|
75
|
+
(module) => {
|
|
76
|
+
sessionNixCommandModule = module;
|
|
77
|
+
return module;
|
|
78
|
+
},
|
|
79
|
+
);
|
|
80
|
+
return sessionNixCommandModulePromise;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function getMatchedCompletions(
|
|
84
|
+
argumentPrefix: string,
|
|
85
|
+
completions: readonly CommandCompletion[],
|
|
86
|
+
): CommandCompletion[] | null {
|
|
87
|
+
const normalizedPrefix = argumentPrefix.trim().toLowerCase();
|
|
88
|
+
if (!normalizedPrefix) {
|
|
89
|
+
return completions.map((completion) => ({ ...completion }));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const matched = completions.filter((completion) =>
|
|
93
|
+
completion.value.startsWith(normalizedPrefix),
|
|
94
|
+
);
|
|
95
|
+
if (matched.length === 0) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return matched.map((completion) => ({ ...completion }));
|
|
100
|
+
}
|
|
101
|
+
|
|
14
102
|
export default function sessionCleanupExtension(pi: ExtensionAPI): void {
|
|
15
103
|
pi.on("session_shutdown", async (_event, ctx) => {
|
|
16
104
|
await flushScheduledSessionDeletionForQuit(ctx);
|
|
@@ -19,8 +107,10 @@ export default function sessionCleanupExtension(pi: ExtensionAPI): void {
|
|
|
19
107
|
pi.registerCommand(SESSION_CLEANUP_COMMAND, {
|
|
20
108
|
description:
|
|
21
109
|
"Batch-select previous sessions and delete them with confirmation.",
|
|
22
|
-
getArgumentCompletions:
|
|
110
|
+
getArgumentCompletions: (argumentPrefix) =>
|
|
111
|
+
getMatchedCompletions(argumentPrefix, SESSION_CLEANUP_ARGUMENT_COMPLETIONS),
|
|
23
112
|
handler: async (args, ctx) => {
|
|
113
|
+
const { handleSessionCleanupCommand } = await loadSessionCleanupCommandModule();
|
|
24
114
|
await handleSessionCleanupCommand(args, ctx);
|
|
25
115
|
},
|
|
26
116
|
});
|
|
@@ -28,8 +118,10 @@ export default function sessionCleanupExtension(pi: ExtensionAPI): void {
|
|
|
28
118
|
pi.registerCommand(SESSION_NIX_COMMAND, {
|
|
29
119
|
description:
|
|
30
120
|
"Start a fresh session, switch to a target agent, or delete the current session and quit Pi.",
|
|
31
|
-
getArgumentCompletions:
|
|
121
|
+
getArgumentCompletions: (argumentPrefix) =>
|
|
122
|
+
getMatchedCompletions(argumentPrefix, SESSION_NIX_ARGUMENT_COMPLETIONS),
|
|
32
123
|
handler: async (args, ctx) => {
|
|
124
|
+
const { handleSessionNixCommand } = await loadSessionNixCommandModule();
|
|
33
125
|
await handleSessionNixCommand(args, ctx);
|
|
34
126
|
},
|
|
35
127
|
});
|
package/src/session-sort.ts
CHANGED
|
@@ -69,7 +69,23 @@ function parseCalendarCandidate(path: string): number | null {
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
const utcTimestamp = Date.UTC(year, month - 1, day, hour, minute, second);
|
|
72
|
-
|
|
72
|
+
if (!Number.isFinite(utcTimestamp)) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const parsed = new Date(utcTimestamp);
|
|
77
|
+
if (
|
|
78
|
+
parsed.getUTCFullYear() !== year ||
|
|
79
|
+
parsed.getUTCMonth() !== month - 1 ||
|
|
80
|
+
parsed.getUTCDate() !== day ||
|
|
81
|
+
parsed.getUTCHours() !== hour ||
|
|
82
|
+
parsed.getUTCMinutes() !== minute ||
|
|
83
|
+
parsed.getUTCSeconds() !== second
|
|
84
|
+
) {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return utcTimestamp;
|
|
73
89
|
}
|
|
74
90
|
|
|
75
91
|
function timestampFromPath(sessionPath: string): number {
|