dsh-plugin-bridge 0.2.10

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/lib/rpc.js ADDED
@@ -0,0 +1,76 @@
1
+ /**
2
+ * dsh 网关 RPC 的最小客户端。
3
+ *
4
+ * 线协议见上游 `packages/host/apiproxy/src/fetch/handler.ts`:
5
+ * `POST /api/<method>`,`Content-Type: application/json`(非 JSON 会被 415 挡掉,
6
+ * 这是跨站写入围栏),请求体是 `client-request` 信封,响应体是 `server-response`。
7
+ * 回环无鉴权。
8
+ */
9
+ /** 一次 RPC 的业务错误(网关返回 `result.ok === false`)。 */
10
+ export class RpcError extends Error {
11
+ method;
12
+ code;
13
+ details;
14
+ constructor(method, code, message, details) {
15
+ super(`${method} 失败(${code}):${message}`);
16
+ this.name = 'RpcError';
17
+ this.method = method;
18
+ this.code = code;
19
+ this.details = details;
20
+ }
21
+ }
22
+ /**
23
+ * 解析 API 根。优先级:显式参数 > `DSH_API` > `DSH_WEB_URL`(模型 shell 环境里
24
+ * 由 web bundle 注入的本机 GUI 地址)> 回环默认值。
25
+ */
26
+ export function resolveApiBase(explicit, env = process.env) {
27
+ // 环境变量被设成空串是常态(脚本里 `DSH_API=` 之类),空串要当作没设。
28
+ const nonEmpty = (value) => {
29
+ const trimmed = value?.trim();
30
+ return trimmed ? trimmed : undefined;
31
+ };
32
+ const webUrl = nonEmpty(env.DSH_WEB_URL);
33
+ const raw = nonEmpty(explicit)
34
+ ?? nonEmpty(env.DSH_API)
35
+ ?? (webUrl ? `${webUrl.replace(/\/$/, '')}/api` : undefined)
36
+ ?? 'http://127.0.0.1:3080/api';
37
+ return raw.replace(/\/$/, '');
38
+ }
39
+ /** 建一个 RPC 调用器。 */
40
+ export function createRpc(options) {
41
+ const api = options.api.replace(/\/$/, '');
42
+ const defaultTimeout = options.timeoutMs ?? 30_000;
43
+ const prefix = options.prefix ?? 'bridge';
44
+ const doFetch = options.fetchImpl ?? fetch;
45
+ let seq = 0;
46
+ return async function rpc(method, payload = {}, timeoutMs) {
47
+ seq += 1;
48
+ const rpcId = `${prefix}-${seq}`;
49
+ let res;
50
+ try {
51
+ res = await doFetch(`${api}/${method}`, {
52
+ method: 'POST',
53
+ headers: { 'Content-Type': 'application/json' },
54
+ body: JSON.stringify({ type: 'client-request', rpcId, method, payload }),
55
+ signal: AbortSignal.timeout(timeoutMs ?? defaultTimeout),
56
+ });
57
+ }
58
+ catch (error) {
59
+ const reason = error instanceof Error ? error.message : String(error);
60
+ throw new RpcError(method, 'unreachable', `连不上 dsh 网关 ${api}(${reason})。dsh web 在跑吗?可用 --api 指定地址。`);
61
+ }
62
+ if (!res.ok) {
63
+ throw new RpcError(method, `http-${res.status}`, `${api}/${method} 返回 HTTP ${res.status}`);
64
+ }
65
+ const envelope = await res.json();
66
+ if (envelope.rpcId !== rpcId) {
67
+ throw new RpcError(method, 'rpc-id-mismatch', `响应 rpcId 与请求不匹配(${String(envelope.rpcId)})`);
68
+ }
69
+ if (!envelope.result?.ok) {
70
+ const err = envelope.result?.error;
71
+ throw new RpcError(method, err?.code ?? 'unknown', err?.message ?? '(网关未给出说明)', err?.details);
72
+ }
73
+ return envelope.result.value;
74
+ };
75
+ }
76
+ export const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
package/lib/types.d.ts ADDED
@@ -0,0 +1,64 @@
1
+ /**
2
+ * 消息与事件的最小结构契约。
3
+ *
4
+ * 这份形状同时被三方消费:`fold.ts`(把 session.history 事件折叠成消息)、
5
+ * `compression.ts`(取材)、以及复用同一语义的客户端(WebUI / 桌面 GUI)。
6
+ * 此前 eval 侧另存了一份同名副本并使用了更宽的字段,导致 `eval/` 无法通过
7
+ * 类型检查;现在只保留这一份,字段以折叠器实际写入的为准。
8
+ */
9
+ /** 一次工具调用在折叠结果里的痕迹。 */
10
+ export interface ToolNode {
11
+ /** 展示分类,折叠器统一写 'bash'(保留字段以兼容客户端渲染)。 */
12
+ type?: string;
13
+ /** 工具名。 */
14
+ title: string;
15
+ /** 运行状态;`tool/result` 到达后转为 done。 */
16
+ status?: 'running' | 'done';
17
+ /** 与 `tool/result` 配对用的调用 id。 */
18
+ callId?: string;
19
+ /** 产生该节点的事件 seq。 */
20
+ eventSeq?: number;
21
+ /** 调用入参摘要(命令 / 路径 / 查询串),不含 stdout。 */
22
+ detail?: string;
23
+ /** 工具输出(取材阶段一律不使用)。 */
24
+ output?: string;
25
+ }
26
+ /** rc.8 持久化图片附件的最小引用;字节仍由 host 保存,不进入折叠结果。 */
27
+ export interface ImageAttachmentRef {
28
+ attachmentId: string;
29
+ mediaType: 'image/jpeg' | 'image/png' | 'image/webp' | 'image/gif';
30
+ bytes: number;
31
+ width: number;
32
+ height: number;
33
+ name?: string;
34
+ }
35
+ /** 折叠后的一条会话消息。 */
36
+ export interface ChatMessage {
37
+ /** 稳定 id,形如 `e-<seq>`。 */
38
+ id?: string;
39
+ role: 'user' | 'assistant' | 'system';
40
+ content: string;
41
+ /** 'compaction' 表示这是一次上下文压缩检查点。 */
42
+ kind?: string;
43
+ toolNodes?: ToolNode[];
44
+ /** 推理内容(取材阶段一律不使用)。 */
45
+ thinking?: string;
46
+ thinkingMs?: number;
47
+ thinkingStartedAt?: number;
48
+ /** 该消息携带的图片数量。 */
49
+ imageCount?: number;
50
+ /** 能从 rc.8 history 恢复出的持久化图片引用;旧 host / 非法块可能只有 imageCount。 */
51
+ imageAttachments?: ImageAttachmentRef[];
52
+ /** 该消息已合并的最新事件 seq。 */
53
+ latestEventSeq?: number;
54
+ /** 本地化时刻,仅用于展示。 */
55
+ timestamp?: string;
56
+ }
57
+ /** session.history 的一条原始事件(宽松,运行时再判 type)。 */
58
+ export interface SessionEvent {
59
+ type?: string;
60
+ seq?: number;
61
+ time?: number;
62
+ data?: Record<string, unknown>;
63
+ [key: string]: unknown;
64
+ }
package/lib/types.js ADDED
@@ -0,0 +1,9 @@
1
+ /**
2
+ * 消息与事件的最小结构契约。
3
+ *
4
+ * 这份形状同时被三方消费:`fold.ts`(把 session.history 事件折叠成消息)、
5
+ * `compression.ts`(取材)、以及复用同一语义的客户端(WebUI / 桌面 GUI)。
6
+ * 此前 eval 侧另存了一份同名副本并使用了更宽的字段,导致 `eval/` 无法通过
7
+ * 类型检查;现在只保留这一份,字段以折叠器实际写入的为准。
8
+ */
9
+ export {};
package/package.json ADDED
@@ -0,0 +1,106 @@
1
+ {
2
+ "name": "dsh-plugin-bridge",
3
+ "version": "0.2.10",
4
+ "description": "Previewable cross-preset session migration for DeepSeek Harness with bounded, fixed-schema handoffs",
5
+ "type": "module",
6
+ "main": "lib/index.js",
7
+ "types": "lib/index.d.ts",
8
+ "files": [
9
+ "lib",
10
+ "docs",
11
+ "reports/v0.2.3-e2e-2026-08-20T13-19-13-924Z.raw.json",
12
+ "reports/v0.2.3-e2e-report.md",
13
+ "reports/v0.2.6-rc11-vision-report.md",
14
+ "cordis.patch.yml",
15
+ "README.md",
16
+ "README.zh.md"
17
+ ],
18
+ "scripts": {
19
+ "build": "tsc -p tsconfig.json",
20
+ "build:check": "npm run build && git diff --exit-code -- lib",
21
+ "typecheck": "tsc -p tsconfig.check.json",
22
+ "prepack": "npm run build",
23
+ "prepublishOnly": "npm run verify",
24
+ "test": "npm run build && npm run typecheck && node --experimental-strip-types --test test/*.test.mjs",
25
+ "eval": "node eval/run.mjs",
26
+ "datasets:check": "node scripts/check-datasets.mjs",
27
+ "pack:check": "npm pack --dry-run",
28
+ "package:smoke": "node scripts/package-smoke.mjs",
29
+ "release:check": "node scripts/check-release-version.mjs",
30
+ "verify": "npm test && npm run build:check && npm run datasets:check && npm run package:smoke"
31
+ },
32
+ "keywords": [
33
+ "dsh-plugin",
34
+ "deepseek-harness",
35
+ "bridge",
36
+ "context-migration",
37
+ "agent-preset",
38
+ "session-migration"
39
+ ],
40
+ "license": "MIT",
41
+ "dsh": {
42
+ "bundle": {
43
+ "patch": "./cordis.patch.yml"
44
+ }
45
+ },
46
+ "engines": {
47
+ "node": ">=22"
48
+ },
49
+ "peerDependencies": {
50
+ "@deepseek-ai/cordis": "^4.0.1"
51
+ },
52
+ "dependencies": {
53
+ "@deepseek-ai/schemastery": "^3.18.1"
54
+ },
55
+ "devDependencies": {
56
+ "@deepseek-ai/cordis": "4.0.1",
57
+ "@types/node": "^26.2.0",
58
+ "typescript": "^7.0.2"
59
+ },
60
+ "publishConfig": {
61
+ "access": "public"
62
+ },
63
+ "repository": {
64
+ "type": "git",
65
+ "url": "git+https://github.com/Totoro-qaq/dsh-plugin-bridge.git"
66
+ },
67
+ "bugs": {
68
+ "url": "https://github.com/Totoro-qaq/dsh-plugin-bridge/issues"
69
+ },
70
+ "homepage": "https://github.com/Totoro-qaq/dsh-plugin-bridge#readme",
71
+ "bin": {
72
+ "dsh-bridge": "lib/cli.js"
73
+ },
74
+ "exports": {
75
+ ".": {
76
+ "types": "./lib/index.d.ts",
77
+ "default": "./lib/index.js"
78
+ },
79
+ "./compression": {
80
+ "types": "./lib/compression.d.ts",
81
+ "default": "./lib/compression.js"
82
+ },
83
+ "./fold": {
84
+ "types": "./lib/fold.d.ts",
85
+ "default": "./lib/fold.js"
86
+ },
87
+ "./migrate": {
88
+ "types": "./lib/migrate.d.ts",
89
+ "default": "./lib/migrate.js"
90
+ },
91
+ "./rpc": {
92
+ "types": "./lib/rpc.d.ts",
93
+ "default": "./lib/rpc.js"
94
+ },
95
+ "./types": {
96
+ "types": "./lib/types.d.ts",
97
+ "default": "./lib/types.js"
98
+ },
99
+ "./command": {
100
+ "types": "./lib/command.d.ts",
101
+ "default": "./lib/command.js"
102
+ },
103
+ "./cordis.patch.yml": "./cordis.patch.yml",
104
+ "./package.json": "./package.json"
105
+ }
106
+ }