@dsh-tom/dsh-css 0.2.1 → 0.2.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -22,7 +22,7 @@ npm publish --access public --registry=https://registry.npmjs.org/
22
22
  打开 **插件 → 添加插件 → 安装第三方插件**,在“包名或地址”输入:
23
23
 
24
24
  ```text
25
- D:\product\dsh-css\dsh-tom-dsh-css-0.2.1.tgz
25
+ D:\product\dsh-css\dsh-tom-dsh-css-0.2.10.tgz
26
26
  ```
27
27
 
28
28
  安装并启用,然后完全退出并重新打开 dsh。
@@ -32,7 +32,7 @@ D:\product\dsh-css\dsh-tom-dsh-css-0.2.1.tgz
32
32
  包发布到 npmjs 后,先卸载已安装的旧版,再打开 **插件 → 添加插件 → 安装第三方插件**,输入:
33
33
 
34
34
  ```text
35
- @dsh-tom/dsh-css@0.2.1
35
+ @dsh-tom/dsh-css@0.2.10
36
36
  ```
37
37
 
38
38
  选择 **安装源 → npm 官方源**,安装并启用,然后完全退出并重新打开 dsh。
package/dist/client.js CHANGED
@@ -29,10 +29,41 @@ __export(client_exports, {
29
29
  inject: () => inject2
30
30
  });
31
31
  module.exports = __toCommonJS(client_exports);
32
- var import_react6 = require("react");
32
+ var import_react8 = require("react");
33
33
 
34
34
  // theme.css
