111 lines
3.4 KiB
JavaScript
Executable File
111 lines
3.4 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
|
|
/**
|
|
* SessionStart Hook
|
|
*
|
|
* Handles session state cleanup when /clear is executed.
|
|
* Clears active session markers to prevent confusion when context is lost.
|
|
*
|
|
* Hook receives:
|
|
* - source: "startup" | "resume" | "clear" | "compact"
|
|
* - session_id: string
|
|
* - cwd: string
|
|
* - permission_mode: string
|
|
*
|
|
* SAFETY: Includes graceful failure handling to avoid blocking Claude Code
|
|
* if plugin is uninstalled or dependencies are missing.
|
|
*/
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
// Graceful failure wrapper - protect against plugin uninstallation
|
|
try {
|
|
// Check if critical dependencies exist (indicates plugin is installed)
|
|
const cliLibPath = path.join(__dirname, '../cli/lib');
|
|
if (!fs.existsSync(cliLibPath)) {
|
|
// Plugin likely uninstalled, exit silently
|
|
process.exit(0);
|
|
}
|
|
|
|
// Import IndexManager for safe index updates
|
|
const IndexManager = require('../cli/lib/index-manager');
|
|
|
|
// Constants
|
|
const SESSIONS_DIR = '.claude/sessions';
|
|
const ACTIVE_SESSION_FILE = path.join(SESSIONS_DIR, '.active-session');
|
|
const indexManager = new IndexManager(SESSIONS_DIR);
|
|
|
|
try {
|
|
// Read input from stdin (provided by Claude Code)
|
|
const input = fs.readFileSync(0, 'utf8').trim();
|
|
|
|
// Parse the JSON input
|
|
let eventData;
|
|
try {
|
|
eventData = JSON.parse(input);
|
|
} catch (parseError) {
|
|
// If parsing fails, exit silently (no input provided)
|
|
process.exit(0);
|
|
}
|
|
|
|
const { source } = eventData;
|
|
|
|
// Only process when source is "clear"
|
|
// Other sources ("startup", "resume", "compact") should allow normal auto-resume
|
|
if (source === 'clear') {
|
|
let sessionName = null;
|
|
|
|
// Read the active session name before clearing (for the message)
|
|
if (fs.existsSync(ACTIVE_SESSION_FILE)) {
|
|
try {
|
|
sessionName = fs.readFileSync(ACTIVE_SESSION_FILE, 'utf8').trim();
|
|
} catch (readError) {
|
|
// Continue even if read fails
|
|
}
|
|
|
|
// Clear the .active-session file
|
|
try {
|
|
fs.unlinkSync(ACTIVE_SESSION_FILE);
|
|
} catch (unlinkError) {
|
|
// File may already be deleted, continue
|
|
}
|
|
}
|
|
|
|
// Update the index.json to clear activeSession using IndexManager
|
|
// This uses proper locking and atomic writes to prevent corruption
|
|
try {
|
|
const index = indexManager.read({ skipValidation: true });
|
|
index.activeSession = null;
|
|
indexManager.write(index);
|
|
} catch (indexError) {
|
|
// Continue even if index update fails
|
|
// This prevents blocking the hook if index is temporarily locked
|
|
}
|
|
|
|
// Inject helpful context message to Claude
|
|
const output = {
|
|
hookSpecificOutput: {
|
|
additionalContext: sessionName
|
|
? `📋 Session '${sessionName}' was auto-closed due to /clear command. The conversation context has been cleared.\n\nTo resume your work on this session, use: /session:continue ${sessionName}\nTo view all sessions, use: /session:list`
|
|
: 'Previous session was auto-closed due to /clear command. Use /session:list to view available sessions.'
|
|
}
|
|
};
|
|
|
|
// Output the context injection
|
|
console.log(JSON.stringify(output));
|
|
}
|
|
|
|
// Exit successfully
|
|
process.exit(0);
|
|
|
|
} catch (error) {
|
|
// Exit silently on any errors to avoid blocking Claude Code startup
|
|
process.exit(0);
|
|
}
|
|
} catch (error) {
|
|
// Outer catch: Handle plugin missing/uninstalled
|
|
// Exit silently to avoid blocking Claude Code
|
|
process.exit(0);
|
|
}
|