uv-suite 0.26.1 → 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.
@@ -1,22 +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 *)
13
+ - Bash(cat *)
14
+ - Bash(grep *)
15
+ - Bash(find *)
16
+ - Bash(git rev-parse *)
17
+ - Bash("$CLAUDE_PROJECT_DIR"/.claude/hooks/checkpoint-helper.sh *)
10
18
  ---
11
19
 
12
- ## Latest checkpoint
20
+ ## Available sessions with checkpoints
13
21
 
14
- !`cat uv-out/checkpoints/latest.md 2>/dev/null || echo "No checkpoint found. Run /checkpoint to create one."`
22
+ !`"$CLAUDE_PROJECT_DIR"/.claude/hooks/checkpoint-helper.sh list`
15
23
 
16
- ## All checkpoints
24
+ (`*` marks the current session.)
17
25
 
18
- !`ls -la uv-out/checkpoints/*.md 2>/dev/null | tail -10 || echo "No checkpoints directory"`
26
+ ## Latest checkpoint for the current session
27
+
28
+ !`"$CLAUDE_PROJECT_DIR"/.claude/hooks/checkpoint-helper.sh latest`
29
+
30
+ ## Argument
31
+
32
+ $ARGUMENTS
19
33
 
20
34
  ## Instructions
21
35
 
22
- 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.
@@ -0,0 +1,45 @@
1
+ ---
2
+ name: session-init
3
+ description: >
4
+ Label or relabel the current UV Suite session — sets name, kind (long-running
5
+ vs outcome), purpose, and priority (low/med/high). Metadata appears in the
6
+ watchtower dashboard. Use when you skipped the launcher prompt or want to
7
+ rename a session mid-flight.
8
+ argument-hint: "<name> | --kind long|outcome | --purpose <text> | --priority low|med|high | show | clear"
9
+ user-invocable: true
10
+ allowed-tools:
11
+ - Bash("$CLAUDE_PROJECT_DIR"/.claude/hooks/session-meta.sh *)
12
+ ---
13
+
14
+ ## Apply /session-init $ARGUMENTS
15
+
16
+ !`HELPER="$CLAUDE_PROJECT_DIR/.claude/hooks/session-meta.sh"; ARGS="$ARGUMENTS"; if [ -z "$ARGS" ] || [ "$ARGS" = "show" ]; then "$HELPER" show; elif [ "$ARGS" = "clear" ]; then "$HELPER" clear; else FIRST=$(printf '%s' "$ARGS" | awk '{print $1}'); REST=$(printf '%s' "$ARGS" | sed 's/^[^ ]* *//'); case "$FIRST" in --kind) "$HELPER" set-kind "$REST" ;; --priority) "$HELPER" set-priority "$REST" ;; --purpose) "$HELPER" set-purpose "$REST" ;; --name) "$HELPER" set-name "$REST" ;; *) "$HELPER" set-name "$ARGS" ;; esac; fi`
17
+
18
+ ## Instructions
19
+
20
+ Show the user the output of the command above. Do not add commentary — the
21
+ command itself confirms what changed. The dashboard reflects changes within
22
+ a few seconds (next event refreshes session metadata).
23
+
24
+ ## Usage
25
+
26
+ ```
27
+ /session-init show current values
28
+ /session-init show show current values
29
+ /session-init <free-text name> set the name (default action)
30
+ /session-init --kind long set kind: long-running
31
+ /session-init --kind outcome set kind: outcome
32
+ /session-init --priority high set priority: low | med | high
33
+ /session-init --purpose <free text> set the purpose
34
+ /session-init clear clear name, kind, purpose, priority
35
+ ```
36
+
37
+ ## Notes
38
+
39
+ - The session id is generated by `uv.sh` at launch and exported as
40
+ `UVS_SESSION_ID`. If you launched `claude` directly, this falls back
41
+ to an `ad-hoc-<timestamp>` id.
42
+ - Metadata lives at `.uv-suite-state/sessions/<id>.json`.
43
+ - Persona is captured at launch time and is not editable from here —
44
+ re-launch with a different `uv` persona to change it.
45
+ - Each invocation sets one field at a time. Run multiple times to set more.
package/uv.sh CHANGED
@@ -41,6 +41,12 @@ case "$1" in
41
41
  echo " pro Production code (all hooks, all guardrails)"
