@linxin666/dsh-client-ui-task-board 0.1.17 → 0.1.19

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 (35) hide show
  1. package/README.i18n.yaml +2 -2
  2. package/README.md +3 -3
  3. package/README.zh.md +3 -3
  4. package/lib/client.js +430 -134
  5. package/lib/client.js.map +1 -1
  6. package/lib/types/client/PluginSettingsCard.d.ts +11 -0
  7. package/lib/types/client/TaskBoardSettingsCard.d.ts +5 -0
  8. package/lib/types/client/locales.d.ts +7 -0
  9. package/lib/types/client/schedule-presets.d.ts +10 -0
  10. package/lib/types/client/settings-form.d.ts +8 -0
  11. package/lib/types/core/controller.d.ts +27 -0
  12. package/lib/types/core/execution.d.ts +16 -0
  13. package/lib/types/core/scheduler.d.ts +7 -0
  14. package/lib/types/core/tasks.d.ts +16 -0
  15. package/lib/types/core/use-cases/task-archive.d.ts +22 -0
  16. package/lib/types/core/use-cases/task-create.d.ts +1 -6
  17. package/package.json +1 -1
  18. package/src/client/PluginSettingsCard.tsx +50 -47
  19. package/src/client/TaskBoardSettingsCard.tsx +8 -0
  20. package/src/client/board/NewTaskModal.tsx +68 -0
  21. package/src/client/board/TaskBoard.tsx +56 -25
  22. package/src/client/board/TaskDetail.tsx +27 -8
  23. package/src/client/board.module.css +68 -1
  24. package/src/client/index.ts +16 -7
  25. package/src/client/locales.ts +15 -1
  26. package/src/client/schedule-presets.ts +13 -0
  27. package/src/client/settings-card.module.css +9 -0
  28. package/src/client/settings-form.ts +15 -1
  29. package/src/core/controller.ts +58 -0
  30. package/src/core/execution.ts +41 -2
  31. package/src/core/scheduler.ts +15 -0
  32. package/src/core/store.ts +1 -0
  33. package/src/core/tasks.ts +15 -0
  34. package/src/core/use-cases/task-archive.ts +48 -0
  35. package/src/core/use-cases/task-create.ts +12 -3
