@huaweidevtools/aishell-dsh-brand 0.0.1-beta.0 → 0.0.1-beta.1

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # @huaweidevtools/aishell-dsh-brand
2
2
 
3
- AI Shell brand reskin for DSH web. Replaces the default DeepSeek fish mark in the sidebar and blank-session hero with the AI Shell icon and wordmark.
3
+ AI Shell brand reskin for DSH web. Replaces the default DeepSeek fish mark in the sidebar and blank-session hero with the AI Shell icon and wordmark, and shadows the browser/window product title at runtime.
4
4
 
5
5
  ## How it works
6
6
 
@@ -14,6 +14,12 @@ All three are `kind: 'single'` slots, so this plugin replaces whatever occupied
14
14
 
15
15
  SVG assets are inlined as CSS `background-image` data URIs via lightningcss CSS Modules — no runtime fetch, no flash of missing image.
16
16
 
17
+ ## Window title shadow
18
+
19
+ The product title "DeepSeek Harness" is baked into the dsh tree at build time (`DSH_CLIENT_TITLE` → both the served `dsh-web-frontend/dist/index.html` and the ui-layout `DocumentTitle` component), and that tree is covered by the desktop-runtime digest — the asar shell-layer swap cannot reach it. The plugin therefore shadows the title at runtime (`src/client/title-shadow.ts`): an own `title` property on the document intercepts every write and rewrites the product name to "AI Shell" in flight, covering both the initial page title and the repeated writes `DocumentTitle` performs on each session/panel change. The Electron main process never calls `setTitle` on the main window, so the window title follows `document.title` and this single seam covers both.
20
+
21
+ Shadowing is a default, not a force: the effect's disposer removes the own property and restores the official title, so disabling the plugin returns the shell to its official behavior.
22
+
17
23
  ## Install
18
24
 
