claude-code-recap 1.2.0
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/LICENSE +21 -0
- package/README.md +279 -0
- package/bin/cli.mjs +286 -0
- package/install.sh +249 -0
- package/package.json +55 -0
- package/skills/recap/SKILL.md +103 -0
- package/skills/recap/recap.py +620 -0
package/install.sh
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# install.sh: install the recap skill for Claude Code.
|
|
3
|
+
#
|
|
4
|
+
# curl -fsSL https://raw.githubusercontent.com/noluyorAbi/claude-code-recap/main/install.sh | sh
|
|
5
|
+
#
|
|
6
|
+
# Copies skills/recap into $CLAUDE_CONFIG_DIR/skills/recap (default ~/.claude/skills/recap).
|
|
7
|
+
# Works from a git checkout and from a curl pipe, where $0 is not a usable path
|
|
8
|
+
# and the skill files are fetched from GitHub instead.
|
|
9
|
+
#
|
|
10
|
+
# Flags:
|
|
11
|
+
# --force overwrite an existing install, even if it was modified locally
|
|
12
|
+
# --uninstall remove the files this script installed
|
|
13
|
+
# --help show usage
|
|
14
|
+
#
|
|
15
|
+
# Env:
|
|
16
|
+
# CLAUDE_CONFIG_DIR Claude Code config dir (default: $HOME/.claude)
|
|
17
|
+
# RECAP_REF git ref to fetch when running from a pipe (default: main)
|
|
18
|
+
# RECAP_TARBALL full tarball URL, overrides REPO/REF (used by the tests)
|
|
19
|
+
|
|
20
|
+
set -eu
|
|
21
|
+
|
|
22
|
+
REPO="noluyorAbi/claude-code-recap"
|
|
23
|
+
REF="${RECAP_REF:-main}"
|
|
24
|
+
SKILL_NAME="recap"
|
|
25
|
+
MANIFEST_NAME=".claude-code-recap-manifest.json"
|
|
26
|
+
TRACKED="SKILL.md recap.py"
|
|
27
|
+
|
|
28
|
+
FORCE=0
|
|
29
|
+
UNINSTALL=0
|
|
30
|
+
TMPDIR_SELF=""
|
|
31
|
+
|
|
32
|
+
usage() {
|
|
33
|
+
cat <<'EOF'
|
|
34
|
+
install.sh: install the recap skill for Claude Code.
|
|
35
|
+
|
|
36
|
+
Usage:
|
|
37
|
+
./install.sh [--force] [--uninstall]
|
|
38
|
+
curl -fsSL https://raw.githubusercontent.com/noluyorAbi/claude-code-recap/main/install.sh | sh
|
|
39
|
+
|
|
40
|
+
Options:
|
|
41
|
+
--force overwrite an existing install, even if it has local edits
|
|
42
|
+
--uninstall remove the files this script installed
|
|
43
|
+
-h, --help show this help
|
|
44
|
+
|
|
45
|
+
Environment:
|
|
46
|
+
CLAUDE_CONFIG_DIR Claude Code config dir (default: $HOME/.claude)
|
|
47
|
+
RECAP_REF git ref fetched when piped from curl (default: main)
|
|
48
|
+
EOF
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
die() {
|
|
52
|
+
printf 'install.sh: %s\n' "$1" >&2
|
|
53
|
+
exit 1
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
cleanup() {
|
|
57
|
+
if [ -n "$TMPDIR_SELF" ] && [ -d "$TMPDIR_SELF" ]; then
|
|
58
|
+
rm -rf "$TMPDIR_SELF"
|
|
59
|
+
fi
|
|
60
|
+
}
|
|
61
|
+
trap cleanup EXIT HUP INT TERM
|
|
62
|
+
|
|
63
|
+
for arg in "$@"; do
|
|
64
|
+
case "$arg" in
|
|
65
|
+
--force) FORCE=1 ;;
|
|
66
|
+
--uninstall) UNINSTALL=1 ;;
|
|
67
|
+
-h|--help) usage; exit 0 ;;
|
|
68
|
+
*) printf 'install.sh: unknown option: %s\n\n' "$arg" >&2; usage >&2; exit 2 ;;
|
|
69
|
+
esac
|
|
70
|
+
done
|
|
71
|
+
|
|
72
|
+
CONFIG_DIR="${CLAUDE_CONFIG_DIR:-$HOME/.claude}"
|
|
73
|
+
DEST="$CONFIG_DIR/skills/$SKILL_NAME"
|
|
74
|
+
MANIFEST="$DEST/$MANIFEST_NAME"
|
|
75
|
+
|
|
76
|
+
sha256() {
|
|
77
|
+
if command -v shasum >/dev/null 2>&1; then
|
|
78
|
+
shasum -a 256 "$1" | awk '{print $1}'
|
|
79
|
+
elif command -v sha256sum >/dev/null 2>&1; then
|
|
80
|
+
sha256sum "$1" | awk '{print $1}'
|
|
81
|
+
else
|
|
82
|
+
die "need shasum or sha256sum to verify installed files"
|
|
83
|
+
fi
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
# Emit "<relative-path> <sha256>" for every file recorded in the manifest.
|
|
87
|
+
manifest_entries() {
|
|
88
|
+
sed -n '/"files"[[:space:]]*:/,/}/p' "$1" |
|
|
89
|
+
sed -n 's/^[[:space:]]*"\([^"]*\)"[[:space:]]*:[[:space:]]*"\([0-9a-f]\{64\}\)".*/\1 \2/p'
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
# Print every tracked file whose content no longer matches the manifest.
|
|
93
|
+
modified_files() {
|
|
94
|
+
[ -f "$MANIFEST" ] || return 0
|
|
95
|
+
manifest_entries "$MANIFEST" | while read -r rel recorded; do
|
|
96
|
+
[ -f "$DEST/$rel" ] || continue
|
|
97
|
+
if [ "$(sha256 "$DEST/$rel")" != "$recorded" ]; then
|
|
98
|
+
printf '%s\n' "$rel"
|
|
99
|
+
fi
|
|
100
|
+
done
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
skill_version() {
|
|
104
|
+
sed -n 's/^[[:space:]]\{1,\}version:[[:space:]]*"\{0,1\}\([0-9][0-9A-Za-z.+-]*\)"\{0,1\}[[:space:]]*$/\1/p' "$1" |
|
|
105
|
+
head -n 1
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
# ---------- uninstall ----------
|
|
109
|
+
if [ "$UNINSTALL" -eq 1 ]; then
|
|
110
|
+
if [ ! -d "$DEST" ]; then
|
|
111
|
+
printf 'recap is not installed (%s does not exist).\n' "$DEST"
|
|
112
|
+
exit 0
|
|
113
|
+
fi
|
|
114
|
+
|
|
115
|
+
if [ ! -f "$MANIFEST" ]; then
|
|
116
|
+
if [ "$FORCE" -ne 1 ]; then
|
|
117
|
+
printf 'install.sh: %s exists but was not installed by this script (no manifest).\n' "$DEST" >&2
|
|
118
|
+
printf 'Refusing to remove it. Re-run with --force to delete it anyway.\n' >&2
|
|
119
|
+
exit 1
|
|
120
|
+
fi
|
|
121
|
+
rm -rf "$DEST"
|
|
122
|
+
printf 'Removed %s (forced, no manifest).\n' "$DEST"
|
|
123
|
+
exit 0
|
|
124
|
+
fi
|
|
125
|
+
|
|
126
|
+
changed="$(modified_files)"
|
|
127
|
+
if [ -n "$changed" ] && [ "$FORCE" -ne 1 ]; then
|
|
128
|
+
printf 'install.sh: these installed files have local edits:\n' >&2
|
|
129
|
+
printf '%s\n' "$changed" | sed 's/^/ /' >&2
|
|
130
|
+
printf 'Refusing to delete them. Back them up, then re-run with --force.\n' >&2
|
|
131
|
+
exit 1
|
|
132
|
+
fi
|
|
133
|
+
|
|
134
|
+
manifest_entries "$MANIFEST" | while read -r rel _hash; do
|
|
135
|
+
rm -f "$DEST/$rel"
|
|
136
|
+
done
|
|
137
|
+
rm -f "$MANIFEST"
|
|
138
|
+
# Prune empty directories bottom-up, including DEST itself when nothing is left.
|
|
139
|
+
find "$DEST" -depth -type d -empty -exec rmdir {} + 2>/dev/null || true
|
|
140
|
+
|
|
141
|
+
if [ -d "$DEST" ]; then
|
|
142
|
+
printf 'Removed the recap skill files from %s.\n' "$DEST"
|
|
143
|
+
printf 'Kept the directory: it still contains files this script did not install.\n'
|
|
144
|
+
else
|
|
145
|
+
printf 'Removed %s.\n' "$DEST"
|
|
146
|
+
fi
|
|
147
|
+
exit 0
|
|
148
|
+
fi
|
|
149
|
+
|
|
150
|
+
# ---------- locate the skill source ----------
|
|
151
|
+
SRC=""
|
|
152
|
+
SCRIPT_DIR=""
|
|
153
|
+
case "${0:-}" in
|
|
154
|
+
''|sh|-sh|bash|-bash|dash|-dash|zsh|-zsh) : ;;
|
|
155
|
+
*)
|
|
156
|
+
if [ -f "$0" ]; then
|
|
157
|
+
SCRIPT_DIR="$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)"
|
|
158
|
+
fi
|
|
159
|
+
;;
|
|
160
|
+
esac
|
|
161
|
+
|
|
162
|
+
if [ -n "$SCRIPT_DIR" ] && [ -f "$SCRIPT_DIR/skills/$SKILL_NAME/SKILL.md" ]; then
|
|
163
|
+
SRC="$SCRIPT_DIR/skills/$SKILL_NAME"
|
|
164
|
+
else
|
|
165
|
+
# Curl pipe: no local checkout, fetch the tarball.
|
|
166
|
+
command -v curl >/dev/null 2>&1 || die "curl is required to fetch the skill"
|
|
167
|
+
command -v tar >/dev/null 2>&1 || die "tar is required to unpack the skill"
|
|
168
|
+
TMPDIR_SELF="$(mktemp -d 2>/dev/null || mktemp -d -t recap)"
|
|
169
|
+
TARBALL="${RECAP_TARBALL:-https://codeload.github.com/$REPO/tar.gz/$REF}"
|
|
170
|
+
printf 'Fetching %s@%s ...\n' "$REPO" "$REF"
|
|
171
|
+
curl -fsSL --retry 2 -o "$TMPDIR_SELF/src.tar.gz" "$TARBALL" ||
|
|
172
|
+
die "could not download $TARBALL"
|
|
173
|
+
tar -xzf "$TMPDIR_SELF/src.tar.gz" -C "$TMPDIR_SELF" ||
|
|
174
|
+
die "could not unpack the archive downloaded from $TARBALL"
|
|
175
|
+
SRC="$(find "$TMPDIR_SELF" -type d -path "*/skills/$SKILL_NAME" | head -n 1)"
|
|
176
|
+
[ -n "$SRC" ] || die "downloaded archive does not contain skills/$SKILL_NAME"
|
|
177
|
+
fi
|
|
178
|
+
|
|
179
|
+
[ -f "$SRC/SKILL.md" ] || die "missing $SRC/SKILL.md"
|
|
180
|
+
[ -f "$SRC/recap.py" ] || die "missing $SRC/recap.py"
|
|
181
|
+
|
|
182
|
+
# The Agent Skills spec requires SKILL.md `name` to equal the directory name.
|
|
183
|
+
DECLARED="$(sed -n 's/^name:[[:space:]]*\([a-z0-9][a-z0-9-]*\)[[:space:]]*$/\1/p' "$SRC/SKILL.md" | head -n 1)"
|
|
184
|
+
[ "$DECLARED" = "$SKILL_NAME" ] ||
|
|
185
|
+
die "SKILL.md declares name '$DECLARED' but must declare '$SKILL_NAME'"
|
|
186
|
+
|
|
187
|
+
VERSION="$(skill_version "$SRC/SKILL.md")"
|
|
188
|
+
[ -n "$VERSION" ] || VERSION="unknown"
|
|
189
|
+
|
|
190
|
+
# ---------- guard an existing install ----------
|
|
191
|
+
if [ -d "$DEST" ]; then
|
|
192
|
+
if [ -f "$MANIFEST" ]; then
|
|
193
|
+
changed="$(modified_files)"
|
|
194
|
+
if [ -n "$changed" ] && [ "$FORCE" -ne 1 ]; then
|
|
195
|
+
printf 'install.sh: these installed files have local edits:\n' >&2
|
|
196
|
+
printf '%s\n' "$changed" | sed 's/^/ /' >&2
|
|
197
|
+
printf 'Refusing to overwrite them. Back them up, then re-run with --force.\n' >&2
|
|
198
|
+
exit 1
|
|
199
|
+
fi
|
|
200
|
+
manifest_entries "$MANIFEST" | while read -r rel _hash; do
|
|
201
|
+
rm -f "$DEST/$rel"
|
|
202
|
+
done
|
|
203
|
+
rm -f "$MANIFEST"
|
|
204
|
+
elif [ "$FORCE" -ne 1 ]; then
|
|
205
|
+
printf 'install.sh: %s already exists and was not installed by this script.\n' "$DEST" >&2
|
|
206
|
+
printf 'Refusing to overwrite it. Move it aside, or re-run with --force.\n' >&2
|
|
207
|
+
exit 1
|
|
208
|
+
fi
|
|
209
|
+
fi
|
|
210
|
+
|
|
211
|
+
# ---------- install ----------
|
|
212
|
+
mkdir -p "$DEST"
|
|
213
|
+
cp "$SRC/SKILL.md" "$DEST/SKILL.md"
|
|
214
|
+
cp "$SRC/recap.py" "$DEST/recap.py"
|
|
215
|
+
chmod 0644 "$DEST/SKILL.md"
|
|
216
|
+
chmod 0755 "$DEST/recap.py"
|
|
217
|
+
|
|
218
|
+
SKILL_SHA="$(sha256 "$DEST/SKILL.md")"
|
|
219
|
+
RECAP_SHA="$(sha256 "$DEST/recap.py")"
|
|
220
|
+
NOW="$(date -u '+%Y-%m-%dT%H:%M:%SZ')"
|
|
221
|
+
|
|
222
|
+
{
|
|
223
|
+
printf '{\n'
|
|
224
|
+
printf ' "tool": "claude-code-recap",\n'
|
|
225
|
+
printf ' "version": "%s",\n' "$VERSION"
|
|
226
|
+
printf ' "installedAt": "%s",\n' "$NOW"
|
|
227
|
+
printf ' "files": {\n'
|
|
228
|
+
printf ' "SKILL.md": "%s",\n' "$SKILL_SHA"
|
|
229
|
+
printf ' "recap.py": "%s"\n' "$RECAP_SHA"
|
|
230
|
+
printf ' }\n'
|
|
231
|
+
printf '}\n'
|
|
232
|
+
} >"$MANIFEST"
|
|
233
|
+
|
|
234
|
+
printf '\nInstalled the recap skill (v%s).\n' "$VERSION"
|
|
235
|
+
printf ' %s\n' "$DEST/SKILL.md"
|
|
236
|
+
printf ' %s\n' "$DEST/recap.py"
|
|
237
|
+
printf '\nClaude Code picks up %s/skills without a restart.\n' "$CONFIG_DIR"
|
|
238
|
+
printf 'Restart it only if that directory did not exist when the session started.\n'
|
|
239
|
+
printf '\nRun it with: /recap\n'
|
|
240
|
+
printf 'Or directly: python3 %s\n' "$DEST/recap.py"
|
|
241
|
+
printf 'Uninstall: ./install.sh --uninstall\n'
|
|
242
|
+
|
|
243
|
+
if ! command -v python3 >/dev/null 2>&1; then
|
|
244
|
+
printf '\nWarning: python3 was not found on PATH. The skill needs Python 3 to run.\n' >&2
|
|
245
|
+
fi
|
|
246
|
+
|
|
247
|
+
for rel in $TRACKED; do
|
|
248
|
+
[ -f "$DEST/$rel" ] || die "post-install check failed: $DEST/$rel is missing"
|
|
249
|
+
done
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "claude-code-recap",
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"description": "Installs the recap skill into your Claude Code skills directory: list recent sessions across every project and get a ready-to-paste resume command.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"claude-code-recap": "bin/cli.mjs"
|
|
8
|
+
},
|
|
9
|
+
"exports": {
|
|
10
|
+
"./package.json": "./package.json"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"bin/",
|
|
14
|
+
"skills/",
|
|
15
|
+
"install.sh",
|
|
16
|
+
"!**/__pycache__",
|
|
17
|
+
"!**/*.pyc"
|
|
18
|
+
],
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=18.17"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"claude-code",
|
|
24
|
+
"claude-code-skills",
|
|
25
|
+
"claude-code-skill",
|
|
26
|
+
"claude-skill",
|
|
27
|
+
"agent-skills",
|
|
28
|
+
"agent-skill",
|
|
29
|
+
"skill-md",
|
|
30
|
+
"skills",
|
|
31
|
+
"anthropic",
|
|
32
|
+
"claude",
|
|
33
|
+
"session-recap",
|
|
34
|
+
"resume",
|
|
35
|
+
"developer-tools",
|
|
36
|
+
"cli"
|
|
37
|
+
],
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "git+https://github.com/noluyorAbi/claude-code-recap.git"
|
|
41
|
+
},
|
|
42
|
+
"homepage": "https://github.com/noluyorAbi/claude-code-recap#readme",
|
|
43
|
+
"bugs": {
|
|
44
|
+
"url": "https://github.com/noluyorAbi/claude-code-recap/issues"
|
|
45
|
+
},
|
|
46
|
+
"license": "MIT",
|
|
47
|
+
"author": "noluyorAbi <121226886+noluyorAbi@users.noreply.github.com>",
|
|
48
|
+
"publishConfig": {
|
|
49
|
+
"access": "public"
|
|
50
|
+
},
|
|
51
|
+
"scripts": {
|
|
52
|
+
"check:version": "node scripts/check-version.mjs",
|
|
53
|
+
"test": "sh tests/smoke.sh"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: recap
|
|
3
|
+
description: Show recent Claude Code sessions across all projects, so the user can re-enter work after a reboot or context switch. Lists per session the absolute project path, a short summary, last activity, turn count, git branch, model, and a ready-to-paste resume command, and can re-open all of them at once in new terminal tabs. Use when the user asks "what was I working on", "which projects did I touch recently", "where did I leave off", "list my recent sessions", "how do I get back into that session", "open all my sessions again", or invokes /recap. Reads only local files; the default run is instant and offline.
|
|
4
|
+
license: MIT
|
|
5
|
+
metadata:
|
|
6
|
+
version: "1.2.0"
|
|
7
|
+
author: noluyorAbi
|
|
8
|
+
source: https://github.com/noluyorAbi/claude-code-recap
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# recap: re-entry radar for Claude Code sessions
|
|
12
|
+
|
|
13
|
+
One command, full overview of recent sessions across every project on this machine. Built for the post-reboot moment: which projects, what was each session about, and the exact command to jump back in.
|
|
14
|
+
|
|
15
|
+
## How to run it
|
|
16
|
+
|
|
17
|
+
Personal or project install (the skill directory is on disk next to this file):
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
python3 ~/.claude/skills/recap/recap.py [flags]
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Plugin install (Claude Code exports the plugin root):
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
python3 "$CLAUDE_PLUGIN_ROOT/skills/recap/recap.py" [flags]
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Nothing to install beyond Python 3 (stdlib only, no third-party packages).
|
|
30
|
+
|
|
31
|
+
| Flag | Meaning |
|
|
32
|
+
|------|---------|
|
|
33
|
+
| (none) | last 15 sessions, newest first, instant, no network |
|
|
34
|
+
| `--since 7d` | only sessions active in the window (`30m`, `24h`, `7d`, `2w`) |
|
|
35
|
+
| `--project foo` | filter by substring of the absolute project path |
|
|
36
|
+
| `--limit N` | max rows (default 15) |
|
|
37
|
+
| `--json` | machine-readable output with full session ids and resume commands |
|
|
38
|
+
| `--smart` | real one-sentence summaries via ONE `claude -p` haiku call (network, ~10s) |
|
|
39
|
+
| `--pick` | choose a row interactively, then `cd` + `claude -r` into it directly |
|
|
40
|
+
| `--open` | open EVERY listed session in its own new terminal tab and resume it there (macOS) |
|
|
41
|
+
| `--claude-flags "..."` | extra flags for each resumed `claude` (e.g. `"--chrome --dangerously-skip-permissions"`); also shown in the printed resume lines and `--json` |
|
|
42
|
+
| `--terminal auto\|iTerm2\|Terminal` | which app `--open` drives (default: iTerm2 when installed) |
|
|
43
|
+
| `--yes` / `-y` | skip the `--open` confirmation prompt (required when stdin is not a TTY) |
|
|
44
|
+
| `--dry-run` | with `--open`: print the tabs and commands, open nothing |
|
|
45
|
+
| `--color` | force ANSI colors when output is piped (e.g. inside Claude Code) |
|
|
46
|
+
| `--plain` | no ANSI at all (also honors NO_COLOR / FORCE_COLOR env) |
|
|
47
|
+
|
|
48
|
+
## Usage examples
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# after a reboot: what was I doing?
|
|
52
|
+
python3 ~/.claude/skills/recap/recap.py
|
|
53
|
+
|
|
54
|
+
# everything in one repo this week
|
|
55
|
+
python3 ~/.claude/skills/recap/recap.py --since 7d --project my-repo
|
|
56
|
+
|
|
57
|
+
# jump straight back into a session
|
|
58
|
+
python3 ~/.claude/skills/recap/recap.py --pick
|
|
59
|
+
|
|
60
|
+
# re-open yesterday's whole working set in terminal tabs, browser enabled, no permission prompts
|
|
61
|
+
python3 ~/.claude/skills/recap/recap.py --since 24h --limit 12 \
|
|
62
|
+
--open --yes --claude-flags "--chrome --dangerously-skip-permissions"
|
|
63
|
+
|
|
64
|
+
# preview first, open nothing
|
|
65
|
+
python3 ~/.claude/skills/recap/recap.py --open --dry-run
|
|
66
|
+
|
|
67
|
+
# feed into other tooling
|
|
68
|
+
python3 ~/.claude/skills/recap/recap.py --json --limit 50
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## The `--open` flag
|
|
72
|
+
|
|
73
|
+
Restores a whole working set at once. It opens one new tab per listed session and types the resume command into it. Rules:
|
|
74
|
+
|
|
75
|
+
- The session recap itself runs in is skipped automatically (matched on `CLAUDE_CODE_SESSION_ID`), so it never re-opens itself.
|
|
76
|
+
- Sessions whose project directory no longer exists are skipped and reported, never opened.
|
|
77
|
+
- Scope comes from the normal filters, so `--limit` / `--since` / `--project` decide exactly which tabs appear. Check with `--dry-run` before committing.
|
|
78
|
+
- Without `--yes` it asks for confirmation; with piped stdin (Claude Code's Bash tool) it refuses to open unless `--yes` is passed.
|
|
79
|
+
- `--claude-flags` is passed through verbatim to every tab. `--dangerously-skip-permissions` disables all permission checks in each opened session; the script prints a warning before doing it.
|
|
80
|
+
- Tab opening drives iTerm2 or Terminal through `osascript`, so it is macOS-only. On other platforms `--open` exits with a clear message; `--open --dry-run` still prints the commands so they can be pasted anywhere.
|
|
81
|
+
|
|
82
|
+
## When Claude runs this skill
|
|
83
|
+
|
|
84
|
+
Run the script with Bash, ALWAYS with `--color` (tool output is piped, auto-detection would strip the colors; Claude Code renders ANSI). Add `--since`/`--project` if the user narrowed the question, then relay the table. Quote the resume command (`cd <path> && claude -r <id>`) for any session the user wants to re-enter. Only add `--smart` if the user explicitly asks for better summaries; it makes a network call.
|
|
85
|
+
|
|
86
|
+
Use `--open` only when the user explicitly asks to re-open or resume the sessions. Because the Bash tool pipes stdin, `--open` needs `--yes`; treat the user's request as the confirmation, and set the scope with `--limit`/`--since` so no unwanted session gets a tab. Pass `--claude-flags` only with flags the user named; state the permission-bypass warning in your reply whenever `--dangerously-skip-permissions` is among them.
|
|
87
|
+
|
|
88
|
+
## Data sources and guarantees
|
|
89
|
+
|
|
90
|
+
- `~/.claude/history.jsonl` is the fast index (prompt text, timestamp, project path, session id). `CLAUDE_CONFIG_DIR` is honored when set.
|
|
91
|
+
- `~/.claude/projects/<encoded>/<session>.jsonl` transcripts are parsed only for the displayed rows (title, branch, model, turn count). Project paths always come from the `cwd`/`project` fields, never decoded from folder names (that encoding is lossy).
|
|
92
|
+
- Summary preference: Claude Code's own `ai-title` line, else the first real user prompt, else `(no prompt)`.
|
|
93
|
+
- `--smart` privacy: the only path that leaves the machine. It shells out to the local `claude` CLI once and sends, for the listed sessions only, each session's 8-character id prefix, its title (first 150 characters), and its first user prompt (first 300 characters). No file bodies, no transcript contents, no other sessions. If `claude` is not on PATH, `--smart` is skipped with a warning and the offline summaries are used.
|
|
94
|
+
- Turn count groups assistant streaming chunks by message id and is labeled approximate.
|
|
95
|
+
- Broken or partial JSONL lines are skipped, never fatal. Times shown in the local timezone.
|
|
96
|
+
- Display: day-grouped timeline (Today green, Yesterday amber), 14-day activity sparkline in the header, per-project colored dot (stable hash), four-level gray hierarchy with one accent color, per-session resume line indented with spaces only (safe to copy). Falls back to plain text when piped or when NO_COLOR is set.
|
|
97
|
+
- Read-only: the tool never writes or deletes anything. It sees only sessions still on disk (Claude Code prunes old ones). `--open` and `--pick` are the only side-effecting paths: `--open` drives iTerm2/Terminal via `osascript`, `--pick` `exec`s `claude -r` in the chosen directory. Neither writes or touches session data.
|
|
98
|
+
|
|
99
|
+
## Optional shell alias
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
alias recap='python3 ~/.claude/skills/recap/recap.py'
|
|
103
|
+
```
|