@linxin666/dsh-remote-web-ui 0.3.5 → 0.3.9
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.i18n.yaml +2 -2
- package/README.md +77 -468
- package/README.zh.md +83 -113
- package/lib/client.js +955 -203
- package/lib/client.js.map +1 -1
- package/lib/index.js +1136 -1466
- package/lib/types/client/FooterRemoteEntry.d.ts +6 -7
- package/lib/types/client/FooterRemoteEntry.d.ts.map +1 -1
- package/lib/types/client/FooterRemoteEntry.js +1 -1
- package/lib/types/client/RemoteEntry.d.ts +7 -4
- package/lib/types/client/RemoteEntry.d.ts.map +1 -1
- package/lib/types/client/RemoteEntry.js +7 -10
- package/lib/types/client/RemotePanel.d.ts +2 -2
- package/lib/types/client/RemotePanel.d.ts.map +1 -1
- package/lib/types/client/RemotePanel.js +2 -2
- package/lib/types/client/RemoteSettingsCard.d.ts +9 -5
- package/lib/types/client/RemoteSettingsCard.d.ts.map +1 -1
- package/lib/types/client/RemoteSettingsCard.js +56 -3
- package/lib/types/client/deep-link.d.ts +10 -13
- package/lib/types/client/deep-link.d.ts.map +1 -1
- package/lib/types/client/deep-link.js +14 -74
- package/lib/types/client/index.d.ts +2 -6
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/index.js +73 -39
- package/lib/types/client/locales.d.ts +26 -12
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/client/locales.js +36 -22
- package/lib/types/client/mobile-adapt.d.ts +40 -0
- package/lib/types/client/mobile-adapt.d.ts.map +1 -0
- package/lib/types/client/mobile-adapt.js +967 -0
- package/lib/types/client/pair-api.d.ts +24 -6
- package/lib/types/client/pair-api.d.ts.map +1 -1
- package/lib/types/client/pair-api.js +9 -14
- package/lib/types/client/remote-channel.d.ts +3 -0
- package/lib/types/client/remote-channel.d.ts.map +1 -1
- package/lib/types/client/remote-channel.js +35 -3
- package/lib/types/client/settings-form.d.ts +35 -43
- package/lib/types/client/settings-form.d.ts.map +1 -1
- package/lib/types/client/settings-form.js +60 -53
- package/lib/types/firewall.d.ts +75 -0
- package/lib/types/firewall.d.ts.map +1 -0
- package/lib/types/firewall.js +184 -0
- package/lib/types/gate.d.ts +11 -5
- package/lib/types/gate.d.ts.map +1 -1
- package/lib/types/gate.js +11 -5
- package/lib/types/index.d.ts +39 -10
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +206 -58
- package/lib/types/inner-auth.d.ts +32 -0
- package/lib/types/inner-auth.d.ts.map +1 -0
- package/lib/types/inner-auth.js +72 -0
- package/lib/types/lan-bind-plan.d.ts +55 -0
- package/lib/types/lan-bind-plan.d.ts.map +1 -0
- package/lib/types/lan-bind-plan.js +60 -0
- package/lib/types/lan-bind.d.ts +69 -0
- package/lib/types/lan-bind.d.ts.map +1 -0
- package/lib/types/lan-bind.js +128 -0
- package/lib/types/loopback-proxy.d.ts +9 -2
- package/lib/types/loopback-proxy.d.ts.map +1 -1
- package/lib/types/loopback-proxy.js +24 -2
- package/lib/types/pairing.d.ts +15 -3
- package/lib/types/pairing.d.ts.map +1 -1
- package/lib/types/pairing.js +20 -6
- package/lib/types/remote-api.d.ts +30 -13
- package/lib/types/remote-api.d.ts.map +1 -1
- package/lib/types/remote-api.js +55 -42
- package/lib/types/remote-channel-boot.d.ts +21 -2
- package/lib/types/remote-channel-boot.d.ts.map +1 -1
- package/lib/types/remote-channel-boot.js +65 -3
- package/lib/types/remote-channel-rules.d.ts +8 -0
- package/lib/types/remote-channel-rules.d.ts.map +1 -1
- package/lib/types/remote-channel-rules.js +9 -2
- package/lib/types/remote-methods.d.ts +45 -11
- package/lib/types/remote-methods.d.ts.map +1 -1
- package/lib/types/remote-methods.js +56 -27
- package/lib/types/remote-presence-pet.d.ts +51 -0
- package/lib/types/remote-presence-pet.d.ts.map +1 -0
- package/lib/types/remote-presence-pet.js +101 -0
- package/lib/types/routes.d.ts +76 -4
- package/lib/types/routes.d.ts.map +1 -1
- package/lib/types/routes.js +336 -19
- package/lib/types/tunnel.d.ts.map +1 -1
- package/lib/types/tunnel.js +7 -1
- package/package.json +20 -18
- package/src/client/FooterRemoteEntry.tsx +9 -10
- package/src/client/RemoteEntry.tsx +13 -14
- package/src/client/RemotePanel.tsx +5 -16
- package/src/client/RemoteSettingsCard.tsx +72 -13
- package/src/client/deep-link.ts +14 -75
- package/src/client/index.ts +77 -39
- package/src/client/locales.ts +36 -22
- package/src/client/mobile-adapt.ts +913 -0
- package/src/client/pair-api.ts +26 -15
- package/src/client/remote-channel.ts +31 -3
- package/src/client/settings-form.ts +78 -92
- package/src/dsh-home.ts +1 -1
- package/src/firewall.ts +230 -0
- package/src/gate.ts +11 -5
- package/src/index.ts +235 -65
- package/src/inner-auth.ts +85 -0
- package/src/lan-bind-plan.ts +81 -0
- package/src/lan-bind.ts +145 -0
- package/src/loopback-proxy.ts +34 -0
- package/src/pairing.persist.test.ts +1 -1
- package/src/pairing.ts +20 -6
- package/src/remote-api.ts +67 -45
- package/src/remote-channel-boot.ts +70 -3
- package/src/remote-channel-rules.ts +17 -2
- package/src/remote-methods.ts +58 -27
- package/src/remote-presence-pet.ts +129 -0
- package/src/routes.ts +358 -19
- package/src/tunnel.ts +7 -1
- package/assets/apple-touch-icon.png +0 -0
- package/assets/mobile-icon-192.png +0 -0
- package/assets/mobile-icon-512.png +0 -0
- package/assets/mobile-service-worker.js +0 -63
- package/lib/mobile.js +0 -17621
- package/lib/mobile.js.map +0 -1
- package/lib/types/mobile/PairRequiredView.d.ts +0 -7
- package/lib/types/mobile/PairRequiredView.d.ts.map +0 -1
- package/lib/types/mobile/PairRequiredView.js +0 -28
- package/lib/types/mobile/PairRequiredView.test.d.ts +0 -2
- package/lib/types/mobile/PairRequiredView.test.d.ts.map +0 -1
- package/lib/types/mobile/PairRequiredView.test.js +0 -24
- package/lib/types/mobile/api.d.ts +0 -145
- package/lib/types/mobile/api.d.ts.map +0 -1
- package/lib/types/mobile/api.js +0 -103
- package/lib/types/mobile/index.d.ts +0 -10
- package/lib/types/mobile/index.d.ts.map +0 -1
- package/lib/types/mobile/index.js +0 -38
- package/lib/types/mobile/markdown.d.ts +0 -34
- package/lib/types/mobile/markdown.d.ts.map +0 -1
- package/lib/types/mobile/markdown.js +0 -285
- package/lib/types/mobile/markdown.test.d.ts +0 -2
- package/lib/types/mobile/markdown.test.d.ts.map +0 -1
- package/lib/types/mobile/markdown.test.js +0 -79
- package/lib/types/mobile/messages.d.ts +0 -141
- package/lib/types/mobile/messages.d.ts.map +0 -1
- package/lib/types/mobile/messages.js +0 -553
- package/lib/types/mobile/messages.test.d.ts +0 -2
- package/lib/types/mobile/messages.test.d.ts.map +0 -1
- package/lib/types/mobile/messages.test.js +0 -356
- package/lib/types/mobile/mobile-styles.d.ts +0 -6
- package/lib/types/mobile/mobile-styles.d.ts.map +0 -1
- package/lib/types/mobile/mobile-styles.js +0 -1438
- package/lib/types/mobile/mobile-theme.d.ts +0 -22
- package/lib/types/mobile/mobile-theme.d.ts.map +0 -1
- package/lib/types/mobile/mobile-theme.js +0 -70
- package/lib/types/mobile/mobile-theme.test.d.ts +0 -2
- package/lib/types/mobile/mobile-theme.test.d.ts.map +0 -1
- package/lib/types/mobile/mobile-theme.test.js +0 -71
- package/lib/types/mobile/mux.d.ts +0 -128
- package/lib/types/mobile/mux.d.ts.map +0 -1
- package/lib/types/mobile/mux.js +0 -305
- package/lib/types/mobile/mux.test.d.ts +0 -2
- package/lib/types/mobile/mux.test.d.ts.map +0 -1
- package/lib/types/mobile/mux.test.js +0 -267
- package/lib/types/mobile/pairing.d.ts +0 -31
- package/lib/types/mobile/pairing.d.ts.map +0 -1
- package/lib/types/mobile/pairing.js +0 -62
- package/lib/types/mobile/rpc.d.ts +0 -38
- package/lib/types/mobile/rpc.d.ts.map +0 -1
- package/lib/types/mobile/rpc.js +0 -83
- package/lib/types/mobile/theme-toggle.d.ts +0 -12
- package/lib/types/mobile/theme-toggle.d.ts.map +0 -1
- package/lib/types/mobile/theme-toggle.js +0 -26
- package/lib/types/mobile/views/App.d.ts +0 -57
- package/lib/types/mobile/views/App.d.ts.map +0 -1
- package/lib/types/mobile/views/App.js +0 -150
- package/lib/types/mobile/views/App.test.d.ts +0 -2
- package/lib/types/mobile/views/App.test.d.ts.map +0 -1
- package/lib/types/mobile/views/App.test.js +0 -52
- package/lib/types/mobile/views/ChatView.d.ts +0 -56
- package/lib/types/mobile/views/ChatView.d.ts.map +0 -1
- package/lib/types/mobile/views/ChatView.js +0 -773
- package/lib/types/mobile/views/ChatView.stream.test.d.ts +0 -2
- package/lib/types/mobile/views/ChatView.stream.test.d.ts.map +0 -1
- package/lib/types/mobile/views/ChatView.stream.test.js +0 -231
- package/lib/types/mobile/views/ChatView.test.d.ts +0 -2
- package/lib/types/mobile/views/ChatView.test.d.ts.map +0 -1
- package/lib/types/mobile/views/ChatView.test.js +0 -718
- package/lib/types/mobile/views/SessionListView.d.ts +0 -27
- package/lib/types/mobile/views/SessionListView.d.ts.map +0 -1
- package/lib/types/mobile/views/SessionListView.js +0 -139
- package/lib/types/mobile/views/SessionListView.test.d.ts +0 -2
- package/lib/types/mobile/views/SessionListView.test.d.ts.map +0 -1
- package/lib/types/mobile/views/SessionListView.test.js +0 -167
- package/lib/types/mobile/views/WorkspaceView.d.ts +0 -21
- package/lib/types/mobile/views/WorkspaceView.d.ts.map +0 -1
- package/lib/types/mobile/views/WorkspaceView.js +0 -93
- package/lib/types/mobile/views/WorkspaceView.test.d.ts +0 -2
- package/lib/types/mobile/views/WorkspaceView.test.d.ts.map +0 -1
- package/lib/types/mobile/views/WorkspaceView.test.js +0 -183
- package/lib/types/mobile-api.d.ts +0 -65
- package/lib/types/mobile-api.d.ts.map +0 -1
- package/lib/types/mobile-api.js +0 -404
- package/lib/types/mobile-pending.d.ts +0 -38
- package/lib/types/mobile-pending.d.ts.map +0 -1
- package/lib/types/mobile-pending.js +0 -59
- package/lib/types/mobile-pwa.d.ts +0 -6
- package/lib/types/mobile-pwa.d.ts.map +0 -1
- package/lib/types/mobile-pwa.js +0 -17
- package/lib/types/mobile-routes.d.ts +0 -13
- package/lib/types/mobile-routes.d.ts.map +0 -1
- package/lib/types/mobile-routes.js +0 -217
- package/lib/types/paired-model-catalog.d.ts +0 -17
- package/lib/types/paired-model-catalog.d.ts.map +0 -1
- package/lib/types/paired-model-catalog.js +0 -311
- package/src/mobile/PairRequiredView.test.tsx +0 -28
- package/src/mobile/PairRequiredView.tsx +0 -58
- package/src/mobile/api.ts +0 -229
- package/src/mobile/index.tsx +0 -41
- package/src/mobile/markdown.test.ts +0 -91
- package/src/mobile/markdown.ts +0 -291
- package/src/mobile/messages.test.ts +0 -402
- package/src/mobile/messages.ts +0 -677
- package/src/mobile/mobile-styles.ts +0 -1439
- package/src/mobile/mobile-theme.test.ts +0 -84
- package/src/mobile/mobile-theme.ts +0 -76
- package/src/mobile/mux.test.ts +0 -314
- package/src/mobile/mux.ts +0 -336
- package/src/mobile/pairing.ts +0 -77
- package/src/mobile/rpc.ts +0 -90
- package/src/mobile/theme-toggle.tsx +0 -47
- package/src/mobile/views/App.test.tsx +0 -62
- package/src/mobile/views/App.tsx +0 -213
- package/src/mobile/views/ChatView.stream.test.tsx +0 -263
- package/src/mobile/views/ChatView.test.tsx +0 -816
- package/src/mobile/views/ChatView.tsx +0 -1295
- package/src/mobile/views/SessionListView.test.tsx +0 -207
- package/src/mobile/views/SessionListView.tsx +0 -244
- package/src/mobile/views/WorkspaceView.test.tsx +0 -227
- package/src/mobile/views/WorkspaceView.tsx +0 -245
- package/src/mobile-api.ts +0 -418
- package/src/mobile-pending.ts +0 -88
- package/src/mobile-pwa.ts +0 -19
- package/src/mobile-routes.ts +0 -231
- package/src/paired-model-catalog.ts +0 -272
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
/**
|
|
3
|
-
* Mobile surface root: the view state machine (workspaces → sessions →
|
|
4
|
-
* chat) and the top-level data flows. Deliberately plain React state — no
|
|
5
|
-
* router, no state library: the surface is three fixed levels with a back
|
|
6
|
-
* affordance, and every piece of data is fetched on demand.
|
|
7
|
-
*/
|
|
8
|
-
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
9
|
-
import { fetchMobilePreferences, history as fetchHistory, listSessions, listWorkspaces, prompt } from "../api.js";
|
|
10
|
-
import { MuxClient } from "../mux.js";
|
|
11
|
-
import { RpcCallError, RpcTransportError } from "../rpc.js";
|
|
12
|
-
import { ChatView } from "./ChatView.js";
|
|
13
|
-
import { SessionListView } from "./SessionListView.js";
|
|
14
|
-
import { WorkspaceView as WorkspaceRoster } from "./WorkspaceView.js";
|
|
15
|
-
import { PairRequiredView } from "../PairRequiredView.js";
|
|
16
|
-
/** Read the optional workspace target carried from the pairing QR flow. */
|
|
17
|
-
export function mobileWorkspaceTarget(search) {
|
|
18
|
-
const value = new URLSearchParams(search).get('workspace');
|
|
19
|
-
return value === null || value === '' ? undefined : value;
|
|
20
|
-
}
|
|
21
|
-
/** Map a list row to the surface model; the title comes from projections when present. */
|
|
22
|
-
export function toSessionView(item) {
|
|
23
|
-
const titleValue = item.projections?.values?.title;
|
|
24
|
-
const title = typeof titleValue === 'string' && titleValue !== ''
|
|
25
|
-
? titleValue
|
|
26
|
-
: item.cwd !== undefined ? item.cwd.split('/').filter(Boolean).at(-1) ?? item.cwd : '新会话';
|
|
27
|
-
return {
|
|
28
|
-
sessionId: item.sessionId,
|
|
29
|
-
title,
|
|
30
|
-
...(item.cwd !== undefined ? { cwd: item.cwd } : {}),
|
|
31
|
-
updatedAt: item.updatedAt,
|
|
32
|
-
running: item.running,
|
|
33
|
-
blank: item.blank,
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
/** Human clock, e.g. "14:05" or "昨天 20:31". */
|
|
37
|
-
export function formatTime(epochMs) {
|
|
38
|
-
const date = new Date(epochMs);
|
|
39
|
-
const clock = `${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`;
|
|
40
|
-
const today = new Date();
|
|
41
|
-
if (date.toDateString() === today.toDateString())
|
|
42
|
-
return clock;
|
|
43
|
-
const yesterday = new Date(today);
|
|
44
|
-
yesterday.setDate(today.getDate() - 1);
|
|
45
|
-
if (date.toDateString() === yesterday.toDateString())
|
|
46
|
-
return `昨天 ${clock}`;
|
|
47
|
-
return `${String(date.getMonth() + 1)}月${String(date.getDate())}日 ${clock}`;
|
|
48
|
-
}
|
|
49
|
-
/** Whether the mobile gateway rejected this browser for lack of a paired cookie. */
|
|
50
|
-
export function isUnpairedMobileError(error) {
|
|
51
|
-
return error instanceof RpcTransportError && error.message === 'HTTP 403';
|
|
52
|
-
}
|
|
53
|
-
/** Classify an initial mobile preference failure without treating outage as authorization. */
|
|
54
|
-
export function mobilePairStateForError(error) {
|
|
55
|
-
return isUnpairedMobileError(error) ? 'unpaired' : 'unavailable';
|
|
56
|
-
}
|
|
57
|
-
/** Gate the independent mobile bundle until its own browser context is paired. */
|
|
58
|
-
export function App({ initialPairError }) {
|
|
59
|
-
const [pairState, setPairState] = useState('checking');
|
|
60
|
-
useEffect(() => {
|
|
61
|
-
let current = true;
|
|
62
|
-
void fetchMobilePreferences().then(() => { if (current)
|
|
63
|
-
setPairState('paired'); }, (error) => { if (current)
|
|
64
|
-
setPairState(mobilePairStateForError(error)); });
|
|
65
|
-
return () => { current = false; };
|
|
66
|
-
}, []);
|
|
67
|
-
if (pairState === 'checking') {
|
|
68
|
-
return _jsx("main", { className: "mobile mobile-empty", children: _jsx("p", { className: "mobile-muted", children: "\u6B63\u5728\u8FDE\u63A5..." }) });
|
|
69
|
-
}
|
|
70
|
-
if (pairState === 'unpaired') {
|
|
71
|
-
return _jsx(PairRequiredView, { initialError: initialPairError, onPaired: (path) => { window.location.replace(path); } });
|
|
72
|
-
}
|
|
73
|
-
if (pairState === 'unavailable') {
|
|
74
|
-
return (_jsxs("main", { className: "mobile mobile-empty", children: [_jsx("p", { className: "mobile-error", role: "alert", children: "\u65E0\u6CD5\u8FDE\u63A5\u5230\u8FD0\u884C\u4E2D\u7684 DSH host\u3002" }), _jsx("button", { className: "mobile-new", type: "button", onClick: () => { window.location.reload(); }, children: "\u91CD\u8BD5" })] }));
|
|
75
|
-
}
|
|
76
|
-
return _jsx(PairedApp, {});
|
|
77
|
-
}
|
|
78
|
-
/** The existing remote mobile surface, mounted only after device pairing succeeds. */
|
|
79
|
-
function PairedApp() {
|
|
80
|
-
const [route, setRoute] = useState({ kind: 'workspaces' });
|
|
81
|
-
const [initialWorkspaceId, setInitialWorkspaceId] = useState(() => mobileWorkspaceTarget(window.location.search));
|
|
82
|
-
const muxRef = useRef(undefined);
|
|
83
|
-
// The mux stream lives for the page lifetime: session events keep the
|
|
84
|
-
// open chat live, and reconnect is automatic.
|
|
85
|
-
useEffect(() => {
|
|
86
|
-
const mux = new MuxClient();
|
|
87
|
-
muxRef.current = mux;
|
|
88
|
-
mux.start();
|
|
89
|
-
return () => { mux.stop(); };
|
|
90
|
-
}, []);
|
|
91
|
-
// Keep the live-event client pointed at the session currently on screen so
|
|
92
|
-
// its polling fallback can keep that chat fresh over SSE-impairing tunnels
|
|
93
|
-
// (quick tunnel / Tailscale Serve do not forward Server-Sent Events).
|
|
94
|
-
useEffect(() => {
|
|
95
|
-
muxRef.current?.observe(route.kind === 'chat' ? route.session.sessionId : undefined);
|
|
96
|
-
}, [route]);
|
|
97
|
-
const back = useCallback(() => {
|
|
98
|
-
setRoute(previous => {
|
|
99
|
-
if (previous.kind === 'chat')
|
|
100
|
-
return { kind: 'sessions', workspace: previous.workspace };
|
|
101
|
-
if (previous.kind === 'sessions')
|
|
102
|
-
return { kind: 'workspaces' };
|
|
103
|
-
return previous;
|
|
104
|
-
});
|
|
105
|
-
}, []);
|
|
106
|
-
const openChat = useCallback((session, workspace) => {
|
|
107
|
-
setRoute({ kind: 'chat', session, workspace });
|
|
108
|
-
}, []);
|
|
109
|
-
const openWorkspace = useCallback((workspace) => {
|
|
110
|
-
if (initialWorkspaceId !== undefined) {
|
|
111
|
-
const url = new URL(window.location.href);
|
|
112
|
-
url.searchParams.delete('workspace');
|
|
113
|
-
window.history.replaceState(null, '', `${url.pathname}${url.search}${url.hash}`);
|
|
114
|
-
setInitialWorkspaceId(undefined);
|
|
115
|
-
}
|
|
116
|
-
setRoute({ kind: 'sessions', workspace });
|
|
117
|
-
}, [initialWorkspaceId]);
|
|
118
|
-
return (_jsx("div", { className: "mobile", children: route.kind === 'workspaces'
|
|
119
|
-
? _jsx(WorkspaceRoster, { initialWorkspaceId: initialWorkspaceId, onPick: openWorkspace })
|
|
120
|
-
: route.kind === 'sessions'
|
|
121
|
-
? (_jsx(SessionListView, { workspace: route.workspace, onBack: back, onPick: (session) => { openChat(session, route.workspace); } }))
|
|
122
|
-
: _jsx(ChatView, { session: route.session, mux: muxRef.current, onBack: back }) }));
|
|
123
|
-
}
|
|
124
|
-
/** Shared error text for the surface's small failure affordances. */
|
|
125
|
-
export function errorText(error) {
|
|
126
|
-
if (error instanceof RpcCallError)
|
|
127
|
-
return error.error.message;
|
|
128
|
-
if (error instanceof RpcTransportError)
|
|
129
|
-
return error.message;
|
|
130
|
-
if (error instanceof Error)
|
|
131
|
-
return error.message;
|
|
132
|
-
return String(error);
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* Actionable hint for transport-level 403s on host-gated channels (model
|
|
136
|
-
* picker, session creation): the phone's UI bundle is served fresh from disk
|
|
137
|
-
* per request, while the host-side allowlist lives in the long-running
|
|
138
|
-
* process — a rebuild without a restart shows the new surface against the
|
|
139
|
-
* old allowlist (HTTP 403 forbidden).
|
|
140
|
-
*/
|
|
141
|
-
export function staleHostHint(message) {
|
|
142
|
-
return /^HTTP 403/.test(message)
|
|
143
|
-
? '宿主端插件可能仍在运行旧版本:请重启 dsh web 后再试。'
|
|
144
|
-
: undefined;
|
|
145
|
-
}
|
|
146
|
-
/** Fetch one history page (tail by default) — thin wrapper so views share the call shape. */
|
|
147
|
-
export function loadHistory(sessionId, beforeSeq, signal) {
|
|
148
|
-
return fetchHistory(sessionId, beforeSeq, undefined, signal);
|
|
149
|
-
}
|
|
150
|
-
export { listSessions, listWorkspaces, prompt };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"App.test.d.ts","sourceRoot":"","sources":["../../../../src/mobile/views/App.test.tsx"],"names":[],"mappings":""}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
// @vitest-environment jsdom
|
|
3
|
-
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
4
|
-
import { cleanup, render, screen, waitFor } from '@testing-library/react';
|
|
5
|
-
import { RpcTransportError } from "../rpc.js";
|
|
6
|
-
const api = vi.hoisted(() => ({
|
|
7
|
-
fetchMobilePreferences: vi.fn(),
|
|
8
|
-
history: vi.fn(),
|
|
9
|
-
listSessions: vi.fn(),
|
|
10
|
-
listWorkspaces: vi.fn(),
|
|
11
|
-
prompt: vi.fn(),
|
|
12
|
-
}));
|
|
13
|
-
vi.mock('../api.ts', () => api);
|
|
14
|
-
vi.mock('../mux.ts', () => ({
|
|
15
|
-
MuxClient: class {
|
|
16
|
-
start() { }
|
|
17
|
-
stop() { }
|
|
18
|
-
observe() { }
|
|
19
|
-
},
|
|
20
|
-
}));
|
|
21
|
-
vi.mock('./WorkspaceView.tsx', () => ({ WorkspaceView: () => _jsx("div", { children: "workspace-ready" }) }));
|
|
22
|
-
vi.mock('./SessionListView.tsx', () => ({ SessionListView: () => _jsx("div", { children: "sessions-ready" }) }));
|
|
23
|
-
vi.mock('./ChatView.tsx', () => ({ ChatView: () => _jsx("div", { children: "chat-ready" }) }));
|
|
24
|
-
import { App, mobilePairStateForError } from "./App.js";
|
|
25
|
-
afterEach(() => {
|
|
26
|
-
cleanup();
|
|
27
|
-
vi.clearAllMocks();
|
|
28
|
-
});
|
|
29
|
-
describe('mobile paired-device gate', () => {
|
|
30
|
-
it('distinguishes a missing paired cookie from a transport outage', () => {
|
|
31
|
-
expect(mobilePairStateForError(new RpcTransportError('HTTP 403'))).toBe('unpaired');
|
|
32
|
-
expect(mobilePairStateForError(new RpcTransportError('HTTP 503'))).toBe('unavailable');
|
|
33
|
-
expect(mobilePairStateForError(new Error('offline'))).toBe('unavailable');
|
|
34
|
-
});
|
|
35
|
-
it('keeps a valid paired context usable after a failed QR token', async () => {
|
|
36
|
-
api.fetchMobilePreferences.mockResolvedValue({ mobileEnterToSend: true });
|
|
37
|
-
render(_jsx(App, { initialPairError: "\u914D\u5BF9\u94FE\u63A5\u5DF2\u88AB\u4F7F\u7528\u3002" }));
|
|
38
|
-
await waitFor(() => expect(screen.getByText('workspace-ready')).toBeDefined());
|
|
39
|
-
expect(screen.queryByRole('alert')).toBeNull();
|
|
40
|
-
});
|
|
41
|
-
it('shows the pairing screen only when the mobile gateway rejects the device', async () => {
|
|
42
|
-
api.fetchMobilePreferences.mockRejectedValue(new RpcTransportError('HTTP 403'));
|
|
43
|
-
render(_jsx(App, { initialPairError: "\u914D\u5BF9\u94FE\u63A5\u5DF2\u88AB\u4F7F\u7528\u3002" }));
|
|
44
|
-
await waitFor(() => expect(screen.getByRole('alert').textContent).toContain('配对链接已被使用。'));
|
|
45
|
-
});
|
|
46
|
-
it('shows a retryable connection failure rather than mounting remote views on outage', async () => {
|
|
47
|
-
api.fetchMobilePreferences.mockRejectedValue(new RpcTransportError('HTTP 503'));
|
|
48
|
-
render(_jsx(App, {}));
|
|
49
|
-
await waitFor(() => expect(screen.getByRole('alert').textContent).toContain('无法连接到运行中的 DSH host。'));
|
|
50
|
-
expect(screen.queryByText('workspace-ready')).toBeNull();
|
|
51
|
-
});
|
|
52
|
-
});
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Chat level: one session. Loads the history tail page on open, appends
|
|
3
|
-
* pages upward (loadOlder), folds live mux frames in as they arrive, and
|
|
4
|
-
* sends prompts through session.prompt.
|
|
5
|
-
*
|
|
6
|
-
* Rendering mirrors the desktop web UI's fold discipline on a small screen:
|
|
7
|
-
* - reasoning text hides behind a collapsed "深度思考" disclosure,
|
|
8
|
-
* - tool calls behind a collapsed tool disclosure (name + arguments),
|
|
9
|
-
* - very long assistant text collapses with an explicit expand toggle,
|
|
10
|
-
* - a toolbar above the composer carries the model (+ thinking effort) and
|
|
11
|
-
* permission pickers, both as bottom sheets.
|
|
12
|
-
*/
|
|
13
|
-
import { type SessionView } from './App.tsx';
|
|
14
|
-
import { MuxClient } from '../mux.ts';
|
|
15
|
-
/** Props for the chat view. */
|
|
16
|
-
export interface ChatViewProps {
|
|
17
|
-
session: SessionView;
|
|
18
|
-
/** The page-lifetime mux client (undefined before the first effect tick). */
|
|
19
|
-
mux?: MuxClient | undefined;
|
|
20
|
-
onBack(): void;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Hard cap on live events buffered while the initial history tail page is in
|
|
24
|
-
* flight. Beyond this the oldest buffered event is dropped and a follow-up
|
|
25
|
-
* history tail re-pull closes the seam.
|
|
26
|
-
*/
|
|
27
|
-
export declare const MAX_TAIL_BUFFER_EVENTS = 500;
|
|
28
|
-
/** One switchable permission preset (the `permissions` projection shape). */
|
|
29
|
-
export interface PermissionOption {
|
|
30
|
-
value: string;
|
|
31
|
-
name: string;
|
|
32
|
-
description?: string;
|
|
33
|
-
}
|
|
34
|
-
/** The `permissions` projection value: options + the effective current value. */
|
|
35
|
-
export interface PermissionSelectValue {
|
|
36
|
-
options: PermissionOption[];
|
|
37
|
-
currentValue: string;
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Render one session's chat.
|
|
41
|
-
* @param props - the session, the mux client, and the back action.
|
|
42
|
-
* @returns the chat surface.
|
|
43
|
-
*/
|
|
44
|
-
export declare function ChatView({ session, mux, onBack }: ChatViewProps): import("react").JSX.Element;
|
|
45
|
-
/**
|
|
46
|
-
* Minimum interval between full markdown re-parses of a live (pending)
|
|
47
|
-
* assistant message. Every streamed chunk replaces the message object, and
|
|
48
|
-
* re-parsing the whole accumulated text per chunk turns a long reply into
|
|
49
|
-
* O(n^2) work on mobile. Pending text keeps the last parsed result visible
|
|
50
|
-
* and re-parses at most once per interval; the moment the turn closes the
|
|
51
|
-
* final text parses immediately, so terminal messages render exactly as
|
|
52
|
-
* before.
|
|
53
|
-
*/
|
|
54
|
-
export declare const STREAM_RENDER_INTERVAL_MS = 120;
|
|
55
|
-
export declare const LONG_TEXT_LIMIT = 6000;
|
|
56
|
-
//# sourceMappingURL=ChatView.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ChatView.d.ts","sourceRoot":"","sources":["../../../../src/mobile/views/ChatView.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,OAAO,EAAuB,KAAK,WAAW,EAAE,MAAM,WAAW,CAAA;AAMjE,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAGrC,+BAA+B;AAC/B,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,WAAW,CAAA;IACpB,6EAA6E;IAC7E,GAAG,CAAC,EAAE,SAAS,GAAG,SAAS,CAAA;IAC3B,MAAM,IAAI,IAAI,CAAA;CACf;AAED;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,MAAM,CAAA;AAqCzC,6EAA6E;AAC7E,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,iFAAiF;AACjF,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,gBAAgB,EAAE,CAAA;IAC3B,YAAY,EAAE,MAAM,CAAA;CACrB;AAqCD;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,aAAa,+BAoe/D;AA2GD;;;;;;;;GAQG;AACH,eAAO,MAAM,yBAAyB,MAAM,CAAA;AA6F5C,eAAO,MAAM,eAAe,OAAO,CAAA"}
|