← Commit history
README.md+2
@@ -276,6 +276,8 @@ v1.1.20: /command returns errorCode command_not_found (HTTP 400) with did-you-me  v1.1.21: event-driven tab census + Claude session identity (John 2026-09-03: never poll the iframes again). GET /tabs and the SSE stream GET /tabs/events publish the extension host's own tabGroups census on every change; POST /claude/session-start ingests the Claude SessionStart hook (id + transcript path, before the jsonl is flushed) and GET /claude/sessions lists it; POST /claude/open-session opens an existing conversation by id and confirms the bind (retagging sdk-cli transcripts, which the Claude extension otherwise declines). Capability markers in /health: tabs.list, tabs.events, claude.open-session, claude.session-start, claude.sessions. +v1.1.65: the Claude usage widget reads the structured limits list, so model-scoped weekly limits (Fable limit 93 percent) show with their own name and the provider severity colour, next to the session and weekly bars.+ v1.1.64: the usage widgets ask their provider at most once every three minutes, pause while the window is hidden, back off on errors (doubling to 15 minutes), and re-read the sign-in file only when it changes.  v1.1.63: the Claude and Codex usage widgets carry their vendor marks (the launch bar artwork) so you can tell them apart at a glance, in the slot and in the Widgets pulldown.
VERSION+1−1
@@ -1 +1 @@-1.1.64+1.1.65
bin/adom-vscode
⋯ 1 unchanged line ⋯
bin/hydrogen-widget-claude-usage+23−6
@@ -16,11 +16,28 @@ def data():     tok = oa.get('accessToken')     if not tok: return {'error': 'not signed in to Claude Code'}     u = lib.http_json('https://api.anthropic.com/api/oauth/usage', {'Authorization': 'Bearer ' + tok, 'anthropic-beta': 'oauth-2025-04-20', 'User-Agent': 'hydrogen-widget-claude-usage'})-    out = {'five_hour': (u.get('five_hour') or {}).get('utilization'), 'seven_day': (u.get('seven_day') or {}).get('utilization'), 'models': []}-    for k, v in u.items():-        if k.startswith('seven_day_') and isinstance(v, dict) and v.get('utilization') is not None:-            out['models'].append({'name': k[len('seven_day_'):].replace('_', ' '), 'pct': v['utilization']})-    return out+    bars = []+    # The structured list is what Claude Code's own Usage panel draws: the session window, the+    # weekly window, and every weekly limit scoped to a model (Fable, Opus, ...), each with the+    # provider's severity. Fall back to the flat fields on an older response.+    for lim in u.get('limits') or []:+        kind = lim.get('kind'); pct = lim.get('percent')+        if pct is None: continue+        if kind == 'session': label = '5h'+        elif kind == 'weekly_all': label = 'week'+        elif kind == 'weekly_scoped':+            scope = lim.get('scope') or {}; model = scope.get('model') or {}+            label = model.get('display_name') or 'model'+        else: label = kind or 'limit'+        bars.append({'label': label, 'pct': pct, 'severity': lim.get('severity') or 'normal'})+    if not bars:+        for label, key in (('5h', 'five_hour'), ('week', 'seven_day')):+            v = (u.get(key) or {}).get('utilization')+            if v is not None: bars.append({'label': label, 'pct': v, 'severity': 'normal'})+        for k, v in u.items():+            if k.startswith('seven_day_') and isinstance(v, dict) and v.get('utilization') is not None:+                bars.append({'label': k[len('seven_day_'):].replace('_', ' '), 'pct': v['utilization'], 'severity': 'normal'})+    return {'bars': bars} -RENDER = r"""(d.error?`<span class="err">${d.error}</span>`:bar('5h',d.five_hour??0)+bar('week',d.seven_day??0)+(d.models||[]).slice(0,1).map(m=>bar(m.name,m.pct)).join(''))"""+RENDER = r"""(d.error?`<span class="err">${d.error}</span>`:(d.bars||[]).map(b=>bar(b.label,b.pct,b.severity)).join(''))""" lib.serve('Claude usage', data, RENDER, 180000, mark=marks.MARKS['claude'])
bin/hydrogen-widget-codex-usage

  
bin/hydrogen-widget-lib.py+1−1
@@ -23,7 +23,7 @@ html,body{margin:0;height:100%%;background:transparent;color:#e6ebef;font-family </style><body><div class="w"><span class="mark" style="color:%(mark_color)s">%(mark_svg)s</span><div class="w" id="w" style="padding-left:0">%(title)s…</div></div> <script> const R=%(refresh_ms)d;-function bar(l,p){const c=p>=90?'hot':p>=70?'warn':'';return `<span class="lbl">${l}</span><span class="bar ${c}"><i style="width:${Math.max(0,Math.min(100,p))}%%"></i></span><span class="v">${Math.round(p)}%%</span>`;}+function bar(l,p,sev){const c=(sev==='critical'||p>=90)?'hot':(sev==='warning'||p>=70)?'warn':'';return `<span class="lbl">${l}</span><span class="bar ${c}"><i style="width:${Math.max(0,Math.min(100,p))}%%"></i></span><span class="v">${Math.round(p)}%%</span>`;} async function tick(){try{const r=await fetch('/data.json',{cache:'no-store'});const d=await r.json();document.getElementById('w').innerHTML=%(render_js)s;}catch(e){document.getElementById('w').innerHTML='<span class="err">no data</span>';}} let tm=null;function arm(){if(tm)return;tm=setInterval(tick,R);}function disarm(){if(tm){clearInterval(tm);tm=null;}} document.addEventListener('visibilitychange',()=>{if(document.hidden)disarm();else{tick();arm();}});
bin/hydrogen-widget-marks.py

  
hydrogen-widget.json+1−1
@@ -6,7 +6,7 @@       "name": "Claude usage",       "icon": "vendor:claude",       "brief": "Your Claude limits at a glance: 5-hour session, weekly, and the weekly model bucket that applies, as percent used. Reads the Claude Code sign-in in this workspace.",-      "width": 250,+      "width": 320,       "install": "adom/adom-vscode",       "launch": { "command": "hydrogen-widget-claude-usage", "port": 8931 },       "health": { "url": "/", "timeout_seconds": 60 }
install.sh

  
package.json+1−1
@@ -1,6 +1,6 @@ {   "slug": "adom-vscode",-  "version": "1.1.64",+  "version": "1.1.65",   "type": "app",   "description": "CLI + VS Code extension that lets AI assistants and the Hydrogen Desktop frontend drive VS Code from inside an Adom container: open files, live get/set of any setting/theme/font (no reload), native streamed exec, a frontend event queue, container identity (hd/hw), api-key status/inject, extension query/update, modes, paste screenshots, and any VS Code command via a local HTTP API on port 8821 (with port-file fallback discovery).",   "license": "PROPRIETARY",
page.json+2−2
@@ -4,7 +4,7 @@   "slug": "adom-vscode",   "title": "adom-vscode",   "brief": "Let Claude, Codex and Kimi drive VS Code inside your Adom container",-  "version": "1.1.64",+  "version": "1.1.65",   "license": "PROPRIETARY",   "visibility": "public",   "hero": {@@ -141,4 +141,4 @@     "adom-vscode-extensions",     "adom-vscode-modes"   ]-}\ No newline at end of file+}