@morlay/dsh-desktop-host 0.0.1-alpha.5 → 0.0.1-alpha.6
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 +4 -3
- package/lib/index.js +52 -5783
- package/lib/webserver.js +1 -1
- package/lib/wire.js +57 -1
- package/package.json +11 -10
package/lib/webserver.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { EventEmitter } from "node:events";
|
|
2
|
+
import { Readable } from "node:stream";
|
|
2
3
|
import { Service } from "@deepseek-ai/cordis";
|
|
3
4
|
import z from "@deepseek-ai/schemastery";
|
|
4
|
-
import { Readable } from "node:stream";
|
|
5
5
|
import { renderIndexInjections } from "@deepseek-ai/dsh-host-webserver";
|
|
6
6
|
//#region src/webserver.ts
|
|
7
7
|
/**
|
package/lib/wire.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { StringDecoder } from "node:string_decoder";
|
|
1
2
|
//#region src/wire.ts
|
|
2
3
|
/**
|
|
3
4
|
* 桌面 host 与 Electron 壳之间的字节管道协议:请求帧(壳 → host,FD 3)与响应帧(host → 壳,FD 4)。
|
|
@@ -8,6 +9,20 @@
|
|
|
8
9
|
const DESKTOP_HOST_PROTOCOL_VERSION = 1;
|
|
9
10
|
/** 桌面流的宿主路径:页面/主进程都用它(两侧共享一份,避免路径写两处)。 */
|
|
10
11
|
const DESKTOP_STREAM_PATH = "/.dsh/remote-stream";
|
|
12
|
+
/**
|
|
13
|
+
* 桌面流请求体的首行:定下这条逻辑流的 endpoint 与 payload,后续行都是上行项
|
|
14
|
+
* (客户端 → 宿主;`$events` 这类宿主自己的流被上游释放,不会读到它们)。
|
|
15
|
+
*/
|
|
16
|
+
function encodeDesktopStreamOpen(endpoint, payload) {
|
|
17
|
+
return `${JSON.stringify({
|
|
18
|
+
endpoint,
|
|
19
|
+
payload
|
|
20
|
+
})}\n`;
|
|
21
|
+
}
|
|
22
|
+
/** 桌面流请求体里的一道上行项。 */
|
|
23
|
+
function encodeDesktopStreamItem(item) {
|
|
24
|
+
return `${JSON.stringify(item)}\n`;
|
|
25
|
+
}
|
|
11
26
|
/** 壳写请求帧的管道描述符。 */
|
|
12
27
|
const DESKTOP_REQUEST_PIPE_FD = 3;
|
|
13
28
|
/** host 写响应帧的管道描述符。 */
|
|
@@ -105,6 +120,47 @@ function parseJson(payload, subject) {
|
|
|
105
120
|
function assertEmpty(payload, subject) {
|
|
106
121
|
if (payload.byteLength !== 0) throw new Error(`dsh desktop: ${subject} frame carried a payload`);
|
|
107
122
|
}
|
|
123
|
+
/**
|
|
124
|
+
* 增量解码桌面流请求体:按行取 JSON,首行是 `open`(endpoint / payload),后续每行是一道上行项。
|
|
125
|
+
* 字节边界可能切开多字节字符,所以先过 `StringDecoder` 再切行。
|
|
126
|
+
*/
|
|
127
|
+
var DesktopStreamBodyDecoder = class {
|
|
128
|
+
text = new StringDecoder("utf8");
|
|
129
|
+
buffer = "";
|
|
130
|
+
/** 追加字节并返回所有已完整的行的解析值(空行忽略)。 */
|
|
131
|
+
push(chunk) {
|
|
132
|
+
this.buffer += this.text.write(Buffer.from(chunk));
|
|
133
|
+
return this.take(false);
|
|
134
|
+
}
|
|
135
|
+
/** 请求体结束:交付末行(没有换行收尾时也存在)。 */
|
|
136
|
+
finish() {
|
|
137
|
+
this.buffer += this.text.end();
|
|
138
|
+
return this.take(true);
|
|
139
|
+
}
|
|
140
|
+
take(last) {
|
|
141
|
+
const values = [];
|
|
142
|
+
for (;;) {
|
|
143
|
+
const at = this.buffer.indexOf("\n");
|
|
144
|
+
if (at === -1) {
|
|
145
|
+
if (!last) return values;
|
|
146
|
+
const tail = this.buffer;
|
|
147
|
+
this.buffer = "";
|
|
148
|
+
if (tail.trim() !== "") values.push(parseStreamLine(tail));
|
|
149
|
+
return values;
|
|
150
|
+
}
|
|
151
|
+
const line = this.buffer.slice(0, at);
|
|
152
|
+
this.buffer = this.buffer.slice(at + 1);
|
|
153
|
+
if (line.trim() !== "") values.push(parseStreamLine(line));
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
function parseStreamLine(line) {
|
|
158
|
+
try {
|
|
159
|
+
return JSON.parse(line);
|
|
160
|
+
} catch (error) {
|
|
161
|
+
throw new Error(`dsh desktop: stream body line is not JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
108
164
|
/** 增量解码 host 侧从请求管道收到的请求帧。 */
|
|
109
165
|
var DesktopHostRequestDecoder = class {
|
|
110
166
|
buffer = Buffer.alloc(0);
|
|
@@ -242,4 +298,4 @@ function isDesktopHostCommand(value) {
|
|
|
242
298
|
return isRecord(value) && value.type === "shutdown";
|
|
243
299
|
}
|
|
244
300
|
//#endregion
|
|
245
|
-
export { DESKTOP_CONTROL_IPC_FD, DESKTOP_HOST_PROTOCOL_VERSION, DESKTOP_PIPE_CHUNK_BYTES, DESKTOP_REQUEST_PIPE_FD, DESKTOP_RESPONSE_PIPE_FD, DESKTOP_STREAM_PATH, DesktopHostRequestDecoder, DesktopHostResponseDecoder, encodeDesktopRequestCancel, encodeDesktopRequestData, encodeDesktopRequestEnd, encodeDesktopRequestStart, encodeDesktopResponseData, encodeDesktopResponseEnd, encodeDesktopResponseError, encodeDesktopResponseStart, isDesktopHostCommand, isDesktopHostEvent };
|
|
301
|
+
export { DESKTOP_CONTROL_IPC_FD, DESKTOP_HOST_PROTOCOL_VERSION, DESKTOP_PIPE_CHUNK_BYTES, DESKTOP_REQUEST_PIPE_FD, DESKTOP_RESPONSE_PIPE_FD, DESKTOP_STREAM_PATH, DesktopHostRequestDecoder, DesktopHostResponseDecoder, DesktopStreamBodyDecoder, encodeDesktopRequestCancel, encodeDesktopRequestData, encodeDesktopRequestEnd, encodeDesktopRequestStart, encodeDesktopResponseData, encodeDesktopResponseEnd, encodeDesktopResponseError, encodeDesktopResponseStart, encodeDesktopStreamItem, encodeDesktopStreamOpen, isDesktopHostCommand, isDesktopHostEvent };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@morlay/dsh-desktop-host",
|
|
3
|
-
"version": "0.0.1-alpha.
|
|
3
|
+
"version": "0.0.1-alpha.6",
|
|
4
4
|
"description": "Desktop host process for dsh-desktopify: boots the desktop profile and serves it through an in-process, portless webServer over byte pipes — upstream apps/desktop-host with the web carrier taken over and the Office skill mount removed.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"desktop",
|
|
@@ -37,20 +37,21 @@
|
|
|
37
37
|
"./package.json": "./package.json"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@deepseek-ai/dsh": "0.1.
|
|
41
|
-
"@deepseek-ai/dsh-app-boot": "0.1.
|
|
42
|
-
"@deepseek-ai/dsh-home-paths": "0.1.
|
|
43
|
-
"@deepseek-ai/dsh-host-webserver": "0.1.
|
|
44
|
-
"@deepseek-ai/
|
|
40
|
+
"@deepseek-ai/dsh": "0.1.7-alpha.1",
|
|
41
|
+
"@deepseek-ai/dsh-app-boot": "0.1.7-alpha.1",
|
|
42
|
+
"@deepseek-ai/dsh-home-paths": "0.1.7-alpha.1",
|
|
43
|
+
"@deepseek-ai/dsh-host-webserver": "0.1.7-alpha.1",
|
|
44
|
+
"@deepseek-ai/dsh-tool-workspace-dependencies": "0.1.7-alpha.1",
|
|
45
|
+
"@deepseek-ai/schemastery": "3.18.3"
|
|
45
46
|
},
|
|
46
47
|
"devDependencies": {
|
|
47
|
-
"@deepseek-ai/cordis": "4.0.
|
|
48
|
-
"@deepseek-ai/dsh-api-gateway": "0.1.
|
|
49
|
-
"@deepseek-ai/dsh-client-connection": "0.1.
|
|
48
|
+
"@deepseek-ai/cordis": "4.0.3",
|
|
49
|
+
"@deepseek-ai/dsh-api-gateway": "0.1.7-alpha.1",
|
|
50
|
+
"@deepseek-ai/dsh-client-connection": "0.1.7-alpha.1",
|
|
50
51
|
"@types/node": "^26.5.0"
|
|
51
52
|
},
|
|
52
53
|
"peerDependencies": {
|
|
53
|
-
"@deepseek-ai/cordis": "4.0.
|
|
54
|
+
"@deepseek-ai/cordis": "4.0.3"
|
|
54
55
|
},
|
|
55
56
|
"engines": {
|
|
56
57
|
"node": ">=24.11.0"
|