@morlay/dsh-desktop-host 0.0.1-alpha.5 → 0.0.1-alpha.7

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/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);
@@ -234,7 +290,7 @@ var DesktopHostResponseDecoder = class {
234
290
  function isDesktopHostEvent(value) {
235
291
  if (!isRecord(value)) return false;
236
292
  if (value.type === "ready") return value.protocolVersion === 1;
237
- if (value.type === "fatal") return typeof value.message === "string";
293
+ if (value.type === "fatal") return typeof value.message === "string" && (value.diagnostic === void 0 || typeof value.diagnostic === "string");
238
294
  return false;
239
295
  }
240
296
  /** IPC 命令校验(host 侧)。 */
@@ -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/locale/en.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Desktop Host",
4
+ "description": "Desktop host process: boots the desktop profile and serves it through an in-process, portless webServer over byte pipes."
5
+ }
6
+ }
package/locale/zh.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "桌面宿主进程",
4
+ "description": "桌面部署的 host 进程:按 desktop profile 装配,经字节管道交给宿主内无端口的 webServer。"
5
+ }
6
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@morlay/dsh-desktop-host",
3
- "version": "0.0.1-alpha.5",
3
+ "version": "0.0.1-alpha.7",
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",
@@ -16,41 +16,31 @@
16
16
  "url": "https://github.com/morlay/dsh-plugin.git"
17
17
  },
18
18
  "files": [
19
+ "locale/*.json",
19
20
  "lib",
20
21
  "config/desktop.cordis.patch.yml"
21
22
  ],
22
23
  "type": "module",
23
24
  "main": "./lib/index.js",
24
25
  "exports": {
25
- ".": {
26
- "types": "./src/index.ts",
27
- "default": "./lib/index.js"
28
- },
29
- "./webserver": {
30
- "types": "./src/webserver.ts",
31
- "default": "./lib/webserver.js"
32
- },
33
- "./wire": {
34
- "types": "./src/wire.ts",
35
- "default": "./lib/wire.js"
36
- },
37
- "./package.json": "./package.json"
26
+ "./locale/*.json": "./locale/*.json"
38
27
  },
39
28
  "dependencies": {
40
- "@deepseek-ai/dsh": "0.1.6-alpha.2",
41
- "@deepseek-ai/dsh-app-boot": "0.1.6-alpha.2",
42
- "@deepseek-ai/dsh-home-paths": "0.1.6-alpha.2",
43
- "@deepseek-ai/dsh-host-webserver": "0.1.6-alpha.2",
44
- "@deepseek-ai/schemastery": "3.18.2"
29
+ "@deepseek-ai/dsh": "0.1.7-alpha.2",
30
+ "@deepseek-ai/dsh-app-boot": "0.1.7-alpha.2",
31
+ "@deepseek-ai/dsh-home-paths": "0.1.7-alpha.2",
32
+ "@deepseek-ai/dsh-host-webserver": "0.1.7-alpha.2",
33
+ "@deepseek-ai/dsh-tool-workspace-dependencies": "0.1.7-alpha.2",
34
+ "@deepseek-ai/schemastery": "3.18.4"
45
35
  },
46
36
  "devDependencies": {
47
- "@deepseek-ai/cordis": "4.0.2",
48
- "@deepseek-ai/dsh-api-gateway": "0.1.6-alpha.2",
49
- "@deepseek-ai/dsh-client-connection": "0.1.6-alpha.2",
37
+ "@deepseek-ai/cordis": "4.0.4",
38
+ "@deepseek-ai/dsh-api-gateway": "0.1.7-alpha.2",
39
+ "@deepseek-ai/dsh-client-connection": "0.1.7-alpha.2",
50
40
  "@types/node": "^26.5.0"
51
41
  },
52
42
  "peerDependencies": {
53
- "@deepseek-ai/cordis": "4.0.2"
43
+ "@deepseek-ai/cordis": "4.0.4"
54
44
  },
55
45
  "engines": {
56
46
  "node": ">=24.11.0"