dsh-zen-remote 1.1.11 → 1.1.13

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 (85) hide show
  1. package/AGENTS.md +24 -0
  2. package/README.md +7 -3
  3. package/README.zh-CN.md +7 -3
  4. package/docs/interface.md +5 -2
  5. package/dsh-push.mjs +25 -1
  6. package/lan-gate.mjs +16 -1
  7. package/lib/client.js +684 -43
  8. package/lib/lan-gate-server.cjs +107 -4
  9. package/lib/types/client/MobileHome.d.ts +7 -2
  10. package/lib/types/client/MobileHome.d.ts.map +1 -1
  11. package/lib/types/client/MobileSessionInfo.d.ts +2 -2
  12. package/lib/types/client/MobileSessionInfo.d.ts.map +1 -1
  13. package/lib/types/client/compat/store.d.ts +62 -0
  14. package/lib/types/client/compat/store.d.ts.map +1 -0
  15. package/lib/types/client/compat/types.d.ts +84 -0
  16. package/lib/types/client/compat/types.d.ts.map +1 -0
  17. package/lib/types/client/debug.d.ts +1 -1
  18. package/lib/types/client/debug.d.ts.map +1 -1
  19. package/lib/types/client/effects/aionui-compat.d.ts +1 -1
  20. package/lib/types/client/effects/aionui-compat.d.ts.map +1 -1
  21. package/lib/types/client/effects/gestures.d.ts +1 -1
  22. package/lib/types/client/effects/gestures.d.ts.map +1 -1
  23. package/lib/types/client/effects/header-status.d.ts +1 -1
  24. package/lib/types/client/effects/header-status.d.ts.map +1 -1
  25. package/lib/types/client/effects/keyboard-avoid.d.ts +1 -1
  26. package/lib/types/client/effects/keyboard-avoid.d.ts.map +1 -1
  27. package/lib/types/client/effects/keyboard-guard.d.ts +1 -1
  28. package/lib/types/client/effects/keyboard-guard.d.ts.map +1 -1
  29. package/lib/types/client/effects/modal-back.d.ts +1 -1
  30. package/lib/types/client/effects/modal-back.d.ts.map +1 -1
  31. package/lib/types/client/effects/model-sheet-extras.d.ts +33 -0
  32. package/lib/types/client/effects/model-sheet-extras.d.ts.map +1 -0
  33. package/lib/types/client/effects/native-trigger-overlay.d.ts +1 -1
  34. package/lib/types/client/effects/native-trigger-overlay.d.ts.map +1 -1
  35. package/lib/types/client/effects/phone-chrome.d.ts +1 -1
  36. package/lib/types/client/effects/phone-chrome.d.ts.map +1 -1
  37. package/lib/types/client/effects/turn-fold.d.ts +1 -1
  38. package/lib/types/client/effects/turn-fold.d.ts.map +1 -1
  39. package/lib/types/client/effects/welcome-notice.d.ts +1 -1
  40. package/lib/types/client/effects/welcome-notice.d.ts.map +1 -1
  41. package/lib/types/client/effects/workbench-ref-close.d.ts +1 -1
  42. package/lib/types/client/effects/workbench-ref-close.d.ts.map +1 -1
  43. package/lib/types/client/index.d.ts +1 -1
  44. package/lib/types/client/index.d.ts.map +1 -1
  45. package/lib/types/client/nav-store.d.ts +2 -2
  46. package/lib/types/client/nav-store.d.ts.map +1 -1
  47. package/lib/types/client/session-dot.d.ts +11 -3
  48. package/lib/types/client/session-dot.d.ts.map +1 -1
  49. package/lib/types/client/styles/compat.css.d.ts +1 -1
  50. package/lib/types/client/styles/compat.css.d.ts.map +1 -1
  51. package/lib/types/client/styles/composer.css.d.ts +1 -1
  52. package/lib/types/client/styles/composer.css.d.ts.map +1 -1
  53. package/lib/types/client/styles/info.css.d.ts +1 -1
  54. package/lib/types/client/styles/info.css.d.ts.map +1 -1
  55. package/package.json +49 -26
  56. package/pwa/app.css +47 -7
  57. package/scripts/check-client-externals.mjs +48 -0
  58. package/scripts/check-compat-store.mjs +113 -0
  59. package/scripts/check-host-shadow.mjs +145 -0
  60. package/scripts/check-info-sheet-stacking.mjs +55 -0
  61. package/src/client/MobileAttachButton.tsx +1 -1
  62. package/src/client/MobileHome.tsx +33 -7
  63. package/src/client/MobileSessionInfo.tsx +6 -4
  64. package/src/client/chips-store.ts +1 -1
  65. package/src/client/compat/store.ts +205 -0
  66. package/src/client/compat/types.ts +115 -0
  67. package/src/client/debug.ts +1 -1
  68. package/src/client/effects/aionui-compat.ts +1 -1
  69. package/src/client/effects/gestures.ts +1 -1
  70. package/src/client/effects/header-status.ts +22 -3
  71. package/src/client/effects/keyboard-avoid.ts +1 -1
  72. package/src/client/effects/keyboard-guard.ts +1 -1
  73. package/src/client/effects/modal-back.ts +1 -1
  74. package/src/client/effects/model-sheet-extras.ts +159 -0
  75. package/src/client/effects/native-trigger-overlay.ts +1 -1
  76. package/src/client/effects/phone-chrome.ts +1 -1
  77. package/src/client/effects/turn-fold.ts +1 -1
  78. package/src/client/effects/welcome-notice.ts +1 -1
  79. package/src/client/effects/workbench-ref-close.ts +1 -1
  80. package/src/client/index.tsx +70 -6
  81. package/src/client/nav-store.ts +2 -2
  82. package/src/client/session-dot.ts +13 -4
  83. package/src/client/styles/compat.css.ts +43 -11
  84. package/src/client/styles/composer.css.ts +184 -9
  85. package/src/client/styles/info.css.ts +21 -0
@@ -51,6 +51,16 @@ const LISTEN_HOST = cfg('LAN_GATE_HOST', 'host', '127.0.0.1')
51
51
  const RATE_LIMIT_PER_MIN = Number(cfg('LAN_GATE_RATE_LIMIT', 'rateLimit', 120))
52
52
  const TARGET_HOST = '127.0.0.1'
53
53
  const TARGET_PORT = Number(cfg('LAN_GATE_TARGET_PORT', 'targetPort', 3080))
54
+ // 0.1.2 browser auth: the host half hands us a one-use token URL via env.
55
+ // ABSENT env = 0.1.1 mode — every auth-exchange branch below short-circuits
56
+ // and proxying behaves exactly as before. Only the token value is kept (and
57
+ // never written to any response, log, or state file).
58
+ var UPSTREAM_TOKEN = null
59
+ ;(function () {
60
+ var url = process.env.LAN_GATE_UPSTREAM_TOKEN_URL
61
+ if (!url) return
62
+ try { UPSTREAM_TOKEN = new URL(url).searchParams.get('token') || null } catch (e) { UPSTREAM_TOKEN = null }
63
+ })()
54
64
  const TRUSTED_PROXIES = String(cfg('LAN_GATE_TRUSTED_PROXIES', 'trustedProxies', '')).split(',').map(function (s) { return s.trim() }).filter(Boolean)
