@michengai/dsh-codex-ui 1.1.11 → 1.1.12

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/CHANGELOG.md CHANGED
@@ -4,6 +4,30 @@
4
4
 
5
5
  This changelog records recent releases of DSH Codex UI and its one-click installer. Earlier changes remain available in the [Git history](https://github.com/MichengAI/dsh-codex-ui/commits/main).
6
6
 
7
+ ## 1.1.12 - 2026-09-17
8
+
9
+ - Session rows show compact relative time on the right (now, minutes, hours, days, weeks, months, years). Hover or the action menu yields to the archive shortcut; a pending label hides the inline time.
10
+ - Truncated session titles scroll on hover or when the menu is open. Reduced motion keeps the ellipsis.
11
+ - Relative times refresh every minute. Inline English uses now; hover cards use Just now.
12
+
13
+ ## suite-installer-v1.0.14 - 2026-09-16
14
+
15
+ Install or maintain 11 first-party plugins in one step. Included plugins and versions:
16
+
17
+ - `@michengai/dsh-archive-manager@0.1.43`
18
+ - `@michengai/dsh-codex-ui@1.1.11`
19
+ - `@michengai/dsh-skills-manager@0.1.52`
20
+ - `@michengai/dsh-agency-agents@0.1.43`
21
+ - `@michengai/dsh-im-connect@0.1.50`
22
+ - `@michengai/dsh-automation@0.1.44`
23
+ - `@michengai/dsh-btw@0.1.8`
24
+ - `@michengai/dsh-simplify@0.1.5`
25
+ - `@michengai/dsh-pua@0.3.13`
26
+ - `@michengai/dsh-code-review@0.1.2`
27
+ - `@michengai/dsh-codex-pet@0.1.6`
28
+
29
+ The installer uses these exact versions for reproducible installation.
30
+
7
31
  ## 1.1.11 - 2026-09-16
8
32
 
9
33
  - Open the settings page (and usage statistics) through a `document.body` portal so a collapsed 56px rail cannot trap the overlay in a transform containing block.
@@ -4,6 +4,30 @@
4
4
 
5
5
  本日志记录 DSH Codex UI 及其一键安装器的最近发布;更早的变更可查看 [Git 提交历史](https://github.com/MichengAI/dsh-codex-ui/commits/main)。
6
6
 
7
+ ## 1.1.12 - 2026-09-17
8
+
9
+ - 会话行右侧显示紧凑相对时间(刚刚、分、小时、天、周、月、年)。悬停或打开菜单时让位给归档快捷图标;待处理标签优先于行内时间。
10
+ - 标题被截断时,悬停或打开菜单会横向滚动全文;系统减动效时保持省略号。
11
+ - 相对时间每分钟对齐刷新。行内英文用 now,悬停卡片用 Just now。
12
+
13
+ ## suite-installer-v1.0.14 - 2026-09-16
14
+
15
+ 一键维护安装 11 个自研插件。包含以下插件及版本:
16
+
17
+ - `@michengai/dsh-archive-manager@0.1.43`
18
+ - `@michengai/dsh-codex-ui@1.1.11`
19
+ - `@michengai/dsh-skills-manager@0.1.52`
20
+ - `@michengai/dsh-agency-agents@0.1.43`
21
+ - `@michengai/dsh-im-connect@0.1.50`
22
+ - `@michengai/dsh-automation@0.1.44`
23
+ - `@michengai/dsh-btw@0.1.8`
24
+ - `@michengai/dsh-simplify@0.1.5`
25
+ - `@michengai/dsh-pua@0.3.13`
26
+ - `@michengai/dsh-code-review@0.1.2`
27
+ - `@michengai/dsh-codex-pet@0.1.6`
28
+
29
+ 安装器使用这些精确版本执行安装,确保可复现。
30
+
7
31
  ## 1.1.11 - 2026-09-16
8
32
 
9
33
  - 设置页和用量统计改为挂到 `document.body`。侧栏收缩后,宿主或插件若给窄轨加了 transform,全屏页不再被困在 56px 里挤成竖排。
package/lib/client.js CHANGED
@@ -1246,6 +1246,23 @@ window.__ModuleLoader__.load({
1246
1246
  return parseChannelGroups(payload, fallbackLabel);
1247
1247
  }
1248
1248
  //#endregion
1249
+ //#region src/client/session-title-scroll.ts
1250
+ /** 会话行只展示标题第一行,避免换行把胶囊撑高。 */
1251
+ function sessionTitleLine(title) {
1252
+ return title.split(/\r?\n/)[0] ?? title;
1253
+ }
1254
+ /** 标题比可视槽多出来的像素;1px 内当作测量误差。 */
1255
+ function titleOverflowPx(scrollWidth, clientWidth) {
1256
+ const extra = Math.ceil(scrollWidth - clientWidth);
1257
+ return extra > 1 ? extra : 0;
1258
+ }
1259
+ const PX_PER_SECOND = 42;
1260
+ /** 按溢出长度估算单程时长,长标题更慢,避免一闪而过。 */
1261
+ function titleScrollDurationMs(overflowPx) {
1262
+ if (overflowPx <= 0) return 0;
1263
+ return Math.min(8e3, Math.max(1600, Math.round(overflowPx / PX_PER_SECOND * 1e3)));
1264
+ }
1265
+ //#endregion
1249
1266
  //#region src/client/session-tree.tsx
1250
1267
  function PinIcon() {
1251
1268
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Pin, {
@@ -1416,7 +1433,58 @@ window.__ModuleLoader__.load({
1416
1433
  });
1417
1434
  return null;
1418
1435
  }
1419
- function SessionRow({ id, title, selected, menuOpen, unread, running, pendingInteraction, t, menuItems, onOpen, onMenuChange, onSelectAction, onArchive, onHover, onLeave, onContextMenu, menuPoint, subtitle, flat, draggable, dropActive, onDragStart, onDragEnd, onDragOver, onDrop }) {
1436
+ function SessionTime({ time }) {
1437
+ if (time === void 0 || time === "") return null;
1438
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1439
+ className: "dcu-wb-session-time",
1440
+ children: time
1441
+ });
1442
+ }
1443
+ function SessionRowTitle({ title }) {
1444
+ const text = sessionTitleLine(title);
1445
+ const wrapRef = (0, react.useRef)(null);
1446
+ const textRef = (0, react.useRef)(null);
1447
+ const [shift, setShift] = (0, react.useState)(0);
1448
+ (0, react.useLayoutEffect)(() => {
1449
+ const wrap = wrapRef.current;
1450
+ const inner = textRef.current;
1451
+ if (wrap === null || inner === null) return;
1452
+ const measure = () => {
1453
+ setShift(titleOverflowPx(inner.scrollWidth, wrap.clientWidth));
1454
+ };
1455
+ measure();
1456
+ let cancelled = false;
1457
+ const fonts = typeof document === "undefined" ? void 0 : document.fonts;
1458
+ if (fonts !== void 0) fonts.ready.then(() => {
1459
+ if (!cancelled) measure();
1460
+ });
1461
+ if (typeof ResizeObserver === "undefined") return () => {
1462
+ cancelled = true;
1463
+ };
1464
+ const observer = new ResizeObserver(measure);
1465
+ observer.observe(wrap);
1466
+ return () => {
1467
+ cancelled = true;
1468
+ observer.disconnect();
1469
+ };
1470
+ }, [text]);
1471
+ const style = shift > 0 ? {
1472
+ "--dcu-title-shift": `${shift}px`,
1473
+ "--dcu-title-duration": `${titleScrollDurationMs(shift)}ms`
1474
+ } : void 0;
1475
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1476
+ ref: wrapRef,
1477
+ className: "dcu-wb-session-title",
1478
+ "data-overflow": shift > 0 || void 0,
1479
+ style,
1480
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1481
+ ref: textRef,
1482
+ className: "dcu-wb-session-title-text",
1483
+ children: text
1484
+ })
1485
+ });
1486
+ }
1487
+ function SessionRow({ id, title, selected, menuOpen, unread, running, pendingInteraction, t, menuItems, onOpen, onMenuChange, onSelectAction, onArchive, onHover, onLeave, onContextMenu, menuPoint, subtitle, flat, draggable, dropActive, onDragStart, onDragEnd, onDragOver, onDrop, time }) {
1420
1488
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1421
1489
  "data-dcu-session": id,
1422
1490
  className: `dcu-wb-session${selected ? " dcu-wb-selected" : ""}${menuOpen ? " dcu-wb-menu-open" : ""}${dropActive === true ? " dcu-wb-drop" : ""}${flat === true ? " dcu-wb-session-flat" : ""}`,
@@ -1434,23 +1502,18 @@ window.__ModuleLoader__.load({
1434
1502
  children: [
1435
1503
  subtitle !== void 0 && subtitle !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1436
1504
  className: "dcu-wb-session-copy",
1437
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1438
- className: "dcu-wb-session-title",
1439
- children: title.split(/\r?\n/)[0] ?? title
1440
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1505
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SessionRowTitle, { title }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1441
1506
  className: "dcu-wb-session-sub",
1442
1507
  children: subtitle
1443
1508
  })]
1444
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1445
- className: "dcu-wb-session-title",
1446
- children: title.split(/\r?\n/)[0] ?? title
1447
- }),
1509
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SessionRowTitle, { title }),
1448
1510
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SessionState, {
1449
1511
  pendingInteraction,
1450
1512
  unread,
1451
1513
  running,
1452
1514
  t
1453
1515
  }),
