dsh-web-icon-indicator 0.4.2 → 0.5.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.
@@ -10,6 +10,7 @@
10
10
  * config:
11
11
  * askingHoldMs: 3500
12
12
  * doneHoldMs: 5000
13
+ * defaultColor: '#5B8DEF' # per-instance default icon color
13
14
  * states:
14
15
  * idle: { effect: static, colors: ['#1a1a1a'] }
15
16
  * running: { effect: static, colors: ['#FACC15'] }
@@ -60,15 +61,50 @@ export interface DshWebIconIndicatorConfig {
60
61
  * Defaults to `<package>/icons/`.
61
62
  */
62
63
  iconsDir?: string;
63
- /** Status JSON endpoint the browser polls. Default `/dsh-web-icon-status.json`. */
64
+ /**
65
+ * Status JSON endpoint the browser polls. Default `/dsh-web-icon-status.json`.
66
+ *
67
+ * **Registration-time:** set it in the composition entry only. The route
68
+ * table and the injected script are built when the plugin mounts, so this key
69
+ * is intentionally absent from the settings schema (`settings.yaml`) — a
70
+ * settings-document change could never be honored and would point the browser
71
+ * at a path the server does not serve.
72
+ */
64
73
  statusPath?: string;
65
- /** URL prefix where `base.svg` is served. Default `/dsh-web-icon-indicator`. */
74
+ /**
75
+ * URL prefix where `base.svg` is served. Default `/dsh-web-icon-indicator`.
76
+ *
77
+ * **Registration-time:** set it in the composition entry only — see
78
+ * {@link statusPath}.
79
+ */
66
80
  iconPathPrefix?: string;
67
81
  /** Minimum visibility of the asking state in milliseconds. Default 3500. */
68
82
  askingHoldMs?: number;
69
83
  /** Time the done state stays before falling back to idle, in milliseconds. Default 5000. */
70
84
  doneHoldMs?: number;
71
- /** Per-state visual config. Each entry is shallow-merged over its default. */
85
+ /**
86
+ * Default icon color — the idle whale's primary color, as `#rgb` / `#rrggbb`.
87
+ * Absent keeps the idle state's own `colors[0]` (the behavior before this key
88
+ * existed). Give each DSH instance a different value to tell their browser
89
+ * tabs apart: it is per instance (profile / `settings.yaml`), not per tab.
90
+ *
91
+ * Folded into `states.idle.colors[0]` at resolve time, so an idle entry that
92
+ * only needs its default is untouched. This is the **only** idle knob the
93
+ * settings card offers: idle paints one color and takes no animation, so it
94
+ * gets no per-state row (no effect / colors / cycle). A value perceptually too
95
+ * close to another state's color raises an advisory warning (settings card,
96
+ * host log, and {@link DshWebIconIndicatorAggregate.warnings}) but is still
97
+ * applied; a malformed value is ignored and reported.
98
+ */
99
+ defaultColor?: string;
100
+ /**
101
+ * Per-state visual config. Each entry is shallow-merged over its default.
102
+ *
103
+ * `idle` is not editable from the settings card (its color is
104
+ * {@link defaultColor}); a `states.idle` entry arriving from the composition
105
+ * entry or a hand-written `settings.yaml` is still honored for backward
106
+ * compatibility — including an idle `effect` and a second color.
107
+ */
72
108
  states?: Partial<Record<DshWebIconStateName, DshWebIconStateConfig>>;
73
109
  }
74
110
 
@@ -91,6 +127,39 @@ export interface DshWebIconIndicatorAggregate {
91
127
  * reload). Added in 0.2.x; older browser bundles ignore it.
92
128
  */
93
129
  states: Partial<Record<DshWebIconStateName, DshWebIconStateConfig>>;
130
+ /**
131
+ * Effective default icon color (normalized to lowercase 6-digit hex), or
132
+ * `null` when none is configured — the status payload always carries the key.
133
+ * Added with the `defaultColor` key; older browser bundles ignore the extra
134
+ * field.
135
+ */
136
+ defaultColor: string | null;
137
+ /**
138
+ * Advisory default-color warnings, echoed so any surface can show them.
139
+ * Added with the `defaultColor` key; older browser bundles ignore the key.
140
+ */
141
+ warnings: DshWebIconColorWarning[];
142
+ }
143
+
144
+ /**
145
+ * A perceptual-distance warning about the effective default icon color.
146
+ * Advisory only — the configured value is still applied.
147
+ */
148
+ export interface DshWebIconColorWarning {
149
+ /** `color-too-close` | `rainbow-overlap` | `invalid-color`. */
150
+ code: "color-too-close" | "rainbow-overlap" | "invalid-color";
151
+ /** The other state involved (absent for `invalid-color`). */
152
+ state?: DshWebIconStateName;
153
+ /** The effective default color the warning is about. */
154
+ base?: string;
155
+ /** The colliding state color (absent for `rainbow-overlap` / `invalid-color`). */
156
+ color?: string;
157
+ /** CIE76 ΔE between `base` and `color`. */
158
+ deltaE?: number;
159
+ /** `strong` below ΔE 12; `warn` below ΔE 25. */
160
+ level?: "strong" | "warn";
161
+ /** The rejected raw value (only for `invalid-color`). */
162
+ value?: string;
94
163
  }
