Merge pull request 'feat: statusbar 在送出第一個提示詞前就顯示額度、ctx 與系統資源' (#25) from feat/statusbar-prefetch into main
Reviewed-on: https://gitea.jsc.idv.tw/jiantw83/jsc-marketplace/pulls/25
This commit was merged in pull request #25.
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "jsc-statusbar",
|
"name": "jsc-statusbar",
|
||||||
"version": "0.0.3",
|
"version": "0.0.4",
|
||||||
"description": "輸入框上方的單行狀態列:模型、目錄、分支、5h/7d 額度與重置、context、CPU/記憶體/磁碟",
|
"description": "輸入框上方的單行狀態列:模型、目錄、分支、5h/7d 額度與重置、context、CPU/記憶體/磁碟",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"types": "./types/index.d.ts",
|
"types": "./types/index.d.ts",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { atom, read, update } from 'claude-code'
|
import { atom, read, update } from 'claude-code'
|
||||||
import type { EngineInterface, Register, SessionContextUsage, SessionRateLimit } from 'claude-code'
|
import type { EngineInterface, Register, SessionContextUsage, SessionRateLimit } from 'claude-code'
|
||||||
|
|
||||||
import type { Mode, Sys, Usage } from '../types'
|
import type { Mode, Sys, Usage, Window } from '../types'
|
||||||
import { fit, cpuPercent, parseCpu, parseDf, parseGit, parseMem, parseOffset } from './format'
|
import { fit, cpuPercent, parseCpu, parseDf, parseGit, parseMem, parseOffset } from './format'
|
||||||
import type { CpuSample } from './format'
|
import type { CpuSample } from './format'
|
||||||
|
|
||||||
@@ -19,6 +19,7 @@ const ALERT_AT = 90
|
|||||||
const GIT_TOOLS = new Set(['Bash', 'Edit', 'Write', 'NotebookEdit'])
|
const GIT_TOOLS = new Set(['Bash', 'Edit', 'Write', 'NotebookEdit'])
|
||||||
const LABEL: Record<string, string> = { five_hour: '5 小時', seven_day: '7 天' }
|
const LABEL: Record<string, string> = { five_hour: '5 小時', seven_day: '7 天' }
|
||||||
|
|
||||||
|
// 引擎要等第一次 API 回應才有額度與 ctx;先前的額度存在 $.store,開新對話時先顯示,ctx 先當作 0
|
||||||
function toUsage(context: SessionContextUsage, rateLimits: SessionRateLimit[]): Usage {
|
function toUsage(context: SessionContextUsage, rateLimits: SessionRateLimit[]): Usage {
|
||||||
const win = (kind: string) => {
|
const win = (kind: string) => {
|
||||||
const r = rateLimits.find(x => x.kind === kind)
|
const r = rateLimits.find(x => x.kind === kind)
|
||||||
@@ -27,9 +28,25 @@ function toUsage(context: SessionContextUsage, rateLimits: SessionRateLimit[]):
|
|||||||
return {
|
return {
|
||||||
fiveHour: win('five_hour'),
|
fiveHour: win('five_hour'),
|
||||||
sevenDay: win('seven_day'),
|
sevenDay: win('seven_day'),
|
||||||
ctxTokens: context.tokens,
|
ctxTokens: context.tokens ?? 0,
|
||||||
ctxWindow: context.window,
|
ctxWindow: context.window,
|
||||||
ctxPercent: context.percent,
|
ctxPercent: context.percent ?? 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 已過重置時間的視窗用量已歸零,不再沿用舊值
|
||||||
|
const live = (w: Window | undefined, now: number) =>
|
||||||
|
w && (!w.resetsAt || Date.parse(w.resetsAt) > now) ? w : undefined
|
||||||
|
|
||||||
|
async function restoreRates($: EngineInterface, usage: Usage): Promise<Usage> {
|
||||||
|
const saved = (await $.store.get('rates')) as Pick<Usage, 'fiveHour' | 'sevenDay'> | undefined
|
||||||
|
if (!saved) return usage
|
||||||
|
const now = await $.clock.now()
|
||||||
|
|
||||||
|
return {
|
||||||
|
...usage,
|
||||||
|
fiveHour: usage.fiveHour ?? live(saved.fiveHour, now),
|
||||||
|
sevenDay: usage.sevenDay ?? live(saved.sevenDay, now),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,9 +121,11 @@ export const register: Register = on => {
|
|||||||
tzOffsetMin = parseOffset(r.stdout)
|
tzOffsetMin = parseOffset(r.stdout)
|
||||||
} catch {}
|
} catch {}
|
||||||
const u = await $.session.usage()
|
const u = await $.session.usage()
|
||||||
await update($, usageAtom, () => toUsage(u.context, u.rateLimits))
|
const usage = await restoreRates($, toUsage(u.context, u.rateLimits))
|
||||||
|
await update($, usageAtom, () => usage)
|
||||||
void refreshGit($)
|
void refreshGit($)
|
||||||
void refreshSys($)
|
// CPU 要兩次取樣才算得出來,開場先隔 0.5 秒補一次,免得等到 3 秒後才出現
|
||||||
|
void refreshSys($).then(() => $.clock.after(500, () => void refreshSys($)))
|
||||||
$.clock.every(SYS_MS, () => void refreshSys($))
|
$.clock.every(SYS_MS, () => void refreshSys($))
|
||||||
$.clock.every(GIT_MS, () => void refreshGit($))
|
$.clock.every(GIT_MS, () => void refreshGit($))
|
||||||
|
|
||||||
@@ -115,6 +134,11 @@ export const register: Register = on => {
|
|||||||
|
|
||||||
on('session.measure', async ($, e, next) => {
|
on('session.measure', async ($, e, next) => {
|
||||||
await update($, usageAtom, () => toUsage(e.context, e.rateLimits))
|
await update($, usageAtom, () => toUsage(e.context, e.rateLimits))
|
||||||
|
if (e.rateLimits.length) {
|
||||||
|
const w = (kind: string) => e.rateLimits.find(x => x.kind === kind)
|
||||||
|
const pick = (r: SessionRateLimit | undefined) => r && { percent: r.percentUsed, resetsAt: r.resetsAt }
|
||||||
|
await $.store.set('rates', { fiveHour: pick(w('five_hour')), sevenDay: pick(w('seven_day')) })
|
||||||
|
}
|
||||||
if (e.changed.includes('rateLimits')) await alert($, e.rateLimits)
|
if (e.changed.includes('rateLimits')) await alert($, e.rateLimits)
|
||||||
|
|
||||||
return next(e)
|
return next(e)
|
||||||
|
|||||||
Reference in New Issue
Block a user