uv-suite 0.26.2 → 0.26.3

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.
@@ -0,0 +1,124 @@
1
+ #!/bin/bash
2
+ # UV Suite helper: locate per-session checkpoint paths and print metadata.
3
+ # Used by the /checkpoint and /restore slash commands.
4
+ #
5
+ # Usage:
6
+ # checkpoint-helper.sh dir # ensure + print the dir for current session
7
+ # checkpoint-helper.sh meta # print session metadata as shell-eval'able lines
8
+ # checkpoint-helper.sh frontmatter # YAML frontmatter to embed at the top of a checkpoint
9
+ # checkpoint-helper.sh latest # cat the latest checkpoint for current session (with fallback)
10
+ # checkpoint-helper.sh list # list all sessions that have checkpoints, newest first
11
+
12
+ resolve_paths() {
13
+ PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"
14
+ STATE_DIR="$PROJECT_DIR/.uv-suite-state"
15
+ SID="${UVS_SESSION_ID:-}"
16
+ if [ -z "$SID" ] && [ -f "$STATE_DIR/current-session.txt" ]; then
17
+ SID=$(cat "$STATE_DIR/current-session.txt" 2>/dev/null)
18
+ fi
19
+ CHECKPOINTS_ROOT="$PROJECT_DIR/uv-out/checkpoints"
20
+ SESSION_CP_DIR=""
21
+ [ -n "$SID" ] && SESSION_CP_DIR="$CHECKPOINTS_ROOT/$SID"
22
+ META_FILE=""
23
+ [ -n "$SID" ] && META_FILE="$STATE_DIR/sessions/$SID.json"
24
+ }
25
+
26
+ print_meta_field() {
27
+ # $1 = field name; reads from $META_FILE; empty if missing
28
+ [ -z "$META_FILE" ] || [ ! -f "$META_FILE" ] && { echo ""; return; }
29
+ if command -v jq >/dev/null 2>&1; then
30
+ jq -r --arg k "$1" '.[$k] // ""' "$META_FILE" 2>/dev/null
31
+ else
32
+ grep -o "\"$1\"[[:space:]]*:[[:space:]]*\"[^\"]*\"" "$META_FILE" | head -1 | sed "s/.*\"$1\"[[:space:]]*:[[:space:]]*\"\(.*\)\"/\1/"
33
+ fi
34
+ }
35
+
36
+ resolve_paths
37
+
38
+ case "$1" in
39
+ dir)
40
+ if [ -n "$SESSION_CP_DIR" ]; then
41
+ mkdir -p "$SESSION_CP_DIR"
42
+ echo "$SESSION_CP_DIR"
43
+ else
44
+ mkdir -p "$CHECKPOINTS_ROOT"
45
+ echo "$CHECKPOINTS_ROOT"
46
+ fi
47
+ ;;
48
+ meta)
49
+ echo "uvs_session_id=${SID:-}"
50
+ echo "session_name=$(print_meta_field name)"
51
+ echo "session_kind=$(print_meta_field kind)"
52
+ echo "session_purpose=$(print_meta_field purpose)"
53
+ echo "session_priority=$(print_meta_field priority)"
54
+ echo "persona=$(print_meta_field persona)"
55
+ ;;
56
+ frontmatter)
57
+ NAME=$(print_meta_field name)
58
+ KIND=$(print_meta_field kind)
59
+ PURPOSE=$(print_meta_field purpose)
60
+ PRIORITY=$(print_meta_field priority)
61
+ PERSONA=$(print_meta_field persona)
62
+ NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
63
+ cat <<EOF
64
+ ---
65
+ uvs_session_id: ${SID:-}
66
+ session_name: ${NAME}
67
+ session_kind: ${KIND}
68
+ session_purpose: ${PURPOSE}
69
+ session_priority: ${PRIORITY}
70
+ persona: ${PERSONA}
71
+ checkpoint_at: ${NOW}
72
+ ---
73
+ EOF
74
+ ;;
75
+ latest)
76
+ if [ -n "$SESSION_CP_DIR" ] && [ -f "$SESSION_CP_DIR/latest.md" ]; then
77
+ cat "$SESSION_CP_DIR/latest.md"
78
+ elif [ -f "$CHECKPOINTS_ROOT/latest.md" ]; then
79
+ echo "(no per-session checkpoint for ${SID:-this session}; showing legacy global latest.md)"
80
+ echo
81
+ cat "$CHECKPOINTS_ROOT/latest.md"
82
+ else
83
+ echo "No checkpoint found at $CHECKPOINTS_ROOT. Run /checkpoint to create one."
84
+ fi
85
+ ;;
86
+ list)
87
+ [ ! -d "$CHECKPOINTS_ROOT" ] && { echo "No checkpoints directory at $CHECKPOINTS_ROOT"; exit 0; }
88
+ found=0
89
+ for d in "$CHECKPOINTS_ROOT"/*/; do
90
+ [ -d "$d" ] || continue
91
+ cp_sid=$(basename "$d")
92
+ cp_meta="$STATE_DIR/sessions/$cp_sid.json"
93
+ cp_name=""
94
+ cp_priority=""
95
+ if [ -f "$cp_meta" ]; then
96
+ if command -v jq >/dev/null 2>&1; then
97
+ cp_name=$(jq -r '.name // ""' "$cp_meta" 2>/dev/null)
98
+ cp_priority=$(jq -r '.priority // ""' "$cp_meta" 2>/dev/null)
99
+ else
100
+ cp_name=$(grep -o '"name"[[:space:]]*:[[:space:]]*"[^"]*"' "$cp_meta" | head -1 | sed 's/.*"name"[[:space:]]*:[[:space:]]*"\(.*\)"/\1/')
101
+ fi
102
+ fi
103
+ latest=$(ls -t "$d"*.md 2>/dev/null | head -1)
104
+ [ -z "$latest" ] && continue
105
+ ts=$(stat -f '%Sm' -t '%Y-%m-%d %H:%M' "$latest" 2>/dev/null || stat -c '%y' "$latest" 2>/dev/null | cut -c1-16)
106
+ label="${cp_name:-(unlabeled)}"
107
+ [ -n "$cp_priority" ] && label="$label [p:$cp_priority]"
108
+ mark=" "
109
+ [ "$cp_sid" = "$SID" ] && mark="*"
110
+ echo "$mark ${cp_sid:0:8} $ts $label"
111
+ found=1
112
+ done
113
+ [ "$found" -eq 0 ] && echo "No per-session checkpoints yet (current session: ${SID:-none})"
114
+ # Note legacy global checkpoint if present
115
+ if [ -f "$CHECKPOINTS_ROOT/latest.md" ]; then
116
+ ts=$(stat -f '%Sm' -t '%Y-%m-%d %H:%M' "$CHECKPOINTS_ROOT/latest.md" 2>/dev/null || stat -c '%y' "$CHECKPOINTS_ROOT/latest.md" 2>/dev/null | cut -c1-16)
117
+ echo " legacy $ts (pre-metadata global latest.md)"
118
+ fi
119
+ ;;
120
+ *)
121
+ echo "Usage: checkpoint-helper.sh [dir|meta|frontmatter|latest|list]"
122
+ exit 1
123
+ ;;
124
+ esac
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uv-suite",
3
- "version": "0.26.2",
3
+ "version": "0.26.3",
4
4
  "description": "Portable framework for AI-assisted software development. 10 agents, 9 skills, 5 hooks, 4 personas. Works with Claude Code, Cursor, and Codex.",
5
5
  "author": "Utsav Anand",
6
6
  "license": "MIT",
@@ -3,7 +3,8 @@ name: checkpoint
3
3
  description: >
4
4
  Save a checkpoint of the current session — what was done, key decisions, current state,
5
5
  and what's next. Use before ending a session, before /compact, or at any natural breakpoint.
6
- The next session auto-loads the latest checkpoint.
6
+ Checkpoints are stored per-session under uv-out/checkpoints/<session-id>/, so concurrent
7
+ terminals don't clobber each other. /restore picks up the latest for the current session.
7
8
  argument-hint: "[optional-label]"
8
9
  user-invocable: true
9
10
  allowed-tools:
@@ -12,39 +13,51 @@ allowed-tools:
12
13
  - Bash(git status *)
13
14
  - Bash(git diff *)
14
15
  - Bash(git log *)
16
+ - Bash(git branch *)
15
17
  - Bash(git rev-parse *)
16
18
  - Bash(date *)
17
19
  - Bash(ls *)
18
20
  - Bash(mkdir *)
21
+ - Bash(cat *)
19
22
  - Bash(echo *)
23
+ - Bash("$CLAUDE_PROJECT_DIR"/.claude/hooks/checkpoint-helper.sh *)
20
24
  ---
21
25
 
22
- ## Resolve checkpoint directory
26
+ ## Resolve session and checkpoint directory
23
27
 
24
- Anchor checkpoints to `$CLAUDE_PROJECT_DIR` (or the git repo root, or the current
25
- working dir as a last resort) so `/checkpoint` and `/restore` always agree, no matter
26
- which subdirectory the session was launched from.
27
-
28
- !`DIR="${CLAUDE_PROJECT_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/uv-out/checkpoints"; mkdir -p "$DIR"; echo "$DIR"`
28
+ !`"$CLAUDE_PROJECT_DIR"/.claude/hooks/checkpoint-helper.sh dir`
29
29
 
30
30
  Use the absolute path printed above as `<checkpoint-dir>` for every file path below.
31
+ The directory is per-session — two `uv` launches in the same repo write to
32
+ different folders, so checkpoints don't collide.
33
+
34
+ ## Session metadata
35
+
36
+ !`"$CLAUDE_PROJECT_DIR"/.claude/hooks/checkpoint-helper.sh meta`
37
+
38
+ ## Frontmatter to embed at the top of the checkpoint
39
+
40
+ !`"$CLAUDE_PROJECT_DIR"/.claude/hooks/checkpoint-helper.sh frontmatter`
31
41
 
32
42
  ## Write a checkpoint
33
43
 
34
- Write a file named `<checkpoint-dir>/YYYY-MM-DD-HHMM.md` using the current timestamp.
44
+ Write a file named `<checkpoint-dir>/YYYY-MM-DD-HHMM.md` using the current
45
+ timestamp. **Begin the file with the YAML frontmatter block printed above
46
+ exactly as shown** — `/restore` parses these fields when picking which
47
+ checkpoint to load.
35
48
 
36
- Also write/overwrite `<checkpoint-dir>/latest.md` with the same content, so the next
37
- session's `/restore` always finds the freshest state.
49
+ Also write/overwrite `<checkpoint-dir>/latest.md` with the same content,
50
+ so the next session's `/restore` always finds the freshest state for this
51
+ session.
38
52
 
39
53
  ## Label
40
54
 
41
55
  $ARGUMENTS
42
56
 
43
- If a label was provided, include it in the filename: `<checkpoint-dir>/YYYY-MM-DD-HHMM-[label].md`
44
-
45
- ## What to capture
57
+ If a label was provided, include it in the filename:
58
+ `<checkpoint-dir>/YYYY-MM-DD-HHMM-[label].md`
46
59
 
47
- Review the full conversation so far and write a structured checkpoint with these exact sections:
60
+ ## Body structure (after the frontmatter)
48
61
 
49
62
  ```markdown
50
63
  # Checkpoint: [date] [time] [label if provided]
@@ -88,5 +101,5 @@ Review the full conversation so far and write a structured checkpoint with these
88
101
 
89
102
  - Be specific. "Worked on auth" is useless. "Added JWT refresh token rotation with 7-day expiry" is useful.
90
103
  - Capture WHY decisions were made, not just what. The next session needs the rationale.
91
- - Keep it under 80 lines. This isn't a novel it's a handoff.
92
- - Every checkpoint overwrites `latest.md` so the next session always finds the freshest state.
104
+ - Keep the body under 80 lines. The frontmatter is required and not counted.
105
+ - Always include the YAML frontmatter — `/restore` reads it to pick the right checkpoint and to display session context.
@@ -1,25 +1,55 @@
1
1
  ---
2
2
  name: restore
3
3
  description: >
4
- Restore the latest checkpoint from a previous session. Shows what was done,
5
- key decisions, current state, and what's next. Use at the start of a new session.
4
+ Restore the latest checkpoint for the current session shows what was done,
5
+ key decisions, current state, and what's next. With no arguments, picks the
6
+ current `UVS_SESSION_ID`'s most recent checkpoint. Pass a session id prefix
7
+ or name to restore from a different session.
8
+ argument-hint: "[<session-id-prefix> | <session-name> | list]"
6
9
  user-invocable: true
7
10
  allowed-tools:
8
11
  - Read(*)
9
12
  - Bash(ls *)
10
13
  - Bash(cat *)
11
14
  - Bash(grep *)
15
+ - Bash(find *)
12
16
  - Bash(git rev-parse *)
17
+ - Bash("$CLAUDE_PROJECT_DIR"/.claude/hooks/checkpoint-helper.sh *)
13
18
  ---
14
19
 
15
- ## Latest checkpoint
20
+ ## Available sessions with checkpoints
16
21
 
17
- !`DIR="${CLAUDE_PROJECT_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/uv-out/checkpoints"; if [ -f "$DIR/latest.md" ]; then cat "$DIR/latest.md"; else echo "No checkpoint found at $DIR. Run /checkpoint to create one."; fi`
22
+ !`"$CLAUDE_PROJECT_DIR"/.claude/hooks/checkpoint-helper.sh list`
18
23
 
19
- ## All checkpoints
24
+ (`*` marks the current session.)
20
25
 
21
- !`DIR="${CLAUDE_PROJECT_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/uv-out/checkpoints"; if [ -d "$DIR" ]; then matches=$(ls -la "$DIR"/ 2>/dev/null | grep '\.md$' | tail -10); if [ -n "$matches" ]; then echo "$matches"; else echo "No checkpoints in $DIR"; fi; else echo "No checkpoints directory at $DIR"; fi`
26
+ ## Latest checkpoint for the current session
27
+
28
+ !`"$CLAUDE_PROJECT_DIR"/.claude/hooks/checkpoint-helper.sh latest`
29
+
30
+ ## Argument
31
+
32
+ $ARGUMENTS
22
33
 
23
34
  ## Instructions
24
35
 
25
- Read the checkpoint above. Summarize it to the user in 3-4 sentences: what was done, what's the current state, and what's next. Then ask: "Ready to pick up from here, or do you want to take a different direction?"
36
+ 1. **If `$ARGUMENTS` is empty or "latest"**: read the checkpoint shown above (the
37
+ current session's `latest.md`). Summarize it in 3-4 sentences: what was
38
+ done, current state, what's next. Then ask: "Ready to pick up from here, or
39
+ do you want to take a different direction?"
40
+
41
+ 2. **If `$ARGUMENTS` is "list"**: just show the user the available-sessions
42
+ list above and ask which one they want to restore.
43
+
44
+ 3. **If `$ARGUMENTS` looks like a session id prefix** (8-char hex / UUID-ish)
45
+ **or a session name**: match it against the list above. Read the
46
+ matching session's `latest.md` from
47
+ `<project>/uv-out/checkpoints/<full-session-id>/latest.md` using the Read
48
+ tool, then summarize as in (1).
49
+
50
+ 4. If no match is found, list the available sessions and ask the user to
51
+ pick one.
52
+
53
+ When summarizing, include the session's name and purpose from the
54
+ frontmatter at the top of the checkpoint — that's the context the next
55
+ session needs to know what it's picking up.