1516
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SessionTime, { time }),
1454
1517
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1455
1518
  className: "dcu-wb-quick-actions",
1456
1519
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
@@ -1915,13 +1978,84 @@ window.__ModuleLoader__.load({
1915
1978
  top: rect.top
1916
1979
  };
1917
1980
  }
1918
- /** Codex 会话卡片右上角的紧凑相对时间。 */
1981
+ const HOUR = 3600;
1982
+ const DAY = HOUR * 24;
1983
+ const WEEK = DAY * 7;
1984
+ const MONTH = DAY * 30;
1985
+ const YEAR = DAY * 365;
1986
+ function formatRelativeTime(updatedAt, t, now, justNow) {
1987
+ const seconds = Math.max(0, Math.floor((now - updatedAt) / 1e3));
1988
+ if (seconds < 60) return t(justNow);
1989
+ if (seconds < HOUR) return t("time.minutes", { count: Math.floor(seconds / 60) });
1990
+ if (seconds < DAY) return t("time.hours", { count: Math.floor(seconds / HOUR) });
1991
+ if (seconds < WEEK) return t("time.days", { count: Math.floor(seconds / DAY) });
1992
+ if (seconds < MONTH) return t("time.weeks", { count: Math.floor(seconds / WEEK) });
1993
+ if (seconds < YEAR) return t("time.months", { count: Math.floor(seconds / MONTH) });
1994
+ return t("time.years", { count: Math.floor(seconds / YEAR) });
1995
+ }
1996
+ /** 悬停卡片右上角。分档与 ChatGPT `$wa` 一致;英文刚刚用 Just now。 */
1919
1997
  function formatHoverTime(updatedAt, t, now = Date.now()) {
1920
- const seconds = Math.max(0, Math.round((now - updatedAt) / 1e3));
1921
- if (seconds < 60) return t("time.justNow");
1922
- if (seconds < 3600) return t("time.minutes", { count: Math.floor(seconds / 60) });
1923
- if (seconds < 86400) return t("time.hours", { count: Math.floor(seconds / 3600) });
1924
- return t("time.days", { count: Math.floor(seconds / 86400) });
1998
+ return formatRelativeTime(updatedAt, t, now, "time.justNow");
1999
+ }
2000
+ /** 会话行右侧。分档相同;英文刚刚用 now,避免挤占标题。 */
2001
+ function formatCompactTime(updatedAt, t, now = Date.now()) {
2002
+ return formatRelativeTime(updatedAt, t, now, "time.justNowShort");
2003
+ }
2004
+ //#endregion
2005
+ //#region src/client/shared-now.ts
2006
+ const SHARED_NOW_INTERVAL_MS = 6e4;
2007
+ /** 对齐到下一个整档,避免「刚刚」在整分钟边界之后还多停将近一轮。 */
2008
+ function msUntilNextNowTick(now, intervalMs = SHARED_NOW_INTERVAL_MS) {
2009
+ const remainder = now % intervalMs;
2010
+ return remainder === 0 ? intervalMs : intervalMs - remainder;
2011
+ }
2012
+ const listeners = /* @__PURE__ */ new Set();
2013
+ let sharedNow = Date.now();
2014
+ let timeoutId = 0;
2015
+ let intervalId = 0;
2016
+ let cancelled = true;
2017
+ function publish(now) {
2018
+ sharedNow = now;
2019
+ for (const listener of listeners) listener();
2020
+ }
2021
+ function startClock() {
2022
+ cancelled = false;
2023
+ timeoutId = window.setTimeout(() => {
2024
+ if (cancelled) return;
2025
+ publish(Date.now());
2026
+ intervalId = window.setInterval(() => {
2027
+ publish(Date.now());
2028
+ }, SHARED_NOW_INTERVAL_MS);
2029
+ if (cancelled) {
2030
+ window.clearInterval(intervalId);
2031
+ intervalId = 0;
2032
+ }
2033
+ }, msUntilNextNowTick(Date.now()));
2034
+ }
2035
+ function stopClock() {
2036
+ cancelled = true;
2037
+ window.clearTimeout(timeoutId);
2038
+ window.clearInterval(intervalId);
2039
+ timeoutId = 0;
2040
+ intervalId = 0;
2041
+ }
2042
+ function subscribe(listener) {
2043
+ if (listeners.size === 0) {
2044
+ sharedNow = Date.now();
2045
+ startClock();
2046
+ }
2047
+ listeners.add(listener);
2048
+ return () => {
2049
+ listeners.delete(listener);
2050
+ if (listeners.size === 0) stopClock();
2051
+ };
2052
+ }
2053
+ function getSnapshot() {
2054
+ return sharedNow;
2055
+ }
2056
+ /** 模块级当前时刻。几棵树挂着都只走一套定时器,每分钟刷新一次。 */
2057
+ function useSharedNow() {
2058
+ return (0, react.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
1925
2059
  }
1926
2060
  //#endregion
1927
2061
  //#region src/client/conversation-bubbles.ts
@@ -2901,7 +3035,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
2901
3035
  }
