clauddy 1.28.2 → 1.29.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 +14 -8
- package/main.js +39 -2
- package/package.json +1 -1
- package/preload.js +2 -1
- package/renderer/index.html +169 -127
- package/renderer/pet.js +224 -22
- package/renderer/pets.css +916 -0
- package/renderer/pets.js +579 -0
- package/renderer/style.css +354 -94
- package/usage.js +57 -26
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ A cute pixel-art desktop pet for macOS that tracks your Claude Code usage — mi
|
|
|
4
4
|
|
|
5
5
|
<p align="center">
|
|
6
6
|
|
|
7
|
-
https://github.com/user-attachments/assets/
|
|
7
|
+
https://github.com/user-attachments/assets/be8d339c-ac69-4980-96a7-8e286f8b080f
|
|
8
8
|
|
|
9
9
|
<em>A little terracotta creature that lives in the corner of your screen, eats your tokens, and naps when you're idle.</em>
|
|
10
10
|
</p>
|
|
@@ -24,7 +24,7 @@ The **percentages are real**, pulled from your account (you log in once — see
|
|
|
24
24
|
|
|
25
25
|
The session/weekly **%** comes straight from your Anthropic account, so it matches the official panel exactly. You connect once via a browser login:
|
|
26
26
|
|
|
27
|
-
1. Open **⚙ Settings →
|
|
27
|
+
1. Open **⚙ Settings → Accounts → Claude → Connect** — your browser opens an Anthropic auth page.
|
|
28
28
|
2. Log in, copy the **authentication code** shown, and paste it back into the app → **Connect**.
|
|
29
29
|
|
|
30
30
|
The token is saved locally (see [Data & privacy](#data--privacy)) and refreshed automatically. **Until you connect**, the limits area shows a _"Connect your account"_ prompt instead of percentages.
|
|
@@ -41,7 +41,7 @@ Removing an account (the **×** on its row) deletes its token from disk. The one
|
|
|
41
41
|
|
|
42
42
|
## Codex
|
|
43
43
|
|
|
44
|
-
Clauddy can follow [Codex](https://openai.com/codex) (the CLI and the desktop app) next to Claude. Open **⚙ Settings →
|
|
44
|
+
Clauddy can follow [Codex](https://openai.com/codex) (the CLI and the desktop app) next to Claude. Open **⚙ Settings → Accounts → Codex → Connect**: it looks for a Codex session on this computer and starts monitoring if it finds one. There's nothing to log into — Codex writes its token counts and rate limits to `~/.codex/sessions` (or `$CODEX_HOME`), and Clauddy only reads those files.
|
|
45
45
|
|
|
46
46
|
With both connected, **tabs under the pet** pick which service the whole panel shows — account chip, pet mood, session and weekly %, the breakdowns, the 30-day map and the **↗** Usage link. The other tab keeps its % in view and gets a **!** when it crosses an alert threshold. Minimized, the ring becomes one reading per service; click one to switch.
|
|
47
47
|
|
|
@@ -55,7 +55,7 @@ Disconnecting (the **×** on the Codex card) only stops monitoring in Clauddy; y
|
|
|
55
55
|
|
|
56
56
|
## Cursor
|
|
57
57
|
|
|
58
|
-
Clauddy can follow [Cursor](https://cursor.com) too. Open **⚙ Settings →
|
|
58
|
+
Clauddy can follow [Cursor](https://cursor.com) too. Open **⚙ Settings → Accounts → Cursor → Connect**: it needs the Cursor app signed in on this computer, and starts monitoring once it finds that login. Clauddy reads the app's session token from its local storage and asks Cursor's own dashboard endpoints for your usage, the same numbers as the Usage page on cursor.com.
|
|
59
59
|
|
|
60
60
|
With three services connected, the tabs under the pet show each logo and %, and the minimized dock gets a third line.
|
|
61
61
|
|
|
@@ -103,6 +103,12 @@ It only appears once there's enough to say honestly — roughly 5 minutes into a
|
|
|
103
103
|
|
|
104
104
|
Plus a welcome **wave** on launch. You can [poke the pet from the terminal](#play-with-the-pet) too.
|
|
105
105
|
|
|
106
|
+
### Pick your pet
|
|
107
|
+
|
|
108
|
+
Clauddy is the default, but **⚙ Settings → Appearance → pet** has more: a Wizard, a Halloween pack (Pumpkin, Skull, Ghost, Bat, Black cat) and a Christmas pack (Snowman, Santa, Reindeer, Gingerbread). Click one to preview it and **Save** to keep it. Each pet stays still and blinks when nothing is running, and has its own way of moving while a provider works: the Pumpkin rocks, the Bat flaps, the Wizard levitates while an owl flies by.
|
|
109
|
+
|
|
110
|
+
On holidays a pet from the season's pack takes over for the day, whichever pet you picked: one Halloween pet on October 31, one Christmas pet on December 24 and 25. The pick changes every year and holds all day. Your own pet comes back the next day.
|
|
111
|
+
|
|
106
112
|
### What Claude's up to
|
|
107
113
|
|
|
108
114
|
While Claude Code is actively working, the pet sets up a little desk scene that
|
|
@@ -148,7 +154,7 @@ Optionally the pet also **blips** as it talks: short chiptune notes, one per let
|
|
|
148
154
|
|
|
149
155
|
Audio should never catch you off guard in a meeting:
|
|
150
156
|
|
|
151
|
-
- **Off by default.** Turn it on under **⚙ Settings →
|
|
157
|
+
- **Off by default.** Turn it on under **⚙ Settings → Appearance → Chiptune voice** (you'll hear a sample).
|
|
152
158
|
- **One-click mute.** While the voice is on, a 🔊 button sits in the title bar. Click it to mute for an hour, and again to unmute.
|
|
153
159
|
- **Always silent** in menu-bar mode and while the pet is minimized.
|
|
154
160
|
|
|
@@ -231,14 +237,14 @@ update-desktop-database ~/.local/share/applications 2>/dev/null
|
|
|
231
237
|
|
|
232
238
|
- **Drag** the widget anywhere on screen
|
|
233
239
|
- **–** minimizes to just the pet, ringed by the live session % (the number sits inside the ring) — or, with more than one service connected, one reading per service; the **⤢** button or a double-click on the pet expands it back
|
|
234
|
-
- **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)
|
|
240
|
+
- **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) pops up the usage glance as the pet's own speech bubble, one reading and a usage bar per service; 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, Cursor, or several at once. 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.
|
|
235
241
|
- **⚙** opens settings (log in, toggle alerts, set thresholds, pick the display mode)
|
|
236
242
|
- **↗** opens the official Usage page of the service on screen
|
|
237
243
|
- **×** quits
|
|
238
244
|
|
|
239
245
|
### Floating or menu bar
|
|
240
246
|
|
|
241
|
-
Under **⚙ Settings →
|
|
247
|
+
Under **⚙ Settings → Appearance** you can pick where Clauddy lives:
|
|
242
248
|
|
|
243
249
|
- **Floating pet** — the always-on widget in the corner (default).
|
|
244
250
|
- **Menu bar** — a small pet icon in the macOS menu bar showing your live session **%** (it turns 🔥 near your limit; with Codex or Cursor too it reads `C 64% · X 28% · Cu 5%`). Click it to pop open the full pet + usage panel; click away to dismiss. Right-click for a quick menu.
|
|
@@ -251,7 +257,7 @@ When a provider's activity changes, the pet briefly glances toward it, with no c
|
|
|
251
257
|
|
|
252
258
|
## Alerts
|
|
253
259
|
|
|
254
|
-
Optional **macOS notifications**, toggled (with their thresholds) in **⚙ Settings**:
|
|
260
|
+
Optional **macOS notifications**, toggled (with their thresholds) in **⚙ Settings → Alerts**:
|
|
255
261
|
|
|
256
262
|
| Notification | When |
|
|
257
263
|
| --- | --- |
|
package/main.js
CHANGED
|
@@ -89,6 +89,7 @@ function publicConfig(c) {
|
|
|
89
89
|
talk: c.talk,
|
|
90
90
|
sound: c.sound,
|
|
91
91
|
soundMutedUntil: c.soundMutedUntil,
|
|
92
|
+
pet: c.pet,
|
|
92
93
|
}
|
|
93
94
|
}
|
|
94
95
|
|
|
@@ -108,6 +109,7 @@ function loadConfig() {
|
|
|
108
109
|
talk: true, // speech bubbles on transitions
|
|
109
110
|
sound: false, // chiptune blips: opt-in, audio must never surprise anyone
|
|
110
111
|
soundMutedUntil: 0, // the one-click "mute for 1 hour", as an epoch ms
|
|
112
|
+
pet: 'clauddy', // renderer/pets.js; holidays override it on their own days
|
|
111
113
|
pollIntervalMs: 4000,
|
|
112
114
|
activeThresholdMs: 20000,
|
|
113
115
|
sleepThresholdMs: 300000,
|
|
@@ -527,6 +529,9 @@ function createWindow() {
|
|
|
527
529
|
resizable: false,
|
|
528
530
|
show: false, // applyMode() reveals it (floating) or keeps it a hidden popover (menubar)
|
|
529
531
|
alwaysOnTop: true,
|
|
532
|
+
// macOS: the widget is rarely the focused window, so without this the first
|
|
533
|
+
// click only focuses it and a button needs a second one
|
|
534
|
+
acceptFirstMouse: true,
|
|
530
535
|
skipTaskbar: true,
|
|
531
536
|
hasShadow: false,
|
|
532
537
|
fullscreenable: false,
|
|
@@ -781,6 +786,10 @@ function positionUnderTray() {
|
|
|
781
786
|
}
|
|
782
787
|
x = Math.max(8, Math.min(x, workAreaSize.width - b.width - 8))
|
|
783
788
|
moveWindow(x, y)
|
|
789
|
+
// the popover's nib points at the icon, even when the screen edge pushed the
|
|
790
|
+
// window off-centre
|
|
791
|
+
const iconX = trayBounds?.width ? trayBounds.x + trayBounds.width / 2 : x + b.width / 2
|
|
792
|
+
win.webContents.send('popover-anchor', Math.round(iconX - x))
|
|
784
793
|
}
|
|
785
794
|
|
|
786
795
|
function positionFloating() {
|
|
@@ -866,10 +875,38 @@ ipcMain.on('pet-pointer-watch', (_e, enabled) => {
|
|
|
866
875
|
})
|
|
867
876
|
|
|
868
877
|
// resize the window to fit the content
|
|
869
|
-
|
|
878
|
+
// Opening and closing Settings eases the window between sizes (an ease-out over
|
|
879
|
+
// RESIZE_MS) instead of jumping; any other resize is immediate and cancels a
|
|
880
|
+
// tween still running, so the latest size always wins.
|
|
881
|
+
const RESIZE_MS = 240
|
|
882
|
+
let resizeTween = null
|
|
883
|
+
ipcMain.on('resize', (_e, w, h, animate) => {
|
|
870
884
|
if (!win || win.isDestroyed()) return
|
|
871
885
|
const width = Math.max(100, Math.round(w))
|
|
872
886
|
const height = Math.max(110, Math.round(h))
|
|
887
|
+
clearInterval(resizeTween)
|
|
888
|
+
resizeTween = null
|
|
889
|
+
if (!animate) return setWindowSize(width, height)
|
|
890
|
+
const from = win.getBounds()
|
|
891
|
+
const start = Date.now()
|
|
892
|
+
const step = () => {
|
|
893
|
+
if (!win || win.isDestroyed()) return clearInterval(resizeTween)
|
|
894
|
+
const t = Math.min(1, (Date.now() - start) / RESIZE_MS)
|
|
895
|
+
const k = 1 - (1 - t) ** 3
|
|
896
|
+
setWindowSize(
|
|
897
|
+
Math.round(from.width + (width - from.width) * k),
|
|
898
|
+
Math.round(from.height + (height - from.height) * k),
|
|
899
|
+
)
|
|
900
|
+
if (t === 1) {
|
|
901
|
+
clearInterval(resizeTween)
|
|
902
|
+
resizeTween = null
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
resizeTween = setInterval(step, 16)
|
|
906
|
+
step()
|
|
907
|
+
})
|
|
908
|
+
|
|
909
|
+
function setWindowSize(width, height) {
|
|
873
910
|
if (currentMode === 'menubar') {
|
|
874
911
|
win.setContentSize(width, height)
|
|
875
912
|
if (win.isVisible()) positionUnderTray() // keep it anchored under the tray
|
|
@@ -885,7 +922,7 @@ ipcMain.on('resize', (_e, w, h) => {
|
|
|
885
922
|
const after = win.getBounds()
|
|
886
923
|
moveWindow(right - after.width, bottom - after.height)
|
|
887
924
|
}
|
|
888
|
-
}
|
|
925
|
+
}
|
|
889
926
|
|
|
890
927
|
// the arrow opens the page of whichever service the panel is showing
|
|
891
928
|
ipcMain.on('open-usage', (_e, provider) =>
|
package/package.json
CHANGED
package/preload.js
CHANGED
|
@@ -10,7 +10,7 @@ contextBridge.exposeInMainWorld('api', {
|
|
|
10
10
|
onError: (cb) => ipcRenderer.on('usage-error', (_e, msg) => cb(msg)),
|
|
11
11
|
onConfig: (cb) => ipcRenderer.on('config', (_e, cfg) => cb(cfg)),
|
|
12
12
|
saveConfig: (patch) => ipcRenderer.send('save-config', patch),
|
|
13
|
-
resize: (w, h) => ipcRenderer.send('resize', w, h),
|
|
13
|
+
resize: (w, h, animate) => ipcRenderer.send('resize', w, h, animate),
|
|
14
14
|
openUsage: (provider) => ipcRenderer.send('open-usage', provider),
|
|
15
15
|
codexDetect: () => ipcRenderer.send('codex-detect'),
|
|
16
16
|
onCodexDetected: (cb) => ipcRenderer.on('codex-detected', (_e, r) => cb(r)),
|
|
@@ -36,6 +36,7 @@ contextBridge.exposeInMainWorld('api', {
|
|
|
36
36
|
onDebugState: (cb) => ipcRenderer.on('debug-state', (_e, s) => cb(s)),
|
|
37
37
|
onVersion: (cb) => ipcRenderer.on('version', (_e, v) => cb(v)),
|
|
38
38
|
onUpdateStatus: (cb) => ipcRenderer.on('update-status', (_e, s) => cb(s)),
|
|
39
|
+
onPopoverAnchor: (cb) => ipcRenderer.on('popover-anchor', (_e, x) => cb(x)),
|
|
39
40
|
checkUpdates: () => ipcRenderer.send('check-updates'),
|
|
40
41
|
doUpdate: () => ipcRenderer.send('do-update'),
|
|
41
42
|
quit: () => ipcRenderer.send('quit'),
|
package/renderer/index.html
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
<title>Clauddy</title>
|
|
7
7
|
<link rel="stylesheet" href="style.css" />
|
|
8
8
|
<link rel="stylesheet" href="motion.css" />
|
|
9
|
+
<link rel="stylesheet" href="pets.css" />
|
|
9
10
|
</head>
|
|
10
11
|
<body class="state-idle one-account">
|
|
11
12
|
<!-- brand marks from simple-icons (CC0); the trademarks are Anthropic's and OpenAI's -->
|
|
@@ -226,10 +227,11 @@
|
|
|
226
227
|
|
|
227
228
|
<div id="pet-activity" class="activity-logos" role="img" hidden><span data-provider="claude"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="#logo-claude" /></svg></span><span data-provider="codex"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="#logo-openai" /></svg></span><span data-provider="cursor"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="#logo-cursor" /></svg></span></div>
|
|
228
229
|
<section id="pet-glance" aria-label="Session usage">
|
|
229
|
-
<button type="button" data-provider="claude" id="glance-claude"><svg class="mini-logo" viewBox="0 0 24 24" aria-hidden="true"><use href="#logo-claude" /></svg><span>Claude</span><b id="glance-claude-value">—</b></button>
|
|
230
|
-
<button type="button" data-provider="codex" id="glance-codex"><svg class="mini-logo" viewBox="0 0 24 24" aria-hidden="true"><use href="#logo-openai" /></svg><span>Codex</span><b id="glance-codex-value">—</b></button>
|
|
231
|
-
<button type="button" data-provider="cursor" id="glance-cursor"><svg class="mini-logo" viewBox="0 0 24 24" aria-hidden="true"><use href="#logo-cursor" /></svg><span>Cursor</span><b id="glance-cursor-value">—</b></button>
|
|
230
|
+
<button type="button" data-provider="claude" id="glance-claude"><svg class="mini-logo" viewBox="0 0 24 24" aria-hidden="true"><use href="#logo-claude" /></svg><span>Claude</span><b id="glance-claude-value">—</b><i class="glance-bar" aria-hidden="true"></i></button>
|
|
231
|
+
<button type="button" data-provider="codex" id="glance-codex"><svg class="mini-logo" viewBox="0 0 24 24" aria-hidden="true"><use href="#logo-openai" /></svg><span>Codex</span><b id="glance-codex-value">—</b><i class="glance-bar" aria-hidden="true"></i></button>
|
|
232
|
+
<button type="button" data-provider="cursor" id="glance-cursor"><svg class="mini-logo" viewBox="0 0 24 24" aria-hidden="true"><use href="#logo-cursor" /></svg><span>Cursor</span><b id="glance-cursor-value">—</b><i class="glance-bar" aria-hidden="true"></i></button>
|
|
232
233
|
<span id="glance-empty" hidden>Connect an account in Settings.</span>
|
|
234
|
+
<i class="glance-sep" aria-hidden="true"></i>
|
|
233
235
|
<button type="button" id="pet-restore" aria-label="Open compact monitor" title="Open compact monitor"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 4h6v6M20 4l-7 7M10 20H4v-6M4 20l7-7" /></svg></button>
|
|
234
236
|
</section>
|
|
235
237
|
<div id="companion-notice" role="status" hidden></div>
|
|
@@ -318,148 +320,176 @@
|
|
|
318
320
|
|
|
319
321
|
<!-- settings panel -->
|
|
320
322
|
<div id="settings">
|
|
321
|
-
<div class="settings-heading">
|
|
322
|
-
<div>
|
|
323
|
-
<h3>Make yourself at home.</h3>
|
|
324
|
-
<p>Your accounts, your little companion.</p>
|
|
325
|
-
</div>
|
|
326
|
-
</div>
|
|
327
323
|
|
|
328
|
-
<div
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
<button type="button" class="
|
|
332
|
-
<span class="connection-avatar claude-avatar"><svg class="connection-logo" viewBox="0 0 24 24" aria-hidden="true"><use href="#logo-claude" /></svg><i class="conn-check" hidden aria-hidden="true">✓</i></span>
|
|
333
|
-
<span class="conn-name">Claude</span>
|
|
334
|
-
<span class="conn-state" id="conn-claude-state">Connect</span>
|
|
335
|
-
</button>
|
|
336
|
-
<button type="button" class="conn-tile" id="conn-codex" data-conn="codex" aria-expanded="false" aria-controls="codex-settings">
|
|
337
|
-
<span class="connection-avatar codex-avatar"><svg class="connection-logo" viewBox="0 0 24 24" aria-hidden="true"><use href="#logo-openai" /></svg><i class="conn-check" hidden aria-hidden="true">✓</i></span>
|
|
338
|
-
<span class="conn-name">Codex</span>
|
|
339
|
-
<span class="conn-state" id="conn-codex-state">Connect</span>
|
|
340
|
-
</button>
|
|
341
|
-
<button type="button" class="conn-tile" id="conn-cursor" data-conn="cursor" aria-expanded="false" aria-controls="cursor-settings">
|
|
342
|
-
<span class="connection-avatar cursor-avatar"><svg class="connection-logo" viewBox="0 0 24 24" aria-hidden="true"><use href="#logo-cursor" /></svg><i class="conn-check" hidden aria-hidden="true">✓</i></span>
|
|
343
|
-
<span class="conn-name">Cursor</span>
|
|
344
|
-
<span class="conn-state" id="conn-cursor-state">Connect</span>
|
|
345
|
-
</button>
|
|
324
|
+
<div id="set-tabs" role="tablist" aria-label="Settings">
|
|
325
|
+
<button type="button" role="tab" class="set-tab" id="tab-accounts" data-tab="accounts" aria-controls="pane-accounts">Accounts</button>
|
|
326
|
+
<button type="button" role="tab" class="set-tab" id="tab-alerts" data-tab="alerts" aria-controls="pane-alerts">Alerts</button>
|
|
327
|
+
<button type="button" role="tab" class="set-tab" id="tab-appearance" data-tab="appearance" aria-controls="pane-appearance">Appearance</button>
|
|
346
328
|
</div>
|
|
347
|
-
|
|
348
|
-
<div id="
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
<div id="
|
|
352
|
-
<
|
|
353
|
-
|
|
354
|
-
<
|
|
355
|
-
<span class="
|
|
356
|
-
</
|
|
357
|
-
<button
|
|
358
|
-
<svg class="
|
|
359
|
-
|
|
360
|
-
</
|
|
329
|
+
<!-- one pane at a time; the window eases to each pane's own height -->
|
|
330
|
+
<div id="set-rows">
|
|
331
|
+
<section class="set-pane" id="pane-accounts" role="tabpanel" aria-labelledby="tab-accounts">
|
|
332
|
+
<!-- one tile per service; a click opens its card below -->
|
|
333
|
+
<div id="conn-tiles">
|
|
334
|
+
<button type="button" class="conn-tile" id="conn-claude" data-conn="claude" aria-expanded="false" aria-controls="account">
|
|
335
|
+
<span class="connection-avatar claude-avatar"><svg class="connection-logo" viewBox="0 0 24 24" aria-hidden="true"><use href="#logo-claude" /></svg><i class="conn-check" hidden aria-hidden="true">✓</i></span>
|
|
336
|
+
<span class="conn-name">Claude</span>
|
|
337
|
+
<span class="conn-state" id="conn-claude-state">Connect</span>
|
|
338
|
+
</button>
|
|
339
|
+
<button type="button" class="conn-tile" id="conn-codex" data-conn="codex" aria-expanded="false" aria-controls="codex-settings">
|
|
340
|
+
<span class="connection-avatar codex-avatar"><svg class="connection-logo" viewBox="0 0 24 24" aria-hidden="true"><use href="#logo-openai" /></svg><i class="conn-check" hidden aria-hidden="true">✓</i></span>
|
|
341
|
+
<span class="conn-name">Codex</span>
|
|
342
|
+
<span class="conn-state" id="conn-codex-state">Connect</span>
|
|
343
|
+
</button>
|
|
344
|
+
<button type="button" class="conn-tile" id="conn-cursor" data-conn="cursor" aria-expanded="false" aria-controls="cursor-settings">
|
|
345
|
+
<span class="connection-avatar cursor-avatar"><svg class="connection-logo" viewBox="0 0 24 24" aria-hidden="true"><use href="#logo-cursor" /></svg><i class="conn-check" hidden aria-hidden="true">✓</i></span>
|
|
346
|
+
<span class="conn-name">Cursor</span>
|
|
347
|
+
<span class="conn-state" id="conn-cursor-state">Connect</span>
|
|
361
348
|
</button>
|
|
362
349
|
</div>
|
|
363
|
-
<div id="
|
|
364
|
-
|
|
365
|
-
|
|
350
|
+
<div id="connections">
|
|
351
|
+
<div id="account" class="conn-panel">
|
|
352
|
+
<!-- who you are comes first: the list, then the login for whichever
|
|
353
|
+
account is active — so "add" and the code field sit together -->
|
|
354
|
+
<div id="acc-connected" class="connect-block connection-card">
|
|
355
|
+
<span class="connection-avatar claude-avatar" id="acc-avatar"><svg class="connection-logo" viewBox="0 0 24 24" aria-hidden="true"><use href="#logo-claude" /></svg></span>
|
|
366
356
|
<div class="connection-copy">
|
|
367
|
-
<div class="connection-heading"><b>Claude</b></div>
|
|
368
|
-
<span class="connection-
|
|
357
|
+
<div class="connection-heading"><b>Claude</b><span id="acc-sub" class="plan-badge" hidden></span></div>
|
|
358
|
+
<span class="connection-caption acc-ok" id="acc-ok">Connected</span>
|
|
369
359
|
</div>
|
|
370
|
-
<button id="acc-
|
|
360
|
+
<button id="acc-logout" class="cb-out connection-remove" title="Disconnect Claude" aria-label="Disconnect Claude">
|
|
361
|
+
<svg class="ic" viewBox="0 0 24 24" aria-hidden="true">
|
|
362
|
+
<path d="M18 6 6 18M6 6l12 12" />
|
|
363
|
+
</svg>
|
|
364
|
+
</button>
|
|
371
365
|
</div>
|
|
372
|
-
<div id="acc-
|
|
373
|
-
<div
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
366
|
+
<div id="acc-disconnected">
|
|
367
|
+
<div id="acc-intro" class="connection-card">
|
|
368
|
+
<span class="connection-avatar claude-avatar"><svg class="connection-logo" viewBox="0 0 24 24" aria-hidden="true"><use href="#logo-claude" /></svg></span>
|
|
369
|
+
<div class="connection-copy">
|
|
370
|
+
<div class="connection-heading"><b>Claude</b></div>
|
|
371
|
+
<span class="connection-hint">Connect via browser to track your usage.</span>
|
|
372
|
+
</div>
|
|
373
|
+
<button id="acc-connect" class="connection-btn claude-connect-btn" aria-label="Connect Claude" title="Log in with browser"><svg class="connection-logo" viewBox="0 0 24 24" aria-hidden="true"><use href="#logo-claude" /></svg><span>Connect</span></button>
|
|
374
|
+
</div>
|
|
375
|
+
<div id="acc-paste">
|
|
376
|
+
<div class="set-hint set-hint-left">Paste the code from the browser page:</div>
|
|
377
|
+
<input id="acc-code" type="text" placeholder="authentication code" />
|
|
378
|
+
<button id="acc-confirm" class="acc-btn">Connect</button>
|
|
379
|
+
<div id="acc-msg"></div>
|
|
380
|
+
</div>
|
|
377
381
|
</div>
|
|
378
382
|
</div>
|
|
379
|
-
</div>
|
|
380
383
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
384
|
+
<!-- Codex: opt-in, read from its local logs — nothing to log into here -->
|
|
385
|
+
<div id="codex-settings" class="connection-card conn-panel">
|
|
386
|
+
<span class="codex-avatar connection-avatar"><svg class="codex-logo" viewBox="0 0 24 24" aria-hidden="true"><use href="#logo-openai" /></svg></span>
|
|
387
|
+
<div class="connection-copy">
|
|
388
|
+
<div class="connection-heading"><b>Codex</b><span id="codex-plan" class="plan-badge" hidden></span></div>
|
|
389
|
+
<span class="connection-caption" id="codex-connected-caption">Connected on this device</span>
|
|
390
|
+
<span id="codex-hint" class="connection-hint">Track Codex alongside Claude, in this pet.</span>
|
|
391
|
+
</div>
|
|
392
|
+
<div class="codex-actions">
|
|
393
|
+
<button id="codex-connect" class="connection-btn" aria-label="Connect Codex"><svg class="codex-logo" viewBox="0 0 24 24" aria-hidden="true"><use href="#logo-openai" /></svg><span>Connect</span></button>
|
|
394
|
+
<span id="codex-setup" hidden>
|
|
395
|
+
<button id="codex-retry" class="connection-btn">Retry</button>
|
|
396
|
+
<button id="codex-setup-cancel" class="codex-x" title="Cancel" aria-label="Cancel">
|
|
397
|
+
<svg class="ic" viewBox="0 0 24 24" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12" /></svg>
|
|
398
|
+
</button>
|
|
399
|
+
</span>
|
|
400
|
+
<button id="codex-disconnect" class="codex-x connection-remove" title="Disconnect Codex" aria-label="Disconnect Codex">
|
|
394
401
|
<svg class="ic" viewBox="0 0 24 24" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12" /></svg>
|
|
395
402
|
</button>
|
|
396
|
-
</
|
|
397
|
-
<button id="codex-disconnect" class="codex-x connection-remove" title="Disconnect Codex" aria-label="Disconnect Codex">
|
|
398
|
-
<svg class="ic" viewBox="0 0 24 24" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12" /></svg>
|
|
399
|
-
</button>
|
|
403
|
+
</div>
|
|
400
404
|
</div>
|
|
401
|
-
</div>
|
|
402
405
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
406
|
+
<!-- Cursor: opt-in, through the Cursor app's own login on this machine -->
|
|
407
|
+
<div id="cursor-settings" class="connection-card conn-panel">
|
|
408
|
+
<span class="cursor-avatar connection-avatar"><svg class="cursor-logo" viewBox="0 0 24 24" aria-hidden="true"><use href="#logo-cursor" /></svg></span>
|
|
409
|
+
<div class="connection-copy">
|
|
410
|
+
<div class="connection-heading"><b>Cursor</b><span id="cursor-plan" class="plan-badge" hidden></span></div>
|
|
411
|
+
<span class="connection-caption" id="cursor-connected-caption">Connected on this device</span>
|
|
412
|
+
<span id="cursor-hint" class="connection-hint">Track Cursor alongside Claude, in this pet.</span>
|
|
413
|
+
</div>
|
|
414
|
+
<div class="codex-actions">
|
|
415
|
+
<button id="cursor-connect" class="connection-btn" aria-label="Connect Cursor"><svg class="cursor-logo" viewBox="0 0 24 24" aria-hidden="true"><use href="#logo-cursor" /></svg><span>Connect</span></button>
|
|
416
|
+
<span id="cursor-setup" hidden>
|
|
417
|
+
<button id="cursor-retry" class="connection-btn">Retry</button>
|
|
418
|
+
<button id="cursor-setup-cancel" class="codex-x" title="Cancel" aria-label="Cancel">
|
|
419
|
+
<svg class="ic" viewBox="0 0 24 24" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12" /></svg>
|
|
420
|
+
</button>
|
|
421
|
+
</span>
|
|
422
|
+
<button id="cursor-disconnect" class="codex-x connection-remove" title="Disconnect Cursor" aria-label="Disconnect Cursor">
|
|
416
423
|
<svg class="ic" viewBox="0 0 24 24" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12" /></svg>
|
|
417
424
|
</button>
|
|
418
|
-
</
|
|
419
|
-
<button id="cursor-disconnect" class="codex-x connection-remove" title="Disconnect Cursor" aria-label="Disconnect Cursor">
|
|
420
|
-
<svg class="ic" viewBox="0 0 24 24" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12" /></svg>
|
|
421
|
-
</button>
|
|
422
|
-
</div>
|
|
423
|
-
</div>
|
|
424
|
-
</div>
|
|
425
|
-
|
|
426
|
-
<div class="settings-label">Preferences</div>
|
|
427
|
-
<div id="set-rows">
|
|
428
|
-
<span class="seg settings-segment" id="set-mode">
|
|
429
|
-
<button type="button" class="seg-btn" data-mode="floating">Floating pet</button>
|
|
430
|
-
<button type="button" class="seg-btn" data-mode="menubar">Menu bar</button>
|
|
431
|
-
</span>
|
|
432
|
-
<div class="set-row">
|
|
433
|
-
<span class="set-row-label">Gentle notifications</span>
|
|
434
|
-
<input id="set-alerts" class="set-toggle" type="checkbox" aria-label="Enable alerts" />
|
|
435
|
-
</div>
|
|
436
|
-
<div class="settings-label threshold-label">alert thresholds</div>
|
|
437
|
-
<div class="set-row set-sub">
|
|
438
|
-
<span class="set-row-label">Heads-up</span>
|
|
439
|
-
<span class="num"><button type="button" class="num-btn" data-for="set-t1" data-step="-1">−</button><span class="num-val"><input id="set-t1" type="number" min="1" max="100" step="1" /><i>%</i></span><button type="button" class="num-btn" data-for="set-t1" data-step="1">+</button></span>
|
|
440
|
-
</div>
|
|
441
|
-
<div class="set-row set-sub">
|
|
442
|
-
<span class="set-row-label">Near limit</span>
|
|
443
|
-
<span class="num"><button type="button" class="num-btn" data-for="set-t2" data-step="-1">−</button><span class="num-val"><input id="set-t2" type="number" min="1" max="100" step="1" /><i>%</i></span><button type="button" class="num-btn" data-for="set-t2" data-step="1">+</button></span>
|
|
444
|
-
</div>
|
|
445
|
-
<div class="settings-label threshold-label">mood thresholds</div>
|
|
446
|
-
<div class="set-row">
|
|
447
|
-
<span class="set-row-label">Catch fire</span>
|
|
448
|
-
<span class="num"><button type="button" class="num-btn" data-for="set-fire" data-step="-1">−</button><span class="num-val"><input id="set-fire" type="number" min="1" max="99" step="1" /><i>%</i></span><button type="button" class="num-btn" data-for="set-fire" data-step="1">+</button></span>
|
|
449
|
-
</div>
|
|
450
|
-
<div class="set-row">
|
|
451
|
-
<span class="set-row-label">Zoom</span>
|
|
452
|
-
<span class="num"><button type="button" class="num-btn" data-for="set-zoom" data-step="-25">−</button><span class="num-val"><input id="set-zoom" type="number" min="100" max="200" step="25" /><i>%</i></span><button type="button" class="num-btn" data-for="set-zoom" data-step="25">+</button></span>
|
|
453
|
-
</div>
|
|
454
|
-
<div class="settings-label threshold-label">voice</div>
|
|
455
|
-
<div class="set-row">
|
|
456
|
-
<span class="set-row-label">Speech bubbles</span>
|
|
457
|
-
<input id="set-talk" class="set-toggle" type="checkbox" aria-label="Let the pet talk" />
|
|
425
|
+
</div>
|
|
458
426
|
</div>
|
|
459
|
-
<div class="set-row voice-sub">
|
|
460
|
-
<span class="set-row-label">Chiptune voice</span>
|
|
461
|
-
<input id="set-sound" class="set-toggle" type="checkbox" aria-label="Play blips when the pet talks" />
|
|
462
427
|
</div>
|
|
428
|
+
</section>
|
|
429
|
+
<!-- every pane is the same pattern: a muted label over a rounded group of
|
|
430
|
+
equal-height rows, label left and a compact control right -->
|
|
431
|
+
<section class="set-pane" id="pane-alerts" role="tabpanel" aria-labelledby="tab-alerts">
|
|
432
|
+
<div class="settings-label">notifications</div>
|
|
433
|
+
<div class="set-group">
|
|
434
|
+
<div class="set-row">
|
|
435
|
+
<span class="set-row-label">Gentle notifications</span>
|
|
436
|
+
<input id="set-alerts" class="set-toggle" type="checkbox" aria-label="Enable alerts" />
|
|
437
|
+
</div>
|
|
438
|
+
<div class="set-row set-sub">
|
|
439
|
+
<span class="set-row-label">Heads-up at</span>
|
|
440
|
+
<span class="num"><button type="button" class="num-btn" data-for="set-t1" data-step="-1">−</button><span class="num-val"><input id="set-t1" type="number" min="1" max="100" step="1" /><i>%</i></span><button type="button" class="num-btn" data-for="set-t1" data-step="1">+</button></span>
|
|
441
|
+
</div>
|
|
442
|
+
<div class="set-row set-sub">
|
|
443
|
+
<span class="set-row-label">Near limit at</span>
|
|
444
|
+
<span class="num"><button type="button" class="num-btn" data-for="set-t2" data-step="-1">−</button><span class="num-val"><input id="set-t2" type="number" min="1" max="100" step="1" /><i>%</i></span><button type="button" class="num-btn" data-for="set-t2" data-step="1">+</button></span>
|
|
445
|
+
</div>
|
|
446
|
+
</div>
|
|
447
|
+
<div class="settings-label">mood</div>
|
|
448
|
+
<div class="set-group">
|
|
449
|
+
<div class="set-row">
|
|
450
|
+
<span class="set-row-label">Catch fire at</span>
|
|
451
|
+
<span class="num"><button type="button" class="num-btn" data-for="set-fire" data-step="-1">−</button><span class="num-val"><input id="set-fire" type="number" min="1" max="99" step="1" /><i>%</i></span><button type="button" class="num-btn" data-for="set-fire" data-step="1">+</button></span>
|
|
452
|
+
</div>
|
|
453
|
+
</div>
|
|
454
|
+
</section>
|
|
455
|
+
<section class="set-pane" id="pane-appearance" role="tabpanel" aria-labelledby="tab-appearance">
|
|
456
|
+
<div class="settings-label">pet</div>
|
|
457
|
+
<div class="set-group">
|
|
458
|
+
<div class="set-row">
|
|
459
|
+
<span class="pet-current">
|
|
460
|
+
<span id="pet-current-thumb" class="pet-thumb" aria-hidden="true"></span>
|
|
461
|
+
<span id="pet-current-name" class="set-row-label"></span>
|
|
462
|
+
</span>
|
|
463
|
+
<button type="button" id="pet-edit" class="set-link" aria-label="Change pet" aria-haspopup="dialog">Change</button>
|
|
464
|
+
</div>
|
|
465
|
+
</div>
|
|
466
|
+
<div id="pet-season" hidden></div>
|
|
467
|
+
<div class="settings-label">display</div>
|
|
468
|
+
<div class="set-group">
|
|
469
|
+
<div class="set-row">
|
|
470
|
+
<span class="set-row-label">Lives in</span>
|
|
471
|
+
<span class="seg settings-segment" id="set-mode">
|
|
472
|
+
<button type="button" class="seg-btn" data-mode="floating">Floating</button>
|
|
473
|
+
<button type="button" class="seg-btn" data-mode="menubar">Menu bar</button>
|
|
474
|
+
</span>
|
|
475
|
+
</div>
|
|
476
|
+
<div class="set-row">
|
|
477
|
+
<span class="set-row-label">Zoom</span>
|
|
478
|
+
<span class="num"><button type="button" class="num-btn" data-for="set-zoom" data-step="-25">−</button><span class="num-val"><input id="set-zoom" type="number" min="100" max="200" step="25" /><i>%</i></span><button type="button" class="num-btn" data-for="set-zoom" data-step="25">+</button></span>
|
|
479
|
+
</div>
|
|
480
|
+
</div>
|
|
481
|
+
<div class="settings-label">voice</div>
|
|
482
|
+
<div class="set-group">
|
|
483
|
+
<div class="set-row">
|
|
484
|
+
<span class="set-row-label">Speech bubbles</span>
|
|
485
|
+
<input id="set-talk" class="set-toggle" type="checkbox" aria-label="Let the pet talk" />
|
|
486
|
+
</div>
|
|
487
|
+
<div class="set-row voice-sub">
|
|
488
|
+
<span class="set-row-label">Chiptune voice</span>
|
|
489
|
+
<input id="set-sound" class="set-toggle" type="checkbox" aria-label="Play blips when the pet talks" />
|
|
490
|
+
</div>
|
|
491
|
+
</div>
|
|
492
|
+
</section>
|
|
463
493
|
</div>
|
|
464
494
|
|
|
465
495
|
<div class="set-actions">
|
|
@@ -476,10 +506,22 @@
|
|
|
476
506
|
</span>
|
|
477
507
|
</div>
|
|
478
508
|
</div>
|
|
509
|
+
<div id="pet-modal" role="dialog" aria-modal="true" aria-labelledby="pet-modal-title" hidden>
|
|
510
|
+
<div class="pet-modal-card">
|
|
511
|
+
<div class="pet-modal-head">
|
|
512
|
+
<span id="pet-modal-title">Choose a pet</span>
|
|
513
|
+
<button type="button" id="pet-modal-close" class="pet-edit" aria-label="Close">
|
|
514
|
+
<svg class="ic" viewBox="0 0 24 24" aria-hidden="true"><path d="M6 6l12 12M18 6 6 18" /></svg>
|
|
515
|
+
</button>
|
|
516
|
+
</div>
|
|
517
|
+
<div id="set-pet" role="radiogroup" aria-label="Pet"></div>
|
|
518
|
+
</div>
|
|
519
|
+
</div>
|
|
479
520
|
</div>
|
|
480
521
|
<script src="burn.js"></script>
|
|
481
522
|
<script src="voice.js"></script>
|
|
482
523
|
<script src="companion.js"></script>
|
|
524
|
+
<script src="pets.js"></script>
|
|
483
525
|
<script src="pet.js"></script>
|
|
484
526
|
</body>
|
|
485
527
|
</html>
|