dsh-taskboard 0.5.3 → 0.5.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -161,6 +161,10 @@ window.__ModuleLoader__.load({
161
161
  function defaultIsolationOf(settings) {
162
162
  return settings?.defaultIsolation ?? "none";
163
163
  }
164
+ /** The effective external session sync switch (board setting → factory default false). */
165
+ function defaultSyncExternalSessionsOf(settings) {
166
+ return settings?.syncExternalSessions ?? false;
167
+ }
164
168
  /**
165
169
  * Parse a five-field cron expression. Supported field syntax: star, star/step
166
170
  * (`* / n` without spaces), a single number, an `a-b` range, and comma lists
@@ -275,7 +279,7 @@ window.__ModuleLoader__.load({
275
279
  sortBy: "default"
276
280
  };
277
281
  const parsed = JSON.parse(raw);
278
- const sortBy = parsed.sortBy === "updated" || parsed.sortBy === "urgency" || parsed.sortBy === "created" ? parsed.sortBy : "default";
282
+ const sortBy = parsed.sortBy === "updated" || parsed.sortBy === "urgency" || parsed.sortBy === "created" || parsed.sortBy === "title" ? parsed.sortBy : "default";
279
283
  return {
280
284
  workspaceId: typeof parsed.workspaceId === "string" ? parsed.workspaceId : void 0,
281
285
  urgencies: Array.isArray(parsed.urgencies) ? parsed.urgencies.filter((u) => u === "urgent" || u === "normal" || u === "relaxed") : [],
@@ -1053,8 +1057,43 @@ window.__ModuleLoader__.load({
1053
1057
  .dsh-atb-spacer { flex: 1; }
1054
1058
  .dsh-atb-select, .dsh-atb-input {
1055
1059
  font: inherit; font-size: 12.5px; padding: 5px 8px; border-radius: 7px;
1056
- border: 1px solid var(--dsw-border, rgba(128,128,128,.35));
1057
- background: var(--dsw-bg, transparent); color: inherit;
1060
+ border: 1px solid var(--dsw-border, var(--dsw-alias-border-l2, rgba(128,128,128,.35)));
1061
+ background: var(--dsw-alias-bg-module-platform, var(--dsw-bg-elevated, var(--dsw-bg, transparent)));
1062
+ color: var(--dsw-alias-label-primary, var(--dsw-text-primary, inherit));
1063
+ color-scheme: light dark;
1064
+ }
1065
+ .dsh-atb-select option,
1066
+ .dsh-atb-modal-body select option {
1067
+ background: var(--dsw-alias-bg-overlay, var(--dsw-alias-bg-module-platform, #252830));
1068
+ color: var(--dsw-alias-label-primary, var(--dsw-text-primary, #e6e8eb));
1069
+ }
1070
+ body[data-ds-dark-theme] .dsh-atb-board,
1071
+ body[data-ds-dark-theme] .dsh-atb-modal,
1072
+ body[data-ds-dark-theme] .dsh-atb-select,
1073
+ body[data-ds-dark-theme] .dsh-atb-input,
1074
+ body[data-ds-dark-theme] .dsh-atb-modal-body select,
1075
+ body[data-ds-dark-theme] .dsh-atb-modal-body input,
1076
+ body[data-ds-dark-theme] .dsh-atb-modal-body textarea {
1077
+ color-scheme: dark;
1078
+ }
1079
+ body[data-ds-dark-theme] .dsh-atb-select option,
1080
+ body[data-ds-dark-theme] .dsh-atb-modal-body select option {
1081
+ background: #252830;
1082
+ color: #e6e8eb;
1083
+ }
1084
+ @media (prefers-color-scheme: dark) {
1085
+ .dsh-atb-select,
1086
+ .dsh-atb-input,
1087
+ .dsh-atb-modal-body select,
1088
+ .dsh-atb-modal-body input,
1089
+ .dsh-atb-modal-body textarea {
1090
+ color-scheme: dark;
1091
+ }
1092
+ .dsh-atb-select option,
1093
+ .dsh-atb-modal-body select option {
1094
+ background: #252830;
1095
+ color: #e6e8eb;
1096
+ }
1058
1097
  }
1059
1098
  .dsh-atb-chip {
1060
1099
  display: inline-flex; align-items: center; gap: 5px;
@@ -1130,6 +1169,19 @@ window.__ModuleLoader__.load({
1130
1169
  .dsh-atb-badge[data-kind="trashed"] { background: rgba(229,72,77,.14); color: #e5484d; text-decoration: line-through; }
1131
1170
  .dsh-atb-badge[data-kind="done"] { background: rgba(46,160,67,.16); color: #2ea043; }
1132
1171
  .dsh-atb-badge[data-kind="running"] { background: rgba(229,152,42,.16); color: #e69842; }
1172
+ .dsh-atb-card-session {
1173
+ font: inherit; font-size: 10.5px; line-height: 1; padding: 2px 6px; border-radius: 5px;
1174
+ border: 1px solid var(--dsw-border, rgba(128,128,128,.3));
1175
+ background: var(--dsw-bg-elevated, rgba(128,128,128,.14));
1176
+ color: var(--dsw-text-secondary, inherit);
1177
+ cursor: pointer; display: inline-flex; align-items: center; gap: 3px;
1178
+ transition: all .15s ease;
1179
+ }
1180
+ .dsh-atb-card-session:hover {
1181
+ border-color: var(--dsw-alias-brand-primary, #1f2328);
1182
+ background: var(--dsw-hover, rgba(128,128,128,.24));
1183
+ color: var(--dsw-alias-label-primary, inherit);
1184
+ }
1133
1185
 
1134
1186
  /* ---------- card quick review (in_review column) ---------- */
1135
1187
  .dsh-atb-quick { display: flex; gap: 6px; margin-top: 7px; }
@@ -1177,6 +1229,17 @@ window.__ModuleLoader__.load({
1177
1229
  background: var(--dsw-bg-elevated, rgba(128,128,128,.07)); color: var(--dsw-text-secondary, inherit);
1178
1230
  }
1179
1231
  .dsh-atb-detail-edit:hover { border-color: var(--dsw-alias-brand-primary, #1f2328); color: var(--dsw-alias-label-primary, inherit); }
1232
+ .dsh-atb-detail-session {
1233
+ font: inherit; font-size: 12px; padding: 4px 10px; border-radius: 7px; cursor: pointer;
1234
+ border: 1px solid var(--dsw-border, rgba(128,128,128,.32));
1235
+ background: var(--dsw-bg-elevated, rgba(128,128,128,.1));
1236
+ color: var(--dsw-alias-label-primary, inherit);
1237
+ display: inline-flex; align-items: center; gap: 4px;
1238
+ }
1239
+ .dsh-atb-detail-session:hover {
1240
+ border-color: var(--dsw-alias-brand-primary, #1f2328);
1241
+ background: var(--dsw-hover, rgba(128,128,128,.22));
1242
+ }
1180
1243
 
1181
1244
  .dsh-atb-statuspill {
1182
1245
  flex: none; font-size: 11px; font-weight: 600; padding: 2px 9px; border-radius: 999px; letter-spacing: .02em;
@@ -1194,6 +1257,14 @@ window.__ModuleLoader__.load({
1194
1257
  padding: 3px 8px; border-radius: 6px;
1195
1258
  background: var(--dsw-bg-inset, rgba(128,128,128,.09)); color: var(--dsw-text-secondary, #999);
1196
1259
  }
1260
+ button.dsh-atb-chip2.dsh-atb-chip-btn {
1261
+ font: inherit; border: 1px solid var(--dsw-border, rgba(128,128,128,.25)); cursor: pointer;
1262
+ }
1263
+ button.dsh-atb-chip2.dsh-atb-chip-btn:hover {
1264
+ border-color: var(--dsw-alias-brand-primary, #1f2328);
1265
+ color: var(--dsw-alias-label-primary, inherit);
1266
+ background: var(--dsw-hover, rgba(128,128,128,.2));
1267
+ }
1197
1268
  .dsh-atb-chip2-icon { font-size: 10.5px; opacity: .85; }
1198
1269
  .dsh-atb-chip2[data-tone="urgent"] { background: rgba(229,72,77,.15); color: #e5484d; }
1199
1270
  .dsh-atb-chip2[data-tone="normal"] { background: rgba(142,78,198,.14); color: #a06ce0; }
@@ -1607,19 +1678,30 @@ window.__ModuleLoader__.load({
1607
1678
  .dsh-atb-newmenu-opt:hover { background: var(--dsw-alias-bg-layer-2, rgba(128,128,128,.1)); }
1608
1679
  .dsh-atb-newmenu-sep { height: 1px; margin: 4px 6px; background: var(--dsw-alias-border-l2, rgba(128,128,128,.25)); }
1609
1680
 
1610
- .dsh-atb-tplm { max-width: 560px; width: min(560px, 92vw); }
1611
- .dsh-atb-tplm-list { display: flex; flex-direction: column; gap: 8px; }
1681
+ .dsh-atb-tplm { max-width: 600px; width: min(600px, 92vw); }
1682
+ .dsh-atb-tplm .dsh-atb-modal-body,
1683
+ .dsh-atb-set .dsh-atb-modal-body,
1684
+ .dsh-atb-diag .dsh-atb-modal-body,
1685
+ .dsh-atb-imp .dsh-atb-modal-body {
1686
+ display: flex; flex-direction: column; gap: 10px;
1687
+ }
1688
+ .dsh-atb-tplm-list { display: flex; flex-direction: column; gap: 8px; width: 100%; }
1612
1689
  .dsh-atb-tplm-row {
1613
- display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: 8px;
1690
+ display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 8px 12px; border-radius: 8px;
1614
1691
  border: 1px solid var(--dsw-alias-border-l2, rgba(128,128,128,.25));
1692
+ background: var(--dsw-alias-bg-layer-1, rgba(128,128,128,.02));
1615
1693
  }
1616
1694
  .dsh-atb-tplm-name {
1617
- flex: 0 0 160px; font-size: 12.5px; padding: 5px 8px; border-radius: 7px;
1695
+ flex: 0 0 150px; width: 150px; max-width: 150px; font-size: 12.5px; padding: 5px 8px; border-radius: 7px;
1618
1696
  border: 1px solid var(--dsw-alias-border-l2, rgba(128,128,128,.3));
1619
1697
  background: var(--dsw-alias-bg-layer-1, transparent); color: inherit;
1698
+ box-sizing: border-box;
1699
+ }
1700
+ .dsh-atb-tplm-meta {
1701
+ flex: 1; min-width: 0; font-size: 11px; color: var(--dsw-alias-label-tertiary, gray);
1702
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
1620
1703
  }
1621
- .dsh-atb-tplm-meta { flex: 1; min-width: 0; font-size: 10.5px; color: var(--dsw-alias-label-tertiary, gray); }
1622
- .dsh-atb-tplm-btns { display: flex; gap: 6px; flex-shrink: 0; }
1704
+ .dsh-atb-tplm-btns { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
1623
1705
 
1624
1706
  .dsh-atb-imp { max-width: 600px; width: min(600px, 92vw); }
1625
1707
  .dsh-atb-imp-picker { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
@@ -1939,7 +2021,7 @@ window.__ModuleLoader__.load({
1939
2021
  * @module dsh-taskboard/shared/version
1940
2022
  */
1941
2023
  /** The package version (must equal package.json "version"). */
1942
- const PLUGIN_VERSION = "0.5.3";
2024
+ const PLUGIN_VERSION = "0.5.4";
1943
2025
 
1944
2026
  //#endregion
1945
2027
  //#region src/client/board/labels.ts
@@ -2021,6 +2103,11 @@ window.__ModuleLoader__.load({
2021
2103
  */
2022
2104
  /** dataTransfer type carrying the dragged task id. */
2023
2105
  const DRAG_TYPE = "application/x-dsh-atb-task";
2106
+ /** Compact session-id display (execution sessions carry the taskboard infix). */
2107
+ function shortId$1(id) {
2108
+ if (id === void 0) return "";
2109
+ return id.replace(/^session-(taskboard-)?/, "").slice(0, 8);
2110
+ }
2024
2111
  /**
2025
2112
  * The card view.
2026
2113
  * @param task - the task record.
@@ -2036,6 +2123,8 @@ window.__ModuleLoader__.load({
2036
2123
  const running = task.executions.find((ex) => ex.outcome === "running");
2037
2124
  const stale = now !== void 0 && isStaleClaim(task, now);
2038
2125
  const reviewing = task.status === "in_review" && task.trashedAt === void 0;
2126
+ const sessionExecution = [...task.executions].reverse().find((ex) => ex.sessionId !== void 0);
2127
+ const targetSessionId = running?.sessionId ?? sessionExecution?.sessionId ?? (task.claimedBy?.startsWith("session-") ? task.claimedBy : void 0);
2039
2128
  /** Submit the quick-reject: one atomic route (move + optional note). */
2040
2129
  const submitReject = () => {
2041
2130
  controller.reject(task.id, task.version, note).then((ok) => {
@@ -2101,9 +2190,10 @@ window.__ModuleLoader__.load({
2101
2190
  "data-kind": "scheduled",
2102
2191
  children: ["⏰ ", fmtTime(task.execution.nextRunAt)]
2103
2192
  }),
2104
- task.model !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2193
+ task.model !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2105
2194
  className: "dsh-atb-badge",
2106
- children: task.model.model
2195
+ title: `固定模型: ${task.model.provider}/${task.model.model}${task.model.reasoningEffort !== void 0 ? ` · 思考强度: ${task.model.reasoningEffort}` : ""}`,
2196
+ children: [task.model.model, task.model.reasoningEffort !== void 0 ? ` (${task.model.reasoningEffort})` : ""]
2107
2197
  }),
2108
2198
  task.checklist !== void 0 && task.checklist.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2109
2199
  className: "dsh-atb-badge",
@@ -2126,6 +2216,34 @@ window.__ModuleLoader__.load({
2126
2216
  "data-kind": last.outcome === "running" ? "running" : last.outcome,
2127
2217
  children: OUTCOME_LABEL[last.outcome] ?? last.outcome
2128
2218
  }),
2219
+ targetSessionId !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2220
+ type: "button",
2221
+ className: "dsh-atb-card-session",
2222
+ title: `点击一键跳转到会话:${targetSessionId}`,
2223
+ onClick: (e) => {
2224
+ e.stopPropagation();
2225
+ controller.openSession(targetSessionId).then((result) => {
2226
+ if (result === "missing") {
2227
+ const msg = `该会话已被删除(${shortId$1(targetSessionId)}),无法打开`;
2228
+ if (onAlert !== void 0) onAlert(msg);
2229
+ else alert(msg);
2230
+ } else if (result === "archived") {
2231
+ const msg = `该会话已归档(${shortId$1(targetSessionId)}),已从会话列表隐藏`;
2232
+ if (onAlert !== void 0) onAlert(msg);
2233
+ else alert(msg);
2234
+ } else if (result === "unavailable") {
2235
+ const msg = `会话导航不可用,会话 ID:${targetSessionId}`;
2236
+ if (onAlert !== void 0) onAlert(msg);
2237
+ else alert(msg);
2238
+ }
2239
+ });
2240
+ },
2241
+ children: [
2242
+ "🤖 ",
2243
+ shortId$1(targetSessionId),
2244
+ " ↗"
2245
+ ]
2246
+ }),
2129
2247
  task.comments.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: ["💬 ", task.comments.length] }),
2130
2248
  task.trashedAt !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2131
2249
  className: "dsh-atb-badge",
@@ -2291,10 +2409,11 @@ window.__ModuleLoader__.load({
2291
2409
  return `${Math.floor(s / 3600)}h${Math.floor(s % 3600 / 60)}m`;
2292
2410
  }
2293
2411
  /** Small labelled meta chip. */
2294
- function Chip({ icon, children, tone }) {
2412
+ function Chip({ icon, children, tone, title }) {
2295
2413
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2296
2414
  className: "dsh-atb-chip2",
2297
2415
  "data-tone": tone,
2416
+ title,
2298
2417
  children: [icon !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2299
2418
  className: "dsh-atb-chip2-icon",
2300
2419
  children: icon
@@ -2753,6 +2872,8 @@ window.__ModuleLoader__.load({
2753
2872
  const holder = task.status === "in_progress" ? task.claimedBy : void 0;
2754
2873
  const stale = now !== void 0 && isStaleClaim(task, now);
2755
2874
  const unchecked = (task.checklist ?? []).filter((i) => !i.checked).length;
2875
+ const sessionExecution = [...task.executions].reverse().find((e) => e.sessionId !== void 0);
2876
+ const targetSessionId = runningExecution?.sessionId ?? sessionExecution?.sessionId ?? (task.claimedBy?.startsWith("session-") ? task.claimedBy : void 0);
2756
2877
  /** Fire one top action under the shared busy guard; re-enable on settle. */
2757
2878
  const runAction = (action) => {
2758
2879
  if (actionBusy) return;
@@ -2795,9 +2916,10 @@ window.__ModuleLoader__.load({
2795
2916
  icon: "📁",
2796
2917
  children: ws?.title ?? shortId(task.workspaceId)
2797
2918
  }),
2798
- task.model !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Chip, {
2919
+ task.model !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Chip, {
2799
2920
  icon: "✦",
2800
- children: task.model.model
2921
+ title: `固定模型: ${task.model.provider}/${task.model.model}${task.model.reasoningEffort !== void 0 ? ` · 思考强度: ${task.model.reasoningEffort}` : ""}`,
2922
+ children: [task.model.model, task.model.reasoningEffort !== void 0 ? ` · ${task.model.reasoningEffort}` : ""]
2801
2923
  }),
2802
2924
  task.presetId !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Chip, {
2803
2925
  icon: "🎛",
@@ -2835,13 +2957,20 @@ window.__ModuleLoader__.load({
2835
2957
  icon: "🌿",
2836
2958
  children: "Worktree 隔离"
2837
2959
  }),
2838
- holder !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Chip, {
2839
- icon: stale ? "" : "🔑",
2840
- tone: stale ? "urgent" : void 0,
2960
+ holder !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2961
+ type: "button",
2962
+ className: "dsh-atb-chip2 dsh-atb-chip-btn",
2963
+ "data-tone": stale ? "urgent" : void 0,
2964
+ title: `点击跳转至该会话:${holder}`,
2965
+ onClick: () => jumpToSession(holder),
2841
2966
  children: [
2967
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2968
+ className: "dsh-atb-chip2-icon",
2969
+ children: stale ? "⏱" : "🤖"
2970
+ }),
2842
2971
  stale ? "认领超时 · " : "由 ",
2843
2972
  shortId(holder),
2844
- " 持有"
2973
+ " 持有"
2845
2974
  ]
2846
2975
  }),
2847
2976
  task.trashedAt !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Chip, {
@@ -2865,6 +2994,13 @@ window.__ModuleLoader__.load({
2865
2994
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2866
2995
  className: "dsh-atb-detail-topbtns",
2867
2996
  children: [
2997
+ targetSessionId !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2998
+ type: "button",
2999
+ className: "dsh-atb-detail-session",
3000
+ title: `一键跳转到对应会话:${targetSessionId}`,
3001
+ onClick: () => jumpToSession(targetSessionId),
3002
+ children: "🤖 跳转会话 ↗"
3003
+ }),
2868
3004
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2869
3005
  type: "button",
2870
3006
  className: "dsh-atb-detail-edit",
@@ -3210,6 +3346,34 @@ window.__ModuleLoader__.load({
3210
3346
  *
3211
3347
  * @module dsh-taskboard/client/board/TaskFormModal
3212
3348
  */
3349
+ /** Local storage key for remembering the last selected model in create mode. */
3350
+ const LAST_MODEL_KEY = "dsh-taskboard-last-model-v1";
3351
+ /** Read the remembered model from localStorage. */
3352
+ function loadLastModel() {
3353
+ try {
3354
+ const raw = localStorage.getItem(LAST_MODEL_KEY);
3355
+ if (raw === null) return void 0;
3356
+ const parsed = JSON.parse(raw);
3357
+ if (typeof parsed === "object" && parsed !== null) {
3358
+ const { provider, model, reasoningEffort } = parsed;
3359
+ if (typeof provider === "string" && typeof model === "string" && provider.trim().length > 0 && model.trim().length > 0) return {
3360
+ provider: provider.trim(),
3361
+ model: model.trim(),
3362
+ ...typeof reasoningEffort === "string" && reasoningEffort.trim().length > 0 ? { reasoningEffort: reasoningEffort.trim() } : {}
3363
+ };
3364
+ }
3365
+ return;
3366
+ } catch {
3367
+ return;
3368
+ }
3369
+ }
3370
+ /** Save the remembered model to localStorage. */
3371
+ function saveLastModel(model) {
3372
+ try {
3373
+ if (model === void 0) localStorage.removeItem(LAST_MODEL_KEY);
3374
+ else localStorage.setItem(LAST_MODEL_KEY, JSON.stringify(model));
3375
+ } catch {}
3376
+ }
3213
3377
  /** Urgency segmented options with a one-line hint each. */
3214
3378
  const URGENCY_OPTIONS = [
3215
3379
  {
@@ -3340,7 +3504,12 @@ window.__ModuleLoader__.load({
3340
3504
  const [mode, setMode] = (0, react.useState)(task?.execution.mode === "scheduled" || prefill?.execution?.mode === "scheduled" ? "scheduled" : "claim");
3341
3505
  const [cron, setCron] = (0, react.useState)(task?.execution.cron ?? prefill?.execution?.cron ?? "0 9 * * *");
3342
3506
  const [catalog, setCatalog] = (0, react.useState)([]);
3343
- const [model, setModel] = (0, react.useState)(task?.model !== void 0 || prefill?.model !== void 0 ? JSON.stringify(task?.model ?? prefill?.model) : "");
3507
+ const initialModel = task?.model ?? prefill?.model ?? (!editing ? loadLastModel() : void 0);
3508
+ const [model, setModel] = (0, react.useState)(initialModel !== void 0 ? JSON.stringify({
3509
+ provider: initialModel.provider,
3510
+ model: initialModel.model
3511
+ }) : "");
3512
+ const [reasoningEffort, setReasoningEffort] = (0, react.useState)(initialModel?.reasoningEffort ?? "");
3344
3513
  const initialPreset = task?.presetId ?? prefill?.presetId ?? "";
3345
3514
  const [presetId, setPresetId] = (0, react.useState)(initialPreset);
3346
3515
  const [presets, setPresets] = (0, react.useState)([]);
@@ -3402,9 +3571,21 @@ window.__ModuleLoader__.load({
3402
3571
  ...r,
3403
3572
  text: r.text.trim()
3404
3573
  })).filter((r) => r.text.length > 0);
3574
+ const parsedModel = model !== "" ? JSON.parse(model) : void 0;
3575
+ const modelReasoning = (parsedModel !== void 0 ? catalog.find((m) => m.provider === parsedModel.provider && m.model === parsedModel.model) : void 0)?.reasoning;
3576
+ const buildPickedModel = () => {
3577
+ if (parsedModel === void 0) return void 0;
3578
+ const eff = reasoningEffort.trim();
3579
+ return {
3580
+ provider: parsedModel.provider,
3581
+ model: parsedModel.model,
3582
+ ...eff.length > 0 ? { reasoningEffort: eff } : {}
3583
+ };
3584
+ };
3405
3585
  const submit = () => {
3406
3586
  if (!valid || busy) return;
3407
- const picked = model !== "" ? JSON.parse(model) : void 0;
3587
+ const picked = buildPickedModel();
3588
+ if (!editing) saveLastModel(picked);
3408
3589
  const isolationOut = isolationPayload();
3409
3590
  const presetOut = presetPayload();
3410
3591
  const rows = filledRows();
@@ -3442,7 +3623,8 @@ window.__ModuleLoader__.load({
3442
3623
  /** Save the form, then immediately trigger a manual run of the task. */
3443
3624
  const submitAndRun = () => {
3444
3625
  if (!valid || runBlocked || busy) return;
3445
- const picked = model !== "" ? JSON.parse(model) : void 0;
3626
+ const picked = buildPickedModel();
3627
+ if (!editing) saveLastModel(picked);
3446
3628
  const isolationOut = isolationPayload();
3447
3629
  const presetOut = presetPayload();
3448
3630
  const rows = filledRows();
@@ -3548,7 +3730,17 @@ window.__ModuleLoader__.load({
3548
3730
  label: "模型(默认 = 会话默认模型)",
3549
3731
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
3550
3732
  value: model,
3551
- onChange: (e) => setModel(e.target.value),
3733
+ onChange: (e) => {
3734
+ const val = e.target.value;
3735
+ setModel(val);
3736
+ if (val === "") setReasoningEffort("");
3737
+ else {
3738
+ const pm = JSON.parse(val);
3739
+ const cm = catalog.find((m) => m.provider === pm.provider && m.model === pm.model);
3740
+ if (cm?.reasoning?.defaultEffort !== void 0) setReasoningEffort(cm.reasoning.defaultEffort);
3741
+ else setReasoningEffort("");
3742
+ }
3743
+ },
3552
3744
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3553
3745
  value: "",
3554
3746
  children: "默认模型"
@@ -3566,6 +3758,38 @@ window.__ModuleLoader__.load({
3566
3758
  }, `${m.provider}/${m.model}`))]
3567
3759
  })
3568
3760
  }),
3761
+ parsedModel !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
3762
+ label: "思考强度(Reasoning Effort)",
3763
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
3764
+ value: reasoningEffort,
3765
+ onChange: (e) => setReasoningEffort(e.target.value),
3766
+ title: "设置模型的思考强度(如 low/medium/high);默认 = 跟随模型/提供商默认",
3767
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("option", {
3768
+ value: "",
3769
+ children: ["跟随模型默认", modelReasoning?.defaultEffort !== void 0 ? `(当前:${modelReasoning.efforts.find((ef) => ef.id === modelReasoning.defaultEffort)?.name ?? modelReasoning.defaultEffort})` : ""]
3770
+ }), modelReasoning !== void 0 && modelReasoning.efforts.length > 0 ? modelReasoning.efforts.map((eff) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("option", {
3771
+ value: eff.id,
3772
+ children: [eff.name, eff.description ? ` (${eff.description})` : ""]
3773
+ }, eff.id)) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
3774
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3775
+ value: "low",
3776
+ children: "低 (low)"
3777
+ }),
3778
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3779
+ value: "medium",
3780
+ children: "中 (medium)"
3781
+ }),
3782
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3783
+ value: "high",
3784
+ children: "高 (high)"
3785
+ }),
3786
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3787
+ value: "none",
3788
+ children: "关闭思考 (none)"
3789
+ })
3790
+ ] })]
3791
+ })
3792
+ }),
3569
3793
  presets.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
3570
3794
  label: "执行模式(preset)",
3571
3795
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
@@ -3796,11 +4020,17 @@ window.__ModuleLoader__.load({
3796
4020
  * @param controller - the board controller.
3797
4021
  */
3798
4022
  function SettingsModal({ controller }) {
3799
- const current = controller.getSnapshot().ledger.settings?.defaultIsolation ?? "none";
3800
- const [draft, setDraft] = (0, react.useState)(current);
3801
- const dirty = draft !== current;
4023
+ const state = controller.getSnapshot();
4024
+ const currentIso = state.ledger.settings?.defaultIsolation ?? "none";
4025
+ const currentSync = defaultSyncExternalSessionsOf(state.ledger.settings);
4026
+ const [draftIso, setDraftIso] = (0, react.useState)(currentIso);
4027
+ const [draftSync, setDraftSync] = (0, react.useState)(currentSync);
4028
+ const dirty = draftIso !== currentIso || draftSync !== currentSync;
3802
4029
  const save = () => {
3803
- controller.updateSettings({ defaultIsolation: draft }).then((ok) => {
4030
+ controller.updateSettings({
4031
+ defaultIsolation: draftIso,
4032
+ syncExternalSessions: draftSync
4033
+ }).then((ok) => {
3804
4034
  if (ok) controller.closeSettings();
3805
4035
  });
3806
4036
  };
@@ -3824,7 +4054,7 @@ window.__ModuleLoader__.load({
3824
4054
  }),
3825
4055
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3826
4056
  className: "dsh-atb-modal-headtext",
3827
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: "看板设置" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: "新建任务时应用的默认值(不影响已有任务)" })]
4057
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: "看板设置" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: "新建任务与会话同步的全局默认值" })]
3828
4058
  }),
3829
4059
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3830
4060
  type: "button",
@@ -3835,9 +4065,9 @@ window.__ModuleLoader__.load({
3835
4065
  })
3836
4066
  ]
3837
4067
  }),
3838
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4068
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3839
4069
  className: "dsh-atb-modal-body",
3840
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
4070
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
3841
4071
  className: "dsh-atb-diag-sec",
3842
4072
  children: [
3843
4073
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", { children: "默认执行隔离" }),
@@ -3846,9 +4076,9 @@ window.__ModuleLoader__.load({
3846
4076
  children: ISOLATION_OPTIONS.map((o) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3847
4077
  type: "button",
3848
4078
  className: "dsh-atb-mode-opt",
3849
- "data-on": draft === o.value,
4079
+ "data-on": draftIso === o.value,
3850
4080
  title: o.hint,
3851
- onClick: () => setDraft(o.value),
4081
+ onClick: () => setDraftIso(o.value),
3852
4082
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3853
4083
  className: "dsh-atb-mode-name",
3854
4084
  children: o.name
@@ -3862,12 +4092,51 @@ window.__ModuleLoader__.load({
3862
4092
  className: "dsh-atb-isolation-note",
3863
4093
  children: [
3864
4094
  "当前保存的默认:",
3865
- current === "worktree" ? "🌿 Worktree 隔离" : "📁 原目录执行",
4095
+ currentIso === "worktree" ? "🌿 Worktree 隔离" : "📁 原目录执行",
3866
4096
  "。 仅影响之后新建的任务;已有任务保持创建时的选择,非 git 项目运行时仍自动降级原目录。"
3867
4097
  ]
3868
4098
  })
3869
4099
  ]
3870
- })
4100
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
4101
+ className: "dsh-atb-diag-sec",
4102
+ children: [
4103
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", { children: "自动同步工作区会话" }),
4104
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4105
+ className: "dsh-atb-mode-picker",
4106
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
4107
+ type: "button",
4108
+ className: "dsh-atb-mode-opt",
4109
+ "data-on": !draftSync,
4110
+ title: "仅管理在任务看板中创建和触发的任务",
4111
+ onClick: () => setDraftSync(false),
4112
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4113
+ className: "dsh-atb-mode-name",
4114
+ children: "🚫 关闭同步"
4115
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4116
+ className: "dsh-atb-mode-hint",
4117
+ children: "仅管理看板任务(出厂默认)"
4118
+ })]
4119
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
4120
+ type: "button",
4121
+ className: "dsh-atb-mode-opt",
4122
+ "data-on": draftSync,
4123
+ title: "各工作区直接新建的会话也会在看板展示,运行中进入「进行中」,完成后自动进入「待验收」",
4124
+ onClick: () => setDraftSync(true),
4125
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4126
+ className: "dsh-atb-mode-name",
4127
+ children: "🔄 自动纳入会话"
4128
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4129
+ className: "dsh-atb-mode-hint",
4130
+ children: "跟踪运行并在完成后进入待验收"
4131
+ })]
4132
+ })]
4133
+ }),
4134
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4135
+ className: "dsh-atb-isolation-note",
4136
+ children: currentSync ? "已开启:工作区直接新建并执行的会话将自动在看板生成任务卡片,并在完成后流转至「待验收」列。" : "已关闭:仅在看板内部创建与触发执行的任务会出现在看板上。"
4137
+ })
4138
+ ]
4139
+ })]
3871
4140
  }),
3872
4141
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3873
4142
  className: "dsh-atb-modal-foot",
@@ -4246,6 +4515,7 @@ window.__ModuleLoader__.load({
4246
4515
  }),
4247
4516
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
4248
4517
  className: "dsh-atb-tplm-meta",
4518
+ title: `${t.builtin === true ? "内置" : "自建"}${t.task.checklist !== void 0 && t.task.checklist.length > 0 ? ` · 清单 ${t.task.checklist.length} 项` : ""}${t.task.urgency !== void 0 ? ` · ${t.task.urgency}` : ""}`,
4249
4519
  children: [
4250
4520
  t.builtin === true ? "内置" : "自建",
4251
4521
  t.task.checklist !== void 0 && t.task.checklist.length > 0 ? ` · 清单 ${t.task.checklist.length} 项` : "",
@@ -4344,6 +4614,7 @@ window.__ModuleLoader__.load({
4344
4614
  if (state.sortBy === "updated") sorted.sort((a, b) => b.updatedAt - a.updatedAt);
4345
4615
  else if (state.sortBy === "created") sorted.sort((a, b) => b.createdAt - a.createdAt);
4346
4616
  else if (state.sortBy === "urgency") sorted.sort((a, b) => URGENCY_RANK[a.urgency] - URGENCY_RANK[b.urgency] || b.updatedAt - a.updatedAt);
4617
+ else if (state.sortBy === "title") sorted.sort((a, b) => a.title.localeCompare(b.title, void 0, { numeric: true }));
4347
4618
  return sorted;
4348
4619
  }
4349
4620
  /**
@@ -4473,6 +4744,10 @@ window.__ModuleLoader__.load({
4473
4744
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
4474
4745
  value: "created",
4475
4746
  children: "创建时间"
4747
+ }),
4748
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
4749
+ value: "title",
4750
+ children: "按标题"
4476
4751
  })
4477
4752
  ]
4478
4753
  }),
@@ -4976,8 +5251,8 @@ window.__ModuleLoader__.load({
4976
5251
  /** Required client services (fiber inject waiting). */
4977
5252
  const inject = ["connection"];
4978
5253
  /**
4979
- * Mount the client half.
4980
- * @param ctx - the client context (connection injected).
5254
+ * Client entry: installs styles, starts the controller, mounts DOM seats.
5255
+ * @param ctx - the cordis client context.
4981
5256
  */
4982
5257
  function apply(ctx) {
4983
5258
  try {
@@ -4992,7 +5267,8 @@ window.__ModuleLoader__.load({
4992
5267
  for (const group of response.result.value.groups) for (const model of group.models) out.push({
4993
5268
  provider: group.id,
4994
5269
  model: model.id,
4995
- name: model.name
5270
+ name: model.name,
5271
+ ...model.reasoning !== void 0 ? { reasoning: model.reasoning } : {}
4996
5272
  });
4997
5273
  return out;
4998
5274
  });
@@ -229,7 +229,8 @@ var ExecutionService = class {
229
229
  },
230
230
  ...model !== void 0 ? { agentOptions: {
231
231
  provider: model.provider,
232
- model: model.model
232
+ model: model.model,
233
+ ...model.reasoningEffort !== void 0 ? { reasoningEffort: model.reasoningEffort } : {}
233
234
  } } : {},
234
235
  ...composition !== void 0 ? { setup: composition.setup } : {}
235
236
  });