beauticode-dsh 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 (40) hide show
  1. package/README.zh-CN.md +48 -0
  2. package/agent.mjs +595 -0
  3. package/atmosphere.js +306 -0
  4. package/bin/beauticode-dsh +219 -0
  5. package/cli.js +219 -0
  6. package/client.js +370 -0
  7. package/console.js +303 -0
  8. package/control-client.mjs +445 -0
  9. package/cordis.patch.yml +4 -0
  10. package/host-apply.mjs +163 -0
  11. package/index.mjs +570 -0
  12. package/package.json +56 -0
  13. package/presets.mjs +73 -0
  14. package/themes/internal-beyond/NOTICE.md +9 -0
  15. package/themes/internal-beyond/bg-canvas-4k.png +0 -0
  16. package/themes/internal-beyond/bg-canvas.png +0 -0
  17. package/themes/internal-beyond/bg-infernal.jpg +0 -0
  18. package/themes/internal-beyond/bg-internal.jpg +0 -0
  19. package/ui-host.mjs +292 -0
  20. package/vendor/adapter-dsh/bridge.js +215 -0
  21. package/vendor/adapter-dsh/host-descriptor.js +15 -0
  22. package/vendor/adapter-dsh/index.js +6 -0
  23. package/vendor/adapter-dsh/injector-lock.js +27 -0
  24. package/vendor/adapter-dsh/package.json +5 -0
  25. package/vendor/adapter-dsh/session.js +527 -0
  26. package/vendor/adapter-dsh/token.js +46 -0
  27. package/vendor/adapter-dsh/tray-handoff.js +54 -0
  28. package/vendor/core/apply-transaction.js +287 -0
  29. package/vendor/core/background-store.js +1116 -0
  30. package/vendor/core/bundled-gallery.js +53 -0
  31. package/vendor/core/constants.js +47 -0
  32. package/vendor/core/error-message.js +208 -0
  33. package/vendor/core/file-lock.js +151 -0
  34. package/vendor/core/host-session.js +2 -0
  35. package/vendor/core/index.js +12 -0
  36. package/vendor/core/media-server.js +544 -0
  37. package/vendor/core/media-validation.js +244 -0
  38. package/vendor/core/package.json +5 -0
  39. package/vendor/core/paths.js +168 -0
  40. package/vendor/core/types.js +15 -0