package/lib/client.js CHANGED
@@ -9,6 +9,8 @@ window.__ModuleLoader__.load({
9
9
  let react_jsx_runtime = require("react/jsx-runtime");
10
10
  let _deepseek_ai_dsh_client_runtime_client = require("@deepseek-ai/dsh-client-runtime/client");
11
11
  //#region src/core/tasks.ts
12
+ /** Statuses a settled task may be archived from. */
13
+ const ARCHIVABLE_STATUSES = ["done", "failed"];
12
14
  /** Permission presets a task may pin on its execution session (the `/permission <id>` ids). */
13
15
  const TASK_PERMISSIONS = [
14
16
  "read-only",
@@ -166,44 +168,42 @@ window.__ModuleLoader__.load({
166
168
  return "running";
167
169
  }
168
170
  //#endregion
169
- //#region src/core/use-cases/task-create.ts
171
+ //#region src/core/use-cases/task-archive.ts
170
172
  /**
171
- * Create-task use case: mint a new task from user input, rejecting a blank
172
- * title. Pure ledger transition (no persistence or notify — the controller
173
- * orchestrates those), so it is unit-testable without any runtime face.
174
- */
175
- /**
176
- * Apply a create against the current ledger. Returns the new task and the
177
- * appended ledger, or the unchanged ledger when the title is blank.
178
- * @param tasks - current ledger.
179
- * @param input - raw user input (title/description/prompt).
180
- * @param now - clock instant (ms epoch).
181
- * @param id - minted task id.
173
+ * Archive one task: only settled statuses (done/failed) can be archived;
174
+ * a running or not-yet-settled task stays on the board (its runner still
175
+ * owns its lifecycle). Already-archived tasks are a no-op.
182
176
  */
183
- function applyCreateTask(tasks, input, now, id) {
184
- if (input.title.trim() === "") return {
185
- task: void 0,
186
- tasks
187
- };
188
- const task = createTask(input, now, id);
177
+ function applyArchiveTask(tasks, id, now) {
178
+ let applied = false;
189
179
  return {
190
- task,
191
- tasks: [...tasks, task]
180
+ tasks: tasks.map((task) => {
181
+ if (task.id !== id || task.archivedAt !== void 0) return task;
182
+ if (!ARCHIVABLE_STATUSES.includes(task.status)) return task;
183
+ applied = true;
184
+ return {
185
+ ...task,
186
+ archivedAt: now,
187
+ updatedAt: now
188
+ };
189
+ }),
190
+ archived: applied
192
191
  };
193
192
  }
194
- //#endregion
195
- //#region src/core/use-cases/task-delete.ts
196
- /**
197
- * Apply a delete across the ledger. The selection (a task id) is cleared when
198
- * it matches the removed task, so the UI never lingers on a vanished detail.
199
- * @param tasks - current ledger.
200
- * @param selectedTaskId - the currently selected task id (may be undefined).
201
- * @param id - the task to remove.
202
- */
203
- function applyDeleteTask(tasks, selectedTaskId, id) {
193
+ /** Restore one task back onto the main board (clears the archive marker). */
194
+ function applyRestoreTask(tasks, id, now) {
195
+ let applied = false;
204
196
  return {
205
- tasks: tasks.filter((task) => task.id !== id),
206
- selectionCleared: selectedTaskId === id
197
+ tasks: tasks.map((task) => {
198
+ if (task.id !== id || task.archivedAt === void 0) return task;
199
+ applied = true;
200
+ const { archivedAt: _archived, ...rest } = task;
201
+ return {
202
+ ...rest,
203
+ updatedAt: now
204
+ };
205
+ }),
206
+ archived: applied
207
207
  };
208
208
  }
209
209
  //#endregion
@@ -308,6 +308,56 @@ window.__ModuleLoader__.load({
308
308
  return /^\d+$/.test(value);
309
309
  }
310
310
  //#endregion
311
+ //#region src/core/use-cases/task-create.ts
312
+ /**
313
+ * Create-task use case: mint a new task from user input, rejecting a blank
314
+ * title. Pure ledger transition (no persistence or notify — the controller
315
+ * orchestrates those), so it is unit-testable without any runtime face.
316
+ */
317
+ /**
318
+ * Apply a create against the current ledger. Returns the new task and the
319
+ * appended ledger, or the unchanged ledger when the title is blank.
320
+ * @param tasks - current ledger.
321
+ * @param input - raw user input (title/description/prompt + optional schedule).
322
+ * @param now - clock instant (ms epoch).
323
+ * @param id - minted task id.
324
+ */
325
+ function applyCreateTask(tasks, input, now, id) {
326
+ if (input.title.trim() === "") return {
327
+ task: void 0,
328
+ tasks
329
+ };
330
+ let task = createTask(input, now, id);
331
+ const requested = input.schedule;
332
+ if (requested?.enabled === true && requested.cron.trim() !== "" && isValidCron(requested.cron)) {
333
+ const cron = requested.cron.trim();
334
+ task = withSchedule(task, {
335
+ enabled: true,
336
+ cron,
337
+ nextRunAt: nextRunAtMs(cron, now)
338
+ }, now);
339
+ }
340
+ return {
341
+ task,
342
+ tasks: [...tasks, task]
343
+ };
344
+ }
345
+ //#endregion
346
+ //#region src/core/use-cases/task-delete.ts
347
+ /**
348
+ * Apply a delete across the ledger. The selection (a task id) is cleared when
349
+ * it matches the removed task, so the UI never lingers on a vanished detail.
350
+ * @param tasks - current ledger.
351
+ * @param selectedTaskId - the currently selected task id (may be undefined).
352
+ * @param id - the task to remove.
353
+ */
354
+ function applyDeleteTask(tasks, selectedTaskId, id) {
355
+ return {
356
+ tasks: tasks.filter((task) => task.id !== id),
357
+ selectionCleared: selectedTaskId === id
358
+ };
359
+ }
360
+ //#endregion
311
361
  //#region src/core/use-cases/task-schedule.ts
312
362
  /**
313
363
  * Schedule use case: arm/disarm a task's cron rule and roll a rule forward.
@@ -417,6 +467,8 @@ window.__ModuleLoader__.load({
417
467
  return snapshot.tasks.find((task) => task.id === snapshot.selectedTaskId);
418
468
  }
419
469
  function randomUuid() {
470
+ const randomUUID = globalThis.crypto?.randomUUID;
471
+ if (randomUUID !== void 0) return randomUUID.call(globalThis.crypto);
420
472
  const bytes = globalThis.crypto?.getRandomValues(/* @__PURE__ */ new Uint8Array(16));
421
473
  if (bytes === void 0) return `t-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
422
474
  bytes[6] = bytes[6] & 15 | 64;
@@ -436,6 +488,7 @@ window.__ModuleLoader__.load({
436
488
  deps;
437
489
  tasks = [];
438
490
  boardOpen = false;
491
+ archiveView = false;
439
492
  selectedTaskId;
440
493
  executionOptions = {
441
494
  workspaces: [],
@@ -476,6 +529,7 @@ window.__ModuleLoader__.load({
476
529
  return {
477
530
  tasks: this.tasks,
478
531
  boardOpen: this.boardOpen,
532
+ archiveView: this.archiveView,
479
533
  selectedTaskId: this.selectedTaskId,
480
534
  executionOptions: this.executionOptions
481
535
  };
@@ -501,6 +555,18 @@ window.__ModuleLoader__.load({
501
555
  if (this.boardOpen) this.closeBoard();
502
556
  else this.openBoard();
503
557
  }
558
+ /**
559
+ * Switch between the kanban columns and the archive view. Leaving the
560
+ * archive view with an archived task still selected closes the selection —
561
+ * the detail overlay must not linger over a task that is off-board.
562
+ */
563
+ toggleArchiveView() {
564
+ this.archiveView = !this.archiveView;
565
+ if (!this.archiveView && this.selectedTaskId !== void 0) {
566
+ if (this.tasks.find((task) => task.id === this.selectedTaskId)?.archivedAt !== void 0) this.selectedTaskId = void 0;
567
+ }
568
+ this.notify();
569
+ }
504
570
  openTask(id) {
505
571
  if (this.tasks.some((task) => task.id === id)) {
506
572
  this.selectedTaskId = id;
@@ -545,6 +611,27 @@ window.__ModuleLoader__.load({
545
611
  this.persistAndNotify();
546
612
  }
547
613
  /**
614
+ * Archive a settled task (done/failed). Running or on-board-unsettled
615
+ * tasks are refused so the runner keeps exclusive ownership of their
616
+ * lifecycle.
617
+ * @returns true when applied.
618
+ */
619
+ archiveTask(id) {
620
+ const { tasks, archived } = applyArchiveTask(this.tasks, id, this.now());
621
+ if (!archived) return false;
622
+ this.tasks = [...tasks];
623
+ this.persistAndNotify();
624
+ return true;
625
+ }
626
+ /** Restore an archived task back onto the board (same status column). */
627
+ restoreTask(id) {
628
+ const { tasks, archived } = applyRestoreTask(this.tasks, id, this.now());
629
+ if (!archived) return false;
630
+ this.tasks = [...tasks];
631
+ this.persistAndNotify();
632
+ return true;
633
+ }
634
+ /**
548
635
  * Update a task's schedule rule. A blank or invalid cron expression is
549
636
  * rejected (returns false, state untouched). When the rule ends up enabled
550
637
  * the next run instant is computed immediately; a disabled rule carries no
@@ -571,6 +658,17 @@ window.__ModuleLoader__.load({
571
658
  this.persistAndNotify();
572
659
  }
573
660
  /**
661
+ * Reload the ledger from the persisted store without notifying subscribers.
662
+ * The scheduler calls this before every tick so a task deleted in another
663
+ * tab (or a stale in-memory copy) can never be fired from this tab: the
664
+ * fire decision and the subsequent roll-forward both run on the freshest
665
+ * persisted truth. Deliberately silent — same-origin external changes still
666
+ * reach subscribers through the storage-event subscription.
667
+ */
668
+ reloadFromStore() {
669
+ this.tasks = this.deps.store.load();
670
+ }
671
+ /**
574
672
  * Jump to an execution's session transcript. Selecting the session changes
575
673
  * `current`, which closes the board (the conversation view takes over).
576
674
  * @param sessionId - the execution session to open.
@@ -729,6 +827,15 @@ window.__ModuleLoader__.load({
729
827
  */
730
828
  var ExecutionService = class {
731
829
  env;
830
+ /**
831
+ * In-flight preset switches keyed by `sessionId\u0000mode`. The session
832
+ * list mirror can lag behind a just-applied switch, so concurrent runs
833
+ * against one blank session would otherwise each issue the same select
834
+ * RPC (an amplified storm); sharing one in-flight call keeps the wire to
835
+ * a single request. The settled entry is forgotten so a later run can
836
+ * switch again.
837
+ */
838
+ presetSwitches = /* @__PURE__ */ new Map();
732
839
  /** @param env - the runtime faces (real or fake). */
733
840
  constructor(env) {
734
841
  this.env = env;
@@ -785,12 +892,13 @@ window.__ModuleLoader__.load({
785
892
  return false;
786
893
  }
787
894
  if (summary?.agentPreset === mode) return true;
788
- if (this.env.presets === void 0) {
895
+ const presets = this.env.presets;
896
+ if (presets === void 0) {
789
897
  settleFailed(`this deployment does not support agent presets (task asks for ${mode})`);
790
898
  return false;
791
899
  }
792
900
  try {
793
- const result = await this.env.presets.select(sessionId, mode);
901
+ const result = await this.switchPreset(presets, sessionId, mode);
794
902
  if (!result.ok) {
795
903
  if (presetAlreadyRuns(result.error, mode)) {
796
904
  this.env.sessions.noteAgentPreset?.(sessionId, mode);
@@ -807,6 +915,22 @@ window.__ModuleLoader__.load({
807
915
  return true;
808
916
  }
809
917
  /**
918
+ * One in-flight `select` per (session, preset): concurrent runs against
919
+ * the same blank session share the same wire call instead of each issuing
920
+ * a duplicate RPC. The entry is removed once the call settles, so a later
921
+ * run (after a shared failure, say) issues a fresh switch.
922
+ */
923
+ switchPreset(presets, sessionId, mode) {
924
+ const key = `${sessionId}\u0000${mode}`;
925
+ const inflight = this.presetSwitches.get(key);
926
+ if (inflight !== void 0) return inflight;
927
+ const attempt = presets.select(sessionId, mode).finally(() => {
928
+ if (this.presetSwitches.get(key) === attempt) this.presetSwitches.delete(key);
929
+ });
930
+ this.presetSwitches.set(key, attempt);
931
+ return attempt;
932
+ }
933
+ /**
810
934
  * Apply the task-pinned permission preset through the `/permission <id>`
811
935
  * slash command. No-op when the task pins none; fails the run when the
812
936
  * admission is rejected or no command claimed the line.
@@ -969,6 +1093,11 @@ window.__ModuleLoader__.load({
969
1093
  * a task still running at its due instant is skipped by the controller's
970
1094
  * runTask guard and simply waits for the next cron match.
971
1095
  *
1096
+ * A deleted task can never fire again from a stale in-memory copy: every
1097
+ * tick first re-reads the persisted ledger through the optional `refresh`
1098
+ * hook (the controller reloads its store), so the fire decision and the
1099
+ * subsequent roll-forward both run on the freshest persisted truth.
1100
+ *
972
1101
  * The ticker is controlled: `start` arms a single interval guarded by an
973
1102
  * idempotence check (a second start while running is a no-op, so wiring can
974
1103
  * never leak a duplicate timer), and `stop`/`dispose` clear the timer and
@@ -1043,6 +1172,7 @@ window.__ModuleLoader__.load({
1043
1172
  async tick() {
1044
1173
  if (this.disposed) return;
1045
1174
  if (this.deps.ready !== void 0 && !this.deps.ready()) return;
1175
+ this.deps.refresh?.();
1046
1176
  const now = this.deps.now();
1047
1177
  for (const task of this.deps.tasks()) {
1048
1178
  const schedule = task.schedule;
@@ -1161,6 +1291,7 @@ window.__ModuleLoader__.load({
1161
1291
  task.schedule = normalizeSchedule(row.schedule);
1162
1292
  task.workspaceId = normalizeTargetId(row.workspaceId);
1163
1293
  task.mode = normalizeTargetId(row.mode);
1294
+ task.archivedAt = typeof row.archivedAt === "number" && Number.isFinite(row.archivedAt) ? row.archivedAt : void 0;
1164
1295
  task.permission = isTaskPermission(row.permission) ? row.permission : void 0;
1165
1296
  tasks.push(task);
1166
1297
  }
@@ -1255,11 +1386,15 @@ window.__ModuleLoader__.load({
1255
1386
  const zh = {
1256
1387
  "entry.label": "任务看板",
1257
1388
  "board.title": "任务看板",
1258
- "board.close": "返回对话",
1389
+ "board.close": "返回会话",
1259
1390
  "board.new": "新建任务",
1260
1391
  "board.search": "筛选任务…",
1261
1392
  "board.empty": "这个状态还没有任务",
1262
1393
  "board.filterAll": "全部",
1394
+ "board.archive": "归档",
1395
+ "board.archiveView": "归档 ({count})",
1396
+ "board.backToBoard": "返回看板",
1397
+ "archive.empty": "没有已归档的任务",
1263
1398
  "board.status": "状态",
1264
1399
  "board.status.backlog": "待规划",
1265
1400
  "board.status.todo": "待办",
@@ -1287,6 +1422,9 @@ window.__ModuleLoader__.load({
1287
1422
  "detail.run": "执行",
1288
1423
  "detail.rerun": "重新执行",
1289
1424
  "detail.delete": "删除",
1425
+ "detail.archive": "归档",
1426
+ "detail.restore": "恢复",
1427
+ "detail.archivedAt": "已归档 · {time}",
1290
1428
  "detail.viewSession": "查看会话",
1291
1429
  "detail.noSession": "暂无会话",
1292
1430
  "detail.executionStarted": "已启动",
@@ -1364,6 +1502,10 @@ window.__ModuleLoader__.load({
1364
1502
  "board.search": "Filter tasks…",
1365
1503
  "board.empty": "No tasks in this column",
1366
1504
  "board.filterAll": "All",
1505
+ "board.archive": "Archive",
1506
+ "board.archiveView": "Archived ({count})",
1507
+ "board.backToBoard": "Back to board",
1508
+ "archive.empty": "No archived tasks",
1367
1509
  "board.status": "Status",
1368
1510
  "board.status.backlog": "Backlog",
1369
1511
  "board.status.todo": "To Do",
@@ -1391,6 +1533,9 @@ window.__ModuleLoader__.load({
1391
1533
  "detail.run": "Run",
1392
1534
  "detail.rerun": "Run Again",
1393
1535
  "detail.delete": "Delete",
1536
+ "detail.archive": "Archive",
1537
+ "detail.restore": "Restore",
1538
+ "detail.archivedAt": "Archived · {time}",
1394
1539
  "detail.viewSession": "View Session",
1395
1540
  "detail.noSession": "No session",
1396
1541
  "detail.executionStarted": "Started",
@@ -1471,7 +1616,7 @@ window.__ModuleLoader__.load({
1471
1616
  }
1472
1617
  //#endregion
1473
1618
  //#region \0dsh-css:packages/dsh-task-board/src/client/board.module.css.mjs
1474
- 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}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{width:100%;height:32px;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 12px;font-size:13px;display:flex}._7D6uKa_entry:hover{background:var(--dsw-specific-sidebar-nav-item-hover);color:var(--dsw-alias-label-primary)}._7D6uKa_entry[data-active]{background:var(--dsw-specific-sidebar-nav-item-active);color:var(--dsw-alias-label-primary);font-weight:600}._7D6uKa_entryIcon{flex:none;justify-content:center;align-items:center;display:inline-flex}._7D6uKa_entryLabel{text-overflow:ellipsis;overflow:hidden}[data-dsh-frame][data-sidebar-collapsed] ._7D6uKa_entry{justify-content:center;width:100%;padding:0}[data-dsh-frame][data-sidebar-collapsed] ._7D6uKa_entryLabel{display:none}._7D6uKa_board{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_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{flex:1;grid-template-columns:repeat(5,minmax(0,1fr));gap:12px;min-height:0;display:grid}._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}._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}}";
1619
+ 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{width:100%;height:32px;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 12px;font-size:13px;display:flex}._7D6uKa_entry:hover{background:var(--dsw-specific-sidebar-nav-item-hover);color:var(--dsw-alias-label-primary)}._7D6uKa_entry[data-active]{background:var(--dsw-specific-sidebar-nav-item-active);color:var(--dsw-alias-label-primary);font-weight:600}._7D6uKa_entryIcon{flex:none;justify-content:center;align-items:center;display:inline-flex}._7D6uKa_entryLabel{text-overflow:ellipsis;overflow:hidden}[data-dsh-frame][data-sidebar-collapsed] ._7D6uKa_entry{justify-content:center;width:100%;padding:0}[data-dsh-frame][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<=720px){._7D6uKa_board{gap:10px;padding:10px}._7D6uKa_columns{gap:10px}}@container _7D6uKa_task-board-view (width<=600px){._7D6uKa_boardHeader{flex-wrap:wrap;gap:8px}._7D6uKa_search{flex:calc(100% - 72px);min-width:0}._7D6uKa_boardHeader>button{flex:1 1 0;min-width:max-content}}._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}}";
1475
1620
  const tagId$1 = "@linxin666/dsh-client-ui-task-board/board.module.css";
1476
1621
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
1477
1622
  const tag = document.createElement("style");
@@ -1481,6 +1626,7 @@ window.__ModuleLoader__.load({
1481
1626
  document.head.appendChild(tag);
1482
1627
  }
1483
1628
  var board_module_css_default = {
1629
+ "backButton": "_7D6uKa_backButton",
1484
1630
  "board": "_7D6uKa_board",
1485
1631
  "boardHeader": "_7D6uKa_boardHeader",
1486
1632
  "boardTitle": "_7D6uKa_boardTitle",
@@ -1543,9 +1689,31 @@ window.__ModuleLoader__.load({
1543
1689
  "search": "_7D6uKa_search",
1544
1690
  "select": "_7D6uKa_select",
1545
1691
  "statusBadge": "_7D6uKa_statusBadge",
1546
- "statusDot": "_7D6uKa_statusDot"
1692
+ "statusDot": "_7D6uKa_statusDot",
1693
+ "task-board-view": "_7D6uKa_task-board-view"
1547
1694
  };
1548
1695
  //#endregion
1696
+ //#region src/client/schedule-presets.ts
1697
+ /** Common scheduled-run presets (cron → locale label). */
1698
+ const SCHEDULE_PRESETS = [
1699
+ {
1700
+ cron: "0 9 * * *",
1701
+ label: "detail.schedule.preset.daily9"
1702
+ },
1703
+ {
1704
+ cron: "0 * * * *",
1705
+ label: "detail.schedule.preset.hourly"
1706
+ },
1707
+ {
1708
+ cron: "*/10 * * * *",
1709
+ label: "detail.schedule.preset.tenMin"
1710
+ },
1711
+ {
1712
+ cron: "0 9 * * 1",
1713
+ label: "detail.schedule.preset.weeklyMon9"
1714
+ }
1715
+ ];
1716
+ //#endregion
1549
1717
  //#region src/client/board/NewTaskModal.tsx
1550
1718
  /**
1551
1719
  * New-task modal: title + description + the prompt that execution will send.
@@ -1559,23 +1727,39 @@ window.__ModuleLoader__.load({
1559
1727
  const [workspaceId, setWorkspaceId] = (0, react.useState)("");
1560
1728
  const [mode, setMode] = (0, react.useState)("");
1561
1729
  const [permission, setPermission] = (0, react.useState)("");
1730
+ const [scheduleEnabled, setScheduleEnabled] = (0, react.useState)(false);
1731
+ const [scheduleCron, setScheduleCron] = (0, react.useState)("");
1732
+ const [scheduleError, setScheduleError] = (0, react.useState)(void 0);
1562
1733
  const [error, setError] = (0, react.useState)(void 0);
1563
1734
  const [options, setOptions] = (0, react.useState)(controller.getSnapshot().executionOptions);
1564
1735
  (0, react.useEffect)(() => controller.subscribe(() => setOptions(controller.getSnapshot().executionOptions)), [controller]);
1565
1736
  const submit = () => {
1737
+ if (scheduleEnabled) {
1738
+ const cron = scheduleCron.trim();
1739
+ if (cron === "" || !isValidCron(cron)) {
1740
+ setScheduleError(t("detail.schedule.invalid"));
1741
+ return;
1742
+ }
1743
+ }
1566
1744
  if (controller.createTask({
1567
1745
  title,
1568
1746
  description,
1569
1747
  prompt,
1570
1748
  workspaceId: workspaceId === "" ? void 0 : workspaceId,
1571
1749
  mode: mode === "" ? void 0 : mode,
1572
- permission: permission === "" ? void 0 : permission
1750
+ permission: permission === "" ? void 0 : permission,
1751
+ schedule: scheduleEnabled ? {
1752
+ enabled: true,
1753
+ cron: scheduleCron.trim()
1754
+ } : void 0
1573
1755
  }) === void 0) {
1574
1756
  setError(t("new.required"));
1575
1757
  return;
1576
1758
  }
1577
1759
  onClose();
1578
1760
  };
1761
+ /** Next-run preview for a valid armed cron (creation-time only). */
1762
+ const scheduleNextRun = scheduleEnabled && scheduleCron.trim() !== "" && isValidCron(scheduleCron) ? nextRunAtMs(scheduleCron, Date.now()) : void 0;
1579
1763
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1580
1764
  className: board_module_css_default.modalBackdrop,
1581
1765
  onMouseDown: (event) => {
@@ -1705,6 +1889,67 @@ window.__ModuleLoader__.load({
1705
1889
  }, id))]
1706
1890
  })]
1707
1891
  }),
1892
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
1893
+ className: board_module_css_default.detailSection,
1894
+ children: [
1895
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", { children: t("detail.schedule") }),
1896
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1897
+ className: board_module_css_default.scheduleToggle,
1898
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1899
+ type: "checkbox",
1900
+ checked: scheduleEnabled,
1901
+ onChange: (event) => {
1902
+ setScheduleEnabled(event.target.checked);
1903
+ if (!event.target.checked) setScheduleError(void 0);
1904
+ }
1905
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("detail.schedule.enable") })]
1906
+ }),
1907
+ scheduleEnabled && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
1908
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1909
+ className: board_module_css_default.scheduleRow,
1910
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1911
+ className: `${board_module_css_default.input} ${board_module_css_default.scheduleInput}${scheduleError !== void 0 ? ` ${board_module_css_default.scheduleInputInvalid}` : ""}`,
1912
+ value: scheduleCron,
1913
+ placeholder: "0 9 * * *",
1914
+ spellCheck: false,
1915
+ "aria-label": t("detail.schedule.cron"),
1916
+ onChange: (event) => {
1917
+ setScheduleCron(event.target.value);
1918
+ setScheduleError(void 0);
1919
+ }
1920
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
1921
+ className: board_module_css_default.schedulePreset,
1922
+ value: "",
1923
+ "aria-label": t("detail.schedule.presets"),
1924
+ onChange: (event) => {
1925
+ if (event.target.value === "") return;
1926
+ setScheduleCron(event.target.value);
1927
+ setScheduleError(void 0);
1928
+ },
1929
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("option", {
1930
+ value: "",
1931
+ children: [t("detail.schedule.presets"), "…"]
1932
+ }), SCHEDULE_PRESETS.map((preset) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1933
+ value: preset.cron,
1934
+ children: t(preset.label)
1935
+ }, preset.cron))]
1936
+ })]
1937
+ }),
1938
+ scheduleError !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1939
+ className: board_module_css_default.formError,
1940
+ children: scheduleError
1941
+ }),
1942
+ scheduleError === void 0 && scheduleNextRun !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
1943
+ className: board_module_css_default.scheduleMeta,
1944
+ children: [
1945
+ t("detail.schedule.nextRun"),
1946
+ " ",
1947
+ new Date(scheduleNextRun).toLocaleString()
1948
+ ]
1949
+ })
1950
+ ] })
1951
+ ]
1952
+ }),
1708
1953
  error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1709
1954
  className: board_module_css_default.formError,
1710
1955
  children: error
@@ -1912,25 +2157,6 @@ window.__ModuleLoader__.load({
1912
2157
  ]
1913
2158
  });
1914
2159
  }
1915
- /** Common scheduled-run presets (cron → locale label). */
1916
- const SCHEDULE_PRESETS = [
1917
- {
1918
- cron: "0 9 * * *",
1919
- label: "detail.schedule.preset.daily9"
1920
- },
1921
- {
1922
- cron: "0 * * * *",
1923
- label: "detail.schedule.preset.hourly"
1924
- },
1925
- {
1926
- cron: "*/10 * * * *",
1927
- label: "detail.schedule.preset.tenMin"
1928
- },
1929
- {
1930
- cron: "0 9 * * 1",
1931
- label: "detail.schedule.preset.weeklyMon9"
1932
- }
1933
- ];
1934
2160
  /** The execution-target editor: workspace / mode / permission pickers. */
1935
2161
  function ExecutionSettingsSection({ controller, task }) {
1936
2162
  const [options, setOptions] = (0, react.useState)(controller.getSnapshot().executionOptions);
@@ -2260,6 +2486,23 @@ window.__ModuleLoader__.load({
2260
2486
  },
2261
2487
  children: current.executions.length === 0 ? t("detail.run") : t("detail.rerun")
2262
2488
  }),
2489
+ current.archivedAt !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2490
+ type: "button",
2491
+ className: board_module_css_default.primaryButton,
2492
+ onClick: () => {
2493
+ controller.restoreTask(current.id);
2494
+ controller.closeTask();
2495
+ },
2496
+ children: t("detail.restore")
2497
+ }) : (current.status === "done" || current.status === "failed") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2498
+ type: "button",
2499
+ className: board_module_css_default.ghostButton,
2500
+ onClick: () => {
2501
+ controller.archiveTask(current.id);
2502
+ controller.closeTask();
2503
+ },
2504
+ children: t("detail.archive")
2505
+ }),
2263
2506
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2264
2507
  type: "button",
2265
2508
  className: board_module_css_default.dangerButton,
@@ -2273,7 +2516,8 @@ window.__ModuleLoader__.load({
2273
2516
  children: [
2274
2517
  t("board.created"),
2275
2518
  " ",
2276
- formatTime(current.createdAt)
2519
+ formatTime(current.createdAt),
2520
+ current.archivedAt !== void 0 && ` · ${t("detail.archivedAt", { time: formatTime(current.archivedAt) })}`
2277
2521
  ]
2278
2522
  })
2279
2523
  ]
@@ -2337,7 +2581,8 @@ window.__ModuleLoader__.load({
2337
2581
  const [filter, setFilter] = (0, react.useState)("");
2338
2582
  const [showNew, setShowNew] = (0, react.useState)(false);
2339
2583
  const selected = selectedTaskOf(snapshot);
2340
- const visible = snapshot.tasks.filter((task) => matchesFilter(task, filter));
2584
+ const archiveView = snapshot.archiveView;
2585
+ const visible = snapshot.tasks.filter((task) => (archiveView ? task.archivedAt !== void 0 : task.archivedAt === void 0) && matchesFilter(task, filter));
2341
2586
  const openTask = (0, react.useCallback)((id) => {
2342
2587
  controller.openTask(id);
2343
2588
  }, [controller]);
@@ -2348,6 +2593,18 @@ window.__ModuleLoader__.load({
2348
2593
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
2349
2594
  className: board_module_css_default.boardHeader,
2350
2595
  children: [
2596
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2597
+ type: "button",
2598
+ className: `${board_module_css_default.ghostButton} ${board_module_css_default.backButton}`,
2599
+ "aria-label": t("board.close"),
2600
+ onClick: () => {
2601
+ controller.closeBoard();
2602
+ },
2603
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2604
+ "aria-hidden": "true",
2605
+ children: "‹"
2606
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("board.close") })]
2607
+ }),
2351
2608
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
2352
2609
  className: board_module_css_default.boardTitle,
2353
2610
  children: t("board.title")
@@ -2362,27 +2619,49 @@ window.__ModuleLoader__.load({
2362
2619
  },
2363
2620
  "aria-label": t("board.search")
2364
2621
  }),
2365
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2622
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2366
2623
  type: "button",
2367
- className: board_module_css_default.primaryButton,
2624
+ className: archiveView ? board_module_css_default.primaryButton : board_module_css_default.ghostButton,
2368
2625
  onClick: () => {
2369
- setShowNew(true);
2626
+ controller.toggleArchiveView();
2370
2627
  },
2371
- children: ["+ ", t("board.new")]
2628
+ children: archiveView ? t("board.backToBoard") : t("board.archiveView", { count: String(snapshot.tasks.filter((task) => task.archivedAt !== void 0).length) })
2372
2629
  }),
2373
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2630
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2374
2631
  type: "button",
2375
- className: board_module_css_default.ghostButton,
2632
+ className: board_module_css_default.primaryButton,
2376
2633
  onClick: () => {
2377
- controller.closeBoard();
2634
+ setShowNew(true);
2378
2635
  },
2379
- children: t("board.close")
2636
+ children: ["+ ", t("board.new")]
2380
2637
  })
2381
2638
  ]
2382
2639
  }),
2383
2640
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2384
2641
  className: board_module_css_default.columns,
2385
- children: COLUMNS.map((column) => {
2642
+ children: archiveView ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
2643
+ className: board_module_css_default.column,
2644
+ "data-status": "archived",
2645
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
2646
+ className: board_module_css_default.columnHeader,
2647
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
2648
+ className: board_module_css_default.columnTitle,
2649
+ children: t("board.archive")
2650
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2651
+ className: board_module_css_default.columnCount,
2652
+ children: visible.length
2653
+ })]
2654
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2655
+ className: board_module_css_default.cards,
2656
+ children: [visible.map((task) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoTaskCard, {
2657
+ task,
2658
+ onOpen: openTask
2659
+ }, task.id)), visible.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2660
+ className: board_module_css_default.columnEmpty,
2661
+ children: t("archive.empty")
2662
+ })]
2663
+ })]
2664
+ }) : COLUMNS.map((column) => {
2386
2665
  const tasks = visible.filter((task) => task.status === column.status);
2387
2666
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
2388
2667
  className: board_module_css_default.column,
@@ -2622,7 +2901,7 @@ window.__ModuleLoader__.load({
2622
2901
  }
2623
2902
  //#endregion
2624
2903
  //#region \0dsh-css:packages/dsh-task-board/src/client/settings-card.module.css.mjs
2625
- const css = ".Jh0q7G_card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none;transition:border-color .16s,background .16s}.Jh0q7G_card:hover{border-color:var(--dsw-alias-label-dimmed)}.Jh0q7G_cardOpen{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}.Jh0q7G_header{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}.Jh0q7G_header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.Jh0q7G_headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.Jh0q7G_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.Jh0q7G_description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.Jh0q7G_pending{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.Jh0q7G_chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.Jh0q7G_chevronOpen{transform:rotate(180deg)}.Jh0q7G_body{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding-bottom:8px}.Jh0q7G_readOnly{color:var(--dsw-alias-label-tertiary);margin:12px 0 0;font-size:12px;line-height:1.5}.Jh0q7G_notExposed{color:var(--dsw-alias-state-warn-primary);margin:12px 0 0;font-size:12px;line-height:1.5}.Jh0q7G_footer{border-top:1px solid var(--dsw-alias-border-l2);justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}.Jh0q7G_failed{min-width:0;color:var(--dsw-alias-label-error);text-overflow:ellipsis;white-space:nowrap;flex:1;margin:0;font-size:12px;line-height:1.5;overflow:hidden}.Jh0q7G_discard,.Jh0q7G_save{appearance:none;font:inherit;cursor:pointer;border:1px solid #0000;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}.Jh0q7G_discard{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0}.Jh0q7G_discard:hover:not(:disabled){color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}.Jh0q7G_save{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}.Jh0q7G_discard:disabled,.Jh0q7G_save:disabled{opacity:.4;cursor:default}.Jh0q7G_discard:focus-visible,.Jh0q7G_save:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.Jh0q7G_field{flex-direction:column;gap:6px;padding:12px 0;display:flex}.Jh0q7G_field+.Jh0q7G_field{border-top:1px solid var(--dsw-alias-border-l2)}.Jh0q7G_head{align-items:center;gap:8px;display:flex}.Jh0q7G_label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}.Jh0q7G_badges{align-items:center;gap:8px;display:inline-flex}.Jh0q7G_badge{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.Jh0q7G_reset{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}.Jh0q7G_reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.Jh0q7G_reset:disabled{cursor:default}.Jh0q7G_reset:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px;outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.Jh0q7G_input,.Jh0q7G_select{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.Jh0q7G_input:focus-visible,.Jh0q7G_select:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}.Jh0q7G_input:disabled,.Jh0q7G_select:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.Jh0q7G_inputInvalid{border:1px solid var(--dsw-alias-label-error);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.Jh0q7G_inputInvalid:focus-visible{outline:2px solid var(--dsw-alias-label-error);outline-offset:1px;border-color:var(--dsw-alias-label-error)}.Jh0q7G_invalid{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}.Jh0q7G_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}@media (prefers-reduced-motion:reduce){.Jh0q7G_card,.Jh0q7G_header,.Jh0q7G_chevron,.Jh0q7G_chevronOpen,.Jh0q7G_discard,.Jh0q7G_save{transition:none}}";
2904
+ const css = ".Jh0q7G_card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none;transition:border-color .16s,background .16s}.Jh0q7G_card:hover{border-color:var(--dsw-alias-label-dimmed)}.Jh0q7G_cardOpen{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}.Jh0q7G_header{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}.Jh0q7G_header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.Jh0q7G_headerStatic{border-radius:12px;align-items:center;gap:12px;width:100%;padding:14px 16px;display:flex}.Jh0q7G_headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.Jh0q7G_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.Jh0q7G_description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.Jh0q7G_pending{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.Jh0q7G_chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.Jh0q7G_chevronOpen{transform:rotate(180deg)}.Jh0q7G_body{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding-bottom:8px}.Jh0q7G_readOnly{color:var(--dsw-alias-label-tertiary);margin:12px 0 0;font-size:12px;line-height:1.5}.Jh0q7G_notExposed{color:var(--dsw-alias-state-warn-primary);margin:12px 0 0;font-size:12px;line-height:1.5}.Jh0q7G_footer{border-top:1px solid var(--dsw-alias-border-l2);justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}.Jh0q7G_failed{min-width:0;color:var(--dsw-alias-label-error);text-overflow:ellipsis;white-space:nowrap;flex:1;margin:0;font-size:12px;line-height:1.5;overflow:hidden}.Jh0q7G_discard,.Jh0q7G_save{appearance:none;font:inherit;cursor:pointer;border:1px solid #0000;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}.Jh0q7G_discard{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0}.Jh0q7G_discard:hover:not(:disabled){color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}.Jh0q7G_save{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}.Jh0q7G_discard:disabled,.Jh0q7G_save:disabled{opacity:.4;cursor:default}.Jh0q7G_discard:focus-visible,.Jh0q7G_save:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.Jh0q7G_field{flex-direction:column;gap:6px;padding:12px 0;display:flex}.Jh0q7G_field+.Jh0q7G_field{border-top:1px solid var(--dsw-alias-border-l2)}.Jh0q7G_head{align-items:center;gap:8px;display:flex}.Jh0q7G_label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}.Jh0q7G_badges{align-items:center;gap:8px;display:inline-flex}.Jh0q7G_badge{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.Jh0q7G_reset{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}.Jh0q7G_reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.Jh0q7G_reset:disabled{cursor:default}.Jh0q7G_reset:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px;outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.Jh0q7G_input,.Jh0q7G_select{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.Jh0q7G_input:focus-visible,.Jh0q7G_select:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}.Jh0q7G_input:disabled,.Jh0q7G_select:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.Jh0q7G_inputInvalid{border:1px solid var(--dsw-alias-label-error);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.Jh0q7G_inputInvalid:focus-visible{outline:2px solid var(--dsw-alias-label-error);outline-offset:1px;border-color:var(--dsw-alias-label-error)}.Jh0q7G_invalid{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}.Jh0q7G_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}@media (prefers-reduced-motion:reduce){.Jh0q7G_card,.Jh0q7G_header,.Jh0q7G_chevron,.Jh0q7G_chevronOpen,.Jh0q7G_discard,.Jh0q7G_save{transition:none}}";
2626
2905
  const tagId = "@linxin666/dsh-client-ui-task-board/settings-card.module.css";
2627
2906
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
2628
2907
  const tag = document.createElement("style");
@@ -2647,6 +2926,7 @@ window.__ModuleLoader__.load({
2647
2926
  "head": "Jh0q7G_head",
2648
2927
  "headText": "Jh0q7G_headText",
2649
2928
  "header": "Jh0q7G_header",
2929
+ "headerStatic": "Jh0q7G_headerStatic",
2650
2930
  "hint": "Jh0q7G_hint",
2651
2931
  "input": "Jh0q7G_input",
2652
2932
  "inputInvalid": "Jh0q7G_inputInvalid",
@@ -2676,24 +2956,42 @@ window.__ModuleLoader__.load({
2676
2956
  * @returns the card, or nothing while the namespace is still loading.
2677
2957
  */
2678
2958
  function PluginSettingsCard(props) {
2679
- const [open, setOpen] = (0, react.useState)(false);
2680
- const { state } = props;
2959
+ const [open, setOpen] = (0, react.useState)(props.defaultOpen ?? true);
2960
+ const { state, alwaysOpen } = props;
2681
2961
  if (!state.available) return null;
2682
2962
  const title = props.t(props.titleKey);
2683
2963
  const description = props.t(props.descriptionKey);
2684
2964
  const blocked = !state.dirty || state.invalid || state.saving;
2685
- const cardClass = open ? `${settings_card_module_css_default.cardOpen} ${settings_card_module_css_default.card}` : settings_card_module_css_default.card;
2686
- if (!state.exposed) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
2687
- className: cardClass,
2688
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2689
- type: "button",
2690
- className: settings_card_module_css_default.header,
2691
- "aria-expanded": open,
2692
- "aria-label": `${props.t(open ? "settings.collapse" : "settings.expand")}: ${title}`,
2693
- onClick: () => {
2694
- setOpen(!open);
2695
- },
2696
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2965
+ const expanded = alwaysOpen === true || open;
2966
+ const cardClass = expanded ? `${settings_card_module_css_default.cardOpen} ${settings_card_module_css_default.card}` : settings_card_module_css_default.card;
2967
+ const header = alwaysOpen === true ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2968
+ className: settings_card_module_css_default.headerStatic,
2969
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2970
+ className: settings_card_module_css_default.headText,
2971
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2972
+ className: settings_card_module_css_default.name,
2973
+ title,
2974
+ children: title
2975
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2976
+ className: settings_card_module_css_default.description,
2977
+ title: description,
2978
+ children: description
2979
+ })]
2980
+ }), state.dirty ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2981
+ className: settings_card_module_css_default.pending,
2982
+ title: props.t("settings.unsaved"),
2983
+ children: props.t("settings.unsaved")
2984
+ }) : null]
2985
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2986
+ type: "button",
2987
+ className: settings_card_module_css_default.header,
2988
+ "aria-expanded": open,
2989
+ "aria-label": `${props.t(open ? "settings.collapse" : "settings.expand")}: ${title}`,
2990
+ onClick: () => {
2991
+ setOpen(!open);
2992
+ },
2993
+ children: [
2994
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2697
2995
  className: settings_card_module_css_default.headText,
2698
2996
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2699
2997
  className: settings_card_module_css_default.name,
@@ -2704,7 +3002,13 @@ window.__ModuleLoader__.load({
2704
3002
  title: description,
2705
3003
  children: description
2706
3004
  })]
2707
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
3005
+ }),
3006
+ state.dirty ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3007
+ className: settings_card_module_css_default.pending,
3008
+ title: props.t("settings.unsaved"),
3009
+ children: props.t("settings.unsaved")
3010
+ }) : null,
3011
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
2708
3012
  width: "14",
2709
3013
  height: "14",
2710
3014
  viewBox: "0 0 14 14",
@@ -2715,8 +3019,12 @@ window.__ModuleLoader__.load({
2715
3019
  d: "M11.8486 5.5L11.4238 5.92383L8.69727 8.65137C8.44157 8.90706 8.21562 9.13382 8.01172 9.29785C7.79912 9.46883 7.55595 9.61756 7.25 9.66602C7.08435 9.69222 6.91565 9.69222 6.75 9.66602C6.44405 9.61756 6.20088 9.46883 5.98828 9.29785C5.78438 9.13382 5.55843 8.90706 5.30273 8.65137L2.57617 5.92383L2.15137 5.5L3 4.65137L3.42383 5.07617L6.15137 7.80273C6.42595 8.07732 6.59876 8.24849 6.74023 8.3623C6.87291 8.46904 6.92272 8.47813 6.9375 8.48047C6.97895 8.48703 7.02105 8.48703 7.0625 8.48047C7.07728 8.47813 7.12709 8.46904 7.25977 8.3623C7.40124 8.24849 7.57405 8.07732 7.84863 7.80273L10.5762 5.07617L11 4.65137L11.8486 5.5Z",
2716
3020
  fill: "currentColor"
2717
3021
  })
2718
- })]
2719
- }), open ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3022
+ })
3023
+ ]
3024
+ });
3025
+ if (!state.exposed) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
3026
+ className: cardClass,
3027
+ children: [header, expanded ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2720
3028
  className: settings_card_module_css_default.body,
2721
3029
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2722
3030
  className: settings_card_module_css_default.notExposed,
@@ -2727,46 +3035,7 @@ window.__ModuleLoader__.load({
2727
3035
  });
2728
3036
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
2729
3037
  className: cardClass,
2730
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2731
- type: "button",
2732
- className: settings_card_module_css_default.header,
2733
- "aria-expanded": open,
2734
- "aria-label": `${props.t(open ? "settings.collapse" : "settings.expand")}: ${title}`,
2735
- onClick: () => {
2736
- setOpen(!open);
2737
- },
2738
- children: [
2739
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2740
- className: settings_card_module_css_default.headText,
2741
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2742
- className: settings_card_module_css_default.name,
2743
- title,
2744
- children: title
2745
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2746
- className: settings_card_module_css_default.description,
2747
- title: description,
2748
- children: description
2749
- })]
2750
- }),
2751
- state.dirty ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2752
- className: settings_card_module_css_default.pending,
2753
- title: props.t("settings.unsaved"),
2754
- children: props.t("settings.unsaved")
2755
- }) : null,
2756
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
2757
- width: "14",
2758
- height: "14",
2759
- viewBox: "0 0 14 14",
2760
- fill: "none",
2761
- xmlns: "http://www.w3.org/2000/svg",
2762
- className: open ? `${settings_card_module_css_default.chevron} ${settings_card_module_css_default.chevronOpen}` : settings_card_module_css_default.chevron,
2763
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
2764
- d: "M11.8486 5.5L11.4238 5.92383L8.69727 8.65137C8.44157 8.90706 8.21562 9.13382 8.01172 9.29785C7.79912 9.46883 7.55595 9.61756 7.25 9.66602C7.08435 9.69222 6.91565 9.69222 6.75 9.66602C6.44405 9.61756 6.20088 9.46883 5.98828 9.29785C5.78438 9.13382 5.55843 8.90706 5.30273 8.65137L2.57617 5.92383L2.15137 5.5L3 4.65137L3.42383 5.07617L6.15137 7.80273C6.42595 8.07732 6.59876 8.24849 6.74023 8.3623C6.87291 8.46904 6.92272 8.47813 6.9375 8.48047C6.97895 8.48703 7.02105 8.48703 7.0625 8.48047C7.07728 8.47813 7.12709 8.46904 7.25977 8.3623C7.40124 8.24849 7.57405 8.07732 7.84863 7.80273L10.5762 5.07617L11 4.65137L11.8486 5.5Z",
2765
- fill: "currentColor"
2766
- })
2767
- })
2768
- ]
2769
- }), open ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3038
+ children: [header, expanded ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2770
3039
  className: settings_card_module_css_default.body,
2771
3040
  children: [
2772
3041
  !state.writable ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
@@ -2892,6 +3161,9 @@ window.__ModuleLoader__.load({
2892
3161
  specs;
2893
3162
  staged = /* @__PURE__ */ new Map();
2894
3163
  listeners = /* @__PURE__ */ new Set();
3164
+ /** The scope subscription installed in the constructor; released by dispose(). */
3165
+ disposeScope;
3166
+ disposed = false;
2895
3167
  saving = false;
2896
3168
  failed = false;
2897
3169
  failedReason;
@@ -2899,10 +3171,20 @@ window.__ModuleLoader__.load({
2899
3171
  constructor(scope, specs) {
2900
3172
  this.scope = scope;
2901
3173
  this.specs = new Map(specs.map((spec) => [spec.field, spec]));
2902
- scope.subscribe(() => {
3174
+ this.disposeScope = scope.subscribe(() => {
2903
3175
  this.publish();
2904
3176
  });
2905
3177
  }
3178
+ /**
3179
+ * Release the scope subscription and every bound store listener. The card
3180
+ * must call this on teardown; later calls are no-ops.
3181
+ */
3182
+ dispose() {
3183
+ if (this.disposed) return;
3184
+ this.disposed = true;
3185
+ this.disposeScope();
3186
+ this.listeners.clear();
3187
+ }
2906
3188
  /** Publish a projection of this form, rebuilt whenever the scope or a draft changes. */
2907
3189
  bind(project) {
2908
3190
  const store = (0, _deepseek_ai_dsh_client_runtime_client.createSnapshotStore)(project());
@@ -3128,6 +3410,13 @@ window.__ModuleLoader__.load({
3128
3410
  ...this.form.actions()
3129
3411
  };
3130
3412
  }
3413
+ /**
3414
+ * Release the card's scope subscription and bound stores; the slot
3415
+ * disposer calls this on teardown.
3416
+ */
3417
+ dispose() {
3418
+ this.form.dispose();
3419
+ }
3131
3420
  };
3132
3421
  /**
3133
3422
  * Render the task-board card.
@@ -3213,13 +3502,19 @@ window.__ModuleLoader__.load({
3213
3502
  }), "task-board: dictionaries");
3214
3503
  const settingsScope = (ctx.get("webUiSettings") ?? ctx.settingsScope).bind({ namespace: TASK_BOARD_NS });
3215
3504
  const settingsCard = new TaskBoardSettingsCardController(settingsScope);
3216
- ctx.slots.inject("web-ui.plugin.item", () => ctx.slots.register({
3217
- name: "web-ui.plugin.item",
3218
- id: "task-board",
3219
- order: 110,
3220
- locale: NS,
3221
- inject: () => settingsCard.inject()
3222
- }, TaskBoardSettingsCard));
3505
+ ctx.slots.inject("web-ui.plugin.item", () => {
3506
+ const unregister = ctx.slots.register({
3507
+ name: "web-ui.plugin.item",
3508
+ id: "task-board",
3509
+ order: 110,
3510
+ locale: NS,
3511
+ inject: () => settingsCard.inject()
3512
+ }, TaskBoardSettingsCard);
3513
+ return () => {
3514
+ settingsCard.dispose();
3515
+ unregister();
3516
+ };
3517
+ });
3223
3518
  let uiDisposer;
3224
3519
  const mountUi = () => {
3225
3520
  if (uiDisposer !== void 0) return;
@@ -3291,6 +3586,7 @@ window.__ModuleLoader__.load({
3291
3586
  controller.start();
3292
3587
  const scheduler = new SchedulerService({
3293
3588
  tasks: () => controller.getSnapshot().tasks,
3589
+ refresh: () => controller.reloadFromStore(),
3294
3590
  now: () => Date.now(),
3295
3591
  runTask: (id) => controller.runTask(id),
3296
3592
  applySchedule: (id, nextRunAt, lastTriggeredAt) => controller.applyScheduleNextRun(id, nextRunAt, lastTriggeredAt),