2902
3036
  const previewTitle = document.createElement("span");
2903
3037
  previewTitle.className = "dcu-wb-drag-ghost-title";
2904
- previewTitle.textContent = title.split(/\r?\n/)[0] ?? title;
3038
+ previewTitle.textContent = sessionTitleLine(title);
2905
3039
  preview.appendChild(previewTitle);
2906
3040
  document.body.appendChild(preview);
2907
3041
  preview.offsetWidth;
@@ -3016,11 +3150,11 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
3016
3150
  .dcu-wb-project-title,.dcu-wb-session-title{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:14px;line-height:20px}
3017
3151
  .dcu-wb-project-title{flex:1;font-weight:400;color:var(--dcu-sidebar-primary)}
3018
3152
  .dcu-wb-session{position:relative;min-width:0;min-height:30px;gap:0;overflow:hidden;padding-left:30px;padding-right:28px}
3019
- .dcu-wb-session-title{flex:1;margin-left:0}.dcu-wb-session-copy{flex:1;min-width:0;display:flex;flex-direction:column;justify-content:center}.dcu-wb-session-sub{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dcu-sidebar-tertiary);font-size:12px;line-height:16px}.dcu-wb-session-flat,.dcu-wb-session-top{padding-left:8px}.dcu-wb-session-flat:has(.dcu-wb-running),.dcu-wb-session-top:has(.dcu-wb-running){padding-left:30px}
3153
+ .dcu-wb-session-title{flex:1;margin-left:0}.dcu-wb-session-title-text{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}@media (prefers-reduced-motion:no-preference){.dcu-wb-session:hover .dcu-wb-session-title[data-overflow] .dcu-wb-session-title-text,.dcu-wb-session.dcu-wb-menu-open .dcu-wb-session-title[data-overflow] .dcu-wb-session-title-text{display:inline-block;width:max-content;max-width:none;overflow:visible;text-overflow:clip;animation:dcu-wb-title-scroll var(--dcu-title-duration,2.4s) linear 320ms infinite alternate}}@keyframes dcu-wb-title-scroll{0%,18%{transform:translateX(0)}82%,100%{transform:translateX(calc(-1 * var(--dcu-title-shift,0px)))}}.dcu-wb-session-time{position:absolute;right:8px;top:50%;transform:translateY(-50%);color:var(--dcu-sidebar-tertiary);font-size:12px;line-height:18px;font-weight:400;font-variant-numeric:tabular-nums;white-space:nowrap;pointer-events:none}.dcu-wb-session:has(.dcu-wb-session-time){padding-right:64px}.dcu-wb-session:has(.dcu-wb-unread) .dcu-wb-session-time{right:22px}.dcu-wb-session:has(.dcu-wb-unread):has(.dcu-wb-session-time){padding-right:78px}.dcu-wb-session-copy{flex:1;min-width:0;display:flex;flex-direction:column;justify-content:center}.dcu-wb-session-sub{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dcu-sidebar-tertiary);font-size:12px;line-height:16px}.dcu-wb-session-flat,.dcu-wb-session-top{padding-left:8px}.dcu-wb-session-flat:has(.dcu-wb-running),.dcu-wb-session-top:has(.dcu-wb-running){padding-left:30px}
3020
3154
  .dcu-wb-actions{display:none;align-items:center;gap:8px;flex:none}
