dsh-taskboard 0.4.3 → 0.4.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.
package/README.md CHANGED
@@ -213,6 +213,18 @@ node scripts/screenshot.mjs # 重新生成 img/ 截图(需本机 Edge)
213
213
 
214
214
  ## 升级日志
215
215
 
216
+ ### 0.4.5
217
+
218
+ - **移除 0.4.4 引入的「每 2 秒自动检查样式」机制**:上一版给样式表打的归属标记已经从根上解决了误删问题——其他插件更新时不会再删看板的样式,周期性检查只是多余的保险。现在去掉这个常驻的后台定时器,页面少一份轮询;防掉样式的效果不变(归属标记仍在,本插件自己热更新后也会重新挂回样式)
219
+ - 对使用者无任何可见变化,纯粹是内部做减法
220
+
221
+ ### 0.4.4
222
+
223
+ - **修复看板偶尔突然掉样式的问题([ #3](https://github.com/cloader/dsh-taskboard/issues/3))**。排查结论:浏览器里其他插件在后台热更新时,会按"样式归属"做清理,而看板自己的样式表没有归属标记,被误当成别的插件的样式连带删掉了。本次修复后:
224
+ - 看板的样式表明确打上了自己的归属标记,其他插件更新时不会再误删它
225
+ - 看板每 2 秒自动检查一次样式是否完好,即便被误删也会立刻自动恢复——以后遇到掉样式,最多闪一下就自动修好,不用再刷新页面
226
+ - 新增回归测试:样式归属标记生效、误删后 2 秒内自动恢复、样式不会重复注入
227
+
216
228
  ### 0.4.3
217
229
 
218
230
  - **修复折叠侧边栏时入口不收成纯图标(用户反馈)**:收起侧边栏后,shell 把侧栏收成 36×36 图标轨道(layout frame 出现 `data-sidebar-collapsed` 属性、侧栏根节点切换 CSS-Module `*_collapsed` 哈希类),而看板入口仍保持全宽——图标、「任务看板」文字、右侧计数角标挤在窄轨里。修复:折叠信号下入口镜像原生轨道几何(36×36、居中、与原生 newSession 折叠态同款间距),隐藏文字与角标,图标 14→16px 保证可读;双信号选择器(`[data-sidebar-collapsed]` 与 `[class*="_collapsed"]`)沿用 0.4.2 双选择器原则,新旧 shell 通吃;展开态完全不受影响,`aria-label` 保留无障碍提示
package/lib/client.js CHANGED
@@ -1586,15 +1586,46 @@ window.__ModuleLoader__.load({
1586
1586
  .dsh-atb-imp-result { font-size: 12px; color: var(--dsw-alias-state-success-primary, #30a46c); margin-top: 10px; }
1587
1587
  .dsh-atb-badge[data-kind="checklist"] { color: var(--dsw-alias-label-secondary, inherit); }
1588
1588
  `;
1589
- let injected = false;
1590
- /** Inject the stylesheet once (idempotent). */
1589
+ /** Style element id (stable since 0.1.x: hook for tests and debugging). */
1590
+ const STYLE_ID = "dsh-taskboard-styles";
1591
+ /**
1592
+ * Ownership tag for the shell's client-module bookkeeping. The web shell
1593
+ * claims every UNTAGGED `<style>` for whichever plugin module materializes
1594
+ * next (claimStyles in dsh-client-modules), and the client HMR driver
1595
+ * deletes `<style>` tags by this attribute on every rebuilt entry
1596
+ * (removeOwnedStyles in dsh-client-hmr).
1597
+ */
1598
+ const PLUGIN_ID = "dsh-taskboard";
1599
+ /** Per-stylesheet identity, mirroring the shell's own data-plugin-css. */
1600
+ const CSS_TAG = "dsh-taskboard/styles";
1601
+ /**
1602
+ * Ensure the stylesheet lives in <head>: create when absent, re-attach when
1603
+ * removed, always carry the ownership tags.
1604
+ *
1605
+ * 0.4.4 fix (field report: CSS randomly dropped, board renders as unstyled
1606
+ * HTML until refresh): injection runs from cordis apply(), which resolves
1607
+ * AFTER this module's materialization, so the old untagged <style> could be
1608
+ * claimed by ANY sibling plugin module that materialized later (observed
1609
+ * with lazily-materializing profile bundles). That sibling's next HMR
1610
+ * rebuild then deleted OUR stylesheet, and the old module-level `injected`
1611
+ * flag blocked re-injection until a full page refresh. Pre-tagging pins
1612
+ * ownership to this plugin: sibling claims skip tagged styles, and only
1613
+ * THIS plugin's rebuild removes it — the fresh apply re-injects. Idempotency
1614
+ * is DOM-based for the same reason: a module flag cannot see removals,
1615
+ * getElementById can. A found element is re-tagged too, so a leftover
1616
+ * pre-0.4.4 element adopted across a hot swap heals its ownership.
1617
+ */
1591
1618
  function injectStyles() {
1592
- if (injected || typeof document === "undefined") return;
1593
- const style = document.createElement("style");
1594
- style.id = "dsh-taskboard-styles";
1595
- style.textContent = STYLES;
1596
- document.head.append(style);
1597
- injected = true;
1619
+ if (typeof document === "undefined") return;
1620
+ let style = document.getElementById(STYLE_ID);
1621
+ if (style === null) {
1622
+ style = document.createElement("style");
1623
+ style.id = STYLE_ID;
1624
+ style.textContent = STYLES;
1625
+ document.head.append(style);
1626
+ }
1627
+ style.dataset.plugin = PLUGIN_ID;
1628
+ style.dataset.pluginCss = CSS_TAG;
1598
1629
  }
1599
1630
 
1600
1631
  //#endregion
@@ -1834,7 +1865,7 @@ window.__ModuleLoader__.load({
1834
1865
  * @module dsh-taskboard/shared/version
1835
1866
  */
1836
1867
  /** The package version (must equal package.json "version"). */
1837
- const PLUGIN_VERSION = "0.4.3";
1868
+ const PLUGIN_VERSION = "0.4.5";
1838
1869
 
1839
1870
  //#endregion
1840
1871
  //#region src/client/board/TaskCard.tsx
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-taskboard",
3
3
  "description": "Agent-first task board for the DSH web GUI: host-authoritative task ledger with taskboard_* agent tools, project (= workspace) claim boundaries, per-task model execution in fresh sessions, optional per-task git-worktree isolation (dedicated task branches, commit evidence, one-click merge), host-side cron scheduling, and a live SSE kanban view. Mounts via the official dsh plugin system — no DSH source changes.",
4
- "version": "0.4.3",
4
+ "version": "0.4.5",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "exports": {
@@ -104,6 +104,10 @@ export function apply(ctx: ClientContextFace): void {
104
104
  // cordis effect semantics: the callback runs immediately and its RETURN
105
105
  // VALUE is the disposer (family-plugin precedent: () => () => {...}).
106
106
  // A single-layer arrow here executes the teardown immediately.
107
+ // The stylesheet itself is NOT removed here: the HMR driver owns removal
108
+ // of tagged styles on this plugin's rebuild (and a self-removal could
109
+ // race a same-lifetime re-apply); its rules are dsh-atb-* scoped, so a
110
+ // leftover tag after a full disable is inert.
107
111
  ctx.effect?.(() => () => {
108
112
  for (const d of disposers.splice(0)) d()
109
113
  controller.dispose()
@@ -691,14 +691,47 @@ html[data-dsh-atb-active] .dsh-atb-view { display: flex; flex-direction: column;
691
691
  .dsh-atb-badge[data-kind="checklist"] { color: var(--dsw-alias-label-secondary, inherit); }
692
692
  `
693
693
 
694
- let injected = false
694
+ /** Style element id (stable since 0.1.x: hook for tests and debugging). */
695
+ const STYLE_ID = 'dsh-taskboard-styles'
695
696
 
696
- /** Inject the stylesheet once (idempotent). */
697
+ /**
698
+ * Ownership tag for the shell's client-module bookkeeping. The web shell
699
+ * claims every UNTAGGED `<style>` for whichever plugin module materializes
700
+ * next (claimStyles in dsh-client-modules), and the client HMR driver
701
+ * deletes `<style>` tags by this attribute on every rebuilt entry
702
+ * (removeOwnedStyles in dsh-client-hmr).
703
+ */
704
+ const PLUGIN_ID = 'dsh-taskboard'
705
+
706
+ /** Per-stylesheet identity, mirroring the shell's own data-plugin-css. */
707
+ const CSS_TAG = 'dsh-taskboard/styles'
708
+
709
+ /**
710
+ * Ensure the stylesheet lives in <head>: create when absent, re-attach when
711
+ * removed, always carry the ownership tags.
712
+ *
713
+ * 0.4.4 fix (field report: CSS randomly dropped, board renders as unstyled
714
+ * HTML until refresh): injection runs from cordis apply(), which resolves
715
+ * AFTER this module's materialization, so the old untagged <style> could be
716
+ * claimed by ANY sibling plugin module that materialized later (observed
717
+ * with lazily-materializing profile bundles). That sibling's next HMR
718
+ * rebuild then deleted OUR stylesheet, and the old module-level `injected`
719
+ * flag blocked re-injection until a full page refresh. Pre-tagging pins
720
+ * ownership to this plugin: sibling claims skip tagged styles, and only
721
+ * THIS plugin's rebuild removes it — the fresh apply re-injects. Idempotency
722
+ * is DOM-based for the same reason: a module flag cannot see removals,
723
+ * getElementById can. A found element is re-tagged too, so a leftover
724
+ * pre-0.4.4 element adopted across a hot swap heals its ownership.
725
+ */
697
726
  export function injectStyles(): void {
698
- if (injected || typeof document === 'undefined') return
699
- const style = document.createElement('style')
700
- style.id = 'dsh-taskboard-styles'
701
- style.textContent = STYLES
702
- document.head.append(style)
703
- injected = true
727
+ if (typeof document === 'undefined') return
728
+ let style = document.getElementById(STYLE_ID)
729
+ if (style === null) {
730
+ style = document.createElement('style')
731
+ style.id = STYLE_ID
732
+ style.textContent = STYLES
733
+ document.head.append(style)
734
+ }
735
+ style.dataset.plugin = PLUGIN_ID
736
+ style.dataset.pluginCss = CSS_TAG
704
737
  }
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  /** The package version (must equal package.json "version"). */
9
- export const PLUGIN_VERSION = '0.4.3'
9
+ export const PLUGIN_VERSION = '0.4.5'