42
42
  echo " auto Fully autonomous (max effort, everything approved)"
43
43
  echo ""
44
+ echo " Session metadata:"
45
+ echo " On launch you'll be prompted for name, kind, purpose, and"
46
+ echo " priority. Press Enter to skip any field; you'll be reminded"
47
+ echo " until the session is named. Use /session-init to relabel."
48
+ echo " Set UVS_NO_PROMPT=1 to suppress prompts entirely."
49
+ echo ""
44
50
  exit 0
45
51
  ;;
46
52
  "")
@@ -73,6 +79,76 @@ case "$PERSONA" in
73
79
  auto) LABEL="Auto — autonomous (max, everything approved)" ;;
74
80
  esac
75
81
 
82
+ # --- Session metadata: generate id and prompt for label ---
83
+ PROJECT_DIR="$(pwd)"
84
+ STATE_DIR="$PROJECT_DIR/.uv-suite-state"
85
+ SESSIONS_DIR="$STATE_DIR/sessions"
86
+ mkdir -p "$SESSIONS_DIR"
87
+
88
+ if command -v uuidgen >/dev/null 2>&1; then
89
+ UVS_SESSION_ID=$(uuidgen | tr '[:upper:]' '[:lower:]')
90
+ else
91
+ UVS_SESSION_ID="uvs-$(date +%s)-$$"
92
+ fi
93
+ export UVS_SESSION_ID
94
+
95
+ UVS_NAME=""
96
+ UVS_KIND=""
97
+ UVS_PURPOSE=""
98
+ UVS_PRIORITY=""
99
+
100
+ # Prompt only if attached to a TTY and not explicitly suppressed
101
+ if [ -t 0 ] && [ -z "$UVS_NO_PROMPT" ]; then
102
+ echo ""
103
+ echo "Label this session (Enter to skip — you'll be reminded):"
104
+ read -r -p " name: " UVS_NAME
105
+ read -r -p " kind [long/outcome]: " UVS_KIND_RAW
106
+ read -r -p " purpose: " UVS_PURPOSE
107
+ read -r -p " priority [low/med/high]: " UVS_PRIORITY_RAW
108
+
109
+ case "$UVS_KIND_RAW" in
110
+ l|long|long-running) UVS_KIND="long-running" ;;
111
+ o|outcome) UVS_KIND="outcome" ;;
112
+ "") UVS_KIND="" ;;
113
+ *) echo " (kind '$UVS_KIND_RAW' not recognized — leaving blank)"; UVS_KIND="" ;;
114
+ esac
115
+
116
+ case "$UVS_PRIORITY_RAW" in
117
+ l|low) UVS_PRIORITY="low" ;;
118
+ m|med|medium) UVS_PRIORITY="med" ;;
119
+ h|high) UVS_PRIORITY="high" ;;
120
+ "") UVS_PRIORITY="" ;;
121
+ *) echo " (priority '$UVS_PRIORITY_RAW' not recognized — leaving blank)"; UVS_PRIORITY="" ;;
122
+ esac
123
+ fi
124
+
125
+ # Write metadata as JSON. Use python3 for proper escaping of free-text fields.
126
+ META_FILE="$SESSIONS_DIR/$UVS_SESSION_ID.json"
127
+ SID="$UVS_SESSION_ID" \
128
+ NAME="$UVS_NAME" \
129
+ KIND="$UVS_KIND" \
130
+ PURPOSE="$UVS_PURPOSE" \
131
+ PRIORITY="$UVS_PRIORITY" \
132
+ PERSONA_VAL="$PERSONA" \
133
+ CWD_VAL="$PROJECT_DIR" \
134
+ STARTED="$(date +%s)" \
135
+ python3 -c '
136
+ import json, os
137
+ print(json.dumps({
138
+ "uvs_session_id": os.environ["SID"],
139
+ "name": os.environ["NAME"],
140
+ "kind": os.environ["KIND"],
141
+ "purpose": os.environ["PURPOSE"],
142
+ "priority": os.environ["PRIORITY"],
143
+ "persona": os.environ["PERSONA_VAL"],
144
+ "cwd": os.environ["CWD_VAL"],
145
+ "started_at": int(os.environ["STARTED"]),
146
+ }, indent=2))
147
+ ' > "$META_FILE" 2>/dev/null
148
+
149
+ # Latest-session pointer (used by hooks that lack UVS_SESSION_ID in their env)
150
+ echo "$UVS_SESSION_ID" > "$STATE_DIR/current-session.txt"
151
+
76
152
  SETTINGS=".claude/personas/$PERSONA.json"
