@goodandready/dsh-subscriptions 0.7.24 → 0.7.25

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.
Files changed (2) hide show
  1. package/lib/client.js +122 -10
  2. package/package.json +1 -1
package/lib/client.js CHANGED
@@ -186,6 +186,16 @@ window.__ModuleLoader__.load({
186
186
  "toastCooldownRecovered": "is now available (cooldown expired)",
187
187
  "modelsCatalogTitle": "Curated Subscription Models",
188
188
  "modelsCatalogDesc": "Available model catalog across active subscriptions in DeepSeek Harness.",
189
+ "modelSearchPlaceholder": "Search models by id, name or alias",
190
+ "modelSortLabel": "Sort models",
191
+ "modelSortName": "Name",
192
+ "modelSortProvider": "Provider",
193
+ "modelSortContext": "Context window",
194
+ "modelSortAvailability": "Availability",
195
+ "modelListCounts": "{shown} of {matched} shown · {hidden} hidden · {total} total",
196
+ "modelShowMore": "Show more",
197
+ "modelShowAll": "Show all",
198
+ "modelNoMatches": "No models match this search.",
189
199
  "rotationDecisionsTitle": "Rotation & Routing Decisions",
190
200
  "rotationDecisionsDesc": "Real-time decision trace explaining account selection, skips, and fallback reasons.",
191
201
  "rotationAttempt": "attempt",
@@ -550,6 +560,16 @@ window.__ModuleLoader__.load({
550
560
  "toastCooldownRecovered": "已解除冷却恢复可用",
551
561
  "modelsCatalogTitle": "精选订阅模型",
552
562
  "modelsCatalogDesc": "当前 DeepSeek Harness 活跃订阅下可用模型一览。",
563
+ "modelSearchPlaceholder": "搜索模型 ID、名称或别名",
564
+ "modelSortLabel": "模型排序",
565
+ "modelSortName": "名称",
566
+ "modelSortProvider": "服务商",
567
+ "modelSortContext": "上下文窗口",
568
+ "modelSortAvailability": "可用性",
569
+ "modelListCounts": "已显示 {shown} / {matched} · 隐藏 {hidden} · 共 {total} 个",
570
+ "modelShowMore": "显示更多",
571
+ "modelShowAll": "显示全部",
572
+ "modelNoMatches": "没有匹配的模型。",
553
573
  "rotationDecisionsTitle": "轮询调度与路由决策",
554
574
  "rotationDecisionsDesc": "实时决策追踪,透明展示每次请求的账号选择、跳过与回退原因。",
555
575
  "rotationAttempt": "次尝试",
@@ -948,7 +968,52 @@ window.__ModuleLoader__.load({
948
968
  }
949
969
  const Chevron = ChevronIcon || FallbackChevron
950
970
 
971
+ // #839 model-list helpers
972
+ function modelListSearchText(model) {
973
+ const parts = [model && model.id, model && model.name, model && model.alias, model && model.provider, model && model.providerName]
974
+ if (model && Array.isArray(model.aliases)) parts.push.apply(parts, model.aliases)
975
+ return parts.filter(Boolean).join(' ').toLowerCase()
976
+ }
977
+
978
+ function filterModelList(models, query) {
979
+ const list = Array.isArray(models) ? models : []
980
+ const q = String(query || '').trim().toLowerCase()
981
+ if (!q) return list.slice()
982
+ return list.filter((model) => modelListSearchText(model).includes(q))
983
+ }
951
984
 
985
+ function modelAvailabilityRank(model) {
986
+ const status = String(model && model.pool && model.pool.status || 'unconfigured').toLowerCase()
987
+ const order = { available: 0, degraded: 1, cooldown: 2, quarantined: 3, exhausted: 4, unconfigured: 5 }
988
+ return order[status] != null ? order[status] : 6
989
+ }
990
+
991
+ function sortModelList(models, sortKey) {
992
+ const list = Array.isArray(models) ? models.slice() : []
993
+ const key = String(sortKey || 'name')
994
+ const byName = (a, b) => String(a && (a.name || a.id) || '').localeCompare(String(b && (b.name || b.id) || ''), undefined, { numeric: true, sensitivity: 'base' })
995
+ list.sort((a, b) => {
996
+ if (key === 'provider') {
997
+ const byProvider = String(a && (a.providerName || a.provider) || '').localeCompare(String(b && (b.providerName || b.provider) || ''), undefined, { sensitivity: 'base' })
998
+ if (byProvider) return byProvider
999
+ } else if (key === 'context') {
1000
+ const delta = Number(b && b.contextWindow || 0) - Number(a && a.contextWindow || 0)
1001
+ if (delta) return delta
1002
+ } else if (key === 'availability') {
1003
+ const delta = modelAvailabilityRank(a) - modelAvailabilityRank(b)
1004
+ if (delta) return delta
1005
+ }
1006
+ return byName(a, b)
1007
+ })
1008
+ return list
1009
+ }
1010
+
1011
+ function modelListCounts(all, shown) {
1012
+ const total = Array.isArray(all) ? all.length : 0
1013
+ const visible = Array.isArray(shown) ? shown.length : 0
1014
+ return { total, shown: visible, hidden: Math.max(0, total - visible) }
1015
+ }
1016
+ // #839 end model-list helpers
952
1017
 
953
1018
  function SubsSection(props) {
954
1019
  // The translator comes from the slot because its registration declares locale.
@@ -961,6 +1026,9 @@ window.__ModuleLoader__.load({
961
1026
  const [accounts, setAccounts] = React.useState([])
962
1027
  const [providers, setProviders] = React.useState([])
963
1028
  const [modelsCatalog, setModelsCatalog] = React.useState([])
1029
+ const [modelQuery, setModelQuery] = React.useState('')
1030
+ const [modelSort, setModelSort] = React.useState('name')
1031
+ const [modelLimit, setModelLimit] = React.useState(40)
964
1032
  const [paste, setPaste] = React.useState({})
965
1033
  const [device, setDevice] = React.useState({}) // #90 key -> {state,userCode,authUrl,intervalMs,status}
966
1034
  const [loginLinks, setLoginLinks] = React.useState({}) // #595 provider:index -> fallback auth URL when a popup is blocked
@@ -1676,6 +1744,20 @@ window.__ModuleLoader__.load({
1676
1744
 
1677
1745
  const connectedCount = accounts.filter((a) => a.configured).length
1678
1746
 
1747
+ const catalogAll = Array.isArray(modelsCatalog) && modelsCatalog.length ? modelsCatalog : [
1748
+ { id: 'gpt-4o', contextLabel: '128k', capabilities: ['vision'], pool: { status: t('sourceAvailable') } },
1749
+ { id: 'o1 / o3-mini', contextLabel: '200k', capabilities: ['reasoning'], pool: { status: t('sourceAvailable') } },
1750
+ { id: 'claude-3-7-sonnet', contextLabel: '200k', capabilities: ['reasoning'], pool: { status: t('sourceAvailable') } },
1751
+ { id: 'claude-3-5-sonnet', contextLabel: '200k', capabilities: ['coding'], pool: { status: t('sourceAvailable') } },
1752
+ { id: 'grok-beta', contextLabel: '128k', capabilities: ['fast'], pool: { status: t('sourceAvailable') } },
1753
+ { id: 'gemini-2.5-pro', contextLabel: '1M', capabilities: ['vision'], pool: { status: t('sourceAvailable') } },
1754
+ { id: 'kimi-k1.5', contextLabel: '128k', capabilities: ['math'], pool: { status: t('sourceAvailable') } },
1755
+ { id: 'glm-4-plus', contextLabel: '128k', capabilities: ['chinese'], pool: { status: t('sourceAvailable') } },
1756
+ ]
1757
+ const catalogSorted = sortModelList(filterModelList(catalogAll, modelQuery), modelSort)
1758
+ const catalogShown = catalogSorted.slice(0, modelLimit)
1759
+ const catalogCounts = modelListCounts(catalogAll, catalogShown)
1760
+
1679
1761
  return h('div', { className: 'dsub-wrap', 'data-tab': tab },
1680
1762
  h('div', { className: 'dsub-header-bar' },
1681
1763
  h('div', { className: 'dsub-row', style: { marginTop: 0 } },
@@ -2197,17 +2279,36 @@ h('div', { className: 'dsub-row' },
2197
2279
  h('details', { className: 'dsub-group', 'data-pane': 'models' },
2198
2280
  h('summary', { className: 'dsub-groupHead' }, '🎯 ' + t('modelsCatalogTitle')),
2199
2281
  h('div', { className: 'dsub-sub', style: { marginTop: '4px' } }, t('modelsCatalogDesc')),
2282
+ h('div', { className: 'dsub-row', style: { marginTop: 8, gap: 6, alignItems: 'center' } },
2283
+ h('input', {
2284
+ className: 'dsub-inp dsub-grow',
2285
+ value: modelQuery,
2286
+ placeholder: t('modelSearchPlaceholder'),
2287
+ 'aria-label': t('modelSearchPlaceholder'),
2288
+ onChange: (e) => { setModelQuery(e.target.value); setModelLimit(40) },
2289
+ }),
2290
+ h('select', {
2291
+ className: 'dsub-select',
2292
+ value: modelSort,
2293
+ title: t('modelSortLabel'),
2294
+ 'aria-label': t('modelSortLabel'),
2295
+ onChange: (e) => { setModelSort(e.target.value); setModelLimit(40) },
2296
+ },
2297
+ h('option', { value: 'name' }, t('modelSortName')),
2298
+ h('option', { value: 'provider' }, t('modelSortProvider')),
2299
+ h('option', { value: 'context' }, t('modelSortContext')),
2300
+ h('option', { value: 'availability' }, t('modelSortAvailability')),
2301
+ ),
2302
+ ),
2303
+ h('div', { className: 'dsub-sub', style: { marginTop: 4 } },
2304
+ t('modelListCounts')
2305
+ .replace('{shown}', String(catalogCounts.shown))
2306
+ .replace('{matched}', String(catalogSorted.length))
2307
+ .replace('{hidden}', String(catalogCounts.hidden))
2308
+ .replace('{total}', String(catalogCounts.total))
2309
+ ),
2200
2310
  h('div', { className: 'dsub-model-grid' },
2201
- (Array.isArray(modelsCatalog) && modelsCatalog.length ? modelsCatalog : [
2202
- { id: 'gpt-4o', contextLabel: '128k', capabilities: ['vision'], pool: { status: t('sourceAvailable') } },
2203
- { id: 'o1 / o3-mini', contextLabel: '200k', capabilities: ['reasoning'], pool: { status: t('sourceAvailable') } },
2204
- { id: 'claude-3-7-sonnet', contextLabel: '200k', capabilities: ['reasoning'], pool: { status: t('sourceAvailable') } },
2205
- { id: 'claude-3-5-sonnet', contextLabel: '200k', capabilities: ['coding'], pool: { status: t('sourceAvailable') } },
2206
- { id: 'grok-beta', contextLabel: '128k', capabilities: ['fast'], pool: { status: t('sourceAvailable') } },
2207
- { id: 'gemini-2.5-pro', contextLabel: '1M', capabilities: ['vision'], pool: { status: t('sourceAvailable') } },
2208
- { id: 'kimi-k1.5', contextLabel: '128k', capabilities: ['math'], pool: { status: t('sourceAvailable') } },
2209
- { id: 'glm-4-plus', contextLabel: '128k', capabilities: ['chinese'], pool: { status: t('sourceAvailable') } },
2210
- ]).map((m, idx) => {
2311
+ catalogShown.map((m, idx) => {
2211
2312
  const poolStatus = m.pool ? m.pool.status : 'unconfigured'
2212
2313
  const statusClass = 'dsub-model-status-' + poolStatus
2213
2314
  let poolLabel = ''
@@ -2244,6 +2345,17 @@ h('div', { className: 'dsub-row' },
2244
2345
  )
2245
2346
  })
2246
2347
  ),
2348
+ catalogSorted.length === 0 ? h('div', { className: 'dsub-sub', style: { marginTop: 6 } }, t('modelNoMatches')) : null,
2349
+ catalogCounts.shown < catalogSorted.length ? h('div', { className: 'dsub-row', style: { marginTop: 6, gap: 6 } },
2350
+ h('button', {
2351
+ type: 'button', className: 'dsub-mini',
2352
+ onClick: () => setModelLimit((n) => n + 40),
2353
+ }, t('modelShowMore')),
2354
+ h('button', {
2355
+ type: 'button', className: 'dsub-mini',
2356
+ onClick: () => setModelLimit(catalogSorted.length),
2357
+ }, t('modelShowAll')),
2358
+ ) : null,
2247
2359
  ),
2248
2360
  h('details', { className: 'dsub-group', 'data-pane': 'models' },
2249
2361
  h('summary', { className: 'dsub-groupHead' }, '🧠 ' + t('reasoningEffortTitle')),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goodandready/dsh-subscriptions",
3
- "version": "0.7.24",
3
+ "version": "0.7.25",
4
4
  "description": "Use ChatGPT Codex, Claude, Grok, Antigravity, Kimi, GLM, Cursor, Kiro, Copilot, Qwen, ERNIE, Spark, JetBrains, Perplexity, Replit, and Cody subscriptions as DeepSeek Harness LLM providers via OAuth.",
5
5
  "license": "MIT",
6
6
  "type": "module",