uv-suite 0.21.0 → 0.22.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/package.json +1 -1
- package/personas/auto.json +10 -1
- package/personas/professional.json +19 -0
- package/personas/spike.json +10 -1
- package/personas/sport.json +10 -1
- package/watchtower/dashboard.html +39 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "uv-suite",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.0",
|
|
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",
|
package/personas/auto.json
CHANGED
|
@@ -54,7 +54,16 @@
|
|
|
54
54
|
{
|
|
55
55
|
"matcher": "*",
|
|
56
56
|
"hooks": [
|
|
57
|
-
{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/session-start.sh", "timeout": 5 }
|
|
57
|
+
{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/session-start.sh", "timeout": 5 },
|
|
58
|
+
{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/watchtower-send.sh SessionStart", "timeout": 2, "async": true }
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
],
|
|
62
|
+
"UserPromptSubmit": [
|
|
63
|
+
{
|
|
64
|
+
"matcher": "*",
|
|
65
|
+
"hooks": [
|
|
66
|
+
{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/watchtower-send.sh UserPromptSubmit", "timeout": 2, "async": true }
|
|
58
67
|
]
|
|
59
68
|
}
|
|
60
69
|
],
|
|
@@ -56,6 +56,25 @@
|
|
|
56
56
|
"type": "command",
|
|
57
57
|
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/session-start.sh",
|
|
58
58
|
"timeout": 5
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"type": "command",
|
|
62
|
+
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/watchtower-send.sh SessionStart",
|
|
63
|
+
"timeout": 2,
|
|
64
|
+
"async": true
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
}
|
|
68
|
+
],
|
|
69
|
+
"UserPromptSubmit": [
|
|
70
|
+
{
|
|
71
|
+
"matcher": "*",
|
|
72
|
+
"hooks": [
|
|
73
|
+
{
|
|
74
|
+
"type": "command",
|
|
75
|
+
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/watchtower-send.sh UserPromptSubmit",
|
|
76
|
+
"timeout": 2,
|
|
77
|
+
"async": true
|
|
59
78
|
}
|
|
60
79
|
]
|
|
61
80
|
}
|
package/personas/spike.json
CHANGED
|
@@ -40,7 +40,16 @@
|
|
|
40
40
|
{
|
|
41
41
|
"matcher": "*",
|
|
42
42
|
"hooks": [
|
|
43
|
-
{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/session-start.sh", "timeout": 5 }
|
|
43
|
+
{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/session-start.sh", "timeout": 5 },
|
|
44
|
+
{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/watchtower-send.sh SessionStart", "timeout": 2, "async": true }
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
],
|
|
48
|
+
"UserPromptSubmit": [
|
|
49
|
+
{
|
|
50
|
+
"matcher": "*",
|
|
51
|
+
"hooks": [
|
|
52
|
+
{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/watchtower-send.sh UserPromptSubmit", "timeout": 2, "async": true }
|
|
44
53
|
]
|
|
45
54
|
}
|
|
46
55
|
],
|
package/personas/sport.json
CHANGED
|
@@ -26,7 +26,16 @@
|
|
|
26
26
|
{
|
|
27
27
|
"matcher": "*",
|
|
28
28
|
"hooks": [
|
|
29
|
-
{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/session-start.sh", "timeout": 5 }
|
|
29
|
+
{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/session-start.sh", "timeout": 5 },
|
|
30
|
+
{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/watchtower-send.sh SessionStart", "timeout": 2, "async": true }
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
],
|
|
34
|
+
"UserPromptSubmit": [
|
|
35
|
+
{
|
|
36
|
+
"matcher": "*",
|
|
37
|
+
"hooks": [
|
|
38
|
+
{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/watchtower-send.sh UserPromptSubmit", "timeout": 2, "async": true }
|
|
30
39
|
]
|
|
31
40
|
}
|
|
32
41
|
],
|
|
@@ -118,12 +118,12 @@ let humanOnly = false;
|
|
|
118
118
|
let selectedSession = '';
|
|
119
119
|
let selectedType = '';
|
|
120
120
|
|
|
121
|
-
// Session colors
|
|
121
|
+
// Session colors and naming
|
|
122
122
|
const palette = ['#0a84ff','#30d158','#ff9f0a','#bf5af2','#ff375f','#64d2ff','#ffd60a','#ac8ee0','#ff6961','#5e5ce6'];
|
|
123
123
|
let colorIdx = 0;
|
|
124
124
|
function sessionColor(id) {
|
|
125
125
|
if (!sessions[id]) {
|
|
126
|
-
sessions[id] = { color: palette[colorIdx++ % palette.length], count: 0, lastEvent: null };
|
|
126
|
+
sessions[id] = { color: palette[colorIdx++ % palette.length], count: 0, lastEvent: null, label: null, app: null };
|
|
127
127
|
updateSessionBar();
|
|
128
128
|
updateFilterSession();
|
|
129
129
|
}
|
|
@@ -132,14 +132,47 @@ function sessionColor(id) {
|
|
|
132
132
|
return sessions[id].color;
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
+
// Build a meaningful session label from the first user prompt or app name
|
|
136
|
+
function updateSessionLabel(sid, ev) {
|
|
137
|
+
if (!sessions[sid]) return;
|
|
138
|
+
// Capture source_app as fallback name
|
|
139
|
+
if (!sessions[sid].app && ev.source_app) {
|
|
140
|
+
sessions[sid].app = ev.source_app;
|
|
141
|
+
}
|
|
142
|
+
// Use first UserPromptSubmit content as the session label
|
|
143
|
+
if (!sessions[sid].label && ev.event_type === 'UserPromptSubmit') {
|
|
144
|
+
const prompt = ev.tool_input?.prompt || ev.tool_input?.content || ev.message || '';
|
|
145
|
+
if (prompt.length > 0) {
|
|
146
|
+
// Take first 40 chars, trim to last word boundary
|
|
147
|
+
let label = prompt.slice(0, 40).replace(/\s+\S*$/, '');
|
|
148
|
+
if (prompt.length > label.length) label += '...';
|
|
149
|
+
sessions[sid].label = label;
|
|
150
|
+
updateSessionBar();
|
|
151
|
+
updateFilterSession();
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function sessionDisplayName(id) {
|
|
157
|
+
const s = sessions[id];
|
|
158
|
+
if (!s) return shortId(id);
|
|
159
|
+
if (s.label) return s.label;
|
|
160
|
+
if (s.app) return s.app;
|
|
161
|
+
return shortId(id);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function shortId(id) {
|
|
165
|
+
if (!id) return '—';
|
|
166
|
+
return id.length > 10 ? id.slice(0, 8) + '..' : id;
|
|
167
|
+
}
|
|
168
|
+
|
|
135
169
|
function formatTime(ts) {
|
|
136
170
|
const d = new Date(ts);
|
|
137
171
|
return d.toLocaleTimeString('en-US', { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit' });
|
|
138
172
|
}
|
|
139
173
|
|
|
140
174
|
function shortSession(id) {
|
|
141
|
-
|
|
142
|
-
return id.length > 12 ? id.slice(0, 8) + '...' : id;
|
|
175
|
+
return sessionDisplayName(id);
|
|
143
176
|
}
|
|
144
177
|
|
|
145
178
|
// Detect if event needs human intervention
|
|
@@ -245,6 +278,8 @@ function renderEvent(ev) {
|
|
|
245
278
|
function addEvent(ev) {
|
|
246
279
|
events.push(ev);
|
|
247
280
|
if (emptyState.parentNode) emptyState.remove();
|
|
281
|
+
const sid = ev.session_id || ev.source_app || 'unknown';
|
|
282
|
+
updateSessionLabel(sid, ev);
|
|
248
283
|
timeline.appendChild(renderEvent(ev));
|
|
249
284
|
updateStats();
|
|
250
285
|
updateFilterType(ev);
|