dsh-remote-plugin 0.4.9 → 0.5.2

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.
@@ -0,0 +1,119 @@
1
+ /* 纯 JS SHA-256(零依赖,二进制安全)
2
+ * 上传大文件时逐块喂入 4MB slice,最后与网关计算的 SHA-256 比对,防坏包。
3
+ */
4
+ 'use strict'
5
+
6
+ function SHA256() {
7
+ this.h = new Uint32Array([
8
+ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
9
+ 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
10
+ ])
11
+ this.buf = new Uint8Array(64)
12
+ this.bufLen = 0
13
+ this.total = 0
14
+ }
15
+
16
+ SHA256.prototype._process = function (block) {
17
+ const w = new Uint32Array(64)
18
+ for (let i = 0; i < 16; i++) {
19
+ w[i] = (block[i * 4] << 24) | (block[i * 4 + 1] << 16) | (block[i * 4 + 2] << 8) | block[i * 4 + 3]
20
+ }
21
+ for (let i = 16; i < 64; i++) {
22
+ const s0 = ((w[i - 15] >>> 7) | (w[i - 15] << 25)) ^ ((w[i - 15] >>> 18) | (w[i - 15] << 14)) ^ (w[i - 15] >>> 3)
23
+ const s1 = ((w[i - 2] >>> 17) | (w[i - 2] << 15)) ^ ((w[i - 2] >>> 19) | (w[i - 2] << 13)) ^ (w[i - 2] >>> 10)
24
+ w[i] = (w[i - 16] + s0 + w[i - 7] + s1) >>> 0
25
+ }
26
+ let a = this.h[0], b = this.h[1], c = this.h[2], d = this.h[3]
27
+ let e = this.h[4], f = this.h[5], g = this.h[6], h = this.h[7]
28
+ for (let i = 0; i < 64; i++) {
29
+ const S1 = ((e >>> 6) | (e << 26)) ^ ((e >>> 11) | (e << 21)) ^ ((e >>> 25) | (e << 7))
30
+ const ch = (e & f) ^ (~e & g)
31
+ const t1 = (h + S1 + ch + K[i] + w[i]) >>> 0
32
+ const S0 = ((a >>> 2) | (a << 30)) ^ ((a >>> 13) | (a << 19)) ^ ((a >>> 22) | (a << 10))
33
+ const maj = (a & b) ^ (a & c) ^ (b & c)
34
+ const t2 = (S0 + maj) >>> 0
35
+ h = g; g = f; f = e; e = (d + t1) >>> 0
36
+ d = c; c = b; b = a; a = (t1 + t2) >>> 0
37
+ }
38
+ this.h[0] = (this.h[0] + a) >>> 0
39
+ this.h[1] = (this.h[1] + b) >>> 0
40
+ this.h[2] = (this.h[2] + c) >>> 0
41
+ this.h[3] = (this.h[3] + d) >>> 0
42
+ this.h[4] = (this.h[4] + e) >>> 0
43
+ this.h[5] = (this.h[5] + f) >>> 0
44
+ this.h[6] = (this.h[6] + g) >>> 0
45
+ this.h[7] = (this.h[7] + h) >>> 0
46
+ }
47
+
48
+ SHA256.prototype.update = function (bytes) {
49
+ const data = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes)
50
+ this.total += data.length
51
+ let i = 0
52
+ if (this.bufLen > 0) {
53
+ const need = 64 - this.bufLen
54
+ const n = Math.min(need, data.length)
55
+ this.buf.set(data.subarray(0, n), this.bufLen)
56
+ this.bufLen += n
57
+ i = n
58
+ if (this.bufLen === 64) {
59
+ this._process(this.buf)
60
+ this.bufLen = 0
61
+ }
62
+ }
63
+ while (i + 64 <= data.length) {
64
+ this._process(data.subarray(i, i + 64))
65
+ i += 64
66
+ }
67
+ if (i < data.length) {
68
+ this.buf.set(data.subarray(i), 0)
69
+ this.bufLen = data.length - i
70
+ }
71
+ return this
72
+ }
73
+
74
+ SHA256.prototype.clone = function () {
75
+ const c = new SHA256()
76
+ c.h.set(this.h)
77
+ c.buf.set(this.buf)
78
+ c.bufLen = this.bufLen
79
+ c.total = this.total
80
+ return c
81
+ }
82
+
83
+ SHA256.prototype.hex = function () {
84
+ const lenBits = this.total * 8
85
+ const pad = new Uint8Array(72)
86
+ pad[0] = 0x80
87
+ const tail = (this.total + 9) % 64
88
+ const zero = tail === 0 ? 0 : 64 - tail
89
+ const padLen = 1 + zero + 8
90
+ // 长度 64 位大端: 高位 32 位 + 低位 32 位
91
+ const hi = Math.floor(lenBits / 0x100000000)
92
+ const lo = lenBits >>> 0
93
+ pad[padLen - 8] = (hi >>> 24) & 0xff
94
+ pad[padLen - 7] = (hi >>> 16) & 0xff
95
+ pad[padLen - 6] = (hi >>> 8) & 0xff
96
+ pad[padLen - 5] = hi & 0xff
97
+ pad[padLen - 4] = (lo >>> 24) & 0xff
98
+ pad[padLen - 3] = (lo >>> 16) & 0xff
99
+ pad[padLen - 2] = (lo >>> 8) & 0xff
100
+ pad[padLen - 1] = lo & 0xff
101
+ this.update(pad.subarray(0, padLen))
102
+ const out = []
103
+ for (let i = 0; i < 8; i++) {
104
+ const v = this.h[i]
105
+ out.push((v >>> 24).toString(16).padStart(2, '0'), ((v >>> 16) & 0xff).toString(16).padStart(2, '0'), ((v >>> 8) & 0xff).toString(16).padStart(2, '0'), (v & 0xff).toString(16).padStart(2, '0'))
106
+ }
107
+ return out.join('')
108
+ }
109
+
110
+ const K = new Uint32Array([
111
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
112
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
113
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
114
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
115
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
116
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
117
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
118
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
119
+ ])
package/public/styles.css CHANGED
@@ -163,12 +163,30 @@ body.in-session .view {
163
163
  backdrop-filter: blur(12px);
164
164
  border-bottom: 1px solid var(--line);
165
165
  }