77
153
 
78
154
  if [ "$TOOL" = "claude" ]; then
@@ -87,7 +163,9 @@ if [ "$TOOL" = "claude" ]; then
87
163
  exit 1
88
164
  fi
89
165
 
166
+ echo ""
90
167
  echo "UV Suite | Claude Code | $LABEL"
168
+ echo "Session: ${UVS_SESSION_ID:0:8}${UVS_NAME:+ — $UVS_NAME}"
91
169
  echo ""
92
170
  exec claude --settings "$SETTINGS" "$@"
93
171
 
@@ -99,24 +177,16 @@ elif [ "$TOOL" = "codex" ]; then
99
177
  exit 1
100
178
  fi
101
179
 
102
- # Codex doesn't have --settings, but reads AGENTS.md and .codex/agents/
103
- # We can pass model and approval mode based on persona
104
180
  case "$PERSONA" in
105
- spike)
106
- CODEX_ARGS="--model o3 --approval-mode suggest"
107
- ;;
108
- sport)
109
- CODEX_ARGS="--approval-mode auto-edit"
110
- ;;
111
- professional)
112
- CODEX_ARGS="--approval-mode suggest"
113
- ;;
114
- auto)
115
- CODEX_ARGS="--approval-mode full-auto"
116
- ;;
181
+ spike) CODEX_ARGS="--model o3 --approval-mode suggest" ;;
182
+ sport) CODEX_ARGS="--approval-mode auto-edit" ;;
183
+ professional) CODEX_ARGS="--approval-mode suggest" ;;
184
+ auto) CODEX_ARGS="--approval-mode full-auto" ;;
117
185
  esac
118
186
 
187
+ echo ""
119
188
  echo "UV Suite | Codex | $LABEL"
189
+ echo "Session: ${UVS_SESSION_ID:0:8}${UVS_NAME:+ — $UVS_NAME}"
120
190
  echo ""
121
191
  exec codex $CODEX_ARGS "$@"
122
192
  fi
@@ -279,6 +279,42 @@
279
279
  .event.user-prompt { background: var(--user-prompt-bg); }
280
280
  .event.user-prompt .detail { color: var(--user-prompt-text); font-style: italic; }
281
281
 
282
+ /* Session priority: low rows are dimmed, high rows get an accent strip */
283
+ .event.priority-low { opacity: 0.45; }
284
+ .event.priority-low:hover { opacity: 0.85; }
285
+ .event.priority-high { border-left: 3px solid var(--accent); padding-left: 25px; }
286
+
287
+ /* Pills shown next to a session label */
288
+ .pill {
289
+ display: inline-block;
290
+ padding: 1px 7px;
291
+ margin-left: 6px;
292
+ font-size: 10.5px;
293
+ font-weight: 600;
294
+ letter-spacing: 0.04em;
295
+ text-transform: uppercase;
296
+ border-radius: 4px;
297
+ vertical-align: 1px;
298
+ }
299
+ .pill.persona-spike { background: rgba(191, 90, 242, 0.18); color: var(--purple); }
300
+ .pill.persona-sport { background: rgba(48, 209, 88, 0.18); color: var(--success); }
301
+ .pill.persona-professional { background: rgba(10, 132, 255, 0.18); color: var(--accent); }
302
+ .pill.persona-auto { background: rgba(255, 159, 10, 0.18); color: var(--warning); }
303
+ .pill.priority-low { background: rgba(154, 154, 163, 0.18); color: var(--text-muted); }
304
+ .pill.priority-med { background: rgba(255, 214, 10, 0.18); color: var(--yellow); }
305
+ .pill.priority-high { background: rgba(255, 69, 58, 0.18); color: var(--danger); }
306
+ .pill.kind-long-running { background: rgba(100, 210, 255, 0.18); color: var(--info); }
307
+ .pill.kind-outcome { background: rgba(255, 105, 97, 0.18); color: var(--peach); }
308
+
309
+ .session-tag.priority-low { opacity: 0.6; }
310
+ .session-tag .meta-line {
311
+ display: block;
312
+ font-size: 11px;
313
+ font-weight: 400;
314
+ color: var(--text-muted);
315
+ margin-top: 2px;
316
+ }
317
+
282
318
  .timeline-end { padding: 20px 24px; text-align: center; border-bottom: 1px solid var(--border-subtle); }
283
319
  .loader { display: inline-block; width: 48px; height: 4px; position: relative; }
284
320
  .loader::before {
@@ -393,9 +429,21 @@ let lastEventDiv = null;
393
429
  // Session colors and naming
394
430
  const palette = ['#0a84ff','#30d158','#ff9f0a','#bf5af2','#ff375f','#64d2ff','#ffd60a','#ac8ee0','#ff6961','#5e5ce6'];
395
431
  let colorIdx = 0;
432
+
433
+ // Resolve the canonical session key for an event: prefer the UV Suite id (one
434
+ // per `uv` launch), fall back to Claude Code's session id, then source_app.
435
+ function eventSid(ev) {
436
+ return ev.uvs_session_id || ev.session_id || ev.source_app || 'unknown';
437
+ }
438
+
396
439
  function sessionColor(id) {
397
440
  if (!sessions[id]) {
398
- sessions[id] = { color: palette[colorIdx++ % palette.length], count: 0, lastEvent: null, label: null, app: null };
441
+ sessions[id] = {
442
+ color: palette[colorIdx++ % palette.length],
443
+ count: 0, lastEvent: null,
444
+ name: '', kind: '', purpose: '', priority: '', persona: '',
445
+ app: null, label: null,
446
+ };
399
447
  updateSessionBar();
400
448
  updateFilterSession();
401
449
  }
@@ -406,33 +454,54 @@ function sessionColor(id) {
406
454
 
407
455
  function updateSessionLabel(sid, ev) {
408
456
  if (!sessions[sid]) return;
409
- if (!sessions[sid].app && ev.source_app) {
410
- sessions[sid].app = ev.source_app;
457
+ const s = sessions[sid];
458
+ let changed = false;
459
+
460
+ if (!s.app && ev.source_app) { s.app = ev.source_app; changed = true; }
461
+
462
+ // Configured metadata wins over heuristics. Update on every event so a
463
+ // mid-session /session-init relabel is reflected without a refresh.
464
+ for (const [evKey, sKey] of [
465
+ ['session_name','name'], ['session_kind','kind'],
466
+ ['session_purpose','purpose'], ['session_priority','priority'],
467
+ ['persona','persona'],
468
+ ]) {
469
+ if (ev[evKey] !== undefined && ev[evKey] !== null && ev[evKey] !== s[sKey]) {
470
+ s[sKey] = ev[evKey];
471
+ changed = true;
472
+ }
411
473
  }
412
- // Use first UserPromptSubmit as session label
474
+
475
+ // Fall back to first UserPromptSubmit if no configured name yet
413
476
  const type = ev.event_type || ev.hook_event_name || '';
414
- if (!sessions[sid].label && type === 'UserPromptSubmit') {
477
+ if (!s.name && !s.label && type === 'UserPromptSubmit') {
415
478
  const prompt = ev.tool_input?.prompt || ev.tool_input?.content || ev.message || '';
416
479
  if (prompt.length > 0) {
417
480
  let label = prompt.slice(0, 45).replace(/\s+\S*$/, '');
418
481
  if (prompt.length > label.length) label += '...';
419
- sessions[sid].label = label;
420
- updateSessionBar();
421
- updateFilterSession();
482
+ s.label = label;
483
+ changed = true;
422
484
  }
423
485
  }
486
+
487
+ if (changed) {
488
+ updateSessionBar();
489
+ updateFilterSession();
490
+ }
424
491
  }
425
492
 
426
493
  function sessionDisplayName(id) {
427
494
  const s = sessions[id];
428
495
  if (!s) return shortId(id);
429
- if (s.label) {
430
- return s.app ? s.app + ': ' + s.label : s.label;
431
- }
496
+ if (s.name) return s.name;
497
+ if (s.label) return s.app ? s.app + ': ' + s.label : s.label;
432
498
  if (s.app) return s.app;
433
499
  return shortId(id);
434
500
  }
435
501
 
502
+ // Sort order: high → med → unset → low (low last so it groups at the bottom)
503
+ const PRIORITY_ORDER = { high: 0, med: 1, '': 2, low: 3 };
504
+
436
505
  function shortId(id) {
437
506
  if (!id) return '—';
438
507
  return id.length > 10 ? id.slice(0, 8) + '..' : id;
@@ -526,7 +595,7 @@ function eventDetail(ev) {
526
595
  }
527
596
 
528
597
  function renderEvent(ev) {
529
- const sid = ev.session_id || ev.source_app || 'unknown';
598
+ const sid = eventSid(ev);
530
599
  const color = sessionColor(sid);
531
600
  const type = ev.event_type || ev.hook_event_name || '?';
532
601
  const tool = ev.tool_name || '';
@@ -534,6 +603,7 @@ function renderEvent(ev) {
534
603
  const fail = isFailure(ev);
535
604
  const boundary = isSessionBoundary(ev);
536
605
  const prompt = isUserPrompt(ev);
606
+ const priority = sessions[sid]?.priority || '';
537
607
 
538
608
  const div = document.createElement('div');
539
609
  let cls = 'event';
@@ -541,6 +611,8 @@ function renderEvent(ev) {
541
611
  else if (fail) cls += ' failure';
542
612
  else if (prompt) cls += ' user-prompt';
543
613
  else if (boundary) cls += ' session-boundary';
614
+ if (priority === 'high') cls += ' priority-high';
615
+ if (priority === 'low') cls += ' priority-low';
544
616
  div.className = cls;
545
617
 
546
618
  const humanBadge = human ? '<span class="human-badge">NEEDS HUMAN</span>' : '';
@@ -567,7 +639,9 @@ function renderEvent(ev) {
567
639
  function addEvent(ev) {
568
640
  events.push(ev);
569
641
  if (emptyState.parentNode) emptyState.remove();
570
- const sid = ev.session_id || ev.source_app || 'unknown';
642
+ const sid = eventSid(ev);
643
+ // Make sure the session is registered before we try to update its metadata
644
+ sessionColor(sid);
571
645
  updateSessionLabel(sid, ev);
572
646
 
573
647
  // Remove "latest" class from previous latest
@@ -592,7 +666,7 @@ function addEvent(ev) {
592
666
 
593
667
  function updateWaitingText(ev) {
594
668
  if (ev) {
595
- const sid = ev.session_id || ev.source_app || 'unknown';
669
+ const sid = eventSid(ev);
596
670
  waitingText.textContent = `Last: ${sessionDisplayName(sid)} — ${timeSince(ev._ts)}`;
597
671
  }
598
672
  }
@@ -613,7 +687,7 @@ function updateStats() {
613
687
  // number drops back down once the session continues past the prompt.
614
688
  const latestBySession = {};
615
689
  for (const ev of events) {
616
- const sid = ev.session_id || ev.source_app || 'unknown';
690
+ const sid = eventSid(ev);
617
691
  latestBySession[sid] = ev;
618
692
  }
619
693
  const humans = Object.values(latestBySession).filter(needsHuman).length;
@@ -621,15 +695,46 @@ function updateStats() {
621
695
  document.getElementById('humanCount').className = 'n' + (humans > 0 ? ' alert' : '');
622
696
  }
623
697
 
698
+ function escapeHtml(s) {
699
+ return String(s).replace(/[&<>"']/g, c => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));
700
+ }
701
+
702
+ function pill(cls, label) {
703
+ return `<span class="pill ${cls}">${escapeHtml(label)}</span>`;
704
+ }
705
+
624
706
  function updateSessionBar() {
625
707
  sessionBar.innerHTML = '';
626
- for (const [id, s] of Object.entries(sessions)) {
708
+ // Sort: high priority first, then med/unset, then low; within a tier, most
709
+ // recent activity wins so the dashboard surfaces what's happening now.
710
+ const ids = Object.keys(sessions).sort((a, b) => {
711
+ const pa = PRIORITY_ORDER[sessions[a].priority] ?? PRIORITY_ORDER[''];
712
+ const pb = PRIORITY_ORDER[sessions[b].priority] ?? PRIORITY_ORDER[''];
713
+ if (pa !== pb) return pa - pb;
714
+ return (sessions[b].lastEvent || 0) - (sessions[a].lastEvent || 0);
715
+ });
716
+
717
+ for (const id of ids) {
718
+ const s = sessions[id];
627
719
  const tag = document.createElement('span');
628
- tag.className = 'session-tag' + (selectedSession === id ? ' active' : '');
720
+ let cls = 'session-tag';
721
+ if (selectedSession === id) cls += ' active';
722
+ if (s.priority === 'low') cls += ' priority-low';
723
+ tag.className = cls;
629
724
  tag.style.background = s.color + '22';
630
725
  tag.style.color = s.color;
631
- tag.textContent = sessionDisplayName(id) + ' (' + s.count + ')';
632
- tag.title = id;
726
+ tag.title = `${id}${s.purpose ? '\n' + s.purpose : ''}`;
727
+
728
+ const pills = [];
729
+ if (s.persona) pills.push(pill('persona-' + s.persona, s.persona));
730
+ if (s.priority) pills.push(pill('priority-' + s.priority, 'P:' + s.priority));
731
+ if (s.kind) pills.push(pill('kind-' + s.kind, s.kind));
732
+
733
+ const namePart = `<strong>${escapeHtml(sessionDisplayName(id))}</strong>` +
734
+ ` <span style="opacity:0.7">(${s.count})</span>`;
735
+ const meta = pills.length ? `<span class="meta-line">${pills.join('')}</span>` : '';
736
+ tag.innerHTML = namePart + meta;
737
+
633
738
  tag.onclick = () => { selectedSession = selectedSession === id ? '' : id; refilter(); updateSessionBar(); };
634
739
  sessionBar.appendChild(tag);
635
740
  }
@@ -662,7 +767,7 @@ function refilter() {
662
767
  rows.forEach((row) => {
663
768
  const ev = row._ev;
664
769
  if (!ev) return;
665
- const sid = ev.session_id || ev.source_app || 'unknown';
770
+ const sid = eventSid(ev);
666
771
  const type = ev.event_type || ev.hook_event_name || '';
667
772
  const show = (!selectedType || type === selectedType)
668
773
  && (!selectedSession || sid === selectedSession)
@@ -1,22 +1 @@
1
- [
2
- {
3
- "event_type": "PostToolUse",
4
- "session_id": "test-123",
5
- "source_app": "uv-suite",
6
- "tool_name": "Edit",
7
- "cwd": "/tmp",
8
- "_ts": 1776756371726,
9
- "_id": "3f130976-6226-47ea-a477-18a16e194415"
10
- },
11
- {
12
- "event_type": "PostToolUse",
13
- "session_id": "test-session",
14
- "source_app": "my-project",
15
- "tool_name": "Edit",
16
- "tool_input": {
17
- "file_path": "src/app.ts"
18
- },
19
- "_ts": 1776757586012,
20
- "_id": "efa9ae75-c0e0-48c2-a078-e7075ccef5a7"
21
- }
22
- ]
1
+ []