dsh-remote-plugin 0.7.2 → 0.7.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/apk/dsh-remote.apk +0 -0
- package/gateway.cjs +313 -18
- package/index.mjs +31 -9
- package/package.json +1 -1
- package/public/app.js +310 -303
- package/public/desktop/desktop.css +101 -0
- package/public/desktop/desktop.html +59 -21
- package/public/desktop/desktop.js +260 -101
- package/public/history.js +160 -0
- package/public/index.html +61 -22
- package/public/link-check.js +109 -0
- package/public/plugin-center.css +11 -0
- package/public/plugin-center.js +92 -39
- package/public/styles.css +107 -2
- package/public/update.json +8 -8
- package/public/version.json +1 -1
|
@@ -52,7 +52,7 @@ themeApply()
|
|
|
52
52
|
|
|
53
53
|
/* ---------------- 状态 ---------------- */
|
|
54
54
|
function emptyDesktopHistory() {
|
|
55
|
-
return { seqs: new Set(), visible: [], hasMore: false, loading: false, minSeq: Infinity, partialReasoning: new Map() }
|
|
55
|
+
return { seqs: new Set(), visible: [], hasMore: false, loading: false, minSeq: Infinity, partialReasoning: new Map(), loaded:false, cached:false, tailEvicted:false }
|
|
56
56
|
}
|
|
57
57
|
const state = {
|
|
58
58
|
token: LS.get('token', ''),
|
|
@@ -114,11 +114,20 @@ for (const key of ['server', 'token']) {
|
|
|
114
114
|
if (next === value) return
|
|
115
115
|
value = next; connectionGeneration++
|
|
116
116
|
state.sessions = []; state.byId.clear(); state.pendingProjections.clear()
|
|
117
|
+
state.hostInfo = null
|
|
118
|
+
if(typeof closeStream==='function'&&typeof streamMeta!=='undefined'){closeStream('mux');closeStream('host')}
|
|
117
119
|
state.current = null; state.history = emptyDesktopHistory()
|
|
118
120
|
state.fs.path = null; state.fs.initial = null; state.fs.loaded = false; state.fs.roots = []; state.fs.rootIndex = 0
|
|
119
121
|
state.workspaces = []; state.archivedIds = []; state.wb = { bound: false, path: '', projects: null }
|
|
120
122
|
window.DshPluginCenter?.close()
|
|
121
123
|
window.DshInsights?.close()
|
|
124
|
+
if(typeof document!=='undefined') {
|
|
125
|
+
const identityGeneration=connectionGeneration
|
|
126
|
+
queueMicrotask(()=>{if(identityGeneration===connectionGeneration&&typeof startOverviewDetection==='function')startOverviewDetection(true,true)})
|
|
127
|
+
document.getElementById('history')?.replaceChildren?.()
|
|
128
|
+
const generation=connectionGeneration
|
|
129
|
+
queueMicrotask(()=>{if(generation!==connectionGeneration)return;if(typeof conversationView!=='undefined')conversationView?.reset();restoreCachedSessionList()})
|
|
130
|
+
}
|
|
122
131
|
if (typeof document !== 'undefined') document.getElementById('modal-workspace')?.classList.add('hidden')
|
|
123
132
|
},
|
|
124
133
|
})
|
|
@@ -302,7 +311,7 @@ function renderModelMenu() {
|
|
|
302
311
|
if (state.models.loading) { box.innerHTML = `<div class="ds-model-head">${t('menu.modelTitle')}</div><span>${t('models.loading')}</span>`; return }
|
|
303
312
|
const groups = state.models.groups || []
|
|
304
313
|
if (!groups.length) {
|
|
305
|
-
box.innerHTML = `<div class="ds-model-head">${t('menu.modelTitle')}</div><span>${(state.models.failures || []).map(f => f.name + ' ' + t('models.unavailable')).join(';') || t('models.none')}</span>`
|
|
314
|
+
box.innerHTML = `<div class="ds-model-head">${t('menu.modelTitle')}</div><span>${(state.models.failures || []).map(f => esc(f.name) + ' ' + t('models.unavailable')).join(';') || t('models.none')}</span>`
|
|
306
315
|
return
|
|
307
316
|
}
|
|
308
317
|
const cur = state.models.current
|
|
@@ -414,6 +423,9 @@ function openFeedbackModal() {
|
|
|
414
423
|
$('fb-msg').value = ''
|
|
415
424
|
$('fb-contact').value = ''
|
|
416
425
|
$('fb-include-diagnostics').checked = false
|
|
426
|
+
$('fb-include-crashes').checked = false
|
|
427
|
+
$('fb-crash-details').open = false
|
|
428
|
+
void loadCrashPreview()
|
|
417
429
|
$('modal-feedback').classList.remove('hidden')
|
|
418
430
|
setTimeout(() => $('fb-msg').focus(), 50)
|
|
419
431
|
}
|
|
@@ -534,11 +546,22 @@ async function checkNotesOnStart() {
|
|
|
534
546
|
openNotesModal(info)
|
|
535
547
|
} catch {}
|
|
536
548
|
}
|
|
549
|
+
async function loadCrashPreview() {
|
|
550
|
+
const connection=captureConnection(),preview=$('fb-crash-preview')
|
|
551
|
+
preview.textContent=t('ds.feedbackCrashLoading')
|
|
552
|
+
try {
|
|
553
|
+
const response=await fetch(apiUrl('/crash-logs'),{headers:{authorization:'Bearer '+connection.token},signal:AbortSignal.timeout(5000),cache:'no-store'})
|
|
554
|
+
if(!response.ok)throw new Error('unavailable')
|
|
555
|
+
const data=await response.json()
|
|
556
|
+
if(connection.valid())preview.textContent=JSON.stringify(data.upload,null,2)
|
|
557
|
+
}catch{if(connection.valid())preview.textContent=t('ds.feedbackCrashUnavailable')}
|
|
558
|
+
}
|
|
537
559
|
async function submitFeedback() {
|
|
538
560
|
const type = document.querySelector('#fb-chips .ds-fb-chip.current')?.dataset.fbType || 'bug'
|
|
539
561
|
const message = $('fb-msg').value.trim()
|
|
540
562
|
const contact = $('fb-contact').value.trim()
|
|
541
563
|
const includeDiagnostics = $('fb-include-diagnostics').checked
|
|
564
|
+
const includeCrashLogs = $('fb-include-crashes').checked
|
|
542
565
|
if (!message) { toast(t('ds.feedbackEmpty'), 'err'); return }
|
|
543
566
|
if (message.length > 2000) { toast(t('ds.feedbackTooLong'), 'err'); return }
|
|
544
567
|
const btn = $('fb-submit')
|
|
@@ -547,7 +570,7 @@ async function submitFeedback() {
|
|
|
547
570
|
const res = await fetch(apiUrl('/feedback'), {
|
|
548
571
|
method: 'POST',
|
|
549
572
|
headers: { 'content-type': 'application/json', authorization: 'Bearer ' + state.token },
|
|
550
|
-
body: JSON.stringify({ type, message, contact, appVersion: '', includeDiagnostics })
|
|
573
|
+
body: JSON.stringify({ type, message, contact, appVersion: '', includeDiagnostics, includeCrashLogs })
|
|
551
574
|
})
|
|
552
575
|
let json = {}
|
|
553
576
|
try { json = await res.json() } catch {}
|
|
@@ -643,6 +666,7 @@ async function safeRpc(method, payload, errText) {
|
|
|
643
666
|
}
|
|
644
667
|
}
|
|
645
668
|
let hostDescribePromise = null
|
|
669
|
+
let hostDescribeConnection = null
|
|
646
670
|
let hostDescribeRetryTimer = null
|
|
647
671
|
let hostDescribeFailures = 0
|
|
648
672
|
|
|
@@ -658,12 +682,13 @@ function scheduleHostDescribeRetryDesktop() {
|
|
|
658
682
|
|
|
659
683
|
async function refreshHostDescriptionDesktop({ notify = false } = {}) {
|
|
660
684
|
if (!state.token) return null
|
|
661
|
-
if (hostDescribePromise) return hostDescribePromise
|
|
662
|
-
const
|
|
663
|
-
|
|
685
|
+
if (hostDescribePromise && hostDescribeConnection?.valid()) return hostDescribePromise
|
|
686
|
+
const connection = captureConnection()
|
|
687
|
+
hostDescribeConnection = connection
|
|
688
|
+
const job = (async () => {
|
|
664
689
|
try {
|
|
665
690
|
const host = await rpc('host.describe', {}, 5000)
|
|
666
|
-
if (
|
|
691
|
+
if (!connection.valid()) return null
|
|
667
692
|
state.hostInfo = host
|
|
668
693
|
const health = activeGatewayHealth()
|
|
669
694
|
if (health) health.upstreamReachable = true
|
|
@@ -673,17 +698,17 @@ async function refreshHostDescriptionDesktop({ notify = false } = {}) {
|
|
|
673
698
|
renderOverviewDesktop()
|
|
674
699
|
return host
|
|
675
700
|
} catch (error) {
|
|
676
|
-
if (
|
|
701
|
+
if (!connection.valid()) return null
|
|
677
702
|
hostDescribeFailures++
|
|
678
703
|
scheduleHostDescribeRetryDesktop()
|
|
679
704
|
if (notify) toast(error.message === 'AUTH' ? t('ds.toastAuth') : error.message, 'err')
|
|
680
705
|
return null
|
|
681
706
|
} finally {
|
|
682
|
-
hostDescribePromise = null
|
|
683
|
-
if (server !== state.server) scheduleHostDescribeRetryDesktop()
|
|
707
|
+
if (hostDescribePromise === job) { hostDescribePromise = null; hostDescribeConnection = null }
|
|
684
708
|
}
|
|
685
709
|
})()
|
|
686
|
-
|
|
710
|
+
hostDescribePromise = job
|
|
711
|
+
return job
|
|
687
712
|
}
|
|
688
713
|
function uuid() {
|
|
689
714
|
try { return crypto.randomUUID() } catch { return 'id-' + Date.now() + '-' + Math.random().toString(36).slice(2) }
|
|
@@ -1192,12 +1217,12 @@ function openStreams() {
|
|
|
1192
1217
|
function openStream(kind, handler, refreshOnOpen, isRestore, ticket = null) {
|
|
1193
1218
|
if (!state.token) return
|
|
1194
1219
|
if (ticket === null) {
|
|
1195
|
-
const token = state.token
|
|
1220
|
+
const token = state.token, connection=captureConnection()
|
|
1196
1221
|
void getWsTicket().then((value) => {
|
|
1197
|
-
if (
|
|
1222
|
+
if (connection.valid()) openStream(kind, handler, refreshOnOpen, isRestore, value)
|
|
1198
1223
|
}).catch(() => {
|
|
1199
1224
|
// 兼容旧网关/插件副本: ticket 接口不可用时临时回退旧 token 握手。
|
|
1200
|
-
if (
|
|
1225
|
+
if (connection.valid()) openStream(kind, handler, refreshOnOpen, isRestore, '')
|
|
1201
1226
|
})
|
|
1202
1227
|
return
|
|
1203
1228
|
}
|
|
@@ -1378,7 +1403,7 @@ window.addEventListener('online', () => {
|
|
|
1378
1403
|
document.addEventListener('visibilitychange', () => {
|
|
1379
1404
|
if (document.visibilityState === 'visible' && state.token &&
|
|
1380
1405
|
(streams.mux?.readyState !== WebSocket.OPEN || streams.host?.readyState !== WebSocket.OPEN)) {
|
|
1381
|
-
|
|
1406
|
+
repairMissingStreams()
|
|
1382
1407
|
}
|
|
1383
1408
|
})
|
|
1384
1409
|
|
|
@@ -1585,7 +1610,11 @@ function sessionLabelOf(s) {
|
|
|
1585
1610
|
function isTopLevelSession(session) {
|
|
1586
1611
|
return !!session && !session.parentSessionId && session.origin !== 'subagent'
|
|
1587
1612
|
}
|
|
1588
|
-
|
|
1613
|
+
// DSH marks sessions created via "new session" but never prompted as blank and hides
|
|
1614
|
+
// them in its own UI; keep the same semantics here so they do not occupy the list,
|
|
1615
|
+
// the workspace tree or the home stats.
|
|
1616
|
+
function isVisibleSession(session) { return isTopLevelSession(session) && !session?.blank }
|
|
1617
|
+
function topLevelSessions() { return state.sessions.filter(isVisibleSession) }
|
|
1589
1618
|
const GOAL_TERMINAL_PHASES = new Set(['complete', 'cleared'])
|
|
1590
1619
|
function isGoalTerminal(goal) {
|
|
1591
1620
|
return !!goal && GOAL_TERMINAL_PHASES.has(goal.phase)
|
|
@@ -1620,6 +1649,7 @@ function onSessionEvent(sessionId, event) {
|
|
|
1620
1649
|
renderSessions()
|
|
1621
1650
|
}
|
|
1622
1651
|
const session = state.byId.get(sessionId)
|
|
1652
|
+
if((event?.type==='session/title'||event?.type==='title')&&event.data?.title&&session){session.projections??={values:{}};session.projections.values??={};session.projections.values.title=event.data.title;if(state.current===sessionId)updateSessionActions()}
|
|
1623
1653
|
if (event?.type === 'agent/status' && session) {
|
|
1624
1654
|
session.running = !!event.data?.running
|
|
1625
1655
|
if (state.current === sessionId) { renderQueue(); updateComposerStatus() }
|
|
@@ -1636,7 +1666,9 @@ function onSessionEvent(sessionId, event) {
|
|
|
1636
1666
|
h.seqs.add(seq)
|
|
1637
1667
|
h.visible.push({ seq, event })
|
|
1638
1668
|
h.visible.sort((a, b) => a.seq - b.seq)
|
|
1669
|
+
trimVisible()
|
|
1639
1670
|
renderHistory()
|
|
1671
|
+
scheduleHistoryCacheSave()
|
|
1640
1672
|
}
|
|
1641
1673
|
if (String(event.type || '').startsWith('goal/') || String(event.type || '').startsWith('todo/')) renderSessionCards()
|
|
1642
1674
|
}
|
|
@@ -1644,6 +1676,7 @@ function onSessionEvent(sessionId, event) {
|
|
|
1644
1676
|
|
|
1645
1677
|
/* ---------------- 会话 ---------------- */
|
|
1646
1678
|
async function refreshSessions() {
|
|
1679
|
+
if(typeof restoreCachedSessionList==='function')restoreCachedSessionList()
|
|
1647
1680
|
const connection = captureConnection(), request = ++sessionsRequest
|
|
1648
1681
|
const v = await safeRpc('session.list', {}, '')
|
|
1649
1682
|
if (!connection.valid() || request !== sessionsRequest) return
|
|
@@ -1651,6 +1684,7 @@ async function refreshSessions() {
|
|
|
1651
1684
|
state.sessions = v.items || []
|
|
1652
1685
|
state.byId = new Map(state.sessions.map(s => [s.sessionId, s]))
|
|
1653
1686
|
applyPendingProjections()
|
|
1687
|
+
try{LS.set(historyCacheScope()+':sessions',JSON.stringify(state.sessions.slice(0,80)))}catch{}
|
|
1654
1688
|
renderSessions()
|
|
1655
1689
|
scheduleWorkbenchRefresh()
|
|
1656
1690
|
renderOverviewDesktop()
|
|
@@ -1771,9 +1805,9 @@ function renderSessions() {
|
|
|
1771
1805
|
}
|
|
1772
1806
|
|
|
1773
1807
|
const emptySessionCleanup = new Set()
|
|
1774
|
-
async function archiveEmptySessionOnLeave(sessionId) {
|
|
1775
|
-
const base = state.server
|
|
1776
|
-
const protectedSession = () => state.server !== base || state.current !== sessionId
|
|
1808
|
+
async function archiveEmptySessionOnLeave(sessionId, leaving = false) {
|
|
1809
|
+
const base = state.server, connection=captureConnection()
|
|
1810
|
+
const protectedSession = () => !connection.valid() || state.server !== base || (!leaving && state.current !== sessionId)
|
|
1777
1811
|
|| !state.byId.has(sessionId) || state.byId.get(sessionId)?.running
|
|
1778
1812
|
|| state.sessionActivity?.has(sessionId) || state.pendingPrompts?.has(sessionId)
|
|
1779
1813
|
|| (state.queues[sessionId] || []).length > 0
|
|
@@ -1794,14 +1828,16 @@ async function archiveEmptySessionOnLeave(sessionId) {
|
|
|
1794
1828
|
}
|
|
1795
1829
|
|
|
1796
1830
|
async function openSession(id) {
|
|
1797
|
-
if (state.current && state.current !== id)
|
|
1831
|
+
if (state.current && state.current !== id) void archiveEmptySessionOnLeave(state.current,true)
|
|
1798
1832
|
state.current = id
|
|
1799
1833
|
setSessionRecovery('loading')
|
|
1800
1834
|
state.history = emptyDesktopHistory()
|
|
1835
|
+
const openingHistory=state.history, openingConnection=captureConnection()
|
|
1801
1836
|
state.models = { loaded: false, loading: false, groups: [], current: null, failures: [] }
|
|
1802
1837
|
showView('view-chat')
|
|
1803
1838
|
$('ds-title').textContent = titleOf(state.byId.get(id)) || t('ds.sessions')
|
|
1804
1839
|
updateSessionActions()
|
|
1840
|
+
getConversationView().reset()
|
|
1805
1841
|
$('history').innerHTML = `<div class="ds-empty">${t('ds.historyLoading')}</div>`
|
|
1806
1842
|
renderSessions()
|
|
1807
1843
|
renderSessionCards()
|
|
@@ -1809,6 +1845,8 @@ async function openSession(id) {
|
|
|
1809
1845
|
renderSessionPendingDesktop()
|
|
1810
1846
|
updateComposerStatus()
|
|
1811
1847
|
void refreshCompactionStatus(id)
|
|
1848
|
+
await restoreCachedHistory()
|
|
1849
|
+
if(state.current!==id||state.history!==openingHistory||!openingConnection.valid())return
|
|
1812
1850
|
await loadHistory()
|
|
1813
1851
|
}
|
|
1814
1852
|
async function closeSession() {
|
|
@@ -1826,53 +1864,112 @@ async function closeSession() {
|
|
|
1826
1864
|
updateSessionActions()
|
|
1827
1865
|
showView('view-sessions')
|
|
1828
1866
|
}
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1867
|
+
|
|
1868
|
+
function restoreCachedSessionList() {
|
|
1869
|
+
if(state.sessions.length)return
|
|
1870
|
+
try{const items=JSON.parse(LS.get(historyCacheScope()+':sessions',''));if(!Array.isArray(items))return;state.sessions=items.filter(item=>typeof item?.sessionId==='string').slice(0,80);state.byId=new Map(state.sessions.map(item=>[item.sessionId,item]));renderSessions()}catch{}
|
|
1871
|
+
}
|
|
1872
|
+
|
|
1873
|
+
let conversationView = null
|
|
1874
|
+
function historyCacheScope() { const hash=new SHA256();hash.update(new TextEncoder().encode(JSON.stringify([state.server||location.origin,state.token])));return 'historyCacheV2:'+hash.hex() }
|
|
1875
|
+
function historySource(value) {
|
|
1876
|
+
state.history.source=value
|
|
1877
|
+
const el=$('history-source')
|
|
1878
|
+
if(el)el.textContent=t(({cache:'ds.historyCached',syncing:'ds.historySyncing',synced:'ds.historySynced',saved:'ds.historySaved',offline:'ds.historyOffline',saveFailed:'ds.historyCacheFailed'})[value]||'ds.historySynced')
|
|
1879
|
+
}
|
|
1880
|
+
function getConversationView() {
|
|
1881
|
+
if(!conversationView)conversationView=new window.DshHistory.HistoryView($('history'),{
|
|
1882
|
+
html:entry=>eventHtml(entry),
|
|
1883
|
+
older:()=>loadHistory(false),olderLabel:()=>t('ds.historyEarlier'),loadingLabel:()=>t('ds.historyLoadingEarlier'),live:partialReasoningHtml,
|
|
1884
|
+
changed:view=>{state.history.renderStart=view.start;state.history.renderEnd=view.end;$('btn-history-latest')?.classList.toggle('hidden',!view.reading&&view.end>=view.entries.length&&!state.history.tailEvicted);},
|
|
1885
|
+
scrolled:()=>{}
|
|
1886
|
+
})
|
|
1887
|
+
return conversationView
|
|
1888
|
+
}
|
|
1889
|
+
function scheduleHistoryCacheSave() {
|
|
1890
|
+
clearTimeout(scheduleHistoryCacheSave._t)
|
|
1891
|
+
const connection=captureConnection(),id=state.current,history=state.history,scope=historyCacheScope()
|
|
1892
|
+
scheduleHistoryCacheSave._t=setTimeout(()=>{if(connection.valid()&&state.current===id&&state.history===history)void saveHistoryCache(scope,id,history)},500)
|
|
1893
|
+
}
|
|
1894
|
+
async function saveHistoryCache(scope=historyCacheScope(),id=state.current,history=state.history) {
|
|
1895
|
+
if(!id||!history.visible.length||history.tailEvicted)return
|
|
1896
|
+
const saved=await window.DshHistory.cacheSave(scope,id,{title:titleOf(state.byId.get(id)),events:history.visible.slice(-250),minSeq:history.visible.slice(-250)[0]?.seq??history.minSeq,hasMore:history.hasMore||history.visible.length>250,partialReasoning:[...history.partialReasoning.values()]})
|
|
1897
|
+
if(!saved&&state.current===id&&state.history===history&&scope===historyCacheScope())historySource('saveFailed')
|
|
1898
|
+
if(saved&&state.current===id&&state.history===history&&scope===historyCacheScope()&&['synced','saveFailed'].includes(history.source))historySource('saved')
|
|
1899
|
+
}
|
|
1900
|
+
async function restoreCachedHistory() {
|
|
1901
|
+
const connection=captureConnection(),id=state.current,history=state.history,scope=historyCacheScope()
|
|
1902
|
+
if(!id)return false
|
|
1903
|
+
const cached=await window.DshHistory.cacheLoad(scope,id,legacyId=>window.DshHistory.decodeLegacy(LS.get(scope,''),legacyId))
|
|
1904
|
+
if(!connection.valid()||state.current!==id||state.history!==history||!cached?.events?.length)return false
|
|
1905
|
+
history.visible=cached.events.slice(-250).filter(entry=>entry?.seq!=null&&shouldShowEvent(entry.event?.type,entry.event)).sort((a,b)=>a.seq-b.seq)
|
|
1906
|
+
history.seqs=new Set(history.visible.map(entry=>entry.seq));history.loaded=true;history.cached=true;history.hasMore=cached.events.length>250||cached.hasMore!==false;history.minSeq=cached.events.length>250?(history.visible[0]?.seq??Infinity):Number.isFinite(cached.minSeq)?cached.minSeq:history.visible[0]?.seq??Infinity
|
|
1907
|
+
if(cached.title&&!hasSessionTitle(state.byId.get(id)))hydrateSessionProjections(id,{values:{title:cached.title},asOfSeq:0})
|
|
1908
|
+
applyReasoningBaseline(cached.partialReasoning||[]);historySource('cache');setSessionRecovery('cached');renderHistory(true)
|
|
1909
|
+
return true
|
|
1910
|
+
}
|
|
1911
|
+
function trimVisible(direction='tail') {
|
|
1912
|
+
const h=state.history,excess=h.visible.length-5000
|
|
1913
|
+
if(excess<=0)return
|
|
1914
|
+
const older=direction==='older'||conversationView?.reading
|
|
1915
|
+
const removed=older?h.visible.splice(5000):h.visible.splice(0,excess)
|
|
1916
|
+
for(const entry of removed)h.seqs.delete(entry.seq)
|
|
1917
|
+
if(older)h.tailEvicted=true
|
|
1918
|
+
else{h.minSeq=h.visible[0]?.seq??Infinity;h.headEvicted=true;h.hasMore=true}
|
|
1919
|
+
}
|
|
1920
|
+
|
|
1921
|
+
async function loadHistory(reset = true) {
|
|
1922
|
+
const connection=captureConnection(),id=state.current,history=state.history
|
|
1923
|
+
if(!id||history.loading||(!reset&&Date.now()<(history.retryAfter||0)))return
|
|
1924
|
+
const reasoningVersion=history.reasoningVersion||0,hadContent=history.visible.length>0
|
|
1925
|
+
history.loading=true
|
|
1926
|
+
if(reset){if(hadContent)historySource('syncing');else setSessionRecovery('loading')}
|
|
1927
|
+
const payload={sessionId:id,maxMessages:60}
|
|
1928
|
+
if(!reset&&Number.isFinite(history.minSeq))payload.beforeSeq=history.minSeq
|
|
1929
|
+
getConversationView().more.disabled=true
|
|
1930
|
+
getConversationView().more.textContent=getConversationView().options.loadingLabel()
|
|
1837
1931
|
let v
|
|
1838
|
-
try
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
if
|
|
1843
|
-
setSessionRecovery('error',
|
|
1844
|
-
$('history').innerHTML
|
|
1932
|
+
try{v=await rpc('session.history',payload)}catch(error){
|
|
1933
|
+
if(!connection.valid()||state.current!==id||state.history!==history)return
|
|
1934
|
+
history.loading=false;history.retryAfter=Date.now()+1500
|
|
1935
|
+
if(error.message==='AUTH'){return}
|
|
1936
|
+
if(hadContent){historySource('offline');setSessionRecovery('cached',error.message);renderHistory(false,'fixed');return}
|
|
1937
|
+
setSessionRecovery('error',error.message)
|
|
1938
|
+
$('history').innerHTML='<div class="history-empty">'+esc(error.message)+'</div>'
|
|
1939
|
+
const retry=document.createElement('button');retry.type='button';retry.className='history-page-control';retry.textContent=t('ds.historyRetry');retry.addEventListener('click',()=>{void loadHistory(true)});$('history').append(retry)
|
|
1845
1940
|
return
|
|
1846
1941
|
}
|
|
1847
|
-
if
|
|
1848
|
-
const liveReasoning
|
|
1849
|
-
hydrateSessionProjections(id,
|
|
1942
|
+
if(!connection.valid()||state.current!==id||state.history!==history)return
|
|
1943
|
+
const liveReasoning=(history.reasoningVersion||0)!==reasoningVersion?new Map(history.partialReasoning):null
|
|
1944
|
+
hydrateSessionProjections(id,v.projections);history.loaded=true
|
|
1945
|
+
const incoming=v.events||[],prepared=[]
|
|
1850
1946
|
for (const entry of v.events || []) {
|
|
1851
|
-
const ev
|
|
1852
|
-
const seq = ev?.seq
|
|
1853
|
-
if (ev?.type === 'turn/start' || ev?.type === 'turn/end') noteSessionTurnTime(id, ev)
|
|
1947
|
+
const ev=entry?.event
|
|
1854
1948
|
applyReasoningStreamEvent(ev)
|
|
1855
|
-
if
|
|
1856
|
-
if
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
setSessionRecovery('ready')
|
|
1866
|
-
updateSessionActions()
|
|
1867
|
-
renderHistory()
|
|
1949
|
+
if(ev?.type==='turn/start'||ev?.type==='turn/end')noteSessionTurnTime(id,ev)
|
|
1950
|
+
if(ev?.seq==null||!shouldShowEvent(ev.type,ev))continue
|
|
1951
|
+
prepared.push({seq:ev.seq,event:ev,view:entry.view})
|
|
1952
|
+
}
|
|
1953
|
+
const rawSeqs=incoming.map(entry=>entry?.event?.seq).filter(Number.isFinite),floor=rawSeqs.length?Math.min(...rawSeqs):Infinity
|
|
1954
|
+
if(reset){const retainedOlder=!!v.hasMore&&history.visible.some(entry=>entry.seq<floor);const ceiling=rawSeqs.length?Math.max(...rawSeqs)+1:Infinity;history.visible=rawSeqs.length?window.DshHistory.reconcile(history.visible,prepared,floor,!!v.hasMore,ceiling):[];history.minSeq=retainedOlder?Math.min(history.minSeq,floor):floor;history.tailEvicted=false}
|
|
1955
|
+
else{history.visible=window.DshHistory.reconcile(history.visible,prepared,floor,true,payload.beforeSeq);history.minSeq=Math.min(history.minSeq,floor)}
|
|
1956
|
+
history.seqs=new Set(history.visible.map(entry=>entry.seq));history.headEvicted=false;trimVisible(reset?'tail':'older')
|
|
1957
|
+
if(liveReasoning)history.partialReasoning=liveReasoning;else applyReasoningBaseline(v.partialReasoning)
|
|
1958
|
+
history.hasMore=(!!v.hasMore||(reset&&history.headEvicted)) && rawSeqs.length>0 && (reset || floor<payload.beforeSeq)
|
|
1959
|
+
history.loading=false;history.cached=false;historySource('synced');setSessionRecovery('ready')
|
|
1960
|
+
updateSessionActions();renderSessionCards()
|
|
1961
|
+
renderHistory(!hadContent,reset?'fixed':'keep')
|
|
1962
|
+
|
|
1963
|
+
scheduleHistoryCacheSave()
|
|
1868
1964
|
}
|
|
1869
1965
|
|
|
1966
|
+
|
|
1870
1967
|
const INTERESTING_EVENTS = new Set([
|
|
1871
1968
|
'user/message', 'assistant/message', 'tool/call', 'tool/result',
|
|
1872
1969
|
'agent/status', 'checkpoint/created', 'compaction/complete', 'compaction/summary',
|
|
1873
1970
|
'goal/created', 'goal/updated', 'goal/completed', 'goal/cleared',
|
|
1874
1971
|
'todo/updated', 'plan/updated', 'question/asked', 'question/resolved',
|
|
1875
|
-
'approval/asked', 'approval/resolved'
|
|
1972
|
+
'approval/asked', 'approval/resolved'
|
|
1876
1973
|
])
|
|
1877
1974
|
function messageSource(data) {
|
|
1878
1975
|
const source = data?.source ?? data?.message?.source
|
|
@@ -1997,12 +2094,8 @@ function eventHtml(entry) {
|
|
|
1997
2094
|
if (type === 'question/asked') return `<div class="ds-tool">❓ ${esc(data.question || '')}</div>`
|
|
1998
2095
|
return `<div class="ds-tool">${esc(type)}</div>`
|
|
1999
2096
|
}
|
|
2000
|
-
function renderHistory() {
|
|
2001
|
-
|
|
2002
|
-
const items = state.history.visible
|
|
2003
|
-
const html = items.map(eventHtml).join('') + partialReasoningHtml()
|
|
2004
|
-
box.innerHTML = html || `<div class="ds-empty">${t('ds.historyEmpty')}</div>`
|
|
2005
|
-
box.scrollTop = box.scrollHeight
|
|
2097
|
+
function renderHistory(reset=false, mode='auto') {
|
|
2098
|
+
getConversationView().set(state.history.visible,{reset,follow:mode==='bottom',live:partialReasoningHtml(),hasMore:state.history.hasMore,loading:state.history.loading,emptyLabel:t('ds.historyEmpty')})
|
|
2006
2099
|
}
|
|
2007
2100
|
|
|
2008
2101
|
/* ---------------- 会话信息卡(goal / todo / 子代理) ---------------- */
|
|
@@ -2888,7 +2981,7 @@ function renderWorkbench() {
|
|
|
2888
2981
|
let html = `<div class="ds-wb-panel-title">${esc(t('wb.projects'))}</div>`
|
|
2889
2982
|
html += projects.length ? projects.map(w => {
|
|
2890
2983
|
const id = String(w.workspaceId || '')
|
|
2891
|
-
const sessions = orderedWorkspaceSessions(id, (w.sessionIds || []).map(sid => state.byId.get(sid)).filter(
|
|
2984
|
+
const sessions = orderedWorkspaceSessions(id, (w.sessionIds || []).map(sid => state.byId.get(sid)).filter(isVisibleSession).filter(s => !archivedSet.has(s.sessionId)).sort((a, b) => sessionSortTime(b) - sessionSortTime(a)))
|
|
2892
2985
|
const open = state.wb.open === id
|
|
2893
2986
|
return `<div class="ds-wb-project ${open ? 'open' : ''}" data-wb-project="${esc(id)}" data-motion-key="${esc(id)}">
|
|
2894
2987
|
<button type="button" class="ds-wb-project-head" data-wb-head="${esc(id)}">
|
|
@@ -3133,35 +3226,88 @@ function renderStats(days) {
|
|
|
3133
3226
|
}
|
|
3134
3227
|
|
|
3135
3228
|
/* ---------------- 视图与连接状态 ---------------- */
|
|
3229
|
+
let overviewDetector = null
|
|
3230
|
+
let overviewPulse = null
|
|
3231
|
+
function setOverviewText(id,value){const node=$(id);if(overviewPulse)overviewPulse.text(node,value);else if(node)node.textContent=value}
|
|
3232
|
+
let overviewStarting = true
|
|
3233
|
+
function overviewChecks() {
|
|
3234
|
+
const confirmed=overviewDetector?.model.gateway===true,health=activeGatewayHealth()
|
|
3235
|
+
return {
|
|
3236
|
+
gateway: !!state.token && (!!state.server || /^https?:$/.test(location.protocol)) && confirmed,
|
|
3237
|
+
dsh: dshReachable() && confirmed,
|
|
3238
|
+
mux: !!state.streamsOk?.mux && confirmed && health?.events?.mux?.connected!==false,
|
|
3239
|
+
host: !!state.streamsOk?.host && confirmed && health?.events?.host?.connected!==false
|
|
3240
|
+
}
|
|
3241
|
+
}
|
|
3242
|
+
function repairMissingStreams() {
|
|
3243
|
+
if(!state.token||!navigator.onLine||state.selectingServer||overviewStarting)return
|
|
3244
|
+
if(state.streamMode==='poll'){tryRestoreWs();return}
|
|
3245
|
+
for(const [kind,handler,refresh] of [['mux',onMuxFrame,true],['host',onHostFrame,false]]) {
|
|
3246
|
+
const ws=streams[kind]
|
|
3247
|
+
if((!ws||ws.readyState===WebSocket.CLOSED)&&!streamMeta[kind].retryTimer)openStream(kind,handler,refresh)
|
|
3248
|
+
}
|
|
3249
|
+
}
|
|
3250
|
+
async function probeOverviewLinks(signal) {
|
|
3251
|
+
const connection=captureConnection(),base=String(connection.server||location.origin).replace(/\/+$/,'')
|
|
3252
|
+
let timer
|
|
3253
|
+
const controller=new AbortController(),cancel=()=>controller.abort()
|
|
3254
|
+
signal.addEventListener('abort',cancel,{once:true});if(signal.aborted)controller.abort()
|
|
3255
|
+
timer=setTimeout(cancel,4000)
|
|
3256
|
+
const healthRequest=fetch(base+'/health?t='+Date.now(),{signal:controller.signal,cache:'no-store'}).then(async response=>{
|
|
3257
|
+
if(!response.ok)throw Error('health')
|
|
3258
|
+
const health=await response.json();if(health?.ok!==true)throw Error('health')
|
|
3259
|
+
return health
|
|
3260
|
+
}).catch(()=>null).finally(()=>{clearTimeout(timer);signal.removeEventListener('abort',cancel)})
|
|
3261
|
+
const [health,host]=await Promise.all([healthRequest,refreshHostDescriptionDesktop()])
|
|
3262
|
+
if(!connection.valid()||signal.aborted)throw Error('stale check')
|
|
3263
|
+
if(health){if(host)health.upstreamReachable=true;state.gatewayHealth[base]=health}
|
|
3264
|
+
else delete state.gatewayHealth[base]
|
|
3265
|
+
return {gateway:!!health}
|
|
3266
|
+
}
|
|
3267
|
+
function startOverviewDetection(force=false,identityChanged=false) {
|
|
3268
|
+
if(identityChanged)overviewDetector?.pause()
|
|
3269
|
+
if(!window.DshLinkCheck)return
|
|
3270
|
+
if(!overviewDetector)overviewDetector=new window.DshLinkCheck.LinkCheck({
|
|
3271
|
+
active:()=>document.visibilityState==='visible'&&!$('view-overview').classList.contains('hidden'),
|
|
3272
|
+
configured:()=>!!state.token&&(!!state.server||/^https?:$/.test(location.protocol)),online:()=>navigator.onLine,
|
|
3273
|
+
snapshot:overviewChecks,repair:repairMissingStreams,probe:probeOverviewLinks,changed:renderOverviewDesktop
|
|
3274
|
+
})
|
|
3275
|
+
overviewDetector.start(force)
|
|
3276
|
+
}
|
|
3277
|
+
window.addEventListener('online',()=>startOverviewDetection(true))
|
|
3278
|
+
window.addEventListener('offline',()=>startOverviewDetection(true))
|
|
3279
|
+
document.addEventListener('visibilitychange',()=>{if(document.visibilityState==='visible')startOverviewDetection(true);else {overviewDetector?.pause();overviewPulse?.pause()}})
|
|
3280
|
+
|
|
3136
3281
|
function renderOverviewDesktop() {
|
|
3137
3282
|
const ring = $('ds-overview-pulse-ring')
|
|
3138
3283
|
if (!ring) return
|
|
3139
|
-
const checks =
|
|
3140
|
-
|
|
3141
|
-
gateway: !!state.token && (!!state.server || /^https?:$/.test(location.protocol)),
|
|
3142
|
-
dsh: dshReachable(),
|
|
3143
|
-
mux: !!state.streamsOk?.mux,
|
|
3144
|
-
host: !!state.streamsOk?.host
|
|
3145
|
-
}
|
|
3284
|
+
const checks = overviewChecks()
|
|
3285
|
+
const detection=overviewDetector?.model,checking=detection?.phase==='checking'||(detection?.phase==='degraded'&&detection?.probing===true)
|
|
3146
3286
|
const online = Object.values(checks).filter(Boolean).length
|
|
3287
|
+
$('ds-overview-refresh').disabled=detection?.probing===true
|
|
3147
3288
|
const status = online === 4 ? 'Nominal' : online > 0 ? 'Degraded' : 'Offline'
|
|
3148
3289
|
const pulseCard = document.querySelector('.ds-overview-pulse-card')
|
|
3149
3290
|
if (pulseCard) {
|
|
3291
|
+
if(!overviewPulse&&window.DshLinkCheck?.PulseVisual)overviewPulse=new window.DshLinkCheck.PulseVisual({card:pulseCard,active:()=>document.visibilityState==='visible'&&!$('view-overview').classList.contains('hidden')})
|
|
3292
|
+
overviewPulse?.setChecking(checking)
|
|
3293
|
+
overviewPulse?.setLinks(checks)
|
|
3150
3294
|
pulseCard.classList.remove('status-nominal', 'status-degraded', 'status-offline')
|
|
3295
|
+
pulseCard.classList.toggle('status-checking',checking)
|
|
3296
|
+
pulseCard.setAttribute('aria-busy',String(checking))
|
|
3151
3297
|
pulseCard.classList.add('status-' + status.toLowerCase())
|
|
3152
3298
|
}
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
$('ds-overview-status-desc').textContent = t('ds.components', { n: online })
|
|
3299
|
+
setOverviewText('ds-overview-health',checking ? t('ds.checking') : online === 4 ? t('ds.live') : online ? `${online}/4` : t('ds.offlineCore'))
|
|
3300
|
+
setOverviewText('ds-overview-health-caption',checking ? `${online}/4` : online === 4 ? t('ds.allLinked') : online ? t('ds.confirmedShort') : t('ds.offlineShort'))
|
|
3301
|
+
setOverviewText('ds-overview-status',checking ? t('ds.checking') : t(`ds.system${status}`))
|
|
3302
|
+
setOverviewText('ds-overview-status-desc',checking ? t('ds.autoChecking',{n:online}) : detection?.phase==='degraded' ? t('ds.autoRetry',{n:online}) : t('ds.components',{n:online}))
|
|
3158
3303
|
for (const [name, ok] of Object.entries(checks)) {
|
|
3159
3304
|
const item = document.querySelector(`[data-ds-overview-link="${name}"]`)
|
|
3160
3305
|
if (!item) continue
|
|
3161
3306
|
item.classList.toggle('ok', ok)
|
|
3162
|
-
item.classList.toggle('off', !ok)
|
|
3307
|
+
item.classList.toggle('off', !ok&&!checking)
|
|
3308
|
+
item.classList.toggle('pending',!ok&&checking)
|
|
3163
3309
|
const value = item.querySelector('b')
|
|
3164
|
-
if (value) value.
|
|
3310
|
+
if (value) setOverviewText(value.id || (value.id=`ds-overview-link-${name}`), ok ? t('ds.online') : checking ? t('ds.checkingShort') : t('ds.offlineShort'))
|
|
3165
3311
|
}
|
|
3166
3312
|
|
|
3167
3313
|
const pending = [
|
|
@@ -3233,19 +3379,28 @@ function setMobileSidebar(open) {
|
|
|
3233
3379
|
$('ds-app')?.classList.toggle('mobile-nav-open', visible)
|
|
3234
3380
|
}
|
|
3235
3381
|
|
|
3382
|
+
function openDesktopPlugins() {
|
|
3383
|
+
const connection=captureConnection()
|
|
3384
|
+
if(!connection.token){$('desktop-plugin-page').textContent=t('ds.toastAuth');return}
|
|
3385
|
+
window.DshPluginCenter.mount({url:path=>connection.server+path,headers:{authorization:'Bearer '+connection.token,'x-dsh-remote-client':'web',...clientIdHeaders()},valid:connection.valid},$('desktop-plugin-page'))
|
|
3386
|
+
}
|
|
3387
|
+
|
|
3236
3388
|
function showView(id) {
|
|
3237
3389
|
if (state.view === 'view-chat' && id !== 'view-chat' && state.current) void archiveEmptySessionOnLeave(state.current)
|
|
3238
3390
|
state.view = id
|
|
3239
|
-
for (const v of ['view-overview', 'view-sessions', 'view-chat', 'view-files', 'view-settings']) $(v).classList.toggle('hidden', v !== id)
|
|
3391
|
+
for (const v of ['view-overview', 'view-sessions', 'view-chat', 'view-files', 'view-plugins', 'view-settings']) $(v).classList.toggle('hidden', v !== id)
|
|
3240
3392
|
document.querySelectorAll('.ds-nav-item').forEach(b => b.classList.toggle('active', b.dataset.view === id))
|
|
3241
3393
|
if (narrowSidebarQuery.matches) setMobileSidebar(false)
|
|
3242
3394
|
window.DshMotion?.view($(id))
|
|
3243
|
-
const titles = { 'view-overview': 'ds.overview', 'view-sessions': 'ds.sessions', 'view-chat': 'ds.sessions', 'view-files': 'ds.files', 'view-settings': 'ds.settings' }
|
|
3395
|
+
const titles = { 'view-overview': 'ds.overview', 'view-sessions': 'ds.sessions', 'view-chat': 'ds.sessions', 'view-files': 'ds.files', 'view-settings': 'ds.settings', 'view-plugins': 'ds.plugins' }
|
|
3244
3396
|
if (id === 'view-chat') { const s = state.byId.get(state.current); $('ds-title').textContent = s ? titleOf(s) : t('ds.sessions') }
|
|
3245
3397
|
else $('ds-title').textContent = t(titles[id])
|
|
3246
|
-
if (id === 'view-overview') renderOverviewDesktop()
|
|
3398
|
+
if (id === 'view-overview') {startOverviewDetection(true);renderOverviewDesktop()}
|
|
3399
|
+
else {overviewDetector?.pause();overviewPulse?.pause()}
|
|
3247
3400
|
if (id === 'view-files' && !state.fs.loaded) loadFs(null, true)
|
|
3248
3401
|
if (id === 'view-settings') showSettingsHome()
|
|
3402
|
+
if (id === 'view-plugins') openDesktopPlugins()
|
|
3403
|
+
else window.DshPluginCenter?.close()
|
|
3249
3404
|
updateSessionActions()
|
|
3250
3405
|
}
|
|
3251
3406
|
|
|
@@ -3254,9 +3409,14 @@ function updateSessionActions() {
|
|
|
3254
3409
|
$('btn-rename-session')?.classList.toggle('hidden', !active)
|
|
3255
3410
|
$('btn-archive-session')?.classList.toggle('hidden', !active || state.archivedIds.includes(state.current))
|
|
3256
3411
|
$('ds-session-status')?.classList.toggle('hidden', !active || !recoveryLabel())
|
|
3412
|
+
if (!active) $('ds-workspace')?.classList.add('hidden')
|
|
3257
3413
|
if (active) {
|
|
3258
3414
|
const s = state.byId.get(state.current)
|
|
3259
3415
|
$('ds-title').textContent = s ? titleOf(s) : t('ds.sessions')
|
|
3416
|
+
const workspace = s?.cwd || ''
|
|
3417
|
+
$('ds-workspace').textContent = '📁 ' + (workspace.replace(/[\\/]+$/, '').split(/[\\/]/).pop() || t('ds.noWorkspace')) + ' ›'
|
|
3418
|
+
$('ds-workspace').title = workspace
|
|
3419
|
+
$('ds-workspace').classList.remove('hidden')
|
|
3260
3420
|
$('ds-session-status').textContent = recoveryLabel()
|
|
3261
3421
|
}
|
|
3262
3422
|
const running = !!state.byId.get(state.current)?.running || (state.queues[state.current] || []).some(i => i.placement !== 'context')
|
|
@@ -3278,6 +3438,7 @@ function showSettingsPage(name) {
|
|
|
3278
3438
|
if (name === 'general') renderPresetSummary()
|
|
3279
3439
|
}
|
|
3280
3440
|
function updateConn() {
|
|
3441
|
+
overviewDetector?.observe()
|
|
3281
3442
|
const el = $('conn-badge')
|
|
3282
3443
|
// 双实时通道可能按任意顺序打开,连接刷新必须同时刷新系统总览。
|
|
3283
3444
|
renderOverviewDesktop()
|
|
@@ -3323,7 +3484,23 @@ function updateConn() {
|
|
|
3323
3484
|
}
|
|
3324
3485
|
|
|
3325
3486
|
/* ---------------- 初始化 ---------------- */
|
|
3487
|
+
|
|
3488
|
+
function bindSessionDialogs() {
|
|
3489
|
+
const actions=$('session-actions'), info=$('session-info');
|
|
3490
|
+
$('btn-session-more').addEventListener('click',()=>actions.showModal());
|
|
3491
|
+
actions.addEventListener('click',e=>{if(e.target===actions)actions.close();else if(e.target.closest('button'))actions.close()},true);
|
|
3492
|
+
const openInfo=()=>{const s=state.byId.get(state.current);if(!s)return; $('session-info-name').textContent=titleOf(s);$('session-info-path').textContent=s.cwd||t('ds.noWorkspace');$('session-info-id').textContent=s.sessionId;$('btn-copy-session-workspace').disabled=!s.cwd;info.showModal()};
|
|
3493
|
+
$('ds-title').addEventListener('click',openInfo);
|
|
3494
|
+
$('ds-workspace').addEventListener('click',openInfo);
|
|
3495
|
+
$('btn-session-info').addEventListener('click',openInfo);
|
|
3496
|
+
info.addEventListener('click',e=>{if(e.target===info||e.target.closest('[data-session-dialog-close]'))info.close()});
|
|
3497
|
+
$('btn-copy-session-workspace').addEventListener('click',async()=>{const value=state.byId.get(state.current)?.cwd;if(value&&await copyText(value))toast(t('ds.copied'),'ok')});
|
|
3498
|
+
}
|
|
3499
|
+
|
|
3326
3500
|
function bindUi() {
|
|
3501
|
+
bindSessionDialogs()
|
|
3502
|
+
getConversationView()
|
|
3503
|
+
$('btn-history-latest').addEventListener('click',()=>{getConversationView().latest();if(state.history.tailEvicted)void loadHistory(true)})
|
|
3327
3504
|
$('btn-new-session').addEventListener('click', openNewSessionModal)
|
|
3328
3505
|
$('btn-new-workspace').addEventListener('click', openWorkspaceModal)
|
|
3329
3506
|
$('session-sort')?.addEventListener('change', (e) => {
|
|
@@ -3341,14 +3518,7 @@ function bindUi() {
|
|
|
3341
3518
|
}
|
|
3342
3519
|
})
|
|
3343
3520
|
document.querySelectorAll('.ds-nav-item').forEach(b => b.addEventListener('click', () => showView(b.dataset.view)))
|
|
3344
|
-
$('ds-overview-refresh').addEventListener('click',
|
|
3345
|
-
toast(t('ds.loading'))
|
|
3346
|
-
if (state.token) {
|
|
3347
|
-
await refreshSessions()
|
|
3348
|
-
await refreshHostDescriptionDesktop({ notify: true })
|
|
3349
|
-
}
|
|
3350
|
-
renderOverviewDesktop()
|
|
3351
|
-
})
|
|
3521
|
+
$('ds-overview-refresh').addEventListener('click',()=>{startOverviewDetection(true);if(state.token)void refreshSessions()})
|
|
3352
3522
|
$('ds-overview-primary-action').addEventListener('click', () => {
|
|
3353
3523
|
const button = $('ds-overview-primary-action')
|
|
3354
3524
|
const action = button.dataset.dsOverviewAction
|
|
@@ -3576,24 +3746,13 @@ async function start() {
|
|
|
3576
3746
|
checkNotesOnStart()
|
|
3577
3747
|
if (state.token) {
|
|
3578
3748
|
await selectFastestServer({ silent: true, reconnect: false })
|
|
3749
|
+
overviewStarting=false
|
|
3579
3750
|
openStreams()
|
|
3580
|
-
await refreshSessions()
|
|
3581
|
-
await refreshHostDescriptionDesktop()
|
|
3751
|
+
await Promise.all([refreshSessions(),refreshHostDescriptionDesktop()])
|
|
3582
3752
|
refreshWorkbench({ silent: true })
|
|
3583
3753
|
}
|
|
3754
|
+
overviewStarting=false
|
|
3584
3755
|
renderOverviewDesktop()
|
|
3585
3756
|
}
|
|
3586
3757
|
|
|
3587
3758
|
start()
|
|
3588
|
-
|
|
3589
|
-
// Capture the connection so switching servers cannot redirect a plugin mutation.
|
|
3590
|
-
document.getElementById('btn-plugin-center')?.addEventListener('click', () => {
|
|
3591
|
-
const connection = captureConnection()
|
|
3592
|
-
const server = connection.server || ''
|
|
3593
|
-
const token = connection.token
|
|
3594
|
-
window.DshPluginCenter.open({
|
|
3595
|
-
url: path => server + path,
|
|
3596
|
-
headers: { authorization: 'Bearer ' + token, 'x-dsh-remote-client': 'web', ...clientIdHeaders() },
|
|
3597
|
-
valid: connection.valid,
|
|
3598
|
-
})
|
|
3599
|
-
})
|