Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@alexismunozdev/claude-session-topics",
"version": "5.3.2",
"version": "5.3.3",
"description": "Session topics for Claude Code — auto-set and display a topic in the statusline, change anytime with /set-topic",
"bin": {
"claude-session-topics": "bin/install.js"
Expand Down
71 changes: 71 additions & 0 deletions scripts/cleanup-orphan-sessions.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#!/bin/bash
# Remove orphan Claude Code sessions left behind by older versions of
# claude-session-topics, when the headless `claude -p` title-generation run
# persisted its own transcript under ~/.claude/projects/<cwd>/. Those show up in
# the IDE session list with the title prompt as their preview.
#
# Fixed in 5.3.3 via --no-session-persistence; this purges the ones already on disk.
#
# Usage:
# ./scripts/cleanup-orphan-sessions.sh # dry-run: list what would be deleted
# ./scripts/cleanup-orphan-sessions.sh --apply # actually delete

set -euo pipefail

APPLY=0
[ "${1:-}" = "--apply" ] && APPLY=1

PROJECTS_DIR="${CLAUDE_CONFIG_DIR:-$HOME/.claude}/projects"

# Signature of the title-generation prompt (matches the instruction in
# user-prompt-hook.sh). Only files whose first user message contains this are
# considered orphans.
SIGNATURE='Genera un título corto'

# Defensive cap: real sessions are longer than a single title-gen round-trip.
MAX_LINES=20

if [ ! -d "$PROJECTS_DIR" ]; then
echo "No projects directory at $PROJECTS_DIR — nothing to do."
exit 0
fi

HAS_JQ=0
command -v jq >/dev/null 2>&1 && HAS_JQ=1

# Returns 0 if the first user message of $1 matches the title-gen signature.
is_orphan() {
local file="$1" first
if [ "$HAS_JQ" = "1" ]; then
first=$(jq -r 'select(.type=="user") | (.message.content // "") | tostring' "$file" 2>/dev/null | head -n 1)
case "$first" in
*"$SIGNATURE"*) return 0 ;;
*) return 1 ;;
esac
fi
# jq-less fallback: scan the first few KB for the signature.
head -c 4000 "$file" 2>/dev/null | grep -q "$SIGNATURE"
}

found=0
deleted=0
while IFS= read -r -d '' file; do
lines=$(wc -l <"$file" 2>/dev/null | tr -d ' ')
[ -z "$lines" ] && continue
[ "$lines" -gt "$MAX_LINES" ] && continue
is_orphan "$file" || continue
found=$((found + 1))
if [ "$APPLY" = "1" ]; then
rm -f "$file" && deleted=$((deleted + 1))
echo "deleted: $file"
else
echo "would delete: $file (${lines} lines)"
fi
done < <(find "$PROJECTS_DIR" -type f -name '*.jsonl' -print0 2>/dev/null)

echo
if [ "$APPLY" = "1" ]; then
echo "Deleted $deleted orphan session(s)."
else
echo "Found $found orphan session(s). Re-run with --apply to delete them."
fi
6 changes: 5 additions & 1 deletion scripts/user-prompt-hook.sh
Original file line number Diff line number Diff line change
Expand Up @@ -283,9 +283,13 @@ refine_topic() {
# so the model can't burn the single turn on a tool call (which would make the
# CLI emit "Error: Reached max turns 1" to stdout and get written as the topic).
# --output-format json lets us accept the result only when is_error is false.
# --no-session-persistence keeps this headless run from writing its own
# transcript under ~/.claude/projects/<cwd>/, which otherwise shows up as an
# orphan session in the IDE list with the title prompt as its preview.
printf '%s' "$full_prompt" | CLAUDE_SESSION_TOPICS_SKIP=1 \
run_with_timeout 30 claude -p --model haiku --max-turns 1 \
--strict-mcp-config --allowedTools "" --output-format json >"$out_file" 2>/dev/null || true
--strict-mcp-config --allowedTools "" --no-session-persistence \
--output-format json >"$out_file" 2>/dev/null || true
if command -v jq >/dev/null 2>&1; then
refined=$(jq -r 'select(.is_error == false) | .result // empty' "$out_file" 2>/dev/null \
| grep -v '^[[:space:]]*$' | head -n 1 || true)
Expand Down
2 changes: 1 addition & 1 deletion skills/set-topic/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: set-topic
description: Set or change the session topic displayed in the statusline
argument-hint: <topic text>
allowed-tools: [Bash]
version: "5.3.2"
version: "5.3.3"
---

Set the session topic to: $ARGUMENTS
Expand Down
7 changes: 7 additions & 0 deletions tests/integration/test_topic_flow.bats
Original file line number Diff line number Diff line change
Expand Up @@ -221,3 +221,10 @@ EOF
run bash "$test_script"
[ "$status" -eq 0 ]
}

@test "test_refine_uses_no_session_persistence" {
# The headless `claude -p` title-generation run must not persist its own
# transcript, or it shows up as an orphan session in the IDE list.
run grep -q -- "--no-session-persistence" "$PROJECT_ROOT/scripts/user-prompt-hook.sh"
[ "$status" -eq 0 ]
}
Loading