dsh-zen-remote 1.0.0

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 (136) hide show
  1. package/AGENTS.md +51 -0
  2. package/LICENSE +38 -0
  3. package/README.md +237 -0
  4. package/assets/home.png +0 -0
  5. package/assets/info.png +0 -0
  6. package/assets/pairing.png +0 -0
  7. package/assets/session.png +0 -0
  8. package/assets/sheet.png +0 -0
  9. package/cordis.patch.yml +17 -0
  10. package/cordis.patch.yml.example +16 -0
  11. package/docs/interface.md +200 -0
  12. package/docs/remote-access.en.md +335 -0
  13. package/docs/remote-access.md +422 -0
  14. package/dsh-push.mjs +213 -0
  15. package/lan-gate.mjs +78 -0
  16. package/lib/client.js +6615 -0
  17. package/lib/index.js +310 -0
  18. package/lib/index.js.map +1 -0
  19. package/lib/lan-gate-server.cjs +626 -0
  20. package/lib/types/client/MobileAttachButton.d.ts +25 -0
  21. package/lib/types/client/MobileAttachButton.d.ts.map +1 -0
  22. package/lib/types/client/MobileAttachChips.d.ts +32 -0
  23. package/lib/types/client/MobileAttachChips.d.ts.map +1 -0
  24. package/lib/types/client/MobileDrawerFooter.d.ts +21 -0
  25. package/lib/types/client/MobileDrawerFooter.d.ts.map +1 -0
  26. package/lib/types/client/MobileHome.d.ts +24 -0
  27. package/lib/types/client/MobileHome.d.ts.map +1 -0
  28. package/lib/types/client/MobileHomeChips.d.ts +76 -0
  29. package/lib/types/client/MobileHomeChips.d.ts.map +1 -0
  30. package/lib/types/client/MobileNavOverlay.d.ts +15 -0
  31. package/lib/types/client/MobileNavOverlay.d.ts.map +1 -0
  32. package/lib/types/client/MobileNavToggle.d.ts +18 -0
  33. package/lib/types/client/MobileNavToggle.d.ts.map +1 -0
  34. package/lib/types/client/MobileSessionHeader.d.ts +58 -0
  35. package/lib/types/client/MobileSessionHeader.d.ts.map +1 -0
  36. package/lib/types/client/MobileSessionInfo.d.ts +41 -0
  37. package/lib/types/client/MobileSessionInfo.d.ts.map +1 -0
  38. package/lib/types/client/attach-upload.d.ts +78 -0
  39. package/lib/types/client/attach-upload.d.ts.map +1 -0
  40. package/lib/types/client/chips-store.d.ts +13 -0
  41. package/lib/types/client/chips-store.d.ts.map +1 -0
  42. package/lib/types/client/debug.d.ts +9 -0
  43. package/lib/types/client/debug.d.ts.map +1 -0
  44. package/lib/types/client/effects/aionui-compat.d.ts +4 -0
  45. package/lib/types/client/effects/aionui-compat.d.ts.map +1 -0
  46. package/lib/types/client/effects/gestures.d.ts +7 -0
  47. package/lib/types/client/effects/gestures.d.ts.map +1 -0
  48. package/lib/types/client/effects/header-status.d.ts +15 -0
  49. package/lib/types/client/effects/header-status.d.ts.map +1 -0
  50. package/lib/types/client/effects/phone-chrome.d.ts +106 -0
  51. package/lib/types/client/effects/phone-chrome.d.ts.map +1 -0
  52. package/lib/types/client/effects/turn-fold.d.ts +25 -0
  53. package/lib/types/client/effects/turn-fold.d.ts.map +1 -0
  54. package/lib/types/client/index.d.ts +18 -0
  55. package/lib/types/client/index.d.ts.map +1 -0
  56. package/lib/types/client/locales.d.ts +58 -0
  57. package/lib/types/client/locales.d.ts.map +1 -0
  58. package/lib/types/client/nav-store.d.ts +73 -0
  59. package/lib/types/client/nav-store.d.ts.map +1 -0
  60. package/lib/types/client/session-dot.d.ts +12 -0
  61. package/lib/types/client/session-dot.d.ts.map +1 -0
  62. package/lib/types/client/styles/base.css.d.ts +2 -0
  63. package/lib/types/client/styles/base.css.d.ts.map +1 -0
  64. package/lib/types/client/styles/chips.css.d.ts +2 -0
  65. package/lib/types/client/styles/chips.css.d.ts.map +1 -0
  66. package/lib/types/client/styles/compat.css.d.ts +2 -0
  67. package/lib/types/client/styles/compat.css.d.ts.map +1 -0
  68. package/lib/types/client/styles/composer.css.d.ts +2 -0
  69. package/lib/types/client/styles/composer.css.d.ts.map +1 -0
  70. package/lib/types/client/styles/header.css.d.ts +2 -0
  71. package/lib/types/client/styles/header.css.d.ts.map +1 -0
  72. package/lib/types/client/styles/home.css.d.ts +2 -0
  73. package/lib/types/client/styles/home.css.d.ts.map +1 -0
  74. package/lib/types/client/styles/index.d.ts +15 -0
  75. package/lib/types/client/styles/index.d.ts.map +1 -0
  76. package/lib/types/client/styles/info.css.d.ts +2 -0
  77. package/lib/types/client/styles/info.css.d.ts.map +1 -0
  78. package/lib/types/client/styles/layout.css.d.ts +2 -0
  79. package/lib/types/client/styles/layout.css.d.ts.map +1 -0
  80. package/lib/types/client/styles/misc.css.d.ts +2 -0
  81. package/lib/types/client/styles/misc.css.d.ts.map +1 -0
  82. package/lib/types/client/styles/turn-fold.css.d.ts +2 -0
  83. package/lib/types/client/styles/turn-fold.css.d.ts.map +1 -0
  84. package/lib/types/index.d.ts +83 -0
  85. package/lib/types/index.d.ts.map +1 -0
  86. package/llms.txt +20 -0
  87. package/package.json +128 -0
  88. package/pwa/app.css +95 -0
  89. package/pwa/icons/icon-192.png +0 -0
  90. package/pwa/icons/icon-512.png +0 -0
  91. package/pwa/icons/icon-maskable-512.png +0 -0
  92. package/pwa/icons/icon-maskable.svg +1 -0
  93. package/pwa/icons/icon.svg +1 -0
  94. package/pwa/inject.js +190 -0
  95. package/pwa/manifest.json +29 -0
  96. package/pwa/offline.html +38 -0
  97. package/pwa/sw.js +176 -0
  98. package/pwa/touch-gestures.js +94 -0
  99. package/scripts/build-client.mjs +101 -0
  100. package/scripts/cdp-probe.mjs +64 -0
  101. package/scripts/check-attach-upload.mjs +99 -0
  102. package/scripts/check-sunk-viewport.mjs +33 -0
  103. package/scripts/check-upload-endpoint.mjs +168 -0
  104. package/src/client/MobileAttachButton.tsx +125 -0
  105. package/src/client/MobileAttachChips.tsx +85 -0
  106. package/src/client/MobileDrawerFooter.tsx +56 -0
  107. package/src/client/MobileHome.tsx +348 -0
  108. package/src/client/MobileHomeChips.tsx +426 -0
  109. package/src/client/MobileNavOverlay.tsx +279 -0
  110. package/src/client/MobileNavToggle.tsx +52 -0
  111. package/src/client/MobileSessionHeader.tsx +242 -0
  112. package/src/client/MobileSessionInfo.tsx +303 -0
  113. package/src/client/attach-upload.ts +140 -0
  114. package/src/client/chips-store.ts +41 -0
  115. package/src/client/debug.ts +253 -0
  116. package/src/client/effects/aionui-compat.ts +183 -0
  117. package/src/client/effects/gestures.ts +265 -0
  118. package/src/client/effects/header-status.ts +30 -0
  119. package/src/client/effects/phone-chrome.ts +265 -0
  120. package/src/client/effects/turn-fold.ts +258 -0
  121. package/src/client/index.tsx +227 -0
  122. package/src/client/locales.ts +109 -0
  123. package/src/client/nav-store.ts +78 -0
  124. package/src/client/session-dot.ts +17 -0
  125. package/src/client/styles/base.css.ts +167 -0
  126. package/src/client/styles/chips.css.ts +224 -0
  127. package/src/client/styles/compat.css.ts +681 -0
  128. package/src/client/styles/composer.css.ts +504 -0
  129. package/src/client/styles/header.css.ts +368 -0
  130. package/src/client/styles/home.css.ts +477 -0
  131. package/src/client/styles/index.ts +25 -0
  132. package/src/client/styles/info.css.ts +238 -0
  133. package/src/client/styles/layout.css.ts +501 -0
  134. package/src/client/styles/misc.css.ts +128 -0
  135. package/src/client/styles/turn-fold.css.ts +106 -0
  136. package/src/index.ts +343 -0