95
164
 
96
165
  /**
@@ -100,7 +169,7 @@ export interface DshWebIconIndicatorAggregate {
100
169
  */
101
170
  declare const plugin: {
102
171
  name: "dsh-web-icon-indicator";
103
- inject: readonly ["webServer", "timer", "agents", "fs", "sandboxPolicy"];
172
+ inject: readonly ["webServer", "timer", "agents", "fs"];
104
173
  config: DshWebIconIndicatorConfig;
105
174
  apply(ctx: unknown, config?: unknown): void;
106
175
  /** Settings namespace carrying the config (`web-icon-indicator`). */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-web-icon-indicator",
3
3
  "description": "Browser tab favicon reflects the DSH session state: idle / running / asking / done, recolored and animated from one base SVG in the browser (fully configurable colors + effects). · 浏览器标签页 favicon 实时反映 DSH 会话状态:待机 / 运行中 / 提问 / 完成,由单个 base.svg 在浏览器中动态上色与动画(颜色与特效完全可配置)。",
4
- "version": "0.4.2",
4
+ "version": "0.5.0",
5
5
  "type": "module",
6
6
  "engines": {
7
7
  "dsh": ">=0.1.2-rc.1"
@@ -13,7 +13,7 @@
13
13
  "type": "git",
14
14
  "url": "git+https://github.com/waknow/dsh-web-icon-indicator.git"
15
15
  },
16
- "homepage": "https://github.com/waknow/dsh-web-icon-indicator",
16
+ "homepage": "https://waknow.github.io/dsh-web-icon-indicator/",
17
17
  "bugs": {
18
18
  "url": "https://github.com/waknow/dsh-web-icon-indicator/issues"
19
19
  },
@@ -51,7 +51,7 @@
51
51
  "lib",
52
52
  "icons",
53
53
  "assets",
54
- "docs",
54
+ "test",
55
55
  "cordis.patch.yml",
56
56
  "screenshots.json",
57
57
  "CHANGELOG.md",
@@ -0,0 +1,21 @@
1
+ // Loader hooks that redirect the two @deepseek-ai peer imports of
2
+ // lib/index.js to local zero-dependency stubs (test/stubs), so test/verify.js
3
+ // can import and drive the REAL host plugin without a node_modules.
4
+ // Registered from test/verify.js via module.register before importing
5
+ // ../lib/index.js.
6
+ import { fileURLToPath, pathToFileURL } from "node:url";
7
+ import { dirname, join } from "node:path";
8
+
9
+ const here = dirname(fileURLToPath(import.meta.url));
10
+
11
+ const STUBS = {
12
+ "@deepseek-ai/schemastery": join(here, "stubs", "schemastery.mjs"),
13
+ "@deepseek-ai/dsh-settings": join(here, "stubs", "dsh-settings.mjs"),
14
+ };
15
+
16
+ export async function resolve(specifier, context, nextResolve) {
17
+ if (specifier in STUBS) {
18
+ return { url: pathToFileURL(STUBS[specifier]).href, shortCircuit: true };
19
+ }
20
+ return nextResolve(specifier, context);
21
+ }
@@ -0,0 +1,15 @@
1
+ // Zero-dependency stub for `@deepseek-ai/dsh-settings`, used only by
2
+ // test/loader-hooks.mjs. Captures the installSettingsSection args into
3
+ // globalThis so test/verify.js can assert the settings wiring and drive the
4
+ // captured setSource/onChange hooks.
5
+ export function settingsNamespace(name) {
6
+ return name;
7
+ }
8
+
9
+ export function installSettingsSection(ctx, ns, schema, entry, opts) {
10
+ const slot = (globalThis.__DSH_ICON_TEST__ ||= {});
11
+ slot.ns = ns;
12
+ slot.schema = schema;
13
+ slot.entry = entry;
14
+ slot.settingsOpts = opts;
15
+ }
@@ -0,0 +1,12 @@
1
+ // Zero-dependency stub for `@deepseek-ai/schemastery`, used only by
2
+ // test/loader-hooks.mjs so test/verify.js can import the REAL lib/index.js
3
+ // without resolving the actual peer dependency. Only the surface used at
4
+ // module top level (chainable z.object / z.array / z.string / z.number /
5
+ // z.union / z.dict with .default()) needs to not throw; CONFIG_SCHEMA is
6
+ // passed to the stubbed installSettingsSection and never validated.
7
+ const z = new Proxy(function schemasteryStub() {}, {
8
+ get: () => z,
9
+ apply: () => z,
10
+ });
11
+
12
+ export default z;