19
25
  ```sh
@@ -26,8 +32,9 @@ dsh plugin --profile <name> add @huaweidevtools/aishell-dsh-base
26
32
 
27
33
  ## What it does NOT touch
28
34
 
29
- - Navigation, settings, panels, conversation — only the three brand slots.
35
+ - Navigation, settings, panels, conversation — only the three brand slots and the product title.
30
36
  - DSH default plugins — no rows disabled.
37
+ - Session titles in the browser title — the part before the product name passes through unchanged.
31
38
 
32
39
  ## License
33
40
 
package/lib/client.js CHANGED
@@ -180,7 +180,7 @@ function AishellBrandName() {
180
180
  "aria-label": "AI Shell",
181
181
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
182
182
  className: brand_module_css_default.version,
183
- children: "0.0.1-beta.0"
183
+ children: "0.0.1-beta.1"
184
184
  })
185
185
  });
186
186
  }
@@ -231,6 +231,89 @@ function injectPoweredBy() {
231
231
  }
232
232
  injectPoweredBy();
233
233
 
234
+ //#endregion
235
+ //#region src/client/title-shadow.ts
236
+ /**
237
+ * Runtime window-title shadowing for the branded distribution.
238
+ *
239
+ * The official product title is baked into the dsh tree at build time
240
+ * (`DSH_CLIENT_TITLE` → "DeepSeek Harness" in both the served
241
+ * dsh-web-frontend dist index.html and the ui-layout DocumentTitle
242
+ * component), and that tree is covered by the desktop-runtime digest —
243
+ * the asar shell-layer swap cannot reach it. The plugin side therefore
244
+ * shadows the title at runtime: this module intercepts every
245
+ * `document.title` write in the renderer and rewrites the product name
246
+ * to "AI Shell" in flight. The Electron main process never calls
247
+ * setTitle on the main window, so the window title follows
248
+ * document.title and this single seam covers both.
249
+ *
250
+ * Shadowing is a default, not a force (plan §2.2): install() and the
251
+ * disposer it returns are symmetric, so disabling the plugin restores
252
+ * the official title behavior exactly.
253
+ *
254
+ * @module @huaweidevtools/aishell-dsh-brand/client
255
+ */
256
+ /** The official product title, baked into the digest-protected dsh tree. */
257
+ const OFFICIAL_TITLE = "DeepSeek Harness";
258
+ /** The branded product title that shadows it. */
259
+ const BRANDED_TITLE = "AI Shell";
260
+ /**
261
+ * Rewrite the product name inside a title write.
262
+ * Anything else in the value (the session-title prefix ui-layout adds)
263
+ * passes through untouched, and a value without the product name is
264
+ * returned as-is — the shadow never invents content.
265
+ */
266
+ function rebrandTitle(value) {
267
+ return value.split(OFFICIAL_TITLE).join(BRANDED_TITLE);
268
+ }
269
+ /**
270
+ * Find the `title` property descriptor on the prototype chain.
271
+ *
272
+ * `document.title` is a WebIDL accessor on Document.prototype — the
273
+ * instance itself has no own property to describe, so the descriptor
274
+ * must be located by walking up the chain.
275
+ */
276
+ function findTitleDescriptor(target) {
277
+ let proto = target;
278
+ while (proto !== null) {
279
+ const desc = Object.getOwnPropertyDescriptor(proto, "title");
280
+ if (desc !== void 0) return desc;
281
+ proto = Object.getPrototypeOf(proto);
282
+ }
283
+ return void 0;
284
+ }
285
+ /**
286
+ * Install the title shadow on the document.
287
+ *
288
+ * Defines an own `title` property on the instance (shadowing the
289
+ * prototype accessor) whose setter rewrites each write, then rewrites
290
+ * the current title once so the page's initial <title> from the served
291
+ * dist is covered too. Returns the disposer: it removes the own
292
+ * property (the prototype accessor takes over again) and rewrites the
293
+ * live value back to its official form, so an unload leaves the shell
294
+ * exactly as it was found.
295
+ */
296
+ function installTitleShadow(target) {
297
+ const original = findTitleDescriptor(target);
298
+ if (original === void 0 || original.configurable !== true || typeof original.set !== "function") return () => {};
299
+ const nativeSet = original.set;
300
+ const shadow = {
301
+ configurable: true,
302
+ enumerable: original.enumerable ?? false,
303
+ ...original.get !== void 0 ? { get: original.get } : {},
304
+ set(value) {
305
+ nativeSet.call(this, typeof value === "string" ? rebrandTitle(value) : value);
306
+ }
307
+ };
308
+ Object.defineProperty(target, "title", shadow);
309
+ const initial = target.title;
310
+ target.title = initial;
311
+ return () => {
312
+ delete target.title;
313
+ target.title = target.title.split(BRANDED_TITLE).join(OFFICIAL_TITLE);
314
+ };
315
+ }
316
+
234
317
  //#endregion
235
318
  //#region src/client/index.ts
236
319
  /** Required service: the UI slot registry. */
@@ -248,6 +331,7 @@ function apply(ctx) {
248
331
  name: "conversation.hero.brand.mark",
249
332
  priority: -1
250
333
  }, AishellHeroBrandMark));
334
+ if (typeof document !== "undefined") ctx.effect(() => installTitleShadow(document), "aishell-brand: window title shadow");
251
335
  }
252
336
 
253
337
  //#endregion
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Runtime window-title shadowing for the branded distribution.
3
+ *
4
+ * The official product title is baked into the dsh tree at build time
5
+ * (`DSH_CLIENT_TITLE` → "DeepSeek Harness" in both the served
6
+ * dsh-web-frontend dist index.html and the ui-layout DocumentTitle
7
+ * component), and that tree is covered by the desktop-runtime digest —
8
+ * the asar shell-layer swap cannot reach it. The plugin side therefore
9
+ * shadows the title at runtime: this module intercepts every
10
+ * `document.title` write in the renderer and rewrites the product name
11
+ * to "AI Shell" in flight. The Electron main process never calls
12
+ * setTitle on the main window, so the window title follows
13
+ * document.title and this single seam covers both.
14
+ *
15
+ * Shadowing is a default, not a force (plan §2.2): install() and the
16
+ * disposer it returns are symmetric, so disabling the plugin restores
17
+ * the official title behavior exactly.
18
+ *
19
+ * @module @huaweidevtools/aishell-dsh-brand/client
20
+ */
21
+ /**
22
+ * Rewrite the product name inside a title write.
23
+ * Anything else in the value (the session-title prefix ui-layout adds)
24
+ * passes through untouched, and a value without the product name is
25
+ * returned as-is — the shadow never invents content.
26
+ */
27
+ export declare function rebrandTitle(value: string): string;
28
+ /** The disposer restores the official title behavior; a no-op install returns this. */
29
+ export type TitleShadowDisposer = () => void;
30
+ /**
31
+ * Install the title shadow on the document.
32
+ *
33
+ * Defines an own `title` property on the instance (shadowing the
34
+ * prototype accessor) whose setter rewrites each write, then rewrites
35
+ * the current title once so the page's initial <title> from the served
36
+ * dist is covered too. Returns the disposer: it removes the own
37
+ * property (the prototype accessor takes over again) and rewrites the
38
+ * live value back to its official form, so an unload leaves the shell
39
+ * exactly as it was found.
40
+ */
41
+ export declare function installTitleShadow(target: Document): TitleShadowDisposer;
42
+ //# sourceMappingURL=title-shadow.d.ts.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@huaweidevtools/aishell-dsh-brand",
3
3
  "description": "AI Shell brand reskin for DSH web — replaces sidebar and hero brand marks with AI Shell SVG",
4
- "version": "0.0.1-beta.0",
4
+ "version": "0.0.1-beta.1",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },