@linxin666/dsh-client-ui-task-board 0.3.22 → 0.3.23

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/lib/client.js CHANGED
@@ -644,6 +644,7 @@ window.__ModuleLoader__.load({
644
644
  presets: [],
645
645
  models: []
646
646
  };
647
+ workspaceCreator;
647
648
  listeners = /* @__PURE__ */ new Set();
648
649
  disposers = [];
649
650
  now;
@@ -687,6 +688,8 @@ window.__ModuleLoader__.load({
687
688
  selectedTaskId: this.selectedTaskId,
688
689
  executionOptions: this.executionOptions,
689
690
  pendingTaskIds: [...this.pendingTaskIds],
691
+ ...this.workspaceCreator === void 0 ? {} : { canCreateWorkspace: true },
692
+ ...typeof this.deps.transport?.parseDraft === "function" ? { canParseTask: true } : {},
690
693
  ...this.transportError === void 0 ? {} : { transportError: this.transportError },
691
694
  ...this.hostState === void 0 ? {} : { host: this.hostState }
692
695
  };
@@ -789,6 +792,33 @@ window.__ModuleLoader__.load({
789
792
  };
790
793
  this.notify();
791
794
  }
795
+ /** Wire (or clear) the runtime's project registration face (issue #1536). */
796
+ setWorkspaceCreator(creator) {
797
+ this.workspaceCreator = creator;
798
+ this.notify();
799
+ }
800
+ /**
801
+ * Register an existing host directory as a DSH project, exactly as the GUI's
802
+ * own "add project" does; the runtime's failure message surfaces unchanged.
803
+ */
804
+ async createWorkspace(path) {
805
+ if (this.workspaceCreator === void 0) throw new Error("workspace creation is unavailable");
806
+ return await this.workspaceCreator(path);
807
+ }
808
+ /** Whether this deployment can parse pasted text into task fields (issue #1540). */
809
+ canParseTask() {
810
+ return typeof this.deps.transport?.parseDraft === "function";
811
+ }
812
+ /**
813
+ * Parse pasted text into task fields through the Host. The transport already
814
+ * phrases every failure for the user, so its message surfaces unchanged.
815
+ */
816
+ async parseTaskDraft(request, signal) {
817
+ const transport = this.deps.transport;
818
+ const parse = transport?.parseDraft;
819
+ if (transport === void 0 || parse === void 0) throw new Error("task parsing is unavailable");
820
+ return await parse.call(transport, request, signal);
821
+ }
792
822
  moveTask(id, status) {
793
823
  if (this.deps.transport !== void 0) {
794
824
  this.commitRemote({
@@ -1573,6 +1603,30 @@ window.__ModuleLoader__.load({
1573
1603
  "board.updated": "更新于",
1574
1604
  "board.created": "创建于",
1575
1605
  "board.hostError": "Host 操作失败:{error}",
1606
+ "board.hostError.notMounted": "任务看板的后台接口没有挂载:宿主可能没有加载该插件,也可能后台数据正被另一个 DSH 实例占用。重启 DSH 服务后再试",
1607
+ "board.hostError.unauthorized": "登录状态已失效,请刷新页面后重试",
1608
+ "board.hostError.locked": "任务看板的后台数据被占用:{detail}",
1609
+ "board.hostError.timeout": "后台 {seconds} 秒内没有响应,请稍后重试",
1610
+ "board.hostError.unreachable": "连接不上本机 DSH 服务,请确认它仍在运行",
1611
+ "board.hostError.unexpected": "后台返回了无法识别的响应(HTTP {status})",
1612
+ "board.project": "项目",
1613
+ "board.projectAll": "全部项目",
1614
+ "board.projectNew": "新建项目…",
1615
+ "board.projectNewPath": "项目目录(宿主上的绝对路径)",
1616
+ "board.projectNewPathPlaceholder": "例如 C:\\work\\my-project 或 /home/me/project",
1617
+ "board.projectCreate": "创建项目",
1618
+ "board.projectCreateFailed": "创建项目失败:{error}",
1619
+ "new.aiParse": "AI 解析",
1620
+ "new.aiParseHint": "把从别处复制的一段话粘进来,让模型整理成标题、描述和执行 Prompt;解析结果只填进下面的表单,你可以先改再创建。",
1621
+ "new.aiParsePlaceholder": "粘贴要变成任务的内容…",
1622
+ "new.aiParseModel": "解析用模型",
1623
+ "new.aiParseRun": "解析并填入",
1624
+ "new.aiParseCancel": "取消解析",
1625
+ "new.aiParseEmpty": "先粘贴一段内容再解析",
1626
+ "new.aiParseNoModel": "这个部署还没有可用的模型,请先在 DSH 里配置模型提供商,或换一个模型再试",
1627
+ "new.aiParseUnavailable": "后台没有解析接口可用,重启 DSH 服务后再试",
1628
+ "new.aiParseTimeout": "模型 {seconds} 秒内没有返回结果,请重试或换一个更快的模型",
1629
+ "new.aiParseFailed": "解析失败:{error}",
1576
1630
  "board.retryHost": "重试连接 Host",
1577
1631
  "board.hostMeta": "Host 时区 {timeZone} · revision {revision}",
1578
1632
  "new.title": "标题",
@@ -1615,6 +1669,7 @@ window.__ModuleLoader__.load({
1615
1669
  "detail.permissionConfirmed": "已确认权限绑定 · {time}",
1616
1670
  "detail.title": "任务详情",
1617
1671
  "detail.edit": "编辑",
1672
+ "detail.editTags": "编辑标签",
1618
1673
  "detail.duplicate": "复制为新任务",
1619
1674
  "detail.duplicateAndEdit": "修改并新建副本",
1620
1675
  "detail.close": "关闭",
@@ -1736,6 +1791,30 @@ window.__ModuleLoader__.load({
1736
1791
  "board.updated": "Updated",
1737
1792
  "board.created": "Created",
1738
1793
  "board.hostError": "Host action failed: {error}",
1794
+ "board.hostError.notMounted": "The task board Host API is not mounted: the Host may not have loaded the plugin, or another DSH instance holds the ledger. Restart the DSH service and try again",
1795
+ "board.hostError.unauthorized": "This session is no longer signed in; reload the page and try again",
1796
+ "board.hostError.locked": "The task board ledger is locked: {detail}",
1797
+ "board.hostError.timeout": "The Host did not answer within {seconds}s; try again shortly",
1798
+ "board.hostError.unreachable": "Cannot reach the local DSH service; make sure it is still running",
1799
+ "board.hostError.unexpected": "The Host returned an unrecognized response (HTTP {status})",
1800
+ "board.project": "Project",
1801
+ "board.projectAll": "All projects",
1802
+ "board.projectNew": "New project…",
1803
+ "board.projectNewPath": "Project directory (absolute path on the Host)",
1804
+ "board.projectNewPathPlaceholder": "e.g. C:\\work\\my-project or /home/me/project",
1805
+ "board.projectCreate": "Create project",
1806
+ "board.projectCreateFailed": "Could not create the project: {error}",
1807
+ "new.aiParse": "Parse with AI",
1808
+ "new.aiParseHint": "Paste text copied from somewhere else and let a model turn it into a title, description, and run prompt; the result only fills the form below, so you can edit it before creating the task.",
1809
+ "new.aiParsePlaceholder": "Paste the content to turn into a task…",
1810
+ "new.aiParseModel": "Model used for parsing",
1811
+ "new.aiParseRun": "Parse and fill",
1812
+ "new.aiParseCancel": "Cancel parsing",
1813
+ "new.aiParseEmpty": "Paste something to parse first",
1814
+ "new.aiParseNoModel": "This deployment has no model available; configure a model provider in DSH or pick another model",
1815
+ "new.aiParseUnavailable": "The Host has no parse endpoint; restart the DSH service and try again",
1816
+ "new.aiParseTimeout": "The model did not answer within {seconds}s; try again or pick a faster model",
1817
+ "new.aiParseFailed": "Parsing failed: {error}",
1739
1818
  "board.retryHost": "Retry Host connection",
1740
1819
  "board.hostMeta": "Host time zone {timeZone} · revision {revision}",
1741
1820
  "new.title": "Title",
@@ -1778,6 +1857,7 @@ window.__ModuleLoader__.load({
1778
1857
  "detail.permissionConfirmed": "Permission confirmed · {time}",
1779
1858
  "detail.title": "Task Detail",
1780
1859
  "detail.edit": "Edit",
1860
+ "detail.editTags": "Edit tags",
1781
1861
  "detail.duplicate": "Duplicate Task",
1782
1862
  "detail.duplicateAndEdit": "Edit as New Copy",
1783
1863
  "detail.close": "Close",
@@ -1900,7 +1980,7 @@ window.__ModuleLoader__.load({
1900
1980
  }
1901
1981
  //#endregion
1902
1982
  //#region \0dsh-css:packages/dsh-task-board/src/client/board.module.css.mjs
1903
- 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}";
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}";
1904
1984
  const tagId$1 = "@linxin666/dsh-client-ui-task-board/packages/dsh-task-board/src/client/board.module.css";
1905
1985
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
1906
1986
  const tag = document.createElement("style");
@@ -1910,6 +1990,8 @@ window.__ModuleLoader__.load({
1910
1990
  document.head.appendChild(tag);
1911
1991
  }
1912
1992
  var board_module_css_default = {
1993
+ "aiParse": "_7D6uKa_aiParse",
1994
+ "aiParseRow": "_7D6uKa_aiParseRow",
1913
1995
  "backButton": "_7D6uKa_backButton",
1914
1996
  "board": "_7D6uKa_board",
1915
1997
  "boardHeader": "_7D6uKa_boardHeader",
@@ -1966,6 +2048,10 @@ window.__ModuleLoader__.load({
1966
2048
  "modalTitle": "_7D6uKa_modalTitle",
1967
2049
  "moveRow": "_7D6uKa_moveRow",
1968
2050
  "primaryButton": "_7D6uKa_primaryButton",
2051
+ "projectDialog": "_7D6uKa_projectDialog",
2052
+ "projectDialogActions": "_7D6uKa_projectDialogActions",
2053
+ "projectFilter": "_7D6uKa_projectFilter",
2054
+ "projectFilterLabel": "_7D6uKa_projectFilterLabel",
1969
2055
  "promptBlock": "_7D6uKa_promptBlock",
1970
2056
  "scheduleInput": "_7D6uKa_scheduleInput",
1971
2057
  "scheduleInputInvalid": "_7D6uKa_scheduleInputInvalid",
@@ -2178,21 +2264,11 @@ window.__ModuleLoader__.load({
2178
2264
  });
2179
2265
  }
2180
2266
  /**
2181
- * Drop blank rows and trim what survives, so the wire always carries a valid
2182
- * tag list (the protocol rejects a list with a blank name or an empty array).
2267
+ * Clean a tag list via normalizeTags: trim, drop blanks and duplicates, cap
2268
+ * lengths and count, so the wire always carries a valid tag list.
2183
2269
  */
2184
2270
  function cleanTags(tags) {
2185
- const cleaned = [];
2186
- for (const tag of tags) {
2187
- const name = tag.name.trim();
2188
- if (name === "") continue;
2189
- const promptPrefix = tag.promptPrefix?.trim();
2190
- cleaned.push(promptPrefix === void 0 || promptPrefix === "" ? { name } : {
2191
- name,
2192
- promptPrefix
2193
- });
2194
- }
2195
- return cleaned;
2271
+ return normalizeTags(tags) ?? [];
2196
2272
  }
2197
2273
  //#endregion
2198
2274
  //#region src/client/board/NewTaskModal.tsx
@@ -2201,12 +2277,12 @@ window.__ModuleLoader__.load({
2201
2277
  * Creates through the Host and closes only after the Host confirms it.
2202
2278
  */
2203
2279
  /** New-task form overlay. */
2204
- function NewTaskModal({ controller, onClose, initialTask, onDuplicateSuccess }) {
2280
+ function NewTaskModal({ controller, onClose, initialTask, defaultWorkspaceId, onDuplicateSuccess }) {
2205
2281
  const isDuplicate = initialTask !== void 0;
2206
2282
  const [title, setTitle] = (0, react.useState)(initialTask?.title ?? "");
2207
2283
  const [description, setDescription] = (0, react.useState)(initialTask?.description ?? "");
2208
2284
  const [prompt, setPrompt] = (0, react.useState)(initialTask?.prompt ?? "");
2209
- const [workspaceId, setWorkspaceId] = (0, react.useState)(initialTask?.workspaceId ?? "");
2285
+ const [workspaceId, setWorkspaceId] = (0, react.useState)(initialTask?.workspaceId ?? defaultWorkspaceId ?? "");
2210
2286
  const [mode, setMode] = (0, react.useState)(initialTask?.mode ?? "");
2211
2287
  const [permission, setPermission] = (0, react.useState)(initialTask?.permission ?? "");
2212
2288
  const [model, setModel] = (0, react.useState)(initialTask?.model ?? "");
@@ -2222,7 +2298,42 @@ window.__ModuleLoader__.load({
2222
2298
  const [error, setError] = (0, react.useState)(void 0);
2223
2299
  const [pending, setPending] = (0, react.useState)(false);
2224
2300
  const [options, setOptions] = (0, react.useState)(controller.getSnapshot().executionOptions);
2301
+ const [canParse] = (0, react.useState)(controller.getSnapshot().canParseTask === true);
2302
+ const [parseText, setParseText] = (0, react.useState)("");
2303
+ const [parseModel, setParseModel] = (0, react.useState)("");
2304
+ const [parsePending, setParsePending] = (0, react.useState)(false);
2305
+ const [parseError, setParseError] = (0, react.useState)(void 0);
2306
+ const parseAbort = (0, react.useRef)(void 0);
2307
+ const parseModels = options.models ?? [];
2225
2308
  (0, react.useEffect)(() => controller.subscribe(() => setOptions(controller.getSnapshot().executionOptions)), [controller]);
2309
+ (0, react.useEffect)(() => {
2310
+ if (parseModel === "" && parseModels.length > 0) setParseModel(parseModels[0].id);
2311
+ }, [parseModel, options.models]);
2312
+ const runParse = async () => {
2313
+ const text = parseText.trim();
2314
+ if (text === "") {
2315
+ setParseError(t("new.aiParseEmpty"));
2316
+ return;
2317
+ }
2318
+ const abort = new AbortController();
2319
+ parseAbort.current = abort;
2320
+ setParsePending(true);
2321
+ setParseError(void 0);
2322
+ try {
2323
+ const draft = await controller.parseTaskDraft({
2324
+ text,
2325
+ ...parseModel === "" ? {} : { model: parseModel }
2326
+ }, abort.signal);
2327
+ setTitle(draft.title);
2328
+ setDescription(draft.description);
2329
+ setPrompt(draft.prompt);
2330
+ } catch (parseFailure) {
2331
+ if (!abort.signal.aborted) setParseError(parseFailure instanceof Error ? parseFailure.message : String(parseFailure));
2332
+ } finally {
2333
+ parseAbort.current = void 0;
2334
+ setParsePending(false);
2335
+ }
2336
+ };
2226
2337
  const submit = async () => {
2227
2338
  if (scheduleEnabled) {
2228
2339
  const cron = scheduleCron.trim();
@@ -2291,6 +2402,65 @@ window.__ModuleLoader__.load({
2291
2402
  },
2292
2403
  onClose,
2293
2404
  children: [
2405
+ canParse && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
2406
+ className: board_module_css_default.aiParse,
2407
+ "data-dsh-part": "ai-parse",
2408
+ children: [
2409
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2410
+ className: board_module_css_default.fieldLabel,
2411
+ children: t("new.aiParse")
2412
+ }),
2413
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2414
+ className: board_module_css_default.fieldHint,
2415
+ children: t("new.aiParseHint")
2416
+ }),
2417
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
2418
+ className: board_module_css_default.input,
2419
+ rows: 3,
2420
+ value: parseText,
2421
+ placeholder: t("new.aiParsePlaceholder"),
2422
+ spellCheck: false,
2423
+ onChange: (event) => {
2424
+ setParseText(event.target.value);
2425
+ setParseError(void 0);
2426
+ }
2427
+ }),
2428
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2429
+ className: board_module_css_default.aiParseRow,
2430
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
2431
+ className: board_module_css_default.select,
2432
+ value: parseModel,
2433
+ "aria-label": t("new.aiParseModel"),
2434
+ onChange: (event) => {
2435
+ setParseModel(event.target.value);
2436
+ },
2437
+ children: parseModels.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
2438
+ value: option.id,
2439
+ children: option.name ?? option.id
2440
+ }, option.id))
2441
+ }), parsePending ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2442
+ type: "button",
2443
+ className: board_module_css_default.ghostButton,
2444
+ onClick: () => {
2445
+ parseAbort.current?.abort();
2446
+ },
2447
+ children: t("new.aiParseCancel")
2448
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2449
+ type: "button",
2450
+ className: board_module_css_default.primaryButton,
2451
+ disabled: parseText.trim() === "",
2452
+ onClick: () => {
2453
+ runParse();
2454
+ },
2455
+ children: t("new.aiParseRun")
2456
+ })]
2457
+ }),
2458
+ parseError !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2459
+ className: board_module_css_default.formError,
2460
+ children: parseError
2461
+ })
2462
+ ]
2463
+ }),
2294
2464
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TaskContentFields, {
2295
2465
  title,
2296
2466
  description,
@@ -2759,6 +2929,39 @@ window.__ModuleLoader__.load({
2759
2929
  })]
2760
2930
  });
2761
2931
  }
2932
+ /** Edit-tags modal: edit labels only, shown for tasks after first execution. */
2933
+ function EditTagsModal({ controller, task, onClose }) {
2934
+ const [tags, setTags] = (0, react.useState)(task.tags ?? []);
2935
+ const [error, setError] = (0, react.useState)(void 0);
2936
+ const [pending, setPending] = (0, react.useState)(false);
2937
+ const submit = async () => {
2938
+ setPending(true);
2939
+ const tagList = cleanTags(tags);
2940
+ const patch = { tags: tagList.length > 0 ? tagList : null };
2941
+ if (await controller.updateTask(task.id, patch)) {
2942
+ onClose();
2943
+ return;
2944
+ }
2945
+ setPending(false);
2946
+ setError(controller.getSnapshot().transportError ?? t("new.required"));
2947
+ };
2948
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModalShell, {
2949
+ ariaLabel: t("detail.editTags"),
2950
+ title: t("detail.editTags"),
2951
+ error,
2952
+ pending,
2953
+ submitLabel: t("edit.save"),
2954
+ onSubmit: () => {
2955
+ submit();
2956
+ },
2957
+ onClose,
2958
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TaskTagFields, {
2959
+ tags,
2960
+ knownTags: collectKnownTags(controller.getSnapshot().tasks),
2961
+ onChange: setTags
2962
+ })
2963
+ });
2964
+ }
2762
2965
  //#endregion
2763
2966
  //#region src/client/board/TaskDetail.tsx
2764
2967
  /**
@@ -3090,6 +3293,7 @@ window.__ModuleLoader__.load({
3090
3293
  function TaskDetail({ controller, task }) {
3091
3294
  const [confirmDelete, setConfirmDelete] = (0, react.useState)(false);
3092
3295
  const [showEdit, setShowEdit] = (0, react.useState)(false);
3296
+ const [showEditTags, setShowEditTags] = (0, react.useState)(false);
3093
3297
  const [showDuplicate, setShowDuplicate] = (0, react.useState)(false);
3094
3298
  const [latest, setLatest] = (0, react.useState)(task);
3095
3299
  (0, react.useEffect)(() => {
@@ -3097,6 +3301,7 @@ window.__ModuleLoader__.load({
3097
3301
  }, [task]);
3098
3302
  (0, react.useEffect)(() => {
3099
3303
  setShowEdit(false);
3304
+ setShowEditTags(false);
3100
3305
  setShowDuplicate(false);
3101
3306
  }, [task.id]);
3102
3307
  const current = latest;
@@ -3166,6 +3371,21 @@ window.__ModuleLoader__.load({
3166
3371
  children: current.description !== "" ? current.description : "—"
3167
3372
  })]
3168
3373
  }),
3374
+ current.tags !== void 0 && current.tags.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
3375
+ className: board_module_css_default.detailSection,
3376
+ "data-dsh-part": "tags",
3377
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", { children: t("new.tags") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3378
+ className: board_module_css_default.cardTags,
3379
+ children: current.tags.map((tag) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3380
+ className: board_module_css_default.cardTag,
3381
+ "data-tag-tone": tagTone(tag.name),
3382
+ "data-dsh-part": "tag-badge",
3383
+ "data-tag-hint": tag.promptPrefix === void 0 ? void 0 : tag.promptPrefix,
3384
+ title: tag.promptPrefix === void 0 ? tag.name : tag.promptPrefix,
3385
+ children: tag.name
3386
+ }, tag.name))
3387
+ })]
3388
+ }),
3169
3389
  current.freeze !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
3170
3390
  className: board_module_css_default.detailSection,
3171
3391
  "data-dsh-part": "freeze",
@@ -3332,6 +3552,15 @@ window.__ModuleLoader__.load({
3332
3552
  },
3333
3553
  children: t("detail.edit")
3334
3554
  }),
3555
+ !archived && !canEditTaskContent(current) && current.status !== "running" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3556
+ type: "button",
3557
+ className: board_module_css_default.ghostButton,
3558
+ disabled: pending,
3559
+ onClick: () => {
3560
+ setShowEditTags(true);
3561
+ },
3562
+ children: t("detail.editTags")
3563
+ }),
3335
3564
  !archived && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3336
3565
  type: "button",
3337
3566
  className: board_module_css_default.ghostButton,
@@ -3412,6 +3641,13 @@ window.__ModuleLoader__.load({
3412
3641
  setShowEdit(false);
3413
3642
  }
3414
3643
  }),
3644
+ showEditTags && !archived && current.status !== "running" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EditTagsModal, {
3645
+ controller,
3646
+ task: current,
3647
+ onClose: () => {
3648
+ setShowEditTags(false);
3649
+ }
3650
+ }),
3415
3651
  showDuplicate && !archived && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NewTaskModal, {
3416
3652
  controller,
3417
3653
  initialTask: current,
@@ -3426,13 +3662,6 @@ window.__ModuleLoader__.load({
3426
3662
  ]
3427
3663
  });
3428
3664
  }
3429
- //#endregion
3430
- //#region src/client/board/TaskBoard.tsx
3431
- /**
3432
- * Board view: the multi-column kanban that replaces the middle column while
3433
- * active. Cards open the task detail (never execute directly); the header
3434
- * offers filter, new-task, and a back-to-chat escape.
3435
- */
3436
3665
  /** Case-insensitive title/description/tag/freeze-snapshot match. */
3437
3666
  function matchesFilter(task, filter) {
3438
3667
  if (filter.trim() === "") return true;
@@ -3479,10 +3708,33 @@ window.__ModuleLoader__.load({
3479
3708
  const [filter, setFilter] = (0, react.useState)("");
3480
3709
  const [tagFilter, setTagFilter] = (0, react.useState)([]);
3481
3710
  const [showNew, setShowNew] = (0, react.useState)(false);
3711
+ const [projectId, setProjectId] = (0, react.useState)("");
3712
+ const [showNewProject, setShowNewProject] = (0, react.useState)(false);
3713
+ const [newProjectPath, setNewProjectPath] = (0, react.useState)("");
3714
+ const [newProjectError, setNewProjectError] = (0, react.useState)(void 0);
3715
+ const [newProjectPending, setNewProjectPending] = (0, react.useState)(false);
3482
3716
  const selected = selectedTaskOf(snapshot);
3483
3717
  const archiveView = snapshot.archiveView;
3484
3718
  const knownTags = collectKnownTags(snapshot.tasks);
3485
- const visible = snapshot.tasks.filter((task) => (archiveView ? task.archivedAt !== void 0 : task.archivedAt === void 0) && matchesFilter(task, filter) && matchesTagFilter(task, tagFilter));
3719
+ const visible = snapshot.tasks.filter((task) => (archiveView ? task.archivedAt !== void 0 : task.archivedAt === void 0) && (projectId === "" || task.workspaceId === projectId) && matchesFilter(task, filter) && matchesTagFilter(task, tagFilter));
3720
+ const projects = snapshot.executionOptions.workspaces;
3721
+ const canCreateProject = snapshot.canCreateWorkspace === true;
3722
+ const submitNewProject = async () => {
3723
+ const path = newProjectPath.trim();
3724
+ if (path === "") return;
3725
+ setNewProjectPending(true);
3726
+ setNewProjectError(void 0);
3727
+ try {
3728
+ const created = await controller.createWorkspace(path);
3729
+ setProjectId(created.workspaceId);
3730
+ setShowNewProject(false);
3731
+ setNewProjectPath("");
3732
+ } catch (error) {
3733
+ setNewProjectError(error instanceof Error ? error.message : String(error));
3734
+ } finally {
3735
+ setNewProjectPending(false);
3736
+ }
3737
+ };
3486
3738
  const toggleTag = (0, react.useCallback)((name) => {
3487
3739
  setTagFilter((current) => current.includes(name) ? current.filter((entry) => entry !== name) : [...current, name]);
3488
3740
  }, []);
@@ -3521,6 +3773,41 @@ window.__ModuleLoader__.load({
3521
3773
  timeZone: snapshot.host.scheduler.timeZone
3522
3774
  })
3523
3775
  }),
3776
+ (projects.length > 0 || canCreateProject) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3777
+ className: board_module_css_default.projectFilter,
3778
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3779
+ className: board_module_css_default.projectFilterLabel,
3780
+ children: t("board.project")
3781
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
3782
+ className: board_module_css_default.select,
3783
+ "data-dsh-part": "project-filter",
3784
+ value: projectId,
3785
+ "aria-label": t("board.project"),
3786
+ onChange: (event) => {
3787
+ const value = event.target.value;
3788
+ if (value === "__dsh_new_project__") {
3789
+ setNewProjectError(void 0);
3790
+ setShowNewProject(true);
3791
+ return;
3792
+ }
3793
+ setProjectId(value);
3794
+ },
3795
+ children: [
3796
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3797
+ value: "",
3798
+ children: t("board.projectAll")
3799
+ }),
3800
+ projects.map((project) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3801
+ value: project.workspaceId,
3802
+ children: project.title
3803
+ }, project.workspaceId)),
3804
+ canCreateProject && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3805
+ value: "__dsh_new_project__",
3806
+ children: t("board.projectNew")
3807
+ })
3808
+ ]
3809
+ })]
3810
+ }),
3524
3811
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3525
3812
  className: board_module_css_default.search,
3526
3813
  type: "search",
@@ -3549,6 +3836,52 @@ window.__ModuleLoader__.load({
3549
3836
  })
3550
3837
  ]
3551
3838
  }),
3839
+ showNewProject && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3840
+ className: board_module_css_default.projectDialog,
3841
+ "data-dsh-part": "project-dialog",
3842
+ children: [
3843
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3844
+ className: board_module_css_default.field,
3845
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3846
+ className: board_module_css_default.fieldLabel,
3847
+ children: t("board.projectNewPath")
3848
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3849
+ className: board_module_css_default.input,
3850
+ value: newProjectPath,
3851
+ placeholder: t("board.projectNewPathPlaceholder"),
3852
+ spellCheck: false,
3853
+ onChange: (event) => {
3854
+ setNewProjectPath(event.target.value);
3855
+ setNewProjectError(void 0);
3856
+ }
3857
+ })]
3858
+ }),
3859
+ newProjectError !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3860
+ className: board_module_css_default.formError,
3861
+ children: t("board.projectCreateFailed", { error: newProjectError })
3862
+ }),
3863
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3864
+ className: board_module_css_default.projectDialogActions,
3865
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3866
+ type: "button",
3867
+ className: board_module_css_default.ghostButton,
3868
+ onClick: () => {
3869
+ setShowNewProject(false);
3870
+ setNewProjectError(void 0);
3871
+ },
3872
+ children: t("new.cancel")
3873
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3874
+ type: "button",
3875
+ className: board_module_css_default.primaryButton,
3876
+ disabled: newProjectPending || newProjectPath.trim() === "",
3877
+ onClick: () => {
3878
+ submitNewProject();
3879
+ },
3880
+ children: t("board.projectCreate")
3881
+ })]
3882
+ })
3883
+ ]
3884
+ }),
3552
3885
  !archiveView && knownTags.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3553
