dsh-subscriptions 0.2.0 → 0.2.3
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 +220 -180
- package/lib/auth/claude-code-creds.js +31 -9
- package/lib/auth/device-flow.js +16 -9
- package/lib/auth/oauth-flow.js +13 -10
- package/lib/auth/rpc.d.ts +8 -4
- package/lib/auth/rpc.js +89 -25
- package/lib/auth/store.js +80 -31
- package/lib/client/CursorCard.d.ts +1 -1
- package/lib/client/CursorCard.js +50 -16
- package/lib/client/ExternalUsageCards.d.ts +1 -1
- package/lib/client/ExternalUsageCards.js +37 -16
- package/lib/client/ImageGallery.d.ts +2 -2
- package/lib/client/ImageGallery.js +92 -33
- package/lib/client/ImageGenerateToolview.js +50 -14
- package/lib/client/OllamaCard.d.ts +1 -1
- package/lib/client/OllamaCard.js +26 -8
- package/lib/client/OllamaSettingsManager.js +113 -30
- package/lib/client/ProviderAccountManager.d.ts +1 -1
- package/lib/client/ProviderAccountManager.js +164 -49
- package/lib/client/ProviderModelEditor.js +137 -34
- package/lib/client/SpeedSelect.d.ts +62 -14
- package/lib/client/SpeedSelect.js +261 -49
- package/lib/client/SubscriptionUsageBadge.d.ts +4 -10
- package/lib/client/SubscriptionUsageBadge.js +300 -112
- package/lib/client/SubscriptionsSection.d.ts +2 -0
- package/lib/client/SubscriptionsSection.js +265 -85
- package/lib/client/UsageBadgeDisplaySetting.js +35 -12
- package/lib/client/UsageMeter.d.ts +1 -1
- package/lib/client/UsageMeter.js +62 -24
- package/lib/client/VideoGenerateToolview.js +69 -17
- package/lib/client/account-preferences.d.ts +8 -0
- package/lib/client/account-preferences.js +20 -5
- package/lib/client/host-contract.d.ts +11 -2
- package/lib/client/host-contract.js +20 -3
- package/lib/client/index.d.ts +5 -5
- package/lib/client/index.js +34 -12
- package/lib/client/locales.d.ts +22 -0
- package/lib/client/locales.js +73 -51
- package/lib/client/model-filter.d.ts +37 -0
- package/lib/client/model-filter.js +45 -0
- package/lib/client/ollama-draft.js +21 -12
- package/lib/client/reset-action.js +6 -4
- package/lib/client/reset-credits-view.d.ts +1 -1
- package/lib/client/reset-credits-view.js +66 -17
- package/lib/client/subscription-card-styles.js +94 -24
- package/lib/client/usage-color-preferences.js +4 -2
- package/lib/client/usage-pace.js +30 -12
- package/lib/client/usage-window-filter.d.ts +7 -0
- package/lib/client/usage-window-filter.js +12 -0
- package/lib/client.js +480 -136
- package/lib/client.js.map +1 -1
- package/lib/http.js +1 -1
- package/lib/index.d.ts +3 -3
- package/lib/index.js +167 -76
- package/lib/model-defaults.js +4 -2
- package/lib/provider-settings.d.ts +17 -0
- package/lib/provider-settings.js +79 -16
- package/lib/providers/account-preferences.js +51 -22
- package/lib/providers/accounts.js +15 -9
- package/lib/providers/antigravity-oauth-client.js +2 -2
- package/lib/providers/antigravity.js +141 -68
- package/lib/providers/catalog-store.js +120 -41
- package/lib/providers/claude-cli-version.js +3 -3
- package/lib/providers/claude.d.ts +9 -2
- package/lib/providers/claude.js +153 -90
- package/lib/providers/codex-client-version.js +3 -3
- package/lib/providers/codex-search.js +40 -13
- package/lib/providers/codex.js +196 -112
- package/lib/providers/common.js +71 -39
- package/lib/providers/copilot.js +143 -82
- package/lib/providers/cursor-adapter.js +42 -18
- package/lib/providers/cursor-auth.d.ts +1 -1
- package/lib/providers/cursor-auth.js +69 -24
- package/lib/providers/cursor-model-settings.js +14 -5
- package/lib/providers/cursor-usage.js +27 -13
- package/lib/providers/external-usage-controller.js +14 -5
- package/lib/providers/external-usage.js +59 -23
- package/lib/providers/grok.js +152 -89
- package/lib/providers/image-pool.js +29 -11
- package/lib/providers/minimax-usage.js +31 -11
- package/lib/providers/npm-cli-version.js +10 -3
- package/lib/providers/ollama-settings.js +24 -8
- package/lib/providers/ollama-web.js +29 -11
- package/lib/providers/ollama.js +129 -66
- package/lib/providers/pool-family.js +11 -3
- package/lib/providers/pool-health.js +28 -8
- package/lib/providers/pool-usage.js +16 -9
- package/lib/providers/pool.d.ts +8 -0
- package/lib/providers/pool.js +81 -42
- package/lib/providers/rate-limit.js +8 -2
- package/lib/providers/replay.js +40 -17
- package/lib/providers/reset-redemption.js +18 -6
- package/lib/tools/image-generate.js +123 -65
- package/lib/tools/registration.js +5 -2
- package/lib/tools/video-generate.js +51 -31
- package/lib/tools/x-search.js +50 -22
- package/lib/translate/anthropic.js +85 -37
- package/lib/translate/antigravity-schema.js +71 -28
- package/lib/translate/antigravity-thinking.js +22 -9
- package/lib/translate/antigravity.js +151 -52
- package/lib/translate/chat-completions.js +67 -23
- package/lib/translate/resolved.js +55 -21
- package/lib/translate/responses.js +69 -29
- package/lib/translate/sse.js +4 -1
- package/package.json +27 -4
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useState } from 'react';
|
|
3
|
-
import { setUsageBadgeMode, useUsageBadgeMode } from './usage-badge-preferences.js';
|
|
4
|
-
import { isUsageColorPreset, setUsageColorPreset, useUsageColorPreset } from './usage-color-preferences.js';
|
|
3
|
+
import { setUsageBadgeMode, useUsageBadgeMode, } from './usage-badge-preferences.js';
|
|
4
|
+
import { isUsageColorPreset, setUsageColorPreset, useUsageColorPreset, } from './usage-color-preferences.js';
|
|
5
5
|
/** Browser-local display preference; never changes provider or account settings. */
|
|
6
6
|
export function UsageBadgeDisplaySetting({ t }) {
|
|
7
7
|
const mode = useUsageBadgeMode();
|
|
8
8
|
const preset = useUsageColorPreset();
|
|
9
9
|
const [failed, setFailed] = useState(false);
|
|
10
|
-
return (_jsxs("div", { style: styles.card, children: [_jsxs("label", { style: styles.field, children: [_jsx("span", { children: t('usageBadgeDisplay') }), _jsxs("select", { style: styles.select, "aria-label": t('usageBadgeDisplay'), value: mode, onChange: event => {
|
|
10
|
+
return (_jsxs("div", { style: styles.card, children: [_jsxs("label", { style: styles.field, children: [_jsx("span", { children: t('usageBadgeDisplay') }), _jsxs("select", { style: styles.select, "aria-label": t('usageBadgeDisplay'), value: mode, onChange: (event) => {
|
|
11
11
|
const value = event.currentTarget.value;
|
|
12
12
|
if (value !== 'recent' && value !== 'always' && value !== 'hidden')
|
|
13
13
|
return;
|
|
@@ -16,11 +16,12 @@ export function UsageBadgeDisplaySetting({ t }) {
|
|
|
16
16
|
setFailed(false);
|
|
17
17
|
}
|
|
18
18
|
catch (error) {
|
|
19
|
-
if (!(error instanceof DOMException) ||
|
|
19
|
+
if (!(error instanceof DOMException) ||
|
|
20
|
+
!['SecurityError', 'QuotaExceededError'].includes(error.name))
|
|
20
21
|
throw error;
|
|
21
22
|
setFailed(true);
|
|
22
23
|
}
|
|
23
|
-
}, children: [_jsx("option", { value: "recent", children: t('usageBadgeDisplayRecent') }), _jsx("option", { value: "always", children: t('usageBadgeDisplayAlways') }), _jsx("option", { value: "hidden", children: t('usageBadgeDisplayHidden') })] })] }), _jsx("p", { style: styles.hint, children: t('usageBadgeDisplayHint') }), _jsxs("label", { style: styles.field, children: [_jsx("span", { children: t('usageColorLabel') }), _jsxs("select", { style: styles.select, "aria-label": t('usageColorLabel'), value: preset, onChange: event => {
|
|
24
|
+
}, children: [_jsx("option", { value: "recent", children: t('usageBadgeDisplayRecent') }), _jsx("option", { value: "always", children: t('usageBadgeDisplayAlways') }), _jsx("option", { value: "hidden", children: t('usageBadgeDisplayHidden') })] })] }), _jsx("p", { style: styles.hint, children: t('usageBadgeDisplayHint') }), _jsxs("label", { style: styles.field, children: [_jsx("span", { children: t('usageColorLabel') }), _jsxs("select", { style: styles.select, "aria-label": t('usageColorLabel'), value: preset, onChange: (event) => {
|
|
24
25
|
const value = event.currentTarget.value;
|
|
25
26
|
if (!isUsageColorPreset(value))
|
|
26
27
|
return;
|
|
@@ -29,21 +30,43 @@ export function UsageBadgeDisplaySetting({ t }) {
|
|
|
29
30
|
setFailed(false);
|
|
30
31
|
}
|
|
31
32
|
catch (error) {
|
|
32
|
-
if (!(error instanceof DOMException) ||
|
|
33
|
+
if (!(error instanceof DOMException) ||
|
|
34
|
+
!['SecurityError', 'QuotaExceededError'].includes(error.name))
|
|
33
35
|
throw error;
|
|
34
36
|
setFailed(true);
|
|
35
37
|
}
|
|
36
|
-
}, children: [_jsx("option", { value: "standard", children: t('usageColorStandard') }), _jsx("option", { value: "relaxed", children: t('usageColorRelaxed') }), _jsx("option", { value: "remaining", children: t('usageColorRemaining') })] })] }), _jsx("p", { style: styles.hint, children: t(preset === 'remaining'
|
|
38
|
+
}, children: [_jsx("option", { value: "standard", children: t('usageColorStandard') }), _jsx("option", { value: "relaxed", children: t('usageColorRelaxed') }), _jsx("option", { value: "remaining", children: t('usageColorRemaining') })] })] }), _jsx("p", { style: styles.hint, children: t(preset === 'remaining'
|
|
39
|
+
? 'usageColorRemainingHint'
|
|
40
|
+
: 'usageColorPaceHint', {
|
|
37
41
|
allowance: preset === 'relaxed' ? 15 : 10,
|
|
38
|
-
}) }), failed && _jsx("p", { role: "alert", style: {
|
|
42
|
+
}) }), failed && (_jsx("p", { role: "alert", style: {
|
|
43
|
+
...styles.hint,
|
|
44
|
+
color: 'var(--dsw-alias-state-error-primary)',
|
|
45
|
+
}, children: t('usageBadgeDisplaySaveFailed') }))] }));
|
|
39
46
|
}
|
|
40
47
|
const styles = {
|
|
41
48
|
card: {
|
|
42
49
|
border: '0.5px solid var(--dsw-alias-settings-card-stroke, var(--dsw-alias-border-l4))',
|
|
43
|
-
borderRadius: 'var(--dsw-radius-xl, 20px)',
|
|
44
|
-
|
|
50
|
+
borderRadius: 'var(--dsw-radius-xl, 20px)',
|
|
51
|
+
background: 'var(--dsw-alias-settings-card-fill, var(--dsw-alias-bg-layer-2))',
|
|
52
|
+
padding: '12px 14px',
|
|
53
|
+
display: 'flex',
|
|
54
|
+
flexDirection: 'column',
|
|
55
|
+
gap: 6,
|
|
56
|
+
},
|
|
57
|
+
field: {
|
|
58
|
+
display: 'flex',
|
|
59
|
+
flexDirection: 'column',
|
|
60
|
+
gap: 6,
|
|
61
|
+
fontSize: 13,
|
|
62
|
+
fontWeight: 500,
|
|
63
|
+
lineHeight: '20px',
|
|
45
64
|
},
|
|
46
|
-
field: { display: 'flex', flexDirection: 'column', gap: 6, fontSize: 13, fontWeight: 500, lineHeight: '20px' },
|
|
47
65
|
select: { width: '100%' },
|
|
48
|
-
hint: {
|
|
66
|
+
hint: {
|
|
67
|
+
margin: 0,
|
|
68
|
+
fontSize: 12,
|
|
69
|
+
lineHeight: '18px',
|
|
70
|
+
color: 'var(--dsw-alias-label-tertiary)',
|
|
71
|
+
},
|
|
49
72
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { CSSProperties } from 'react';
|
|
2
2
|
import type { UsageWindow, SubscriptionsSectionInjected } from './SubscriptionsSection.js';
|
|
3
3
|
import type { UsageObservation } from './usage-pace.js';
|
|
4
|
-
export declare function UsageMeter({ window: quota, t, style, observedAt, stale }: {
|
|
4
|
+
export declare function UsageMeter({ window: quota, t, style, observedAt, stale, }: {
|
|
5
5
|
window: UsageWindow;
|
|
6
6
|
t: SubscriptionsSectionInjected['t'];
|
|
7
7
|
style?: CSSProperties;
|
package/lib/client/UsageMeter.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useState } from 'react';
|
|
3
|
-
import { displayStartPercent, elapsedPercent, isUsageFresh, resetCountdownParts, usageBarColor, usageColorState, validUsage } from './usage-pace.js';
|
|
3
|
+
import { displayStartPercent, elapsedPercent, isUsageFresh, resetCountdownParts, usageBarColor, usageColorState, validUsage, } from './usage-pace.js';
|
|
4
4
|
import { useUsageColorPreset } from './usage-color-preferences.js';
|
|
5
5
|
/** Singular/plural locale keys per countdown unit (zh maps both to one string). */
|
|
6
6
|
const UNIT_KEYS = {
|
|
@@ -8,7 +8,7 @@ const UNIT_KEYS = {
|
|
|
8
8
|
hour: ['usageUnitHour', 'usageUnitHours'],
|
|
9
9
|
minute: ['usageUnitMinute', 'usageUnitMinutes'],
|
|
10
10
|
};
|
|
11
|
-
export function UsageMeter({ window: quota, t, style, observedAt, stale }) {
|
|
11
|
+
export function UsageMeter({ window: quota, t, style, observedAt, stale, }) {
|
|
12
12
|
const preset = useUsageColorPreset();
|
|
13
13
|
const [now, setNow] = useState(Date.now);
|
|
14
14
|
useEffect(() => {
|
|
@@ -31,30 +31,68 @@ export function UsageMeter({ window: quota, t, style, observedAt, stale }) {
|
|
|
31
31
|
const state = usageColorState(quota.usedPercent, pace, preset, fresh);
|
|
32
32
|
const lead = pace === undefined ? 0 : Math.round(used - pace);
|
|
33
33
|
const label = [
|
|
34
|
-
valid
|
|
34
|
+
valid
|
|
35
|
+
? t('usageMeterUsed', {
|
|
36
|
+
used: Math.round(used),
|
|
37
|
+
remaining: Math.round(100 - used),
|
|
38
|
+
})
|
|
39
|
+
: t('usageMeterInvalid'),
|
|
35
40
|
// An invalid reading already states unavailability; the stale line would repeat it.
|
|
36
|
-
!valid
|
|
37
|
-
|
|
38
|
-
|
|
41
|
+
!valid
|
|
42
|
+
? ''
|
|
43
|
+
: !fresh
|
|
44
|
+
? t('usageMeterStale')
|
|
45
|
+
: state === 'red'
|
|
46
|
+
? t('usageMeterNearLimit')
|
|
47
|
+
: pace === undefined && preset !== 'remaining'
|
|
48
|
+
? t('usageMeterUnknownTime')
|
|
49
|
+
: state === 'yellow'
|
|
50
|
+
? t('usageMeterAhead')
|
|
51
|
+
: t('usageMeterNoWarning'),
|
|
39
52
|
// The elapsed-time line is a timing fact: it shows whenever the window's
|
|
40
53
|
// interval is known, even for a stale or invalid reading.
|
|
41
|
-
marker === undefined
|
|
42
|
-
|
|
43
|
-
:
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
54
|
+
marker === undefined
|
|
55
|
+
? ''
|
|
56
|
+
: t('usageMeterPace', { elapsed: Math.round(marker) }),
|
|
57
|
+
pace === undefined
|
|
58
|
+
? ''
|
|
59
|
+
: lead > 0
|
|
60
|
+
? t('usageMeterPaceAhead', { points: lead })
|
|
61
|
+
: lead < 0
|
|
62
|
+
? t('usageMeterPaceBehind', { points: -lead })
|
|
63
|
+
: t('usageMeterPaceEven'),
|
|
64
|
+
quota.resetsAt !== undefined && quota.resetsAt > current
|
|
65
|
+
? t('usageMeterReset', {
|
|
66
|
+
duration: resetCountdownParts(quota.resetsAt - current)
|
|
67
|
+
.map((part) => t(UNIT_KEYS[part.unit][part.count === 1 ? 0 : 1], {
|
|
68
|
+
count: part.count,
|
|
69
|
+
}))
|
|
70
|
+
.join(' '),
|
|
71
|
+
})
|
|
72
|
+
: '',
|
|
73
|
+
]
|
|
74
|
+
.filter(Boolean)
|
|
75
|
+
.join(' · ');
|
|
76
|
+
return (_jsxs("div", { role: "img", "aria-label": label, title: label, "data-usage-color": state, style: {
|
|
77
|
+
height: 6,
|
|
78
|
+
borderRadius: 3,
|
|
79
|
+
overflow: 'hidden',
|
|
80
|
+
background: 'var(--dsw-alias-bg-layer-1)',
|
|
81
|
+
border: '1px solid var(--dsw-alias-border-l2)',
|
|
82
|
+
...style,
|
|
83
|
+
position: 'relative',
|
|
84
|
+
}, children: [_jsx("div", { style: {
|
|
85
|
+
height: '100%',
|
|
86
|
+
borderRadius: 'inherit',
|
|
87
|
+
width: `${used}%`,
|
|
88
|
+
background: usageBarColor(quota.usedPercent, pace, preset, fresh),
|
|
89
|
+
} }), marker !== undefined && (_jsx("span", { "aria-hidden": "true", "data-usage-time-marker": true, style: {
|
|
90
|
+
position: 'absolute',
|
|
91
|
+
left: `clamp(0px, calc(${marker}% - 1px), calc(100% - 2px))`,
|
|
92
|
+
top: 0,
|
|
93
|
+
bottom: 0,
|
|
94
|
+
width: 2,
|
|
95
|
+
background: 'var(--dsw-alias-label-primary)',
|
|
58
96
|
boxShadow: '0 0 0 1px var(--dsw-alias-bg-layer-1)',
|
|
59
|
-
} })] });
|
|
97
|
+
} }))] }));
|
|
60
98
|
}
|
|
@@ -29,7 +29,7 @@ const PROMPT_MAX_LENGTH = 60;
|
|
|
29
29
|
* @returns loader resolving a bare file name to the decoded bytes.
|
|
30
30
|
*/
|
|
31
31
|
export function createVideoLoader(rpc) {
|
|
32
|
-
return name => callSubscriptionsAuth(rpc, 'video', { name });
|
|
32
|
+
return (name) => callSubscriptionsAuth(rpc, 'video', { name });
|
|
33
33
|
}
|
|
34
34
|
/**
|
|
35
35
|
* English-dictionary fallback for a missing locale seat (standalone renders);
|
|
@@ -67,7 +67,9 @@ function derivePrompt(argsRaw) {
|
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
const line = (prompt ?? argsRaw).split('\n', 1)[0] ?? '';
|
|
70
|
-
return line.length > PROMPT_MAX_LENGTH
|
|
70
|
+
return line.length > PROMPT_MAX_LENGTH
|
|
71
|
+
? `${line.slice(0, PROMPT_MAX_LENGTH)}…`
|
|
72
|
+
: line;
|
|
71
73
|
}
|
|
72
74
|
/** Flatten a settled result's text blocks (the fallback body and the error line). */
|
|
73
75
|
function resultText(block) {
|
|
@@ -111,21 +113,51 @@ function base64Bytes(dataBase64) {
|
|
|
111
113
|
return bytes;
|
|
112
114
|
}
|
|
113
115
|
const styles = {
|
|
114
|
-
container: {
|
|
116
|
+
container: {
|
|
117
|
+
display: 'flex',
|
|
118
|
+
flexDirection: 'column',
|
|
119
|
+
gap: 6,
|
|
120
|
+
padding: '4px 0',
|
|
121
|
+
},
|
|
115
122
|
row: { display: 'flex', alignItems: 'center', gap: 6, minWidth: 0 },
|
|
116
|
-
icon: {
|
|
123
|
+
icon: {
|
|
124
|
+
display: 'inline-flex',
|
|
125
|
+
flexShrink: 0,
|
|
126
|
+
color: 'var(--dsw-alias-label-tertiary)',
|
|
127
|
+
},
|
|
117
128
|
title: {
|
|
118
|
-
fontSize: 13,
|
|
119
|
-
|
|
129
|
+
fontSize: 13,
|
|
130
|
+
lineHeight: '20px',
|
|
131
|
+
color: 'var(--dsw-alias-label-primary)',
|
|
132
|
+
overflow: 'hidden',
|
|
133
|
+
textOverflow: 'ellipsis',
|
|
134
|
+
whiteSpace: 'nowrap',
|
|
135
|
+
},
|
|
136
|
+
subtle: {
|
|
137
|
+
margin: 0,
|
|
138
|
+
fontSize: 12,
|
|
139
|
+
lineHeight: '18px',
|
|
140
|
+
color: 'var(--dsw-alias-label-tertiary)',
|
|
120
141
|
},
|
|
121
|
-
subtle: { margin: 0, fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-label-tertiary)' },
|
|
122
142
|
output: {
|
|
123
|
-
margin: 0,
|
|
124
|
-
|
|
143
|
+
margin: 0,
|
|
144
|
+
fontSize: 12,
|
|
145
|
+
lineHeight: '18px',
|
|
146
|
+
color: 'var(--dsw-alias-label-secondary)',
|
|
147
|
+
whiteSpace: 'pre-wrap',
|
|
148
|
+
overflowWrap: 'anywhere',
|
|
149
|
+
},
|
|
150
|
+
error: {
|
|
151
|
+
margin: 0,
|
|
152
|
+
fontSize: 12,
|
|
153
|
+
lineHeight: '18px',
|
|
154
|
+
color: 'var(--dsw-alias-state-error-primary)',
|
|
125
155
|
},
|
|
126
|
-
error: { margin: 0, fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-state-error-primary)' },
|
|
127
156
|
video: {
|
|
128
|
-
display: 'block',
|
|
157
|
+
display: 'block',
|
|
158
|
+
maxWidth: 480,
|
|
159
|
+
width: '100%',
|
|
160
|
+
borderRadius: 8,
|
|
129
161
|
backgroundColor: 'var(--dsw-alias-bg-skeleton)',
|
|
130
162
|
},
|
|
131
163
|
};
|
|
@@ -139,7 +171,9 @@ export function VideoGenerateToolview(props) {
|
|
|
139
171
|
const t = props.t ?? fallbackTranslate;
|
|
140
172
|
const settled = block !== undefined && 'kind' in block;
|
|
141
173
|
const isError = settled && block.isError;
|
|
142
|
-
const fileName = block !== undefined && settled && !isError
|
|
174
|
+
const fileName = block !== undefined && settled && !isError
|
|
175
|
+
? resolveFileName(block)
|
|
176
|
+
: undefined;
|
|
143
177
|
const [load, setLoad] = useState({ phase: 'loading' });
|
|
144
178
|
useEffect(() => {
|
|
145
179
|
if (fileName === undefined || loadVideo === undefined)
|
|
@@ -151,12 +185,17 @@ export function VideoGenerateToolview(props) {
|
|
|
151
185
|
if (cancelled)
|
|
152
186
|
return;
|
|
153
187
|
// Uint8Array#slice detaches a plain ArrayBuffer view for BlobPart.
|
|
154
|
-
objectUrl = URL.createObjectURL(new Blob([base64Bytes(video.dataBase64).slice()], {
|
|
188
|
+
objectUrl = URL.createObjectURL(new Blob([base64Bytes(video.dataBase64).slice()], {
|
|
189
|
+
type: video.mediaType,
|
|
190
|
+
}));
|
|
155
191
|
setLoad({ phase: 'ready', url: objectUrl });
|
|
156
192
|
}, (error) => {
|
|
157
193
|
if (cancelled)
|
|
158
194
|
return;
|
|
159
|
-
setLoad({
|
|
195
|
+
setLoad({
|
|
196
|
+
phase: 'failed',
|
|
197
|
+
message: error instanceof Error ? error.message : String(error),
|
|
198
|
+
});
|
|
160
199
|
});
|
|
161
200
|
return () => {
|
|
162
201
|
cancelled = true;
|
|
@@ -166,10 +205,23 @@ export function VideoGenerateToolview(props) {
|
|
|
166
205
|
}, [fileName, loadVideo]);
|
|
167
206
|
if (block === undefined)
|
|
168
207
|
return null;
|
|
169
|
-
const argsRaw = (settled
|
|
208
|
+
const argsRaw = (settled
|
|
209
|
+
? block.call?.argsRaw
|
|
210
|
+
: block.phase === 'start'
|
|
211
|
+
? block.argsRaw
|
|
212
|
+
: undefined) ?? '';
|
|
170
213
|
const title = `video_generate: ${derivePrompt(argsRaw)}`;
|
|
171
214
|
const text = settled ? resultText(block) : '';
|
|
172
|
-
return (_jsxs("div", { style: styles.container, children: [_jsxs("div", { style: styles.row, children: [_jsx("span", { style: styles.icon, children: _jsx(SparkleIcon, { size: 14 }) }), _jsx("span", { style: styles.title, children: title })] }), !settled && _jsx("p", { style: styles.subtle, children: t('generatingVideo') }), settled && isError && text !== '' && (_jsx("p", { style: styles.error, children: text.split('\n', 1)[0] })), settled &&
|
|
173
|
-
|
|
215
|
+
return (_jsxs("div", { style: styles.container, children: [_jsxs("div", { style: styles.row, children: [_jsx("span", { style: styles.icon, children: _jsx(SparkleIcon, { size: 14 }) }), _jsx("span", { style: styles.title, children: title })] }), !settled && _jsx("p", { style: styles.subtle, children: t('generatingVideo') }), settled && isError && text !== '' && (_jsx("p", { style: styles.error, children: text.split('\n', 1)[0] })), settled &&
|
|
216
|
+
!isError &&
|
|
217
|
+
fileName !== undefined &&
|
|
218
|
+
load.phase === 'loading' && (_jsx("p", { style: styles.subtle, children: t('videoLoading') })), settled &&
|
|
219
|
+
!isError &&
|
|
220
|
+
fileName !== undefined &&
|
|
221
|
+
load.phase === 'failed' && (_jsx("p", { style: styles.error, children: t('videoLoadFailed', { message: load.message }) })), settled &&
|
|
222
|
+
!isError &&
|
|
223
|
+
fileName !== undefined &&
|
|
224
|
+
load.phase === 'ready' && (
|
|
225
|
+
// Generated clip; no caption track exists.
|
|
174
226
|
_jsx("video", { style: styles.video, src: load.url, controls: true, preload: "metadata" })), settled && !isError && fileName === undefined && text !== '' && (_jsx("p", { style: styles.output, children: text }))] }));
|
|
175
227
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { AccountPreferences, ProviderPreferences } from '../provider-settings.js';
|
|
2
|
+
import type { PromptCacheTtl } from '../translate/anthropic.js';
|
|
2
3
|
export interface AccountCatalogRow {
|
|
3
4
|
key: string;
|
|
4
5
|
label: string;
|
|
@@ -20,5 +21,12 @@ export declare function accountModelRows(account: AccountCatalogRow, preferences
|
|
|
20
21
|
}[];
|
|
21
22
|
/** The model editor owns everything except the separately managed accounts. */
|
|
22
23
|
export declare function mergeLatestAccounts(draft: ProviderPreferences, latest: ProviderPreferences): ProviderPreferences;
|
|
24
|
+
/**
|
|
25
|
+
* The account manager owns the Claude prompt-cache TTL picker. The model
|
|
26
|
+
* editor's draft carries the TTL it loaded, so the dialog always replaces it
|
|
27
|
+
* with the picker's choice when touched, or the freshly re-read value
|
|
28
|
+
* otherwise.
|
|
29
|
+
*/
|
|
30
|
+
export declare function mergePromptCacheTtl(settings: ProviderPreferences, promptCacheTtl: PromptCacheTtl | undefined): ProviderPreferences;
|
|
23
31
|
/** Only touched accounts replace their latest preferences; other settings survive. */
|
|
24
32
|
export declare function mergeAccountChanges(latest: ProviderPreferences, changes: Record<string, AccountPreferences>): ProviderPreferences;
|
|
@@ -1,19 +1,34 @@
|
|
|
1
1
|
/** Missing allowlist follows discovery; explicit [] must remain empty. */
|
|
2
2
|
export function accountPoolSelection(account, models) {
|
|
3
|
-
return new Set(account.poolModels ?? models.map(model => model.id));
|
|
3
|
+
return new Set(account.poolModels ?? models.map((model) => model.id));
|
|
4
4
|
}
|
|
5
5
|
/** Retain unavailable saved IDs so a temporary catalog failure cannot erase them. */
|
|
6
6
|
export function accountModelRows(account, preferences) {
|
|
7
|
-
const known = new Set(account.models.map(model => model.id));
|
|
7
|
+
const known = new Set(account.models.map((model) => model.id));
|
|
8
8
|
return [
|
|
9
|
-
...account.models.map(model => ({ ...model, unavailable: false })),
|
|
10
|
-
...(preferences.poolModels ?? [])
|
|
9
|
+
...account.models.map((model) => ({ ...model, unavailable: false })),
|
|
10
|
+
...(preferences.poolModels ?? [])
|
|
11
|
+
.filter((id) => !known.has(id))
|
|
12
|
+
.map((id) => ({ id, name: id, unavailable: true })),
|
|
11
13
|
];
|
|
12
14
|
}
|
|
13
15
|
/** The model editor owns everything except the separately managed accounts. */
|
|
14
16
|
export function mergeLatestAccounts(draft, latest) {
|
|
15
17
|
const { accounts: _stale, ...settings } = draft;
|
|
16
|
-
return {
|
|
18
|
+
return {
|
|
19
|
+
...settings,
|
|
20
|
+
...(latest.accounts === undefined ? {} : { accounts: latest.accounts }),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The account manager owns the Claude prompt-cache TTL picker. The model
|
|
25
|
+
* editor's draft carries the TTL it loaded, so the dialog always replaces it
|
|
26
|
+
* with the picker's choice when touched, or the freshly re-read value
|
|
27
|
+
* otherwise.
|
|
28
|
+
*/
|
|
29
|
+
export function mergePromptCacheTtl(settings, promptCacheTtl) {
|
|
30
|
+
const { promptCacheTtl: _stale, ...rest } = settings;
|
|
31
|
+
return promptCacheTtl === undefined ? rest : { ...rest, promptCacheTtl };
|
|
17
32
|
}
|
|
18
33
|
/** Only touched accounts replace their latest preferences; other settings survive. */
|
|
19
34
|
export function mergeAccountChanges(latest, changes) {
|
|
@@ -62,9 +62,16 @@ export declare const HOST_CONTRACT: {
|
|
|
62
62
|
};
|
|
63
63
|
/** DOM attributes the client looks up in host-rendered markup. */
|
|
64
64
|
readonly markers: {
|
|
65
|
-
/**
|
|
65
|
+
/**
|
|
66
|
+
* Stats pill anchors, by role. `row` is the shared stats row through DSH
|
|
67
|
+
* 0.2.0; the badge portals into it. `dock` is the per-pill anchor from
|
|
68
|
+
* 0.2.1; the badge stays in its dock entry and stops watching once that
|
|
69
|
+
* anchor is in scope. A host renders one of them. The package check
|
|
70
|
+
* accepts either spelling; callers read `row` and `dock` by name.
|
|
71
|
+
*/
|
|
66
72
|
readonly composerStats: {
|
|
67
|
-
readonly
|
|
73
|
+
readonly row: "data-composer-stats";
|
|
74
|
+
readonly dock: "data-composer-stat";
|
|
68
75
|
readonly package: "@deepseek-ai/dsh-client-ui-chat";
|
|
69
76
|
};
|
|
70
77
|
};
|
|
@@ -88,3 +95,5 @@ export declare const HOST_CONTRACT: {
|
|
|
88
95
|
};
|
|
89
96
|
/** A glyph name listed in {@link HOST_CONTRACT}; hostIcon() accepts no other. */
|
|
90
97
|
export type HostIconName = (typeof HOST_CONTRACT.icons.names)[number];
|
|
98
|
+
/** Attribute selector for a host DOM marker (`data-composer-stats` → `[data-composer-stats]`). */
|
|
99
|
+
export declare function markerSelector(attribute: string): string;
|
|
@@ -30,7 +30,10 @@ export const HOST_CONTRACT = {
|
|
|
30
30
|
moduleTable: '@deepseek-ai/dsh-web-frontend',
|
|
31
31
|
/** Named runtime exports the client reads from a host module. */
|
|
32
32
|
exports: {
|
|
33
|
-
'@deepseek-ai/dsh-client-ui-primitives': [
|
|
33
|
+
'@deepseek-ai/dsh-client-ui-primitives': [
|
|
34
|
+
'useAnchoredPosition',
|
|
35
|
+
'useDismissOnOutsidePointer',
|
|
36
|
+
],
|
|
34
37
|
},
|
|
35
38
|
/**
|
|
36
39
|
* 16px glyphs read through hostIcon(). The host must export
|
|
@@ -62,8 +65,18 @@ export const HOST_CONTRACT = {
|
|
|
62
65
|
},
|
|
63
66
|
/** DOM attributes the client looks up in host-rendered markup. */
|
|
64
67
|
markers: {
|
|
65
|
-
/**
|
|
66
|
-
|
|
68
|
+
/**
|
|
69
|
+
* Stats pill anchors, by role. `row` is the shared stats row through DSH
|
|
70
|
+
* 0.2.0; the badge portals into it. `dock` is the per-pill anchor from
|
|
71
|
+
* 0.2.1; the badge stays in its dock entry and stops watching once that
|
|
72
|
+
* anchor is in scope. A host renders one of them. The package check
|
|
73
|
+
* accepts either spelling; callers read `row` and `dock` by name.
|
|
74
|
+
*/
|
|
75
|
+
composerStats: {
|
|
76
|
+
row: 'data-composer-stats',
|
|
77
|
+
dock: 'data-composer-stat',
|
|
78
|
+
package: '@deepseek-ai/dsh-client-ui-chat',
|
|
79
|
+
},
|
|
67
80
|
},
|
|
68
81
|
/**
|
|
69
82
|
* What the slot renderer emits when an entry throws. It catches the error,
|
|
@@ -122,3 +135,7 @@ export const HOST_CONTRACT = {
|
|
|
122
135
|
],
|
|
123
136
|
},
|
|
124
137
|
};
|
|
138
|
+
/** Attribute selector for a host DOM marker (`data-composer-stats` → `[data-composer-stats]`). */
|
|
139
|
+
export function markerSelector(attribute) {
|
|
140
|
+
return `[${attribute}]`;
|
|
141
|
+
}
|
package/lib/client/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { Context as ClientContext } from '@deepseek-ai/cordis';
|
|
2
2
|
import type { SubscriptionsKey } from './locales.js';
|
|
3
|
-
export type { SubscriptionsSectionInjected, SubscriptionsSectionProps } from './SubscriptionsSection.js';
|
|
4
|
-
export type { ImageGenerateToolviewInjected, ImageGenerateToolviewProps } from './ImageGenerateToolview.js';
|
|
5
|
-
export type { VideoGenerateToolviewInjected, VideoGenerateToolviewProps } from './VideoGenerateToolview.js';
|
|
6
|
-
export type { SpeedSelectInjected, SpeedSelectProps, SpeedState, SpeedTier } from './SpeedSelect.js';
|
|
7
|
-
export type { SubscriptionUsageBadgeInjected, SubscriptionUsageBadgeProps } from './SubscriptionUsageBadge.js';
|
|
3
|
+
export type { SubscriptionsSectionInjected, SubscriptionsSectionProps, } from './SubscriptionsSection.js';
|
|
4
|
+
export type { ImageGenerateToolviewInjected, ImageGenerateToolviewProps, } from './ImageGenerateToolview.js';
|
|
5
|
+
export type { VideoGenerateToolviewInjected, VideoGenerateToolviewProps, } from './VideoGenerateToolview.js';
|
|
6
|
+
export type { SpeedSelectInjected, SpeedSelectProps, SpeedState, SpeedTier, } from './SpeedSelect.js';
|
|
7
|
+
export type { SubscriptionUsageBadgeInjected, SubscriptionUsageBadgeProps, } from './SubscriptionUsageBadge.js';
|
|
8
8
|
export type { SubscriptionsKey } from './locales.js';
|
|
9
9
|
declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
10
10
|
interface LocaleNamespaceMap {
|
package/lib/client/index.js
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
// allowImportingTsExtensions/rewriteRelativeImportExtensions pair; under
|
|
3
3
|
// nodenext the .js specifier resolves to the .tsx source (see README note).
|
|
4
4
|
import { SubscriptionsSection } from './SubscriptionsSection.js';
|
|
5
|
-
import { ImageGenerateToolview, createImageLoader } from './ImageGenerateToolview.js';
|
|
6
|
-
import { VideoGenerateToolview, createVideoLoader } from './VideoGenerateToolview.js';
|
|
7
|
-
import { SpeedSelect, createSpeedLoader, createSpeedSetter } from './SpeedSelect.js';
|
|
8
|
-
import { SubscriptionUsageBadge, createCurrentModelReader } from './SubscriptionUsageBadge.js';
|
|
5
|
+
import { ImageGenerateToolview, createImageLoader, } from './ImageGenerateToolview.js';
|
|
6
|
+
import { VideoGenerateToolview, createVideoLoader, } from './VideoGenerateToolview.js';
|
|
7
|
+
import { SpeedSelect, createModelSelectionWatch, createSpeedLoader, createSpeedSetter, notifySpeedChanged, } from './SpeedSelect.js';
|
|
8
|
+
import { SubscriptionUsageBadge, createCurrentModelReader, } from './SubscriptionUsageBadge.js';
|
|
9
9
|
import { en, zh } from './locales.js';
|
|
10
10
|
import { fastCommandDescription } from './fast-command.js';
|
|
11
11
|
/** Dictionary namespace owned by this plugin. */
|
|
@@ -31,7 +31,8 @@ export function apply(ctx) {
|
|
|
31
31
|
ctx.effect(() => {
|
|
32
32
|
const style = document.createElement('style');
|
|
33
33
|
style.setAttribute('data-plugin', 'dsh-subscriptions');
|
|
34
|
-
style.textContent =
|
|
34
|
+
style.textContent =
|
|
35
|
+
'div[role="dialog"][aria-modal="true"]:has(> nav) { padding-top: 14px; }';
|
|
35
36
|
document.head.appendChild(style);
|
|
36
37
|
return () => style.remove();
|
|
37
38
|
}, 'dsh-subscriptions: settings panel breathing room');
|
|
@@ -39,7 +40,10 @@ export function apply(ctx) {
|
|
|
39
40
|
// browser shell the same key holds the full client ConnectionHandle.
|
|
40
41
|
const connection = ctx.get('connection');
|
|
41
42
|
const t = ctx.locale.bind(NS);
|
|
42
|
-
const injected = () => ({
|
|
43
|
+
const injected = () => ({
|
|
44
|
+
rpc: connection.rpc,
|
|
45
|
+
t,
|
|
46
|
+
});
|
|
43
47
|
ctx.slots.inject('settings.section', () => ctx.slots.register({
|
|
44
48
|
name: 'settings.section',
|
|
45
49
|
id: 'subscriptions',
|
|
@@ -51,7 +55,9 @@ export function apply(ctx) {
|
|
|
51
55
|
// The image_generate keyed toolview owns how image calls render inline; its
|
|
52
56
|
// gallery bytes ride the same channel through the injected loader. The
|
|
53
57
|
// framework synthesizes the toolview's own `t` seat from `locale: NS`.
|
|
54
|
-
const toolviewInjected = () => ({
|
|
58
|
+
const toolviewInjected = () => ({
|
|
59
|
+
load: createImageLoader(connection.rpc),
|
|
60
|
+
});
|
|
55
61
|
ctx.slots.inject('tool.call.toolview', () => ctx.slots.register({
|
|
56
62
|
name: 'tool.call.toolview',
|
|
57
63
|
key: 'image_generate',
|
|
@@ -60,7 +66,9 @@ export function apply(ctx) {
|
|
|
60
66
|
}, ImageGenerateToolview));
|
|
61
67
|
// The video_generate keyed toolview plays the saved MP4 inline; its bytes
|
|
62
68
|
// ride the same channel's `video` endpoint through the injected loader.
|
|
63
|
-
const videoToolviewInjected = () => ({
|
|
69
|
+
const videoToolviewInjected = () => ({
|
|
70
|
+
loadVideo: createVideoLoader(connection.rpc),
|
|
71
|
+
});
|
|
64
72
|
ctx.slots.inject('tool.call.toolview', () => ctx.slots.register({
|
|
65
73
|
name: 'tool.call.toolview',
|
|
66
74
|
key: 'video_generate',
|
|
@@ -81,6 +89,7 @@ export function apply(ctx) {
|
|
|
81
89
|
inject: (sessionId) => ({
|
|
82
90
|
loadSpeed: createSpeedLoader(connection, models, sessionId),
|
|
83
91
|
setSpeed: createSpeedSetter(connection, sessionId),
|
|
92
|
+
watchModel: createModelSelectionWatch(models, sessionId),
|
|
84
93
|
}),
|
|
85
94
|
}, SpeedSelect));
|
|
86
95
|
// The subscription usage badge renders a stats pill in the composer's dock
|
|
@@ -123,12 +132,25 @@ export function apply(ctx) {
|
|
|
123
132
|
if (!state.visible)
|
|
124
133
|
throw new Error(t('commandFastUnavailable'));
|
|
125
134
|
return [
|
|
126
|
-
{
|
|
127
|
-
|
|
128
|
-
|
|
135
|
+
{
|
|
136
|
+
id: 'standard',
|
|
137
|
+
label: t('speedStandard'),
|
|
138
|
+
detail: t('speedStandardDescription'),
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
id: 'fast',
|
|
142
|
+
label: t('speedFast'),
|
|
143
|
+
detail: t('speedFastDescription'),
|
|
144
|
+
},
|
|
145
|
+
].map((option) => ({
|
|
146
|
+
...option,
|
|
147
|
+
active: option.id === state.tier,
|
|
148
|
+
}));
|
|
129
149
|
},
|
|
130
150
|
onSelect: async (option, session) => {
|
|
131
|
-
await createSpeedSetter(connection, session.sessionId)(option.id);
|
|
151
|
+
const wrote = await createSpeedSetter(connection, session.sessionId)(option.id);
|
|
152
|
+
if (wrote)
|
|
153
|
+
notifySpeedChanged();
|
|
132
154
|
},
|
|
133
155
|
},
|
|
134
156
|
}), 'dsh-subscriptions: /fast contribution');
|