166
+ /* 会话运行状态可视化(类似 Web UI deepdiving):
167
+ 运行中 = 蓝色流动渐变; 出错/中断 = 橙红; 空闲 = 原始样式 */
168
+ .session-head.running {
169
+ background: linear-gradient(90deg, rgba(11, 14, 26, .94), rgba(35, 65, 150, .92), rgba(125, 207, 255, .6), rgba(35, 65, 150, .92), rgba(11, 14, 26, .94));
170
+ background-size: 200% 100%;
171
+ animation: session-running-flow 2.6s ease-in-out infinite alternate;
172
+ border-bottom-color: rgba(91, 140, 255, .55);
173
+ }
174
+ .session-head.interrupted {
175
+ background: linear-gradient(90deg, rgba(11, 14, 26, .94), rgba(90, 26, 12, .92), rgba(255, 158, 100, .55), rgba(90, 26, 12, .92), rgba(11, 14, 26, .94));
176
+ background-size: 200% 100%;
177
+ animation: session-running-flow 1.8s ease-in-out infinite alternate;
178
+ border-bottom-color: rgba(255, 158, 100, .55);
179
+ }
180
+ @keyframes session-running-flow {
181
+ from { background-position: 0% 50%; }
182
+ to { background-position: 100% 50%; }
183
+ }
166
184
  .session-head .session-title { flex-shrink: 1; }
167
185
  .session-head-meta { flex: 1; min-width: 0; }
168
186
  .session-title {
169
187
  font-size: 16px; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
170
188
  }
