@juliantanx/aiusage-widget 1.3.2 → 1.3.4

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
@@ -17,7 +17,7 @@ English | [中文](./README_zh.md)
17
17
  ## Prerequisites
18
18
 
19
19
  - [aiusage](https://github.com/juliantanx/aiusage) CLI installed and data parsed (`aiusage parse`)
20
- - Node.js >= 18
20
+ - Node.js >= 20
21
21
 
22
22
  ## Install
23
23
 
package/README_zh.md CHANGED
@@ -17,7 +17,7 @@
17
17
  ## 前置条件
18
18
 
19
19
  - 已安装 [aiusage](https://github.com/juliantanx/aiusage) CLI 并完成数据解析(`aiusage parse`)
20
- - Node.js >= 18
20
+ - Node.js >= 20
21
21
 
22
22
  ## 安装
23
23
 
@@ -0,0 +1,121 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * postinstall: produce a better-sqlite3 native binding that matches BOTH the
4
+ * end user's platform/arch AND Electron's ABI, and place it at
5
+ * dist/native/better_sqlite3.node (where main.ts loads it via `nativeBinding`).
6
+ *
7
+ * Why this exists:
8
+ * - Electron embeds its own Node, so a binding compiled for the system Node
9
+ * ABI fails to load inside Electron, and vice versa.
10
+ * - The published package cannot ship a single prebuilt binary, because that
11
+ * binary is locked to the platform/arch of the machine that built it
12
+ * (the CI runner). On any other OS/arch it is unloadable.
13
+ *
14
+ * Strategy: download the prebuilt better-sqlite3 binary for `electron` runtime
15
+ * matching the locally installed Electron version, this platform, and this
16
+ * arch. We run prebuild-install inside a throwaway copy of better-sqlite3's
17
+ * package.json so we never clobber the shared better-sqlite3 build/Release
18
+ * (the CLI package relies on its Node-ABI binding in a pnpm workspace).
19
+ *
20
+ * Best-effort: a failure here (e.g. offline install, or no prebuilt for an
21
+ * exotic platform) prints a warning but does not fail `npm install`; any
22
+ * binary shipped in dist/native remains as a last-resort fallback.
23
+ */
24
+ const { existsSync, mkdirSync, copyFileSync, readFileSync, writeFileSync, rmSync } = require('node:fs')
25
+ const { dirname, join } = require('node:path')
26
+ const { execFileSync } = require('node:child_process')
27
+ const { tmpdir } = require('node:os')
28
+
29
+ const widgetRoot = join(__dirname, '..')
30
+
31
+ function warn(message) {
32
+ console.warn(`[aiusage-widget] ${message}`)
33
+ console.warn('[aiusage-widget] the tray widget may fail to open the usage database until this is resolved.')
34
+ }
35
+
36
+ function resolveElectronVersion() {
37
+ try {
38
+ return require('electron/package.json').version
39
+ } catch {
40
+ return null
41
+ }
42
+ }
43
+
44
+ function main() {
45
+ const electronVersion = resolveElectronVersion()
46
+ if (!electronVersion) {
47
+ warn('could not resolve the installed electron version; skipping native binding setup.')
48
+ return
49
+ }
50
+
51
+ let betterSqlite3Pkg
52
+ try {
53
+ betterSqlite3Pkg = require.resolve('better-sqlite3/package.json')
54
+ } catch {
55
+ warn('could not locate better-sqlite3; skipping native binding setup.')
56
+ return
57
+ }
58
+ const betterSqlite3Dir = dirname(betterSqlite3Pkg)
59
+
60
+ let prebuildInstallBin
61
+ try {
62
+ prebuildInstallBin = require.resolve('prebuild-install/bin.js', { paths: [betterSqlite3Dir] })
63
+ } catch {
64
+ warn('could not locate prebuild-install; skipping native binding setup.')
65
+ return
66
+ }
67
+
68
+ // Run prebuild-install against a disposable copy of better-sqlite3's
69
+ // package.json so the shared install (used by the Node-side CLI) is untouched.
70
+ const stageDir = join(tmpdir(), `aiusage-widget-native-${process.pid}`)
71
+ try {
72
+ mkdirSync(stageDir, { recursive: true })
73
+ writeFileSync(join(stageDir, 'package.json'), readFileSync(betterSqlite3Pkg))
74
+
75
+ execFileSync(
76
+ process.execPath,
77
+ [
78
+ prebuildInstallBin,
79
+ '--runtime=electron',
80
+ `--target=${electronVersion}`,
81
+ `--arch=${process.arch}`,
82
+ `--platform=${process.platform}`,
83
+ ],
84
+ { cwd: stageDir, stdio: 'inherit' },
85
+ )
86
+
87
+ const built = join(stageDir, 'build', 'Release', 'better_sqlite3.node')
88
+ if (!existsSync(built)) {
89
+ warn('prebuild-install completed but produced no binary; skipping native binding setup.')
90
+ return
91
+ }
92
+
93
+ const nativeDir = join(widgetRoot, 'dist', 'native')
94
+ mkdirSync(nativeDir, { recursive: true })
95
+ const target = join(nativeDir, 'better_sqlite3.node')
96
+ copyFileSync(built, target)
97
+
98
+ if (process.platform === 'darwin') {
99
+ // Ad-hoc sign so Gatekeeper / hardened runtime will load the binding.
100
+ try {
101
+ execFileSync('codesign', ['--force', '--sign', '-', target], { stdio: 'inherit' })
102
+ } catch {
103
+ // Non-fatal: unsigned binaries still load in most local setups.
104
+ }
105
+ }
106
+
107
+ console.log(
108
+ `[aiusage-widget] installed better-sqlite3 binding for electron ${electronVersion} (${process.platform}-${process.arch}).`,
109
+ )
110
+ } catch (error) {
111
+ warn(`failed to set up the native binding: ${error && error.message ? error.message : error}`)
112
+ } finally {
113
+ try {
114
+ rmSync(stageDir, { recursive: true, force: true })
115
+ } catch {
116
+ // ignore cleanup failures
117
+ }
118
+ }
119
+ }
120
+
121
+ main()
package/bin/launcher.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  const { spawn } = require('child_process')
3
- const { writeFileSync, mkdirSync } from 'fs'
3
+ const { writeFileSync, mkdirSync } = require('fs')
4
4
  const { homedir } = require('os')
5
5
  const electron = require('electron')
6
6
  const path = require('path')
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env node
2
+ const { copyFileSync, mkdirSync } = require('node:fs')
3
+ const { dirname, join } = require('node:path')
4
+ const { execFileSync } = require('node:child_process')
5
+ const { rebuild } = require('@electron/rebuild')
6
+
7
+ const widgetRoot = join(__dirname, '..')
8
+ const nativeSource = join(
9
+ dirname(require.resolve('better-sqlite3/package.json')),
10
+ 'build',
11
+ 'Release',
12
+ 'better_sqlite3.node'
13
+ )
14
+ const nativeDir = join(widgetRoot, 'dist', 'native')
15
+ const nativeTarget = join(nativeDir, 'better_sqlite3.node')
16
+
17
+ async function main() {
18
+ const electronVersion = require('electron/package.json').version
19
+
20
+ await rebuild({
21
+ buildPath: widgetRoot,
22
+ electronVersion,
23
+ onlyModules: ['better-sqlite3'],
24
+ force: true,
25
+ })
26
+
27
+ mkdirSync(nativeDir, { recursive: true })
28
+ copyFileSync(nativeSource, nativeTarget)
29
+
30
+ if (process.platform === 'darwin') {
31
+ execFileSync('codesign', ['--force', '--sign', '-', nativeTarget], { stdio: 'inherit' })
32
+ }
33
+
34
+ execFileSync('npm', ['run', 'install'], {
35
+ cwd: dirname(require.resolve('better-sqlite3/package.json')),
36
+ stdio: 'inherit',
37
+ })
38
+ }
39
+
40
+ main().catch((error) => {
41
+ console.error(error)
42
+ process.exit(1)
43
+ })
package/dist/main.js CHANGED
@@ -23,7 +23,10 @@ if (process.platform === 'darwin' && electron_1.app.dock) {
23
23
  }
24
24
  electron_1.app.whenReady().then(() => {
25
25
  if ((0, node_fs_1.existsSync)(DB_PATH)) {
26
- db = new Database(DB_PATH, { readonly: true });
26
+ db = new Database(DB_PATH, {
27
+ readonly: true,
28
+ nativeBinding: (0, ui_1.getWidgetNativeBindingPath)(__dirname),
29
+ });
27
30
  }
28
31
  createTray();
29
32
  createWindow();
@@ -39,13 +42,10 @@ electron_1.app.on('before-quit', () => {
39
42
  db?.close();
40
43
  });
41
44
  function createTray() {
42
- const icon = electron_1.nativeImage.createFromDataURL((0, ui_1.getTrayIconDataUrl)());
45
+ const { buffer, scaleFactor } = (0, ui_1.getTrayIconNativeImage)();
46
+ const icon = electron_1.nativeImage.createFromBuffer(buffer, scaleFactor ? { scaleFactor } : undefined);
43
47
  tray = new electron_1.Tray(icon);
44
48
  tray.setToolTip('aiusage Widget');
45
- // On macOS, SVG icons silently fail — use a text label as the visible entry
46
- if (process.platform === 'darwin') {
47
- tray.setTitle('⚡');
48
- }
49
49
  tray.on('click', () => toggleWindow());
50
50
  tray.on('right-click', () => {
51
51
  const menu = electron_1.Menu.buildFromTemplate([
@@ -85,10 +85,13 @@ function showWindow() {
85
85
  // Position near tray icon
86
86
  const trayBounds = tray.getBounds();
87
87
  const winBounds = win.getBounds();
88
- const x = Math.round(trayBounds.x + trayBounds.width / 2 - winBounds.width / 2);
89
- const y = process.platform === 'darwin'
90
- ? trayBounds.y + trayBounds.height + 4
91
- : trayBounds.y - winBounds.height - 4;
88
+ const displayBounds = electron_1.screen.getDisplayNearestPoint({ x: trayBounds.x, y: trayBounds.y }).workArea;
89
+ const { x, y } = (0, ui_1.getWindowPosition)({
90
+ platform: process.platform,
91
+ trayBounds,
92
+ windowBounds: winBounds,
93
+ displayBounds,
94
+ });
92
95
  win.setPosition(x, y, false);
93
96
  win.show();
94
97
  win.focus();
@@ -156,7 +159,8 @@ async function isDashboardReachable(port) {
156
159
  resolve(res.statusCode !== undefined && res.statusCode < 500);
157
160
  });
158
161
  req.on('error', () => resolve(false));
159
- req.setTimeout(1000, () => { req.destroy(); resolve(false); });
162
+ // 200ms is plenty for localhost; 1000ms caused each poll to block for 1s
163
+ req.setTimeout(200, () => { req.destroy(); resolve(false); });
160
164
  });
161
165
  }
162
166
  async function launchDashboard() {
@@ -167,21 +171,20 @@ async function launchDashboard() {
167
171
  stdio: 'ignore',
168
172
  shell: true,
169
173
  });
170
- let spawnError = null;
171
- child.on('error', (err) => {
172
- if (err.code === 'ENOENT') {
173
- spawnError = 'aiusage command not found';
174
- }
175
- else {
176
- spawnError = err.message;
177
- }
174
+ let failed = false;
175
+ child.on('error', () => { failed = true; });
176
+ // shell:true suppresses ENOENT on the error event — the shell itself spawns fine
177
+ // but exits immediately (code 127) when the command isn't found. Detect that here.
178
+ child.on('close', (code) => {
179
+ if (code !== 0)
180
+ failed = true;
178
181
  });
179
182
  child.unref();
180
- // Wait up to 5 seconds for the server to be ready
183
+ // Poll up to 5s (25 × 200ms) for the server to become reachable
181
184
  let attempts = 0;
182
185
  const check = async () => {
183
- if (spawnError) {
184
- resolve({ success: false, error: spawnError });
186
+ if (failed) {
187
+ resolve({ success: false, error: 'aiusage command not found' });
185
188
  return;
186
189
  }
187
190
  if (await isDashboardReachable(getDashboardPort())) {
@@ -189,11 +192,11 @@ async function launchDashboard() {
189
192
  return;
190
193
  }
191
194
  attempts++;
192
- if (attempts >= 10) {
195
+ if (attempts >= 25) {
193
196
  resolve({ success: false, error: 'Server failed to start within 5 seconds' });
194
197
  return;
195
198
  }
196
- setTimeout(check, 500);
199
+ setTimeout(check, 200);
197
200
  };
198
201
  check();
199
202
  });
Binary file
@@ -0,0 +1,2 @@
1
+ var se=Object.defineProperty;var ie=(e,t,n)=>t in e?se(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var z=(e,t,n)=>ie(e,typeof t!="symbol"?t+"":t,n);(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const r of document.querySelectorAll('link[rel="modulepreload"]'))o(r);new MutationObserver(r=>{for(const s of r)if(s.type==="childList")for(const f of s.addedNodes)f.tagName==="LINK"&&f.rel==="modulepreload"&&o(f)}).observe(document,{childList:!0,subtree:!0});function n(r){const s={};return r.integrity&&(s.integrity=r.integrity),r.referrerPolicy&&(s.referrerPolicy=r.referrerPolicy),r.crossOrigin==="use-credentials"?s.credentials="include":r.crossOrigin==="anonymous"?s.credentials="omit":s.credentials="same-origin",s}function o(r){if(r.ep)return;r.ep=!0;const s=n(r);fetch(r.href,s)}})();function w(){}function re(e){return e()}function X(){return Object.create(null)}function T(e){e.forEach(re)}function R(e){return typeof e=="function"}function Y(e,t){return e!=e?t==t:e!==t||e&&typeof e=="object"||typeof e=="function"}function le(e){return Object.keys(e).length===0}function d(e,t){e.appendChild(t)}function I(e,t,n){e.insertBefore(t,n||null)}function M(e){e.parentNode&&e.parentNode.removeChild(e)}function g(e){return document.createElement(e)}function F(e){return document.createTextNode(e)}function _(){return F(" ")}function K(e,t,n,o){return e.addEventListener(t,n,o),()=>e.removeEventListener(t,n,o)}function p(e,t,n){n==null?e.removeAttribute(t):e.getAttribute(t)!==n&&e.setAttribute(t,n)}function fe(e){return Array.from(e.childNodes)}function U(e,t){t=""+t,e.data!==t&&(e.data=t)}function Z(e,t,n){e.classList.toggle(t,!!n)}let L;function x(e){L=e}function ce(){if(!L)throw new Error("Function called outside component initialization");return L}function ue(e){ce().$$.on_mount.push(e)}const $=[],ee=[];let k=[];const te=[],ae=Promise.resolve();let V=!1;function de(){V||(V=!0,ae.then(oe))}function W(e){k.push(e)}const B=new Set;let v=0;function oe(){if(v!==0)return;const e=L;do{try{for(;v<$.length;){const t=$[v];v++,x(t),he(t.$$)}}catch(t){throw $.length=0,v=0,t}for(x(null),$.length=0,v=0;ee.length;)ee.pop()();for(let t=0;t<k.length;t+=1){const n=k[t];B.has(n)||(B.add(n),n())}k.length=0}while($.length);for(;te.length;)te.pop()();V=!1,B.clear(),x(e)}function he(e){if(e.fragment!==null){e.update(),T(e.before_update);const t=e.dirty;e.dirty=[-1],e.fragment&&e.fragment.p(e.ctx,t),e.after_update.forEach(W)}}function pe(e){const t=[],n=[];k.forEach(o=>e.indexOf(o)===-1?t.push(o):n.push(o)),n.forEach(o=>o()),k=t}const P=new Set;let ge;function O(e,t){e&&e.i&&(P.delete(e),e.i(t))}function N(e,t,n,o){if(e&&e.o){if(P.has(e))return;P.add(e),ge.c.push(()=>{P.delete(e)}),e.o(t)}}function A(e){e&&e.c()}function E(e,t,n){const{fragment:o,after_update:r}=e.$$;o&&o.m(t,n),W(()=>{const s=e.$$.on_mount.map(re).filter(R);e.$$.on_destroy?e.$$.on_destroy.push(...s):T(s),e.$$.on_mount=[]}),r.forEach(W)}function C(e,t){const n=e.$$;n.fragment!==null&&(pe(n.after_update),T(n.on_destroy),n.fragment&&n.fragment.d(t),n.on_destroy=n.fragment=null,n.ctx=[])}function me(e,t){e.$$.dirty[0]===-1&&($.push(e),de(),e.$$.dirty.fill(0)),e.$$.dirty[t/31|0]|=1<<t%31}function G(e,t,n,o,r,s,f=null,h=[-1]){const l=L;x(e);const i=e.$$={fragment:null,ctx:[],props:s,update:w,not_equal:r,bound:X(),on_mount:[],on_destroy:[],on_disconnect:[],before_update:[],after_update:[],context:new Map(t.context||(l?l.$$.context:[])),callbacks:X(),dirty:h,skip_bound:!1,root:t.target||l.$$.root};f&&f(i.root);let u=!1;if(i.ctx=n?n(e,t.props||{},(c,m,...b)=>{const S=b.length?b[0]:m;return i.ctx&&r(i.ctx[c],i.ctx[c]=S)&&(!i.skip_bound&&i.bound[c]&&i.bound[c](S),u&&me(e,c)),m}):[],i.update(),u=!0,T(i.before_update),i.fragment=o?o(i.ctx):!1,t.target){if(t.hydrate){const c=fe(t.target);i.fragment&&i.fragment.l(c),c.forEach(M)}else i.fragment&&i.fragment.c();t.intro&&O(e.$$.fragment),E(e,t.target,t.anchor),oe()}x(l)}class J{constructor(){z(this,"$$");z(this,"$$set")}$destroy(){C(this,1),this.$destroy=w}$on(t,n){if(!R(n))return w;const o=this.$$.callbacks[t]||(this.$$.callbacks[t]=[]);return o.push(n),()=>{const r=o.indexOf(n);r!==-1&&o.splice(r,1)}}$set(t){this.$$set&&!le(t)&&(this.$$.skip_bound=!0,this.$$set(t),this.$$.skip_bound=!1)}}const ye="4";typeof window<"u"&&(window.__svelte||(window.__svelte={v:new Set})).v.add(ye);function _e(e){let t,n,o,r,s,f,h,l,i;return{c(){t=g("div"),n=g("span"),n.innerHTML=`<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 64 64" style="display:block;border-radius:4px"><rect width="64" height="64" rx="14" fill="#0d9488"></rect><rect x="10" y="38" width="12" height="16" rx="3" fill="white"></rect><rect x="26" y="26" width="12" height="28" rx="3" fill="white"></rect><rect x="42" y="14" width="12" height="40" rx="3" fill="white"></rect></svg>
2
+ aiusage`,o=_(),r=g("div"),s=g("button"),s.textContent="↻",f=_(),h=g("button"),h.textContent="✕",p(n,"class","logo svelte-soepgf"),p(s,"class","icon-btn svelte-soepgf"),p(s,"title","Refresh"),p(h,"class","icon-btn svelte-soepgf"),p(h,"title","Close"),p(r,"class","actions svelte-soepgf"),p(t,"class","header svelte-soepgf")},m(u,c){I(u,t,c),d(t,n),d(t,o),d(t,r),d(r,s),d(r,f),d(r,h),l||(i=[K(s,"click",function(){R(e[0])&&e[0].apply(this,arguments)}),K(h,"click",function(){R(e[1])&&e[1].apply(this,arguments)})],l=!0)},p(u,[c]){e=u},i:w,o:w,d(u){u&&M(t),l=!1,T(i)}}}function we(e,t,n){let{onRefresh:o}=t,{onClose:r}=t;return e.$$set=s=>{"onRefresh"in s&&n(0,o=s.onRefresh),"onClose"in s&&n(1,r=s.onClose)},[o,r]}class be extends J{constructor(t){super(),G(this,t,we,_e,Y,{onRefresh:0,onClose:1})}}function ne(e){let t,n;return{c(){t=g("span"),n=F(e[2]),p(t,"class","secondary svelte-savwyt")},m(o,r){I(o,t,r),d(t,n)},p(o,r){r&4&&U(n,o[2])},d(o){o&&M(t)}}}function ve(e){let t,n,o,r,s,f,h,l,i=e[2]&&ne(e);return{c(){t=g("div"),n=g("div"),o=F(e[0]),r=_(),s=g("div"),f=g("span"),h=F(e[1]),l=_(),i&&i.c(),p(n,"class","section-label svelte-savwyt"),p(f,"class","primary svelte-savwyt"),p(s,"class","values svelte-savwyt"),p(t,"class","section svelte-savwyt")},m(u,c){I(u,t,c),d(t,n),d(n,o),d(t,r),d(t,s),d(s,f),d(f,h),d(s,l),i&&i.m(s,null)},p(u,[c]){c&1&&U(o,u[0]),c&2&&U(h,u[1]),u[2]?i?i.p(u,c):(i=ne(u),i.c(),i.m(s,null)):i&&(i.d(1),i=null)},i:w,o:w,d(u){u&&M(t),i&&i.d()}}}function $e(e,t,n){let{label:o}=t,{primary:r}=t,{secondary:s=""}=t;return e.$$set=f=>{"label"in f&&n(0,o=f.label),"primary"in f&&n(1,r=f.primary),"secondary"in f&&n(2,s=f.secondary)},[o,r,s]}class H extends J{constructor(t){super(),G(this,t,$e,ve,Y,{label:0,primary:1,secondary:2})}}function ke(e){let t,n,o,r,s,f,h,l,i,u,c,m,b,S;return n=new be({props:{onRefresh:e[6],onClose:Se}}),r=new H({props:{label:"TODAY",primary:e[5],secondary:e[4]}}),f=new H({props:{label:"THIS MONTH",primary:e[3]}}),l=new H({props:{label:"TOP MODEL",primary:e[2],secondary:e[1]}}),{c(){t=g("div"),A(n.$$.fragment),o=_(),A(r.$$.fragment),s=_(),A(f.$$.fragment),h=_(),A(l.$$.fragment),i=_(),u=g("div"),c=g("button"),c.textContent="Open Full Dashboard →",p(c,"class","open-btn svelte-z2p4qk"),p(u,"class","footer svelte-z2p4qk"),p(t,"class","panel svelte-z2p4qk"),Z(t,"loading",e[0])},m(a,y){I(a,t,y),E(n,t,null),d(t,o),E(r,t,null),d(t,s),E(f,t,null),d(t,h),E(l,t,null),d(t,i),d(t,u),d(u,c),m=!0,b||(S=K(c,"click",Oe),b=!0)},p(a,[y]){const j={};y&32&&(j.primary=a[5]),y&16&&(j.secondary=a[4]),r.$set(j);const Q={};y&8&&(Q.primary=a[3]),f.$set(Q);const q={};y&4&&(q.primary=a[2]),y&2&&(q.secondary=a[1]),l.$set(q),(!m||y&1)&&Z(t,"loading",a[0])},i(a){m||(O(n.$$.fragment,a),O(r.$$.fragment,a),O(f.$$.fragment,a),O(l.$$.fragment,a),m=!0)},o(a){N(n.$$.fragment,a),N(r.$$.fragment,a),N(f.$$.fragment,a),N(l.$$.fragment,a),m=!1},d(a){a&&M(t),C(n),C(r),C(f),C(l),b=!1,S()}}}function D(e){return e>=1e6?`${(e/1e6).toFixed(1)}M`:e>=1e3?`${(e/1e3).toFixed(1)}K`:String(e)}function Se(){window.widget.hideWindow()}async function Oe(){await window.widget.openDashboard()}function Ee(e,t,n){let o,r,s,f,h,l=null,i=!0;async function u(){n(0,i=!0),n(7,l=await window.widget.getData()),n(0,i=!1)}return ue(()=>{u(),window.widget.onDataUpdate(c=>{n(7,l=c),n(0,i=!1)})}),e.$$.update=()=>{var c;e.$$.dirty&128&&n(5,o=l?D(l.todayTokens.total):"—"),e.$$.dirty&128&&n(4,r=l?`↑${D(l.todayTokens.input)} ↓${D(l.todayTokens.output)}`:""),e.$$.dirty&128&&n(3,s=l?D(l.monthTokens.total):"—"),e.$$.dirty&128&&n(2,f=((c=l==null?void 0:l.topModel)==null?void 0:c.name)??"—"),e.$$.dirty&128&&n(1,h=l!=null&&l.topModel?`${l.topModel.share}%`:"")},[i,h,f,s,r,o,u,l]}class Ce extends J{constructor(t){super(),G(this,t,Ee,ke,Y,{})}}new Ce({target:document.getElementById("app")});
@@ -0,0 +1 @@
1
+ .header.svelte-soepgf{display:flex;align-items:center;justify-content:space-between;padding:12px 14px 10px;border-bottom:1px solid var(--border);-webkit-app-region:drag}.logo.svelte-soepgf{display:flex;align-items:center;gap:6px;font-size:13px;font-weight:600;color:var(--text-primary);letter-spacing:.01em}.actions.svelte-soepgf{display:flex;gap:4px;-webkit-app-region:no-drag}.icon-btn.svelte-soepgf{width:24px;height:24px;border:none;border-radius:4px;background:transparent;color:var(--text-muted);cursor:pointer;font-size:13px;display:flex;align-items:center;justify-content:center;transition:background .1s,color .1s;padding:0}.icon-btn.svelte-soepgf:hover{background:var(--bg-hover);color:var(--text-primary)}.section.svelte-savwyt{padding:12px 14px;border-bottom:1px solid var(--border)}.section-label.svelte-savwyt{font-size:10px;font-weight:700;letter-spacing:.08em;color:var(--text-muted);text-transform:uppercase;margin-bottom:5px}.values.svelte-savwyt{display:flex;align-items:baseline;gap:8px}.primary.svelte-savwyt{font-size:16px;font-weight:600;color:var(--text-primary);font-variant-numeric:tabular-nums}.secondary.svelte-savwyt{font-size:11px;color:var(--text-muted);font-variant-numeric:tabular-nums}*{box-sizing:border-box;margin:0;padding:0}body{background:transparent;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;-webkit-font-smoothing:antialiased}:root{--bg:#1a1a1f;--bg-hover:rgba(255, 255, 255, .06);--border:rgba(255, 255, 255, .08);--text-primary:#f0f0f2;--text-muted:rgba(240, 240, 242, .45);--accent:#6c8eff}@media (prefers-color-scheme: light){:root{--bg:#ffffff;--bg-hover:rgba(0, 0, 0, .05);--border:rgba(0, 0, 0, .08);--text-primary:#0f0f12;--text-muted:rgba(15, 15, 18, .45);--accent:#3b5bdb}}.panel.svelte-z2p4qk{background:var(--bg);border-radius:12px;border:1px solid var(--border);overflow:hidden;width:320px;box-shadow:0 8px 32px #0000004d,0 2px 8px #0003;transition:opacity .15s}.panel.loading.svelte-z2p4qk{opacity:.7}.footer.svelte-z2p4qk{padding:10px 14px 14px}.open-btn.svelte-z2p4qk{width:100%;padding:9px 14px;border:1px solid var(--accent);border-radius:7px;background:transparent;color:var(--accent);font-size:12px;font-weight:600;cursor:pointer;transition:background .15s;letter-spacing:.01em}.open-btn.svelte-z2p4qk:hover{background:#6c8eff1a}
@@ -5,8 +5,8 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'" />
7
7
  <title>aiusage Widget</title>
8
- <script type="module" crossorigin src="./assets/index-Bb9mog0W.js"></script>
9
- <link rel="stylesheet" crossorigin href="./assets/index-2X4hbwJe.css">
8
+ <script type="module" crossorigin src="./assets/index-CArY3S1D.js"></script>
9
+ <link rel="stylesheet" crossorigin href="./assets/index-D6oVYB8t.css">
10
10
  </head>
11
11
  <body>
12
12
  <div id="app"></div>
package/dist/ui.js CHANGED
@@ -3,19 +3,26 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.shouldShowWindowOnLaunch = shouldShowWindowOnLaunch;
4
4
  exports.shouldHideWindowOnBlur = shouldHideWindowOnBlur;
5
5
  exports.shouldHideWindowOnClose = shouldHideWindowOnClose;
6
- exports.getTrayIconDataUrl = getTrayIconDataUrl;
7
- const TRAY_ICON_SVG = `
8
- <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
9
- <rect x="1" y="1" width="14" height="14" rx="4" fill="#111827"/>
10
- <path d="M8.8 2.5 4.7 8.2h2.9L7 13.5l4.3-5.9H8.4l.4-5.1Z" fill="#f8fafc"/>
11
- </svg>
12
- `.trim();
13
- // Pre-rendered 32x32 PNG of the same icon — Windows tray doesn't support SVG
14
- const TRAY_ICON_PNG_BASE64 = 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAyUlEQVR4nMWXMQ6DMAxFzRcX6NYu' +
15
- 'XTtw/6N06NqFbhyhVYYsQUkT+zt+ExLI7zsCJ4gEs7RuXq6PL0NyfF5Vz+Ip7gmCWfJabcyS1xxg' +
16
- 'yPf3Ux0CWqlWXoIy0SyyE5HdmwIw5OoApfx23+YGYIKopVcF2MnyoQAe8sTKKFIL1/NywiJo0ftl' +
17
- 'rJZioYOoxchcgJAZHUqQYMAsphnJ0MpY+wEkGDCKmHfDo3Fu95JnJyQY5AvNKli7T5yk3gfUslH8e' +
18
- '8BTngj/OQ3nB+9vTnl87+2CAAAAAElFTkSuQmCC';
6
+ exports.getWindowPosition = getWindowPosition;
7
+ exports.getWidgetNativeBindingPath = getWidgetNativeBindingPath;
8
+ exports.getTrayIconNativeImage = getTrayIconNativeImage;
9
+ const node_path_1 = require("node:path");
10
+ // macOS: 32x32 PNG rendered at @2x — displayed as 16x16 logical on Retina via scaleFactor:2
11
+ const TRAY_ICON_PNG_MAC_BASE64 = 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAsklEQVR4nO2XQQ7EIAhFuQBX8HQe' +
12
+ 'hu7Z9U6z8TZu2jSxjekwYxpUuoCEjRr+EzEBgMqQKSDTgkwJmTIybZ08l5hH7ACSIVPsLPoPJkri' +
13
+ 'o4XvHuu0z7i5lIkA5V1mi5++QCkOK4AERum/ngFGBF7TZ7vbsSadHQLwyxzAAboBtKp8OEBLwAEc' +
14
+ 'QA2grXI1gFbAARzgKcBXSzYRIItNaesbavcrT69oy20HE/PR7BXDqeV4vgPnux87hsqGswAAAABJ' +
15
+ 'RU5ErkJggg==';
16
+ // Windows: 16x16 PNG
17
+ const TRAY_ICON_PNG_WIN_BASE64 = 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAaElEQVR4nGNgYGBg4J3Skco7peMa' +
18
+ '75SO/0RikNpUBiTNxGpEx6kMJNqM4RIGYhVbr5j/v+3UETAGsWHiRBsA0ggDIDbtDUB3MskGoGug' +
19
+ 'vQGEnEzQAEIaBrcB17CFASE+clKmLDNRmp0B5XqLc//RXPMAAAAASUVORK5CYII=';
20
+ // Linux: 22x22 PNG
21
+ const TRAY_ICON_PNG_LINUX_BASE64 = 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAAt0lEQVR4nGNggALeKR3ZvFM6zvJO' +
22
+ '6fjDO6XjP4n4D1RvNgMy4J3SsYAMw3DhBcgupZahMJzNAPUCtQ0+y0BmmIKx1Yp5cIwe5gzkGtp+' +
23
+ '6sh/ZADiI8uTbfDUC6dRDAbxB5fBMrP7wZiqBt//+B5uAIhNFYNBrkQHILFhbnDuvu3/P/z4AccQ' +
24
+ 'PlUMxqZ4ZBn8hwYG/0EpNk2WzgYrgGEQHyRefXQfXAzExqcWis/SrqCnWdVEq8oUAE+RyDWaecD7' +
25
+ 'AAAAAElFTkSuQmCC';
19
26
  function shouldShowWindowOnLaunch(isPackaged) {
20
27
  return !isPackaged;
21
28
  }
@@ -25,10 +32,28 @@ function shouldHideWindowOnBlur(isPackaged) {
25
32
  function shouldHideWindowOnClose(_) {
26
33
  return true;
27
34
  }
28
- function getTrayIconDataUrl() {
29
- // Windows tray doesn't render SVG icons use pre-rendered PNG
30
- if (process.platform === 'win32') {
31
- return `data:image/png;base64,${TRAY_ICON_PNG_BASE64}`;
35
+ function getWindowPosition({ platform, trayBounds, windowBounds, displayBounds, }) {
36
+ const preferredX = Math.round(trayBounds.x + trayBounds.width / 2 - windowBounds.width / 2);
37
+ const preferredY = platform === 'darwin'
38
+ ? trayBounds.y + trayBounds.height + 4
39
+ : trayBounds.y - windowBounds.height - 4;
40
+ const maxX = Math.max(displayBounds.x, displayBounds.x + displayBounds.width - windowBounds.width);
41
+ const maxY = Math.max(displayBounds.y, displayBounds.y + displayBounds.height - windowBounds.height);
42
+ return {
43
+ x: Math.min(Math.max(preferredX, displayBounds.x), maxX),
44
+ y: Math.min(Math.max(preferredY, displayBounds.y), maxY),
45
+ };
46
+ }
47
+ function getWidgetNativeBindingPath(baseDir) {
48
+ return (0, node_path_1.join)(baseDir, 'native', 'better_sqlite3.node');
49
+ }
50
+ function getTrayIconNativeImage() {
51
+ if (process.platform === 'darwin') {
52
+ // 32x32 PNG at scaleFactor 2 = renders as 16x16 logical, sharp on Retina
53
+ return { buffer: Buffer.from(TRAY_ICON_PNG_MAC_BASE64, 'base64'), scaleFactor: 2 };
54
+ }
55
+ if (process.platform === 'linux') {
56
+ return { buffer: Buffer.from(TRAY_ICON_PNG_LINUX_BASE64, 'base64') };
32
57
  }
33
- return `data:image/svg+xml;base64,${Buffer.from(TRAY_ICON_SVG).toString('base64')}`;
58
+ return { buffer: Buffer.from(TRAY_ICON_PNG_WIN_BASE64, 'base64') };
34
59
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juliantanx/aiusage-widget",
3
- "version": "1.3.2",
3
+ "version": "1.3.4",
4
4
  "private": false,
5
5
  "description": "System tray widget for aiusage — view AI token usage from your system tray",
6
6
  "keywords": [
@@ -22,7 +22,7 @@
22
22
  },
23
23
  "license": "MIT",
24
24
  "engines": {
25
- "node": ">=18"
25
+ "node": ">=20"
26
26
  },
27
27
  "main": "dist/main.js",
28
28
  "files": [
@@ -35,10 +35,11 @@
35
35
  "aiusage-widget": "bin/launcher.js"
36
36
  },
37
37
  "dependencies": {
38
- "better-sqlite3": "^11.0.0"
38
+ "better-sqlite3": "^12.0.0",
39
+ "electron": "^33.0.0"
39
40
  },
40
41
  "devDependencies": {
41
- "electron": "^33.0.0",
42
+ "@electron/rebuild": "^3.6.1",
42
43
  "@sveltejs/vite-plugin-svelte": "^3.0.0",
43
44
  "@types/better-sqlite3": "*",
44
45
  "@types/node": "*",
@@ -51,11 +52,13 @@
51
52
  "wait-on": "^7.0.0"
52
53
  },
53
54
  "scripts": {
55
+ "postinstall": "node bin/install-native.js",
54
56
  "rebuild": "pnpm run rebuild:electron",
55
- "rebuild:electron": "node -e \"const {execSync}=require('child_process'); const electronVersion=require('electron/package.json').version; const cmd='npm rebuild better-sqlite3 --runtime=electron --target=' + electronVersion + ' --dist-url=https://electronjs.org/headers'; execSync(cmd, {stdio:'inherit'})\"",
57
+ "rebuild:electron": "node -e \"const {rebuild}=require('@electron/rebuild');const v=require('electron/package.json').version;rebuild({buildPath:process.cwd(),electronVersion:v,onlyModules:['better-sqlite3'],force:true}).then(()=>process.exit(0)).catch(e=>{console.error(e);process.exit(1)})\"",
58
+ "prepare:native": "node bin/prepare-native.js",
56
59
  "rebuild:node": "npm rebuild better-sqlite3",
57
- "dev": "pnpm run rebuild:electron && concurrently --names \"vite,tsc,electron\" --kill-others --success command-electron \"vite build --watch\" \"tsc -p tsconfig.json --watch\" \"pnpm exec wait-on dist/main.js && pnpm exec electron .\"",
58
- "build": "rm -rf dist/renderer && vite build && tsc -p tsconfig.json",
60
+ "dev": "pnpm run prepare:native && concurrently --names \"vite,tsc,electron\" --kill-others --success command-electron \"vite build --watch\" \"tsc -p tsconfig.json --watch\" \"node -e \\\"require('wait-on')({resources:['dist/main.js']},()=>{const c=require('child_process').spawn(require('electron'),['.'],{stdio:'inherit'});c.on('exit',(code,signal)=>process.exit(code ?? (signal ? 1 : 0)))})\\\"\"",
61
+ "build": "rm -rf dist/renderer && vite build && tsc -p tsconfig.json && pnpm run prepare:native",
59
62
  "pack": "pnpm build && electron-builder",
60
63
  "test": "pnpm run rebuild:node && vitest run"
61
64
  }
@@ -1 +0,0 @@
1
- .header.svelte-14gtt2i{display:flex;align-items:center;justify-content:space-between;padding:12px 14px 10px;border-bottom:1px solid var(--border);-webkit-app-region:drag}.logo.svelte-14gtt2i{font-size:13px;font-weight:600;color:var(--text-primary);letter-spacing:.01em}.actions.svelte-14gtt2i{display:flex;gap:4px;-webkit-app-region:no-drag}.icon-btn.svelte-14gtt2i{width:24px;height:24px;border:none;border-radius:4px;background:transparent;color:var(--text-muted);cursor:pointer;font-size:13px;display:flex;align-items:center;justify-content:center;transition:background .1s,color .1s;padding:0}.icon-btn.svelte-14gtt2i:hover{background:var(--bg-hover);color:var(--text-primary)}.section.svelte-savwyt{padding:12px 14px;border-bottom:1px solid var(--border)}.section-label.svelte-savwyt{font-size:10px;font-weight:700;letter-spacing:.08em;color:var(--text-muted);text-transform:uppercase;margin-bottom:5px}.values.svelte-savwyt{display:flex;align-items:baseline;gap:8px}.primary.svelte-savwyt{font-size:16px;font-weight:600;color:var(--text-primary);font-variant-numeric:tabular-nums}.secondary.svelte-savwyt{font-size:11px;color:var(--text-muted);font-variant-numeric:tabular-nums}*{box-sizing:border-box;margin:0;padding:0}body{background:transparent;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;-webkit-font-smoothing:antialiased}:root{--bg:#1a1a1f;--bg-hover:rgba(255, 255, 255, .06);--border:rgba(255, 255, 255, .08);--text-primary:#f0f0f2;--text-muted:rgba(240, 240, 242, .45);--accent:#6c8eff}@media (prefers-color-scheme: light){:root{--bg:#ffffff;--bg-hover:rgba(0, 0, 0, .05);--border:rgba(0, 0, 0, .08);--text-primary:#0f0f12;--text-muted:rgba(15, 15, 18, .45);--accent:#3b5bdb}}.panel.svelte-z2p4qk{background:var(--bg);border-radius:12px;border:1px solid var(--border);overflow:hidden;width:320px;box-shadow:0 8px 32px #0000004d,0 2px 8px #0003;transition:opacity .15s}.panel.loading.svelte-z2p4qk{opacity:.7}.footer.svelte-z2p4qk{padding:10px 14px 14px}.open-btn.svelte-z2p4qk{width:100%;padding:9px 14px;border:1px solid var(--accent);border-radius:7px;background:transparent;color:var(--accent);font-size:12px;font-weight:600;cursor:pointer;transition:background .15s;letter-spacing:.01em}.open-btn.svelte-z2p4qk:hover{background:#6c8eff1a}
@@ -1 +0,0 @@
1
- var se=Object.defineProperty;var ie=(e,t,n)=>t in e?se(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var x=(e,t,n)=>ie(e,typeof t!="symbol"?t+"":t,n);(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const r of document.querySelectorAll('link[rel="modulepreload"]'))o(r);new MutationObserver(r=>{for(const s of r)if(s.type==="childList")for(const u of s.addedNodes)u.tagName==="LINK"&&u.rel==="modulepreload"&&o(u)}).observe(document,{childList:!0,subtree:!0});function n(r){const s={};return r.integrity&&(s.integrity=r.integrity),r.referrerPolicy&&(s.referrerPolicy=r.referrerPolicy),r.crossOrigin==="use-credentials"?s.credentials="include":r.crossOrigin==="anonymous"?s.credentials="omit":s.credentials="same-origin",s}function o(r){if(r.ep)return;r.ep=!0;const s=n(r);fetch(r.href,s)}})();function w(){}function re(e){return e()}function X(){return Object.create(null)}function M(e){e.forEach(re)}function F(e){return typeof e=="function"}function Y(e,t){return e!=e?t==t:e!==t||e&&typeof e=="object"||typeof e=="function"}function le(e){return Object.keys(e).length===0}function d(e,t){e.appendChild(t)}function j(e,t,n){e.insertBefore(t,n||null)}function N(e){e.parentNode&&e.parentNode.removeChild(e)}function h(e){return document.createElement(e)}function I(e){return document.createTextNode(e)}function _(){return I(" ")}function K(e,t,n,o){return e.addEventListener(t,n,o),()=>e.removeEventListener(t,n,o)}function p(e,t,n){n==null?e.removeAttribute(t):e.getAttribute(t)!==n&&e.setAttribute(t,n)}function ue(e){return Array.from(e.childNodes)}function U(e,t){t=""+t,e.data!==t&&(e.data=t)}function Z(e,t,n){e.classList.toggle(t,!!n)}let T;function L(e){T=e}function ae(){if(!T)throw new Error("Function called outside component initialization");return T}function fe(e){ae().$$.on_mount.push(e)}const v=[],ee=[];let S=[];const te=[],ce=Promise.resolve();let V=!1;function de(){V||(V=!0,ce.then(oe))}function W(e){S.push(e)}const B=new Set;let $=0;function oe(){if($!==0)return;const e=T;do{try{for(;$<v.length;){const t=v[$];$++,L(t),me(t.$$)}}catch(t){throw v.length=0,$=0,t}for(L(null),v.length=0,$=0;ee.length;)ee.pop()();for(let t=0;t<S.length;t+=1){const n=S[t];B.has(n)||(B.add(n),n())}S.length=0}while(v.length);for(;te.length;)te.pop()();V=!1,B.clear(),L(e)}function me(e){if(e.fragment!==null){e.update(),M(e.before_update);const t=e.dirty;e.dirty=[-1],e.fragment&&e.fragment.p(e.ctx,t),e.after_update.forEach(W)}}function pe(e){const t=[],n=[];S.forEach(o=>e.indexOf(o)===-1?t.push(o):n.push(o)),n.forEach(o=>o()),S=t}const R=new Set;let he;function O(e,t){e&&e.i&&(R.delete(e),e.i(t))}function A(e,t,n,o){if(e&&e.o){if(R.has(e))return;R.add(e),he.c.push(()=>{R.delete(e)}),e.o(t)}}function D(e){e&&e.c()}function C(e,t,n){const{fragment:o,after_update:r}=e.$$;o&&o.m(t,n),W(()=>{const s=e.$$.on_mount.map(re).filter(F);e.$$.on_destroy?e.$$.on_destroy.push(...s):M(s),e.$$.on_mount=[]}),r.forEach(W)}function E(e,t){const n=e.$$;n.fragment!==null&&(pe(n.after_update),M(n.on_destroy),n.fragment&&n.fragment.d(t),n.on_destroy=n.fragment=null,n.ctx=[])}function ge(e,t){e.$$.dirty[0]===-1&&(v.push(e),de(),e.$$.dirty.fill(0)),e.$$.dirty[t/31|0]|=1<<t%31}function G(e,t,n,o,r,s,u=null,m=[-1]){const l=T;L(e);const i=e.$$={fragment:null,ctx:[],props:s,update:w,not_equal:r,bound:X(),on_mount:[],on_destroy:[],on_disconnect:[],before_update:[],after_update:[],context:new Map(t.context||(l?l.$$.context:[])),callbacks:X(),dirty:m,skip_bound:!1,root:t.target||l.$$.root};u&&u(i.root);let f=!1;if(i.ctx=n?n(e,t.props||{},(a,g,...b)=>{const k=b.length?b[0]:g;return i.ctx&&r(i.ctx[a],i.ctx[a]=k)&&(!i.skip_bound&&i.bound[a]&&i.bound[a](k),f&&ge(e,a)),g}):[],i.update(),f=!0,M(i.before_update),i.fragment=o?o(i.ctx):!1,t.target){if(t.hydrate){const a=ue(t.target);i.fragment&&i.fragment.l(a),a.forEach(N)}else i.fragment&&i.fragment.c();t.intro&&O(e.$$.fragment),C(e,t.target,t.anchor),oe()}L(l)}class J{constructor(){x(this,"$$");x(this,"$$set")}$destroy(){E(this,1),this.$destroy=w}$on(t,n){if(!F(n))return w;const o=this.$$.callbacks[t]||(this.$$.callbacks[t]=[]);return o.push(n),()=>{const r=o.indexOf(n);r!==-1&&o.splice(r,1)}}$set(t){this.$$set&&!le(t)&&(this.$$.skip_bound=!0,this.$$set(t),this.$$.skip_bound=!1)}}const ye="4";typeof window<"u"&&(window.__svelte||(window.__svelte={v:new Set})).v.add(ye);function _e(e){let t,n,o,r,s,u,m,l,i;return{c(){t=h("div"),n=h("span"),n.textContent="⚡ aiusage",o=_(),r=h("div"),s=h("button"),s.textContent="↻",u=_(),m=h("button"),m.textContent="✕",p(n,"class","logo svelte-14gtt2i"),p(s,"class","icon-btn svelte-14gtt2i"),p(s,"title","Refresh"),p(m,"class","icon-btn svelte-14gtt2i"),p(m,"title","Close"),p(r,"class","actions svelte-14gtt2i"),p(t,"class","header svelte-14gtt2i")},m(f,a){j(f,t,a),d(t,n),d(t,o),d(t,r),d(r,s),d(r,u),d(r,m),l||(i=[K(s,"click",function(){F(e[0])&&e[0].apply(this,arguments)}),K(m,"click",function(){F(e[1])&&e[1].apply(this,arguments)})],l=!0)},p(f,[a]){e=f},i:w,o:w,d(f){f&&N(t),l=!1,M(i)}}}function we(e,t,n){let{onRefresh:o}=t,{onClose:r}=t;return e.$$set=s=>{"onRefresh"in s&&n(0,o=s.onRefresh),"onClose"in s&&n(1,r=s.onClose)},[o,r]}class be extends J{constructor(t){super(),G(this,t,we,_e,Y,{onRefresh:0,onClose:1})}}function ne(e){let t,n;return{c(){t=h("span"),n=I(e[2]),p(t,"class","secondary svelte-savwyt")},m(o,r){j(o,t,r),d(t,n)},p(o,r){r&4&&U(n,o[2])},d(o){o&&N(t)}}}function $e(e){let t,n,o,r,s,u,m,l,i=e[2]&&ne(e);return{c(){t=h("div"),n=h("div"),o=I(e[0]),r=_(),s=h("div"),u=h("span"),m=I(e[1]),l=_(),i&&i.c(),p(n,"class","section-label svelte-savwyt"),p(u,"class","primary svelte-savwyt"),p(s,"class","values svelte-savwyt"),p(t,"class","section svelte-savwyt")},m(f,a){j(f,t,a),d(t,n),d(n,o),d(t,r),d(t,s),d(s,u),d(u,m),d(s,l),i&&i.m(s,null)},p(f,[a]){a&1&&U(o,f[0]),a&2&&U(m,f[1]),f[2]?i?i.p(f,a):(i=ne(f),i.c(),i.m(s,null)):i&&(i.d(1),i=null)},i:w,o:w,d(f){f&&N(t),i&&i.d()}}}function ve(e,t,n){let{label:o}=t,{primary:r}=t,{secondary:s=""}=t;return e.$$set=u=>{"label"in u&&n(0,o=u.label),"primary"in u&&n(1,r=u.primary),"secondary"in u&&n(2,s=u.secondary)},[o,r,s]}class H extends J{constructor(t){super(),G(this,t,ve,$e,Y,{label:0,primary:1,secondary:2})}}function Se(e){let t,n,o,r,s,u,m,l,i,f,a,g,b,k;return n=new be({props:{onRefresh:e[6],onClose:ke}}),r=new H({props:{label:"TODAY",primary:e[5],secondary:e[4]}}),u=new H({props:{label:"THIS MONTH",primary:e[3]}}),l=new H({props:{label:"TOP MODEL",primary:e[2],secondary:e[1]}}),{c(){t=h("div"),D(n.$$.fragment),o=_(),D(r.$$.fragment),s=_(),D(u.$$.fragment),m=_(),D(l.$$.fragment),i=_(),f=h("div"),a=h("button"),a.textContent="Open Full Dashboard →",p(a,"class","open-btn svelte-z2p4qk"),p(f,"class","footer svelte-z2p4qk"),p(t,"class","panel svelte-z2p4qk"),Z(t,"loading",e[0])},m(c,y){j(c,t,y),C(n,t,null),d(t,o),C(r,t,null),d(t,s),C(u,t,null),d(t,m),C(l,t,null),d(t,i),d(t,f),d(f,a),g=!0,b||(k=K(a,"click",Oe),b=!0)},p(c,[y]){const q={};y&32&&(q.primary=c[5]),y&16&&(q.secondary=c[4]),r.$set(q);const Q={};y&8&&(Q.primary=c[3]),u.$set(Q);const z={};y&4&&(z.primary=c[2]),y&2&&(z.secondary=c[1]),l.$set(z),(!g||y&1)&&Z(t,"loading",c[0])},i(c){g||(O(n.$$.fragment,c),O(r.$$.fragment,c),O(u.$$.fragment,c),O(l.$$.fragment,c),g=!0)},o(c){A(n.$$.fragment,c),A(r.$$.fragment,c),A(u.$$.fragment,c),A(l.$$.fragment,c),g=!1},d(c){c&&N(t),E(n),E(r),E(u),E(l),b=!1,k()}}}function P(e){return e>=1e6?`${(e/1e6).toFixed(1)}M`:e>=1e3?`${(e/1e3).toFixed(1)}K`:String(e)}function ke(){window.widget.hideWindow()}async function Oe(){await window.widget.openDashboard()}function Ce(e,t,n){let o,r,s,u,m,l=null,i=!0;async function f(){n(0,i=!0),n(7,l=await window.widget.getData()),n(0,i=!1)}return fe(()=>{f(),window.widget.onDataUpdate(a=>{n(7,l=a),n(0,i=!1)})}),e.$$.update=()=>{var a;e.$$.dirty&128&&n(5,o=l?P(l.todayTokens.total):"—"),e.$$.dirty&128&&n(4,r=l?`↑${P(l.todayTokens.input)} ↓${P(l.todayTokens.output)}`:""),e.$$.dirty&128&&n(3,s=l?P(l.monthTokens.total):"—"),e.$$.dirty&128&&n(2,u=((a=l==null?void 0:l.topModel)==null?void 0:a.name)??"—"),e.$$.dirty&128&&n(1,m=l!=null&&l.topModel?`${l.topModel.share}%`:"")},[i,m,u,s,r,o,f,l]}class Ee extends J{constructor(t){super(),G(this,t,Ce,Se,Y,{})}}new Ee({target:document.getElementById("app")});