* fix: filter session-start injection by cwd/project to prevent cross-project contamination
The SessionStart hook previously selected the most recent session file
purely by timestamp, ignoring the current working directory. This caused
Claude to receive a previous project's session context when switching
between projects, leading to incorrect file reads and project analysis.
session-end.js already writes **Project:** and **Worktree:** header
fields into each session file. This commit adds selectMatchingSession()
which uses those fields with the following priority:
1. Exact worktree (cwd) match — most recent
2. Same project name match — most recent
3. Fallback to overall most recent (preserves backward compatibility)
No new dependencies. Gracefully falls back to original behavior when
no matching session exists.
* fix: address review feedback — eliminate duplicate I/O, add null guards, improve docstrings
- Return { session, content, matchReason } from selectMatchingSession()
to avoid reading the same file twice (coderabbitai, greptile P2)
- Add empty array guard: return null when sessions.length === 0 (coderabbitai)
- Stop mutating input objects — no more session._matchReason (coderabbitai)
- Add null check on result before accessing properties (coderabbitai)
- Only log "selected" after confirming content is readable (cubic-dev-ai P3)
- Add full JSDoc with @param/@returns (docstring coverage)
* fix: track fallback session object to prevent session/content mismatch
When sessions[0] is unreadable, fallbackContent came from a later
session (e.g. sessions[1]) while the returned session object still
pointed to sessions[0]. This caused misleading logs and injected
content from the wrong session — the exact problem this PR fixes.
Now tracks fallbackSession alongside fallbackContent so the returned
pair is always consistent.
Addresses greptile-apps P1 review feedback.
* fix: normalize worktree paths to handle symlinks and case differences
On macOS /var is a symlink to /private/var, and on Windows paths may
differ in casing (C:\repo vs c:\repo). Use fs.realpathSync() to
resolve both sides before comparison so worktree matching is reliable
across symlinked and case-insensitive filesystems.
cwd is normalized once outside the loop to avoid repeated syscalls.
Addresses coderabbitai Major review feedback.
---------
Co-authored-by: kuqili <kuqili@tencent.com>
Windows terminals emit control sequences (cursor movement, screen
clearing) that leaked into session.tmp files and were injected
verbatim into Claude's context on the next session start.
Add a comprehensive stripAnsi() to utils.js that handles CSI, OSC,
charset selection, and bare ESC sequences. Apply it in session-end.js
(when extracting user messages from the transcript) and in
session-start.js (safety net before injecting session content).
getAvailablePackageManagers() spawned where.exe/which for each package
manager (npm, pnpm, yarn, bun). During SessionStart hooks, these 4+
child processes combined with Bun's own initialization exceeded the
spawn limit on Windows, freezing the terminal.
Fix: Remove process spawning from the hot path. Steps 1-5 of detection
(env var, project config, package.json, lock file, global config) already
cover all file-based detection. If none match, default to npm without
spawning. Also fix getSelectionPrompt() to list supported PMs without
checking availability.
session-end.js: Extract meaningful summaries from CLAUDE_TRANSCRIPT_PATH
instead of writing blank template files. Pulls user messages, tools used,
and files modified from the session transcript JSONL.
session-start.js: Output the latest session summary to stdout (via the
output() helper) so it gets injected into Claude's conversation context,
instead of only logging to stderr which just shows briefly in the terminal.
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: 王志坚 <wangzhijian10@bgyfw.com>
Co-authored-by: Claude <noreply@anthropic.com>
- Fix 16 ESLint no-unused-vars errors across hook scripts and tests
- Add eslint-disable comment for intentional control-regex in ANSI stripper
- Update session file test to use getSessionIdShort() instead of hardcoded 'default'
(reflects PR #110's project-name fallback behavior)
- Add marketing/ to .gitignore (local drafts)
- Add skill-create-output.js (terminal output formatter)
All 69 tests now pass. CI should be green.