clauddy 1.26.0 → 1.27.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/README.md CHANGED
@@ -215,7 +215,7 @@ update-desktop-database ~/.local/share/applications 2>/dev/null
215
215
 
216
216
  - **Drag** the widget anywhere on screen
217
217
  - **–** minimizes to just the pet, ringed by the live session % (the number sits inside the ring) — or, with Claude and Codex both connected, one reading per service; the **⤢** button or a double-click on the pet expands it back
218
- - **Pet icon** in the compact header switches to **Just the pet** (floating mode). Drag the pet itself to move it. Hovering over the pet (or focusing it) reveals the usage glance; the small expand button in it returns to compact. Keyboard users can focus the pet and press Enter. The chosen size is remembered. In compact and pet-only modes, the pet follows whoever is working, with provider logos identifying Claude, Codex, or both. Usage selection stays manual; when neither is active the pet rests.
218
+ - **Pet icon** in the compact header switches to **Just the pet** (floating mode). Drag the pet itself to move it. Hovering over the pet (or focusing it) reveals the usage glance; the small expand button in it returns to compact. Keyboard users can focus the pet and press Enter. The chosen size is remembered. In compact and pet-only modes, the pet follows whoever is working, with provider logos identifying Claude, Codex, or both. Usage selection stays manual. When neither is active, the hottest session still sets the mood: the pet catches fire (or maxes out) with that provider's logo beside it, and otherwise rests.
219
219
  - **⚙** opens settings (log in, toggle alerts, set thresholds, pick the display mode)
220
220
  - **↗** opens the official Usage page of the service on screen
221
221
  - **×** quits
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "clauddy",
3
3
  "desktopName": "clauddy.desktop",
4
- "version": "1.26.0",
4
+ "version": "1.27.0",
5
5
  "description": "A cute desktop pet that tracks your Claude Code usage",
6
6
  "main": "main.js",
7
7
  "bin": {
@@ -261,9 +261,6 @@ body.collapsed.state-stressed:not(.dual) #pet {
261
261
  body.collapsed.dual.state-stressed #compact-flames {
262
262
  top: -30px;
263
263
  }
264
- body.collapsed.dual.state-stressed #pet {
265
- transform: translateY(4px);
266
- }
267
264
  body.collapsed.state-stressed .compact-flame {
268
265
  transform-box: fill-box;
269
266
  transform-origin: 50% 100%;
package/renderer/pet.js CHANGED
@@ -780,6 +780,20 @@ const CODEX_SLEEP_MS = 5 * 60000 // main's default sleepThresholdMs
780
780
  const codexStale = (c) =>
781
781
  !!c && (c.session?.expired || (c.limitsAt != null && Date.now() - c.limitsAt > STALE_MS))
782
782
 
783
+ // the highest session % across connected services, and which ones are at or
784
+ // past `from`; an expired Codex reading is null, so it never counts
785
+ function sessionHeat(from) {
786
+ const pcts = {
787
+ claude: claudeOn() ? realUsage?.session?.pct : null,
788
+ codex: codexOn() ? codexData?.session?.pct : null,
789
+ }
790
+ const known = Object.entries(pcts).filter(([, p]) => p != null)
791
+ return {
792
+ pct: Math.max(0, ...known.map(([, p]) => p)),
793
+ providers: known.filter(([, p]) => p >= from).map(([k]) => k),
794
+ }
795
+ }
796
+
783
797
  // Codex's numbers in the shape the panel draws; its logs have no activity or tok/min
784
798
  function codexView(c) {
785
799
  const idleFor = c.lastSeen ? Date.now() - c.lastSeen : null
@@ -1070,19 +1084,23 @@ function paintActivity() {
1070
1084
  claudeOn() ? claudeActivityData : null,
1071
1085
  codexOn() ? codexData : null,
1072
1086
  )
1073
- const names = activity.providers.map((p) => (p === 'claude' ? 'Claude' : 'Codex')).join(' + ')
1074
- const label = names ? `${names} · ${activity.activity}` : ''
1087
+ paintLogos(activity.providers, activity.activity)
1088
+ return activity
1089
+ }
1090
+
1091
+ // the logos under the pet name who it's about: the workers, or the service on fire
1092
+ function paintLogos(providers, caption) {
1093
+ const names = providers.map((p) => (p === 'claude' ? 'Claude' : 'Codex')).join(' + ')
1094
+ const label = names ? `${names} · ${caption}` : ''
1075
1095
  for (const id of ['pet-activity', 'mini-workers']) {
1076
1096
  const badge = el(id)
1077
1097
  badge.hidden = !names
1078
1098
  badge.setAttribute('aria-label', label)
1079
1099
  for (const logo of badge.querySelectorAll('[data-provider]')) {
1080
- logo.hidden = !activity.providers.includes(logo.dataset.provider)
1100
+ logo.hidden = !providers.includes(logo.dataset.provider)
1081
1101
  }
1082
1102
  }
1083
- el('mini-dot').hidden =
1084
- activity.providers.length > 0 && document.body.classList.contains('collapsed')
1085
- return activity
1103
+ el('mini-dot').hidden = providers.length > 0 && document.body.classList.contains('collapsed')
1086
1104
  }
1087
1105
 
1088
1106
  // main render
@@ -1140,7 +1158,20 @@ function paint() {
1140
1158
  const activity = paintActivity()
1141
1159
  const collapsedNow = document.body.classList.contains('collapsed')
1142
1160
  if (collapsedNow) {
1143
- st = activity.providers.length ? 'working' : activity.sleeping ? 'sleeping' : 'idle'
1161
+ // work wins; at rest, the hottest connected session still sets the mood,
1162
+ // and its logo takes the status dot's place
1163
+ const heat = sessionHeat(fireAt)
1164
+ st = activity.providers.length
1165
+ ? 'working'
1166
+ : heat.pct >= 100
1167
+ ? 'tired'
1168
+ : heat.pct >= fireAt
1169
+ ? 'stressed'
1170
+ : activity.sleeping
1171
+ ? 'sleeping'
1172
+ : 'idle'
1173
+ if (st === 'tired') paintLogos(sessionHeat(100).providers, 'maxed out')
1174
+ else if (st === 'stressed') paintLogos(heat.providers, 'on fire')
1144
1175
  curActivity = activity.providers.length ? activity.activity : null
1145
1176
  }
1146
1177
  // dev override from `./pet <state>` (base states or an activity name)