55
65
  // UI language for the pages this file serves. "auto" (default) follows the
56
66
  // requesting browser's Accept-Language, which is the only language signal a
@@ -248,7 +258,12 @@ const COPY = {
248
258
  kindDesktop: '电脑',
249
259
  chipTitle: '设备配对管理',
250
260
  chipText: '配对管理',
251
- turnEnd: 'DSH 任务完成'
261
+ turnEnd: 'DSH 任务完成',
262
+ tapH1: '需要再点一次',
263
+ tapBody: '从外部应用打开的链接还没登录这个浏览器。点下面的站内链接一次即可进入。',
264
+ tapOpen: '打开 DSH 界面',
265
+ upstreamToken: 'DSH 上游鉴权:token(自动交换)',
266
+ upstreamNone: 'DSH 上游鉴权:无(0.1.1 直连模式)'
252
267
  },
253
268
  en: {
254
269
  pairH1: 'Device Pairing',
@@ -287,7 +302,12 @@ const COPY = {
287
302
  kindDesktop: 'Desktop',
288
303
  chipTitle: 'Device Pairing Admin',
289
304
  chipText: 'Pairing Admin',
290
- turnEnd: 'DSH task finished'
305
+ turnEnd: 'DSH task finished',
306
+ tapH1: 'Tap once to continue',
307
+ tapBody: 'A link opened from another app has not logged this browser in yet. Tap the in-page link below once to enter.',
308
+ tapOpen: 'Open DSH',
309
+ upstreamToken: 'Upstream auth: token (auto exchange)',
310
+ upstreamNone: 'Upstream auth: none (0.1.1 direct mode)'
291
311
  }
292
312
  }
293
313
  function copyOf(lang) { return COPY[lang] || COPY.zh }
@@ -313,15 +333,25 @@ function rateLimitPage(lang) {
313
333
  return gatePage(lang, C.rateH1 + ' · DSH', '<div class="logo">DSH</div><h1>' + C.rateH1 + '</h1><p class="bad">' + C.rateBody.replace('{n}', RATE_LIMIT_PER_MIN) + '</p>')
314
334
  }
315
335
 
