@linxin666/dsh-client-ui-task-board 0.3.23 → 0.4.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 (37) hide show
  1. package/icon.svg +3 -0
  2. package/lib/client.js +351 -85
  3. package/lib/client.js.map +1 -1
  4. package/lib/index.js +174 -916
  5. package/lib/types/client/PluginSettingsCard.d.ts +4 -0
  6. package/lib/types/client/TaskBoardSettingsCard.d.ts +5 -5
  7. package/lib/types/client/board/TaskForm.d.ts +6 -1
  8. package/lib/types/client/board/parse-model-pref.d.ts +4 -0
  9. package/lib/types/client/index.d.ts +43 -10
  10. package/lib/types/client/locales.d.ts +1 -0
  11. package/lib/types/client/main-session.d.ts +32 -0
  12. package/lib/types/client/plugin-card-seat.d.ts +103 -0
  13. package/lib/types/client/settings-form.d.ts +17 -17
  14. package/lib/types/core/controller.d.ts +10 -8
  15. package/lib/types/core/session-reuse.d.ts +4 -2
  16. package/lib/types/host-ledger.d.ts +15 -0
  17. package/lib/types/http.d.ts +18 -1
  18. package/lib/types/index.d.ts +72 -17
  19. package/package.json +30 -24
  20. package/src/client/PluginSettingsCard.tsx +7 -2
  21. package/src/client/TaskBoardSettingsCard.tsx +7 -5
  22. package/src/client/board/NewTaskModal.tsx +33 -7
  23. package/src/client/board/TaskForm.tsx +13 -0
  24. package/src/client/board/parse-model-pref.ts +35 -0
  25. package/src/client/board.module.css +31 -12
  26. package/src/client/index.ts +121 -38
  27. package/src/client/locales.ts +2 -0
  28. package/src/client/main-session.ts +43 -0
  29. package/src/client/plugin-card-seat.ts +192 -0
  30. package/src/client/settings-form.ts +34 -31
  31. package/src/client/sidebar-entry-core.ts +3 -3
  32. package/src/client/sidebar-entry.ts +2 -2
  33. package/src/core/controller.ts +12 -8
  34. package/src/core/session-reuse.ts +14 -5
  35. package/src/host-ledger.ts +59 -11
  36. package/src/http.ts +23 -1
  37. package/src/index.ts +97 -52
