Skip to content

Commit d85b1ae

Browse files
xcfdszzr王志坚claude
authored
feat: add /sessions command for session history management (anomalyco#142)
Add a new /sessions command to manage Claude Code session history with alias support for quick access to previous sessions. Features: - List sessions with pagination and filtering (by date, ID) - Load and view session content and metadata - Create memorable aliases for sessions - Remove aliases - Display session statistics (lines, items, size) - List all aliases New libraries: - scripts/lib/session-manager.js - Core session CRUD operations - scripts/lib/session-aliases.js - Alias management with atomic saves New command: - commands/sessions.md - Complete command with embedded scripts Modified: - scripts/lib/utils.js - Add getAliasesPath() export - scripts/hooks/session-start.js - Show available aliases on session start Session format support: - Old: YYYY-MM-DD-session.tmp - New: YYYY-MM-DD-<short-id>-session.tmp Aliases are stored in ~/.claude/session-aliases.json with Windows- compatible atomic writes and backup support. Co-authored-by: 王志坚 <[email protected]> Co-authored-by: Claude <[email protected]>
1 parent e7cb442 commit d85b1ae

5 files changed

Lines changed: 1152 additions & 0 deletions

File tree

‎commands/sessions.md‎

Lines changed: 305 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,305 @@
1+
# Sessions Command
2+
3+
Manage Claude Code session history - list, load, alias, and edit sessions stored in `~/.claude/sessions/`.
4+
5+
## Usage
6+
7+
`/sessions [list|load|alias|info|help] [options]`
8+
9+
## Actions
10+
11+
### List Sessions
12+
13+
Display all sessions with metadata, filtering, and pagination.
14+
15+
```bash
16+
/sessions # List all sessions (default)
17+
/sessions list # Same as above
18+
/sessions list --limit 10 # Show 10 sessions
19+
/sessions list --date 2026-02-01 # Filter by date
20+
/sessions list --search abc # Search by session ID
21+
```
22+
23+
**Script:**
24+
```bash
25+
node -e "
26+
const sm = require('./scripts/lib/session-manager');
27+
const aa = require('./scripts/lib/session-aliases');
28+
29+
const result = sm.getAllSessions({ limit: 20 });
30+
const aliases = aa.listAliases();
31+
const aliasMap = {};
32+
for (const a of aliases) aliasMap[a.sessionPath] = a.name;
33+
34+
console.log('Sessions (showing ' + result.sessions.length + ' of ' + result.total + '):');
35+
console.log('');
36+
console.log('ID Date Time Size Lines Alias');
37+
console.log('────────────────────────────────────────────────────');
38+
39+
for (const s of result.sessions) {
40+
const alias = aliasMap[s.filename] || '';
41+
const size = sm.getSessionSize(s.sessionPath);
42+
const stats = sm.getSessionStats(s.sessionPath);
43+
const id = s.shortId === 'no-id' ? '(none)' : s.shortId.slice(0, 8);
44+
const time = s.modifiedTime.toTimeString().slice(0, 5);
45+
46+
console.log(id.padEnd(8) + ' ' + s.date + ' ' + time + ' ' + size.padEnd(7) + ' ' + String(stats.lineCount).padEnd(5) + ' ' + alias);
47+
}
48+
"
49+
```
50+
51+
### Load Session
52+
53+
Load and display a session's content (by ID or alias).
54+
55+
```bash
56+
/sessions load <id|alias> # Load session
57+
/sessions load 2026-02-01 # By date (for no-id sessions)
58+
/sessions load a1b2c3d4 # By short ID
59+
/sessions load my-alias # By alias name
60+
```
61+
62+
**Script:**
63+
```bash
64+
node -e "
65+
const sm = require('./scripts/lib/session-manager');
66+
const aa = require('./scripts/lib/session-aliases');
67+
const id = process.argv[1];
68+
69+
// First try to resolve as alias
70+
const resolved = aa.resolveAlias(id);
71+
const sessionId = resolved ? resolved.sessionPath : id;
72+
73+
const session = sm.getSessionById(sessionId, true);
74+
if (!session) {
75+
console.log('Session not found: ' + id);
76+
process.exit(1);
77+
}
78+
79+
const stats = sm.getSessionStats(session.sessionPath);
80+
const size = sm.getSessionSize(session.sessionPath);
81+
const aliases = aa.getAliasesForSession(session.filename);
82+
83+
console.log('Session: ' + session.filename);
84+
console.log('Path: ~/.claude/sessions/' + session.filename);
85+
console.log('');
86+
console.log('Statistics:');
87+
console.log(' Lines: ' + stats.lineCount);
88+
console.log(' Total items: ' + stats.totalItems);
89+
console.log(' Completed: ' + stats.completedItems);
90+
console.log(' In progress: ' + stats.inProgressItems);
91+
console.log(' Size: ' + size);
92+
console.log('');
93+
94+
if (aliases.length > 0) {
95+
console.log('Aliases: ' + aliases.map(a => a.name).join(', '));
96+
console.log('');
97+
}
98+
99+
if (session.metadata.title) {
100+
console.log('Title: ' + session.metadata.title);
101+
console.log('');
102+
}
103+
104+
if (session.metadata.started) {
105+
console.log('Started: ' + session.metadata.started);
106+
}
107+
108+
if (session.metadata.lastUpdated) {
109+
console.log('Last Updated: ' + session.metadata.lastUpdated);
110+
}
111+
" "$ARGUMENTS"
112+
```
113+
114+
### Create Alias
115+
116+
Create a memorable alias for a session.
117+
118+
```bash
119+
/sessions alias <id> <name> # Create alias
120+
/sessions alias 2026-02-01 today-work # Create alias named "today-work"
121+
```
122+
123+
**Script:**
124+
```bash
125+
node -e "
126+
const sm = require('./scripts/lib/session-manager');
127+
const aa = require('./scripts/lib/session-aliases');
128+
129+
const sessionId = process.argv[1];
130+
const aliasName = process.argv[2];
131+
132+
if (!sessionId || !aliasName) {
133+
console.log('Usage: /sessions alias <id> <name>');
134+
process.exit(1);
135+
}
136+
137+
// Get session filename
138+
const session = sm.getSessionById(sessionId);
139+
if (!session) {
140+
console.log('Session not found: ' + sessionId);
141+
process.exit(1);
142+
}
143+
144+
const result = aa.setAlias(aliasName, session.filename);
145+
if (result.success) {
146+
console.log('✓ Alias created: ' + aliasName + ' → ' + session.filename);
147+
} else {
148+
console.log('✗ Error: ' + result.error);
149+
process.exit(1);
150+
}
151+
" "$ARGUMENTS"
152+
```
153+
154+
### Remove Alias
155+
156+
Delete an existing alias.
157+
158+
```bash
159+
/sessions alias --remove <name> # Remove alias
160+
/sessions unalias <name> # Same as above
161+
```
162+
163+
**Script:**
164+
```bash
165+
node -e "
166+
const aa = require('./scripts/lib/session-aliases');
167+
168+
const aliasName = process.argv[1];
169+
if (!aliasName) {
170+
console.log('Usage: /sessions alias --remove <name>');
171+
process.exit(1);
172+
}
173+
174+
const result = aa.deleteAlias(aliasName);
175+
if (result.success) {
176+
console.log('✓ Alias removed: ' + aliasName);
177+
} else {
178+
console.log('✗ Error: ' + result.error);
179+
process.exit(1);
180+
}
181+
" "$ARGUMENTS"
182+
```
183+
184+
### Session Info
185+
186+
Show detailed information about a session.
187+
188+
```bash
189+
/sessions info <id|alias> # Show session details
190+
```
191+
192+
**Script:**
193+
```bash
194+
node -e "
195+
const sm = require('./scripts/lib/session-manager');
196+
const aa = require('./scripts/lib/session-aliases');
197+
198+
const id = process.argv[1];
199+
const resolved = aa.resolveAlias(id);
200+
const sessionId = resolved ? resolved.sessionPath : id;
201+
202+
const session = sm.getSessionById(sessionId, true);
203+
if (!session) {
204+
console.log('Session not found: ' + id);
205+
process.exit(1);
206+
}
207+
208+
const stats = sm.getSessionStats(session.sessionPath);
209+
const size = sm.getSessionSize(session.sessionPath);
210+
const aliases = aa.getAliasesForSession(session.filename);
211+
212+
console.log('Session Information');
213+
console.log('════════════════════');
214+
console.log('ID: ' + (session.shortId === 'no-id' ? '(none)' : session.shortId));
215+
console.log('Filename: ' + session.filename);
216+
console.log('Date: ' + session.date);
217+
console.log('Modified: ' + session.modifiedTime.toISOString().slice(0, 19).replace('T', ' '));
218+
console.log('');
219+
console.log('Content:');
220+
console.log(' Lines: ' + stats.lineCount);
221+
console.log(' Total items: ' + stats.totalItems);
222+
console.log(' Completed: ' + stats.completedItems);
223+
console.log(' In progress: ' + stats.inProgressItems);
224+
console.log(' Size: ' + size);
225+
if (aliases.length > 0) {
226+
console.log('Aliases: ' + aliases.map(a => a.name).join(', '));
227+
}
228+
" "$ARGUMENTS"
229+
```
230+
231+
### List Aliases
232+
233+
Show all session aliases.
234+
235+
```bash
236+
/sessions aliases # List all aliases
237+
```
238+
239+
**Script:**
240+
```bash
241+
node -e "
242+
const aa = require('./scripts/lib/session-aliases');
243+
244+
const aliases = aa.listAliases();
245+
console.log('Session Aliases (' + aliases.length + '):');
246+
console.log('');
247+
248+
if (aliases.length === 0) {
249+
console.log('No aliases found.');
250+
} else {
251+
console.log('Name Session File Title');
252+
console.log('─────────────────────────────────────────────────────────────');
253+
for (const a of aliases) {
254+
const name = a.name.padEnd(12);
255+
const file = (a.sessionPath.length > 30 ? a.sessionPath.slice(0, 27) + '...' : a.sessionPath).padEnd(30);
256+
const title = a.title || '';
257+
console.log(name + ' ' + file + ' ' + title);
258+
}
259+
}
260+
"
261+
```
262+
263+
## Arguments
264+
265+
$ARGUMENTS:
266+
- `list [options]` - List sessions
267+
- `--limit <n>` - Max sessions to show (default: 50)
268+
- `--date <YYYY-MM-DD>` - Filter by date
269+
- `--search <pattern>` - Search in session ID
270+
- `load <id|alias>` - Load session content
271+
- `alias <id> <name>` - Create alias for session
272+
- `alias --remove <name>` - Remove alias
273+
- `unalias <name>` - Same as `--remove`
274+
- `info <id|alias>` - Show session statistics
275+
- `aliases` - List all aliases
276+
- `help` - Show this help
277+
278+
## Examples
279+
280+
```bash
281+
# List all sessions
282+
/sessions list
283+
284+
# Create an alias for today's session
285+
/sessions alias 2026-02-01 today
286+
287+
# Load session by alias
288+
/sessions load today
289+
290+
# Show session info
291+
/sessions info today
292+
293+
# Remove alias
294+
/sessions alias --remove today
295+
296+
# List all aliases
297+
/sessions aliases
298+
```
299+
300+
## Notes
301+
302+
- Sessions are stored as markdown files in `~/.claude/sessions/`
303+
- Aliases are stored in `~/.claude/session-aliases.json`
304+
- Session IDs can be shortened (first 4-8 characters usually unique enough)
305+
- Use aliases for frequently referenced sessions

‎scripts/hooks/session-start.js‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const {
1616
log
1717
} = require('../lib/utils');
1818
const { getPackageManager, getSelectionPrompt } = require('../lib/package-manager');
19+
const { listAliases } = require('../lib/session-aliases');
1920

2021
async function main() {
2122
const sessionsDir = getSessionsDir();
@@ -42,6 +43,15 @@ async function main() {
4243
log(`[SessionStart] ${learnedSkills.length} learned skill(s) available in ${learnedDir}`);
4344
}
4445

46+
// Check for available session aliases
47+
const aliases = listAliases({ limit: 5 });
48+
49+
if (aliases.length > 0) {
50+
const aliasNames = aliases.map(a => a.name).join(', ');
51+
log(`[SessionStart] ${aliases.length} session alias(es) available: ${aliasNames}`);
52+
log(`[SessionStart] Use /sessions load <alias> to continue a previous session`);
53+
}
54+
4555
// Detect and report package manager
4656
const pm = getPackageManager();
4757
log(`[SessionStart] Package manager: ${pm.name} (${pm.source})`);

0 commit comments

Comments
 (0)