336
+ // Strict-cookie guard: a cross-app top-level navigation never carries the
337
+ // SameSite=Strict cookie, so after one exchange round-trip the retry marker
338
+ // still 401s. Looping again would be an infinite redirect — instead serve a
339
+ // same-site page whose link, once tapped, IS same-site navigation and sends
340
+ // the cookie. href = the ORIGINAL path with the retry marker stripped.
341
+ function tapThroughPage(lang, target) {
342
+ var C = copyOf(lang)
343
+ return gatePage(lang, C.tapH1 + ' · DSH', '<div class="logo">DSH</div><h1>' + C.tapH1 + '</h1><p class="sub">' + C.tapBody + '</p><a class="btn" href="' + target + '">' + C.tapOpen + '</a>')
344
+ }
345
+
316
346
  function adminPage(lang) {
317
347
  var C = copyOf(lang)
318
- return '<!doctype html><html lang="' + (lang === 'zh' ? 'zh-CN' : 'en') + '"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="theme-color" content="#0f1115"><title>' + C.adminTitle + '</title><style>*{box-sizing:border-box}html,body{margin:0;padding:0}body{min-height:100dvh;font-family:system-ui,-apple-system,"Segoe UI","PingFang SC","Microsoft YaHei",sans-serif;background:radial-gradient(1100px 700px at 50% -10%,#1b2233 0%,#0f1115 55%);color:#e6e8ec;padding:20px 16px 30px}.card{width:100%;max-width:560px;margin:0 auto;padding:28px 24px 24px;border:1px solid #2a2f3a;border-radius:20px;background:#161a22;box-shadow:0 20px 60px rgba(0,0,0,.45)}.head{display:flex;align-items:center;gap:12px;margin-bottom:18px}.logo{width:44px;height:44px;flex:none;border-radius:13px;background:linear-gradient(135deg,#4c8dff,#7a5cff);display:flex;align-items:center;justify-content:center;font-size:19px;font-weight:700;color:#fff}h1{font-size:19px;margin:0}.sub{font-size:13px;color:#9aa3b2;margin:2px 0 0}.badge{display:inline-flex;align-items:center;gap:6px;font-size:12px;border-radius:999px;padding:3px 10px;border:1px solid #2a2f3a;color:#9aa3b2;margin:0 0 14px}.badge b{width:8px;height:8px;border-radius:50%;background:#34d399;box-shadow:0 0 8px #34d399}.label{font-size:13px;font-weight:600;margin:18px 0 8px}.code{font-family:ui-monospace,Consolas,monospace;font-size:26px;letter-spacing:6px;color:#9cc0ff;background:#0b0e14;border:1px solid #232a37;border-radius:10px;padding:12px 16px;text-align:center;margin:6px 0}.item{padding:10px 0;border-bottom:1px solid #232a37}.item:last-child{border-bottom:none}.name{font-size:14px;font-weight:600}.muted{font-size:12px;color:#9aa3b2;margin:3px 0;word-break:break-all}.row{display:flex;align-items:center;gap:8px;margin-top:8px;flex-wrap:wrap}.btn{font-size:13px;border:1px solid #2f3748;background:transparent;color:#e6e8ec;border-radius:9px;padding:7px 14px;cursor:pointer}.btn:active{background:#222838}.btn-primary{border-color:#4c8dff;color:#9cc0ff;background:rgba(76,141,255,.08)}.btn-danger{border-color:#f0716f;color:#f0716f}.kind{font-size:12px;border:1px solid #2f3748;background:transparent;color:#9aa3b2;border-radius:999px;padding:5px 12px;cursor:pointer}.kind.on{border-color:#4c8dff;color:#9cc0ff;background:rgba(76,141,255,.08)}.empty{font-size:13px;color:#9aa3b2;text-align:center;padding:12px 0}.note{font-size:12px;color:#6b7280;line-height:1.7;margin:16px 0 0}.err{color:#f0716f;font-size:13px}</style></head><body><div class="card"><div class="head"><div class="logo">DSH</div><div><h1>' + C.adminH1 + '</h1><p class="sub">' + C.adminSub + '</p></div></div><span class="badge"><b></b>' + C.running + ' · 127.0.0.1:' + PROXY_PORT + ' → DSH ' + TARGET_PORT + '</span>' +
348
+ return '<!doctype html><html lang="' + (lang === 'zh' ? 'zh-CN' : 'en') + '"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="theme-color" content="#0f1115"><title>' + C.adminTitle + '</title><style>*{box-sizing:border-box}html,body{margin:0;padding:0}body{min-height:100dvh;font-family:system-ui,-apple-system,"Segoe UI","PingFang SC","Microsoft YaHei",sans-serif;background:radial-gradient(1100px 700px at 50% -10%,#1b2233 0%,#0f1115 55%);color:#e6e8ec;padding:20px 16px 30px}.card{width:100%;max-width:560px;margin:0 auto;padding:28px 24px 24px;border:1px solid #2a2f3a;border-radius:20px;background:#161a22;box-shadow:0 20px 60px rgba(0,0,0,.45)}.head{display:flex;align-items:center;gap:12px;margin-bottom:18px}.logo{width:44px;height:44px;flex:none;border-radius:13px;background:linear-gradient(135deg,#4c8dff,#7a5cff);display:flex;align-items:center;justify-content:center;font-size:19px;font-weight:700;color:#fff}h1{font-size:19px;margin:0}.sub{font-size:13px;color:#9aa3b2;margin:2px 0 0}.badge{display:inline-flex;align-items:center;gap:6px;font-size:12px;border-radius:999px;padding:3px 10px;border:1px solid #2a2f3a;color:#9aa3b2;margin:0 0 14px}.badge b{width:8px;height:8px;border-radius:50%;background:#34d399;box-shadow:0 0 8px #34d399}.label{font-size:13px;font-weight:600;margin:18px 0 8px}.code{font-family:ui-monospace,Consolas,monospace;font-size:26px;letter-spacing:6px;color:#9cc0ff;background:#0b0e14;border:1px solid #232a37;border-radius:10px;padding:12px 16px;text-align:center;margin:6px 0}.item{padding:10px 0;border-bottom:1px solid #232a37}.item:last-child{border-bottom:none}.name{font-size:14px;font-weight:600}.muted{font-size:12px;color:#9aa3b2;margin:3px 0;word-break:break-all}.row{display:flex;align-items:center;gap:8px;margin-top:8px;flex-wrap:wrap}.btn{font-size:13px;border:1px solid #2f3748;background:transparent;color:#e6e8ec;border-radius:9px;padding:7px 14px;cursor:pointer}.btn:active{background:#222838}.btn-primary{border-color:#4c8dff;color:#9cc0ff;background:rgba(76,141,255,.08)}.btn-danger{border-color:#f0716f;color:#f0716f}.kind{font-size:12px;border:1px solid #2f3748;background:transparent;color:#9aa3b2;border-radius:999px;padding:5px 12px;cursor:pointer}.kind.on{border-color:#4c8dff;color:#9cc0ff;background:rgba(76,141,255,.08)}.empty{font-size:13px;color:#9aa3b2;text-align:center;padding:12px 0}.note{font-size:12px;color:#6b7280;line-height:1.7;margin:16px 0 0}.err{color:#f0716f;font-size:13px}</style></head><body><div class="card"><div class="head"><div class="logo">DSH</div><div><h1>' + C.adminH1 + '</h1><p class="sub">' + C.adminSub + '</p></div></div><span class="badge"><b></b>' + C.running + ' · 127.0.0.1:' + PROXY_PORT + ' → DSH ' + TARGET_PORT + '</span><div class="muted" id="authline"></div>' +
319
349
  '<div class="label">' + C.codeLabel + '</div><div id="pair" class="empty">' + C.codeEmpty + '</div><div class="row"><button class="btn btn-primary" data-act="new-code">' + C.codeNew + '</button></div><p class="note">' + C.codeNote + '</p>' +
320
350
  '<div class="label">' + C.devLabel + '</div><div id="devices" class="empty">' + C.loading + '</div>' +
321
351
  '<div class="row" style="margin-top:14px"><button class="btn btn-danger" data-act="revoke-all">' + C.revokeAll + '</button></div>' +
322
352
  '<p class="note">' + C.devNote + '</p><div id="err"></div></div><script>' + copyScript(lang) +
323
353
  'var KIND={auto:C.kindAuto,phone:C.kindPhone,desktop:C.kindDesktop};function post(body){return fetch("/lan-gate/action",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(body)}).then(function(){refresh()}).catch(function(){})}function esc(s){return String(s==null?"":s).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function fmt(ms){return ms?new Date(ms).toLocaleString():""}' +
324
- 'function render(s){var pairEl=document.getElementById("pair");if(s.pairing&&s.pairing.code){pairEl.innerHTML="<div class=\\"code\\">"+esc(s.pairing.code)+"</div><div class=\\"muted\\">"+C.validUntil+fmt(s.pairing.expiresAt)+"</div>";pairEl.className=""}else{pairEl.textContent=C.codeGone;pairEl.className="empty"}' +
354
+ 'function render(s){var al=document.getElementById("authline");if(al)al.textContent=s.upstreamAuth==="token"?C.upstreamToken:C.upstreamNone;var pairEl=document.getElementById("pair");if(s.pairing&&s.pairing.code){pairEl.innerHTML="<div class=\\"code\\">"+esc(s.pairing.code)+"</div><div class=\\"muted\\">"+C.validUntil+fmt(s.pairing.expiresAt)+"</div>";pairEl.className=""}else{pairEl.textContent=C.codeGone;pairEl.className="empty"}' +
325
355
  'var ds=s.devices||[],h="";if(!ds.length)h="<div class=\\"empty\\">"+C.noDevices+"</div>";for(var i=0;i<ds.length;i++){var d=ds[i];var kb="";var ks=["auto","phone","desktop"];for(var j=0;j<ks.length;j++){var k=ks[j];kb+="<button class=\\"kind"+(d.kind===k?" on":"")+"\\" data-act=\\"set-kind\\" data-id=\\""+esc(d.id)+"\\" data-kind=\\""+k+"\\">"+KIND[k]+"</button>"}h+="<div class=\\"item\\"><div class=\\"name\\">"+esc(d.name)+(d.hasPush?" · 🔔":"")+"</div><div class=\\"muted\\">"+esc(d.ua||"")+"</div><div class=\\"muted\\">"+C.paired+fmt(d.createdAt)+" · "+C.lastSeen+fmt(d.lastSeen)+"</div><div class=\\"row\\">"+kb+"<button class=\\"btn btn-danger\\" data-act=\\"revoke\\" data-id=\\""+esc(d.id)+"\\">"+C.revoke+"</button></div></div>"}document.getElementById("devices").innerHTML=h}' +
326
356
  'function refresh(){fetch("/lan-gate/status").then(function(r){return r.json()}).then(render).catch(function(){var e=document.getElementById("err");if(e)e.innerHTML="<div class=\\"err\\">"+C.statusErr+"</div>"})}' +
327
357
  'document.addEventListener("click",function(ev){var el=ev.target;if(!el||!el.getAttribute)return;var act=el.getAttribute("data-act");if(!act)return;if(act==="new-code"){post({action:"new-code"});return}if(act==="set-kind"){post({action:"set-kind",id:el.getAttribute("data-id"),kind:el.getAttribute("data-kind")});return}if(act==="revoke"){post({action:"revoke",id:el.getAttribute("data-id")});return}if(act==="revoke-all"){post({action:"revoke-all"});return}});refresh();setInterval(refresh,3000);' +
@@ -338,6 +368,8 @@ function statusHandler(req, res) {
338
368
  devices.sort(function (a, b) { return (b.lastSeen || 0) - (a.lastSeen || 0) })
339
369
  json(req, res, 200, {
340
370
  state: 'running', port: PROXY_PORT, target: TARGET_HOST + ':' + TARGET_PORT, pwa: true,
371
+ // 0.1.2 浏览器鉴权模式:token 存在 = 自动交换;缺失 = 0.1.1 直连。只报有无。
372
+ upstreamAuth: UPSTREAM_TOKEN === null ? 'none' : 'token',
341
373
  pairing: (pairing && pairing.expiresAt > Date.now()) ? pairing : null,
342
374
  devices: devices, pushSubscriptions: Object.keys(state.pushSubscriptions).length
343
375
  })
@@ -601,9 +633,80 @@ function cleanHeaders(req, clientIp) {
601
633
  return out
602
634
  }
603
635
 
636
+ // --- 0.1.2 browser-auth exchange --------------------------------------------
637
+ // DSH 0.1.2 requires a signed cookie even for the homepage. The gateway
638
+ // "plays courier": when the upstream 401s an HTML navigation, it does one
639
+ // `GET /?token=…` on the client's behalf (Host still rewritten to loopback,
640
+ // so the authority the cookie binds to is the same one DSH validates) and
641
+ // hands the resulting set-cookie straight back with a 303 to the client's
642
+ // original path + a retry marker. The marker breaks the SameSite=Strict
643
+ // dead-loop: a marked request that STILL 401s (cross-app navigation) gets the
644
+ // tap-through page instead of another redirect.
645
+ var AUTH_RETRY_MARKER = 'dsh-auth-retry=1'
646
+ function hasAuthRetry(url) {
647
+ var q = String(url || '').indexOf('?')
648
+ if (q < 0) return false
649
+ return String(url).slice(q + 1).split('&').indexOf(AUTH_RETRY_MARKER) >= 0
650
+ }
651
+ function addAuthRetry(url) {
652
+ return String(url || '/') + (String(url || '').indexOf('?') >= 0 ? '&' : '?') + AUTH_RETRY_MARKER
653
+ }
654
+ function stripAuthRetry(url) {
655
+ var u = String(url || '/')
656
+ var q = u.indexOf('?')
657
+ if (q < 0) return u
658
+ var rest = u.slice(q + 1).split('&').filter(function (p) { return p !== AUTH_RETRY_MARKER })
659
+ return rest.length ? u.slice(0, q) + '?' + rest.join('&') : u.slice(0, q)
660
+ }
661
+ function isHtmlNavigation(req) {
662
+ return req.method === 'GET'
663
+ && String(req.headers.accept || '').indexOf('text/html') >= 0
664
+ && String(req.url || '').split('?')[0].indexOf('/api/') !== 0
665
+ }
666
+ function serveTapThrough(req, res, rejectedUpRes) {
667
+ try { if (rejectedUpRes) rejectedUpRes.resume() } catch (e) {}
668
+ sendHtml(req, res, 200, tapThroughPage(langOf(req), stripAuthRetry(req.url || '/')))
669
+ }
670
+ function attemptAuthExchange(req, res, client, rejectedUpRes) {
671
+ // Free the rejected 401 socket before making the follow-up request.
672
+ try { rejectedUpRes.resume() } catch (e) {}
673
+ var exchangeHeaders = cleanHeaders({ headers: { accept: 'text/html' } }, client.ip)
674
+ var exchange = http.request({
675
+ host: TARGET_HOST, port: TARGET_PORT, method: 'GET',
676
+ path: '/?token=' + encodeURIComponent(UPSTREAM_TOKEN),
677
+ headers: exchangeHeaders
678
+ }, function (xRes) {
679
+ var xc = xRes.statusCode || 0
680
+ var cookies = xRes.headers['set-cookie']
681
+ if (xc >= 300 && xc < 400 && cookies && cookies.length) {
682
+ // The token worked: pass the upstream cookie through verbatim and send
683
+ // the client back to its original path, marked once.
684
+ var out = { location: addAuthRetry(req.url), 'set-cookie': cookies }
685
+ try { res.writeHead(303, out) } catch (e2) {}
686
+ res.end()
687
+ return
688
+ }
689
+ // Token exchange failed too: guard page, never another redirect.
690
+ serveTapThrough(req, res)
691
+ })
692
+ exchange.on('error', function () {
693
+ try { if (!res.headersSent) res.writeHead(502, { 'Content-Type': 'text/plain; charset=utf-8' }); res.end('Bad Gateway') } catch (e) {}
694
+ })
695
+ exchange.end()
696
+ }
697
+
604
698
  function forwardRequest(req, res, client, device, isLocal) {
605
699
  var headers = cleanHeaders(req, client.ip)
606
700
  var upstream = http.request({ host: TARGET_HOST, port: TARGET_PORT, method: req.method, path: req.url, headers: headers }, function (upRes) {
701
+ // 0.1.2 browser auth: an HTML navigation that upstream 401s is either
702
+ // exchanged for a cookie (first try) or, when the retry marker says we
703
+ // already tried, answered with the tap-through page — never a 401 body
704
+ // handed to a phone that cannot act on it, and never a second redirect.
705
+ if (UPSTREAM_TOKEN !== null && upRes.statusCode === 401 && isHtmlNavigation(req)) {
706
+ if (hasAuthRetry(req.url)) { serveTapThrough(req, res, upRes); return }
707
+ attemptAuthExchange(req, res, client, upRes)
708
+ return
709
+ }
607
710
  var outHeaders = {}; for (var k in upRes.headers) outHeaders[k] = upRes.headers[k]
608
711
  // upRes is already de-chunked by the http client; forwarding hop-by-hop
609
712
  // framing headers would produce an invalid (or double-framed) response.
@@ -1,5 +1,5 @@
1
1
  import type { PropsLocale, PropsRuntime, PropsStore } from '@deepseek-ai/dsh-client-ui-slots';
2
- import type { SessionId, WorkspaceId } from '@deepseek-ai/dsh-client-runtime/client';
2
+ import type { SessionId, UsePendingInteractions, WorkspaceId } from './compat/types.ts';
3
3
  import { NS } from './locales.ts';
4
4
  import type { createNavStore } from './nav-store.ts';
5
5
  /** Full props for the phone home screen (shell.overlay entry). */
@@ -12,6 +12,11 @@ export type MobileHomeProps = PropsRuntime<'shell.overlay'> & PropsStore<ReturnT
12
12
  downloadSessionLog: (id: SessionId) => void;
13
13
  /** Bound ctx.workspaces.archiveSession(id) — the row swipe action. */
14
14
  archiveSession: (id: SessionId) => Promise<void>;
15
+ /**
16
+ * 0.1.2 的待处理交互选择器标准 prop;0.1.1 没有这个 prop,运行时读到
17
+ * undefined(见组件里 EMPTY_PENDING_HOOK 兜底)。
18
+ */
19
+ useSessionPendingInteraction?: UsePendingInteractions;
15
20
  };
16
21
  /**
17
22
  * Phone home screen: the full-screen session list that owns the first level
@@ -22,5 +27,5 @@ export type MobileHomeProps = PropsRuntime<'shell.overlay'> & PropsStore<ReturnT
22
27
  * all navigation from the injected official actions; nothing here reads the
23
28
  * official DOM.
24
29
  */
25
- export declare function MobileHome({ useSessions, useWorkspaces, useStore, actions, openSession, startSession, downloadSessionLog, archiveSession, t, }: MobileHomeProps): import("react").JSX.Element | null;
30
+ export declare function MobileHome({ useSessions, useWorkspaces, useSessionPendingInteraction, useStore, actions, openSession, startSession, downloadSessionLog, archiveSession, t, }: MobileHomeProps): import("react").JSX.Element | null;
26
31
  //# sourceMappingURL=MobileHome.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MobileHome.d.ts","sourceRoot":"","sources":["../../../src/client/MobileHome.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAA;AAS7F,OAAO,KAAK,EAAE,SAAS,EAAkB,WAAW,EAAE,MAAM,wCAAwC,CAAA;AACpG,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAA;AAMjC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAMpD,kEAAkE;AAClE,MAAM,MAAM,eAAe,GACvB,YAAY,CAAC,eAAe,CAAC,GAC7B,UAAU,CAAC,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC,GAC7C,WAAW,CAAC,OAAO,EAAE,CAAC,GACtB;IACA,mCAAmC;IACnC,WAAW,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,IAAI,CAAA;IACpC,uDAAuD;IACvD,YAAY,EAAE,CAAC,WAAW,CAAC,EAAE,WAAW,KAAK,IAAI,CAAA;IACjD,2EAA2E;IAC3E,kBAAkB,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,IAAI,CAAA;IAC3C,sEAAsE;IACtE,cAAc,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CACjD,CAAA;AAkMH;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,EACzB,WAAW,EACX,aAAa,EACb,QAAQ,EACR,OAAO,EACP,WAAW,EACX,YAAY,EACZ,kBAAkB,EAClB,cAAc,EACd,CAAC,GACF,EAAE,eAAe,sCAgRjB"}
1
+ {"version":3,"file":"MobileHome.d.ts","sourceRoot":"","sources":["../../../src/client/MobileHome.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAA;AAU7F,OAAO,KAAK,EAAoB,SAAS,EAAE,sBAAsB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACzG,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAA;AAMjC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAMpD,kEAAkE;AAClE,MAAM,MAAM,eAAe,GACvB,YAAY,CAAC,eAAe,CAAC,GAC7B,UAAU,CAAC,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC,GAC7C,WAAW,CAAC,OAAO,EAAE,CAAC,GACtB;IACA,mCAAmC;IACnC,WAAW,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,IAAI,CAAA;IACpC,uDAAuD;IACvD,YAAY,EAAE,CAAC,WAAW,CAAC,EAAE,WAAW,KAAK,IAAI,CAAA;IACjD,2EAA2E;IAC3E,kBAAkB,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,IAAI,CAAA;IAC3C,sEAAsE;IACtE,cAAc,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAChD;;;OAGG;IACH,4BAA4B,CAAC,EAAE,sBAAsB,CAAA;CACtD,CAAA;AAgNH;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,EACzB,WAAW,EACX,aAAa,EACb,4BAA4B,EAC5B,QAAQ,EACR,OAAO,EACP,WAAW,EACX,YAAY,EACZ,kBAAkB,EAClB,cAAc,EACd,CAAC,GACF,EAAE,eAAe,sCAqRjB"}
@@ -1,5 +1,5 @@
1
1
  import type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
2
- import type { SessionFace, SessionId } from '@deepseek-ai/dsh-client-runtime/client';
2
+ import type { RenameResult, SessionId } from './compat/types.ts';
3
3
  import { NS } from './locales.ts';
4
4
  /** Full props for the session-info sheet (header.utilities, second entry). */
5
5
  export type MobileSessionInfoProps = PropsRuntime<'conversation.session.header.utilities'> & PropsLocale<typeof NS> & {
@@ -8,7 +8,7 @@ export type MobileSessionInfoProps = PropsRuntime<'conversation.session.header.u
8
8
  /** Bound ctx.sessions.open(id) — lands on the freshly forked session. */
9
9
  openSession: (id: SessionId) => void;
10
10
  /** Bound ctx.sessions.binding(id)?.session.rename(title); undefined when the binding is gone. */
11
- renameSession: (sessionId: SessionId, title: string) => ReturnType<SessionFace['rename']> | undefined;
11
+ renameSession: (sessionId: SessionId, title: string) => RenameResult | undefined;
12
12
  /** Bound ctx.workspaces.archiveSession(sessionId). */
13
13
  archiveSession: (sessionId: SessionId) => Promise<void>;
14
14
  /** Bound ctx.sessionLogDownload.download(sessionId) — owns its own progress/result modal. */
@@ -1 +1 @@
1
- {"version":3,"file":"MobileSessionInfo.d.ts","sourceRoot":"","sources":["../../../src/client/MobileSessionInfo.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AASjF,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,wCAAwC,CAAA;AACpF,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAA;AAiBjC,8EAA8E;AAC9E,MAAM,MAAM,sBAAsB,GAC9B,YAAY,CAAC,uCAAuC,CAAC,GACrD,WAAW,CAAC,OAAO,EAAE,CAAC,GACtB;IACA,4CAA4C;IAC5C,WAAW,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,OAAO,CAAC,SAAS,CAAC,CAAA;IACzD,yEAAyE;IACzE,WAAW,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,IAAI,CAAA;IACpC,iGAAiG;IACjG,aAAa,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,KAAK,UAAU,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,GAAG,SAAS,CAAA;IACrG,sDAAsD;IACtD,cAAc,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACvD,6FAA6F;IAC7F,kBAAkB,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAC5D,CAAA;AA0CH;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,SAAS,EACT,WAAW,EACX,aAAa,EACb,WAAW,EACX,WAAW,EACX,aAAa,EACb,cAAc,EACd,kBAAkB,EAClB,CAAC,GACF,EAAE,sBAAsB,sCAsNxB"}
1
+ {"version":3,"file":"MobileSessionInfo.d.ts","sourceRoot":"","sources":["../../../src/client/MobileSessionInfo.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AAUjF,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAChE,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAA;AAiBjC,8EAA8E;AAC9E,MAAM,MAAM,sBAAsB,GAC9B,YAAY,CAAC,uCAAuC,CAAC,GACrD,WAAW,CAAC,OAAO,EAAE,CAAC,GACtB;IACA,4CAA4C;IAC5C,WAAW,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,OAAO,CAAC,SAAS,CAAC,CAAA;IACzD,yEAAyE;IACzE,WAAW,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,IAAI,CAAA;IACpC,iGAAiG;IACjG,aAAa,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,KAAK,YAAY,GAAG,SAAS,CAAA;IAChF,sDAAsD;IACtD,cAAc,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACvD,6FAA6F;IAC7F,kBAAkB,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAC5D,CAAA;AA0CH;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,SAAS,EACT,WAAW,EACX,aAAa,EACb,WAAW,EACX,WAAW,EACX,aAAa,EACb,cAAc,EACd,kBAAkB,EAClB,CAAC,GACF,EAAE,sBAAsB,sCAuNxB"}
@@ -0,0 +1,62 @@
1
+ import type { ActionsDecl, StoreHandle, StoreSpec } from '@deepseek-ai/dsh-client-ui-slots';
2
+ /** Writable snapshot source: read + subscribe + mutate/wholesale-set. */
3
+ export interface SnapshotStore<T> {
4
+ /** Read the current state. Same reference every time until an update. */
5
+ getSnapshot(): T;
6
+ /**
7
+ * Subscribe to state changes.
8
+ * @param fn - invalidation callback.
9
+ * @returns unsubscribe function.
10
+ */
11
+ subscribe(fn: () => void): () => void;
12
+ /**
13
+ * Mutate the state through a draft.
14
+ * @param mutator - draft mutator.
15
+ */
16
+ update(mutator: (draft: T) => void): void;
17
+ /** Replace the state wholesale. @param next - next state. */
18
+ set(next: T): void;
19
+ }
20
+ /**
21
+ * Create a snapshot store with optional whole-value localStorage persistence.
22
+ * The 0.1.1 `opts.flush: 'raf' | 'sync'` mode is deliberately not
23
+ * implemented: this plugin never used it (chips-store.ts persists
24
+ * synchronously and React reads via useSyncExternalStore).
25
+ * @param init - initial state.
26
+ * @param opts - optional persistence key.
27
+ * @returns the store.
28
+ */
29
+ export declare function createSnapshotStore<T>(init: T, opts?: {
30
+ persist?: {
31
+ name: string;
32
+ };
33
+ }): SnapshotStore<T>;
34
+ /**
35
+ * Declare a store: an init lambda (fresh state per instance), an optional
36
+ * persistence key, and the full write set as pure draft mutators. Returns
37
+ * the registration currency of the slot system's store seat.
38
+ *
39
+ * The `A & ActionsDecl<T>` actions position is load-bearing: T resolves from
40
+ * `init` in the first inference round, and the intersection then
41
+ * contextually types each mutator's draft parameter, so call sites write
42
+ * `(draft, view: MobileView) => { … }` without annotating the draft. Keep
43
+ * the intersection — dropping it makes nav-store.ts fail to typecheck.
44
+ *
45
+ * Persist-key rules mirror the official defineStore: `decl.persist` alone at
46
+ * root scope, suffixed with `.{scopeKey}` per session scope, none when
47
+ * `decl.persist` is absent.
48
+ * @param decl - init/persist/actions declaration.
49
+ * @returns the store handle.
50
+ */
51
+ export declare function defineStore<T, A extends ActionsDecl<T>>(decl: StoreSpec<T, A> & {
52
+ actions: A & ActionsDecl<T>;
53
+ }): StoreHandle<T, A>;
54
+ /**
55
+ * Last path segment of a workspace directory, for showing "which workspace
56
+ * is this session in" on the mobile info card. 0.1.1's one-line
57
+ * implementation, kept verbatim.
58
+ * @param cwd - a workspace path (posix or windows separators).
59
+ * @returns the trailing name, or '' when no non-empty segment exists.
60
+ */
61
+ export declare function workspaceTitleOf(cwd: string): string;
62
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../../src/client/compat/store.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EACV,WAAW,EAEX,WAAW,EAEX,SAAS,EACV,MAAM,kCAAkC,CAAA;AAEzC,yEAAyE;AACzE,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B,yEAAyE;IACzE,WAAW,IAAI,CAAC,CAAA;IAChB;;;;OAIG;IACH,SAAS,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAA;IACrC;;;OAGG;IACH,MAAM,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,GAAG,IAAI,CAAA;IACzC,6DAA6D;IAC7D,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,CAAA;CACnB;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EACnC,IAAI,EAAE,CAAC,EACP,IAAI,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GACpC,aAAa,CAAC,CAAC,CAAC,CA4DlB;AAcD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,CAAC,SAAS,WAAW,CAAC,CAAC,CAAC,EACrD,IAAI,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG;IAAE,OAAO,EAAE,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAAA;CAAE,GACtD,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,CA2CnB;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEpD"}
@@ -0,0 +1,84 @@
1
+ import type { Context } from '@deepseek-ai/cordis';
2
+ import type { SessionId } from '@deepseek-ai/dsh-session/types';
3
+ import type { WorkspaceId } from '@deepseek-ai/dsh-workspace/types';
4
+ /**
5
+ * Browser-half cordis context. 0.1.1's `dsh-client-runtime` exported
6
+ * `ClientContext` as the bare `Context` type (lib/types/client/index.d.ts:55);
7
+ * 0.1.2 has no such alias. Re-declared here under the same name so the
8
+ * dozen files that used it only change their import path, not the
9
+ * identifier.
10
+ */
11
+ export type ClientContext = Context;
12
+ /** Session id. Both versions ship it in `@deepseek-ai/dsh-session/types`; re-exported to collect import points. */
13
+ export type { SessionId };
14
+ /** Workspace id. 0.1.2 lives in `@deepseek-ai/dsh-workspace/types`. */
15
+ export type { WorkspaceId };
16
+ /**
17
+ * Structural mirror of the session-row fields this plugin reads, valid
18
+ * against both versions' `SessionSummary`. Deliberately NOT imported from
19
+ * either version (see the file header): `projectionValues` stays `unknown`
20
+ * rather than copying the host's
21
+ * `Readonly<Partial<SessionProjectionMap>>` — that type differs between
22
+ * versions and fights assignments under `exactOptionalPropertyTypes`. The
23
+ * single read site (MobileHome.tsx:311) already casts.
24
+ *
25
+ * `agentPreset` and `pendingInteraction` are intentionally absent: their
26
+ * real readers (MobileHome.tsx, MobileSessionInfo.tsx) receive rows typed by
27
+ * the host's devDeps (0.1.2), not by this mirror, so fields here would not
28
+ * help them — use {@link agentPresetOf} / {@link hasPendingInteraction}
29
+ * instead.
30
+ */
31
+ export interface MobileSessionRow {
32
+ id: SessionId;
33
+ title?: string;
34
+ displayTitle: string;
35
+ cwd?: string;
36
+ parentId?: SessionId;
37
+ origin?: 'subagent';
38
+ running: boolean;
39
+ completed?: boolean;
40
+ blank: boolean;
41
+ updatedAt: number;
42
+ /** 宿主投影值;本插件只读 sessionStats.turns,读的地方自己 cast。 */
43
+ projectionValues?: unknown;
44
+ }
45
+ /**
46
+ * 0.1.1's session row carries `agentPreset`; 0.1.2 dropped it. Reading it
47
+ * must not depend on which version's types are in scope in the current
48
+ * file, so narrow through unknown.
49
+ * @param row - a session row of either version.
50
+ * @returns the agent preset name, or undefined when absent.
51
+ */
52
+ export declare function agentPresetOf(row: unknown): string | undefined;
53
+ /**
54
+ * 0.1.1's session row carries `pendingInteraction` (the pending-interaction
55
+ * state behind the sidebar's yellow dot); 0.1.2 serves it from the
56
+ * uiSession service instead. This answers only "does this row carry a
57
+ * pending interaction".
58
+ * @param row - a session row of either version.
59
+ * @returns true when the row has a pending interaction.
60
+ */
61
+ export declare function hasPendingInteraction(row: unknown): boolean;
62
+ /**
63
+ * `ctx.sessions.binding(id)?.session.rename(title)` 的返回值。
64
+ * 两版的包裹类型不同(0.1.1 是 RpcResult、0.1.2 是 RemoteResult),但判别式
65
+ * 联合的形状一致:成功分支带 ok:true(还有个我们不读的 value),失败分支带
66
+ * ok:false + error。这里只镜像本插件真正读到的两个字段(ok、error.message),
67
+ * 两版的真类型都能结构赋值进来。
68
+ */
69
+ export type RenameResult = Promise<{
70
+ readonly ok: true;
71
+ } | {
72
+ readonly ok: false;
73
+ readonly error: {
74
+ readonly message: string;
75
+ };
76
+ }>;
77
+ /**
78
+ * 待处理交互的选择器 hook(0.1.2 的标准 prop `useSessionPendingInteraction`);
79
+ * 0.1.1 没有这个 prop,运行时读到 undefined。本地镜像只描述本插件读到的形状
80
+ * (按会话 id 的只读 Map + 选择器调用),不从
81
+ * `@deepseek-ai/dsh-client-ui-session/client` 拿类型——那个包 0.1.1 装不到。
82
+ */
83
+ export type UsePendingInteractions = <S>(sel: (m: ReadonlyMap<SessionId, unknown>) => S, eq?: (a: S, b: S) => boolean) => S;
84
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/client/compat/types.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAMlD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAA;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAA;AAEnE;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,GAAG,OAAO,CAAA;AAEnC,mHAAmH;AACnH,YAAY,EAAE,SAAS,EAAE,CAAA;AAEzB,uEAAuE;AACvE,YAAY,EAAE,WAAW,EAAE,CAAA;AAE3B;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,SAAS,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,YAAY,EAAE,MAAM,CAAA;IACpB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,SAAS,CAAA;IACpB,MAAM,CAAC,EAAE,UAAU,CAAA;IACnB,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,KAAK,EAAE,OAAO,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,kDAAkD;IAClD,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAC3B;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAG9D;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAG3D;AAED;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,GAAG,OAAO,CAC9B;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAA;CAAE,GACrB;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CACvE,CAAA;AAED;;;;;GAKG;AACH,MAAM,MAAM,sBAAsB,GAChC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,WAAW,CAAC,SAAS,EAAE,OAAO,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,OAAO,KAAK,CAAC,CAAA"}
@@ -1,4 +1,4 @@
1
- import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
1
+ import type { ClientContext } from './compat/types.ts';
2
2
  /**
3
3
  * Debug badge — ?mobile-nav-debug=1
4
4
  * Renders a live state overlay (URL, viewport, media queries, shell chrome,
@@ -1 +1 @@
1
- {"version":3,"file":"debug.d.ts","sourceRoot":"","sources":["../../../src/client/debug.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAC3E;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAqP1D"}
1
+ {"version":3,"file":"debug.d.ts","sourceRoot":"","sources":["../../../src/client/debug.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACtD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAqP1D"}
@@ -1,4 +1,4 @@
1
- import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
1
+ import type { ClientContext } from '../compat/types.ts';
2
2
  /** dsh-web-ui 兼容:explorer / preview 列的显隐标记与升起动画(同域同机制,合并一处)。 */
3
3
  export declare function installAionuiCompat(ctx: ClientContext): void;
4
4
  //# sourceMappingURL=aionui-compat.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"aionui-compat.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/aionui-compat.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAE3E,gEAAgE;AAChE,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAmL5D"}
1
+ {"version":3,"file":"aionui-compat.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/aionui-compat.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAEvD,gEAAgE;AAChE,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAmL5D"}
@@ -1,4 +1,4 @@
1
- import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
1
+ import type { ClientContext } from '../compat/types.ts';
2
2
  /** S6: the two-gesture set — left-edge swipe-back and sheet drag-to-close.
3
3
  * Both install/uninstall their own document listeners on the phone
4
4
  * breakpoint's matchMedia change, so at >= 768px this is a true no-op (no
@@ -1 +1 @@
1
- {"version":3,"file":"gestures.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/gestures.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAiQ3E;;;2EAG2E;AAC3E,wBAAgB,eAAe,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAGxD"}
1
+ {"version":3,"file":"gestures.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/gestures.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAiQvD;;;2EAG2E;AAC3E,wBAAgB,eAAe,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAGxD"}
@@ -1,4 +1,4 @@
1
- import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
1
+ import type { ClientContext } from '../compat/types.ts';
2
2
  /**
3
3
  * Session header running-status dot (S2). No official element exists to
4
4
  * reposition (ConversationSessionHeader renders only the crumb title, the
@@ -1 +1 @@
1
- {"version":3,"file":"header-status.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/header-status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAG3E;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAc/D"}
1
+ {"version":3,"file":"header-status.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/header-status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAGvD;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAiC/D"}
@@ -1,4 +1,4 @@
1
- import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
1
+ import type { ClientContext } from '../compat/types.ts';
2
2
  import { type KeyboardTuning } from '../client-config.ts';
3
3
  /** The safety pad this platform gets: the configured clearance, or nothing
4
4
  * off Android. UA sniffing is the right tool here — the target is a platform
@@ -1 +1 @@
1
- {"version":3,"file":"keyboard-avoid.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/keyboard-avoid.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAC3E,OAAO,EAAmC,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAoC1F;;;uEAGuE;AACvE,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,GAAE,MAAsB,GAAG,MAAM,CAElF;AAyBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,GAAE,cAAkC,GAAG,MAAM,CAErG;AAED,iDAAiD;AACjD,MAAM,WAAW,eAAe;IAC9B,mDAAmD;IACnD,WAAW,EAAE,MAAM,CAAA;IACnB,6BAA6B;IAC7B,QAAQ,EAAE,MAAM,CAAA;IAChB,gCAAgC;IAChC,SAAS,EAAE,MAAM,CAAA;IACjB,4BAA4B;IAC5B,KAAK,EAAE,MAAM,CAAA;CACd;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,CAI7D;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,cAAc,EAAE,OAAO,EACvB,GAAG,EAAE,MAAM,GACV,MAAM,CAUR;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CA2L7D"}
1
+ {"version":3,"file":"keyboard-avoid.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/keyboard-avoid.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AACvD,OAAO,EAAmC,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAoC1F;;;uEAGuE;AACvE,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,GAAE,MAAsB,GAAG,MAAM,CAElF;AAyBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,GAAE,cAAkC,GAAG,MAAM,CAErG;AAED,iDAAiD;AACjD,MAAM,WAAW,eAAe;IAC9B,mDAAmD;IACnD,WAAW,EAAE,MAAM,CAAA;IACnB,6BAA6B;IAC7B,QAAQ,EAAE,MAAM,CAAA;IAChB,gCAAgC;IAChC,SAAS,EAAE,MAAM,CAAA;IACjB,4BAA4B;IAC5B,KAAK,EAAE,MAAM,CAAA;CACd;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,CAI7D;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,cAAc,EAAE,OAAO,EACvB,GAAG,EAAE,MAAM,GACV,MAAM,CAUR;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CA2L7D"}
@@ -1,4 +1,4 @@
1
- import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
1
+ import type { ClientContext } from '../compat/types.ts';
2
2
  /**
3
3
  * S9 — keep the phone keyboard down until the user asks for it.
4
4
  *
@@ -1 +1 @@
1
- {"version":3,"file":"keyboard-guard.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/keyboard-guard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAW3E;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAqF7D"}
1
+ {"version":3,"file":"keyboard-guard.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/keyboard-guard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAWvD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAqF7D"}
@@ -17,6 +17,6 @@
17
17
  * Phone only. On desktop the back gesture is not a thing and the official
18
18
  * dialogs keep their own behaviour untouched (the repo's desktop no-op rule).
19
19
  */
20
- import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
20
+ import type { ClientContext } from '../compat/types.ts';
21
21
  export declare function installModalBack(ctx: ClientContext): void;
22
22
  //# sourceMappingURL=modal-back.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"modal-back.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/modal-back.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAyB3E,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAoDzD"}
1
+ {"version":3,"file":"modal-back.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/modal-back.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAyBvD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAoDzD"}
@@ -0,0 +1,33 @@
1
+ import type { ClientContext } from '../compat/types.ts';
2
+ /**
3
+ * Phone: park the composer row's third-party controls inside the model sheet.
4
+ *
5
+ * With the speed chip and the vision toggle both present on a GPT model the
6
+ * row runs out of width. Both are model-scoped settings, so the model sheet —
7
+ * which already holds 模型 and 推理等级 — is where they belong (user request,
8
+ * 2026-09-06).
9
+ *
10
+ * Why move the real controls instead of drawing our own rows that drive them:
11
+ * the same reason native-trigger-overlay.ts moves the real trigger. A stand-in
12
+ * has to script the original, which is a road this plugin does not go down —
13
+ * beyond the trusted-input wall that effect documents, our own rows would have
14
+ * to mirror every piece of state (speed tier, disabled, aria-pressed, whether
15
+ * a vision twin exists for the current model) and would rot on the next
16
+ * upstream restyle. Moving the node keeps one source of truth: their React
17
+ * roots go on owning and updating these elements, we only change where they
18
+ * hang.
19
+ *
20
+ * Measured 2026-09-06 (DSH 0.1.2, 390px) before writing this — the two things
21
+ * that would have killed the approach both hold: a relocated control survives
22
+ * host re-renders (typing into the composer re-renders the row and does not
23
+ * yank it back) and stays hit-testable at its new position.
24
+ *
25
+ * Restoring on close is not cosmetic. The sheet unmounts when it closes and
26
+ * anything still inside goes with it, so the controls would vanish from the
27
+ * page while their React roots kept updating detached nodes. The observer
28
+ * therefore watches the menu leaving too, and the parked node is held as a
29
+ * reference rather than looked up — once the menu is detached a document
30
+ * query can no longer find it.
31
+ */
32
+ export declare function installModelSheetExtras(ctx: ClientContext): void;
33
+ //# sourceMappingURL=model-sheet-extras.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-sheet-extras.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/model-sheet-extras.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AA8DvD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAkEhE"}
@@ -20,6 +20,6 @@
20
20
  * trigger on top keeps the behaviour. Pills are `pointer-events: none` so a
21
21
  * tap can only ever reach the real thing — no double handling.
22
22
  */
23
- import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
23
+ import type { ClientContext } from '../compat/types.ts';
24
24
  export declare function installNativeTriggerOverlay(ctx: ClientContext): void;
25
25
  //# sourceMappingURL=native-trigger-overlay.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"native-trigger-overlay.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/native-trigger-overlay.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAuC3E,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAuCpE"}
1
+ {"version":3,"file":"native-trigger-overlay.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/native-trigger-overlay.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAuCvD,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAuCpE"}
@@ -1,4 +1,4 @@
1
- import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
1
+ import type { ClientContext } from '../compat/types.ts';
2
2
  /**
3
3
  * Phone chrome: KEEP the system status bar (no fullscreen) and make it
4
4
  * blend into the page. On narrow screens:
@@ -1 +1 @@
1
- {"version":3,"file":"phone-chrome.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/phone-chrome.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAE3E;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAkC3D;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,4BAA4B,CAAC,KAAK,EAAE;IAClD,UAAU,EAAE,OAAO,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;CACf,GAAG,OAAO,CAIV;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CA6E5D;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAyCzD"}
1
+ {"version":3,"file":"phone-chrome.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/phone-chrome.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAEvD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAkC3D;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,4BAA4B,CAAC,KAAK,EAAE;IAClD,UAAU,EAAE,OAAO,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;CACf,GAAG,OAAO,CAIV;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CA6E5D;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAyCzD"}
@@ -1,4 +1,4 @@
1
- import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
1
+ import type { ClientContext } from '../compat/types.ts';
2
2
  /** Whole-row node kinds that are turn *process*, not conversation content.
3
3
  * Keys are ChatNodeSeat's own `data-chat-flow-kind` dispatch values
4
4
  * (registerChatNodeRenderers, lib/client.js:9322): tool calls, injected
@@ -1 +1 @@
1
- {"version":3,"file":"turn-fold.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/turn-fold.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAkD3E;;;;;;;sDAOsD;AACtD,eAAO,MAAM,aAAa,8CAA+C,CAAA;AAMzE;sEACsE;AACtE,eAAO,MAAM,KAAK,6BAA2B,CAAA;AAS7C,4DAA4D;AAC5D,eAAO,MAAM,IAAI,wBAAwB,CAAA;AA4FzC;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAyNxD"}
1
+ {"version":3,"file":"turn-fold.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/turn-fold.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAkDvD;;;;;;;sDAOsD;AACtD,eAAO,MAAM,aAAa,8CAA+C,CAAA;AAMzE;sEACsE;AACtE,eAAO,MAAM,KAAK,6BAA2B,CAAA;AAS7C,4DAA4D;AAC5D,eAAO,MAAM,IAAI,wBAAwB,CAAA;AA4FzC;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAyNxD"}
@@ -1,4 +1,4 @@
1
- import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
1
+ import type { ClientContext } from '../compat/types.ts';
2
2
  /**
3
3
  * "内测声明" first-run notice, opt-out half (ALL widths — same user-directed
4
4
  * exception as the _previewBadge rule in styles/base.css.ts).
@@ -1 +1 @@
1
- {"version":3,"file":"welcome-notice.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/welcome-notice.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAU3E;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAsCnE"}
1
+ {"version":3,"file":"welcome-notice.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/welcome-notice.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAUvD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAsCnE"}
@@ -1,4 +1,4 @@
1
- import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
1
+ import type { ClientContext } from '../compat/types.ts';
2
2
  /**
3
3
  * Phone: an @-file reference tap in the workbench closes the workbench.
4
4
  *
@@ -1 +1 @@
1
- {"version":3,"file":"workbench-ref-close.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/workbench-ref-close.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAuB3E;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAmBjE"}
1
+ {"version":3,"file":"workbench-ref-close.d.ts","sourceRoot":"","sources":["../../../../src/client/effects/workbench-ref-close.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAuBvD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAmBjE"}
@@ -1,4 +1,4 @@
1
- import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
1
+ import type { ClientContext } from './compat/types.ts';
2
2
  import type { MobileNavKey } from './locales.ts';
3
3
  declare module '@deepseek-ai/dsh-client-ui-slots' {
4
4
  interface LocaleNamespaceMap {