package/lib/client.js CHANGED
@@ -609,7 +609,7 @@ window.__ModuleLoader__.load({
609
609
  //#endregion
610
610
  //#region src/core/controller.ts
611
611
  function currentOf(sessions) {
612
- return sessions?.list.getSnapshot().current;
612
+ return sessions?.current();
613
613
  }
614
614
  /** The selected task (resolved from the ledger), or undefined. */
615
615
  function selectedTaskOf(snapshot) {
@@ -670,7 +670,7 @@ window.__ModuleLoader__.load({
670
670
  this.notify();
671
671
  }) : void 0;
672
672
  if (unsubscribeExternal !== void 0) this.disposers.push(unsubscribeExternal);
673
- this.disposers.push(this.deps.sessions.list.subscribe(() => {
673
+ this.disposers.push(this.deps.sessions.subscribe(() => {
674
674
  this.onSessionsChanged();
675
675
  }));
676
676
  this.notify();
@@ -1100,6 +1100,21 @@ window.__ModuleLoader__.load({
1100
1100
  for (const fn of [...this.listeners]) fn();
1101
1101
  }
1102
1102
  };
1103
+ //#endregion
1104
+ //#region src/client/main-session.ts
1105
+ /**
1106
+ * Resolve the Session the main view currently shows.
1107
+ *
1108
+ * Reads the catalog's rows rather than a per-id retain-info source: ownership
1109
+ * counts ride the list snapshot, so this neither allocates observers nor opens
1110
+ * history, and a subscription to the list still fires when the selection moves.
1111
+ * @param byId - the session catalog's rows (`SessionListState.byId`), when available.
1112
+ * @returns the main-view session id, or undefined when the main view shows none.
1113
+ */
1114
+ function mainViewSessionId(byId) {
1115
+ if (byId === void 0 || byId === null) return void 0;
1116
+ for (const row of Object.values(byId)) if (row !== void 0 && (row.retainedBy?.mainView ?? 0) > 0) return row.id;
1117
+ }
1103
1118
  /** Marker replacing every sensitive match. */
1104
1119
  const REDACTED_MARKER = "[REDACTED]";
1105
1120
  const BEGIN = "<<<FREEZE";
@@ -1636,6 +1651,7 @@ window.__ModuleLoader__.load({
1636
1651
  "new.prompt": "执行 Prompt",
1637
1652
  "new.promptPlaceholder": "发给 agent 的完整指令(留空则使用标题)",
1638
1653
  "new.submit": "创建",
1654
+ "new.createAndRun": "创建并执行",
1639
1655
  "new.cancel": "取消",
1640
1656
  "new.required": "标题不能为空",
1641
1657
  "new.freeze": "冻结快照(可选)",
@@ -1824,6 +1840,7 @@ window.__ModuleLoader__.load({
1824
1840
  "new.prompt": "Run Prompt",
1825
1841
  "new.promptPlaceholder": "The full instruction sent to the agent (title is used when blank)",
1826
1842
  "new.submit": "Create",
1843
+ "new.createAndRun": "Create and run",
1827
1844
  "new.cancel": "Cancel",
1828
1845
  "new.required": "Title is required",
1829
1846
  "new.freeze": "Frozen snapshot (optional)",
@@ -1980,7 +1997,7 @@ window.__ModuleLoader__.load({
1980
1997
  }
1981
1998
  //#endregion
1982
1999
  //#region \0dsh-css:packages/dsh-task-board/src/client/board.module.css.mjs
1983
- const css$1 = "[data-pane=conversation],[class*=centerCol]{position:relative}[data-dsh-taskboard-view]{z-index:60;background:var(--dsw-alias-bg-base);display:none;position:absolute;inset:0;container:_7D6uKa_task-board-view/inline-size}html[data-dsh-taskboard-active]:not([data-dsh-ssh-active]) [data-dsh-taskboard-view]{display:block}html[data-dsh-taskboard-active]:not([data-dsh-ssh-active]) [data-pane=conversation]>:not([data-dsh-taskboard-view]),html[data-dsh-taskboard-active]:not([data-dsh-ssh-active]) [class*=centerCol]>:not([data-dsh-taskboard-view]){display:none!important}._7D6uKa_entry{box-sizing:border-box;width:100%;height:36px;color:var(--dsw-alias-label-secondary);cursor:pointer;white-space:nowrap;background:0 0;border:none;border-radius:8px;align-items:center;gap:8px;padding:0 10px;font-size:13px;display:flex}._7D6uKa_entry:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}._7D6uKa_entry[data-active]{background:var(--dsw-alias-interactive-bg-active);color:var(--dsw-alias-label-primary);font-weight:600}._7D6uKa_entryIcon{flex:none;justify-content:center;align-items:center;width:24px;height:24px;display:inline-flex}._7D6uKa_entryIcon svg{width:18px;height:18px;display:block}._7D6uKa_entryLabel{text-overflow:ellipsis;overflow:hidden}[data-dsh-frame][data-sidebar-collapsed] ._7D6uKa_entry,[data-sidebar-collapsed] ._7D6uKa_entry{border-radius:50%;justify-content:center;width:36px;height:36px;margin:0 auto 12px;padding:0}[data-dsh-frame][data-sidebar-collapsed] ._7D6uKa_entryLabel,[data-sidebar-collapsed] ._7D6uKa_entryLabel{display:none}._7D6uKa_board{box-sizing:border-box;background:var(--dsw-alias-bg-base);min-width:0;height:100%;min-height:0;color:var(--dsw-alias-label-primary);font-family:var(--dsw-font-family);flex-direction:column;gap:12px;padding:14px 16px 16px;display:flex}._7D6uKa_boardHeader{flex:none;align-items:center;gap:10px;display:flex}._7D6uKa_boardTitle{color:var(--dsw-alias-label-primary);white-space:nowrap;margin:0;font-size:16px;font-weight:700}._7D6uKa_backButton{align-items:center;gap:4px;display:inline-flex}._7D6uKa_search{min-width:120px;color:var(--dsw-alias-label-primary);background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;outline:none;flex:0 260px;padding:6px 10px;font-size:13px}._7D6uKa_search::placeholder{color:var(--dsw-alias-label-tertiary)}._7D6uKa_columns{overscroll-behavior-inline:contain;scrollbar-color:var(--dsw-alias-border-l3) var(--dsw-alias-interactive-bg-hover);scrollbar-width:thin;flex:1;grid-auto-columns:minmax(220px,1fr);grid-auto-flow:column;gap:12px;min-height:0;padding-bottom:6px;display:grid;overflow:auto hidden}._7D6uKa_columns::-webkit-scrollbar{height:10px}._7D6uKa_columns::-webkit-scrollbar-track{background:var(--dsw-alias-interactive-bg-hover);border-radius:999px}._7D6uKa_columns::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l3);background-clip:content-box;border:2px solid #0000;border-radius:999px}._7D6uKa_columns::-webkit-scrollbar-thumb:hover{background:var(--dsw-alias-border-l4);background-clip:content-box}._7D6uKa_column{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:12px;flex-direction:column;min-height:0;display:flex;overflow:hidden}._7D6uKa_columnHeader{flex:none;align-items:center;gap:6px;padding:10px 12px;display:flex}._7D6uKa_columnTitle{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;flex:1;margin:0;font-size:13px;font-weight:700;overflow:hidden}._7D6uKa_columnCount{min-width:0;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-interactive-bg-hover);border-radius:999px;flex:none;padding:1px 8px;font-size:12px}._7D6uKa_statusDot{border-radius:50%;flex:none;width:8px;height:8px}._7D6uKa_statusDot[data-status=backlog]{background:var(--dsw-alias-label-tertiary)}._7D6uKa_statusDot[data-status=todo]{background:var(--dsw-alias-state-business-primary)}._7D6uKa_statusDot[data-status=running]{background:var(--dsw-alias-state-warn-primary)}._7D6uKa_statusDot[data-status=done]{background:var(--dsw-alias-state-success-primary)}._7D6uKa_statusDot[data-status=failed]{background:var(--dsw-alias-state-error-primary)}._7D6uKa_cards{flex-direction:column;flex:1;gap:8px;min-height:0;padding:2px 8px 10px;display:flex;overflow-y:auto}._7D6uKa_columnEmpty{text-align:center;color:var(--dsw-alias-label-tertiary);padding:24px 8px;font-size:12px}._7D6uKa_card{text-align:left;background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;color:var(--dsw-alias-label-primary);border-radius:10px;flex-direction:column;gap:6px;padding:10px 12px;font-family:inherit;transition:box-shadow .12s,border-color .12s,transform .12s;display:flex}._7D6uKa_card:hover{box-shadow:var(--dsw-shadow-lv2);border-color:var(--dsw-alias-border-l3);transform:translateY(-1px)}._7D6uKa_card[data-status=running]{border-color:var(--dsw-alias-state-warn-primary)}._7D6uKa_cardTitle{-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:13px;font-weight:600;line-height:1.35;display:-webkit-box;overflow:hidden}._7D6uKa_cardExcerpt{color:var(--dsw-alias-label-secondary);-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:12px;line-height:1.4;display:-webkit-box;overflow:hidden}._7D6uKa_cardMeta{color:var(--dsw-alias-label-tertiary);align-items:center;gap:8px;font-size:11px;display:flex}._7D6uKa_cardTime{text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}._7D6uKa_cardSchedule{white-space:nowrap;min-width:0;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-interactive-bg-hover);border-radius:999px;flex:none;padding:2px 6px;font-size:12px;line-height:1}._7D6uKa_cardRun{flex:none}._7D6uKa_cardRun[data-result=failed]{color:var(--dsw-alias-state-error-primary)}._7D6uKa_cardRun[data-result=succeeded]{color:var(--dsw-alias-state-success-primary)}._7D6uKa_cardSession{color:var(--dsw-alias-state-business-primary);flex:none}._7D6uKa_cardRunningLabel{color:var(--dsw-alias-state-warn-primary);font-size:11px}._7D6uKa_cardSpinner{border:2px solid var(--dsw-alias-state-warn-primary);border-top-color:#0000;border-radius:50%;flex:none;width:10px;height:10px;animation:.8s linear infinite _7D6uKa_dshTbSpin}@keyframes _7D6uKa_dshTbSpin{to{transform:rotate(360deg)}}._7D6uKa_primaryButton{color:var(--dsw-alias-label-primary-foreground);background:var(--dsw-alias-button-info-fill);cursor:pointer;white-space:nowrap;border:none;border-radius:8px;padding:6px 14px;font-size:13px;font-weight:600}._7D6uKa_primaryButton:hover:not(:disabled){background:var(--dsw-alias-button-info-hover)}._7D6uKa_primaryButton:disabled{opacity:.5;cursor:default}._7D6uKa_ghostButton{color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;white-space:nowrap;background:0 0;border-radius:8px;padding:5px 12px;font-size:12px}._7D6uKa_ghostButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}._7D6uKa_ghostButton:disabled{opacity:.45;cursor:default}._7D6uKa_dangerButton{color:#fff;background:var(--dsw-alias-state-error-primary);cursor:pointer;white-space:nowrap;border:none;border-radius:8px;padding:6px 14px;font-size:13px;font-weight:600}._7D6uKa_dangerButton:hover:not(:disabled){filter:brightness(1.08)}._7D6uKa_dangerButton:active:not(:disabled){filter:brightness(.94)}._7D6uKa_dangerButton:disabled{opacity:.5;cursor:default}._7D6uKa_iconButton{width:26px;height:26px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;padding:0;font-size:13px;display:inline-flex}._7D6uKa_iconButton:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}._7D6uKa_linkButton{color:var(--dsw-alias-state-business-primary);cursor:pointer;white-space:nowrap;background:0 0;border:none;padding:0;font-size:12px}._7D6uKa_linkButton:hover{text-decoration:underline}._7D6uKa_modalBackdrop{z-index:1300;background:var(--dsw-alias-bg-mask-1);justify-content:center;align-items:center;display:flex;position:fixed;inset:0}._7D6uKa_modal{background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);width:min(520px,100vw - 48px);max-height:calc(100vh - 96px);box-shadow:var(--dsw-shadow-lv3);color:var(--dsw-alias-label-primary);border-radius:14px;flex-direction:column;gap:12px;padding:18px;display:flex;overflow-y:auto}._7D6uKa_modalTitle{margin:0;font-size:15px;font-weight:700}._7D6uKa_confirmMessage{color:var(--dsw-alias-label-secondary);white-space:pre-wrap;overflow-wrap:anywhere;margin:0;font-size:13px;line-height:1.5}._7D6uKa_modalFooter{justify-content:flex-end;gap:10px;margin-top:4px;display:flex}._7D6uKa_field{flex-direction:column;gap:5px;display:flex}._7D6uKa_fieldLabel{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:600}._7D6uKa_input{color:var(--dsw-alias-label-primary);background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);resize:vertical;border-radius:8px;outline:none;padding:7px 10px;font-family:inherit;font-size:13px}._7D6uKa_input:focus{border-color:var(--dsw-alias-state-business-primary)}._7D6uKa_select{color:var(--dsw-alias-label-primary);background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;outline:none;max-width:100%;padding:7px 10px;font-family:inherit;font-size:13px}._7D6uKa_input::placeholder{color:var(--dsw-alias-label-tertiary)}._7D6uKa_formError{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px}._7D6uKa_detail{background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);width:min(640px,100vw - 48px);max-height:calc(100vh - 80px);box-shadow:var(--dsw-shadow-lv3);color:var(--dsw-alias-label-primary);border-radius:14px;flex-direction:column;display:flex;overflow:hidden}._7D6uKa_detailHeader{border-bottom:1px solid var(--dsw-alias-separator-primary);flex:none;align-items:center;gap:10px;padding:14px 18px;display:flex}._7D6uKa_detailTitle{overflow-wrap:anywhere;flex:1;margin:0;font-size:15px;font-weight:700}._7D6uKa_statusBadge{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:2px 10px;font-size:12px}._7D6uKa_statusBadge[data-status=running]{color:var(--dsw-alias-state-warn-primary);border-color:var(--dsw-alias-state-warn-primary)}._7D6uKa_statusBadge[data-status=done]{color:var(--dsw-alias-state-success-primary);border-color:var(--dsw-alias-state-success-primary)}._7D6uKa_statusBadge[data-status=failed]{color:var(--dsw-alias-state-error-primary);border-color:var(--dsw-alias-state-error-primary)}._7D6uKa_detailBody{flex-direction:column;flex:1;gap:16px;padding:14px 18px;display:flex;overflow-y:auto}._7D6uKa_detailSection{flex-direction:column;gap:6px;display:flex}._7D6uKa_detailSection h4{color:var(--dsw-alias-label-tertiary);text-transform:none;margin:0;font-size:12px;font-weight:700}._7D6uKa_detailText{color:var(--dsw-alias-label-primary);white-space:pre-wrap;overflow-wrap:anywhere;margin:0;font-size:13px;line-height:1.55}._7D6uKa_scheduleToggle{color:var(--dsw-alias-label-primary);cursor:pointer;user-select:none;align-items:center;gap:8px;font-size:13px;display:flex}._7D6uKa_scheduleToggle input{accent-color:var(--dsw-alias-state-business-primary)}._7D6uKa_scheduleRow{align-items:center;gap:8px;display:flex}._7D6uKa_scheduleInput{min-width:0;font-family:var(--dsw-font-markdown-code-block-small);flex:1;font-size:12.5px}._7D6uKa_scheduleInputInvalid,._7D6uKa_scheduleInputInvalid:focus{border-color:var(--dsw-alias-state-error-primary)}._7D6uKa_schedulePreset{color:var(--dsw-alias-label-primary);background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;outline:none;flex:none;padding:7px 8px;font-size:12.5px}._7D6uKa_scheduleMeta{color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere;margin:0;font-size:12px}._7D6uKa_promptBlock{font-size:12.5px;line-height:1.5;font-family:var(--dsw-font-markdown-code-block-small);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-markdown-code-block);border:1px solid var(--dsw-alias-border-l1);white-space:pre-wrap;overflow-wrap:anywhere;border-radius:8px;max-height:240px;margin:0;padding:10px 12px;overflow-y:auto}._7D6uKa_executionList{flex-direction:column;gap:8px;margin:0;padding:0;list-style:none;display:flex}._7D6uKa_executionRow{border:1px solid var(--dsw-alias-border-l1);border-radius:8px;flex-wrap:wrap;align-items:center;gap:10px;padding:8px 10px;display:flex}._7D6uKa_executionBadge{color:var(--dsw-alias-state-warn-primary);background:var(--dsw-alias-state-warn-secondary);border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:600}._7D6uKa_executionBadge[data-result=succeeded]{color:var(--dsw-alias-state-success-primary);background:0 0}._7D6uKa_executionBadge[data-result=failed]{color:var(--dsw-alias-state-error-primary);background:0 0}._7D6uKa_executionBadge[data-result=cancelled]{color:var(--dsw-alias-label-tertiary);background:0 0}._7D6uKa_executionTimes{color:var(--dsw-alias-label-secondary);font-size:12px}._7D6uKa_executionError{width:100%;color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere;font-size:12px}._7D6uKa_moveRow{flex-wrap:wrap;gap:8px;display:flex}._7D6uKa_detailFooter{border-top:1px solid var(--dsw-alias-separator-primary);flex:none;align-items:center;gap:10px;padding:12px 18px;display:flex}._7D6uKa_detailMeta{color:var(--dsw-alias-label-tertiary);margin-left:auto;font-size:11px}@container _7D6uKa_task-board-view (width<=768px){._7D6uKa_board{gap:10px;padding:10px}._7D6uKa_boardHeader{flex-wrap:wrap;align-items:center;gap:8px}._7D6uKa_backButton{flex:none;order:1}._7D6uKa_boardTitle{flex:auto;order:2}._7D6uKa_boardHeader>._7D6uKa_detailMeta{flex:1 0 100%;order:3;margin-left:0}._7D6uKa_search{flex:1 0 100%;order:4;min-width:0}._7D6uKa_boardHeader>button:not(._7D6uKa_backButton){flex:1 1 0;order:5;min-width:0}._7D6uKa_columns{scroll-snap-type:inline mandatory;scrollbar-width:none;-webkit-overflow-scrolling:touch;grid-auto-columns:86cqw;gap:10px;padding-inline:2px 14cqw;scroll-padding-inline:2px}._7D6uKa_columns::-webkit-scrollbar{display:none}._7D6uKa_column{scroll-snap-align:start;scroll-snap-stop:always}}@container _7D6uKa_task-board-view (width<=720px){._7D6uKa_boardHeader>._7D6uKa_detailMeta{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}}@container _7D6uKa_task-board-view (width<=600px){._7D6uKa_board{padding-inline:8px}}@media (width<=768px){[data-dsh-taskboard-view]{height:100dvh}._7D6uKa_entry,._7D6uKa_card,._7D6uKa_primaryButton,._7D6uKa_ghostButton,._7D6uKa_dangerButton,._7D6uKa_iconButton,._7D6uKa_linkButton,._7D6uKa_search,._7D6uKa_input,._7D6uKa_select,._7D6uKa_schedulePreset,._7D6uKa_scheduleToggle{min-height:44px}._7D6uKa_search,._7D6uKa_input,._7D6uKa_select,._7D6uKa_schedulePreset{box-sizing:border-box;font-size:16px}._7D6uKa_modalBackdrop{justify-content:stretch;align-items:stretch;width:100vw;height:100dvh}._7D6uKa_modal,._7D6uKa_detail{box-sizing:border-box;border:0;border-radius:0;width:100vw;height:100dvh;max-height:none}._7D6uKa_modal{padding-top:max(16px, env(safe-area-inset-top));padding-right:max(16px, env(safe-area-inset-right));padding-bottom:max(16px, env(safe-area-inset-bottom));padding-left:max(16px, env(safe-area-inset-left))}._7D6uKa_modalFooter{z-index:1;background:var(--dsw-alias-bg-base);flex-wrap:wrap;padding-top:8px;position:sticky;bottom:0}._7D6uKa_modalFooter>button{flex:120px}._7D6uKa_detailHeader{padding-top:max(12px, env(safe-area-inset-top));padding-right:max(14px, env(safe-area-inset-right));padding-left:max(14px, env(safe-area-inset-left));flex-wrap:wrap}._7D6uKa_detailTitle{min-width:0}._7D6uKa_detailBody{overscroll-behavior-y:contain;padding-right:max(14px, env(safe-area-inset-right));padding-left:max(14px, env(safe-area-inset-left))}._7D6uKa_detailFooter{padding-right:max(14px, env(safe-area-inset-right));padding-bottom:max(12px, env(safe-area-inset-bottom));padding-left:max(14px, env(safe-area-inset-left));flex-wrap:wrap}._7D6uKa_detailFooter>button{flex:96px}._7D6uKa_detailFooter>._7D6uKa_detailMeta{text-align:end;flex:1 0 100%;margin-left:0}._7D6uKa_scheduleRow{flex-direction:column;align-items:stretch}._7D6uKa_schedulePreset{width:100%}}._7D6uKa_entry:focus-visible,._7D6uKa_card:focus-visible,._7D6uKa_primaryButton:focus-visible,._7D6uKa_ghostButton:focus-visible,._7D6uKa_dangerButton:focus-visible,._7D6uKa_iconButton:focus-visible,._7D6uKa_linkButton:focus-visible,._7D6uKa_search:focus-visible,._7D6uKa_input:focus-visible,._7D6uKa_select:focus-visible,._7D6uKa_schedulePreset:focus-visible,._7D6uKa_scheduleToggle input:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}._7D6uKa_entry,._7D6uKa_primaryButton,._7D6uKa_ghostButton,._7D6uKa_dangerButton,._7D6uKa_iconButton,._7D6uKa_linkButton,._7D6uKa_search,._7D6uKa_input,._7D6uKa_select,._7D6uKa_schedulePreset,._7D6uKa_scheduleToggle input{transition:background-color .12s,color .12s,border-color .12s,outline-color .12s,box-shadow .12s,transform .12s}._7D6uKa_card:active{box-shadow:var(--dsw-shadow-lv1);transform:translateY(0)}._7D6uKa_entry:active,._7D6uKa_primaryButton:active:not(:disabled),._7D6uKa_ghostButton:active:not(:disabled),._7D6uKa_dangerButton:active:not(:disabled),._7D6uKa_iconButton:active:not(:disabled),._7D6uKa_linkButton:active:not(:disabled){transform:translateY(1px)}._7D6uKa_entry[data-active]:hover{background:var(--dsw-specific-sidebar-nav-item-active)}._7D6uKa_iconButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}._7D6uKa_linkButton:hover:not(:disabled){text-decoration:underline}._7D6uKa_iconButton:disabled,._7D6uKa_linkButton:disabled{opacity:.45;cursor:default}._7D6uKa_search:focus,._7D6uKa_select:focus,._7D6uKa_schedulePreset:focus{border-color:var(--dsw-alias-state-business-primary)}._7D6uKa_scheduleToggle input{margin:0}@media (prefers-reduced-motion:reduce){._7D6uKa_entry,._7D6uKa_card,._7D6uKa_primaryButton,._7D6uKa_ghostButton,._7D6uKa_dangerButton,._7D6uKa_iconButton,._7D6uKa_linkButton,._7D6uKa_search,._7D6uKa_input,._7D6uKa_select,._7D6uKa_schedulePreset,._7D6uKa_scheduleToggle input{transition:none}._7D6uKa_cardSpinner{animation:none}}._7D6uKa_cardTags{flex-wrap:wrap;gap:4px;display:flex}._7D6uKa_cardTag{border:1px solid var(--dsh-task-tag-border);background:var(--dsh-task-tag-fill);max-width:100%;color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;border-radius:999px;padding:0 7px;font-size:10px;line-height:16px;overflow:hidden}._7D6uKa_tagFilter{flex-wrap:wrap;align-items:center;gap:6px;margin:0 0 10px;display:flex}._7D6uKa_tagFilterLabel{color:var(--dsw-alias-label-tertiary);font-size:11px}._7D6uKa_tagChip{border:1px solid var(--dsh-task-tag-border);color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border-radius:999px;padding:1px 9px;font-family:inherit;font-size:11px;line-height:18px}._7D6uKa_tagChip[data-active=true]{background:var(--dsh-task-tag-fill);color:var(--dsw-alias-label-primary)}._7D6uKa_cardTag[data-tag-tone=\"0\"],._7D6uKa_tagChip[data-tag-tone=\"0\"]{--dsh-task-tag-fill:#4e93e82e;--dsh-task-tag-border:#4e93e866}._7D6uKa_cardTag[data-tag-tone=\"1\"],._7D6uKa_tagChip[data-tag-tone=\"1\"]{--dsh-task-tag-fill:#2ea36a2e;--dsh-task-tag-border:#2ea36a66}._7D6uKa_cardTag[data-tag-tone=\"2\"],._7D6uKa_tagChip[data-tag-tone=\"2\"]{--dsh-task-tag-fill:#d08a2a2e;--dsh-task-tag-border:#d08a2a66}._7D6uKa_cardTag[data-tag-tone=\"3\"],._7D6uKa_tagChip[data-tag-tone=\"3\"]{--dsh-task-tag-fill:#b456c82e;--dsh-task-tag-border:#b456c866}._7D6uKa_cardTag[data-tag-tone=\"4\"],._7D6uKa_tagChip[data-tag-tone=\"4\"]{--dsh-task-tag-fill:#cf5f7a2e;--dsh-task-tag-border:#cf5f7a66}._7D6uKa_cardTag[data-tag-tone=\"5\"],._7D6uKa_tagChip[data-tag-tone=\"5\"]{--dsh-task-tag-fill:#4a9fb52e;--dsh-task-tag-border:#4a9fb566}._7D6uKa_fieldHint{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.4}._7D6uKa_tagRow{align-items:center;gap:6px;display:flex}._7D6uKa_tagRow ._7D6uKa_input{flex:1 1 0;min-width:0}._7D6uKa_tagRow ._7D6uKa_ghostButton{flex:none}._7D6uKa_tagAddButton{align-self:flex-start}._7D6uKa_projectFilter{flex:none;align-items:center;gap:6px;display:flex}._7D6uKa_projectFilterLabel{color:var(--dsw-alias-label-secondary);white-space:nowrap;font-size:12px}._7D6uKa_projectDialog{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:10px;flex-direction:column;flex:none;gap:8px;margin-bottom:8px;padding:10px 12px;display:flex}._7D6uKa_projectDialogActions{justify-content:flex-end;gap:8px;display:flex}._7D6uKa_aiParse{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:10px;flex-direction:column;gap:6px;padding:10px 12px;display:flex}._7D6uKa_aiParseRow{align-items:center;gap:8px;display:flex}._7D6uKa_aiParseRow ._7D6uKa_select{flex:1 1 0;min-width:0}._7D6uKa_aiParseRow ._7D6uKa_ghostButton,._7D6uKa_aiParseRow ._7D6uKa_primaryButton{flex:none}";
2000
+ const css$1 = "[data-pane=conversation],[class*=centerCol]{position:relative}[data-dsh-taskboard-view]{z-index:60;background:var(--dsw-alias-bg-base);display:none;position:absolute;inset:0;container:_7D6uKa_task-board-view/inline-size}html[data-dsh-taskboard-active]:not([data-dsh-ssh-active]) [data-dsh-taskboard-view]{display:block}html[data-dsh-taskboard-active]:not([data-dsh-ssh-active]) [data-pane=conversation]>:not([data-dsh-taskboard-view]),html[data-dsh-taskboard-active]:not([data-dsh-ssh-active]) [class*=centerCol]>:not([data-dsh-taskboard-view]){display:none!important}._7D6uKa_entry{box-sizing:border-box;min-height:36px;color:var(--dsw-alias-label-primary);cursor:pointer;font:inherit;text-align:left;white-space:nowrap;background:0 0;border:none;border-radius:12px;align-items:center;gap:8px;margin:0 2px;padding:7px 8px;font-size:14px;line-height:22px;display:flex}._7D6uKa_entry:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}._7D6uKa_entry[data-active]{background:var(--dsw-alias-interactive-bg-active);color:var(--dsw-alias-label-primary);font-weight:600}._7D6uKa_entryIcon{flex:none;justify-content:center;align-items:center;width:16px;height:16px;display:inline-flex}._7D6uKa_entryIcon svg{width:16px;height:16px;display:block}._7D6uKa_entryLabel{text-overflow:ellipsis;overflow:hidden}[data-dsh-frame][data-sidebar-collapsed] ._7D6uKa_entry,[data-sidebar-collapsed] ._7D6uKa_entry{border-radius:12px;justify-content:center;width:36px;height:36px;margin:0 auto 12px;padding:0}[data-dsh-frame][data-sidebar-collapsed] ._7D6uKa_entryIcon,[data-sidebar-collapsed] ._7D6uKa_entryIcon,[data-dsh-frame][data-sidebar-collapsed] ._7D6uKa_entryIcon svg,[data-sidebar-collapsed] ._7D6uKa_entryIcon svg{width:18px;height:18px}[data-dsh-frame][data-sidebar-collapsed] ._7D6uKa_entryLabel,[data-sidebar-collapsed] ._7D6uKa_entryLabel{display:none}._7D6uKa_board{box-sizing:border-box;background:var(--dsw-alias-bg-base);min-width:0;height:100%;min-height:0;color:var(--dsw-alias-label-primary);font-family:var(--dsw-font-family);flex-direction:column;gap:12px;padding:14px 16px 16px;display:flex}._7D6uKa_boardHeader{flex:none;align-items:center;gap:10px;display:flex}._7D6uKa_boardTitle{color:var(--dsw-alias-label-primary);white-space:nowrap;margin:0;font-size:16px;font-weight:700}._7D6uKa_backButton{align-items:center;gap:4px;display:inline-flex}._7D6uKa_search{min-width:120px;color:var(--dsw-alias-label-primary);background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;outline:none;flex:0 260px;padding:6px 10px;font-size:13px}._7D6uKa_search::placeholder{color:var(--dsw-alias-label-tertiary)}._7D6uKa_columns{overscroll-behavior-inline:contain;scrollbar-color:var(--dsw-alias-border-l3) var(--dsw-alias-interactive-bg-hover);scrollbar-width:thin;flex:1;grid-auto-columns:minmax(220px,1fr);grid-auto-flow:column;gap:12px;min-height:0;padding-bottom:6px;display:grid;overflow:auto hidden}._7D6uKa_columns::-webkit-scrollbar{height:10px}._7D6uKa_columns::-webkit-scrollbar-track{background:var(--dsw-alias-interactive-bg-hover);border-radius:999px}._7D6uKa_columns::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l3);background-clip:content-box;border:2px solid #0000;border-radius:999px}._7D6uKa_columns::-webkit-scrollbar-thumb:hover{background:var(--dsw-alias-border-l4);background-clip:content-box}._7D6uKa_column{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:12px;flex-direction:column;min-height:0;display:flex;overflow:hidden}._7D6uKa_columnHeader{flex:none;align-items:center;gap:6px;padding:10px 12px;display:flex}._7D6uKa_columnTitle{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;flex:1;margin:0;font-size:13px;font-weight:700;overflow:hidden}._7D6uKa_columnCount{min-width:0;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-interactive-bg-hover);border-radius:999px;flex:none;padding:1px 8px;font-size:12px}._7D6uKa_statusDot{border-radius:50%;flex:none;width:8px;height:8px}._7D6uKa_statusDot[data-status=backlog]{background:var(--dsw-alias-label-tertiary)}._7D6uKa_statusDot[data-status=todo]{background:var(--dsw-alias-state-business-primary)}._7D6uKa_statusDot[data-status=running]{background:var(--dsw-alias-state-warn-primary)}._7D6uKa_statusDot[data-status=done]{background:var(--dsw-alias-state-success-primary)}._7D6uKa_statusDot[data-status=failed]{background:var(--dsw-alias-state-error-primary)}._7D6uKa_cards{flex-direction:column;flex:1;gap:8px;min-height:0;padding:2px 8px 10px;display:flex;overflow-y:auto}._7D6uKa_columnEmpty{text-align:center;color:var(--dsw-alias-label-tertiary);padding:24px 8px;font-size:12px}._7D6uKa_card{text-align:left;background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;color:var(--dsw-alias-label-primary);border-radius:10px;flex-direction:column;gap:6px;padding:10px 12px;font-family:inherit;transition:box-shadow .12s,border-color .12s,transform .12s;display:flex}._7D6uKa_card:hover{box-shadow:var(--dsw-shadow-lv2);border-color:var(--dsw-alias-border-l3);transform:translateY(-1px)}._7D6uKa_card[data-status=running]{border-color:var(--dsw-alias-state-warn-primary)}._7D6uKa_cardTitle{-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:13px;font-weight:600;line-height:1.35;display:-webkit-box;overflow:hidden}._7D6uKa_cardExcerpt{color:var(--dsw-alias-label-secondary);-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:12px;line-height:1.4;display:-webkit-box;overflow:hidden}._7D6uKa_cardMeta{color:var(--dsw-alias-label-tertiary);align-items:center;gap:8px;font-size:11px;display:flex}._7D6uKa_cardTime{text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}._7D6uKa_cardSchedule{white-space:nowrap;min-width:0;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-interactive-bg-hover);border-radius:999px;flex:none;padding:2px 6px;font-size:12px;line-height:1}._7D6uKa_cardRun{flex:none}._7D6uKa_cardRun[data-result=failed]{color:var(--dsw-alias-state-error-primary)}._7D6uKa_cardRun[data-result=succeeded]{color:var(--dsw-alias-state-success-primary)}._7D6uKa_cardSession{color:var(--dsw-alias-state-business-primary);flex:none}._7D6uKa_cardRunningLabel{color:var(--dsw-alias-state-warn-primary);font-size:11px}._7D6uKa_cardSpinner{border:2px solid var(--dsw-alias-state-warn-primary);border-top-color:#0000;border-radius:50%;flex:none;width:10px;height:10px;animation:.8s linear infinite _7D6uKa_dshTbSpin}@keyframes _7D6uKa_dshTbSpin{to{transform:rotate(360deg)}}._7D6uKa_primaryButton{color:var(--dsw-alias-label-primary-foreground);background:var(--dsw-alias-button-info-fill);cursor:pointer;white-space:nowrap;border:none;border-radius:8px;padding:6px 14px;font-size:13px;font-weight:600}._7D6uKa_primaryButton:hover:not(:disabled){background:var(--dsw-alias-button-info-hover)}._7D6uKa_primaryButton:disabled{opacity:.5;cursor:default}._7D6uKa_ghostButton{color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;white-space:nowrap;background:0 0;border-radius:8px;padding:5px 12px;font-size:12px}._7D6uKa_ghostButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}._7D6uKa_ghostButton:disabled{opacity:.45;cursor:default}._7D6uKa_dangerButton{color:#fff;background:var(--dsw-alias-state-error-primary);cursor:pointer;white-space:nowrap;border:none;border-radius:8px;padding:6px 14px;font-size:13px;font-weight:600}._7D6uKa_dangerButton:hover:not(:disabled){filter:brightness(1.08)}._7D6uKa_dangerButton:active:not(:disabled){filter:brightness(.94)}._7D6uKa_dangerButton:disabled{opacity:.5;cursor:default}._7D6uKa_iconButton{width:26px;height:26px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;padding:0;font-size:13px;display:inline-flex}._7D6uKa_iconButton:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}._7D6uKa_linkButton{color:var(--dsw-alias-state-business-primary);cursor:pointer;white-space:nowrap;background:0 0;border:none;padding:0;font-size:12px}._7D6uKa_linkButton:hover{text-decoration:underline}._7D6uKa_modalBackdrop{z-index:1300;background:var(--dsw-alias-bg-mask-1);justify-content:center;align-items:center;display:flex;position:fixed;inset:0}._7D6uKa_modal{background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);width:min(520px,100vw - 48px);max-height:calc(100vh - 96px);box-shadow:var(--dsw-shadow-lv3);color:var(--dsw-alias-label-primary);border-radius:14px;flex-direction:column;gap:12px;padding:18px;display:flex;overflow-y:auto}._7D6uKa_modalTitle{margin:0;font-size:15px;font-weight:700}._7D6uKa_confirmMessage{color:var(--dsw-alias-label-secondary);white-space:pre-wrap;overflow-wrap:anywhere;margin:0;font-size:13px;line-height:1.5}._7D6uKa_modalFooter{justify-content:flex-end;gap:10px;margin-top:4px;display:flex}._7D6uKa_field{flex-direction:column;gap:5px;display:flex}._7D6uKa_fieldLabel{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:600}._7D6uKa_input{color:var(--dsw-alias-label-primary);background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);resize:vertical;border-radius:8px;outline:none;padding:7px 10px;font-family:inherit;font-size:13px}._7D6uKa_input:focus{border-color:var(--dsw-alias-state-business-primary)}._7D6uKa_select{color:var(--dsw-alias-label-primary);background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;outline:none;max-width:100%;padding:7px 10px;font-family:inherit;font-size:13px}._7D6uKa_input::placeholder{color:var(--dsw-alias-label-tertiary)}._7D6uKa_formError{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px}._7D6uKa_detail{background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);width:min(640px,100vw - 48px);max-height:calc(100vh - 80px);box-shadow:var(--dsw-shadow-lv3);color:var(--dsw-alias-label-primary);border-radius:14px;flex-direction:column;display:flex;overflow:hidden}._7D6uKa_detailHeader{border-bottom:1px solid var(--dsw-alias-separator-primary);flex:none;align-items:center;gap:10px;padding:14px 18px;display:flex}._7D6uKa_detailTitle{overflow-wrap:anywhere;flex:1;margin:0;font-size:15px;font-weight:700}._7D6uKa_statusBadge{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:2px 10px;font-size:12px}._7D6uKa_statusBadge[data-status=running]{color:var(--dsw-alias-state-warn-primary);border-color:var(--dsw-alias-state-warn-primary)}._7D6uKa_statusBadge[data-status=done]{color:var(--dsw-alias-state-success-primary);border-color:var(--dsw-alias-state-success-primary)}._7D6uKa_statusBadge[data-status=failed]{color:var(--dsw-alias-state-error-primary);border-color:var(--dsw-alias-state-error-primary)}._7D6uKa_detailBody{flex-direction:column;flex:1;gap:16px;padding:14px 18px;display:flex;overflow-y:auto}._7D6uKa_detailSection{flex-direction:column;gap:6px;display:flex}._7D6uKa_detailSection h4{color:var(--dsw-alias-label-tertiary);text-transform:none;margin:0;font-size:12px;font-weight:700}._7D6uKa_detailText{color:var(--dsw-alias-label-primary);white-space:pre-wrap;overflow-wrap:anywhere;margin:0;font-size:13px;line-height:1.55}._7D6uKa_scheduleToggle{color:var(--dsw-alias-label-primary);cursor:pointer;user-select:none;align-items:center;gap:8px;font-size:13px;display:flex}._7D6uKa_scheduleToggle input{accent-color:var(--dsw-alias-state-business-primary)}._7D6uKa_scheduleRow{align-items:center;gap:8px;display:flex}._7D6uKa_scheduleInput{min-width:0;font-family:var(--dsw-font-markdown-code-block-small);flex:1;font-size:12.5px}._7D6uKa_scheduleInputInvalid,._7D6uKa_scheduleInputInvalid:focus{border-color:var(--dsw-alias-state-error-primary)}._7D6uKa_schedulePreset{color:var(--dsw-alias-label-primary);background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;outline:none;flex:none;padding:7px 8px;font-size:12.5px}._7D6uKa_scheduleMeta{color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere;margin:0;font-size:12px}._7D6uKa_promptBlock{font-size:12.5px;line-height:1.5;font-family:var(--dsw-font-markdown-code-block-small);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-markdown-code-block);border:1px solid var(--dsw-alias-border-l1);white-space:pre-wrap;overflow-wrap:anywhere;border-radius:8px;max-height:240px;margin:0;padding:10px 12px;overflow-y:auto}._7D6uKa_executionList{flex-direction:column;gap:8px;margin:0;padding:0;list-style:none;display:flex}._7D6uKa_executionRow{border:1px solid var(--dsw-alias-border-l1);border-radius:8px;flex-wrap:wrap;align-items:center;gap:10px;padding:8px 10px;display:flex}._7D6uKa_executionBadge{color:var(--dsw-alias-state-warn-primary);background:var(--dsw-alias-state-warn-secondary);border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:600}._7D6uKa_executionBadge[data-result=succeeded]{color:var(--dsw-alias-state-success-primary);background:0 0}._7D6uKa_executionBadge[data-result=failed]{color:var(--dsw-alias-state-error-primary);background:0 0}._7D6uKa_executionBadge[data-result=cancelled]{color:var(--dsw-alias-label-tertiary);background:0 0}._7D6uKa_executionTimes{color:var(--dsw-alias-label-secondary);font-size:12px}._7D6uKa_executionError{width:100%;color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere;font-size:12px}._7D6uKa_moveRow{flex-wrap:wrap;gap:8px;display:flex}._7D6uKa_detailFooter{border-top:1px solid var(--dsw-alias-separator-primary);flex:none;align-items:center;gap:10px;padding:12px 18px;display:flex}._7D6uKa_detailMeta{color:var(--dsw-alias-label-tertiary);margin-left:auto;font-size:11px}@container _7D6uKa_task-board-view (width<=768px){._7D6uKa_board{gap:10px;padding:10px}._7D6uKa_boardHeader{flex-wrap:wrap;align-items:center;gap:8px}._7D6uKa_backButton{flex:none;order:1}._7D6uKa_boardTitle{flex:auto;order:2}._7D6uKa_boardHeader>._7D6uKa_detailMeta{flex:1 0 100%;order:3;margin-left:0}._7D6uKa_search{flex:1 0 100%;order:4;min-width:0}._7D6uKa_boardHeader>button:not(._7D6uKa_backButton){flex:1 1 0;order:5;min-width:0}._7D6uKa_columns{scroll-snap-type:inline mandatory;scrollbar-width:none;-webkit-overflow-scrolling:touch;grid-auto-columns:86cqw;gap:10px;padding-inline:2px 14cqw;scroll-padding-inline:2px}._7D6uKa_columns::-webkit-scrollbar{display:none}._7D6uKa_column{scroll-snap-align:start;scroll-snap-stop:always}}@container _7D6uKa_task-board-view (width<=720px){._7D6uKa_boardHeader>._7D6uKa_detailMeta{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}}@container _7D6uKa_task-board-view (width<=600px){._7D6uKa_board{padding-inline:8px}}@media (width<=768px){[data-dsh-taskboard-view]{height:100dvh}._7D6uKa_entry,._7D6uKa_card,._7D6uKa_primaryButton,._7D6uKa_ghostButton,._7D6uKa_dangerButton,._7D6uKa_iconButton,._7D6uKa_linkButton,._7D6uKa_search,._7D6uKa_input,._7D6uKa_select,._7D6uKa_schedulePreset,._7D6uKa_scheduleToggle{min-height:44px}._7D6uKa_search,._7D6uKa_input,._7D6uKa_select,._7D6uKa_schedulePreset{box-sizing:border-box;font-size:16px}._7D6uKa_modalBackdrop{justify-content:stretch;align-items:stretch;width:100vw;height:100dvh}._7D6uKa_modal,._7D6uKa_detail{box-sizing:border-box;border:0;border-radius:0;width:100vw;height:100dvh;max-height:none}._7D6uKa_modal{padding-top:max(16px, env(safe-area-inset-top));padding-right:max(16px, env(safe-area-inset-right));padding-bottom:max(16px, env(safe-area-inset-bottom));padding-left:max(16px, env(safe-area-inset-left))}._7D6uKa_modalFooter{z-index:1;background:var(--dsw-alias-bg-base);flex-wrap:wrap;padding-top:8px;position:sticky;bottom:0}._7D6uKa_modalFooter>button{flex:120px}._7D6uKa_detailHeader{padding-top:max(12px, env(safe-area-inset-top));padding-right:max(14px, env(safe-area-inset-right));padding-left:max(14px, env(safe-area-inset-left));flex-wrap:wrap}._7D6uKa_detailTitle{min-width:0}._7D6uKa_detailBody{overscroll-behavior-y:contain;padding-right:max(14px, env(safe-area-inset-right));padding-left:max(14px, env(safe-area-inset-left))}._7D6uKa_detailFooter{padding-right:max(14px, env(safe-area-inset-right));padding-bottom:max(12px, env(safe-area-inset-bottom));padding-left:max(14px, env(safe-area-inset-left));flex-wrap:wrap}._7D6uKa_detailFooter>button{flex:96px}._7D6uKa_detailFooter>._7D6uKa_detailMeta{text-align:end;flex:1 0 100%;margin-left:0}._7D6uKa_scheduleRow{flex-direction:column;align-items:stretch}._7D6uKa_schedulePreset{width:100%}}._7D6uKa_entry:focus-visible,._7D6uKa_card:focus-visible,._7D6uKa_primaryButton:focus-visible,._7D6uKa_ghostButton:focus-visible,._7D6uKa_dangerButton:focus-visible,._7D6uKa_iconButton:focus-visible,._7D6uKa_linkButton:focus-visible,._7D6uKa_search:focus-visible,._7D6uKa_input:focus-visible,._7D6uKa_select:focus-visible,._7D6uKa_schedulePreset:focus-visible,._7D6uKa_scheduleToggle input:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}._7D6uKa_entry,._7D6uKa_primaryButton,._7D6uKa_ghostButton,._7D6uKa_dangerButton,._7D6uKa_iconButton,._7D6uKa_linkButton,._7D6uKa_search,._7D6uKa_input,._7D6uKa_select,._7D6uKa_schedulePreset,._7D6uKa_scheduleToggle input{transition:background-color .12s,color .12s,border-color .12s,outline-color .12s,box-shadow .12s,transform .12s}._7D6uKa_card:active{box-shadow:var(--dsw-shadow-lv1);transform:translateY(0)}._7D6uKa_entry:active,._7D6uKa_primaryButton:active:not(:disabled),._7D6uKa_ghostButton:active:not(:disabled),._7D6uKa_dangerButton:active:not(:disabled),._7D6uKa_iconButton:active:not(:disabled),._7D6uKa_linkButton:active:not(:disabled){transform:translateY(1px)}._7D6uKa_entry[data-active]:hover{background:var(--dsw-specific-sidebar-nav-item-active)}._7D6uKa_iconButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}._7D6uKa_linkButton:hover:not(:disabled){text-decoration:underline}._7D6uKa_iconButton:disabled,._7D6uKa_linkButton:disabled{opacity:.45;cursor:default}._7D6uKa_search:focus,._7D6uKa_select:focus,._7D6uKa_schedulePreset:focus{border-color:var(--dsw-alias-state-business-primary)}._7D6uKa_scheduleToggle input{margin:0}@media (prefers-reduced-motion:reduce){._7D6uKa_entry,._7D6uKa_card,._7D6uKa_primaryButton,._7D6uKa_ghostButton,._7D6uKa_dangerButton,._7D6uKa_iconButton,._7D6uKa_linkButton,._7D6uKa_search,._7D6uKa_input,._7D6uKa_select,._7D6uKa_schedulePreset,._7D6uKa_scheduleToggle input{transition:none}._7D6uKa_cardSpinner{animation:none}}._7D6uKa_cardTags{flex-wrap:wrap;gap:4px;display:flex}._7D6uKa_cardTag{border:1px solid var(--dsh-task-tag-border);background:var(--dsh-task-tag-fill);max-width:100%;color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;border-radius:999px;padding:0 7px;font-size:10px;line-height:16px;overflow:hidden}._7D6uKa_tagFilter{flex-wrap:wrap;align-items:center;gap:6px;margin:0 0 10px;display:flex}._7D6uKa_tagFilterLabel{color:var(--dsw-alias-label-tertiary);font-size:11px}._7D6uKa_tagChip{border:1px solid var(--dsh-task-tag-border);color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border-radius:999px;padding:1px 9px;font-family:inherit;font-size:11px;line-height:18px}._7D6uKa_tagChip[data-active=true]{background:var(--dsh-task-tag-fill);color:var(--dsw-alias-label-primary)}._7D6uKa_cardTag[data-tag-tone=\"0\"],._7D6uKa_tagChip[data-tag-tone=\"0\"]{--dsh-task-tag-fill:#4e93e82e;--dsh-task-tag-border:#4e93e866}._7D6uKa_cardTag[data-tag-tone=\"1\"],._7D6uKa_tagChip[data-tag-tone=\"1\"]{--dsh-task-tag-fill:#2ea36a2e;--dsh-task-tag-border:#2ea36a66}._7D6uKa_cardTag[data-tag-tone=\"2\"],._7D6uKa_tagChip[data-tag-tone=\"2\"]{--dsh-task-tag-fill:#d08a2a2e;--dsh-task-tag-border:#d08a2a66}._7D6uKa_cardTag[data-tag-tone=\"3\"],._7D6uKa_tagChip[data-tag-tone=\"3\"]{--dsh-task-tag-fill:#b456c82e;--dsh-task-tag-border:#b456c866}._7D6uKa_cardTag[data-tag-tone=\"4\"],._7D6uKa_tagChip[data-tag-tone=\"4\"]{--dsh-task-tag-fill:#cf5f7a2e;--dsh-task-tag-border:#cf5f7a66}._7D6uKa_cardTag[data-tag-tone=\"5\"],._7D6uKa_tagChip[data-tag-tone=\"5\"]{--dsh-task-tag-fill:#4a9fb52e;--dsh-task-tag-border:#4a9fb566}._7D6uKa_fieldHint{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.4}._7D6uKa_tagRow{align-items:center;gap:6px;display:flex}._7D6uKa_tagRow ._7D6uKa_input{flex:1 1 0;min-width:0}._7D6uKa_tagRow ._7D6uKa_ghostButton{flex:none}._7D6uKa_tagAddButton{align-self:flex-start}._7D6uKa_projectFilter{flex:none;align-items:center;gap:6px;display:flex}._7D6uKa_projectFilterLabel{color:var(--dsw-alias-label-secondary);white-space:nowrap;font-size:12px}._7D6uKa_projectDialog{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:10px;flex-direction:column;flex:none;gap:8px;margin-bottom:8px;padding:10px 12px;display:flex}._7D6uKa_projectDialogActions{justify-content:flex-end;gap:8px;display:flex}._7D6uKa_aiParse{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:10px;flex-direction:column;gap:6px;padding:10px 12px;display:flex}._7D6uKa_aiParseRow{align-items:center;gap:8px;display:flex}._7D6uKa_aiParseRow ._7D6uKa_select{flex:1 1 0;min-width:0}._7D6uKa_aiParseRow ._7D6uKa_ghostButton,._7D6uKa_aiParseRow ._7D6uKa_primaryButton{flex:none}";
1984
2001
  const tagId$1 = "@linxin666/dsh-client-ui-task-board/packages/dsh-task-board/src/client/board.module.css";
1985
2002
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
1986
2003
  const tag = document.createElement("style");
@@ -2096,7 +2113,7 @@ window.__ModuleLoader__.load({
2096
2113
  /** DOM id shared by the tag-name inputs and their datalist (one board at a time). */
2097
2114
  const TAG_NAME_LIST_ID = "dsh-task-board-tag-names";
2098
2115
  /** Modal overlay: closes on backdrop press, submits through the form. */
2099
- function ModalShell({ ariaLabel, title, error, pending, submitLabel, onSubmit, onClose, children }) {
2116
+ function ModalShell({ ariaLabel, title, error, pending, submitLabel, onSubmit, onClose, secondaryAction, children }) {
2100
2117
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2101
2118
  className: board_module_css_default.modalBackdrop,
2102
2119
  onMouseDown: (event) => {
@@ -2122,17 +2139,27 @@ window.__ModuleLoader__.load({
2122
2139
  }),
2123
2140
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("footer", {
2124
2141
  className: board_module_css_default.modalFooter,
2125
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2126
- type: "button",
2127
- className: board_module_css_default.ghostButton,
2128
- onClick: onClose,
2129
- children: t("new.cancel")
2130
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2131
- type: "submit",
2132
- className: board_module_css_default.primaryButton,
2133
- disabled: pending,
2134
- children: submitLabel
2135
- })]
2142
+ children: [
2143
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2144
+ type: "button",
2145
+ className: board_module_css_default.ghostButton,
2146
+ onClick: onClose,
2147
+ children: t("new.cancel")
2148
+ }),
2149
+ secondaryAction !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2150
+ type: "button",
2151
+ className: board_module_css_default.ghostButton,
2152
+ disabled: pending,
2153
+ onClick: secondaryAction.onSubmit,
2154
+ children: secondaryAction.label
2155
+ }),
2156
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2157
+ type: "submit",
2158
+ className: board_module_css_default.primaryButton,
2159
+ disabled: pending,
2160
+ children: submitLabel
2161
+ })
2162
+ ]
2136
2163
  })
2137
2164
  ]
2138
2165
  })
@@ -2271,6 +2298,37 @@ window.__ModuleLoader__.load({
2271
2298
  return normalizeTags(tags) ?? [];
2272
2299
  }
2273
2300
  //#endregion
2301
+ //#region src/client/board/parse-model-pref.ts
2302
+ /**
2303
+ * The model the user last picked for AI parsing, remembered per browser so the
2304
+ * next new-task modal starts from it instead of the roster's first entry
2305
+ * (issue #1621). An empty value is a real choice — "let the Host use its
2306
+ * default model" — and is remembered as such.
2307
+ */
2308
+ const PARSE_MODEL_KEY = "dsh-task-board.parse-model";
2309
+ /** The nearest browser storage, or undefined when the global itself throws. */
2310
+ function defaultStorage() {
2311
+ try {
2312
+ return globalThis.localStorage;
2313
+ } catch {
2314
+ return;
2315
+ }
2316
+ }
2317
+ /** The remembered parse model; '' means the Host default (or no preference). */
2318
+ function readParseModelPreference(storage = defaultStorage()) {
2319
+ try {
2320
+ return storage?.getItem(PARSE_MODEL_KEY) ?? "";
2321
+ } catch {
2322
+ return "";
2323
+ }
2324
+ }
2325
+ /** Remember the picked parse model; '' records the Host-default choice. */
2326
+ function writeParseModelPreference(model, storage = defaultStorage()) {
2327
+ try {
2328
+ storage?.setItem(PARSE_MODEL_KEY, model);
2329
+ } catch {}
2330
+ }
2331
+ //#endregion
2274
2332
  //#region src/client/board/NewTaskModal.tsx
2275
2333
  /**
2276
2334
  * New-task modal: title + description + the prompt that execution will send.
@@ -2300,14 +2358,17 @@ window.__ModuleLoader__.load({
2300
2358
  const [options, setOptions] = (0, react.useState)(controller.getSnapshot().executionOptions);
2301
2359
  const [canParse] = (0, react.useState)(controller.getSnapshot().canParseTask === true);
2302
2360
  const [parseText, setParseText] = (0, react.useState)("");
2303
- const [parseModel, setParseModel] = (0, react.useState)("");
2361
+ const [parseModel, setParseModel] = (0, react.useState)(() => readParseModelPreference());
2304
2362
  const [parsePending, setParsePending] = (0, react.useState)(false);
2305
2363
  const [parseError, setParseError] = (0, react.useState)(void 0);
2306
2364
  const parseAbort = (0, react.useRef)(void 0);
2307
2365
  const parseModels = options.models ?? [];
2308
2366
  (0, react.useEffect)(() => controller.subscribe(() => setOptions(controller.getSnapshot().executionOptions)), [controller]);
2309
2367
  (0, react.useEffect)(() => {
2310
- if (parseModel === "" && parseModels.length > 0) setParseModel(parseModels[0].id);
2368
+ if (parseModel === "" || parseModels.length === 0) return;
2369
+ if (parseModels.some((option) => option.id === parseModel)) return;
2370
+ setParseModel("");
2371
+ writeParseModelPreference("");
2311
2372
  }, [parseModel, options.models]);
2312
2373
  const runParse = async () => {
2313
2374
  const text = parseText.trim();
@@ -2334,7 +2395,13 @@ window.__ModuleLoader__.load({
2334
2395
  setParsePending(false);
2335
2396
  }
2336
2397
  };
2337
- const submit = async () => {
2398
+ /**
2399
+ * Create the task through the Host, then optionally start it.
2400
+ * @param runAfterCreate - true for the "create and run" action: the task is
2401
+ * committed either way, and a refused start opens the task instead of
2402
+ * reporting the creation as failed.
2403
+ */
2404
+ const submit = async (runAfterCreate) => {
2338
2405
  if (scheduleEnabled) {
2339
2406
  const cron = scheduleCron.trim();
2340
2407
  if (cron === "" || !isValidCron(cron)) {
@@ -2363,7 +2430,7 @@ window.__ModuleLoader__.load({
2363
2430
  };
2364
2431
  const tagList = cleanTags(tags);
2365
2432
  setPending(true);
2366
- if (await controller.createTaskConfirmed({
2433
+ const task = await controller.createTaskConfirmed({
2367
2434
  title,
2368
2435
  description,
2369
2436
  prompt,
@@ -2379,13 +2446,17 @@ window.__ModuleLoader__.load({
2379
2446
  enabled: true,
2380
2447
  cron: scheduleCron.trim()
2381
2448
  } : void 0
2382
- }) === void 0) {
2449
+ });
2450
+ if (task === void 0) {
2383
2451
  setPending(false);
2384
2452
  setError(controller.getSnapshot().transportError ?? t("new.required"));
2385
2453
  return;
2386
2454
  }
2387
2455
  if (isDuplicate && archiveOriginal && initialTask !== void 0) if (onDuplicateSuccess !== void 0) await onDuplicateSuccess(initialTask.id);
2388
2456
  else await controller.archiveTask(initialTask.id);
2457
+ if (runAfterCreate) {
2458
+ if (!await controller.runTask(task.id)) controller.openTask(task.id);
2459
+ }
2389
2460
  onClose();
2390
2461
  };
2391
2462
  /** Next-run preview for a valid armed cron (creation-time only). */
@@ -2398,9 +2469,15 @@ window.__ModuleLoader__.load({
2398
2469
  pending,
2399
2470
  submitLabel: t("new.submit"),
2400
2471
  onSubmit: () => {
2401
- submit();
2472
+ submit(false);
2402
2473
  },
2403
2474
  onClose,
2475
+ secondaryAction: {
2476
+ label: t("new.createAndRun"),
2477
+ onSubmit: () => {
2478
+ submit(true);
2479
+ }
2480
+ },
2404
2481
  children: [
2405
2482
  canParse && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
2406
2483
  className: board_module_css_default.aiParse,
@@ -2427,17 +2504,21 @@ window.__ModuleLoader__.load({
2427
2504
  }),
2428
2505
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2429
2506
  className: board_module_css_default.aiParseRow,
2430
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
2507
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
2431
2508
  className: board_module_css_default.select,
2432
2509
  value: parseModel,
2433
2510
  "aria-label": t("new.aiParseModel"),
2434
2511
  onChange: (event) => {
2435
2512
  setParseModel(event.target.value);
2513
+ writeParseModelPreference(event.target.value);
2436
2514
  },
2437
- children: parseModels.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
2515
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
2516
+ value: "",
2517
+ children: t("exec.model.default")
2518
+ }), parseModels.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
2438
2519
  value: option.id,
2439
2520
  children: option.name ?? option.id
2440
- }, option.id))
2521
+ }, option.id))]
2441
2522
  }), parsePending ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2442
2523
  type: "button",
2443
2524
  className: board_module_css_default.ghostButton,
@@ -4267,7 +4348,7 @@ window.__ModuleLoader__.load({
4267
4348
  if (nested !== null) return nested;
4268
4349
  for (const child of root.children) if (child.tagName === "BUTTON") return child;
4269
4350
  }
4270
- /** Build the entry row (a detached button; insert once the shell is up). */
4351
+ /** Build the entry row (detached; inserted once the shell is up). */
4271
4352
  function createEntry(options) {
4272
4353
  const entry = document.createElement("button");
4273
4354
  entry.type = "button";
@@ -4376,8 +4457,8 @@ window.__ModuleLoader__.load({
4376
4457
  //#region src/client/sidebar-entry.ts
4377
4458
  /** Stable data attribute identifying the injected entry row. */
4378
4459
  const ENTRY_SELECTOR = "[data-dsh-taskboard-entry]";
4379
- /** Inline icon normalized to the shell's 18px navigation glyph size. */
4380
- const ICON = "<svg viewBox=\"0 0 16 16\" width=\"18\" height=\"18\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.3\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><rect x=\"2\" y=\"2.5\" width=\"12\" height=\"11\" rx=\"1.5\"/><path d=\"M2 6.5h12M6.5 6.5v7\"/></svg>";
4460
+ /** Inline icon normalized to the shell's 16px navigation glyph size. */
4461
+ const ICON = "<svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.3\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><rect x=\"2\" y=\"2.5\" width=\"12\" height=\"11\" rx=\"1.5\"/><path d=\"M2 6.5h12M6.5 6.5v7\"/></svg>";
4381
4462
  /**
4382
4463
  * Mount the sidebar entry, waiting for the shell to render and self-healing
4383
4464
  * on later React re-renders.
@@ -4540,17 +4621,20 @@ window.__ModuleLoader__.load({
4540
4621
  })
4541
4622
  ]
4542
4623
  });
4543
- if (!state.exposed) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
4544
- className: cardClass,
4545
- children: [header, expanded ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4546
- className: settings_card_module_css_default.body,
4547
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4548
- className: settings_card_module_css_default.notExposed,
4549
- role: "status",
4550
- children: props.t("settings.notExposed")
4551
- })
4552
- }) : null]
4553
- });
4624
+ if (!state.exposed && props.renderChildrenWhenNotExposed !== true) {
4625
+ const showNotice = props.hideNotExposedNotice !== true;
4626
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
4627
+ className: cardClass,
4628
+ children: [header, expanded ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4629
+ className: settings_card_module_css_default.body,
4630
+ children: showNotice ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4631
+ className: settings_card_module_css_default.notExposed,
4632
+ role: "status",
4633
+ children: props.t("settings.notExposed")
4634
+ }) : null
4635
+ }) : null]
4636
+ });
4637
+ }
4554
4638
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
4555
4639
  className: cardClass,
4556
4640
  children: [header, expanded ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -4859,31 +4943,31 @@ window.__ModuleLoader__.load({
4859
4943
  specs;
4860
4944
  staged = /* @__PURE__ */ new Map();
4861
4945
  listeners = /* @__PURE__ */ new Set();
4862
- /** The scope subscription installed in the constructor; released by dispose(). */
4863
- disposeScope;
4946
+ /** The form subscription installed in the constructor; released by dispose(). */
4947
+ disposeForm;
4864
4948
  disposed = false;
4865
4949
  saving = false;
4866
4950
  failed = false;
4867
4951
  failedReason;
4868
- /** @param scope - the bound settings scope for this card's namespace. */
4952
+ /** @param scope - the bound configuration form for this card's namespace. */
4869
4953
  constructor(scope, specs) {
4870
4954
  this.scope = scope;
4871
4955
  this.specs = new Map(specs.map((spec) => [spec.field, spec]));
4872
- this.disposeScope = scope.subscribe(() => {
4956
+ this.disposeForm = scope.subscribe(() => {
4873
4957
  this.publish();
4874
4958
  });
4875
4959
  }
4876
4960
  /**
4877
- * Release the scope subscription and every bound store listener. The card
4961
+ * Release the form subscription and every bound store listener. The card
4878
4962
  * must call this on teardown; later calls are no-ops.
4879
4963
  */
4880
4964
  dispose() {
4881
4965
  if (this.disposed) return;
4882
4966
  this.disposed = true;
4883
- this.disposeScope();
4967
+ this.disposeForm();
4884
4968
  this.listeners.clear();
4885
4969
  }
4886
- /** Publish a projection of this form, rebuilt whenever the scope or a draft changes. */
4970
+ /** Publish a projection of this form, rebuilt whenever the form or a draft changes. */
4887
4971
  bind(project) {
4888
4972
  const store = createSnapshotStore(project());
4889
4973
  this.listeners.add(() => {
@@ -4950,19 +5034,19 @@ window.__ModuleLoader__.load({
4950
5034
  };
4951
5035
  }
4952
5036
  /**
4953
- * Write every staged edit in one atomic scope mutation, then re-seed from
5037
+ * Write every staged edit in one atomic form mutation, then re-seed from
4954
5038
  * what the Host accepted.
4955
5039
  *
4956
5040
  * The whole batch rides one mutate, so cross-field validate hooks
4957
5041
  * (baseURL+model) judge it as a unit: the Host either applies every write
4958
- * or refuses the batch. The 0.1.2 scope contract never rejects a refused
4959
- * mutation — the scope recovers with a fresh Host view and resolves — so
4960
- * resolution alone proves nothing: the outcome is judged by reading the
4961
- * settled snapshot back, one planned write at a time, and one missed write
4962
- * fails the whole save. A scope that still rejects on refusal (the dsh-web
4963
- * bridge scope) reports through the same failure path with its rejection
4964
- * message. A save that did not land keeps its drafts, so the user can
4965
- * correct them instead of retyping.
5042
+ * or refuses the batch. The form contract answers a refusal or a skipped
5043
+ * write with `false` (it recovers with a fresh Host view instead of
5044
+ * throwing), so the outcome is judged twice: the answer itself, and then the
5045
+ * settled snapshot read back one planned write at a time. One missed write
5046
+ * fails the whole save. A transport that rejects instead (the dsh-web bridge
5047
+ * controller on a dead connection) reports through the same failure path
5048
+ * with its rejection message. A save that did not land keeps its drafts, so
5049
+ * the user can correct them instead of retyping.
4966
5050
  * @returns settlement after the mutation and the read-back.
4967
5051
  */
4968
5052
  async save() {
@@ -4984,12 +5068,13 @@ window.__ModuleLoader__.load({
4984
5068
  path: [item.field]
4985
5069
  });
4986
5070
  let failedReason;
5071
+ let accepted = false;
4987
5072
  try {
4988
- await this.scope.mutate(ops);
5073
+ accepted = await this.scope.mutate(ops);
4989
5074
  } catch (error) {
4990
5075
  failedReason = error instanceof Error ? error.message : String(error);
4991
5076
  }
4992
- const landed = failedReason === void 0 && valid.every((item) => item.judge());
5077
+ const landed = accepted && failedReason === void 0 && valid.every((item) => item.judge());
4993
5078
  for (const [field, before] of pending) if (landed && this.staged.get(field) === before) this.staged.delete(field);
4994
5079
  this.saving = false;
4995
5080
  this.failed = !landed;
@@ -5096,11 +5181,11 @@ window.__ModuleLoader__.load({
5096
5181
  };
5097
5182
  //#endregion
5098
5183
  //#region src/client/TaskBoardSettingsCard.tsx
5099
- /** Bridges the `task-board` scope onto the card's staged form. */
5184
+ /** Bridges the `task-board` settings form onto the card's staged form. */
5100
5185
  var TaskBoardSettingsCardController = class {
5101
5186
  form;
5102
5187
  store;
5103
- /** @param scope - the bound settings scope for the `task-board` namespace. */
5188
+ /** @param scope - the bound configuration form for the `task-board` namespace. */
5104
5189
  constructor(scope) {
5105
5190
  this.form = new CardForm(scope, [
5106
5191
  booleanField("enabled"),
@@ -5128,7 +5213,7 @@ window.__ModuleLoader__.load({
5128
5213
  };
5129
5214
  }
5130
5215
  /**
5131
- * Release the card's scope subscription and bound stores; the slot
5216
+ * Release the card's form subscription and bound stores; the slot
5132
5217
  * disposer calls this on teardown.
5133
5218
  */
5134
5219
  dispose() {
@@ -5171,6 +5256,8 @@ window.__ModuleLoader__.load({
5171
5256
  descriptionKey: "settings.description",
5172
5257
  defaultOpen: false,
5173
5258
  state,
5259
+ renderChildrenWhenNotExposed: true,
5260
+ hideNotExposedNotice: true,
5174
5261
  onSave: props.save,
5175
5262
  onDiscard: props.discard,
5176
5263
  children: [
@@ -5434,7 +5521,7 @@ window.__ModuleLoader__.load({
5434
5521
  /** The building package's version, when the bundle carries it. */
5435
5522
  function bakedVersion() {
5436
5523
  try {
5437
- return "0.3.23";
5524
+ return "0.4.0";
5438
5525
  } catch {
5439
5526
  return;
5440
5527
  }
@@ -5497,12 +5584,155 @@ window.__ModuleLoader__.load({
5497
5584
  } catch {}
5498
5585
  }
5499
5586
  //#endregion
5587
+ //#region src/client/plugin-card-seat.ts
5588
+ /**
5589
+ * Family plugin-card seat.
5590
+ *
5591
+ * A family plugin contributes its settings card to whichever plugin-card seat
5592
+ * the running host actually renders:
5593
+ *
5594
+ * - `web-ui.plugin.item` — the list seat declared by the dsh-web-settings
5595
+ * group section (this family's own first-level "Web UI plugins" section);
5596
+ * - `plugins.bundle.config` — the official keyed seat of the harness's plugin
5597
+ * manager page, keyed by the bundle's package name and rendered on that
5598
+ * bundle's page. alpha.2 removed the `settings.plugin.item` keyed seat of the
5599
+ * `ui-settings-plugins` tab that this helper used before, so a card keyed by
5600
+ * its settings namespace has no seat to land in any more.
5601
+ *
5602
+ * SEAT SELECTION IS NOT A DECLARATION PROBE. The official plugin surface
5603
+ * belongs to the harness bundle and declares its seats before any external
5604
+ * plugin's `apply()` runs, so "is the official seat declared?" answers yes even
5605
+ * in the deployment whose whole point is the family group. Choosing on that
5606
+ * probe sends every family card to the official page and leaves the group's own
5607
+ * section permanently empty — the family of reports where the section renders
5608
+ * its heading and zero cards.
5609
+ *
5610
+ * The signal that actually distinguishes the two deployments is whether
5611
+ * dsh-web-settings is loaded: it is the package that owns the group section and
5612
+ * it publishes the `webUiSettings` service during `apply()`, which every
5613
+ * family plugin already reads for its settings form. Group loaded -> the family
5614
+ * seat; group absent -> the official seat.
5615
+ *
5616
+ * The decision is re-evaluated on every `slots/changed` because the group may
5617
+ * apply after this plugin (the family aggregate orders it first, a profile that
5618
+ * installs the group separately need not): the initial contribution goes to the
5619
+ * official seat, then moves to the family seat the moment the group's section
5620
+ * registers. The entry is disposed before the replacement is registered, so a
5621
+ * card is never in two seats at once.
5622
+ *
5623
+ * The shared tree has no client-SDK dependency, so this module reads its
5624
+ * context through the structural shape below; callers pass the plugin's own
5625
+ * `ctx`.
5626
+ */
5627
+ /** The family list seat key. */
5628
+ const FAMILY_PLUGIN_CARD_SEAT = "web-ui.plugin.item";
5629
+ /** The official keyed plugin-card seat key (the alpha.2 bundle-configuration seat). */
5630
+ const OFFICIAL_PLUGIN_CARD_SEAT = "plugins.bundle.config";
5631
+ /** The service dsh-web-settings publishes while it is loaded. */
5632
+ const FAMILY_GROUP_SERVICE = "webUiSettings";
5633
+ /**
5634
+ * Whether the family group (dsh-web-settings) is loaded in this page. The
5635
+ * service is the group package's own contract, so the probe cannot be fooled
5636
+ * by a harness release that starts declaring the official seat differently.
5637
+ */
5638
+ function familyGroupLoaded(ctx) {
5639
+ const get = ctx.get;
5640
+ if (typeof get !== "function") return false;
5641
+ try {
5642
+ return get.call(ctx, FAMILY_GROUP_SERVICE) !== void 0;
5643
+ } catch {
5644
+ return false;
5645
+ }
5646
+ }
5647
+ /** Report a refused registration instead of leaving the user with no card. */
5648
+ function warnRefusedSeat(seat, error) {
5649
+ try {
5650
+ console.warn(`[dsh-web] plugin card registration into "${seat}" was refused; the card will not render`, error);
5651
+ } catch {}
5652
+ }
5653
+ /**
5654
+ * Contribute one family plugin card to the seat this host renders, following
5655
+ * the group if it loads later. The entry is disposed and re-registered on a
5656
+ * seat change, never duplicated.
5657
+ * @param ctx - client context (its slot registry decides the seat).
5658
+ * @param seat - the card contribution.
5659
+ */
5660
+ function installPluginCard(ctx, seat) {
5661
+ const slots = ctx.slots;
5662
+ const component = seat.component;
5663
+ const inject = seat.inject;
5664
+ let dispose;
5665
+ let current;
5666
+ /**
5667
+ * Re-entrancy latch. The registry emits a change event synchronously from
5668
+ * inside both `register` and the previous entry's disposer, so an unguarded
5669
+ * reconcile would re-enter itself mid-move and register the card twice into
5670
+ * the seat it is leaving ("already has an entry for key ...").
5671
+ */
5672
+ let reconciling = false;
5673
+ /** Reconcile the contribution with the currently live seat (no-op when unchanged). */
5674
+ const reconcile = () => {
5675
+ if (reconciling) return;
5676
+ const target = familyGroupLoaded(ctx) ? FAMILY_PLUGIN_CARD_SEAT : OFFICIAL_PLUGIN_CARD_SEAT;
5677
+ if (current === target) return;
5678
+ reconciling = true;
5679
+ const previous = dispose;
5680
+ dispose = void 0;
5681
+ current = void 0;
5682
+ previous?.();
5683
+ try {
5684
+ dispose = slots.register(target === "web-ui.plugin.item" ? {
5685
+ name: FAMILY_PLUGIN_CARD_SEAT,
5686
+ id: seat.id,
5687
+ ...seat.order === void 0 ? {} : { order: seat.order },
5688
+ ...seat.label === void 0 ? {} : { label: seat.label },
5689
+ locale: seat.locale,
5690
+ ...seat.inject === void 0 ? {} : { inject }
5691
+ } : {
5692
+ name: OFFICIAL_PLUGIN_CARD_SEAT,
5693
+ key: seat.bundle,
5694
+ locale: seat.locale,
5695
+ ...seat.inject === void 0 ? {} : { inject }
5696
+ }, component);
5697
+ current = target;
5698
+ } catch (error) {
5699
+ warnRefusedSeat(target, error);
5700
+ } finally {
5701
+ reconciling = false;
5702
+ }
5703
+ };
5704
+ if (typeof ctx.on === "function") try {
5705
+ ctx.on("slots/changed", () => {
5706
+ reconcile();
5707
+ });
5708
+ } catch {}
5709
+ reconcile();
5710
+ }
5711
+ //#endregion
5500
5712
  //#region src/client/index.ts
5501
5713
  /** Locale namespace this plugin owns. */
5502
5714
  const NS = "task-board";
5503
- /** Settings namespace the settings card edits (the Host plugin registers it). */
5715
+ /** Settings namespace this card edits (the family identity of the plugin's own settings form). */
5504
5716
  const TASK_BOARD_NS = "task-board";
5505
5717
  /**
5718
+ * Profile entry id the family aggregate's generated row carries — the
5719
+ * deployment shape nearly every user runs. Under 0.1.7 a settings form is
5720
+ * addressed by profile entry id, so the shared-forms fallback below has to
5721
+ * name it; the family binder resolves the family namespace instead.
5722
+ */
5723
+ const AGGREGATE_ENTRY_ID = "web-ui-task-board";
5724
+ /**
5725
+ * Profile entry ids this package's two patch rows carry: the aggregate's
5726
+ * generated row and the standalone bundle patch's row (`ui-task-board`), plus
5727
+ * the bare namespace as the last resort for a Host whose descriptor is keyed
5728
+ * by the family namespace itself.
5729
+ */
5730
+ const TASK_BOARD_ENTRY_IDS = [
5731
+ AGGREGATE_ENTRY_ID,
5732
+ "ui-task-board",
5733
+ TASK_BOARD_NS
5734
+ ];
5735
+ /**
5506
5736
  * Required services (fiber inject waiting — the runtime must be up first).
5507
5737
  * The generated remote faces are probed at use time instead of injected:
5508
5738
  * `remote.agentPresets` only registers on 0.1.2-alpha.2 hosts (the
@@ -5515,10 +5745,11 @@ window.__ModuleLoader__.load({
5515
5745
  "sessions",
5516
5746
  "workspaces",
5517
5747
  "connection",
5518
- "settingsScope",
5748
+ "configForms",
5519
5749
  "locale",
5520
5750
  "remote",
5521
- "remote.session"
5751
+ "remote.session",
5752
+ "uiWorkspace"
5522
5753
  ];
5523
5754
  /**
5524
5755
  * Mount the task board.
@@ -5541,25 +5772,19 @@ window.__ModuleLoader__.load({
5541
5772
  try {
5542
5773
  setRuntimeTranslate(ctx.locale.bind(NS));
5543
5774
  } catch {}
5544
- const settingsScope = (ctx.get("webUiSettings") ?? ctx.settingsScope).bind({ namespace: TASK_BOARD_NS });
5545
- const settingsCard = new TaskBoardSettingsCardController(settingsScope);
5546
- ctx.slots.inject("web-ui.plugin.item", () => {
5547
- try {
5548
- const unregister = ctx.slots.register({
5549
- name: "web-ui.plugin.item",
5550
- id: "task-board",
5551
- order: 110,
5552
- locale: NS,
5553
- inject: () => settingsCard.inject()
5554
- }, TaskBoardSettingsCard);
5555
- return () => {
5556
- settingsCard.dispose();
5557
- unregister();
5558
- };
5559
- } catch {
5560
- return () => {};
5561
- }
5775
+ const settingsForm = bindSettingsForm(ctx);
5776
+ const settingsCard = new TaskBoardSettingsCardController(settingsForm);
5777
+ installPluginCard(ctx, {
5778
+ bundle: "@linxin666/dsh-client-ui-task-board",
5779
+ id: "task-board",
5780
+ order: 110,
5781
+ locale: NS,
5782
+ inject: () => settingsCard.inject(),
5783
+ component: TaskBoardSettingsCard
5562
5784
  });
5785
+ ctx.effect(() => () => {
5786
+ settingsCard.dispose();
5787
+ }, "task-board: settings card");
5563
5788
  let uiDisposer;
5564
5789
  const mountUi = () => {
5565
5790
  if (uiDisposer !== void 0) return;
@@ -5570,8 +5795,9 @@ window.__ModuleLoader__.load({
5570
5795
  store: new LocalStorageTaskStore(),
5571
5796
  transport: new HttpTaskBoardHostTransport(),
5572
5797
  sessions: {
5573
- list: sessions.list,
5574
- open: (id) => sessions.open(id)
5798
+ current: () => mainViewSessionId(sessions.list.getSnapshot().byId),
5799
+ open: (id) => ctx.uiWorkspace.openSession(id),
5800
+ subscribe: (fn) => sessions.list.subscribe(fn)
5575
5801
  }
5576
5802
  });
5577
5803
  controller.start();
@@ -5660,15 +5886,55 @@ window.__ModuleLoader__.load({
5660
5886
  };
5661
5887
  };
5662
5888
  const syncEnabled = () => {
5663
- const snapshot = settingsScope.getSnapshot();
5889
+ const snapshot = settingsForm.getSnapshot();
5664
5890
  if (snapshot.status === "ready" ? snapshot.value?.enabled ?? true : snapshot.status === "unavailable") mountUi();
5665
5891
  else uiDisposer?.();
5666
5892
  };
5667
- settingsScope.subscribe(syncEnabled);
5893
+ settingsForm.subscribe(syncEnabled);
5668
5894
  syncEnabled();
5669
5895
  }
5896
+ /**
5897
+ * Bind the settings form this card stages over.
5898
+ *
5899
+ * The family binder (`ctx.get('webUiSettings')`, published by dsh-web-settings)
5900
+ * comes first: it is what traces this package's family namespace onto the
5901
+ * profile entry id the Host serves the form under, and it keeps the loopback
5902
+ * bridge as its own fallback. A page without that group falls back to the
5903
+ * shared configuration forms service bound directly at one of this package's
5904
+ * own profile entry ids.
5905
+ * @param ctx - client root context.
5906
+ * @returns the form the settings card reads and writes.
5907
+ */
5908
+ function bindSettingsForm(ctx) {
5909
+ const binder = ctx.get("webUiSettings");
5910
+ if (binder !== void 0 && typeof binder.bind === "function") return binder.bind({ namespace: TASK_BOARD_NS });
5911
+ return ctx.configForms.get(servedEntryId(ctx.configForms));
5912
+ }
5913
+ /**
5914
+ * The profile entry id this package's own row carries.
5915
+ *
5916
+ * The shared describe mirror is the only local evidence of which row id this
5917
+ * profile actually serves, but it answers asynchronously: at plugin
5918
+ * activation it usually holds nothing yet. An unanswered mirror therefore
5919
+ * binds the aggregate row id rather than guessing among the candidates —
5920
+ * the form is bound once for the session, so a wrong guess would leave the
5921
+ * card reporting an unserved namespace even after the mirror settles.
5922
+ * @param forms - the shared configuration forms service.
5923
+ * @returns the entry id to bind.
5924
+ */
5925
+ function servedEntryId(forms) {
5926
+ let served;
5927
+ try {
5928
+ served = forms.describe().getSnapshot().view?.namespaces.map((view) => view.ns);
5929
+ } catch {
5930
+ served = void 0;
5931
+ }
5932
+ if (served === void 0) return AGGREGATE_ENTRY_ID;
5933
+ return TASK_BOARD_ENTRY_IDS.find((id) => served.includes(id)) ?? TASK_BOARD_NS;
5934
+ }
5670
5935
  //#endregion
5671
5936
  exports.apply = apply;
5937
+ exports.bindSettingsForm = bindSettingsForm;
5672
5938
  exports.inject = inject;
5673
5939
  return module.exports;
5674
5940
  }