3021
3155
  .dcu-wb-quick-actions{position:absolute;right:8px;top:50%;display:flex;align-items:center;gap:2px;opacity:0;pointer-events:none;transform:translateY(-50%);background:var(--dcu-sidebar-hover);border-radius:6px}
3022
3156
  .dcu-wb-project-head:hover .dcu-wb-actions,.dcu-wb-project-head.dcu-wb-menu-open .dcu-wb-actions,.dcu-wb-session.dcu-wb-menu-open .dcu-wb-actions{display:flex}
3023
- .dcu-wb-session:hover .dcu-wb-quick-actions,.dcu-wb-session.dcu-wb-menu-open .dcu-wb-quick-actions{opacity:1;pointer-events:auto}.dcu-wb-session:hover .dcu-wb-pending,.dcu-wb-session.dcu-wb-menu-open .dcu-wb-pending,.dcu-wb-session:hover .dcu-wb-unread,.dcu-wb-session.dcu-wb-menu-open .dcu-wb-unread{visibility:hidden}
3157
+ .dcu-wb-session:hover .dcu-wb-quick-actions,.dcu-wb-session.dcu-wb-menu-open .dcu-wb-quick-actions{opacity:1;pointer-events:auto}.dcu-wb-session:hover .dcu-wb-pending,.dcu-wb-session.dcu-wb-menu-open .dcu-wb-pending,.dcu-wb-session:hover .dcu-wb-unread,.dcu-wb-session.dcu-wb-menu-open .dcu-wb-unread,.dcu-wb-session:hover .dcu-wb-session-time,.dcu-wb-session.dcu-wb-menu-open .dcu-wb-session-time{visibility:hidden}.dcu-wb-session:has(.dcu-wb-pending) .dcu-wb-session-time{display:none}
3024
3158
  .dcu-wb-more{display:grid;place-items:center;width:20px;height:20px;border:0;border-radius:4px;padding:0;background:transparent;color:var(--dcu-sidebar-tertiary);cursor:pointer}