@@ -0,0 +1,25 @@
1
+ import type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
2
+ import { NS } from './locales.ts';
3
+ /** Full props for the composer attachment seat. */
4
+ export type MobileAttachButtonProps = PropsRuntime<'conversation.input.left'> & PropsLocale<typeof NS>;
5
+ /**
6
+ * Composer attachment button (S7).
7
+ *
8
+ * Renders into `conversation.input.left`, which CSS orders to the leftmost
9
+ * seat of the phone composer's bottom row (and hides at >= 768px, where the
10
+ * official picker on the host machine is the right answer). Tapping it opens
11
+ * the CLIENT's picker — no `accept` attribute on purpose, so iOS offers the
12
+ * full 相册 / 拍照 / 选取文件 sheet rather than one of them.
13
+ *
14
+ * Every picked file takes the SAME path: upload to the node half, then append
15
+ * `@.dsh-uploads/name` to the draft through `inputActions.setDraft` (the
16
+ * official write path — no DOM value poking). S7.1 removed the split that used
17
+ * to send inlineable images straight into the session with `session.prompt`:
18
+ * one behaviour for every attachment, and the user always presses send.
19
+ * MobileAttachChips renders the preview row off those same draft tokens.
20
+ *
21
+ * Files upload one at a time: a phone uplink gains nothing from parallelism
22
+ * and a serial loop keeps the mentions in pick order.
23
+ */
24
+ export declare function MobileAttachButton({ t, sessionId, useInput, inputActions }: MobileAttachButtonProps): import("react").JSX.Element;
25
+ //# sourceMappingURL=MobileAttachButton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MobileAttachButton.d.ts","sourceRoot":"","sources":["../../../src/client/MobileAttachButton.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AAGjF,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAA;AAGjC,mDAAmD;AACnD,MAAM,MAAM,uBAAuB,GAC/B,YAAY,CAAC,yBAAyB,CAAC,GACvC,WAAW,CAAC,OAAO,EAAE,CAAC,CAAA;AAsB1B;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE,EAAE,uBAAuB,+BAwEnG"}
@@ -0,0 +1,32 @@
1
+ import type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
2
+ import { NS } from './locales.ts';
3
+ /** Full props for the attachment preview row. */
4
+ export type MobileAttachChipsProps = PropsRuntime<'conversation.input.dock'> & PropsLocale<typeof NS>;
5
+ /**
6
+ * Attachment preview row (S7.1), in `conversation.input.dock` — the official
7
+ * full-width row above the composer card, which composer.css.ts already lays
8
+ * out as one horizontally scrollable chip line shared with whatever else docks
9
+ * there (the git branch chip, a todo strip). No DOM injection into the
10
+ * official card.
11
+ *
12
+ * **This component owns no state.** It renders whatever
13
+ * `@.dsh-uploads/...` tokens the draft currently holds, so:
14
+ *
15
+ * - uploading appends a token -> a chip appears;
16
+ * - the × removes the token -> the chip disappears;
17
+ * - the user hand-deleting the text -> the chip disappears;
18
+ * - the official send clearing the draft -> every chip disappears.
19
+ *
20
+ * There is no list to keep in sync and nothing to reconcile on session switch.
21
+ * The only side state is the preview-URL map in attach-upload.ts, and the
22
+ * effect below is what keeps it honest: anything no longer mentioned gets its
23
+ * object URL revoked.
24
+ *
25
+ * An image chip is a 48px tile; anything else (and any image whose preview did
26
+ * not survive, see below) is a name pill. The `<img>` is stacked ON TOP of the
27
+ * paperclip rather than swapped for it, so a format the engine cannot decode —
28
+ * HEIC everywhere except WebKit — just fails to paint and reveals the icon,
29
+ * with no error state to track.
30
+ */
31
+ export declare function MobileAttachChips({ t, useInput, inputActions }: MobileAttachChipsProps): import("react").JSX.Element | null;
32
+ //# sourceMappingURL=MobileAttachChips.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MobileAttachChips.d.ts","sourceRoot":"","sources":["../../../src/client/MobileAttachChips.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AAEjF,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAA;AAUjC,iDAAiD;AACjD,MAAM,MAAM,sBAAsB,GAC9B,YAAY,CAAC,yBAAyB,CAAC,GACvC,WAAW,CAAC,OAAO,EAAE,CAAC,CAAA;AAE1B;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,EAAE,sBAAsB,sCAwCtF"}
@@ -0,0 +1,21 @@
1
+ import type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
2
+ import { NS } from './locales.ts';
3
+ /** Full props for the sidebar footer action entry. */
4
+ export interface MobileDrawerFooterProps extends PropsRuntime<'sidebar.footer.action'>, PropsLocale<typeof NS> {
5
+ /** Bound ctx.sessionLogDownload.download() for the current session. */
6
+ downloadSessionLog: (sessionId: string) => void;
7
+ /** Bound ctx.layout.toggleSidebar(): the Files sheet closes the drawer. */
8
+ toggleSidebar: () => void;
9
+ }
10
+ /**
11
+ * Mobile-only drawer footer actions, relocated from the session header to the
12
+ * drawer footer (beside Settings):
13
+ * - Files: opens the dsh-web-ui aionui explorer as a floating bottom sheet
14
+ * (the explorer column is hidden on mobile until this marker is set, so
15
+ * the suite's own persisted-expanded state can never cover the UI on load).
16
+ * - Session log: the official session-log-export controller, so the
17
+ * progress/result dialog is shared with the desktop flow.
18
+ * Hidden entirely on wide screens (CSS media query).
19
+ */
20
+ export declare function MobileDrawerFooter({ useSessions, downloadSessionLog, toggleSidebar, t }: MobileDrawerFooterProps): import("react").JSX.Element;
21
+ //# sourceMappingURL=MobileDrawerFooter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MobileDrawerFooter.d.ts","sourceRoot":"","sources":["../../../src/client/MobileDrawerFooter.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AAEjF,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAA;AAEjC,sDAAsD;AACtD,MAAM,WAAW,uBAAwB,SAAQ,YAAY,CAAC,uBAAuB,CAAC,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC;IAC5G,uEAAuE;IACvE,kBAAkB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/C,2EAA2E;IAC3E,aAAa,EAAE,MAAM,IAAI,CAAA;CAC1B;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,WAAW,EAAE,kBAAkB,EAAE,aAAa,EAAE,CAAC,EAAE,EAAE,uBAAuB,+BAiChH"}
@@ -0,0 +1,24 @@
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';
3
+ import { NS } from './locales.ts';
4
+ import type { createNavStore } from './nav-store.ts';
5
+ /** Full props for the phone home screen (shell.overlay entry). */
6
+ export type MobileHomeProps = PropsRuntime<'shell.overlay'> & PropsStore<ReturnType<typeof createNavStore>> & PropsLocale<typeof NS> & {
7
+ /** Bound ctx.sessions.open(id). */
8
+ openSession: (id: SessionId) => void;
9
+ /** Bound ctx.workspaces.startSession(workspaceId?). */
10
+ startSession: (workspaceId?: WorkspaceId) => void;
11
+ /** Bound ctx.sessionLogDownload.download() — the session-log chip (S5). */
12
+ downloadSessionLog: (id: SessionId) => void;
13
+ };
14
+ /**
15
+ * Phone home screen: the full-screen session list that owns the first level
16
+ * of the page stack. Renders nothing at or above 768px — the tablet drawer
17
+ * and the desktop layout stay exactly as they were.
18
+ *
19
+ * All data comes from the standard kit (`useSessions` / `useWorkspaces`) and
20
+ * all navigation from the injected official actions; nothing here reads the
21
+ * official DOM.
22
+ */
23
+ export declare function MobileHome({ useSessions, useWorkspaces, useStore, actions, openSession, startSession, downloadSessionLog, t, }: MobileHomeProps): import("react").JSX.Element | null;
24
+ //# sourceMappingURL=MobileHome.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MobileHome.d.ts","sourceRoot":"","sources":["../../../src/client/MobileHome.tsx"],"names":[],"mappings":"AACA,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;AAEjC,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;CAC5C,CAAA;AAuEH;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,EACzB,WAAW,EACX,aAAa,EACb,QAAQ,EACR,OAAO,EACP,WAAW,EACX,YAAY,EACZ,kBAAkB,EAClB,CAAC,GACF,EAAE,eAAe,sCAmOjB"}
@@ -0,0 +1,76 @@
1
+ import type { Translate } from '@deepseek-ai/dsh-client-ui-slots';
2
+ import type { MobileNavKey } from './locales.ts';
3
+ /** One icon component's minimal shared shape (every `@deepseek-ai/dsh-client-ui-primitives` icon accepts `size`, regardless of the fixed number in its own name — see e.g. IconDownloadOutline16 used at size 14 elsewhere in this codebase). */
4
+ type IconFC = (props: {
5
+ size?: number;
6
+ }) => React.JSX.Element;
7
+ /**
8
+ * One home-screen chip's static registration (S5). `selector` is the
9
+ * stable, non-hashed DOM anchor for the plugin's REAL entry button — the
10
+ * chip never reimplements the target feature, it just "代点" (synthetic
11
+ * `.click()`, bypasses hit-testing per the S2.1 precedent in AGENTS.md) the
12
+ * button the plugin itself already renders elsewhere in the tree, exactly
13
+ * like MobileSessionHeader's Chat/Trajectory tab click and the workbench
14
+ * button's `[data-dsh-better-sidebar] button[class$="_toggleButton"]`.
15
+ * `selector: null` marks the one chip (session log) whose availability and
16
+ * action come from injected props instead of a DOM probe — it is a
17
+ * first-party dsh-session-log-export service call, not a third-party
18
+ * plugin's button.
19
+ */
20
+ export interface ChipDef {
21
+ id: string;
22
+ label: MobileNavKey;
23
+ Icon: IconFC;
24
+ selector: string | null;
25
+ }
26
+ /** Static chip registry (S5). Order here is the default row order. */
27
+ export declare const CHIP_DEFS: readonly ChipDef[];
28
+ /** Full props for the chip row. */
29
+ export interface MobileHomeChipsProps {
30
+ t: Translate<MobileNavKey>;
31
+ sessionId: string | undefined;
32
+ downloadSessionLog: (id: string) => void;
33
+ onCustomize: () => void;
34
+ }
35
+ /**
36
+ * Plugin-entry chips row (S5): a horizontally-scrolling line of 34px pills
37
+ * between the workspace title and the session list, plus a trailing "···"
38
+ * that opens the customize sheet (MobileHomeChipsSheetBody below, rendered
39
+ * by MobileHome inside its existing home-sheet chrome). Every chip renders
40
+ * only when both true: the user has not hidden it (useChipsPrefs) AND its
41
+ * target actually exists right now (useDetectedIds / sessionId) — an
42
+ * uninstalled plugin's chip never appears, matching the plan's "按用户实装
43
+ * 插件逐个接入口". Chips beyond {@link CHIP_DEFS} (S5.1: any OTHER plugin's
44
+ * own sidebar-footer-action entry) are auto-discovered by
45
+ * {@link useHarvestedChips} and appended after the hand-registered ones —
46
+ * "装了新插件、chips 行零代码长出对应入口".
47
+ */
48
+ export declare function MobileHomeChips({ t, sessionId, downloadSessionLog, onCustomize }: MobileHomeChipsProps): import("react").JSX.Element;
49
+ /**
50
+ * Customize-sheet body (S5, existence filter added 2026-08-17 real-device
51
+ * follow-up): one toggle row per chip whose target actually exists —
52
+ * `useDetectedIds()`, the SAME live probe `MobileHomeChips` uses for the row
53
+ * itself. Originally listed every `CHIP_DEFS` entry unconditionally, on the
54
+ * theory that a not-yet-installed plugin's toggle should still be
55
+ * pre-settable; real-device feedback was that this instead surfaces dead
56
+ * switches for plugins the user never installed (taskboard/ssh). Detection
57
+ * is a live MutationObserver subscription, so installing the plugin later
58
+ * still makes its toggle appear with no reload needed — "将来装了自动出现"
59
+ * survives the change, it just also stops showing before that. `sessionLog`
60
+ * (selector: null) is exempt: its existence is a runtime session-scope
61
+ * question, not a plugin-install question, so it always lists regardless of
62
+ * whether a session happens to be open right now. Stale prefs entries for a
63
+ * chip that no longer renders (e.g. an uninstalled plugin's old toggle
64
+ * value) are simply never read — `isChipEnabled`/`toggleChip`
65
+ * (chips-store.ts) key off `CHIP_DEFS` ids already, so leftover keys in the
66
+ * persisted object are inert, not an error. Rendered by MobileHome inside
67
+ * the SAME home-sheet-layer/mask/sheet chrome the workspace switcher uses
68
+ * (S6's drag-to-close and mask-click-close already bind generically to
69
+ * `[data-mobile-nav="home-sheet"]`, so this second use needs no new gesture
70
+ * wiring — see styles/chips.css.ts).
71
+ */
72
+ export declare function MobileHomeChipsSheetBody({ t }: {
73
+ t: Translate<MobileNavKey>;
74
+ }): import("react").JSX.Element;
75
+ export {};
76
+ //# sourceMappingURL=MobileHomeChips.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MobileHomeChips.d.ts","sourceRoot":"","sources":["../../../src/client/MobileHomeChips.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAA;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAGhD,iPAAiP;AACjP,KAAK,MAAM,GAAG,CAAC,KAAK,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,KAAK,KAAK,CAAC,GAAG,CAAC,OAAO,CAAA;AAE7D;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,YAAY,CAAA;IACnB,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CACxB;AA0CD,sEAAsE;AACtE,eAAO,MAAM,SAAS,EAAE,SAAS,OAAO,EAMvC,CAAA;AAoND,mCAAmC;AACnC,MAAM,WAAW,oBAAoB;IACnC,CAAC,EAAE,SAAS,CAAC,YAAY,CAAC,CAAA;IAC1B,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;IAC7B,kBAAkB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACxC,WAAW,EAAE,MAAM,IAAI,CAAA;CACxB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,EAAE,CAAC,EAAE,SAAS,EAAE,kBAAkB,EAAE,WAAW,EAAE,EAAE,oBAAoB,+BAuCtG;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,wBAAwB,CAAC,EAAE,CAAC,EAAE,EAAE;IAAE,CAAC,EAAE,SAAS,CAAC,YAAY,CAAC,CAAA;CAAE,+BA4C7E"}
@@ -0,0 +1,15 @@
1
+ import type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
2
+ import { NS } from './locales.ts';
3
+ /** Full props for the shell overlay entry. */
4
+ export interface MobileNavOverlayProps extends PropsRuntime<'shell.overlay'>, PropsLocale<typeof NS> {
5
+ /** Bound ctx.layout.toggleSidebar(). */
6
+ toggleSidebar: () => void;
7
+ }
8
+ /**
9
+ * Mobile shell overlay: owns the `data-mobile-nav` marker on the AppFrame
10
+ * element (the CSS restructure keys off it), mirrors the frame's collapsed
11
+ * state into React state, and renders the dimmed backdrop plus a floating
12
+ * directory button for the hero/blank phases that have no session header.
13
+ */
14
+ export declare function MobileNavOverlay({ toggleSidebar, t }: MobileNavOverlayProps): import("react").JSX.Element | null;
15
+ //# sourceMappingURL=MobileNavOverlay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MobileNavOverlay.d.ts","sourceRoot":"","sources":["../../../src/client/MobileNavOverlay.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AAEjF,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAA;AAEjC,8CAA8C;AAC9C,MAAM,WAAW,qBAAsB,SAAQ,YAAY,CAAC,eAAe,CAAC,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC;IAClG,wCAAwC;IACxC,aAAa,EAAE,MAAM,IAAI,CAAA;CAC1B;AAmCD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,EAAE,qBAAqB,sCAoO3E"}
@@ -0,0 +1,18 @@
1
+ import type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
2
+ import { NS } from './locales.ts';
3
+ /** Full props for the session-header directory toggle. */
4
+ export interface MobileNavToggleProps extends PropsRuntime<'conversation.session.header.actions'>, PropsLocale<typeof NS> {
5
+ /** Bound ctx.layout.toggleSidebar(). */
6
+ toggleSidebar: () => void;
7
+ }
8
+ /**
9
+ * Mobile-only icon buttons next to the session title:
10
+ * - toggle: opens the directory drawer on narrow screens.
11
+ * - files: toggles the dsh-web-ui explorer sheet directly — one tap opens,
12
+ * a second tap closes it, no drawer round-trip. (The drawer footer keeps
13
+ * a Files entry for the hero/blank phases where this header does not
14
+ * exist.)
15
+ * Hidden entirely on wide screens (CSS media query).
16
+ */
17
+ export declare function MobileNavToggle({ toggleSidebar, t }: MobileNavToggleProps): import("react").JSX.Element;
18
+ //# sourceMappingURL=MobileNavToggle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MobileNavToggle.d.ts","sourceRoot":"","sources":["../../../src/client/MobileNavToggle.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AAEjF,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAA;AAEjC,0DAA0D;AAC1D,MAAM,WAAW,oBAAqB,SAAQ,YAAY,CAAC,qCAAqC,CAAC,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC;IACvH,wCAAwC;IACxC,aAAa,EAAE,MAAM,IAAI,CAAA;CAC1B;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,EAAE,oBAAoB,+BAgCzE"}
@@ -0,0 +1,58 @@
1
+ import type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
2
+ import { NS } from './locales.ts';
3
+ /** Full props for the session header's back button + view-switch row. */
4
+ export type MobileHeaderActionsProps = PropsRuntime<'conversation.session.header.actions'> & PropsLocale<typeof NS>;
5
+ /** One tab read off the official (now visually hidden) Chat/Trajectory tablist. */
6
+ export interface ViewTabInfo {
7
+ label: string;
8
+ active: boolean;
9
+ el: HTMLButtonElement;
10
+ }
11
+ /**
12
+ * Reads the official session-header tablist by role/aria only (no hashed
13
+ * classes) — the plan's one sanctioned official-DOM read: ChatStore's view
14
+ * selection has no public setter (design doc Appendix C), so switching
15
+ * views means clicking the official tab button ourselves.
16
+ *
17
+ * Exported: effects/gestures.ts (S6) reuses this exact read for the
18
+ * content-area swipe gesture instead of re-querying the tablist a second
19
+ * way — it runs outside React (a document-level touch listener), so it
20
+ * needs the plain function, not the {@link useViewTabs} hook below.
21
+ */
22
+ export declare function readViewTabs(): ViewTabInfo[];
23
+ /**
24
+ * Live view-tab mirror. The tablist mounts/unmounts with the session header
25
+ * and its `aria-selected` flips on every view switch (ours or the suite's
26
+ * own), so a MutationObserver — not a one-time read — keeps the mirror
27
+ * current. Scoped to `document.body` like the existing aionui-compat
28
+ * effects (styles/aionui-compat.ts): the tablist itself may not exist yet
29
+ * at mount time.
30
+ *
31
+ * Exported: MobileSessionInfo.tsx (S4) reuses this exact hook for the info
32
+ * sheet's Chat/Trajectory segmented control instead of re-reading the
33
+ * tablist a second way.
34
+ */
35
+ export declare function useViewTabs(): ViewTabInfo[];
36
+ /**
37
+ * Session header, left lane: the back button (returns the phone page stack
38
+ * to the session list) plus the "current view + dots" row that mirrors the
39
+ * hidden official tablist. Both render unconditionally; CSS
40
+ * (styles/header.css.ts) keeps them hidden at >= 768px so the tablet drawer
41
+ * and the desktop layout stay exactly as they were.
42
+ */
43
+ export declare function MobileHeaderActions({ t }: MobileHeaderActionsProps): import("react").JSX.Element;
44
+ /** Full props for the session header's right-edge utility buttons. */
45
+ export type MobileHeaderUtilitiesProps = PropsRuntime<'conversation.session.header.utilities'> & PropsLocale<typeof NS>;
46
+ /**
47
+ * Session header, right lane: the session-info entry (S4 owns the actual
48
+ * sheet — this fires a hook event for it to pick up) and the workbench
49
+ * entry, which triggers dsh-better-sidebar's own toggle. There is no public
50
+ * API for "open the panel" (BetterSidebarService.openTab only auto-expands
51
+ * for a content open, not a bare type-only open), so this clicks the
52
+ * plugin's real toggle button through a stable, non-hashed anchor: its root
53
+ * mount marker `[data-dsh-better-sidebar]` plus the `_toggleButton` class
54
+ * suffix (verified live: 2026-08-17). Safe no-op when the plugin, or any
55
+ * other workbench-style plugin sharing that convention, is not installed.
56
+ */
57
+ export declare function MobileHeaderUtilities({ t }: MobileHeaderUtilitiesProps): import("react").JSX.Element;
58
+ //# sourceMappingURL=MobileSessionHeader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MobileSessionHeader.d.ts","sourceRoot":"","sources":["../../../src/client/MobileSessionHeader.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AAEjF,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAA;AAsBjC,yEAAyE;AACzE,MAAM,MAAM,wBAAwB,GAChC,YAAY,CAAC,qCAAqC,CAAC,GACnD,WAAW,CAAC,OAAO,EAAE,CAAC,CAAA;AAE1B,mFAAmF;AACnF,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,OAAO,CAAA;IACf,EAAE,EAAE,iBAAiB,CAAA;CACtB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,IAAI,WAAW,EAAE,CAQ5C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,IAAI,WAAW,EAAE,CAe3C;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,CAAC,EAAE,EAAE,wBAAwB,+BA+BlE;AAED,sEAAsE;AACtE,MAAM,MAAM,0BAA0B,GAClC,YAAY,CAAC,uCAAuC,CAAC,GACrD,WAAW,CAAC,OAAO,EAAE,CAAC,CAAA;AAE1B;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,EAAE,CAAC,EAAE,EAAE,0BAA0B,+BAkGtE"}
@@ -0,0 +1,41 @@
1
+ import type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
2
+ import type { SessionFace, SessionId } from '@deepseek-ai/dsh-client-runtime/client';
3
+ import { NS } from './locales.ts';
4
+ /** Full props for the session-info sheet (header.utilities, second entry). */
5
+ export type MobileSessionInfoProps = PropsRuntime<'conversation.session.header.utilities'> & PropsLocale<typeof NS> & {
6
+ /** Bound ctx.sessions.fork({sessionId}). */
7
+ forkSession: (sessionId: SessionId) => Promise<SessionId>;
8
+ /** Bound ctx.sessions.open(id) — lands on the freshly forked session. */
9
+ openSession: (id: SessionId) => void;
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;
12
+ /** Bound ctx.workspaces.archiveSession(sessionId). */
13
+ archiveSession: (sessionId: SessionId) => Promise<void>;
14
+ /** Bound ctx.sessionLogDownload.download(sessionId) — owns its own progress/result modal. */
15
+ downloadSessionLog: (sessionId: SessionId) => Promise<void>;
16
+ };
17
+ /**
18
+ * Session-info sheet: the bottom sheet that gathers everything S3 pulled off
19
+ * the composer (the official stats strip) and everything S2 left out of the
20
+ * header (Chat/Trajectory as a real control, badges, session actions).
21
+ *
22
+ * Registered as a SECOND entry on `conversation.session.header.utilities` —
23
+ * session scope, sibling to the ⓘ button that opens it
24
+ * (MobileSessionHeader.tsx dispatches {@link SESSION_INFO_EVENT}).
25
+ *
26
+ * Mount-point choice (the plan's own tradeoff to weigh): this needs
27
+ * `useProjection`/`sessionId` for the stats grid, and those are
28
+ * session-scope-only standard props — `header.utilities` has them,
29
+ * `shell.overlay` (S1's other option) does not. `shell.overlay` would have
30
+ * gained nothing in exchange (GlobalStandardProps — `useSessions` for the
31
+ * badges/subagent-count — is unconditional on every slot per
32
+ * `PropsRuntime`, so this component gets it here for free too) while
33
+ * running into a real problem: shell.overlay content renders inside the
34
+ * `pI_x6G_overlayLayer`, a z-index:20 stacking context (AGENTS.md), and the
35
+ * composer's own permission/model bottom sheets sit at z:60 — a
36
+ * shell.overlay-hosted info sheet would render BEHIND an open composer
37
+ * menu. Mounting inside the header's own DOM (outside that capped layer)
38
+ * lets this sheet's z-index clear every other phone-shell float.
39
+ */
40
+ export declare function MobileSessionInfo({ sessionId, useSessions, useProjection, forkSession, openSession, renameSession, archiveSession, downloadSessionLog, t, }: MobileSessionInfoProps): import("react").JSX.Element | null;
41
+ //# sourceMappingURL=MobileSessionInfo.d.ts.map
@@ -0,0 +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;AAajC,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;AAsCH;;;;;;;;;;;;;;;;;;;;;;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,sCAgMxB"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * S7 attachment plumbing: the string math plus the thumbnail registry.
3
+ *
4
+ * Kept free of React so `scripts/check-attach-upload.mjs` can import it
5
+ * directly under Node's type stripping.
6
+ *
7
+ * The one idea worth stating up front: **the composer draft is the only state
8
+ * this feature has.** Every attachment is an `@.dsh-uploads/name` token in the
9
+ * draft text, and the chip row is a pure function of that text. Nothing to
10
+ * keep in sync — the user deleting the token by hand, or the official send
11
+ * clearing the draft, makes the chips disappear on their own.
12
+ */
13
+ /** Exact host route registered by the node half (src/index.ts). */
14
+ export declare const UPLOAD_ROUTE = "/_dsh/mobile-nav/upload";
15
+ /** Workspace-relative directory uploads land in; also the `@` mention prefix. */
16
+ export declare const UPLOAD_DIR = ".dsh-uploads";
17
+ /**
18
+ * The upload URL for one file. Root-relative on purpose: through the
19
+ * gateway half the pairing cookie only rides along same-origin.
20
+ * @param sessionId - target session (its workspace receives the file).
21
+ * @param name - the browser filename; the host sanitizes it again.
22
+ * @returns a root-relative URL.
23
+ */
24
+ export declare function uploadUrl(sessionId: string, name: string): string;
25
+ /**
26
+ * Every attachment mentioned in a draft, in reading order, without repeats.
27
+ * @param draft - the composer draft text.
28
+ * @returns workspace-relative paths (no leading `@`).
29
+ */
30
+ export declare function mentionsIn(draft: string): string[];
31
+ /**
32
+ * Append one `@path` mention to the draft.
33
+ *
34
+ * Separated from whatever came before by a space (or a newline when the draft
35
+ * already ends in one), and trailed by a space so the next mention does not
36
+ * fuse onto this one — and so {@link draftWithoutMention} can lift it back out
37
+ * without leaving a double space behind.
38
+ * @param draft - the current draft text.
39
+ * @param relPath - workspace-relative path returned by the upload route.
40
+ * @returns the next draft.
41
+ */
42
+ export declare function draftWithMention(draft: string, relPath: string): string;
43
+ /**
44
+ * Remove one `@path` mention from the draft — what a chip's × does.
45
+ *
46
+ * The file itself stays on disk: it is a few KB in a directory the user can
47
+ * clear whenever, and deleting it would need a second host route whose only
48
+ * job is destruction.
49
+ * @param draft - the current draft text.
50
+ * @param relPath - the attachment to drop.
51
+ * @returns the next draft; whitespace-only collapses to empty.
52
+ */
53
+ export declare function draftWithoutMention(draft: string, relPath: string): string;
54
+ /** The filename part of a workspace-relative path. */
55
+ export declare function leafOf(relPath: string): string;
56
+ /**
57
+ * Shorten a filename from the MIDDLE, so both the stem and the extension stay
58
+ * readable (CSS `text-overflow` can only cut one end).
59
+ * @param text - the filename.
60
+ * @param max - budget in characters, including the ellipsis.
61
+ * @returns the original when it fits, else head + `…` + tail.
62
+ */
63
+ export declare function middleEllipsis(text: string, max?: number): string;
64
+ /**
65
+ * Register a preview for an uploaded image.
66
+ * @param relPath - workspace-relative path the file landed on.
67
+ * @param blob - the browser-owned file.
68
+ */
69
+ export declare function rememberThumbnail(relPath: string, blob: Blob): void;
70
+ /** The preview URL for one attachment, or undefined when there is none. */
71
+ export declare function thumbnailFor(relPath: string): string | undefined;
72
+ /**
73
+ * Revoke and forget every preview whose attachment is no longer in the draft.
74
+ * Called whenever the chip row re-renders, so a removed chip frees its blob.
75
+ * @param keep - the attachments still mentioned.
76
+ */
77
+ export declare function releaseThumbnailsExcept(keep: readonly string[]): void;
78
+ //# sourceMappingURL=attach-upload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attach-upload.d.ts","sourceRoot":"","sources":["../../../src/client/attach-upload.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,mEAAmE;AACnE,eAAO,MAAM,YAAY,4BAA4B,CAAA;AAErD,iFAAiF;AACjF,eAAO,MAAM,UAAU,iBAAiB,CAAA;AAWxC;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAGjE;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAElD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAGvE;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAI1E;AAED,sDAAsD;AACtD,wBAAgB,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,SAAK,GAAG,MAAM,CAI7D;AAaD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI,CAKnE;AAED,2EAA2E;AAC3E,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEhE;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAOrE"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Home-screen chip visibility, keyed by {@link ChipDef.id} (MobileHomeChips.tsx).
3
+ * A missing key means "shown" — new chip ids need no migration step, they
4
+ * just default enabled the first time they exist.
5
+ */
6
+ export type ChipPrefs = Record<string, boolean>;
7
+ /** @param prefs - current snapshot. @param id - chip id. @returns whether the chip should render (default true). */
8
+ export declare function isChipEnabled(prefs: ChipPrefs, id: string): boolean;
9
+ /** Flip one chip's visibility and persist it. @param id - chip id. */
10
+ export declare function toggleChip(id: string): void;
11
+ /** Live chip-prefs mirror (React 18 tearing-safe external store read). */
12
+ export declare function useChipsPrefs(): ChipPrefs;
13
+ //# sourceMappingURL=chips-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chips-store.d.ts","sourceRoot":"","sources":["../../../src/client/chips-store.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAiB/C,oHAAoH;AACpH,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAEnE;AAED,sEAAsE;AACtE,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAI3C;AAED,0EAA0E;AAC1E,wBAAgB,aAAa,IAAI,SAAS,CAEzC"}
@@ -0,0 +1,9 @@
1
+ import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
2
+ /**
3
+ * Debug badge — ?mobile-nav-debug=1
4
+ * Renders a live state overlay (URL, viewport, media queries, shell chrome,
5
+ * aionui columns, genui cards, captured errors) so a phone-side repro can be
6
+ * diagnosed without guessing. No-op unless the query param is present.
7
+ */
8
+ export declare function installDebugBadge(ctx: ClientContext): void;
9
+ //# sourceMappingURL=debug.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,4 @@
1
+ import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
2
+ /** dsh-web-ui 兼容:explorer / preview 列的显隐标记与升起动画(同域同机制,合并一处)。 */
3
+ export declare function installAionuiCompat(ctx: ClientContext): void;
4
+ //# sourceMappingURL=aionui-compat.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,7 @@
1
+ import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
2
+ /** S6: the two-gesture set — left-edge swipe-back and sheet drag-to-close.
3
+ * Both install/uninstall their own document listeners on the phone
4
+ * breakpoint's matchMedia change, so at >= 768px this is a true no-op (no
5
+ * listeners attached at all), matching every other effect in this file. */
6
+ export declare function installGestures(ctx: ClientContext): void;
7
+ //# sourceMappingURL=gestures.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,15 @@
1
+ import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
2
+ /**
3
+ * Session header running-status dot (S2). No official element exists to
4
+ * reposition (ConversationSessionHeader renders only the crumb title, the
5
+ * actions/utilities slots, and the tablist — dsh-client-ui-conversation
6
+ * lib/client.js:6949-7009), so this reads `ctx.sessions.list` directly
7
+ * (the same feed `useSessions` wraps) and stamps a data attribute the
8
+ * mobile stylesheet turns into a `::after` dot on the title crumb —
9
+ * "read data, self-draw" is the plan's documented fallback for this piece.
10
+ * Kept outside React: the dot must track the CURRENT session regardless of
11
+ * which component the header happens to mount, and a plain attribute +
12
+ * CSS avoids reaching into the official crumb's own DOM subtree.
13
+ */
14
+ export declare function installHeaderStatusDot(ctx: ClientContext): void;
15
+ //# sourceMappingURL=header-status.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,106 @@
1
+ import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
2
+ /**
3
+ * Phone chrome: KEEP the system status bar (no fullscreen) and make it
4
+ * blend into the page. On narrow screens:
5
+ * - The viewport meta gains viewport-fit=cover, so env(safe-area-inset-top)
6
+ * is the real status-bar / notch height and the stylesheet can push every
7
+ * surface below it (off notched phones, or in a browser tab where the
8
+ * layout viewport already sits below the status bar, the inset is 0 and
9
+ * nothing shifts).
10
+ * - A theme-color meta tracks the shell background (the official theme is
11
+ * toggled by body[data-ds-dark-theme], which flips --dsw-alias-bg-base):
12
+ * Android then paints the status bar / URL bar with the page's own base
13
+ * color, so the status bar reads as part of the UI instead of a foreign
14
+ * strip. The drawer paints the same strip on iOS / notch displays.
15
+ * - gesturestart is suppressed as the legacy-iOS fallback for double-tap
16
+ * zoom; modern browsers are covered by the stylesheet's
17
+ * touch-action: manipulation (which keeps pan and pinch zoom).
18
+ */
19
+ export declare function installPhoneChrome(ctx: ClientContext): void;
20
+ /**
21
+ * Does the layout viewport sit shorter than the screen by at least the top
22
+ * inset env() still claims? (S1.2 predicate, wired in S1.3.)
23
+ *
24
+ * Device numbers (iPhone, iOS 26.5, standalone PWA, 393x852): innerHeight
25
+ * 793, env top 59 (= 852 - 793), env bottom 34, frame bottom 793 flush.
26
+ * The same device in a Safari TAB reads innerHeight 695 with every surface
27
+ * flush and every design value correct, which is what rules our own CSS out.
28
+ *
29
+ * What the true-branch means, settled by S1.2 + S1.3 device evidence: the
30
+ * viewport is anchored at screen y=0 and merely cut 59px short at the BOTTOM
31
+ * — not pushed down below the status bar. So the top inset is paid exactly
32
+ * once and must be left alone, while the bottom inset is a lie: the home
33
+ * indicator lives in the dead strip below the page. installSunkInset() acts
34
+ * on that, and only on --mnav-sab.
35
+ *
36
+ * The `envTop > 0` guard is what keeps every other standalone install out:
37
+ * landscape iPhone (top inset 0, the notch moves to left/right), iPad, and
38
+ * Android — where standalone also loses status-bar height off innerHeight but
39
+ * reports env top 0 — all fall through to false. Kept pure so the boundaries
40
+ * are checkable off-device: scripts/check-sunk-viewport.mjs.
41
+ */
42
+ export declare function isViewportSunkBelowStatusBar(input: {
43
+ standalone: boolean;
44
+ screenHeight: number;
45
+ innerHeight: number;
46
+ envTop: number;
47
+ }): boolean;
48
+ /**
49
+ * iOS standalone-PWA keyboard shrink (S1.2, 2026-08-17) — the ~60px white
50
+ * band under the composer AND under the session list.
51
+ *
52
+ * Documented WebKit defect: the first time the software keyboard opens inside
53
+ * a home-screen (standalone) PWA, the layout viewport permanently loses the
54
+ * status-bar height for the rest of the app session. innerHeight,
55
+ * visualViewport.height and 100dvh all report the shrunken value together, so
56
+ * nothing inside the page can see anything wrong — the page simply ends early
57
+ * and the strip below it is system background that no CSS can reach. Reported
58
+ * as 932 -> 873 on an iPhone Pro Max; the user's device reads 852 -> 793.
59
+ * Both are exactly one status bar. See
60
+ * https://dev.to/cederhook/fixing-the-ios-standalone-pwa-keyboard-bug-that-shrinks-your-viewport-for-good-63d
61
+ *
62
+ * This is why the reported symptom is asymmetric and why the earlier
63
+ * "double-counted top inset" reading was wrong: the top edge is genuinely
64
+ * correct (env top 59 is paid once, the viewport starts at screen y=0), the
65
+ * bottom is simply 59px short. It also explains a chat client being hit
66
+ * hardest — the trigger is typing, which happens on the first message.
67
+ *
68
+ * The only known cure is to make WebKit re-measure: drop a full-viewport
69
+ * element out of the box tree and force a synchronous reflow. Two departures
70
+ * from the published recipe:
71
+ * - scrollTop is saved and restored around the toggle. Un-boxing an ancestor
72
+ * resets every descendant scroller to 0, which in a chat client means the
73
+ * conversation jumps to its first message. Both happen inside one task, so
74
+ * no frame is ever painted in between and nothing flickers.
75
+ * - the baseline is the tallest innerHeight this session has actually seen,
76
+ * not the screen height. On any device where the viewport is legitimately
77
+ * short, the baseline equals the current height and this never fires.
78
+ *
79
+ * Standalone-gated, so a browser tab (and every desktop, CDP included) is a
80
+ * strict no-op — which is also why the fix cannot be regression-tested here
81
+ * and has to be confirmed on the device.
82
+ */
83
+ export declare function installViewportHeal(ctx: ClientContext): void;
84
+ /**
85
+ * Sunk-viewport compensation (S1.3, 2026-08-17) — zeroes --mnav-sab ONLY.
86
+ *
87
+ * When isViewportSunkBelowStatusBar() holds, the layout viewport is 59px
88
+ * shorter than the screen while env() still reports the full pair of insets.
89
+ * The bottom one is then a lie with a cost: the home indicator sits in the
90
+ * dead strip BELOW the page, so the 34px we reserve for it is 34px of blank
91
+ * page stacked on top of an already-blank system band. Zeroing it does not
92
+ * fix the band (nothing in the page can) but stops us widening it.
93
+ *
94
+ * --mnav-sat is deliberately left alone: the top edge is measured correct on
95
+ * the device (header sits right under the notch), and the S1.2 round already
96
+ * burned a cycle on the theory that it was double-counted.
97
+ *
98
+ * Reversible by design. The predicate is re-evaluated on every resize, so a
99
+ * viewport that comes back to full height — the heal above winning, or Apple
100
+ * shipping the fix — drops the override and the normal env() compensation
101
+ * returns without a reload. `data-mnav-sunk` on <html> is what the debug
102
+ * badge reads, so the badge reports the state that is actually in force
103
+ * rather than re-deriving it.
104
+ */
105
+ export declare function installSunkInset(ctx: ClientContext): void;
106
+ //# sourceMappingURL=phone-chrome.d.ts.map