dsh-zen-remote 1.1.13 → 1.1.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/README.zh-CN.md +3 -2
- package/docs/interface.md +46 -3
- package/lib/client.js +3421 -103
- package/lib/index.js +13 -0
- package/lib/index.js.map +1 -1
- package/lib/share-export.js +347 -0
- package/lib/share-export.js.map +1 -0
- package/lib/types/client/MobileAttachButton.d.ts +8 -1
- package/lib/types/client/MobileAttachButton.d.ts.map +1 -1
- package/lib/types/client/MobileAttachChips.d.ts.map +1 -1
- package/lib/types/client/MobileSessionHeader.d.ts +7 -8
- package/lib/types/client/MobileSessionHeader.d.ts.map +1 -1
- package/lib/types/client/MobileSessionInfo.d.ts.map +1 -1
- package/lib/types/client/effects/keyboard-avoid.d.ts.map +1 -1
- package/lib/types/client/effects/keyboard-guard.d.ts +16 -11
- package/lib/types/client/effects/keyboard-guard.d.ts.map +1 -1
- package/lib/types/client/host-attach.d.ts +38 -0
- package/lib/types/client/host-attach.d.ts.map +1 -0
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/locales.d.ts +23 -0
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/client/share/fetch-share.d.ts +77 -0
- package/lib/types/client/share/fetch-share.d.ts.map +1 -0
- package/lib/types/client/share/markdown.d.ts +97 -0
- package/lib/types/client/share/markdown.d.ts.map +1 -0
- package/lib/types/client/share/png-stitch.d.ts +96 -0
- package/lib/types/client/share/png-stitch.d.ts.map +1 -0
- package/lib/types/client/share/rasterize.d.ts +317 -0
- package/lib/types/client/share/rasterize.d.ts.map +1 -0
- package/lib/types/client/share/share-card.d.ts +93 -0
- package/lib/types/client/share/share-card.d.ts.map +1 -0
- package/lib/types/client/share/share-constants.d.ts +27 -0
- package/lib/types/client/share/share-constants.d.ts.map +1 -0
- package/lib/types/client/share/share-flow.d.ts +76 -0
- package/lib/types/client/share/share-flow.d.ts.map +1 -0
- package/lib/types/client/share/share-preview.d.ts +11 -0
- package/lib/types/client/share/share-preview.d.ts.map +1 -0
- package/lib/types/client/share/share-sheet.d.ts +17 -0
- package/lib/types/client/share/share-sheet.d.ts.map +1 -0
- package/lib/types/client/share/text-layout.d.ts +48 -0
- package/lib/types/client/share/text-layout.d.ts.map +1 -0
- package/lib/types/client/styles/header.css.d.ts +1 -1
- package/lib/types/client/styles/header.css.d.ts.map +1 -1
- package/lib/types/client/styles/layout.css.d.ts +1 -1
- package/lib/types/client/styles/layout.css.d.ts.map +1 -1
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/share-export.d.ts +66 -0
- package/lib/types/share-export.d.ts.map +1 -0
- package/package.json +7 -2
- package/scripts/check-host-shadow.mjs +41 -9
- package/scripts/check-keyboard-avoid.mjs +4 -2
- package/scripts/check-share-image.mjs +970 -0
- package/scripts/check-upload-endpoint.mjs +10 -3
- package/src/client/MobileAttachButton.tsx +13 -0
- package/src/client/MobileAttachChips.tsx +8 -1
- package/src/client/MobileSessionHeader.tsx +90 -30
- package/src/client/MobileSessionInfo.tsx +234 -1
- package/src/client/effects/keyboard-avoid.ts +14 -7
- package/src/client/effects/keyboard-guard.ts +28 -18
- package/src/client/host-attach.ts +54 -0
- package/src/client/index.tsx +16 -0
- package/src/client/locales.ts +46 -0
- package/src/client/share/fetch-share.ts +161 -0
- package/src/client/share/markdown.ts +609 -0
- package/src/client/share/png-stitch.ts +281 -0
- package/src/client/share/rasterize.ts +1078 -0
- package/src/client/share/share-card.tsx +637 -0
- package/src/client/share/share-constants.ts +30 -0
- package/src/client/share/share-flow.ts +166 -0
- package/src/client/share/share-preview.tsx +337 -0
- package/src/client/share/share-sheet.tsx +222 -0
- package/src/client/share/text-layout.ts +147 -0
- package/src/client/styles/header.css.ts +30 -0
- package/src/client/styles/layout.css.ts +5 -2
- package/src/index.ts +13 -0
- package/src/share-export.ts +431 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Share-image transcript route (issue #7): fold one session's raw event log
|
|
3
|
+
* into the flat user/assistant transcript the phone rasterizes into shareable
|
|
4
|
+
* PNG cards.
|
|
5
|
+
*
|
|
6
|
+
* Why a host route at all: the Chat view is a paged window over a surface the
|
|
7
|
+
* compactor rewrites, so the browser DOM never holds the whole conversation
|
|
8
|
+
* and cloning it cannot work. The whole-log source of truth is the host-side
|
|
9
|
+
* `sessionQuery` service (standard dsh-base composition), which no browser
|
|
10
|
+
* half can reach.
|
|
11
|
+
*
|
|
12
|
+
* Why the RAW log (`readSession`) and not the observed surface: the surface
|
|
13
|
+
* deliberately shadows replaced ranges, so once a replacement lands it shows
|
|
14
|
+
* LESS than the user already saw — wrong source for a human transcript (the
|
|
15
|
+
* official trap note on `isAppendSurfaceEvent`: append-origin events are the
|
|
16
|
+
* transcript's durable source material). The raw log additionally carries the
|
|
17
|
+
* `agent/inbox/spliced` bookkeeping the steering classification below folds —
|
|
18
|
+
* it never exists on the surface. The fold keeps every append-origin message
|
|
19
|
+
* in log order and never applies the shadows, so a steered or compacted
|
|
20
|
+
* session still exports everything the user saw.
|
|
21
|
+
*/
|
|
22
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
23
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
24
|
+
/** Exact route the browser GETs a session's share transcript from. */
|
|
25
|
+
export declare const SHARE_EXPORT_ROUTE = "/_dsh/mobile-nav/share-export";
|
|
26
|
+
/** Upper bound on `turns` for `range=last` (PLAN §4). 500 exchanges is
|
|
27
|
+
* already more wall of text than any share card wants, and the cap keeps a
|
|
28
|
+
* careless `turns=99999999` from quietly meaning "the whole log". */
|
|
29
|
+
export declare const MAX_SHARE_TURNS = 500;
|
|
30
|
+
/** One exportable content block of a transcript row. */
|
|
31
|
+
export type ShareBlock = {
|
|
32
|
+
kind: 'text';
|
|
33
|
+
text: string;
|
|
34
|
+
} | {
|
|
35
|
+
kind: 'image';
|
|
36
|
+
};
|
|
37
|
+
/** One transcript row. `seq` is the source event's log position — stable
|
|
38
|
+
* across re-renders and usable as a React key; a range=last body keeps whole
|
|
39
|
+
* turns, so its seqs always arrive turn-contiguous. */
|
|
40
|
+
export interface ShareTurn {
|
|
41
|
+
role: 'user' | 'assistant';
|
|
42
|
+
seq: number;
|
|
43
|
+
blocks: ShareBlock[];
|
|
44
|
+
}
|
|
45
|
+
/** Response body of a successful export (PLAN §4 contract). */
|
|
46
|
+
export interface ShareExportBody {
|
|
47
|
+
ok: true;
|
|
48
|
+
/** Session creation time (Unix epoch ms) from the observed header. */
|
|
49
|
+
createdAt: number;
|
|
50
|
+
turns: ShareTurn[];
|
|
51
|
+
/** Constant false while the server never truncates; the client's slice
|
|
52
|
+
* budget is the only truncation that exists. */
|
|
53
|
+
truncated: false;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Handle one `GET {@link SHARE_EXPORT_ROUTE}?session=<id>&range=all|last&turns=N`
|
|
57
|
+
* request.
|
|
58
|
+
*
|
|
59
|
+
* Exported so an integration test can drive it with a plain node:http server
|
|
60
|
+
* and a fake sessionQuery service instead of booting a harness.
|
|
61
|
+
* @param ctx - host context carrying the sessionQuery service and logger.
|
|
62
|
+
* @param req - inbound request; no body is read.
|
|
63
|
+
* @param res - the response this call owns end to end.
|
|
64
|
+
*/
|
|
65
|
+
export declare function handleShareExport(ctx: Context, req: IncomingMessage, res: ServerResponse): Promise<void>;
|
|
66
|
+
//# sourceMappingURL=share-export.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"share-export.d.ts","sourceRoot":"","sources":["../../src/share-export.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAChE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAWlD,sEAAsE;AACtE,eAAO,MAAM,kBAAkB,kCAAkC,CAAA;AAEjE;;qEAEqE;AACrE,eAAO,MAAM,eAAe,MAAM,CAAA;AAElC,wDAAwD;AACxD,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAA;AAErB;;uDAEuD;AACvD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,GAAG,WAAW,CAAA;IAC1B,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,UAAU,EAAE,CAAA;CACrB;AAaD,+DAA+D;AAC/D,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,IAAI,CAAA;IACR,sEAAsE;IACtE,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,SAAS,EAAE,CAAA;IAClB;oDACgD;IAChD,SAAS,EAAE,KAAK,CAAA;CACjB;AAoTD;;;;;;;;;GASG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAoC9G"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-zen-remote",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.14",
|
|
4
4
|
"description": "把 DeepSeek Harness 变成手机 App:移动端界面重排(两级页面栈、会话列表主屏、composer 重排、手势、附件上传)+ 配对码认证网关 + PWA 安装 + 真 Web Push。Complete mobile plugin for DeepSeek Harness (DSH): app-shell mobile UI, pairing-code gateway for public-internet access behind your own reverse proxy, installable PWA, offline service worker, and real Web Push agent-done notifications.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -88,6 +88,7 @@
|
|
|
88
88
|
"@deepseek-ai/dsh-host-webserver": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.0 <0.2.0-0 || >=0.1.2-rc.0 <0.2.0-0",
|
|
89
89
|
"@deepseek-ai/dsh-session": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.0 <0.2.0-0 || >=0.1.2-rc.0 <0.2.0-0",
|
|
90
90
|
"@deepseek-ai/dsh-session-log-export": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.0 <0.2.0-0 || >=0.1.2-rc.0 <0.2.0-0",
|
|
91
|
+
"@deepseek-ai/dsh-session-query": ">=0.1.0-rc.7 <0.2.0-0 || >=0.1.1-rc.0 <0.2.0-0 || >=0.1.2-rc.0 <0.2.0-0",
|
|
91
92
|
"react": "^18.2.0",
|
|
92
93
|
"@deepseek-ai/dsh-tools": ">=0.0.1-rc.1 <0.1.0 || >=0.1.0-rc.1 <0.2.0-0 || >=0.1.2-rc.0 <0.2.0-0",
|
|
93
94
|
"@deepseek-ai/dsh-workspace": ">=0.1.1-rc.0 <0.2.0-0 || >=0.1.2-rc.0 <0.2.0-0"
|
|
@@ -99,6 +100,9 @@
|
|
|
99
100
|
"@deepseek-ai/dsh-session": {
|
|
100
101
|
"optional": true
|
|
101
102
|
},
|
|
103
|
+
"@deepseek-ai/dsh-session-query": {
|
|
104
|
+
"optional": true
|
|
105
|
+
},
|
|
102
106
|
"@deepseek-ai/dsh-tools": {
|
|
103
107
|
"optional": true
|
|
104
108
|
},
|
|
@@ -128,6 +132,7 @@
|
|
|
128
132
|
"@deepseek-ai/dsh-scope": "0.1.2-rc.1",
|
|
129
133
|
"@deepseek-ai/dsh-session": "0.1.2-rc.1",
|
|
130
134
|
"@deepseek-ai/dsh-session-log-export": "0.1.2-rc.1",
|
|
135
|
+
"@deepseek-ai/dsh-session-query": "0.1.2-rc.1",
|
|
131
136
|
"@deepseek-ai/dsh-session-stats": "0.1.2-rc.1",
|
|
132
137
|
"@deepseek-ai/dsh-subagent": "0.1.2-rc.1",
|
|
133
138
|
"@deepseek-ai/dsh-timeout": "0.1.2-rc.1",
|
|
@@ -146,7 +151,7 @@
|
|
|
146
151
|
"scripts": {
|
|
147
152
|
"build": "tsc -p tsconfig.json && tsc -p tsconfig.client.json && node scripts/build-client.mjs",
|
|
148
153
|
"verify": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.client.json --noEmit",
|
|
149
|
-
"test": "node --test \"test/*.test.cjs\" && node scripts/check-sunk-viewport.mjs && node scripts/check-keyboard-avoid.mjs && node scripts/check-attach-upload.mjs && node scripts/check-upload-endpoint.mjs && node scripts/check-host-shadow.mjs && node scripts/check-compat-store.mjs && node scripts/check-client-externals.mjs && node scripts/check-info-sheet-stacking.mjs && node scripts/sync-doc-version.mjs --check",
|
|
154
|
+
"test": "node --test \"test/*.test.cjs\" && node scripts/check-sunk-viewport.mjs && node scripts/check-keyboard-avoid.mjs && node scripts/check-attach-upload.mjs && node scripts/check-share-image.mjs && node scripts/check-upload-endpoint.mjs && node scripts/check-host-shadow.mjs && node scripts/check-compat-store.mjs && node scripts/check-client-externals.mjs && node scripts/check-info-sheet-stacking.mjs && node scripts/sync-doc-version.mjs --check",
|
|
150
155
|
"version": "node scripts/sync-doc-version.mjs && git add README.md README.zh-CN.md"
|
|
151
156
|
}
|
|
152
157
|
}
|
|
@@ -8,12 +8,13 @@
|
|
|
8
8
|
// means the host half silently loads whatever version this plugin last
|
|
9
9
|
// installed — "it links and starts" proves nothing.
|
|
10
10
|
//
|
|
11
|
-
// Instead of hand-maintaining a package list, the
|
|
12
|
-
// actually loads (dsh-push.mjs, lan-gate.mjs, lib/index.js
|
|
13
|
-
// @deepseek-ai specifiers — static
|
|
14
|
-
// so a new import added there gets
|
|
15
|
-
// type-only imports (erased at
|
|
16
|
-
// stdlib + web-push, so this
|
|
11
|
+
// Instead of hand-maintaining a package list, the files the host half
|
|
12
|
+
// actually loads (dsh-push.mjs, lan-gate.mjs, lib/index.js and the modules
|
|
13
|
+
// it statically pulls in) are scanned for @deepseek-ai specifiers — static
|
|
14
|
+
// import, dynamic import() and require() — so a new import added there gets
|
|
15
|
+
// watched automatically. src/index.ts is type-only imports (erased at
|
|
16
|
+
// runtime) and the gateway subprocess uses only stdlib + web-push, so this
|
|
17
|
+
// scan is the whole runtime story.
|
|
17
18
|
//
|
|
18
19
|
// Run: node scripts/check-host-shadow.mjs
|
|
19
20
|
import assert from 'node:assert/strict'
|
|
@@ -47,15 +48,46 @@ const require = createRequire(import.meta.url)
|
|
|
47
48
|
// first, or temporarily accept the drift).
|
|
48
49
|
// - npm-published tarballs contain no node_modules, so this shadow only
|
|
49
50
|
// exists on dev machines where the plugin is link-installed.
|
|
50
|
-
|
|
51
|
+
//
|
|
52
|
+
// @deepseek-ai/dsh-session:
|
|
53
|
+
// - Why allowed at all: src/share-export.ts (the share-image transcript
|
|
54
|
+
// route) statically imports the two pure fold helpers
|
|
55
|
+
// (isAppendSurfaceEvent, deriveEventMessage) from the browser-safe
|
|
56
|
+
// `@deepseek-ai/dsh-session/surface` subpath. They are THE canonical
|
|
57
|
+
// per-node projection rule per their own doc; reimplementing them locally
|
|
58
|
+
// would be a second fold that silently drifts, and no host service exposes
|
|
59
|
+
// them, so a module import is the only way to reuse them.
|
|
60
|
+
// - Why 0.1.2-rc.1: same release line as every other devDep; the package is
|
|
61
|
+
// also needed in node_modules for pnpm verify's type check regardless. The
|
|
62
|
+
// shadow only bites the two pure functions — both take plain event records
|
|
63
|
+
// and touch no class identity, and their signatures are identical on the
|
|
64
|
+
// 0.1.2 and 0.1.5 lines — so a version-skewed copy cannot diverge the fold
|
|
65
|
+
// the way a service-class mismatch could.
|
|
66
|
+
// The fact BEHIND that "signatures identical" conclusion, verified against
|
|
67
|
+
// both closures (2026-09-10): the SURFACE_EVENT_TYPES set differs across
|
|
68
|
+
// the lines — 0.1.2-rc.1 admits user/message, assistant/message,
|
|
69
|
+
// tool/result, while 0.1.5-rc.2 also admits system/message (and its
|
|
70
|
+
// deriveEventMessage projects it to a system-role message). The fold in
|
|
71
|
+
// src/share-export.ts neutralizes the difference: its role filter keeps
|
|
72
|
+
// only 'user'/'assistant' rows, so a system/message is dropped on 0.1.5 by
|
|
73
|
+
// the filter and on 0.1.2 by isAppendSurfaceEvent itself — the exported
|
|
74
|
+
// transcript is byte-identical either way. A future DSH that adds another
|
|
75
|
+
// role-bearing surface type must re-run this equivalence, not assume it.
|
|
76
|
+
// - WHEN TO ACT: a future DSH that renames the surface subpath or changes
|
|
77
|
+
// event shapes will break this import loudly at plugin load; re-pin the
|
|
78
|
+
// devDep then.
|
|
79
|
+
// - npm-published tarballs contain no node_modules, so this shadow only
|
|
80
|
+
// exists on dev machines where the plugin is link-installed.
|
|
81
|
+
const SHADOW_ALLOWED = ['@deepseek-ai/dsh-tools', '@deepseek-ai/dsh-session']
|
|
51
82
|
|
|
52
83
|
// Packages that must never exist in this plugin's node_modules at all: DSH
|
|
53
84
|
// 0.1.2 dropped them, and a stale copy would let the type check quietly pass
|
|
54
85
|
// against outdated declarations. NOT exemptible via SHADOW_ALLOWED.
|
|
55
86
|
const BANNED_PACKAGES = ['@deepseek-ai/dsh-client-runtime', '@deepseek-ai/dsh-host-apiproxy']
|
|
56
87
|
|
|
57
|
-
// The
|
|
58
|
-
|
|
88
|
+
// The files the host half actually loads. lib/share-export.js is statically
|
|
89
|
+
// imported by lib/index.js, so it is part of the same runtime graph.
|
|
90
|
+
const HOST_ENTRY_FILES = ['dsh-push.mjs', 'lan-gate.mjs', 'lib/index.js', 'lib/share-export.js']
|
|
59
91
|
|
|
60
92
|
// Matches the specifier of real module statements only — `... from 'pkg'`,
|
|
61
93
|
// `import 'pkg'`, `import('pkg')`, `require('pkg')` — so @deepseek-ai names
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
// Self-check for the composer keyboard-avoid lift (S10, issue #1 方案 2).
|
|
2
2
|
// The failing environment (小米 + 微信输入法) cannot be reproduced off-device,
|
|
3
3
|
// so the boundary cases of the pure geometry are asserted numerically.
|
|
4
|
-
// Run: node scripts/check-keyboard-avoid.mjs (needs Node >= 23.6 type stripping
|
|
4
|
+
// Run: node scripts/check-keyboard-avoid.mjs (needs Node >= 23.6 type stripping;
|
|
5
|
+
// clamped comes from lib/index.js — the host source is multi-file since the
|
|
6
|
+
// share-export route, so strip-only cannot load src/index.ts. Build first.)
|
|
5
7
|
import assert from 'node:assert/strict'
|
|
6
8
|
import { readFileSync } from 'node:fs'
|
|
7
9
|
import { composerLift, estimatedLift, keyboardLift as lift, safetyPad } from '../src/client/effects/keyboard-avoid.ts'
|
|
8
10
|
import { KEYBOARD_DEFAULTS, parseClientConfig } from '../src/client/client-config.ts'
|
|
9
|
-
import { clamped } from '../
|
|
11
|
+
import { clamped } from '../lib/index.js'
|
|
10
12
|
|
|
11
13
|
// The reported class of bug: keyboard shrinks the visual viewport, browser
|
|
12
14
|
// does not pan it — the whole shrink is an occluded band at the bottom.
|