3025
3159
  .dcu-wb-more:hover{color:var(--dcu-sidebar-primary)}
3026
3160
  .dcu-wb-context-anchor{opacity:0;pointer-events:none}
@@ -3091,6 +3225,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
3091
3225
  }
3092
3226
  function CodexWorkspaceTree({ wide, useSessions, useSessionPendingInteraction, useWorkspaces, t, archiveSession, deleteSession, deleteWorkspace, forkSession, insertSessionBefore, insertWorkspaceBefore, moveSession, openPath, openSession, renameSession, renameWorkspace, startSession, canDeleteSession }) {
3093
3227
  const sessions = useSessions((state) => state);
3228
+ const now = useSharedNow();
3094
3229
  const pendingInteractions = (useSessionPendingInteraction ?? useEmptySessionPendingInteraction)((state) => state);
3095
3230
  const workspaces = useWorkspaces((state) => state);
3096
3231
  const baselinesReady = workspaceBaselinesReady(workspaces, sessions);
@@ -3951,23 +4086,21 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
3951
4086
  project: workspace.title,
3952
4087
  path,
3953
4088
  branch,
3954
- time: formatHoverTime(session.updatedAt, t),
4089
+ time: formatHoverTime(session.updatedAt, t, now),
3955
4090
  left: box.left,
3956
4091
  top: box.top
3957
4092
  });
