dsh-any-background 0.1.4 → 0.1.5

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 (3) hide show
  1. package/lib/client.js +1290 -1290
  2. package/lib/index.js +176 -176
  3. package/package.json +1 -1
package/lib/index.js CHANGED
@@ -1,176 +1,176 @@
1
- import { access, mkdir, readFile, rm, writeFile } from "node:fs/promises";
2
- import { dshHomePath } from "@deepseek-ai/dsh-home-paths";
3
- //#region src/index.ts
4
- /**
5
- * Node half of the dsh-any-background plugin: file-backed theme persistence.
6
- *
7
- * The browser client cannot touch the filesystem, so this half owns the
8
- * `.dsh-any-background-data/` store under the DSH data home and exposes a
9
- * small RPC surface over the shared `/api` channel. The client reads the
10
- * persisted theme on boot and writes it back on every setting change.
11
- *
12
- * Storage layout:
13
- * ~/.dsh/.dsh-any-background-data/
14
- * ├── theme-config.json settings (color, opacities, blur, bg state)
15
- * └── wallpaper.jpg the chosen background image (deleted on remove)
16
- *
17
- * @module dsh-any-background
18
- */
19
- const name = "dsh-any-background";
20
- const inject = ["connection"];
21
- const DATA_DIR = ".dsh-any-background-data";
22
- const CONFIG_FILE = "theme-config.json";
23
- const WALLPAPER_FILE = "wallpaper.jpg";
24
- const DEFAULT_CONFIG = {
25
- color: null,
26
- opacity: .85,
27
- settingsOpacity: 1,
28
- wallpaperOpacity: 1,
29
- blur: 0,
30
- bgState: {
31
- zoom: 1,
32
- x: 0,
33
- y: 0,
34
- iw: 0,
35
- ih: 0
36
- }
37
- };
38
- const dataDir = () => dshHomePath(DATA_DIR);
39
- const configPath = () => dshHomePath(DATA_DIR, CONFIG_FILE);
40
- const wallpaperPath = () => dshHomePath(DATA_DIR, WALLPAPER_FILE);
41
- function clamp(n, lo, hi, def) {
42
- return typeof n === "number" && isFinite(n) ? Math.min(hi, Math.max(lo, n)) : def;
43
- }
44
- /** Coerce an unknown persisted value into a valid ThemeConfig, falling back per-field. */
45
- function normalizeConfig(raw) {
46
- const r = raw ?? {};
47
- const c = r.color;
48
- const color = Array.isArray(c) && c.length === 3 && c.every((x) => typeof x === "number" && isFinite(x)) ? [
49
- clamp(c[0], 0, 360, 220),
50
- clamp(c[1], 0, 1, .55),
51
- clamp(c[2], 0, 1, .25)
52
- ] : null;
53
- const bg = r.bgState ?? {};
54
- return {
55
- color,
56
- opacity: clamp(r.opacity, 0, 1, DEFAULT_CONFIG.opacity),
57
- settingsOpacity: clamp(r.settingsOpacity, 0, 1, DEFAULT_CONFIG.settingsOpacity),
58
- wallpaperOpacity: clamp(r.wallpaperOpacity, 0, 1, DEFAULT_CONFIG.wallpaperOpacity),
59
- blur: clamp(r.blur, 0, 60, DEFAULT_CONFIG.blur),
60
- bgState: {
61
- zoom: clamp(bg.zoom, .1, 10, 1),
62
- x: typeof bg.x === "number" && isFinite(bg.x) ? bg.x : 0,
63
- y: typeof bg.y === "number" && isFinite(bg.y) ? bg.y : 0,
64
- iw: typeof bg.iw === "number" && bg.iw > 0 ? bg.iw : 0,
65
- ih: typeof bg.ih === "number" && bg.ih > 0 ? bg.ih : 0
66
- }
67
- };
68
- }
69
- async function ensureDir() {
70
- try {
71
- await mkdir(dataDir(), { recursive: true });
72
- } catch (e) {
73
- console.warn(`dsh-any-background: cannot create data dir "${dataDir()}"`, e);
74
- }
75
- }
76
- async function readConfig() {
77
- await ensureDir();
78
- try {
79
- await access(configPath());
80
- } catch {
81
- return { ...DEFAULT_CONFIG };
82
- }
83
- try {
84
- const raw = await readFile(configPath(), "utf8");
85
- return normalizeConfig(JSON.parse(raw));
86
- } catch (e) {
87
- console.warn(`dsh-any-background: cannot read "${CONFIG_FILE}", using defaults`, e);
88
- return { ...DEFAULT_CONFIG };
89
- }
90
- }
91
- async function writeConfig(config) {
92
- await ensureDir();
93
- try {
94
- await writeFile(configPath(), JSON.stringify(normalizeConfig(config), null, 2), "utf8");
95
- return true;
96
- } catch (e) {
97
- console.error(`dsh-any-background: failed to write "${CONFIG_FILE}"`, e);
98
- return false;
99
- }
100
- }
101
- /** Read the wallpaper file and return it as a JPEG data URL (null when absent). */
102
- async function readWallpaper() {
103
- try {
104
- return `data:image/jpeg;base64,${(await readFile(wallpaperPath())).toString("base64")}`;
105
- } catch {
106
- return null;
107
- }
108
- }
109
- /**
110
- * Persist a wallpaper. Passing null removes the stored file; otherwise the
111
- * data URL is decoded and written to wallpaper.jpg. Returns false (and keeps
112
- * the previous file) when the payload is invalid or the write fails.
113
- */
114
- async function writeWallpaper(dataUrl) {
115
- await ensureDir();
116
- try {
117
- if (dataUrl === null) {
118
- await rm(wallpaperPath(), { force: true });
119
- return true;
120
- }
121
- const m = /^data:image\/[a-zA-Z0-9.+-]+;base64,([A-Za-z0-9+/=]+)$/.exec(dataUrl);
122
- if (!m) return false;
123
- await writeFile(wallpaperPath(), Buffer.from(m[1], "base64"));
124
- return true;
125
- } catch (e) {
126
- console.error(`dsh-any-background: failed to write "${WALLPAPER_FILE}"`, e);
127
- return false;
128
- }
129
- }
130
- const NS = "dshAnyBackground";
131
- function apply(ctx) {
132
- const dispose = ctx.connection.rpc.intercept("/api", (ep) => ep.startsWith(`${NS}/`), async (ep, payload) => {
133
- const method = ep.slice(`${NS}/`.length);
134
- try {
135
- switch (method) {
136
- case "read": return {
137
- ok: true,
138
- value: {
139
- config: await readConfig(),
140
- wallpaper: await readWallpaper()
141
- }
142
- };
143
- case "writeConfig": return {
144
- ok: true,
145
- value: await writeConfig(payload?.config ?? {})
146
- };
147
- case "setWallpaper": return {
148
- ok: true,
149
- value: await writeWallpaper(payload?.dataUrl ?? null)
150
- };
151
- default: return {
152
- ok: false,
153
- error: {
154
- code: "bad-request",
155
- message: `unknown endpoint ${ep}`,
156
- details: { issues: [] }
157
- }
158
- };
159
- }
160
- } catch (e) {
161
- return {
162
- ok: false,
163
- error: {
164
- code: "internal",
165
- message: e instanceof Error ? e.message : String(e),
166
- details: {}
167
- }
168
- };
169
- }
170
- }, { authority: "trusted-host" });
171
- ctx.on("dispose", () => {
172
- dispose();
173
- });
174
- }
175
- //#endregion
176
- export { apply, inject, name };
1
+ import { access, mkdir, readFile, rm, writeFile } from "node:fs/promises";
2
+ import { dshHomePath } from "@deepseek-ai/dsh-home-paths";
3
+ //#region src/index.ts
4
+ /**
5
+ * Node half of the dsh-any-background plugin: file-backed theme persistence.
6
+ *
7
+ * The browser client cannot touch the filesystem, so this half owns the
8
+ * `.dsh-any-background-data/` store under the DSH data home and exposes a
9
+ * small RPC surface over the shared `/api` channel. The client reads the
10
+ * persisted theme on boot and writes it back on every setting change.
11
+ *
12
+ * Storage layout:
13
+ * ~/.dsh/.dsh-any-background-data/
14
+ * ├── theme-config.json settings (color, opacities, blur, bg state)
15
+ * └── wallpaper.jpg the chosen background image (deleted on remove)
16
+ *
17
+ * @module dsh-any-background
18
+ */
19
+ const name = "dsh-any-background";
20
+ const inject = ["connection"];
21
+ const DATA_DIR = ".dsh-any-background-data";
22
+ const CONFIG_FILE = "theme-config.json";
23
+ const WALLPAPER_FILE = "wallpaper.jpg";
24
+ const DEFAULT_CONFIG = {
25
+ color: null,
26
+ opacity: .85,
27
+ settingsOpacity: 1,
28
+ wallpaperOpacity: 1,
29
+ blur: 0,
30
+ bgState: {
31
+ zoom: 1,
32
+ x: 0,
33
+ y: 0,
34
+ iw: 0,
35
+ ih: 0
36
+ }
37
+ };
38
+ const dataDir = () => dshHomePath(DATA_DIR);
39
+ const configPath = () => dshHomePath(DATA_DIR, CONFIG_FILE);
40
+ const wallpaperPath = () => dshHomePath(DATA_DIR, WALLPAPER_FILE);
41
+ function clamp(n, lo, hi, def) {
42
+ return typeof n === "number" && isFinite(n) ? Math.min(hi, Math.max(lo, n)) : def;
43
+ }
44
+ /** Coerce an unknown persisted value into a valid ThemeConfig, falling back per-field. */
45
+ function normalizeConfig(raw) {
46
+ const r = raw ?? {};
47
+ const c = r.color;
48
+ const color = Array.isArray(c) && c.length === 3 && c.every((x) => typeof x === "number" && isFinite(x)) ? [
49
+ clamp(c[0], 0, 360, 220),
50
+ clamp(c[1], 0, 1, .55),
51
+ clamp(c[2], 0, 1, .25)
52
+ ] : null;
53
+ const bg = r.bgState ?? {};
54
+ return {
55
+ color,
56
+ opacity: clamp(r.opacity, 0, 1, DEFAULT_CONFIG.opacity),
57
+ settingsOpacity: clamp(r.settingsOpacity, 0, 1, DEFAULT_CONFIG.settingsOpacity),
58
+ wallpaperOpacity: clamp(r.wallpaperOpacity, 0, 1, DEFAULT_CONFIG.wallpaperOpacity),
59
+ blur: clamp(r.blur, 0, 60, DEFAULT_CONFIG.blur),
60
+ bgState: {
61
+ zoom: clamp(bg.zoom, .1, 10, 1),
62
+ x: typeof bg.x === "number" && isFinite(bg.x) ? bg.x : 0,
63
+ y: typeof bg.y === "number" && isFinite(bg.y) ? bg.y : 0,
64
+ iw: typeof bg.iw === "number" && bg.iw > 0 ? bg.iw : 0,
65
+ ih: typeof bg.ih === "number" && bg.ih > 0 ? bg.ih : 0
66
+ }
67
+ };
68
+ }
69
+ async function ensureDir() {
70
+ try {
71
+ await mkdir(dataDir(), { recursive: true });
72
+ } catch (e) {
73
+ console.warn(`dsh-any-background: cannot create data dir "${dataDir()}"`, e);
74
+ }
75
+ }
76
+ async function readConfig() {
77
+ await ensureDir();
78
+ try {
79
+ await access(configPath());
80
+ } catch {
81
+ return { ...DEFAULT_CONFIG };
82
+ }
83
+ try {
84
+ const raw = await readFile(configPath(), "utf8");
85
+ return normalizeConfig(JSON.parse(raw));
86
+ } catch (e) {
87
+ console.warn(`dsh-any-background: cannot read "${CONFIG_FILE}", using defaults`, e);
88
+ return { ...DEFAULT_CONFIG };
89
+ }
90
+ }
91
+ async function writeConfig(config) {
92
+ await ensureDir();
93
+ try {
94
+ await writeFile(configPath(), JSON.stringify(normalizeConfig(config), null, 2), "utf8");
95
+ return true;
96
+ } catch (e) {
97
+ console.error(`dsh-any-background: failed to write "${CONFIG_FILE}"`, e);
98
+ return false;
99
+ }
100
+ }
101
+ /** Read the wallpaper file and return it as a JPEG data URL (null when absent). */
102
+ async function readWallpaper() {
103
+ try {
104
+ return `data:image/jpeg;base64,${(await readFile(wallpaperPath())).toString("base64")}`;
105
+ } catch {
106
+ return null;
107
+ }
108
+ }
109
+ /**
110
+ * Persist a wallpaper. Passing null removes the stored file; otherwise the
111
+ * data URL is decoded and written to wallpaper.jpg. Returns false (and keeps
112
+ * the previous file) when the payload is invalid or the write fails.
113
+ */
114
+ async function writeWallpaper(dataUrl) {
115
+ await ensureDir();
116
+ try {
117
+ if (dataUrl === null) {
118
+ await rm(wallpaperPath(), { force: true });
119
+ return true;
120
+ }
121
+ const m = /^data:image\/[a-zA-Z0-9.+-]+;base64,([A-Za-z0-9+/=]+)$/.exec(dataUrl);
122
+ if (!m) return false;
123
+ await writeFile(wallpaperPath(), Buffer.from(m[1], "base64"));
124
+ return true;
125
+ } catch (e) {
126
+ console.error(`dsh-any-background: failed to write "${WALLPAPER_FILE}"`, e);
127
+ return false;
128
+ }
129
+ }
130
+ const NS = "dshAnyBackground";
131
+ function apply(ctx) {
132
+ const dispose = ctx.connection.rpc.handle("/dsh-any-background", async (ep, payload) => {
133
+ const method = ep.slice(`${NS}/`.length);
134
+ try {
135
+ switch (method) {
136
+ case "read": return {
137
+ ok: true,
138
+ value: {
139
+ config: await readConfig(),
140
+ wallpaper: await readWallpaper()
141
+ }
142
+ };
143
+ case "writeConfig": return {
144
+ ok: true,
145
+ value: await writeConfig(payload?.config ?? {})
146
+ };
147
+ case "setWallpaper": return {
148
+ ok: true,
149
+ value: await writeWallpaper(payload?.dataUrl ?? null)
150
+ };
151
+ default: return {
152
+ ok: false,
153
+ error: {
154
+ code: "bad-request",
155
+ message: `unknown endpoint ${ep}`,
156
+ details: { issues: [] }
157
+ }
158
+ };
159
+ }
160
+ } catch (e) {
161
+ return {
162
+ ok: false,
163
+ error: {
164
+ code: "internal",
165
+ message: e instanceof Error ? e.message : String(e),
166
+ details: {}
167
+ }
168
+ };
169
+ }
170
+ }, { authority: "trusted-host" });
171
+ ctx.on("dispose", () => {
172
+ dispose();
173
+ });
174
+ }
175
+ //#endregion
176
+ export { apply, inject, name };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-any-background",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Appearance plugin for DeepSeek Harness: custom theme color (PS-style color wheel), background wallpaper with opacity/blur controls, and separate main/settings interface opacity.",
5
5
  "keywords": [
6
6
  "deepseek-harness",