@linxin666/dsh-usage 0.4.10 → 0.4.11

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.
@@ -16,9 +16,9 @@ export const zh = {
16
16
  'usage.refresh': '刷新',
17
17
  'usage.refreshing': '刷新中…',
18
18
  'usage.updated': '更新于 {time}',
19
- 'usage.loading': '正在加载用量数据…',
19
+ 'usage.loading': '正在读取用量…',
20
20
  'usage.error': '加载失败:{error}',
21
- 'usage.disabled': '插件已停用:勾选下方「启用插件」即可恢复统计。',
21
+ 'usage.disabled': '已停用,打开开关继续统计。',
22
22
  'usage.current': '当前',
23
23
  'usage.today': '今日用量',
24
24
  'usage.today.cost': '今日消费(估算)',
@@ -42,28 +42,26 @@ export const zh = {
42
42
  'usage.tokens.cacheRead': '缓存读',
43
43
  'usage.tokens.cacheWrite': '缓存写',
44
44
  'usage.trend': '近 30 天',
45
- 'usage.noData': '暂无用量数据(统计自插件启用起)',
45
+ 'usage.noData': '还没有用量,插件启用后开始统计。',
46
46
  'usage.balance': '余额',
47
- 'usage.balance.unsupported': '暂不支持余额查询',
47
+ 'usage.balance.unsupported': '不支持查询余额',
48
48
  'usage.balance.noCredential': '未配置凭据',
49
- 'usage.balance.noneConfigured': '没有已配置的提供方',
50
- 'usage.oauth': 'OAuth 凭据,不做余额查询',
49
+ 'usage.balance.noneConfigured': '还没有配置提供方',
50
+ 'usage.oauth': 'OAuth 凭据,不查余额',
51
51
  'usage.plan.reset': '{date} 重置',
52
- 'usage.plan.noPlan': '未检测到套餐数据',
53
- 'usage.plan.noneConfigured': '没有已配置的套餐类 provider(如 Kimi、GLM、OpenCode Go、MiniMax、Codex 订阅)',
52
+ 'usage.plan.noPlan': '没有读到套餐数据',
53
+ 'usage.plan.noneConfigured': '没有配置套餐类提供方,例如 Kimi、GLM、OpenCode Go、MiniMax、Codex 订阅。',
54
54
  'usage.plan.windows.5h': '5 小时',
55
55
  'usage.plan.windows.week': '每周',
56
56
  'usage.plan.windows.month': '每月',
57
57
  'usage.provider.error': '查询失败:{error}',
58
58
  'usage.errorListSeparator': ';',
59
59
  'usage.config.title': '设置',
60
- 'usage.config.enabled': '启用插件',
61
60
  'usage.config.pollIntervalSec': '轮询间隔(秒)',
62
- 'usage.config.spendCurrency': '消费显示货币',
63
- 'usage.config.cnyPerUsd': '汇率(1 美元兑人民币)',
64
- 'usage.config.saveFailed': '保存失败:设置未被接受。',
61
+ 'usage.config.spendCurrency': '货币',
62
+ 'usage.config.cnyPerUsd': '汇率',
65
63
  'usage.bank.title': '鲸元券',
66
- 'usage.bank.hint': '所有模型每消耗 100 万 tokens 铸造 1 鲸元;保存或分享这张票券。',
64
+ 'usage.bank.hint': '每用掉 100 万 tokens 铸造 1 鲸元,可以保存或分享这张票券。',
67
65
  'usage.bank.noUsage': '暂无用量数据',
68
66
  'usage.bank.minted': '累计铸造 {minted} 鲸元({tokens} tokens)',
69
67
  'usage.bank.spend.observed': '官方余额实测花费 {cost}(自 {since} 起)',
@@ -78,6 +76,19 @@ export const zh = {
78
76
  'usage.foot.open': '打开使用统计设置',
79
77
  'usage.foot.collapse': '收起用量卡片',
80
78
  'usage.foot.expand': '展开用量卡片',
79
+ 'usage.description': '各提供方的用量、余额与套餐额度。',
80
+ 'usage.config.pollIntervalHint': '多久查一次余额与套餐。',
81
+ 'usage.config.spendCurrencyHint': '消费金额用这种货币显示。',
82
+ 'usage.config.cnyPerUsdHint': '1 美元折合多少人民币。',
83
+ 'settings.collapse': '收起',
84
+ 'settings.expand': '展开',
85
+ 'settings.notExposed': '这个版本的 DSH 没有开放使用统计的设置。',
86
+ 'settings.readOnly': '设置只读。',
87
+ 'settings.saveFailed': '没有保存成功。',
88
+ 'settings.inherit': '默认',
89
+ 'settings.overridden': '已修改',
90
+ 'settings.reset': '恢复默认',
91
+ 'settings.invalidNumber': '填一个数字,留空用默认值。',
81
92
  }
82
93
 
83
94
  /** English mirror; every zh key present. */
@@ -89,9 +100,9 @@ export const en: Record<UsageKey, string> = {
89
100
  'usage.refresh': 'Refresh',
90
101
  'usage.refreshing': 'Refreshing…',
91
102
  'usage.updated': 'Updated {time}',
92
- 'usage.loading': 'Loading usage data…',
103
+ 'usage.loading': 'Reading usage…',
93
104
  'usage.error': 'Failed to load: {error}',
94
- 'usage.disabled': 'Plugin disabled. Tick "Enable plugin" below to resume statistics.',
105
+ 'usage.disabled': 'Turned off; flip the switch to resume.',
95
106
  'usage.current': 'Current',
96
107
  'usage.today': 'Today',
97
108
  'usage.today.cost': 'Today spend (estimated)',
@@ -115,28 +126,26 @@ export const en: Record<UsageKey, string> = {
115
126
  'usage.tokens.cacheRead': 'Cache read',
116
127
  'usage.tokens.cacheWrite': 'Cache write',
117
128
  'usage.trend': 'Last 30 days',
118
- 'usage.noData': 'No usage data yet (counting starts when the plugin is enabled)',
129
+ 'usage.noData': 'No usage yet; counting starts once the plugin is on.',
119
130
  'usage.balance': 'Balance',
120
- 'usage.balance.unsupported': 'Balance query not supported',
131
+ 'usage.balance.unsupported': 'No balance query',
121
132
  'usage.balance.noCredential': 'No credential configured',
122
133
  'usage.balance.noneConfigured': 'No providers configured',
123
134
  'usage.oauth': 'OAuth credential, no balance query',
124
135
  'usage.plan.reset': 'resets {date}',
125
- 'usage.plan.noPlan': 'No plan data detected',
126
- 'usage.plan.noneConfigured': 'No plan-capable provider configured (such as Kimi, GLM, OpenCode Go, MiniMax, Codex subscription)',
136
+ 'usage.plan.noPlan': 'No plan data',
137
+ 'usage.plan.noneConfigured': 'No plan provider configured, such as Kimi, GLM, OpenCode Go, MiniMax or a Codex subscription.',
127
138
  'usage.plan.windows.5h': '5 hours',
128
139
  'usage.plan.windows.week': 'Weekly',
129
140
  'usage.plan.windows.month': 'Monthly',
130
141
  'usage.provider.error': 'Query failed: {error}',
131
142
  'usage.errorListSeparator': '; ',
132
143
  'usage.config.title': 'Settings',
133
- 'usage.config.enabled': 'Enable plugin',
134
144
  'usage.config.pollIntervalSec': 'Poll interval (seconds)',
135
- 'usage.config.spendCurrency': 'Spend display currency',
136
- 'usage.config.cnyPerUsd': 'Exchange rate (CNY per USD)',
137
- 'usage.config.saveFailed': 'Save failed: the deployment did not accept the setting.',
145
+ 'usage.config.spendCurrency': 'Currency',
146
+ 'usage.config.cnyPerUsd': 'Exchange rate',
138
147
  'usage.bank.title': 'Whale-yuan voucher',
139
- 'usage.bank.hint': 'Every 1,000,000 tokens spent across all models mint one whale yuan; save or share the note.',
148
+ 'usage.bank.hint': 'Every million tokens mints one whale yuan; save or share the note.',
140
149
  'usage.bank.noUsage': 'No usage data yet',
141
150
  'usage.bank.minted': 'Minted {minted} whale yuan ({tokens} tokens)',
142
151
  'usage.bank.spend.observed': 'Spent {cost} observed on the official balance (watching since {since})',
@@ -151,6 +160,19 @@ export const en: Record<UsageKey, string> = {
151
160
  'usage.foot.open': 'Open usage statistics settings',
152
161
  'usage.foot.collapse': 'Collapse the usage card',
153
162
  'usage.foot.expand': 'Expand the usage card',
163
+ 'usage.description': 'Usage, balances and plan quotas for each provider.',
164
+ 'usage.config.pollIntervalHint': 'How often balances and plans are read.',
165
+ 'usage.config.spendCurrencyHint': 'Spend figures show in this currency.',
166
+ 'usage.config.cnyPerUsdHint': 'Yuan per US dollar.',
167
+ 'settings.collapse': 'Collapse',
168
+ 'settings.expand': 'Expand',
169
+ 'settings.notExposed': 'This DSH version does not open the usage settings.',
170
+ 'settings.readOnly': 'Settings are read-only.',
171
+ 'settings.saveFailed': 'Not saved.',
172
+ 'settings.inherit': 'Default',
173
+ 'settings.overridden': 'Changed',
174
+ 'settings.reset': 'Reset',
175
+ 'settings.invalidNumber': 'Enter a number, or leave it empty for the default.',
154
176
  }
155
177
 
156
178
  export type UsageKey = keyof typeof zh
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Optional integration with the family Web Extensions parent.
3
+ *
4
+ * The parent service owns page mounting; this module contributes one page
5
+ * contract and keeps the original first-level section as the standalone
6
+ * fallback. Deep links still resolve the parent service first.
7
+ */
8
+
9
+ import { openUsageSettings, settingsShellStore, type SlotSeatReader } from './foot-card-mount.tsx'
10
+ import { t } from './locales.ts'
11
+ import { installWebExtensionPage, type WebExtensionPageContext } from './web-extension-page.ts'
12
+
13
+ /** The original first-level settings seat and its usage entry id. */
14
+ export const USAGE_SETTINGS_SEAT = 'settings.section'
15
+ export const USAGE_SECTION_ID = 'dsh-usage'
16
+
17
+ /** The family section's keyed extension seat. */
18
+ export const WEB_UI_EXTENSION_SEAT = 'web-ui.extension'
19
+
20
+ /** Optional navigation contract published by the family extensions plugin. */
21
+ export interface WebUiExtensionsService {
22
+ sectionId: 'web-ui-plugins'
23
+ label(): string
24
+ open(id: string): boolean
25
+ }
26
+
27
+ /** The context slice needed by the migrating section registration. */
28
+ export type UsageSectionContext = WebExtensionPageContext
29
+
30
+ /** The context slice needed by the foot card's settings navigation. */
31
+ export interface UsageNavigationContext {
32
+ get?(name: string): unknown
33
+ slots: SlotSeatReader
34
+ }
35
+
36
+ /** The usage card contribution, independent of the seat that owns it. */
37
+ export interface UsageSectionRegistration {
38
+ order: number
39
+ locale: string
40
+ label(): string
41
+ inject(): object
42
+ component: unknown
43
+ }
44
+
45
+ /** Read the optional service without assuming a particular cordis test double. */
46
+ export function getWebUiExtensions(ctx: { get?(name: string): unknown }): WebUiExtensionsService | undefined {
47
+ if (typeof ctx.get !== 'function') return undefined
48
+ try {
49
+ const service = ctx.get('webUiExtensions') as Partial<WebUiExtensionsService> | undefined
50
+ return service?.sectionId === 'web-ui-plugins'
51
+ && typeof service.label === 'function'
52
+ && typeof service.open === 'function'
53
+ ? service as WebUiExtensionsService
54
+ : undefined
55
+ } catch {
56
+ return undefined
57
+ }
58
+ }
59
+
60
+ /** Register the one usage page; disposal is owned by the calling plugin fiber. */
61
+ export function installUsageSection(
62
+ ctx: UsageSectionContext,
63
+ registration: UsageSectionRegistration,
64
+ ): () => void {
65
+ return installWebExtensionPage(ctx, {
66
+ key: USAGE_SECTION_ID,
67
+ order: registration.order,
68
+ locale: registration.locale,
69
+ label: registration.label,
70
+ inject: registration.inject,
71
+ component: registration.component,
72
+ })
73
+ }
74
+
75
+ /**
76
+ * Open usage through the family service first. If it declines, fall back to the
77
+ * native settings shell on the family section (or on the original usage row
78
+ * when the service is absent), preserving the matching localized nav label.
79
+ */
80
+ export function openIntegratedUsageSettings(ctx: UsageNavigationContext): void {
81
+ const service = getWebUiExtensions(ctx)
82
+ if (service?.open(USAGE_SECTION_ID) === true) return
83
+ openUsageSettings({
84
+ id: service?.sectionId ?? USAGE_SECTION_ID,
85
+ label: service === undefined ? () => t('usage.title') : () => service.label(),
86
+ store: settingsShellStore(ctx.slots),
87
+ })
88
+ }