3958
4093
  },
3959
4094
  onMouseLeave: hideTip,
3960
4095
  children: [
3961
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3962
- className: "dcu-wb-session-title",
3963
- children: session.displayTitle.split(/\r?\n/)[0] ?? session.displayTitle
3964
- }),
4096
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SessionRowTitle, { title: session.displayTitle }),
3965
4097
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SessionState, {
3966
4098
  pendingInteraction,
3967
4099
  unread: unreadSessionIds.includes(id),
3968
4100
  running: session.running === true,
3969
4101
  t
3970
4102
  }),
4103
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SessionTime, { time: formatCompactTime(session.updatedAt, t, now) }),
3971
4104
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3972
4105
  className: "dcu-wb-quick-actions",
3973
4106
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
@@ -4724,6 +4857,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
4724
4857
  unread,
4725
4858
  running: session.running === true,
4726
4859
  pendingInteraction,
4860
+ time: formatCompactTime(session.updatedAt, t, now),
4727
4861
  t,
4728
4862
  menuItems: sessionMenu(id, session.cwd),
4729
4863
  draggable: true,
@@ -4769,7 +4903,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
4769
4903
  kind: "session",
4770
4904
  id,
4771
4905
  title,
4772
- time: formatHoverTime(session.updatedAt, t),
4906
+ time: formatHoverTime(session.updatedAt, t, now),
4773
4907
  left: box.left,
4774
4908
  top: box.top
4775
4909
  });
@@ -5418,6 +5552,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
5418
5552
  }