@@ -0,0 +1,9 @@
1
+ # Internal / Infernal atmosphere assets
2
+
3
+ `bg-internal.jpg`, `bg-infernal.jpg`, `bg-canvas.png`, and the local
4
+ `bg-canvas-4k.png` (Real-ESRGAN 4x then 3840×2160) are visual materials
5
+ from [Internal Beyond](https://github.com/Sui-IB/InternalBeyond) by Sui.
6
+
7
+ They remain under that project's CC BY-NC-SA 4.0 terms for visual assets.
8
+ BeautiCode ships them as bundled workspace themes for local, non-commercial use.
9
+ The project name, logo, and character identity are not licensed here.
package/ui-host.mjs ADDED
@@ -0,0 +1,292 @@
1
+ import fs from "node:fs";
2
+ import fsp from "node:fs/promises";
3
+ import path from "node:path";
4
+ import crypto from "node:crypto";
5
+ import { pipeline } from "node:stream/promises";
6
+ import { Transform } from "node:stream";
7
+ import { createBeauticodeActions } from "./agent.mjs";
8
+ import { callDshControl } from "./control-client.mjs";
9
+ import { hasLiveTray, resolveApplyBackend, stopInProcessSession } from "./host-apply.mjs";
10
+
11
+ const IMAGE_EXTENSIONS = new Set([".jpg", ".jpeg", ".png", ".webp", ".avif"]);
12
+ const MAX_IMAGE_BYTES = 18 * 1024 * 1024;
13
+ const MAX_VIDEO_BYTES = 800 * 1024 * 1024;
14
+
15
+ export function parseImportFilename(raw) {
16
+ if (typeof raw !== "string" || !raw.trim()) {
17
+ return { ok: false, error: "缺少文件名。" };
18
+ }
19
+ let decoded = raw.trim();
20
+ try {
21
+ decoded = decodeURIComponent(decoded);
22
+ } catch {
23
+ /* keep raw */
24
+ }
25
+ const name = path.basename(decoded.replaceAll("\\", "/"));
26
+ if (!name || name === "." || name === "..") {
27
+ return { ok: false, error: "文件名无效。" };
28
+ }
29
+ const ext = path.extname(name).toLowerCase();
30
+ if (ext === ".mp4") {
31
+ return { ok: true, name, ext, kind: "video", maxBytes: MAX_VIDEO_BYTES };
32
+ }
33
+ if (IMAGE_EXTENSIONS.has(ext)) {
34
+ return { ok: true, name, ext, kind: "image", maxBytes: MAX_IMAGE_BYTES };
35
+ }
36
+ return { ok: false, error: "只支持图片(jpg / jpeg / png / webp / avif)或 MP4 视频。" };
37
+ }
38
+
39
+ function limitBytes(maxBytes) {
40
+ let size = 0;
41
+ return new Transform({
42
+ transform(chunk, _enc, callback) {
43
+ size += chunk.length;
44
+ if (size > maxBytes) {
45
+ const error = new Error("文件过大。");
46
+ error.statusCode = 413;
47
+ callback(error);
48
+ return;
49
+ }
50
+ callback(null, chunk);
51
+ },
52
+ });
53
+ }
54
+
55
+ function publicThemes(list) {
56
+ return (Array.isArray(list) ? list : []).map((theme) => ({
57
+ id: theme.id,
58
+ name: theme.name,
59
+ type: theme.type ?? null,
60
+ ...(theme.bundled ? { bundled: true } : {}),
61
+ }));
62
+ }
63
+
64
+ async function canReachBridge(baseUrl) {
65
+ const origin = typeof baseUrl === "string" && baseUrl ? baseUrl : "http://127.0.0.1:3080";
66
+ const controller = new AbortController();
67
+ const timer = setTimeout(() => controller.abort(), 800);
68
+ try {
69
+ const response = await fetch(new URL("__beauticode/version", origin.endsWith("/") ? origin : `${origin}/`), {
70
+ signal: controller.signal,
71
+ });
72
+ return response.ok;
73
+ } catch {
74
+ return false;
75
+ } finally {
76
+ clearTimeout(timer);
77
+ }
78
+ }
79
+
80
+ export function createBeauticodeUi({ dataRoot, baseUrl, getBaseUrl, sendJson, isSameOrigin, readJson }) {
81
+ const options = {
82
+ dataRoot,
83
+ get baseUrl() {
84
+ if (typeof getBaseUrl === "function") return getBaseUrl();
85
+ return baseUrl;
86
+ },
87
+ };
88
+ const actions = createBeauticodeActions(options);
89
+ let restoreStarted = false;
90
+
91
+ async function restoreOnce() {
92
+ if (await hasLiveTray(dataRoot)) {
93
+ return callDshControl(dataRoot, {
94
+ method: "POST",
95
+ path: "/reapply",
96
+ body: {},
97
+ timeoutMs: 30_000,
98
+ });
99
+ }
100
+ if (!(await canReachBridge(options.baseUrl))) return;
101
+ const resolved = await resolveApplyBackend(options);
102
+ if (resolved.kind === "tray") {
103
+ return callDshControl(dataRoot, {
104
+ method: "POST",
105
+ path: "/reapply",
106
+ body: {},
107
+ timeoutMs: 30_000,
108
+ });
109
+ }
110
+ return resolved.session.reapply();
111
+ }
112
+
113
+ return {
114
+ dispose() {
115
+ return stopInProcessSession(dataRoot);
116
+ },
117
+ scheduleRestore() {
118
+ if (restoreStarted) return;
119
+ restoreStarted = true;
120
+ queueMicrotask(() => {
121
+ void restoreOnce().catch(() => {
122
+ restoreStarted = false;
123
+ });
124
+ });
125
+ },
126
+
127
+ async status(req, res) {
128
+ if (req.method !== "GET") {
129
+ res.writeHead(405).end();
130
+ return;
131
+ }
132
+ if (!isSameOrigin(req)) {
133
+ res.writeHead(403).end();
134
+ return;
135
+ }
136
+ try {
137
+ const status = await actions.status();
138
+ const listed = await actions.listThemes();
139
+ const background = status.background ?? null;
140
+ sendJson(res, 200, {
141
+ ok: true,
142
+ media: background?.type ?? null,
143
+ muted: status.muted !== false,
144
+ atmosphere: background?.effects?.preset ?? null,
145
+ themes: publicThemes(listed.themes),
146
+ message: status.message,
147
+ });
148
+ } catch (error) {
149
+ sendJson(res, 200, {
150
+ ok: false,
151
+ error: error instanceof Error ? error.message : String(error),
152
+ });
153
+ }
154
+ },
155
+
156
+ async importFile(req, res) {
157
+ if (req.method !== "POST") {
158
+ res.writeHead(405).end();
159
+ return;
160
+ }
161
+ if (!isSameOrigin(req)) {
162
+ res.writeHead(403).end();
163
+ return;
164
+ }
165
+ const parsed = parseImportFilename(req.headers["x-beauticode-filename"]);
166
+ if (!parsed.ok) {
167
+ req.resume();
168
+ sendJson(res, 400, { ok: false, error: parsed.error });
169
+ return;
170
+ }
171
+ const length = Number(req.headers["content-length"]);
172
+ if (Number.isFinite(length) && length > parsed.maxBytes) {
173
+ req.resume();
174
+ sendJson(res, 413, { ok: false, error: "文件过大。" });
175
+ return;
176
+ }
177
+ const tmpDir = path.join(dataRoot, "tmp");
178
+ await fsp.mkdir(tmpDir, { recursive: true });
179
+ const tmpPath = path.join(
180
+ tmpDir,
181
+ `${Date.now()}-${crypto.randomBytes(8).toString("hex")}${parsed.ext}`,
182
+ );
183
+ try {
184
+ await pipeline(req, limitBytes(parsed.maxBytes), fs.createWriteStream(tmpPath));
185
+ const result =
186
+ parsed.kind === "video"
187
+ ? await actions.applyVideo({ path: tmpPath })
188
+ : await actions.applyImage(tmpPath);
189
+ sendJson(res, 200, result);
190
+ } catch (error) {
191
+ const status = error?.statusCode === 413 ? 413 : 422;
192
+ sendJson(res, status, {
193
+ ok: false,
194
+ error: error instanceof Error ? error.message : String(error),
195
+ });
196
+ } finally {
197
+ await fsp.rm(tmpPath, { force: true }).catch(() => {});
198
+ }
199
+ },
200
+
201
+ async clear(req, res) {
202
+ if (req.method !== "POST") {
203
+ res.writeHead(405).end();
204
+ return;
205
+ }
206
+ if (!isSameOrigin(req)) {
207
+ res.writeHead(403).end();
208
+ return;
209
+ }
210
+ try {
211
+ sendJson(res, 200, await actions.clear());
212
+ } catch (error) {
213
+ sendJson(res, 422, {
214
+ ok: false,
215
+ error: error instanceof Error ? error.message : String(error),
216
+ });
217
+ }
218
+ },
219
+
220
+ async mode(req, res) {
221
+ if (req.method !== "POST") {
222
+ res.writeHead(405).end();
223
+ return;
224
+ }
225
+ if (!isSameOrigin(req)) {
226
+ res.writeHead(403).end();
227
+ return;
228
+ }
229
+ const body = await readJson(req);
230
+ if (typeof body.muted !== "boolean" || Object.keys(body).some((key) => key !== "muted")) {
231
+ sendJson(res, 400, { ok: false, error: "只接受 muted 开关。" });
232
+ return;
233
+ }
234
+ try {
235
+ sendJson(res, 200, await actions.setMuted(body.muted));
236
+ } catch (error) {
237
+ sendJson(res, 422, {
238
+ ok: false,
239
+ error: error instanceof Error ? error.message : String(error),
240
+ });
241
+ }
242
+ },
243
+
244
+ async useTheme(req, res) {
245
+ if (req.method !== "POST") {
246
+ res.writeHead(405).end();
247
+ return;
248
+ }
249
+ if (!isSameOrigin(req)) {
250
+ res.writeHead(403).end();
251
+ return;
252
+ }
253
+ const body = await readJson(req);
254
+ if (typeof body.id !== "string" || !body.id.trim()) {
255
+ sendJson(res, 400, { ok: false, error: "必须提供主题。" });
256
+ return;
257
+ }
258
+ try {
259
+ sendJson(res, 200, await actions.useTheme(body.id.trim()));
260
+ } catch (error) {
261
+ sendJson(res, 422, {
262
+ ok: false,
263
+ error: error instanceof Error ? error.message : String(error),
264
+ });
265
+ }
266
+ },
267
+
268
+ async applyPreset(req, res) {
269
+ if (req.method !== "POST") {
270
+ res.writeHead(405).end();
271
+ return;
272
+ }
273
+ if (!isSameOrigin(req)) {
274
+ res.writeHead(403).end();
275
+ return;
276
+ }
277
+ const body = await readJson(req);
278
+ if (body.id !== "internal" && body.id !== "infernal") {
279
+ sendJson(res, 400, { ok: false, error: "未知的内置主题。" });
280
+ return;
281
+ }
282
+ try {
283
+ sendJson(res, 200, await actions.applyPreset(body.id));
284
+ } catch (error) {
285
+ sendJson(res, 422, {
286
+ ok: false,
287
+ error: error instanceof Error ? error.message : String(error),
288
+ });
289
+ }
290
+ },
291
+ };
292
+ }
@@ -0,0 +1,215 @@
1
+ export function normalizeDshBaseUrl(value) {
2
+ const url = new URL(value);
3
+ const hostname = url.hostname.toLowerCase();
4
+ if (url.protocol !== "http:" ||
5
+ !["127.0.0.1", "localhost", "[::1]"].includes(hostname) ||
6
+ url.username ||
7
+ url.password ||
8
+ (url.pathname !== "" && url.pathname !== "/") ||
9
+ url.search ||
10
+ url.hash) {
11
+ throw new Error("DeepSeek Harness URL must be loopback HTTP.");
12
+ }
13
+ url.pathname = url.pathname.replace(/\/+$/, "") || "/";
14
+ return url;
15
+ }
16
+ function delay(ms) {
17
+ return new Promise((resolve) => setTimeout(resolve, ms));
18
+ }
19
+ export class DshHostApplier {
20
+ baseUrl;
21
+ requestTimeoutMs;
22
+ pollMs;
23
+ token;
24
+ lastStatus = null;
25
+ constructor(opts) {
26
+ this.baseUrl = normalizeDshBaseUrl(opts.baseUrl ?? "http://127.0.0.1:3080");
27
+ this.token = opts.token;
28
+ this.requestTimeoutMs = opts.requestTimeoutMs ?? 3_000;
29
+ this.pollMs = opts.pollMs ?? 150;
30
+ }
31
+ get origin() {
32
+ return this.baseUrl.origin;
33
+ }
34
+ get activeSessionCount() {
35
+ return this.lastStatus?.connectedClients ?? 0;
36
+ }
37
+ async status() {
38
+ try {
39
+ const status = await this.#request("status", { method: "GET" });
40
+ if (!status || status.ok !== true || !Number.isInteger(status.connectedClients)) {
41
+ throw new Error("DeepSeek Harness bridge returned an invalid status.");
42
+ }
43
+ this.lastStatus = status;
44
+ return status;
45
+ }
46
+ catch (error) {
47
+ this.lastStatus = null;
48
+ throw error;
49
+ }
50
+ }
51
+ async apply(payload) {
52
+ if (payload.media !== "clear" && !payload.imageUrl) {
53
+ throw new Error("DeepSeek Harness background apply requires a loopback poster URL.");
54
+ }
55
+ if (payload.media === "video" && !payload.video?.srcUrl) {
56
+ throw new Error("DeepSeek Harness video apply requires a loopback MP4 URL.");
57
+ }
58
+ const body = {
59
+ generation: payload.generation,
60
+ media: payload.media,
61
+ imageUrl: payload.media === "clear" ? null : payload.imageUrl,
62
+ videoUrl: payload.media === "video" ? payload.video?.srcUrl : null,
63
+ startAt: payload.media === "video" && Number.isFinite(payload.video?.startAt)
64
+ ? Math.max(0, Number(payload.video?.startAt))
65
+ : null,
66
+ };
67
+ if (payload.atmosphere?.preset)
68
+ body.atmosphere = payload.atmosphere;
69
+ await this.#request("apply", {
70
+ method: "POST",
71
+ body: JSON.stringify(body),
72
+ });
73
+ }
74
+ async setFishMode(enabled) {
75
+ const result = await this.#setMode({ fish: Boolean(enabled) });
76
+ return { ok: result.ok, fish: Boolean(enabled), sessions: result.sessions, ...(result.error ? { error: result.error } : {}) };
77
+ }
78
+ async setMuted(muted) {
79
+ const result = await this.#setMode({ muted: Boolean(muted) });
80
+ return {
81
+ ok: result.ok,
82
+ muted: Boolean(muted),
83
+ blocked: result.blocked,
84
+ sessions: result.sessions,
85
+ ...(result.error ? { error: result.error } : {}),
86
+ };
87
+ }
88
+ async setBackgroundTone(tone) {
89
+ const normalized = tone === "light" || tone === "auto" ? tone : "dark";
90
+ const result = await this.#setMode({ tone: normalized });
91
+ return { ok: result.ok, tone: normalized, sessions: result.sessions, ...(result.error ? { error: result.error } : {}) };
92
+ }
93
+ async getPlaybackPosition() {
94
+ const status = await this.status();
95
+ const playback = status.playback;
96
+ if (!playback?.hasVideo) {
97
+ return { ok: false, currentTime: 0, duration: 0, hasVideo: false };
98
+ }
99
+ return {
100
+ ok: true,
101
+ currentTime: Number.isFinite(playback.currentTime) ? playback.currentTime : 0,
102
+ duration: Number.isFinite(playback.duration) ? playback.duration : 0,
103
+ hasVideo: true,
104
+ };
105
+ }
106
+ async verify(expected, opts) {
107
+ const deadline = Date.now() + Math.max(0, opts.deadlineMs);
108
+ let last = null;
109
+ let lastError = "DeepSeek Harness bridge is unavailable.";
110
+ do {
111
+ try {
112
+ last = await this.status();
113
+ const currentMatches = last.current?.generation === expected.generation &&
114
+ last.current.media === expected.media;
115
+ if (currentMatches && last.readyClients > 0) {
116
+ return {
117
+ status: "pass",
118
+ reason: "DeepSeek Harness client acknowledged the background.",
119
+ details: { ...last },
120
+ };
121
+ }
122
+ if (currentMatches && last.failedClients > 0 && last.readyClients === 0) {
123
+ return {
124
+ status: "fail",
125
+ reason: "DeepSeek Harness client failed to render the background.",
126
+ details: { ...last },
127
+ };
128
+ }
129
+ lastError =
130
+ last.connectedClients === 0
131
+ ? "No DeepSeek Harness browser client is connected."
132
+ : "DeepSeek Harness client has not acknowledged this generation.";
133
+ }
134
+ catch (error) {
135
+ lastError = error instanceof Error ? error.message : String(error);
136
+ }
137
+ if (Date.now() >= deadline)
138
+ break;
139
+ await delay(Math.min(this.pollMs, Math.max(0, deadline - Date.now())));
140
+ } while (true);
141
+ return {
142
+ status: "inconclusive",
143
+ reason: lastError,
144
+ ...(last ? { details: { ...last } } : {}),
145
+ };
146
+ }
147
+ async #request(route, init) {
148
+ const endpoint = new URL(`__beauticode/${route}`, this.baseUrl);
149
+ const controller = new AbortController();
150
+ const timer = setTimeout(() => controller.abort(), this.requestTimeoutMs);
151
+ try {
152
+ const response = await fetch(endpoint, {
153
+ ...init,
154
+ signal: controller.signal,
155
+ headers: {
156
+ Authorization: `Bearer ${this.token}`,
157
+ "Content-Type": "application/json",
158
+ ...(init.headers ?? {}),
159
+ },
160
+ });
161
+ const body = (await response.json().catch(() => null));
162
+ if (!response.ok) {
163
+ const detail = typeof body?.error === "string" ? body.error : `HTTP ${response.status}`;
164
+ throw new Error(`DeepSeek Harness bridge request failed: ${detail}`);
165
+ }
166
+ return body;
167
+ }
168
+ catch (error) {
169
+ if (error?.name === "AbortError") {
170
+ throw new Error("DeepSeek Harness bridge request timed out.");
171
+ }
172
+ throw error;
173
+ }
174
+ finally {
175
+ clearTimeout(timer);
176
+ }
177
+ }
178
+ async #setMode(change) {
179
+ await this.#request("mode", { method: "POST", body: JSON.stringify(change) });
180
+ const deadline = Date.now() + this.requestTimeoutMs;
181
+ let last = null;
182
+ do {
183
+ try {
184
+ last = await this.status();
185
+ if (last.connectedClients === 0) {
186
+ return { ok: true, sessions: 0, blocked: false };
187
+ }
188
+ if (last.modeReadyClients > 0) {
189
+ return {
190
+ ok: true,
191
+ sessions: last.modeReadyClients,
192
+ blocked: last.blockedClients > 0,
193
+ };
194
+ }
195
+ }
196
+ catch (error) {
197
+ if (Date.now() >= deadline) {
198
+ return { ok: false, sessions: 0, blocked: false, error: error instanceof Error ? error.message : String(error) };
199
+ }
200
+ }
201
+ if (Date.now() >= deadline)
202
+ break;
203
+ await delay(Math.min(this.pollMs, Math.max(0, deadline - Date.now())));
204
+ } while (true);
205
+ return {
206
+ ok: false,
207
+ sessions: 0,
208
+ blocked: false,
209
+ error: last?.connectedClients
210
+ ? "DeepSeek Harness client did not acknowledge the mode change."
211
+ : "No DeepSeek Harness browser client is connected.",
212
+ };
213
+ }
214
+ }
215
+ //# sourceMappingURL=bridge.js.map
@@ -0,0 +1,15 @@
1
+ export const DSH_HOST_DESCRIPTOR = Object.freeze({
2
+ kind: "dsh",
3
+ displayName: "DeepSeek Harness",
4
+ capabilities: Object.freeze({
5
+ image: true,
6
+ clear: true,
7
+ reapply: true,
8
+ savedThemes: true,
9
+ video: true,
10
+ fish: true,
11
+ muted: true,
12
+ tone: true,
13
+ }),
14
+ });
15
+ //# sourceMappingURL=host-descriptor.js.map
@@ -0,0 +1,6 @@
1
+ export { DshHostApplier, normalizeDshBaseUrl, } from "./bridge.js";
2
+ export { DSH_HOST_DESCRIPTOR } from "./host-descriptor.js";
3
+ export { DshSession } from "./session.js";
4
+ export { DSH_BRIDGE_TOKEN_FILE, bridgeTokenPath, ensureBridgeToken, } from "./token.js";
5
+ export { toChineseErrorMessage } from "../core/index.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,27 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { acquireFileLock } from "../core/index.js";
4
+ /** Shares injector.lock with the Codex adapter to prevent cross-host writes. */
5
+ export async function acquireDshInjectorLock(dataRoot) {
6
+ await fs.mkdir(dataRoot, { recursive: true });
7
+ const file = path.join(dataRoot, "injector.lock");
8
+ const lease = await acquireFileLock(file, { purpose: "beautiCode injector" });
9
+ const lock = {
10
+ pid: lease.owner.pid,
11
+ port: 0,
12
+ host: "dsh",
13
+ startedAt: lease.owner.startedAt,
14
+ nonce: lease.owner.nonce,
15
+ };
16
+ const handle = await fs.open(file, "r+");
17
+ try {
18
+ await handle.truncate(0);
19
+ await handle.writeFile(`${JSON.stringify(lock, null, 2)}\n`, "utf8");
20
+ await handle.sync();
21
+ }
22
+ finally {
23
+ await handle.close();
24
+ }
25
+ return () => lease.release();
26
+ }
27
+ //# sourceMappingURL=injector-lock.js.map
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "@beauticode/adapter-dsh",
3
+ "type": "module",
4
+ "main": "./index.js"
5
+ }