3886
  className: board_module_css_default.tagFilter,
3554
3887
  "data-dsh-part": "tag-filter",
@@ -3681,6 +4014,7 @@ window.__ModuleLoader__.load({
3681
4014
  }),
3682
4015
  showNew && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NewTaskModal, {
3683
4016
  controller,
4017
+ ...projectId === "" ? {} : { defaultWorkspaceId: projectId },
3684
4018
  onClose: () => {
3685
4019
  setShowNew(false);
3686
4020
  }
@@ -4902,19 +5236,64 @@ window.__ModuleLoader__.load({
4902
5236
  //#endregion
4903
5237
  //#region src/protocol.ts
4904
5238
  const TASK_BOARD_API_PREFIX = "/api/task-board";
5239
+ /** Whether a decoded reply carries the three draft strings the form accepts. */
5240
+ function isTaskParseDraft(value) {
5241
+ if (typeof value !== "object" || value === null) return false;
5242
+ const record = value;
5243
+ return typeof record.title === "string" && typeof record.description === "string" && typeof record.prompt === "string";
5244
+ }
4905
5245
  //#endregion
4906
5246
  //#region src/client/host-api.ts
4907
5247
  const IMPORT_MARKER = "dsh.taskBoard.v2.hostImported";
4908
5248
  const SOURCE_KEY = "dsh.taskBoard.v2.sourceId";
4909
5249
  const IMPORT_REQUEST_KEY = "dsh.taskBoard.v2.importRequestId";
4910
5250
  const REQUEST_TIMEOUT_MS = 15e3;
5251
+ /** Re-notify the panel at most this often while the event stream stays broken. */
5252
+ const STREAM_ERROR_NOTIFY_MS = 15e3;
5253
+ /** Mirrors the Host's own parse budget; only used to phrase the timeout. */
5254
+ const TASK_PARSE_TIMEOUT_SECONDS = 45;
5255
+ /** Transport failure carrying a stable class next to its user-facing message. */
5256
+ var HostApiError = class extends Error {
5257
+ failure;
5258
+ status;
5259
+ constructor(failure, message, status) {
5260
+ super(message);
5261
+ this.failure = failure;
5262
+ this.status = status;
5263
+ this.name = "HostApiError";
5264
+ }
5265
+ };
4911
5266
  function uuid() {
4912
5267
  return globalThis.crypto?.randomUUID?.() ?? `browser-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
4913
5268
  }
5269
+ /**
5270
+ * Read one Host response without ever handing a non-JSON body to JSON.parse:
5271
+ * the core webserver answers an unmounted `/api/*` path with the plain text
5272
+ * "not found", which used to surface as a JavaScript parse error in the panel.
5273
+ */
4914
5274
  async function readJson(response) {
4915
- const body = await response.json();
4916
- if (!response.ok) throw new Error(body.error ?? `task-board request failed: ${response.status}`);
4917
- return body;
5275
+ const text = await response.text();
5276
+ let parsed;
5277
+ let readable = false;
5278
+ if (text.trim() !== "") try {
5279
+ parsed = JSON.parse(text);
5280
+ readable = true;
5281
+ } catch {
5282
+ readable = false;
5283
+ }
5284
+ const hostError = readable && typeof parsed === "object" && parsed !== null && typeof parsed.error === "string" ? parsed.error : void 0;
5285
+ if (response.ok) {
5286
+ if (!readable) throw new HostApiError("unexpected", t("board.hostError.unexpected", { status: String(response.status) }), response.status);
5287
+ return parsed;
5288
+ }
5289
+ if (hostError !== void 0) {
5290
+ if (hostError === "forbidden") throw new HostApiError("unauthorized", t("board.hostError.unauthorized"), response.status);
5291
+ if (response.status === 503 || /lock/i.test(hostError)) throw new HostApiError("locked", t("board.hostError.locked", { detail: hostError }), response.status);
5292
+ throw new HostApiError("rejected", hostError, response.status);
5293
+ }
5294
+ if (response.status === 404) throw new HostApiError("not-mounted", t("board.hostError.notMounted"), 404);
5295
+ if (response.status === 401 || response.status === 403) throw new HostApiError("unauthorized", t("board.hostError.unauthorized"), response.status);
5296
+ throw new HostApiError("unexpected", t("board.hostError.unexpected", { status: String(response.status) }), response.status);
4918
5297
  }
4919
5298
  var HttpTaskBoardHostTransport = class {
4920
5299
  storage;
@@ -4974,14 +5353,54 @@ window.__ModuleLoader__.load({
4974
5353
  signal: controller.signal
4975
5354
  }));
4976
5355
  } catch (error) {
4977
- if (controller.signal.aborted) throw new Error(`task-board Host request timed out after ${REQUEST_TIMEOUT_MS / 1e3}s`);
4978
- throw error;
5356
+ if (error instanceof HostApiError) throw error;
5357
+ if (controller.signal.aborted) throw new HostApiError("timeout", t("board.hostError.timeout", { seconds: String(REQUEST_TIMEOUT_MS / 1e3) }));
5358
+ throw new HostApiError("unreachable", t("board.hostError.unreachable"));
4979
5359
  } finally {
4980
5360
  globalThis.clearTimeout(timeout);
4981
5361
  }
4982
5362
  }
5363
+ /**
5364
+ * Ask the Host to turn pasted text into task fields. The route answers a
5365
+ * typed failure (no model, timeout, unparseable reply) already phrased for
5366
+ * the form, so the UI never renders a raw status code (issue #1540).
5367
+ */
5368
+ async parseDraft(request, signal) {
5369
+ let response;
5370
+ try {
5371
+ response = await fetch(`${TASK_BOARD_API_PREFIX}/parse`, {
5372
+ method: "POST",
5373
+ headers: { "content-type": "application/json" },
5374
+ body: JSON.stringify(request),
5375
+ ...signal === void 0 ? {} : { signal }
5376
+ });
5377
+ } catch {
5378
+ throw new HostApiError("unreachable", t("board.hostError.unreachable"));
5379
+ }
5380
+ const text = await response.text();
5381
+ let parsed;
5382
+ let readable = false;
5383
+ if (text.trim() !== "") try {
5384
+ parsed = JSON.parse(text);
5385
+ readable = true;
5386
+ } catch {
5387
+ readable = false;
5388
+ }
5389
+ const record = readable && typeof parsed === "object" && parsed !== null ? parsed : void 0;
5390
+ if (response.ok) {
5391
+ if (record !== void 0 && isTaskParseDraft(record.draft)) return record.draft;
5392
+ throw new HostApiError("unexpected", t("new.aiParseFailed", { error: t("board.hostError.unexpected", { status: String(response.status) }) }), response.status);
5393
+ }
5394
+ if (response.status === 404) throw new HostApiError("not-mounted", t("new.aiParseUnavailable"), 404);
5395
+ if (response.status === 401 || response.status === 403) throw new HostApiError("unauthorized", t("board.hostError.unauthorized"), response.status);
5396
+ const code = typeof record?.code === "string" ? record.code : void 0;
5397
+ if (code === "no-model") throw new HostApiError("rejected", t("new.aiParseNoModel"), response.status);
5398
+ if (code === "timeout") throw new HostApiError("timeout", t("new.aiParseTimeout", { seconds: String(TASK_PARSE_TIMEOUT_SECONDS) }), response.status);
5399
+ throw new HostApiError("rejected", t("new.aiParseFailed", { error: typeof record?.error === "string" && record.error !== "" ? record.error : String(response.status) }), response.status);
5400
+ }
4983
5401
  subscribe(listener) {
4984
5402
  const events = new EventSource(`${TASK_BOARD_API_PREFIX}/events`);
5403
+ let lastStreamErrorNotify = 0;
4985
5404
  events.onmessage = (message) => {
4986
5405
  try {
4987
5406
  const parsed = JSON.parse(message.data);
@@ -4991,6 +5410,12 @@ window.__ModuleLoader__.load({
4991
5410
  listener();
4992
5411
  }
4993
5412
  };
5413
+ events.onerror = () => {
5414
+ const now = Date.now();
5415
+ if (now - lastStreamErrorNotify < STREAM_ERROR_NOTIFY_MS) return;
5416
+ lastStreamErrorNotify = now;
5417
+ listener();
5418
+ };
4994
5419
  const onVisible = () => {
4995
5420
  if (document.visibilityState === "visible") listener();
4996
5421
  };
@@ -5009,7 +5434,7 @@ window.__ModuleLoader__.load({
5009
5434
  /** The building package's version, when the bundle carries it. */
5010
5435
  function bakedVersion() {
5011
5436
  try {
5012
- return "0.3.22";
5437
+ return "0.3.23";
5013
5438
  } catch {
5014
5439
  return;
5015
5440
  }
@@ -5160,6 +5585,9 @@ window.__ModuleLoader__.load({
5160
5585
  };
5161
5586
  pushWorkspaceOptions();
5162
5587
  disposers.push(workspaces.list.subscribe(pushWorkspaceOptions));
5588
+ controller.setWorkspaceCreator(async (path) => {
5589
+ return { workspaceId: (await workspaces.create({ path })).workspaceId };
5590
+ });
5163
5591
  const pushModelOptions = async () => {
5164
5592
  try {
5165
5593
  let models = [];