5419
5553
  function ChannelBrowserTree({ openSession, archiveSession, deleteSession, forkSession, moveSession, renameSession, useSessions, useSessionPendingInteraction, useWorkspaces, t, canDeleteSession, menu, setMenu }) {
5420
5554
  const sessions = useSessions((state) => state);
5555
+ const now = useSharedNow();
5421
5556
  const workspaces = useWorkspaces?.((state) => state);
5422
5557
  const pendingInteractions = (useSessionPendingInteraction ?? useEmptySessionPendingInteraction)((state) => state);
5423
5558
  const [groups, setGroups] = (0, react.useState)([]);
@@ -5537,6 +5672,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
5537
5672
  unread,
5538
5673
  running,
5539
5674
  pendingInteraction,
5675
+ time: updatedAt === void 0 ? void 0 : formatCompactTime(updatedAt, t, now),
5540
5676
  t,
5541
5677
  menuItems: sessionMenuItems(t, {
5542
5678
  unread,
@@ -5562,7 +5698,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
5562
5698
  showTip({
5563
5699
  title,
5564
5700
  project: label,
5565
- time: updatedAt === void 0 ? void 0 : formatHoverTime(updatedAt, t),
5701
+ time: updatedAt === void 0 ? void 0 : formatHoverTime(updatedAt, t, now),
5566
5702
  left: box.left,
5567
5703
  top: box.top
5568
5704
  });
@@ -5692,6 +5828,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
5692
5828
  }
5693
5829
  function ScheduleBrowserTree({ openSession, archiveSession, deleteSession, forkSession, moveSession, renameSession, useSessions, useSessionPendingInteraction, useWorkspaces, t, canDeleteSession, openTaskSettings, menu, setMenu }) {
5694
5830
  const sessions = useSessions((state) => state);
5831
+ const now = useSharedNow();
5695
5832
  const pendingInteractions = (useSessionPendingInteraction ?? useEmptySessionPendingInteraction)((state) => state);
5696
5833
  const workspaces = useWorkspaces((state) => state);
5697
5834
  const [expanded, setExpanded] = (0, react.useState)(() => readTreeExpansionState(browserStorage(), SCHEDULE_EXPANSION_STORAGE_KEY));
@@ -5841,6 +5978,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
5841
5978
  unread,
5842
5979
  running: session.running,
5843
5980
  pendingInteraction,
5981
+ time: session.updatedAt === void 0 ? void 0 : formatCompactTime(session.updatedAt, t, now),
5844
5982
  t,
5845
5983
  menuItems: sessionMenuItems(t, {
5846
5984
  unread,
@@ -5866,7 +6004,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
5866
6004
  showTip({
5867
6005
  title,
5868
6006
  project: group.label,
5869
- time: session.updatedAt === void 0 ? void 0 : formatHoverTime(session.updatedAt, t),
6007
+ time: session.updatedAt === void 0 ? void 0 : formatHoverTime(session.updatedAt, t, now),
5870
6008
  left: box.left,
5871
6009
  top: box.top
5872
6010
  });
@@ -8284,9 +8422,13 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
8284
8422
  "turns.untitled": "未命名提问",
8285
8423
  "turns.jump": "跳转到第 {index} 轮:{summary}",
8286
8424
  "time.justNow": "刚刚",
8425
+ "time.justNowShort": "刚刚",
8287
8426
  "time.minutes": "{count}分",
8288
8427
  "time.hours": "{count}小时",
8289
8428
  "time.days": "{count}天",
8429
+ "time.weeks": "{count}周",
8430
+ "time.months": "{count}个月",
8431
+ "time.years": "{count}年",
8290
8432
  "errors.unauthorized": "请先登录 DSH,再重试。",
8291
8433
  "errors.forbidden": "请求被安全检查拒绝,请从可信的 DSH 地址重试。",
8292
8434
  "errors.serviceUnavailable": "服务暂不可用,请稍后重试。",
@@ -8568,9 +8710,13 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
8568
8710
  "turns.untitled": "Untitled prompt",
8569
8711
  "turns.jump": "Jump to turn {index}: {summary}",
8570
8712
  "time.justNow": "Just now",
8713
+ "time.justNowShort": "now",
8571
8714
  "time.minutes": "{count}m",
8572
8715
  "time.hours": "{count}h",
8573
8716
  "time.days": "{count}d",
8717
+ "time.weeks": "{count}w",
8718
+ "time.months": "{count}mo",
8719
+ "time.years": "{count}y",
8574
8720
  "errors.unauthorized": "Sign in to DSH, then try again.",
8575
8721
  "errors.forbidden": "The security check rejected this request. Try again from a trusted DSH address.",
8576
8722
  "errors.serviceUnavailable": "The service is unavailable. Try again later.",
@@ -259,9 +259,13 @@ const zh = {
259
259
  "turns.untitled": "未命名提问",
260
260
  "turns.jump": "跳转到第 {index} 轮:{summary}",
261
261
  "time.justNow": "刚刚",
262
+ "time.justNowShort": "刚刚",
262
263
  "time.minutes": "{count}分",
263
264
  "time.hours": "{count}小时",
264
265
  "time.days": "{count}天",
266
+ "time.weeks": "{count}周",
267
+ "time.months": "{count}个月",
268
+ "time.years": "{count}年",
265
269
  "errors.unauthorized": "请先登录 DSH,再重试。",
266
270
  "errors.forbidden": "请求被安全检查拒绝,请从可信的 DSH 地址重试。",
267
271
  "errors.serviceUnavailable": "服务暂不可用,请稍后重试。",
@@ -543,9 +547,13 @@ const en = {
543
547
  "turns.untitled": "Untitled prompt",
544
548
  "turns.jump": "Jump to turn {index}: {summary}",
545
549
  "time.justNow": "Just now",
550
+ "time.justNowShort": "now",
546
551
  "time.minutes": "{count}m",
547
552
  "time.hours": "{count}h",
548
553
  "time.days": "{count}d",
554
+ "time.weeks": "{count}w",
555
+ "time.months": "{count}mo",
556
+ "time.years": "{count}y",
549
557
  "errors.unauthorized": "Sign in to DSH, then try again.",
550
558
  "errors.forbidden": "The security check rejected this request. Try again from a trusted DSH address.",
551
559
  "errors.serviceUnavailable": "The service is unavailable. Try again later.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@michengai/dsh-codex-ui",
3
- "version": "1.1.11",
3
+ "version": "1.1.12",
4
4
  "description": "以 Codex 风格重构 DSH Web 侧栏的独立客户端插件",
5
5
  "license": "Apache-2.0",
6
6
  "publishConfig": {