171
- .session-sub { font-size: 12px; color: var(--muted); margin-top: 1px; }
189
+ .session-sub { font-size: 12px; color: var(--muted); margin-top: 1px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
172
190
  .cards {
173
191
  display: flex; flex-direction: column; gap: 8px; margin-top: 8px;
174
192
  flex-shrink: 0; max-height: 42vh; overflow-y: auto;
@@ -271,13 +289,15 @@ body.in-session .view {
271
289
  .tool.error summary { color: var(--orange); }
272
290
 
273
291
  /* ---------- composer ---------- */
274
- .composer {
292
+ .composer-wrap {
275
293
  position: fixed; left: 0; right: 0; bottom: calc(58px + var(--safe-b)); z-index: 20;
276
- display: flex; gap: 8px; align-items: flex-end;
277
- padding: 8px 12px calc(8px + var(--safe-b));
294
+ max-width: 720px; margin: 0 auto;
278
295
  background: rgba(11, 14, 26, .92); backdrop-filter: blur(10px);
279
296
  border-top: 1px solid var(--line);
280
- max-width: 720px; margin: 0 auto;
297
+ }
298
+ .composer {
299
+ display: flex; gap: 8px; align-items: flex-end;
300
+ padding: 8px 12px calc(8px + var(--safe-b));
281
301
  }
282
302
  .composer textarea {
283
303
  flex: 1; resize: none; background: var(--panel); color: var(--text);
@@ -286,11 +306,43 @@ body.in-session .view {
286
306
  max-height: 120px; outline: none;
287
307
  }
288
308
  .composer textarea:focus { border-color: rgba(91, 140, 255, .6); }
309
+ .plus-btn {
310
+ flex-shrink: 0; width: 42px; height: 42px; border-radius: 14px;
311
+ background: var(--panel); color: var(--cyan); border: 1px solid var(--line);
312
+ font-size: 22px; font-weight: 700; line-height: 1;
313
+ }
314
+ .plus-btn.active { background: rgba(125, 207, 255, .14); border-color: rgba(125, 207, 255, .45); }
289
315
  .send-btn {
290
316
  flex-shrink: 0; width: 46px; height: 42px; border-radius: 14px;
291
317
  background: var(--blue); color: #fff; font-weight: 700; font-size: 14px;
292
318
  }
293
319
  .send-btn:disabled { opacity: .45; }
320
+ .composer-menu {
321
+ max-height: min(46vh, 340px); overflow-y: auto;
322
+ padding: 10px 12px; display: flex; flex-direction: column; gap: 12px;
323
+ border-bottom: 1px solid var(--line);
324
+ }
325
+ .menu-title {
326
+ font-size: 12px; color: var(--muted); font-weight: 700; letter-spacing: .5px;
327
+ margin-bottom: 7px; display: flex; align-items: center; justify-content: space-between;
328
+ }
329
+ .menu-chips { display: flex; flex-wrap: wrap; gap: 7px; align-items: center; }
330
+ .menu-chip {
331
+ background: var(--panel); color: var(--text); border: 1px solid var(--line);
332
+ border-radius: 999px; padding: 6px 11px; font-size: 12.5px; cursor: pointer;
333
+ white-space: nowrap; max-width: 100%; overflow: hidden; text-overflow: ellipsis;
334
+ }
335
+ .menu-chip:active { background: rgba(91, 140, 255, .16); border-color: rgba(91, 140, 255, .5); }
336
+ .menu-chip.current { color: var(--cyan); border-color: rgba(125, 207, 255, .45); background: rgba(125, 207, 255, .08); }
337
+ .menu-chip.danger { color: var(--orange); border-color: rgba(255, 158, 100, .4); }
338
+ .menu-models { display: flex; flex-wrap: wrap; gap: 7px; }
339
+ .model-chip {
340
+ background: var(--panel); border: 1px solid var(--line); color: var(--text);
341
+ border-radius: 999px; padding: 6px 11px; font-size: 12.5px; cursor: pointer;
342
+ max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
343
+ }
344
+ .model-chip.current { color: var(--cyan); border-color: rgba(125, 207, 255, .45); background: rgba(125, 207, 255, .08); }
345
+ .model-provider { font-size: 11px; color: var(--muted); margin: 7px 0 5px; }
294
346
  body.in-session .main { padding-bottom: 84px; }
295
347
 
296
348
  /* ---------- 待办 ---------- */
@@ -302,7 +354,7 @@ body.in-session .main { padding-bottom: 84px; }
302
354
  .pending-card.approval { border-left: 3px solid var(--orange); }
303
355
  .pending-card.question { border-left: 3px solid var(--purple); }
304
356
  .pc-title { font-weight: 600; font-size: 14px; }
305
- .pc-desc { font-size: 12.5px; color: var(--muted); margin-top: 3px; word-break: break-all; }
357
+ .pc-desc { font-size: 12.5px; color: var(--muted); margin-top: 3px; overflow-wrap: anywhere; }
306
358
  .pc-session { font-size: 11px; color: var(--blue); margin-top: 5px; }
307
359
  .job-card .job-name { font-weight: 600; font-size: 14px; }
308
360
  .job-state { font-size: 12px; color: var(--muted); margin-top: 3px; }
@@ -328,6 +380,8 @@ body.in-session .main { padding-bottom: 84px; }
328
380
  transition: width .15s ease;
329
381
  }
330
382
  .fs-progress-text { flex-shrink: 0; min-width: 112px; text-align: right; }
383
+ .fs-progress-actions { flex-shrink: 0; display: flex; gap: 6px; }
384
+ .fs-progress-actions .mini-btn { padding: 4px 10px; font-size: 12px; }
331
385
  .fs-pull {
332
386
  height: 0; overflow: hidden; text-align: center; font-size: 12px; color: var(--cyan);
333
387
  transition: height .12s ease; line-height: 26px;
@@ -1,6 +1,6 @@
1
1
  {
2
- "version": "0.4.9",
2
+ "version": "0.5.2",
3
3
  "apkUrl": "dsh-remote.apk",
4
- "releasedAt": "2026-08-16T03:05:53.903Z",
5
- "notes": "上传支持分块断点续传(断网重选同一文件接着传); APK 固定签名, 各版本可原地覆盖升级; 发版全自动: tag CI 构建 Release 资产 + npm + 独立仓库"
4
+ "releasedAt": "2026-08-16T05:47:22.411Z",
5
+ "notes": "管理页二维码修复 SVG 尺寸白点并新增网关徽章一键开面板, 抽屉去标题栏沉浸式; App 扫码改为 Camera+jsQR 本地解码(无谷歌服务依赖, APK 27MB→9MB), 保留系统相机/手动输入冗余; 桌面端已回答的提问不再残留手机待办; Android 安装界面显示真实版本号"
6
6
  }
@@ -1,3 +1,3 @@
1
1
  {
2
- "version": "0.4.9"
2
+ "version": "0.5.2"
3
3
  }