35
- var theme_default = `/* \u6DF1\u8272\u6A21\u5F0F\u914D\u8272\uFF0C\u4FDD\u7559\u5185\u7F6E\u6587\u5B57\u3001\u8FB9\u6846\u548C\u8BED\u6CD5\u9AD8\u4EAE\u989C\u8272\u3002 */
35
+ var theme_default = `.dsh-css-unread-dot {
36
+ display: inline-block;
37
+ flex: none;
38
+ width: 8px;
39
+ height: 8px;
40
+ border-radius: 50%;
41
+ background: var(--dsw-alias-label-secondary, #aaa);
42
+ }
43
+
44
+ /* \u4F1A\u8BDD\u64CD\u4F5C\u51FA\u73B0\u65F6\u9690\u85CF\u672A\u8BFB\u63D0\u793A\uFF1B\u9879\u76EE\u6811\u4FDD\u7559\u5DE6\u4FA7\u56FE\u6807\u4F4D\u7F6E\uFF0C\u907F\u514D\u6807\u9898\u8DF3\u52A8\u3002 */
45
+ .hIlkoa_sessionRow:is(:hover, .hIlkoa_menuOpen) > .hIlkoa_slot .dsh-css-unread-dot {
46
+ visibility: hidden;
47
+ }
48
+
49
+ /* \u83DC\u5355\u5173\u95ED\u53EF\u80FD\u6B8B\u7559\u5BBF\u4E3B\u7684\u6EDA\u52A8\u548C\u6E10\u9690\u72B6\u6001\uFF1B\u975E\u60AC\u505C\u65F6\u4ECE\u6807\u9898\u5F00\u5934\u6B63\u5E38\u663E\u793A\u3002 */
50
+ .hIlkoa_sessionRow:not(:hover):not(.hIlkoa_menuOpen) > .hIlkoa_title {
51
+ overflow: clip;
52
+ mask-image: none;
53
+ }
54
+
55
+ /* \u4F1A\u8BDD\u83DC\u5355\u6539\u4E3A\u53F3\u952E\u6253\u5F00\uFF1B\u4FDD\u7559\u5BBF\u4E3B\u83DC\u5355\u951A\u70B9\uFF0C\u5E76\u79FB\u5230\u9F20\u6807\u4F4D\u7F6E\u3002 */
56
+ .hIlkoa_sessionRow > .hIlkoa_rowActions > ._root_4ub78_1 {
57
+ position: fixed;
58
+ left: var(--dsh-css-context-x, 0px);
59
+ top: var(--dsh-css-context-y, 0px);
60
+ width: 0;
61
+ height: 0;
62
+
63
+ & > button { display: none; }
64
+ }
65
+
66
+ /* \u6DF1\u8272\u6A21\u5F0F\u914D\u8272\uFF0C\u4FDD\u7559\u5185\u7F6E\u6587\u5B57\u3001\u8FB9\u6846\u548C\u8BED\u6CD5\u9AD8\u4EAE\u989C\u8272\u3002 */
36
67
  html body[data-ds-dark-theme] {
37
68
  /* \u533A\u57DF 1\uFF1A\u5DE6\u4FA7\u4F1A\u8BDD\u5217\u8868\uFF1BWindows \u6807\u9898\u680F\u5728\u4E0B\u65B9\u5355\u72EC\u8BBE\u7F6E\u3002\u539F RGB(27, 27, 28)\u3002 */
38
69
  --dsw-specific-sidebar-fill: rgb(36, 37, 33) !important;
@@ -200,9 +231,17 @@ html[data-windows-titlebar] body[data-ds-dark-theme] ._2H3hWW_root:not(._2H3hWW_
200
231
  padding: 44px 0 0 12px;
201
232
  }
202
233
 
203
- /* \u5E73\u94FA\u4F1A\u8BDD\u6807\u9898\u4E0E\u201C\u4F1A\u8BDD\u201D\u5DE6\u5BF9\u9F50\uFF0C\u72B6\u6001\u56FE\u6807\u653E\u5230\u53F3\u4FA7\u3002 */
234
+ /* \u64CD\u4F5C\u6309\u94AE\u95F4\u8DDD 15px \u2192 10px\uFF1B\u53F3\u4FA7\u5185\u8FB9\u8DDD 8px \u2192 4px\u3002 */
235
+ & .hIlkoa_sessionRow {
236
+ padding-inline-end: 4px;
237
+
238
+ & > .hIlkoa_rowActions { gap: 10px; }
239
+ }
240
+
241
+ /* \u884C\u80CC\u666F\u5411\u5DE6\u5EF6\u4F38 4px\uFF0C\u7559\u8DB3\u6807\u9898\u5185\u8FB9\u8DDD\u5E76\u4E0E\u201C\u4F1A\u8BDD\u201D\u4FDD\u6301\u5DE6\u5BF9\u9F50\u3002 */
204
242
  & ._9lTDKa_flatList .hIlkoa_sessionRow {
205
- padding-inline-start: 4px;
243
+ margin-inline-start: -4px;
244
+ padding-inline-start: 8px;
206
245
 
207
246
  & > .hIlkoa_title {
208
247
  margin-left: 0;
@@ -212,7 +251,13 @@ html[data-windows-titlebar] body[data-ds-dark-theme] ._2H3hWW_root:not(._2H3hWW_
212
251
  order: 1;
213
252
  }
214
253
 
215
- & > .hIlkoa_slot:empty {
254
+ /* \u7A7A\u72B6\u6001\u5360\u4F4D\u51CF\u534A\uFF0C\u4E0E\u53F3\u5185\u8FB9\u8DDD\u5408\u8BA1 12px\uFF1B\u5B9E\u9645\u72B6\u6001\u56FE\u6807\u4FDD\u7559\u539F\u5BBD\u5EA6\u3002 */
255
+ & > .hIlkoa_slot:has(> [data-slot="sidebar.session.row.leading"]:empty) {
256
+ width: 8px;
257
+ }
258
+
259
+ & > .hIlkoa_slot:empty,
260
+ &:is(:hover, .hIlkoa_menuOpen) > .hIlkoa_slot:has(.dsh-css-unread-dot) {
216
261
  display: none;
217
262
  }
218
263
  }
@@ -289,6 +334,15 @@ html[data-windows-titlebar] body[data-ds-dark-theme] ._2H3hWW_root:not(._2H3hWW_
289
334
  }
290
335
  }
291
336
 
337
+ .dsh-css-date-heading {
338
+ padding: 16px 4px 6px;
339
+ color: var(--dsw-alias-label-tertiary);
340
+ font-size: 12px;
341
+ line-height: 18px;
342
+
343
+ &:first-child { padding-top: 6px; }
344
+ }
345
+
292
346
  /* \u60AC\u6D6E\u5361\u7247\u7531\u5BBF\u4E3B\u901A\u8FC7 portal \u6302\u5728\u4FA7\u680F\u5916\u3002 */
293
347
  .dsh-css-project {
294
348
  display: none;
@@ -1050,8 +1104,210 @@ function registerCacheHitPrecision(ctx) {
1050
1104
  });
1051
1105
  }
1052
1106
 
1107
+ // src/date-groups.js
1108
+ var import_react3 = require("react");
1109
+ var DAY = 864e5;
1110
+ var calendarDay = (date5) => Date.UTC(date5.getFullYear(), date5.getMonth(), date5.getDate()) / DAY;
1111
+ function dateHeading(timestamp, now) {
1112
+ const date5 = new Date(timestamp);
1113
+ const day = calendarDay(date5);
1114
+ const age = calendarDay(new Date(now)) - day;
1115
+ const label = ["\u4ECA\u5929", "\u6628\u5929", "\u524D\u5929"][age] ?? `${String(date5.getMonth() + 1).padStart(2, "0")}-${String(date5.getDate()).padStart(2, "0")}`;
1116
+ return { day, label };
1117
+ }
1118
+ function mapElements(value, visit2) {
1119
+ if (Array.isArray(value)) return import_react3.Children.map(value, (child) => mapElements(child, visit2));
1120
+ if (!(0, import_react3.isValidElement)(value)) return value;
1121
+ const replacement = visit2(value);
1122
+ if (replacement !== value) return replacement;
1123
+ return "children" in value.props ? (0, import_react3.cloneElement)(value, {}, mapElements(value.props.children, visit2)) : value;
1124
+ }
1125
+ function DateViewOptions({ renderMenu, dateMode, ...props }) {
1126
+ const menu = renderMenu(props);
1127
+ const items = menu.props.items.flatMap((item) => item.id === "flat" ? [item, {
1128
+ id: "date",
1129
+ label: "\u6309\u65E5\u671F",
1130
+ icon: (0, import_react3.createElement)("svg", {
1131
+ width: 16,
1132
+ height: 16,
1133
+ viewBox: "0 0 24 24",
1134
+ fill: "none",
1135
+ stroke: "currentColor",
1136
+ strokeWidth: 1.7,
1137
+ strokeLinecap: "round",
1138
+ strokeLinejoin: "round",
1139
+ "aria-hidden": true
1140
+ }, (0, import_react3.createElement)("path", { d: "M8 3v4M16 3v4M3 10h18M5 5h14a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2Z" }))
1141
+ }] : [item]);
1142
+ return (0, import_react3.cloneElement)(menu, {
1143
+ items,
1144
+ selectedIds: menu.props.selectedIds.map((id) => dateMode && id === "flat" ? "date" : id),
1145
+ onSelect: (id) => {
1146
+ if (id !== "date") return menu.props.onSelect(id);
1147
+ props.onGroupPick("date");
1148
+ menu.props.onClose();
1149
+ }
1150
+ });
1151
+ }
1152
+ function DateFlatList({ renderList, enabled, ...props }) {
1153
+ const [clock, setClock] = (0, import_react3.useState)(Date.now);
1154
+ (0, import_react3.useEffect)(() => {
1155
+ if (!enabled) return;
1156
+ const now2 = /* @__PURE__ */ new Date();
1157
+ const midnight = new Date(now2.getFullYear(), now2.getMonth(), now2.getDate() + 1);
1158
+ const timer = setTimeout(() => setClock(Date.now()), midnight - now2);
1159
+ return () => clearTimeout(timer);
1160
+ }, [enabled, clock]);
1161
+ const tree = renderList(props);
1162
+ if (!enabled) return tree;
1163
+ const now = Date.now();
1164
+ return mapElements(tree, (element) => {
1165
+ if (!element.props.className?.split(" ").includes("_9lTDKa_flatList")) return element;
1166
+ let previousDay;
1167
+ const children = mapElements(element.props.children, (row) => {
1168
+ const node2 = row.props.node;
1169
+ if (!node2 || node2.pinned || node2.blank) return row;
1170
+ const { day, label } = dateHeading(node2.updatedAt, now);
1171
+ if (day === previousDay) return row;
1172
+ previousDay = day;
1173
+ return [(0, import_react3.createElement)("div", {
1174
+ key: `date:${node2.id}`,
1175
+ className: "dsh-css-date-heading",
1176
+ role: "presentation"
1177
+ }, label), row];
1178
+ });
1179
+ return (0, import_react3.cloneElement)(element, {}, children);
1180
+ });
1181
+ }
1182
+ function registerDateGroups(ctx) {
1183
+ const slot = "sidebar.workspaces";
1184
+ ctx.slots.inject(slot, () => {
1185
+ const original = ctx.slots.entries(slot)[0];
1186
+ if (!original) return;
1187
+ const renderBrowser = original.component;
1188
+ function DateWorkspaceBrowser(props) {
1189
+ const dateMode = props.useStore((state) => state.groupBy === "date");
1190
+ const tree = renderBrowser({
1191
+ ...props,
1192
+ useStore: (selector) => props.useStore((state) => selector(state.groupBy === "date" ? { ...state, groupBy: "flat" } : state))
1193
+ });
1194
+ return mapElements(tree, (element) => {
1195
+ if (element.props.onGroupPick && element.props.onOrderPick) {
1196
+ return (0, import_react3.createElement)(DateViewOptions, {
1197
+ ...element.props,
1198
+ key: element.key ?? void 0,
1199
+ renderMenu: element.type,
1200
+ dateMode
1201
+ });
1202
+ }
1203
+ if (element.props.sessionIds && element.props.setSessionOrder) {
1204
+ return (0, import_react3.createElement)(DateFlatList, {
1205
+ ...element.props,
1206
+ key: element.key ?? void 0,
1207
+ renderList: element.type,
1208
+ enabled: dateMode
1209
+ });
1210
+ }
1211
+ return element;
1212
+ });
1213
+ }
1214
+ const priority = Math.max(...ctx.slots.entries(slot).map((entry) => entry.options.priority ?? 0)) + 1;
1215
+ const dispose = ctx.slots.register({ name: slot, priority }, renderBrowser);
1216
+ original.component = DateWorkspaceBrowser;
1217
+ return () => {
1218
+ original.component = renderBrowser;
1219
+ dispose();
1220
+ };
1221
+ });
1222
+ }
1223
+
1224
+ // src/unread.js
1225
+ var import_react4 = require("react");
1226
+ var import_dsh_client_ui_primitives2 = require("@deepseek-ai/dsh-client-ui-primitives");
1227
+
1228
+ // src/unread-store.js
1229
+ var STORAGE_KEY = "dsh-css.unread.v1";
1230
+ function createUnreadStore(sessions, storage) {
1231
+ let snapshot = /* @__PURE__ */ new Set();
1232
+ const listeners = /* @__PURE__ */ new Set();
1233
+ try {
1234
+ const saved = JSON.parse((storage ?? window.localStorage).getItem(STORAGE_KEY) ?? "[]");
1235
+ if (Array.isArray(saved)) snapshot = new Set(saved.filter((id) => typeof id === "string"));
1236
+ } catch {
1237
+ }
1238
+ const publish = (next) => {
1239
+ snapshot = next;
1240
+ try {
1241
+ (storage ?? window.localStorage).setItem(STORAGE_KEY, JSON.stringify([...next]));
1242
+ } catch {
1243
+ console.warn("[dsh-css] \u672A\u8BFB\u6807\u8BB0\u65E0\u6CD5\u4FDD\u5B58\uFF0C\u91CD\u542F\u540E\u53EF\u80FD\u4E22\u5931\u3002");
1244
+ }
1245
+ for (const listener of listeners) listener();
1246
+ };
1247
+ const mainCount = (row) => row?.retainedBy?.mainView ?? 0;
1248
+ return {
1249
+ getSnapshot: () => snapshot,
1250
+ subscribe(listener) {
1251
+ listeners.add(listener);
1252
+ return () => listeners.delete(listener);
1253
+ },
1254
+ setUnread(id, unread) {
1255
+ if (snapshot.has(id) === unread) return;
1256
+ const next = new Set(snapshot);
1257
+ if (unread) next.add(id);
1258
+ else next.delete(id);
1259
+ publish(next);
1260
+ },
1261
+ watch() {
1262
+ let previous = sessions.getSnapshot().byId;
1263
+ return sessions.subscribe(() => {
1264
+ const current = sessions.getSnapshot().byId;
1265
+ const next = new Set(snapshot);
1266
+ for (const id of snapshot) {
1267
+ if (mainCount(current[id]) > mainCount(previous[id])) next.delete(id);
1268
+ }
1269
+ previous = current;
1270
+ if (next.size !== snapshot.size) publish(next);
1271
+ });
1272
+ }
1273
+ };
1274
+ }
1275
+
1276
+ // src/unread.js
1277
+ function UnreadMenuItem({ sessionId, useUnread, useWorkspaces, useMenuOpenState, setUnread }) {
1278
+ const unread = useUnread((state) => state.has(sessionId));
1279
+ const archived = useWorkspaces((state) => state.archivedSessionIds.includes(sessionId));
1280
+ const [, setMenuOpen] = useMenuOpenState();
1281
+ if (archived) return null;
1282
+ return (0, import_react4.createElement)(import_dsh_client_ui_primitives2.MenuItemButton, {
1283
+ icon: unread ? (0, import_react4.createElement)(import_dsh_client_ui_primitives2.IconCheckOutlineRegular, { size: 14 }) : (0, import_react4.createElement)("span", { className: "dsh-css-unread-dot", "aria-hidden": true }),
1284
+ onSelect: () => {
1285
+ setUnread(sessionId, !unread);
1286
+ setMenuOpen(false);
1287
+ }
1288
+ }, unread ? "\u6807\u8BB0\u4E3A\u5DF2\u8BFB" : "\u6807\u8BB0\u4E3A\u672A\u8BFB");
1289
+ }
1290
+ function UnreadIndicator({ sessionId, useUnread }) {
1291
+ return useUnread((state) => state.has(sessionId)) ? (0, import_react4.createElement)("span", { className: "dsh-css-unread-dot", role: "img", "aria-label": "\u672A\u8BFB", title: "\u672A\u8BFB" }) : null;
1292
+ }
1293
+ function registerUnread(ctx) {
1294
+ const unread = createUnreadStore(ctx.sessions.list);
1295
+ ctx.effect(() => unread.watch());
1296
+ ctx.slots.inject("sidebar.workspaces.session.menu.item", () => ctx.slots.register({
1297
+ name: "sidebar.workspaces.session.menu.item",
1298
+ id: "dsh-css-unread",
1299
+ order: 250,
1300
+ inject: () => ({ setUnread: unread.setUnread, hooks: { unread, workspaces: ctx.workspaces.list } })
1301
+ }, UnreadMenuItem));
1302
+ ctx.slots.inject("sidebar.session.row.leading", () => ctx.slots.register({
1303
+ name: "sidebar.session.row.leading",
1304
+ id: "dsh-css-unread",
1305
+ inject: () => ({ hooks: { unread } })
1306
+ }, UnreadIndicator));
1307
+ }
1308
+
1053
1309
  // src/cost/client.js
1054
- var import_react5 = require("react");
1310
+ var import_react7 = require("react");
1055
1311
 
1056
1312
  // src/cost/pricing.js
1057
1313
  var PROJECTION_KEY = "dshTomCost";
@@ -1089,7 +1345,7 @@ function formatMoney(units) {
1089
1345
  }
1090
1346
 
1091
1347
  // src/cost/panel.js
1092
- var import_react3 = require("react");
1348
+ var import_react5 = require("react");
1093
1349
  var import_react_dom = require("react-dom");
1094
1350
 
1095
1351
  // src/cost/panel-styles.js
@@ -1165,8 +1421,8 @@ function costRows(totals, daily, day = beijingDay()) {
1165
1421
  ];
1166
1422
  }
1167
1423
  function useBeijingDay() {
1168
- const [day, setDay] = (0, import_react3.useState)(beijingDay);
1169
- (0, import_react3.useEffect)(() => {
1424
+ const [day, setDay] = (0, import_react5.useState)(beijingDay);
1425
+ (0, import_react5.useEffect)(() => {
1170
1426
  let timer;
1171
1427
  const refresh = () => {
1172
1428
  const current = beijingDay();
@@ -1180,7 +1436,7 @@ function useBeijingDay() {
1180
1436
  return day;
1181
1437
  }
1182
1438
  function CostIcon() {
1183
- return (0, import_react3.createElement)(
1439
+ return (0, import_react5.createElement)(
1184
1440
  "svg",
1185
1441
  {
1186
1442
  viewBox: "0 0 24 24",
@@ -1193,18 +1449,18 @@ function CostIcon() {
1193
1449
  strokeLinejoin: "round",
1194
1450
  "aria-hidden": true
1195
1451
  },
1196
- (0, import_react3.createElement)("circle", { cx: 12, cy: 12, r: 9 }),
1197
- (0, import_react3.createElement)("path", { d: "m8.5 7.5 3.5 4 3.5-4M8.5 12h7M8.5 15h7M12 11.5V18" })
1452
+ (0, import_react5.createElement)("circle", { cx: 12, cy: 12, r: 9 }),
1453
+ (0, import_react5.createElement)("path", { d: "m8.5 7.5 3.5 4 3.5-4M8.5 12h7M8.5 15h7M12 11.5V18" })
1198
1454
  );
1199
1455
  }
1200
1456
  function CostPanel({ totals, daily, balance }) {
1201
1457
  const day = useBeijingDay();
1202
1458
  const rows = costRows(totals, daily, day);
1203
- const [open2, setOpen] = (0, import_react3.useState)(false);
1204
- const anchor2 = (0, import_react3.useRef)(null);
1205
- const panel = (0, import_react3.useRef)(null);
1206
- const dialogId = (0, import_react3.useId)();
1207
- (0, import_react3.useLayoutEffect)(() => {
1459
+ const [open2, setOpen] = (0, import_react5.useState)(false);
1460
+ const anchor2 = (0, import_react5.useRef)(null);
1461
+ const panel = (0, import_react5.useRef)(null);
1462
+ const dialogId = (0, import_react5.useId)();
1463
+ (0, import_react5.useLayoutEffect)(() => {
1208
1464
  if (!open2) return;
1209
1465
  const element = panel.current;
1210
1466
  const document2 = element.ownerDocument;
@@ -1243,11 +1499,11 @@ function CostPanel({ totals, daily, balance }) {
1243
1499
  document2.removeEventListener("keydown", dismissEscape);
1244
1500
  };
1245
1501
  }, [open2]);
1246
- return (0, import_react3.createElement)(
1502
+ return (0, import_react5.createElement)(
1247
1503
  "span",
1248
1504
  { className: "dsh-tom-cost-anchor", "data-composer-stat": "cost" },
1249
- (0, import_react3.createElement)("style", { "data-dsh-tom-cost-styles": "" }, panelStyles),
1250
- (0, import_react3.createElement)("button", {
1505
+ (0, import_react5.createElement)("style", { "data-dsh-tom-cost-styles": "" }, panelStyles),
1506
+ (0, import_react5.createElement)("button", {
1251
1507
  ref: anchor2,
1252
1508
  type: "button",
1253
1509
  className: "dsh-tom-cost-pill",
@@ -1257,8 +1513,8 @@ function CostPanel({ totals, daily, balance }) {
1257
1513
  "aria-controls": open2 ? dialogId : void 0,
1258
1514
  "aria-label": `\u4F1A\u8BDD\u7D2F\u8BA1\u8D39\u7528 ${rows[1][1]}`,
1259
1515
  onClick: () => setOpen(!open2)
1260
- }, (0, import_react3.createElement)(CostIcon), (0, import_react3.createElement)("span", { className: "dsh-tom-cost-label" }, rows[1][1])),
1261
- open2 && (0, import_react_dom.createPortal)((0, import_react3.createElement)(
1516
+ }, (0, import_react5.createElement)(CostIcon), (0, import_react5.createElement)("span", { className: "dsh-tom-cost-label" }, rows[1][1])),
1517
+ open2 && (0, import_react_dom.createPortal)((0, import_react5.createElement)(
1262
1518
  "div",
1263
1519
  {
1264
1520
  ref: panel,
@@ -1268,11 +1524,11 @@ function CostPanel({ totals, daily, balance }) {
1268
1524
  className: "dsh-tom-cost-panel",
1269
1525
  style: { visibility: "hidden", left: 0, top: 0 }
1270
1526
  },
1271
- (0, import_react3.createElement)("div", { className: "dsh-tom-cost-title" }, (0, import_react3.createElement)(CostIcon), "\u8D39\u7528\u660E\u7EC6"),
1272
- (0, import_react3.createElement)("div", { className: "dsh-tom-cost-rule", "aria-hidden": true }),
1273
- (0, import_react3.createElement)("dl", { className: "dsh-tom-cost-details" }, rows.flatMap(([label, value]) => [
1274
- (0, import_react3.createElement)("dt", { key: label }, label),
1275
- (0, import_react3.createElement)("dd", { key: `${label}-value` }, value)
1527
+ (0, import_react5.createElement)("div", { className: "dsh-tom-cost-title" }, (0, import_react5.createElement)(CostIcon), "\u8D39\u7528\u660E\u7EC6"),
1528
+ (0, import_react5.createElement)("div", { className: "dsh-tom-cost-rule", "aria-hidden": true }),
1529
+ (0, import_react5.createElement)("dl", { className: "dsh-tom-cost-details" }, rows.flatMap(([label, value]) => [
1530
+ (0, import_react5.createElement)("dt", { key: label }, label),
1531
+ (0, import_react5.createElement)("dd", { key: `${label}-value` }, value)
1276
1532
  ]))
1277
1533
  ), anchor2.current.ownerDocument.body)
1278
1534
  );
@@ -21219,7 +21475,7 @@ function createBalanceStore(readBalance) {
21219
21475
  }
21220
21476
 
21221
21477
  // src/cost/settings.js
21222
- var import_react4 = require("react");
21478
+ var import_react6 = require("react");
21223
21479
 
21224
21480
  // src/cost/settings-styles.js
21225
21481
  var settingsStyles = `
@@ -21275,62 +21531,62 @@ function usageSummary(row) {
21275
21531
  function CostSettings({ useCostReport }) {
21276
21532
  const report = useCostReport((value2) => value2);
21277
21533
  const day = useBeijingDay();
21278
- const [hideZero, setHideZero] = (0, import_react4.useState)(true);
21534
+ const [hideZero, setHideZero] = (0, import_react6.useState)(true);
21279
21535
  const value = report.status === "ready" && report.value.day === day ? report.value : void 0;
21280
21536
  const status = report.status === "error" ? "\u8BFB\u53D6\u5931\u8D25" : "\u52A0\u8F7D\u4E2D\u2026";
21281
21537
  const rows = value ? visibleHistory(value.history, hideZero) : [];
21282
21538
  const summaries = [["today", "\u4ECA\u65E5\u8D39\u7528"], ["week", "\u672C\u5468\u8D39\u7528"], ["month", "\u672C\u6708\u8D39\u7528"]];
21283
- return (0, import_react4.createElement)(
21539
+ return (0, import_react6.createElement)(
21284
21540
  "section",
21285
21541
  { className: "dsh-tom-cost-settings", "aria-label": "\u8D39\u7528" },
21286
- (0, import_react4.createElement)("style", null, settingsStyles),
21287
- (0, import_react4.createElement)("div", { className: "dsh-tom-cost-cards" }, summaries.map(([key, label]) => {
21542
+ (0, import_react6.createElement)("style", null, settingsStyles),
21543
+ (0, import_react6.createElement)("div", { className: "dsh-tom-cost-cards" }, summaries.map(([key, label]) => {
21288
21544
  const row = value?.[key];
21289
- return (0, import_react4.createElement)(
21545
+ return (0, import_react6.createElement)(
21290
21546
  "div",
21291
21547
  { key, className: "dsh-tom-cost-card" },
21292
- (0, import_react4.createElement)("div", { className: "dsh-tom-cost-card-label" }, label),
21293
- (0, import_react4.createElement)("div", { className: "dsh-tom-cost-amount" }, row ? costValue(row.totals, row.failedSessions) : status),
21294
- (0, import_react4.createElement)("div", { className: "dsh-tom-cost-usage" }, usageSummary(row))
21548
+ (0, import_react6.createElement)("div", { className: "dsh-tom-cost-card-label" }, label),
21549
+ (0, import_react6.createElement)("div", { className: "dsh-tom-cost-amount" }, row ? costValue(row.totals, row.failedSessions) : status),
21550
+ (0, import_react6.createElement)("div", { className: "dsh-tom-cost-usage" }, usageSummary(row))
21295
21551
  );
21296
21552
  })),
21297
- (0, import_react4.createElement)(
21553
+ (0, import_react6.createElement)(
21298
21554
  "div",
21299
21555
  { className: "dsh-tom-cost-history-heading" },
21300
- (0, import_react4.createElement)("h3", null, "\u5386\u53F2\u8BB0\u5F55", (0, import_react4.createElement)("span", null, "\u6700\u8FD1 30 \u5929")),
21301
- (0, import_react4.createElement)(
21556
+ (0, import_react6.createElement)("h3", null, "\u5386\u53F2\u8BB0\u5F55", (0, import_react6.createElement)("span", null, "\u6700\u8FD1 30 \u5929")),
21557
+ (0, import_react6.createElement)(
21302
21558
  "label",
21303
21559
  { className: "dsh-tom-cost-filter" },
21304
- (0, import_react4.createElement)("input", { type: "checkbox", checked: hideZero, onChange: (event) => setHideZero(event.target.checked) }),
21560
+ (0, import_react6.createElement)("input", { type: "checkbox", checked: hideZero, onChange: (event) => setHideZero(event.target.checked) }),
21305
21561
  "\u8FC7\u6EE4\u96F6\u8D39\u7528\u65E5\u671F"
21306
21562
  )
21307
21563
  ),
21308
- (0, import_react4.createElement)(
21564
+ (0, import_react6.createElement)(
21309
21565
  "div",
21310
21566
  { className: "dsh-tom-cost-table-wrap", tabIndex: 0, role: "region", "aria-label": "\u6BCF\u65E5\u8D39\u7528\u5386\u53F2\u8BB0\u5F55" },
21311
- (0, import_react4.createElement)(
21567
+ (0, import_react6.createElement)(
21312
21568
  "table",
21313
21569
  { className: "dsh-tom-cost-table" },
21314
- (0, import_react4.createElement)("thead", null, (0, import_react4.createElement)("tr", null, ["\u65E5\u671F", "\u8C03\u7528", "\u8F93\u5165 tok", "\u7F13\u5B58 tok", "\u8F93\u51FA tok", "\u8D39\u7528"].map((label) => (0, import_react4.createElement)("th", { key: label, scope: "col" }, label)))),
21315
- (0, import_react4.createElement)("tbody", null, value && rows.length ? rows.map((row) => {
21570
+ (0, import_react6.createElement)("thead", null, (0, import_react6.createElement)("tr", null, ["\u65E5\u671F", "\u8C03\u7528", "\u8F93\u5165 tok", "\u7F13\u5B58 tok", "\u8F93\u51FA tok", "\u8D39\u7528"].map((label) => (0, import_react6.createElement)("th", { key: label, scope: "col" }, label)))),
21571
+ (0, import_react6.createElement)("tbody", null, value && rows.length ? rows.map((row) => {
21316
21572
  const totals = row.totals;
21317
21573
  const unavailable = row.failedSessions > 0 && calls(totals) === 0;
21318
- return (0, import_react4.createElement)(
21574
+ return (0, import_react6.createElement)(
21319
21575
  "tr",
21320
21576
  { key: row.day },
21321
- (0, import_react4.createElement)("td", null, row.day),
21322
- (0, import_react4.createElement)("td", null, unavailable ? "\u2014" : calls(totals).toLocaleString("zh-CN")),
21323
- ...["inputTokens", "cacheTokens", "outputTokens"].map((key) => (0, import_react4.createElement)("td", {
21577
+ (0, import_react6.createElement)("td", null, row.day),
21578
+ (0, import_react6.createElement)("td", null, unavailable ? "\u2014" : calls(totals).toLocaleString("zh-CN")),
21579
+ ...["inputTokens", "cacheTokens", "outputTokens"].map((key) => (0, import_react6.createElement)("td", {
21324
21580
  key,
21325
21581
  title: unavailable ? void 0 : totals[key].toLocaleString("zh-CN")
21326
21582
  }, unavailable ? "\u2014" : formatTokens(totals[key]))),
21327
- (0, import_react4.createElement)("td", null, costValue(totals, row.failedSessions))
21583
+ (0, import_react6.createElement)("td", null, costValue(totals, row.failedSessions))
21328
21584
  );
21329
- }) : (0, import_react4.createElement)("tr", null, (0, import_react4.createElement)("td", { colSpan: 6, className: "dsh-tom-cost-empty", role: "status" }, value ? "\u6700\u8FD1 30 \u5929\u6682\u65E0\u975E\u96F6\u8D39\u7528\u8BB0\u5F55" : status)))
21585
+ }) : (0, import_react6.createElement)("tr", null, (0, import_react6.createElement)("td", { colSpan: 6, className: "dsh-tom-cost-empty", role: "status" }, value ? "\u6700\u8FD1 30 \u5929\u6682\u65E0\u975E\u96F6\u8D39\u7528\u8BB0\u5F55" : status)))
21330
21586
  )
21331
21587
  ),
21332
- (0, import_react4.createElement)("p", { className: "dsh-tom-cost-note" }, "\u5317\u4EAC\u65F6\u95F4 \xB7 \u672C\u5468\u4ECE\u5468\u4E00\u5F00\u59CB \xB7 \u8D39\u7528\u6309\u672C\u673A\u4F1A\u8BDD\u8BB0\u5F55\u4F30\u7B97"),
21333
- value && value.history.some(incomplete) && (0, import_react4.createElement)(
21588
+ (0, import_react6.createElement)("p", { className: "dsh-tom-cost-note" }, "\u5317\u4EAC\u65F6\u95F4 \xB7 \u672C\u5468\u4ECE\u5468\u4E00\u5F00\u59CB \xB7 \u8D39\u7528\u6309\u672C\u673A\u4F1A\u8BDD\u8BB0\u5F55\u4F30\u7B97"),
21589
+ value && value.history.some(incomplete) && (0, import_react6.createElement)(
21334
21590
  "p",
21335
21591
  { className: "dsh-tom-cost-note", role: "status" },
21336
21592
  "\u90E8\u5206\u8BB0\u5F55\u65E0\u6CD5\u8BFB\u53D6\u6216\u8BA1\u4EF7\uFF0C\u76F8\u5173\u91D1\u989D\u53EF\u80FD\u4E0D\u5B8C\u6574\u3002"
@@ -21344,7 +21600,7 @@ function CostMount({ useProjection, useDailyCost, useAccountBalance, sessionId }
21344
21600
  const totals = useProjection(PROJECTION_KEY);
21345
21601
  const daily = useDailyCost((value) => value);
21346
21602
  const balance = useAccountBalance((value) => value);
21347
- return (0, import_react5.createElement)(CostPanel, { key: sessionId, totals, daily, balance });
21603
+ return (0, import_react7.createElement)(CostPanel, { key: sessionId, totals, daily, balance });
21348
21604
  }
21349
21605
  async function apply(ctx) {
21350
21606
  await ctx.remote.$mount(dailyRemote);
@@ -21380,10 +21636,10 @@ function ProjectHover({ sessionId, useWorkspaces, useSessions }) {
21380
21636
  const cwd = useSessions((state) => state.byId[sessionId]?.cwd);
21381
21637
  const path = workspace?.path || cwd;
21382
21638
  const name = workspace?.title || path?.split(/[\\/]/).filter(Boolean).at(-1) || path || "\u672A\u5F52\u5C5E\u9879\u76EE";
21383
- return (0, import_react6.createElement)(
21639
+ return (0, import_react8.createElement)(
21384
21640
  "div",
21385
21641
  { className: "dsh-css-project", title: path },
21386
- (0, import_react6.createElement)("svg", {
21642
+ (0, import_react8.createElement)("svg", {
21387
21643
  width: 14,
21388
21644
  height: 14,
21389
21645
  viewBox: "0 0 24 24",
@@ -21392,8 +21648,8 @@ function ProjectHover({ sessionId, useWorkspaces, useSessions }) {
21392
21648
  strokeWidth: 1.7,
21393
21649
  strokeLinejoin: "round",
21394
21650
  "aria-hidden": true
21395
- }, (0, import_react6.createElement)("path", { d: "M3 7V5a2 2 0 0 1 2-2h5l2 3h7a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V7Zm0 2h18" })),
21396
- (0, import_react6.createElement)("span", null, name)
21651
+ }, (0, import_react8.createElement)("path", { d: "M3 7V5a2 2 0 0 1 2-2h5l2 3h7a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V7Zm0 2h18" })),
21652
+ (0, import_react8.createElement)("span", null, name)
21397
21653
  );
21398
21654
  }
21399
21655
  function applySidebarWidth(layout) {
@@ -21435,6 +21691,28 @@ function applySidebarWidth(layout) {
21435
21691
  restore();
21436
21692
  };
21437
21693
  }
21694
+ function applySessionContextMenu() {
21695
+ const menuSelector = ".hIlkoa_sessionRow > .hIlkoa_rowActions > ._root_4ub78_1";
21696
+ const open2 = (event) => {
21697
+ const row = event.target.closest?.(".hIlkoa_sessionRow");
21698
+ const menu = row?.querySelector(menuSelector);
21699
+ const button = menu?.querySelector(":scope > button");
21700
+ if (!button) return;
21701
+ event.preventDefault();
21702
+ event.stopPropagation();
21703
+ menu.style.setProperty("--dsh-css-context-x", `${event.clientX}px`);
21704
+ menu.style.setProperty("--dsh-css-context-y", `${event.clientY}px`);
21705
+ if (!row.classList.contains("hIlkoa_menuOpen")) button.click();
21706
+ };
21707
+ document.addEventListener("contextmenu", open2);
21708
+ return () => {
21709
+ document.removeEventListener("contextmenu", open2);
21710
+ for (const menu of document.querySelectorAll(menuSelector)) {
21711
+ menu.style.removeProperty("--dsh-css-context-x");
21712
+ menu.style.removeProperty("--dsh-css-context-y");
21713
+ }
21714
+ };
21715
+ }
21438
21716
  async function apply2(ctx) {
21439
21717
  ctx.effect(() => {
21440
21718
  const style = document.createElement("style");
@@ -21445,8 +21723,11 @@ async function apply2(ctx) {
21445
21723
  return () => style.remove();
21446
21724
  });
21447
21725
  ctx.effect(() => applySidebarWidth(ctx.layout));
21726
+ ctx.effect(applySessionContextMenu);
21448
21727
  registerCacheHitPrecision(ctx);
21728
+ registerDateGroups(ctx);
21449
21729
  registerProjects(ctx);
21730
+ registerUnread(ctx);
21450
21731
  ctx.slots.inject("sidebar.session.row.hover", () => ctx.slots.register({
21451
21732
  name: "sidebar.session.row.hover",
21452
21733
  id: "dsh-css-project",
package/dist/index.js CHANGED
@@ -20064,10 +20064,33 @@ function apply(ctx) {
20064
20064
  });
20065
20065
  }
20066
20066
 
20067
+ // src/progress.js
20068
+ var PROGRESS_SECTION = "dsh-tom:progress-updates";
20069
+ var instructions = `# \u4EFB\u52A1\u8FDB\u5C55\u64AD\u62A5
20070
+ \u6267\u884C\u9700\u8981\u8C03\u67E5\u3001\u4FEE\u6539\u3001\u9A8C\u8BC1\u6216\u591A\u6B65\u5DE5\u5177\u64CD\u4F5C\u7684\u4EFB\u52A1\u65F6\uFF0C\u4E3B\u52A8\u5411\u7528\u6237\u7B80\u77ED\u6C47\u62A5\u8FDB\u5C55\uFF1A
20071
+ - \u7B2C\u4E00\u6B21\u8C03\u7528\u5DE5\u5177\u524D\uFF0C\u7528\u4E00\u4E24\u53E5\u8BDD\u8BF4\u660E\u63A5\u4E0B\u6765\u51C6\u5907\u505A\u4EC0\u4E48\u3002
20072
+ - \u83B7\u5F97\u5173\u952E\u53D1\u73B0\u3001\u8C03\u6574\u65B9\u5411\u6216\u8FDB\u5165\u9A8C\u8BC1\u9636\u6BB5\u65F6\uFF0C\u7B80\u77ED\u8BF4\u660E\u5DF2\u786E\u8BA4\u7684\u7ED3\u679C\u4EE5\u53CA\u4E0B\u4E00\u6B65\u3002\u8FDE\u7EED\u591A\u8F6E\u5DE5\u5177\u64CD\u4F5C\u65F6\u9002\u65F6\u66F4\u65B0\uFF0C\u4E0D\u8981\u59CB\u7EC8\u6C89\u9ED8\u76F4\u5230\u7ED3\u675F\uFF1B\u65E0\u9700\u6BCF\u6B21\u8C03\u7528\u5DE5\u5177\u90FD\u6C47\u62A5\uFF0C\u4E5F\u4E0D\u8981\u91CD\u590D\u7A7A\u6CDB\u7684\u201C\u6B63\u5728\u5904\u7406\u201D\u3002
20073
+ - \u8FDB\u5C55\u5FC5\u987B\u4F5C\u4E3A\u7528\u6237\u53EF\u89C1\u7684\u666E\u901A\u52A9\u624B\u6B63\u6587\u8F93\u51FA\uFF0C\u4E0D\u8981\u53EA\u653E\u5728\u601D\u8003\u5185\u5BB9\u3001\u5DE5\u5177\u53C2\u6570\u6216\u6700\u7EC8\u56DE\u7B54\u91CC\u3002\u9700\u8981\u7EE7\u7EED\u6267\u884C\u65F6\uFF0C\u5728\u540C\u4E00\u54CD\u5E94\u4E2D\u5148\u8F93\u51FA\u8FDB\u5C55\u6B63\u6587\uFF0C\u518D\u53D1\u8D77\u5B9E\u9645\u5DE5\u5177\u8C03\u7528\uFF1B\u4E0D\u8981\u4EC5\u8BF4\u201C\u63A5\u4E0B\u6765\u4F1A\u505A\u201D\u5C31\u7ED3\u675F\u4EFB\u52A1\u6216\u7B49\u5F85\u786E\u8BA4\u3002
20074
+ - \u53EA\u62A5\u544A\u771F\u5B9E\u89C2\u5BDF\u3001\u5DF2\u7ECF\u5B8C\u6210\u7684\u64CD\u4F5C\u548C\u660E\u786E\u7684\u4E0B\u4E00\u6B65\uFF0C\u4E0D\u8981\u63D0\u524D\u58F0\u79F0\u6210\u529F\uFF0C\u4E0D\u8981\u5C55\u793A\u5185\u90E8\u63A8\u7406\u8FC7\u7A0B\u3002\u9ED8\u8BA4\u4F7F\u7528\u7528\u6237\u7684\u8BED\u8A00\uFF0C\u6BCF\u6B21\u4E00\u4E24\u53E5\u8BDD\u3002
20075
+ - \u7B80\u5355\u95EE\u7B54\u76F4\u63A5\u56DE\u7B54\u3002\u7528\u6237\u660E\u786E\u8981\u6C42\u4E0D\u64AD\u62A5\u3001\u4EC5\u7ED9\u7ED3\u8BBA\u6216\u7279\u5B9A\u8F93\u51FA\u683C\u5F0F\u65F6\uFF0C\u9075\u5FAA\u7528\u6237\u8981\u6C42\u3002
20076
+ - \u4EFB\u52A1\u5B8C\u6210\u540E\u6309\u539F\u6709\u65B9\u5F0F\u7ED9\u51FA\u6700\u7EC8\u56DE\u7B54\uFF0C\u4E0D\u8981\u628A\u4E2D\u9014\u64AD\u62A5\u91CD\u65B0\u62FC\u6210\u4E00\u4EFD\u91CD\u590D\u7684\u603B\u7ED3\u3002`;
20077
+ function registerProgressUpdates(ctx) {
20078
+ ctx.systemPrompt.section({
20079
+ name: PROGRESS_SECTION,
20080
+ order: 10300,
20081
+ interpolate: false,
20082
+ text: ({ agent }) => agent && agent.session.header.origin !== "subagent" ? instructions : ""
20083
+ });
20084
+ }
20085
+
20067
20086
  // index.js
20068
20087
  var name = "dsh-css";
20088
+ function apply2(ctx) {
20089
+ apply(ctx);
20090
+ ctx.inject(["systemPrompt"], registerProgressUpdates);
20091
+ }
20069
20092
  export {
20070
- apply,
20093
+ apply2 as apply,
20071
20094
  inject,
20072
20095
  name
20073
20096
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dsh-tom/dsh-css",
3
- "version": "0.2.1",
4
- "description": "为 DeepSeek Harness 调整深色界面,增加项目管理、会话费用和费用历史统计。",
3
+ "version": "0.2.10",
4
+ "description": "为 DeepSeek Harness 调整深色界面,增加项目管理、费用统计和任务进展播报。",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "exports": {
@@ -43,7 +43,7 @@
43
43
  "scripts": {
44
44
  "build": "node scripts/build.mjs",
45
45
  "test": "node --test test/*.test.mjs",
46
- "check": "node --check index.js && node --check src/client.js && node --check src/projects.js && node --check scripts/build.mjs && npm run build && node --check dist/index.js && node --check dist/client.js && npm test",
46
+ "check": "node --check index.js && node --check src/client.js && node --check src/projects.js && node --check src/progress.js && node --check scripts/build.mjs && npm run build && node --check dist/index.js && node --check dist/client.js && npm test",
47
47
  "prepack": "npm run check"
48
48
  },
49
49
  "license": "MIT",
@@ -65,6 +65,7 @@
65
65
  "@deepseek-ai/dsh-typert-registry": "0.2.1-rc.2",
66
66
  "@deepseek-ai/dsh-typert-protocol": "0.2.1-rc.2",
67
67
  "@deepseek-ai/dsh-session-projection": "0.2.1-rc.2",
68
+ "@deepseek-ai/dsh-system-prompt": "0.2.1-rc.2",
68
69
  "esbuild": "0.28.2",
69
70
  "jsdom": "^27.0.0",
70
71
  "react": "18.3.1",
package/theme.css CHANGED
@@ -1,3 +1,34 @@
1
+ .dsh-css-unread-dot {
2
+ display: inline-block;
3
+ flex: none;
4
+ width: 8px;
5
+ height: 8px;
6
+ border-radius: 50%;
7
+ background: var(--dsw-alias-label-secondary, #aaa);
8
+ }
9
+
10
+ /* 会话操作出现时隐藏未读提示;项目树保留左侧图标位置,避免标题跳动。 */
11
+ .hIlkoa_sessionRow:is(:hover, .hIlkoa_menuOpen) > .hIlkoa_slot .dsh-css-unread-dot {
12
+ visibility: hidden;
13
+ }
14
+
15
+ /* 菜单关闭可能残留宿主的滚动和渐隐状态;非悬停时从标题开头正常显示。 */
16
+ .hIlkoa_sessionRow:not(:hover):not(.hIlkoa_menuOpen) > .hIlkoa_title {
17
+ overflow: clip;
18
+ mask-image: none;
19
+ }
20
+
21
+ /* 会话菜单改为右键打开;保留宿主菜单锚点,并移到鼠标位置。 */
22
+ .hIlkoa_sessionRow > .hIlkoa_rowActions > ._root_4ub78_1 {
23
+ position: fixed;
24
+ left: var(--dsh-css-context-x, 0px);
25
+ top: var(--dsh-css-context-y, 0px);
26
+ width: 0;
27
+ height: 0;
28
+
29
+ & > button { display: none; }
30
+ }
31
+
1
32
  /* 深色模式配色,保留内置文字、边框和语法高亮颜色。 */
2
33
  html body[data-ds-dark-theme] {
3
34
  /* 区域 1:左侧会话列表;Windows 标题栏在下方单独设置。原 RGB(27, 27, 28)。 */
@@ -166,9 +197,17 @@ html[data-windows-titlebar] body[data-ds-dark-theme] ._2H3hWW_root:not(._2H3hWW_
166
197
  padding: 44px 0 0 12px;
167
198
  }
168
199
 
169
- /* 平铺会话标题与“会话”左对齐,状态图标放到右侧。 */
200
+ /* 操作按钮间距 15px → 10px;右侧内边距 8px → 4px。 */
201
+ & .hIlkoa_sessionRow {
202
+ padding-inline-end: 4px;
203
+
204
+ & > .hIlkoa_rowActions { gap: 10px; }
205
+ }
206
+
207
+ /* 行背景向左延伸 4px,留足标题内边距并与“会话”保持左对齐。 */
170
208
  & ._9lTDKa_flatList .hIlkoa_sessionRow {
171
- padding-inline-start: 4px;
209
+ margin-inline-start: -4px;
210
+ padding-inline-start: 8px;
172
211
 
173
212
  & > .hIlkoa_title {
174
213
  margin-left: 0;
@@ -178,7 +217,13 @@ html[data-windows-titlebar] body[data-ds-dark-theme] ._2H3hWW_root:not(._2H3hWW_
178
217
  order: 1;
179
218
  }
180
219
 
181
- & > .hIlkoa_slot:empty {
220
+ /* 空状态占位减半,与右内边距合计 12px;实际状态图标保留原宽度。 */
221
+ & > .hIlkoa_slot:has(> [data-slot="sidebar.session.row.leading"]:empty) {
222
+ width: 8px;
223
+ }
224
+
225
+ & > .hIlkoa_slot:empty,
226
+ &:is(:hover, .hIlkoa_menuOpen) > .hIlkoa_slot:has(.dsh-css-unread-dot) {
182
227
  display: none;
183
228
  }
184
229
  }
@@ -255,6 +300,15 @@ html[data-windows-titlebar] body[data-ds-dark-theme] ._2H3hWW_root:not(._2H3hWW_
255
300
  }
256
301
  }
257
302
 
303
+ .dsh-css-date-heading {
304
+ padding: 16px 4px 6px;
305
+ color: var(--dsw-alias-label-tertiary);
306
+ font-size: 12px;
307
+ line-height: 18px;
308
+
309
+ &:first-child { padding-top: 6px; }
310
+ }
311
+
258
312
  /* 悬浮卡片由宿主通过 portal 挂在侧栏外。 */
259
313
  .dsh-css-project {
260
314
  display: none;