@michengai/dsh-codex-ui 0.2.111 → 0.2.113

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
@@ -848,6 +848,32 @@ window.__ModuleLoader__.load({
848
848
  function pendingInteractionForSession(sessionId, pendingInteractions, summaryKind) {
849
849
  return visiblePendingKind(summaryKind) ?? visiblePendingKind(pendingInteractions.get(sessionId)?.kind);
850
850
  }
851
+ //#endregion
852
+ //#region src/business-api.ts
853
+ const CODEX_UI_API_BASE = "/api/dsh-codex-ui";
854
+ const CODEX_UI_API_ENDPOINTS = Object.freeze({
855
+ connectors: `${CODEX_UI_API_BASE}/connectors`,
856
+ dependencies: `${CODEX_UI_API_BASE}/dependencies`,
857
+ openInExplorer: `${CODEX_UI_API_BASE}/open-in-explorer`,
858
+ preferences: `${CODEX_UI_API_BASE}/preferences`,
859
+ sessionMove: `${CODEX_UI_API_BASE}/session-move`
860
+ });
861
+ //#endregion
862
+ //#region src/client/business-request-error.ts
863
+ var BusinessRequestError = class extends Error {
864
+ status;
865
+ constructor(status) {
866
+ super(`业务请求失败:HTTP ${status}`);
867
+ this.status = status;
868
+ this.name = "BusinessRequestError";
869
+ }
870
+ };
871
+ function businessRequestErrorKey(error) {
872
+ if (!(error instanceof BusinessRequestError)) return void 0;
873
+ if (error.status === 401) return "errors.unauthorized";
874
+ if (error.status === 403) return "errors.forbidden";
875
+ if (error.status === 503) return "errors.serviceUnavailable";
876
+ }
851
877
  const WORKSPACE_GROUP_ERROR_MESSAGES = {
852
878
  "group-invalid": "分组信息无效。",
853
879
  "workspace-invalid": "项目标识无效。",
@@ -1001,7 +1027,7 @@ window.__ModuleLoader__.load({
1001
1027
  /** 浏览器本地持久化键;用于工作区偏好的首帧恢复与 Host 故障兜底。 */
1002
1028
  const PINNED_WORKSPACES_STORAGE_KEY = "dsh-codex-ui.pinned-workspace-ids";
1003
1029
  const WORKSPACE_GROUPS_STORAGE_KEY = "dsh-codex-ui.workspace-groups.v1";
1004
- const WORKSPACE_PREFERENCES_ENDPOINT = "/api/michengai/codex-ui/preferences";
1030
+ const WORKSPACE_PREFERENCES_ENDPOINT = CODEX_UI_API_ENDPOINTS.preferences;
1005
1031
  /** 清理无效或重复的工作区标识。 */
1006
1032
  function normalizePinnedWorkspaceIds(ids) {
1007
1033
  return [...new Set(ids.filter((id) => id.trim() !== ""))];
@@ -1040,7 +1066,7 @@ window.__ModuleLoader__.load({
1040
1066
  cache: "no-store",
1041
1067
  signal: AbortSignal.timeout(5e3)
1042
1068
  });
1043
- if (!response.ok) throw new Error(`读取置顶偏好失败:HTTP ${response.status}`);
1069
+ if (!response.ok) throw new BusinessRequestError(response.status);
1044
1070
  const payload = await response.json();
1045
1071
  if (payload === null || typeof payload !== "object") throw new Error("置顶偏好响应格式无效。");
1046
1072
  const record = payload;
@@ -1067,7 +1093,7 @@ window.__ModuleLoader__.load({
1067
1093
  }),
1068
1094
  signal: AbortSignal.timeout(5e3)
1069
1095
  });
1070
- if (!response.ok) throw new Error(`保存置顶偏好失败:HTTP ${response.status}`);
1096
+ if (!response.ok) throw new BusinessRequestError(response.status);
1071
1097
  }
1072
1098
  /** 兼容旧调用方;新代码应同时写入分组。 */
1073
1099
  async function readHostPinnedWorkspaceIds(fetcher = fetch) {
@@ -2009,6 +2035,8 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
2009
2035
  }
2010
2036
  /** 将业务错误映射为当前语言,未知底层错误统一脱敏。 */
2011
2037
  function userErrorText(error, t) {
2038
+ const requestKey = businessRequestErrorKey(error);
2039
+ if (requestKey !== void 0) return t(requestKey);
2012
2040
  if (error instanceof UserFacingError) return error.message;
2013
2041
  if (error instanceof WorkspaceGroupError) return t(WORKSPACE_GROUP_ERROR_KEYS[error.code]);
2014
2042
  if (error instanceof HostActionError) return t(hostActionErrorKey(error));
@@ -2016,16 +2044,20 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
2016
2044
  }
2017
2045
  /** 安装错误保留用户可执行的处理建议,但不直接展示 Host 原文。 */
2018
2046
  function installErrorText(error, t) {
2047
+ const requestKey = businessRequestErrorKey(error);
2048
+ if (requestKey !== void 0) return t(requestKey);
2019
2049
  const message = error instanceof Error ? error.message : String(error);
2020
2050
  return t(INSTALL_ERROR_KEYS.find(([pattern]) => pattern.test(message))?.[1] ?? "about.installFailed");
2021
2051
  }
2022
2052
  //#endregion
2023
2053
  //#region src/client/session-move.ts
2024
- const SESSION_MOVE_ENDPOINT = "/api/michengai/codex-ui/session-move";
2054
+ const SESSION_MOVE_ENDPOINT = CODEX_UI_API_ENDPOINTS.sessionMove;
2025
2055
  const MOVE_ACTION_PREFIX = "move-session:";
2026
2056
  const SESSION_MOVE_ERROR_KEYS = {
2027
2057
  "session-move/unavailable": "sessions.moveUnavailable",
2028
2058
  "session-move/service-unavailable": "sessions.moveUnavailable",
2059
+ "session-move/unauthorized": "sessions.moveUnauthorized",
2060
+ "session-move/forbidden": "sessions.moveForbidden",
2029
2061
  "session-move/session-not-found": "sessions.moveNotFound",
2030
2062
  "session-move/workspace-not-found": "sessions.moveNotFound",
2031
2063
  "session-move/subagent-unsupported": "sessions.moveSubagent",
@@ -2101,6 +2133,85 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
2101
2133
  for (const sessionId of new Set(sessionIds)) await archiveSession(sessionId);
2102
2134
  }
2103
2135
  //#endregion
2136
+ //#region src/client/workspace-drop-indicator.ts
2137
+ const ROWS = ".dcu-wb-section-head,.dcu-wb-collection-head,.dcu-wb-project-head,.dcu-wb-session,.dcu-wb-nochat,.dcu-wb-empty";
2138
+ const TARGETS = ".dcu-wb-drop,.dcu-wb-group-order-drop";
2139
+ function measureWorkspaceDropIndicator(root, onTargets) {
2140
+ const measured = Array.from(root.querySelectorAll(TARGETS)).filter((node) => node.closest("[data-open=false]") === null).map((target) => ({
2141
+ target,
2142
+ rect: measureTarget(root, target)
2143
+ })).filter((item) => item.rect !== void 0);
2144
+ const unique = measured.filter((item, index) => !measured.slice(0, index).some((previous) => previous.rect.top === item.rect.top && previous.rect.left === item.rect.left && previous.rect.width === item.rect.width));
2145
+ onTargets?.(unique.map((item) => item.target));
2146
+ return unique[0]?.rect;
2147
+ }
2148
+ function measureTarget(root, target) {
2149
+ const section = target.closest(".dcu-wb-section") ?? root;
2150
+ const rows = Array.from(section.querySelectorAll(ROWS)).filter((node) => node.closest("[data-open=false]") === null).map((node) => ({
2151
+ node,
2152
+ rect: node.getBoundingClientRect()
2153
+ })).filter((row) => row.rect.height > 0 && row.rect.width > 0);
2154
+ const owned = rows.filter((row) => row.node === target || target.contains(row.node));
2155
+ const after = target.classList.contains("dcu-wb-drop-after");
2156
+ let upper;
2157
+ let lower;
2158
+ let anchor = target.getBoundingClientRect();
2159
+ if (owned.length > 0) {
2160
+ const edge = after ? owned[owned.length - 1] : owned[0];
2161
+ const index = rows.indexOf(edge);
2162
+ anchor = edge.rect;
2163
+ upper = after ? edge.rect.bottom : rows[index - 1]?.rect.bottom;
2164
+ lower = after ? rows[index + 1]?.rect.top : edge.rect.top;
2165
+ } else if (target.matches(".dcu-wb-pin-start,.dcu-wb-pin-end")) {
2166
+ if (anchor.width <= 0 || anchor.height <= 0) return void 0;
2167
+ upper = rows.filter((row) => row.rect.bottom <= anchor.top).at(-1)?.rect.bottom;
2168
+ lower = rows.find((row) => row.rect.top >= anchor.bottom)?.rect.top;
2169
+ if (lower === void 0) lower = anchor.bottom;
2170
+ if (upper === void 0) upper = anchor.top;
2171
+ } else return void 0;
2172
+ const center = upper === void 0 ? lower - 4 : lower === void 0 ? upper + 4 : (upper + lower) / 2;
2173
+ const box = root.getBoundingClientRect();
2174
+ return {
2175
+ top: center - box.top - root.clientTop + root.scrollTop - 4,
2176
+ left: anchor.left - box.left - root.clientLeft + root.scrollLeft + 4,
2177
+ width: Math.max(0, anchor.width - 12)
2178
+ };
2179
+ }
2180
+ /** 仅拖拽期间刷新,滚动、折叠动画和尺寸变化都使用当前帧的布局;结束时完整清理。 */
2181
+ function mountWorkspaceDropIndicator(root) {
2182
+ const line = root.ownerDocument.createElement("div");
2183
+ line.className = "dcu-wb-drop-indicator";
2184
+ line.setAttribute("aria-hidden", "true");
2185
+ root.append(line);
2186
+ root.dataset.dropIndicator = "measured";
2187
+ const view = root.ownerDocument.defaultView;
2188
+ let frame = 0;
2189
+ let previous = "";
2190
+ let previousConflict = [];
2191
+ const update = () => {
2192
+ const rect = measureWorkspaceDropIndicator(root, (targets) => {
2193
+ const conflict = targets.length > 1 ? targets : [];
2194
+ if (conflict.length > 1 && (conflict.length !== previousConflict.length || conflict.some((target, index) => target !== previousConflict[index]))) console.warn("Codex UI 拖拽存在多个有效落点,请检查跨区状态清理。", { count: conflict.length });
2195
+ previousConflict = conflict;
2196
+ });
2197
+ const next = rect === void 0 ? "" : `${rect.top},${rect.left},${rect.width}`;
2198
+ line.hidden = rect === void 0;
2199
+ if (rect !== void 0 && next !== previous) {
2200
+ line.style.top = `${rect.top}px`;
2201
+ line.style.left = `${rect.left}px`;
2202
+ line.style.width = `${rect.width}px`;
2203
+ }
2204
+ previous = next;
2205
+ frame = view.requestAnimationFrame(update);
2206
+ };
2207
+ update();
2208
+ return () => {
2209
+ view.cancelAnimationFrame(frame);
2210
+ line.remove();
2211
+ delete root.dataset.dropIndicator;
2212
+ };
2213
+ }
2214
+ //#endregion
2104
2215
  //#region src/client/CodexWorkspaceBrowser.tsx
2105
2216
  const DISCLOSURE_EXIT_MS = 180;
2106
2217
  function NewSessionIcon() {
@@ -2259,8 +2370,40 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
2259
2370
  .dcu-wb-rename-input:focus{border-color:var(--dsw-alias-state-business-primary);box-shadow:0 0 0 1px color-mix(in srgb,var(--dsw-alias-state-business-primary) 28%,transparent)}
2260
2371
  `;
2261
2372
  const runningStyles = `.dcu-wb-running{position:absolute;right:10px;top:50%;flex:none;width:12px;height:12px;margin-top:-6px;border:2px solid color-mix(in srgb,var(--dcu-sidebar-secondary) 25%,transparent);border-top-color:var(--dcu-sidebar-secondary);border-radius:50%;animation:dcu-wb-spin .8s linear infinite}@keyframes dcu-wb-spin{to{transform:rotate(360deg)}}@media (prefers-reduced-motion:reduce){.dcu-wb-running{animation:none}}`;
2262
- const typographyStyles = `.dcu-wb{--dcu-wb-disclosure-duration:180ms;--dcu-wb-disclosure-ease:cubic-bezier(.16,1,.3,1);font:14px/20px var(--dcu-font,var(--dsw-font-family))}.dcu-wb-section-label{color:var(--dcu-sidebar-secondary);font:13px/20px var(--dcu-font,var(--dsw-font-family));font-weight:400;letter-spacing:0;padding-left:0}.dcu-wb-section-caret{transition:opacity var(--dcu-wb-disclosure-duration) var(--dcu-wb-disclosure-ease),transform var(--dcu-wb-disclosure-duration) var(--dcu-wb-disclosure-ease)}.dcu-wb-section-head .dcu-wb-section-caret{position:static;left:auto;top:auto;opacity:.78}.dcu-wb-section-body,.dcu-wb-project-body,.dcu-wb-collection-body{display:block;min-height:0;height:auto;overflow:clip;opacity:1;transform:none;visibility:visible}.dcu-wb-section-body[data-open=false],.dcu-wb-project-body[data-open=false],.dcu-wb-collection-body[data-open=false]{display:block;height:0;opacity:0;transform:translateY(-2px);pointer-events:none}.dcu-wb-section-body[data-open=true]:has(.dcu-wb-drop),.dcu-wb-project-body[data-open=true]:has(.dcu-wb-drop),.dcu-wb-collection-body[data-open=true]:has(.dcu-wb-drop){overflow:visible}.dcu-wb-section-body[data-open=true]>div{animation:none}@media (prefers-reduced-motion:reduce){.dcu-wb-section-caret{transition:none}}.dcu-wb-project-title{font-size:14px;line-height:20px;font-weight:400;color:var(--dcu-sidebar-primary)}.dcu-wb-session-title{font-size:14px;line-height:20px;font-weight:400;color:var(--dcu-sidebar-secondary)}.dcu-wb-session.dcu-wb-selected .dcu-wb-session-title,.dcu-wb-session:hover .dcu-wb-session-title{color:var(--dcu-sidebar-primary)}.dcu-wb-empty{color:var(--dcu-sidebar-tertiary);font-size:13px;line-height:18px}.dcu-wb-nochat{padding:0 8px 4px 28px;color:var(--dcu-sidebar-tertiary);font-size:14px;line-height:20px}`;
2263
- const collectionLayoutStyles = `.dcu-wb-collection-body{padding-left:0}.dcu-wb-collection-body .dcu-wb-project-head{padding-left:8px}.dcu-wb-collection-body::before,.dcu-wb-group-member::after{display:none}.dcu-wb-collection-head,.dcu-wb-collection-head:focus-within{background:color-mix(in srgb,var(--dcu-sidebar-hover) 28%,transparent)}.dcu-wb-collection-head:hover{background:var(--dcu-sidebar-hover)}.dcu-wb-collection-head.dcu-wb-group-drop{background:var(--dcu-sidebar-hover)}.dcu-wb-workspace-move-drop>.dcu-wb-collection-head{background:transparent}`;
2373
+ const typographyStyles = `.dcu-wb{--dcu-wb-disclosure-duration:180ms;--dcu-wb-disclosure-ease:cubic-bezier(.16,1,.3,1);font:14px/20px var(--dcu-font,var(--dsw-font-family))}.dcu-wb-section-label{color:var(--dcu-sidebar-secondary);font:13px/20px var(--dcu-font,var(--dsw-font-family));font-weight:400;letter-spacing:0;padding-left:0}.dcu-wb-section-caret{transition:opacity var(--dcu-wb-disclosure-duration) var(--dcu-wb-disclosure-ease),transform var(--dcu-wb-disclosure-duration) var(--dcu-wb-disclosure-ease)}.dcu-wb-section-head .dcu-wb-section-caret{position:static;left:auto;top:auto;opacity:.78}.dcu-wb-section-body,.dcu-wb-project-body,.dcu-wb-collection-body{display:block;min-height:0;height:auto;overflow:clip;opacity:1;transform:none;visibility:visible}.dcu-wb-section-body[data-open=false],.dcu-wb-project-body[data-open=false],.dcu-wb-collection-body[data-open=false]{display:block;height:0;opacity:0;transform:translateY(-2px);pointer-events:none}.dcu-wb-section-body[data-open=true]:has(.dcu-wb-drop),.dcu-wb-project-body[data-open=true]:has(.dcu-wb-drop),.dcu-wb-collection-body[data-open=true]:has(.dcu-wb-drop){overflow:visible}.dcu-wb-section-body[data-open=true]>div{animation:none}@media (prefers-reduced-motion:reduce){.dcu-wb-section-caret{transition:none}}.dcu-wb-project-title{font-size:14px;line-height:20px;font-weight:400;color:var(--dcu-sidebar-primary)}.dcu-wb-session-title{font-size:14px;line-height:20px;font-weight:400;color:var(--dcu-sidebar-secondary)}.dcu-wb-session.dcu-wb-selected .dcu-wb-session-title,.dcu-wb-session:hover .dcu-wb-session-title{color:var(--dcu-sidebar-primary)}.dcu-wb-empty{color:var(--dcu-sidebar-tertiary);font-size:13px;line-height:18px}`;
2374
+ const collectionLayoutStyles = `
2375
+ .dcu-wb-tree{position:relative}
2376
+ .dcu-wb-tree[data-drop-indicator=measured] .dcu-wb-drop::before,.dcu-wb-tree[data-drop-indicator=measured] .dcu-wb-group-order-drop::before{display:none}
2377
+ .dcu-wb-drop-indicator{position:absolute;z-index:3;height:8px;pointer-events:none;color:var(--dsw-alias-state-business-primary)}
2378
+ .dcu-wb-drop-indicator::before{content:"";position:absolute;left:6px;right:0;top:3px;height:2px;border-radius:999px;background:currentColor}
2379
+ .dcu-wb-drop-indicator::after{content:"";position:absolute;box-sizing:border-box;left:0;top:0;width:8px;height:8px;border:2px solid currentColor;border-radius:50%}
2380
+ .dcu-wb-project-body:has(>.dcu-wb-session)::after{content:"";display:block;height:4px;pointer-events:none}
2381
+ .dcu-wb-section-body[data-open=true]:has(.dcu-wb-group-order-drop){overflow:visible}
2382
+ .dcu-wb-collection-body{padding-left:0}
2383
+ .dcu-wb-collection-body>.dcu-wb-group-member:first-child{padding-top:4px}
2384
+ .dcu-wb-collection-body .dcu-wb-project-head{padding-left:8px}
2385
+ .dcu-wb-collection-body>.dcu-wb-empty{padding:8px 8px 8px 26px}
2386
+ .dcu-wb-collection-body>.dcu-wb-empty,.dcu-wb-nochat{font-size:13px;line-height:18px;color:var(--dcu-sidebar-tertiary)}
2387
+ .dcu-wb-nochat{padding:1px 8px 5px 28px}
2388
+ .dcu-wb-collection:has(+.dcu-wb-collection)>.dcu-wb-collection-body>.dcu-wb-empty,.dcu-wb-collection:has(+.dcu-wb-ungrouped)>.dcu-wb-collection-body>.dcu-wb-empty{padding-top:14px;padding-bottom:2px}
2389
+ .dcu-wb-collection-body::before,.dcu-wb-group-member::after{display:none}
2390
+ .dcu-wb-collections{gap:12px}
2391
+ .dcu-wb-collections:has(>.dcu-wb-project){gap:0}
2392
+ .dcu-wb-collection-head{min-height:32px}
2393
+ .dcu-wb-collection-head:hover{background:var(--dcu-sidebar-hover)}
2394
+ .dcu-wb-collection-head.dcu-wb-group-drop{background:var(--dcu-sidebar-hover)}
2395
+ .dcu-wb-collection-head{background:color-mix(in srgb,var(--dcu-sidebar-hover) 55%,transparent)}
2396
+ .dcu-wb-collection-label{gap:4px;min-height:32px;font-size:14px;font-weight:600}
2397
+ .dcu-wb-collection-label .dcu-wb-section-caret{width:14px;height:14px;opacity:1;color:var(--dcu-sidebar-primary)}
2398
+ .dcu-wb-collection-label .dcu-wb-section-caret svg{width:14px;height:14px}
2399
+ .dcu-wb-collection-label .dcu-wb-section-caret svg path{stroke-width:2}
2400
+ .dcu-wb-collection-count{flex:none;font-size:12px;font-weight:400;padding-left:8px}
2401
+ .dcu-wb-ungrouped .dcu-wb-collection-label{color:var(--dcu-sidebar-secondary)}
2402
+ .dcu-wb-collection-head:focus-within,.dcu-wb-collection-head:has(.dcu-wb-more[aria-expanded=true]){background:var(--dcu-sidebar-hover)}
2403
+ .dcu-wb-workspace-move-drop>.dcu-wb-collection-head{background:transparent}
2404
+ .dcu-wb-collection-label:focus-visible,.dcu-wb-project-head:focus-visible,.dcu-wb-session:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:-2px;border-radius:6px}
2405
+ @media (pointer:coarse){.dcu-wb-collection-head,.dcu-wb-collection-label{min-height:36px}.dcu-wb-collection-actions{width:28px}.dcu-wb-collection-actions .dcu-wb-more{width:28px;height:28px}}
2406
+ `;
2264
2407
  const WORKSPACE_TREE_STYLE = stylesheet$4 + runningStyles + typographyStyles + collectionLayoutStyles;
2265
2408
  function storage$1() {
2266
2409
  return browserStorage();
@@ -2296,6 +2439,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
2296
2439
  const pinnedHostDirtyRef = (0, react.useRef)(false);
2297
2440
  const pinnedHostSkipWriteRef = (0, react.useRef)();
2298
2441
  const pinnedHostWriteRef = (0, react.useRef)(Promise.resolve());
2442
+ const [preferencesFailure, setPreferencesFailure] = (0, react.useState)();
2299
2443
  const workspaceBaselineRef = (0, react.useRef)({
2300
2444
  ready: false,
2301
2445
  validIds: []
@@ -2314,12 +2458,15 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
2314
2458
  };
2315
2459
  const pending = pinnedHostWriteRef.current.then(async () => {
2316
2460
  await writeHostWorkspacePreferences(snapshot.pinnedWorkspaceIds, snapshot.workspaceGroups);
2461
+ setPreferencesFailure(void 0);
2317
2462
  if (!pinnedHostSupportsWorkspaceGroupsRef.current) return;
2318
2463
  if (!sameIds(pinnedWorkspaceIdsRef.current, snapshot.pinnedWorkspaceIds) || !sameWorkspaceGroups(workspaceGroupsRef.current, snapshot.workspaceGroups)) return;
2319
2464
  workspaceGroupsPendingHostSyncRef.current = false;
2320
2465
  saveWorkspaceGroupsCache(storage$1(), snapshot.workspaceGroups, false);
2321
2466
  });
2322
- pinnedHostWriteRef.current = pending.catch(() => void 0);
2467
+ pinnedHostWriteRef.current = pending.catch((reason) => {
2468
+ setPreferencesFailure(reason);
2469
+ });
2323
2470
  };
2324
2471
  const setPinnedWorkspaceIds = (update) => {
2325
2472
  pinnedHostDirtyRef.current = true;
@@ -2427,7 +2574,9 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
2427
2574
  }
2428
2575
  savePinnedWorkspaceIds(storage$1(), ids);
2429
2576
  if (writeHost) queuePinnedHostWrite(ids, groups);
2430
- }).catch(() => {
2577
+ }).catch((reason) => {
2578
+ if (!alive) return;
2579
+ setPreferencesFailure(reason);
2431
2580
  pinnedHostHydratedRef.current = true;
2432
2581
  });
2433
2582
  return () => {
@@ -2980,7 +3129,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
2980
3129
  top: box.top
2981
3130
  }, { immediate: true });
2982
3131
  },
2983
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFolderClose16, { size: 16 })
3132
+ children: isExpanded ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFolderOpenOutline16, { size: 16 }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFolderClose16, { size: 16 })
2984
3133
  }),
2985
3134
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2986
3135
  className: "dcu-wb-project-title",
@@ -3592,6 +3741,11 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
3592
3741
  };
3593
3742
  const treeRef = (0, react.useRef)(null);
3594
3743
  useSectionDisclosureMotion(treeRef);
3744
+ const sorting = workspaceDragId !== void 0 || workspaceGroupDragId !== void 0 || sessionDrag !== void 0;
3745
+ (0, react.useLayoutEffect)(() => {
3746
+ if (!wide || !sorting || treeRef.current === null) return;
3747
+ return mountWorkspaceDropIndicator(treeRef.current);
3748
+ }, [wide, sorting]);
3595
3749
  if (!wide) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3596
3750
  className: "dcu-wb dcu-wb-rail",
3597
3751
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: stylesheet$4 })
@@ -3606,6 +3760,11 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
3606
3760
  typographyStyles,
3607
3761
  collectionLayoutStyles
3608
3762
  ] }),
3763
+ preferencesFailure !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3764
+ className: "dcu-wb-error",
3765
+ role: "status",
3766
+ children: [t("workspace.preferencesLocalOnly"), businessRequestErrorKey(preferencesFailure) !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [" ", userErrorText(preferencesFailure, t)] })]
3767
+ }),
3609
3768
  error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3610
3769
  className: "dcu-wb-error",
3611
3770
  role: "alert",
@@ -5098,15 +5257,18 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
5098
5257
  const next = `${width}px ${tracks.middle} ${tracks.details}px`;
5099
5258
  const changed = frame.style.gridTemplateColumns !== next;
5100
5259
  if (changed) frame.style.gridTemplateColumns = next;
5260
+ const contentWidth = `${width}px`;
5261
+ if (frame.style.getPropertyValue("--dcu-sidebar-expanded-width") !== contentWidth) frame.style.setProperty("--dcu-sidebar-expanded-width", contentWidth);
5101
5262
  const handle = frame.querySelector("[data-side=\"sidebar\"]");
5102
- if (handle !== null) handle.style.left = `${width}px`;
5263
+ if (handle !== null && handle.style.left !== contentWidth) handle.style.left = contentWidth;
5103
5264
  return changed;
5104
5265
  }
5105
5266
  function applySlimSidebar(frame) {
5106
5267
  if (frame.hasAttribute("data-dragging")) return false;
5107
5268
  if (parseSidebarGrid(frame.style.gridTemplateColumns) === void 0 || frame.hasAttribute("data-sidebar-collapsed")) return false;
5108
- const changed = applySidebarWidth(frame, frame.hasAttribute("data-dcu-codex-sidebar-initialized") ? visibleSidebarWidths.get(frame) ?? 240 : 240);
5109
- frame.setAttribute("data-dcu-codex-sidebar-initialized", "");
5269
+ const initialized = frame.hasAttribute("data-dcu-codex-sidebar-initialized");
5270
+ const changed = applySidebarWidth(frame, initialized ? visibleSidebarWidths.get(frame) ?? 240 : 240);
5271
+ if (!initialized) frame.setAttribute("data-dcu-codex-sidebar-initialized", "");
5110
5272
  return changed;
5111
5273
  }
5112
5274
  /** 仅在首帧覆盖宿主默认宽度时关闭过渡,避免刷新出现收缩动画。 */
@@ -5132,7 +5294,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
5132
5294
  frameObserver?.disconnect();
5133
5295
  frame = next;
5134
5296
  if (frame === void 0) return;
5135
- frameObserver = new MutationObserver(schedule);
5297
+ frameObserver = new MutationObserver(apply);
5136
5298
  frameObserver.observe(frame, {
5137
5299
  attributes: true,
5138
5300
  attributeFilter: [
@@ -5232,7 +5394,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
5232
5394
  //#region src/client/CodexSidebar.tsx
5233
5395
  const subscribeEmptyCompanionTabs = () => () => {};
5234
5396
  const getEmptyCompanionTabs = () => EMPTY_COMPANION_TABS;
5235
- const SIDEBAR_COLLAPSE_SETTLE_MS = 140;
5397
+ const SIDEBAR_COLLAPSE_SETTLE_MS = 500;
5236
5398
  const SIDEBAR_EXPANSION_STORAGE_KEY = "dsh-codex-ui.sidebar-expansion.v1";
5237
5399
  const EXTENSIONS_EXPANSION_KEY = "extensions";
5238
5400
  function readExtensionsOpen() {
@@ -5251,14 +5413,14 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
5251
5413
  /* 滤镜只作用于背景,避免为设置和搜索等 fixed 后代创建侧栏包含块。 */
5252
5414
  body[data-we-sidebar-glass] .dcu-root{position:relative;background:transparent}body[data-we-sidebar-glass] .dcu-root::before{content:"";position:absolute;inset:0;z-index:0;pointer-events:none;background-color:color-mix(in srgb,var(--we-sidebar-color,#fff) calc(var(--we-sidebar-alpha,.15)*.66*100%),transparent);background-image:linear-gradient(180deg,rgba(255,255,255,calc(var(--we-sidebar-sheen,1)*.14)),rgba(255,255,255,calc(var(--we-sidebar-sheen,1)*.04)) 38%,rgba(255,255,255,calc(var(--we-sidebar-sheen,1)*.01)));-webkit-backdrop-filter:blur(var(--we-sidebar-blur,16px)) saturate(var(--we-sidebar-saturate,1.8)) brightness(var(--we-glass-brightness,1.04)) contrast(1.01);backdrop-filter:blur(var(--we-sidebar-blur,16px)) saturate(var(--we-sidebar-saturate,1.8)) brightness(var(--we-glass-brightness,1.04)) contrast(1.01);box-shadow:inset 0 1px 0 rgba(255,255,255,calc(var(--we-sidebar-sheen,1)*.32)),inset 0 -1px 0 rgba(255,255,255,calc(var(--we-sidebar-sheen,1)*.08)),inset 0 0 0 .5px rgba(255,255,255,calc(var(--we-sidebar-sheen,1)*.06))}body[data-ds-dark-theme][data-we-sidebar-glass] .dcu-root::before{background-color:color-mix(in srgb,var(--we-sidebar-color,#fff) calc(var(--we-sidebar-alpha,.15)*.33*100%),transparent)}body[data-we-appwindow][data-we-sidebar-glass] .dcu-root::before{-webkit-backdrop-filter:none;backdrop-filter:none}@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){body[data-we-sidebar-glass] .dcu-root{background:#eef7f5}body[data-ds-dark-theme][data-we-sidebar-glass] .dcu-root{background:#1d2120}body[data-we-sidebar-glass] .dcu-root::before{display:none}}
5253
5415
  body[data-we-sidebar-glass] .dcu-expanded-shell,body[data-we-sidebar-glass] .dcu-compact-shell,body[data-we-sidebar-glass] .dcu-foot{position:relative}
5254
- .dcu-expanded-shell{display:flex;width:100%;min-height:0;flex:1 1 0;overflow:hidden;flex-direction:column;transform-origin:left center;transition:opacity 140ms ease-out,transform 180ms cubic-bezier(.16,1,.3,1);animation:dcu-sidebar-expanded-in 180ms cubic-bezier(.16,1,.3,1)}.dcu-compact-shell{display:none;width:56px}.dcu-root.dcu-collapsing .dcu-expanded-shell{opacity:0;transform:translateX(-6px);pointer-events:none}.dcu-root.dcu-compact .dcu-expanded-shell{display:none}.dcu-root.dcu-compact .dcu-compact-shell{display:flex;min-height:0;flex:1;flex-direction:column;align-items:center;animation:dcu-sidebar-compact-in 140ms ease-out}@keyframes dcu-sidebar-expanded-in{from{opacity:0;transform:translateX(-6px)}to{opacity:1;transform:none}}@keyframes dcu-sidebar-compact-in{from{opacity:0;transform:translateX(-4px)}to{opacity:1;transform:none}}
5416
+ .dcu-expanded-shell{display:flex;width:100%;min-height:0;flex:1 1 0;overflow:hidden;flex-direction:column;transform-origin:left center;transition:opacity 500ms cubic-bezier(.16,1,.3,1),transform 500ms cubic-bezier(.16,1,.3,1);animation:dcu-sidebar-expanded-in 500ms cubic-bezier(.16,1,.3,1)}.dcu-compact-shell{display:none;width:56px}.dcu-root.dcu-collapsing .dcu-expanded-shell{opacity:0;transform:translateX(-6px);pointer-events:none}.dcu-root.dcu-compact .dcu-expanded-shell{display:none}.dcu-root.dcu-compact .dcu-compact-shell{display:flex;min-height:0;flex:1;flex-direction:column;align-items:center;animation:dcu-sidebar-compact-in 140ms ease-out}@keyframes dcu-sidebar-expanded-in{from{opacity:0;transform:translateX(-6px)}to{opacity:1;transform:none}}@keyframes dcu-sidebar-compact-in{from{opacity:0;transform:translateX(-4px)}to{opacity:1;transform:none}}
5255
5417
  .dcu-root *{box-sizing:border-box}.dcu-head{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;column-gap:8px;height:60px;padding:8px 8px 8px 12px}.dcu-brand{border:0;background:transparent;color:inherit;padding:0;display:flex;align-items:center;min-width:0;overflow:hidden}.dcu-brand svg{display:block;width:auto;max-width:100%;height:24px;min-width:0}.dcu-head-actions{display:grid;grid-auto-flow:column;grid-auto-columns:28px;align-items:center;column-gap:8px;height:28px}
5256
5418
  .dcu-icon,.dcu-menu button,.dcu-footer-link{appearance:none;border:0;background:transparent;color:inherit;font:inherit;cursor:pointer}.dcu-icon{display:grid;place-items:center;width:36px;height:36px;border-radius:8px;color:var(--dcu-sidebar-icon)}.dcu-head .dcu-icon{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;margin:0;padding:0;border-radius:50%;line-height:0}.dcu-head .dcu-icon svg{display:block;width:16px;height:16px}
5257
5419
  .dcu-icon:hover,.dcu-menu button:hover:not(:disabled),.dcu-footer-link:hover{background:var(--dcu-sidebar-hover);color:var(--dcu-sidebar-primary)}
5258
5420
  .dcu-menu{padding:0 6px 8px;display:grid;gap:2px}.dcu-menu button,.dcu-footer-link{display:grid;grid-template-columns:20px minmax(0,1fr);column-gap:8px;align-items:center;width:100%;min-height:36px;padding:0 4px;border-radius:8px;color:var(--dcu-sidebar-navigation);font-size:14px;line-height:20px;text-align:left;font-weight:400}
5259
5421
  .dcu-menu-icon{display:grid;place-items:center start;width:20px;height:20px}.dcu-menu-icon svg,.dcu-footer-link svg{display:block;width:16px;height:16px;color:var(--dcu-sidebar-icon)}.dcu-menu button:disabled{color:var(--dcu-sidebar-secondary);cursor:default;opacity:1}.dcu-menu button:disabled svg{color:var(--dcu-sidebar-secondary)}
5260
5422
  .dcu-extensions-group{display:grid}.dcu-extension-leading{position:relative;display:block;width:16px;height:16px}.dcu-extension-leading svg{position:absolute;inset:0;transition:opacity 140ms ease-out,transform 220ms cubic-bezier(.16,1,.3,1)}.dcu-extension-default-icon{opacity:1}.dcu-extension-state-arrow{opacity:0;transform:rotate(0)}.dcu-extensions-group:hover .dcu-extension-default-icon,.dcu-extensions-toggle:focus-visible .dcu-extension-default-icon{opacity:0}.dcu-extensions-group:hover .dcu-extension-state-arrow,.dcu-extensions-toggle:focus-visible .dcu-extension-state-arrow{opacity:1}.dcu-extensions-toggle[aria-expanded=true] .dcu-extension-state-arrow{transform:rotate(90deg)}.dcu-extension-panel{display:grid;grid-template-rows:1fr;opacity:1;transition:grid-template-rows 220ms cubic-bezier(.16,1,.3,1),opacity 160ms ease-out}.dcu-extension-panel[data-open=false]{grid-template-rows:0fr;opacity:0;pointer-events:none}.dcu-extension-panel-inner{position:relative;min-height:0;overflow:hidden}.dcu-extension-items{position:relative;display:grid;gap:1px;margin:1px 0 4px 28px}.dcu-extension-items::before{content:"";position:absolute;left:-16px;top:0;bottom:4px;width:1px;background:var(--dcu-sidebar-border)}.dcu-extension-items button{grid-template-columns:minmax(0,1fr);min-height:32px;color:var(--dcu-sidebar-secondary);font-size:13px;font-weight:400}.dcu-extension-items .dcu-menu-icon{display:none}
5261
- .dcu-workspaces{display:flex;min-height:0;flex:1;flex-direction:column;margin-top:2px;padding-top:8px;border-top:1px solid var(--dcu-sidebar-border)}.dcu-workspaces.dcu-workspaces-tabs{padding-top:0;border-top:0}.dcu-im-tabs{display:flex;gap:16px;margin:0 8px 12px;padding:0;border-bottom:1px solid var(--dcu-sidebar-border)}.dcu-im-tab{appearance:none;border:0;background:transparent;color:var(--dcu-sidebar-secondary);padding:8px 0 7px;font:14px/22px var(--dcu-font);font-weight:500;cursor:pointer}.dcu-im-tab[data-on=true]{color:var(--dcu-sidebar-primary);font-weight:600;box-shadow:inset 0 -2px 0 currentColor}.dcu-native-workspaces{display:flex;min-height:0;flex:1}.dcu-native-workspaces>*{min-width:0;flex:1}.dcu-native-workspaces .ima-tabs,.dcu-native-workspaces [role=tablist]{display:none!important}.dcu-schedule-browser{display:flex;min-height:0;flex:1;flex-direction:column}.dcu-native-workspaces .dcu-schedule-views{display:flex!important;flex:none;min-height:30px;margin:0 8px 8px;padding:2px;border:1px solid var(--dcu-sidebar-border);border-radius:8px;background:rgba(255,255,255,.025)}.dcu-schedule-views button{appearance:none;flex:1;min-width:0;height:24px;border:0;border-radius:6px;background:transparent;color:var(--dcu-sidebar-secondary);font:600 12px/18px var(--dcu-font);cursor:pointer}.dcu-schedule-views button[aria-selected=true]{background:var(--dcu-sidebar-hover);color:var(--dcu-sidebar-primary);box-shadow:inset 0 0 0 1px var(--dcu-sidebar-border)}.dcu-schedule-pane{display:flex;min-height:0;flex:1}.dcu-schedule-pane>*{min-width:0;flex:1}.dcu-schedule-pane>[data-slot="sidebar.schedule"]{display:flex!important;width:100%;min-width:0;flex:1}.dcu-schedule-pane>[data-slot="sidebar.schedule"]>.dsh-st-rail{width:100%;min-width:0;padding-right:8px;scrollbar-gutter:auto}.dcu-schedule-pane .dsh-st-overview{padding-right:8px}.dcu-foot{display:grid;width:100%;gap:4px;padding:8px 6px 12px;border-top:1px solid var(--dcu-sidebar-border);transition:opacity 120ms ease-out,transform 160ms cubic-bezier(.16,1,.3,1)}.dcu-root.dcu-collapsing>.dcu-foot{opacity:0;transform:translateX(-4px);pointer-events:none}.dcu-footer-actions:empty,.dcu-settings-seat:empty{display:none}.dcu-settings-seat>button{width:100%;min-height:36px;padding-left:4px!important;color:var(--dcu-sidebar-navigation);font:14px/20px var(--dcu-font);font-weight:400}.dcu-compact{width:100%;align-items:flex-start;overflow:hidden;padding:10px 0 8px}.dcu-compact-nav{display:flex;flex:1;min-height:0;flex-direction:column;align-items:center;gap:2px;overflow:auto;padding:6px 0}.dcu-compact .dcu-icon{width:36px;height:36px;flex:none}.dcu-compact .dcu-foot{width:36px;margin-top:auto;margin-left:10px;padding:8px 0;border-top:0}.dcu-compact .dcu-settings-seat{width:36px;overflow:hidden}.dcu-compact .dcu-settings-seat>button{display:grid;place-items:center;width:36px;min-height:36px;padding:0!important;font-size:0!important;line-height:0}.dcu-compact .dcu-settings-seat>button svg{width:16px;height:16px}.dcu-compact .dcu-footer-link{display:flex;justify-content:center;width:36px;padding:0;font-size:0}.dcu-compact .dcu-footer-link svg{width:16px;height:16px}
5423
+ .dcu-workspaces{display:flex;min-height:0;flex:1;flex-direction:column;margin-top:2px;padding-top:8px;border-top:1px solid var(--dcu-sidebar-border)}.dcu-workspaces.dcu-workspaces-tabs{padding-top:0;border-top:0}.dcu-im-tabs{display:flex;gap:16px;margin:0 8px 12px;padding:0;border-bottom:1px solid var(--dcu-sidebar-border)}.dcu-im-tab{appearance:none;border:0;background:transparent;color:var(--dcu-sidebar-secondary);padding:8px 0 7px;font:14px/22px var(--dcu-font);font-weight:500;cursor:pointer}.dcu-im-tab[data-on=true]{color:var(--dcu-sidebar-primary);font-weight:600;box-shadow:inset 0 -2px 0 currentColor}.dcu-native-workspaces{display:flex;min-height:0;flex:1}.dcu-native-workspaces>*{min-width:0;flex:1}.dcu-native-workspaces .ima-tabs,.dcu-native-workspaces [role=tablist]{display:none!important}.dcu-schedule-browser{display:flex;min-height:0;flex:1;flex-direction:column}.dcu-native-workspaces .dcu-schedule-views{display:flex!important;flex:none;min-height:30px;margin:0 8px 8px;padding:2px;border:1px solid var(--dcu-sidebar-border);border-radius:8px;background:rgba(255,255,255,.025)}.dcu-schedule-views button{appearance:none;flex:1;min-width:0;height:24px;border:0;border-radius:6px;background:transparent;color:var(--dcu-sidebar-secondary);font:600 12px/18px var(--dcu-font);cursor:pointer}.dcu-schedule-views button[aria-selected=true]{background:var(--dcu-sidebar-hover);color:var(--dcu-sidebar-primary);box-shadow:inset 0 0 0 1px var(--dcu-sidebar-border)}.dcu-schedule-pane{display:flex;min-height:0;flex:1}.dcu-schedule-pane>*{min-width:0;flex:1}.dcu-schedule-pane>[data-slot="sidebar.schedule"]{display:flex!important;width:100%;min-width:0;flex:1}.dcu-schedule-pane>[data-slot="sidebar.schedule"]>.dsh-st-rail{width:100%;min-width:0;padding-right:8px;scrollbar-gutter:auto}.dcu-schedule-pane .dsh-st-overview{padding-right:8px}.dcu-foot{display:grid;width:100%;gap:4px;padding:8px 6px 12px;border-top:1px solid var(--dcu-sidebar-border);transition:opacity 500ms cubic-bezier(.16,1,.3,1),transform 500ms cubic-bezier(.16,1,.3,1)}.dcu-root.dcu-collapsing>.dcu-foot{opacity:0;transform:translateX(-4px);pointer-events:none}.dcu-footer-actions:empty,.dcu-settings-seat:empty{display:none}.dcu-settings-seat>button{width:100%;min-height:36px;padding-left:4px!important;color:var(--dcu-sidebar-navigation);font:14px/20px var(--dcu-font);font-weight:400}.dcu-compact{width:100%;align-items:flex-start;overflow:hidden;padding:10px 0 8px}.dcu-compact-nav{display:flex;flex:1;min-height:0;flex-direction:column;align-items:center;gap:2px;overflow:auto;padding:6px 0}.dcu-compact .dcu-icon{width:36px;height:36px;flex:none}.dcu-compact .dcu-foot{width:36px;margin-top:auto;margin-left:10px;padding:8px 0;border-top:0}.dcu-compact .dcu-settings-seat{width:36px;overflow:hidden}.dcu-compact .dcu-settings-seat>button{display:grid;place-items:center;width:36px;min-height:36px;padding:0!important;font-size:0!important;line-height:0}.dcu-compact .dcu-settings-seat>button svg{width:16px;height:16px}.dcu-compact .dcu-footer-link{display:flex;justify-content:center;width:36px;padding:0;font-size:0}.dcu-compact .dcu-footer-link svg{width:16px;height:16px}
5262
5424
  /* 仅适配费用插件入口;通过标记及入口结构定位,保留原生统计、浮层和容器查询。 */
5263
5425
  .dcu-footer-actions [data-testid="billing-trigger"]{box-sizing:border-box;width:100%;min-width:0;min-height:52px;padding:8px 6px;gap:8px;border:0;border-radius:6px;background:transparent;color:var(--dcu-sidebar-primary);font-family:var(--dcu-font);box-shadow:none;transform:none;transition:background-color 120ms ease-out,color 120ms ease-out}
5264
5426
  .dcu-footer-actions :is([data-testid="billing-trigger"],[data-testid="billing-rail-button"]):hover{border-color:transparent;background:var(--dcu-sidebar-hover);box-shadow:none;transform:none}
@@ -5278,7 +5440,21 @@ body[data-we-sidebar-glass] .dcu-expanded-shell,body[data-we-sidebar-glass] .dcu
5278
5440
  .dcu-settings-seat [data-slot="settings.trigger"]>svg{color:var(--dcu-sidebar-icon)}
5279
5441
  .dcu-root:not(.dcu-compact) .dcu-settings-seat [data-slot="settings.trigger"]>span{margin-left:4px}
5280
5442
  @media (prefers-reduced-motion:reduce){.dcu-footer-actions :is([data-testid="billing-trigger"],[data-testid="billing-rail-button"]){transition:none}}
5281
- .dcu-expanded-shell,.dcu-foot{width:100%}
5443
+ /* 宿主列负责缩放,宽态内容保持展开宽度,避免中文竖排与工作区逐帧重排。 */
5444
+ .dcu-expanded-shell,.dcu-root:not(.dcu-compact)>.dcu-foot{width:var(--dcu-sidebar-expanded-width,240px);flex-shrink:0}
5445
+ /* 对齐 Codex 的半秒布局节奏;显式声明避免依赖宿主主题的动画 token。 */
5446
+ .dcu-root{position:relative}
5447
+ .dcu-root.dcu-collapsing .dcu-compact-shell{position:absolute;left:0;top:10px;bottom:8px;display:flex;flex-direction:column;align-items:center;animation:dcu-sidebar-compact-in 500ms cubic-bezier(.16,1,.3,1)}
5448
+ .dcu-root.dcu-collapsing .dcu-compact-shell .dcu-icon{width:36px;height:36px;flex:none}
5449
+ /* 收尾仅移除宽态层,窄轨不重复淡入,否则会在半秒处闪烁。 */
5450
+ .dcu-root.dcu-compact .dcu-compact-shell{animation:none}
5451
+ [data-dcu-codex-sidebar-initialized]{transition:grid-template-columns 500ms cubic-bezier(.16,1,.3,1)}
5452
+ /* dsh-better-sidebar 的 #root 布局规则会覆盖 transition 简写;合并两侧过渡而非只争抢左栏。 */
5453
+ #root [data-dcu-codex-sidebar-initialized]:not([data-dragging]){transition:grid-template-columns 500ms cubic-bezier(.16,1,.3,1),padding-right var(--ds-transition-duration-slow,.3s) var(--ds-ease-in-out,cubic-bezier(.4,0,.2,1))}
5454
+ #root [data-dcu-codex-sidebar-initialized][data-dragging]{transition:none}
5455
+ [data-dcu-codex-sidebar-initialized] [data-side="sidebar"]{transition:left 500ms cubic-bezier(.16,1,.3,1)}
5456
+ [data-dcu-codex-sidebar-initialized][data-dragging],[data-dcu-codex-sidebar-initialized][data-dragging] [data-side="sidebar"]{transition:none}
5457
+ @media (prefers-reduced-motion:reduce){[data-dcu-codex-sidebar-initialized],[data-dcu-codex-sidebar-initialized] [data-side="sidebar"],#root [data-dcu-codex-sidebar-initialized]:not([data-dragging]){transition:none}.dcu-root.dcu-collapsing .dcu-compact-shell{animation:none}}
5282
5458
  .dcu-native-workspaces{flex-direction:column}.dcu-native-workspaces>[data-mcp-connector-top-mount=true]{flex:none}.dcu-root .mcpConnectorLauncher,.dcu-root [data-mcp-connector-top-mount=true]{display:none!important}
5283
5459
  .dcu-dependency-notice{margin:0 10px 8px;border:1px solid var(--dcu-sidebar-border);border-radius:8px;padding:8px;color:var(--dcu-sidebar-secondary);font-size:12px;line-height:18px}
5284
5460
  [role="dialog"][aria-labelledby]{width:min(1000px,calc(100vw - 48px));max-width:calc(100vw - 48px);height:min(800px,calc(100vh - 48px))}
@@ -6139,7 +6315,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
6139
6315
  "linking",
6140
6316
  "building"
6141
6317
  ]);
6142
- const endpoint = "/api/michengai/codex-ui/dependencies";
6318
+ const endpoint = CODEX_UI_API_ENDPOINTS.dependencies;
6143
6319
  const stylesheet$2 = `
6144
6320
  .dcu-about{color:var(--dsw-alias-label-primary)}.dcu-about h2{margin:0;font-size:20px;line-height:28px}.dcu-about-intro{margin:6px 0 22px;color:var(--dsw-alias-label-secondary);font-size:13px;line-height:20px}.dcu-about h3{margin:24px 0 8px;font-size:14px;line-height:20px}.dcu-about-features{margin:0;padding-left:20px;color:var(--dsw-alias-label-secondary);font-size:13px;line-height:24px}.dcu-about-dependencies-heading{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:24px}.dcu-about-dependencies-heading h3{margin:0}.dcu-about-dependencies-heading+.dcu-about-intro{margin-bottom:14px}.dcu-about-dependencies{overflow:hidden;border:1px solid var(--dsw-alias-border-l2);border-radius:10px}.dcu-about-dependency{display:flex;align-items:center;gap:12px;min-height:64px;padding:12px;border-bottom:1px solid var(--dsw-alias-border-l2)}.dcu-about-dependency:last-child{border-bottom:0}.dcu-about-copy{min-width:0;flex:1}.dcu-about-name{font-size:13px;line-height:20px;font-weight:600}.dcu-about-package{overflow:hidden;margin-top:2px;color:var(--dsw-alias-label-tertiary);font-size:12px;text-overflow:ellipsis;white-space:nowrap}.dcu-about-status{display:flex;align-items:center;gap:5px;font-size:12px}.dcu-about-status[data-installed=true]{color:var(--dsw-alias-state-success-primary)}.dcu-about-status[data-installed=false]{color:var(--dsw-alias-state-error-primary)}.dcu-about-status[data-update=true]{color:var(--dsw-alias-state-warning-primary)}.dcu-about-install{display:inline-flex;align-items:center;justify-content:center;gap:5px;min-height:32px;border:1px solid var(--dsw-alias-border-l2);border-radius:7px;padding:6px 9px;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:12px;cursor:pointer}.dcu-about-install:hover:not(:disabled){background:var(--dsw-specific-menu-item-hover)}.dcu-about-install:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}.dcu-about-install:disabled{cursor:wait;opacity:.65}.dcu-about-update-all{min-width:92px}.dcu-about-message{margin:10px 0 0;border-radius:8px;padding:9px 10px;background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 12%,transparent);color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px}.dcu-about-message[data-error=true]{background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 12%,transparent);color:var(--dsw-alias-state-error-primary)}.dcu-about-progress{display:grid;grid-template-columns:auto 1fr auto;gap:8px 10px;align-items:center;margin-top:10px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:9px 10px}.dcu-about-progress code{min-width:0;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dcu-about-progress-pct{color:var(--dsw-alias-label-tertiary);font-size:12px;font-variant-numeric:tabular-nums}.dcu-about-progress-bar{grid-column:1/-1;height:4px;overflow:hidden;border-radius:99px;background:var(--dsw-alias-border-l2)}.dcu-about-progress-fill{height:100%;background:var(--dsw-alias-state-business-primary);transition:width .2s ease}.dcu-about-progress-fill[data-wave=true]{width:28%;animation:dcu-about-progress-wave 1.2s ease-in-out infinite}@keyframes dcu-about-progress-wave{0%{transform:translateX(-60%)}100%{transform:translateX(280%)}}
6145
6321
  .dcu-about-title-row{display:flex;align-items:center;gap:8px;min-width:0}.dcu-about-links{display:flex;align-items:center;gap:4px}.dcu-about-external-link{display:inline-flex;align-items:center;gap:5px;min-height:28px;padding:0 8px;color:var(--dsw-alias-label-secondary);background:transparent;border:1px solid var(--dsw-alias-border-l2);border-radius:7px;font-size:12px;font-weight:500;line-height:18px;text-decoration:none;white-space:nowrap}.dcu-about-external-link:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}.dcu-about-external-link:focus-visible{outline:2px solid var(--dsw-alias-state-success-primary);outline-offset:2px}.dcu-about-external-link svg{flex:none}@media(max-width:720px){.dcu-about-title-row{flex-wrap:wrap}}
@@ -6190,6 +6366,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
6190
6366
  const [progress, setProgress] = (0, react.useState)();
6191
6367
  const [message, setMessage] = (0, react.useState)();
6192
6368
  const [refreshFailed, setRefreshFailed] = (0, react.useState)(false);
6369
+ const [loadFailure, setLoadFailure] = (0, react.useState)();
6193
6370
  const alive = (0, react.useRef)(true);
6194
6371
  const root = (0, react.useRef)(null);
6195
6372
  const stateRef = (0, react.useRef)("loading");
@@ -6210,14 +6387,17 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
6210
6387
  cache: "no-store",
6211
6388
  signal
6212
6389
  });
6390
+ if (!response.ok) throw new BusinessRequestError(response.status);
6213
6391
  const payload = await response.json();
6214
6392
  if (signal?.aborted || currentRequest !== requestId.current) return;
6215
- if (!response.ok || !Array.isArray(payload.dependencies) || !payload.dependencies.every(isDependencyStatus)) throw new Error();
6393
+ if (!Array.isArray(payload.dependencies) || !payload.dependencies.every(isDependencyStatus)) throw new Error();
6216
6394
  setDependencies(payload.dependencies);
6217
6395
  setState("ready");
6218
6396
  setRefreshFailed(false);
6397
+ setLoadFailure(void 0);
6219
6398
  } catch (error) {
6220
6399
  if (signal?.aborted || error instanceof DOMException && error.name === "AbortError" || currentRequest !== requestId.current) return;
6400
+ setLoadFailure(error);
6221
6401
  if (stateRef.current === "ready") setRefreshFailed(true);
6222
6402
  else setState("failed");
6223
6403
  }
@@ -6282,6 +6462,11 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
6282
6462
  setMessage(void 0);
6283
6463
  try {
6284
6464
  const response = await fetch(`${endpoint}?dependency=${encodeURIComponent(id)}`, { method: "POST" });
6465
+ if ([
6466
+ 401,
6467
+ 403,
6468
+ 503
6469
+ ].includes(response.status)) throw new BusinessRequestError(response.status);
6285
6470
  const payload = await response.json();
6286
6471
  if (!response.ok || !Array.isArray(payload.dependencies) || !payload.dependencies.every(isDependencyStatus)) throw new Error(typeof payload.error === "string" ? payload.error : t("about.installFailed"));
6287
6472
  if (!alive.current) return;
@@ -6310,6 +6495,11 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
6310
6495
  setMessage(void 0);
6311
6496
  try {
6312
6497
  const response = await fetch(`${endpoint}?action=update-all`, { method: "POST" });
6498
+ if ([
6499
+ 401,
6500
+ 403,
6501
+ 503
6502
+ ].includes(response.status)) throw new BusinessRequestError(response.status);
6313
6503
  const payload = await response.json();
6314
6504
  if (!response.ok || !Array.isArray(payload.dependencies) || !payload.dependencies.every(isDependencyStatus)) throw new Error(typeof payload.error === "string" ? payload.error : t("about.installFailed"));
6315
6505
  if (!alive.current) return;
@@ -6405,7 +6595,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
6405
6595
  className: "dcu-about-message",
6406
6596
  "data-error": "true",
6407
6597
  role: "alert",
6408
- children: t("about.statusFailed")
6598
+ children: t(businessRequestErrorKey(loadFailure) ?? "about.statusFailed")
6409
6599
  }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6410
6600
  className: "dcu-about-dependencies",
6411
6601
  "aria-busy": installing !== void 0,
@@ -6468,7 +6658,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
6468
6658
  className: "dcu-about-message",
6469
6659
  "data-error": "true",
6470
6660
  role: "status",
6471
- children: t("about.refreshFailed")
6661
+ children: t(businessRequestErrorKey(loadFailure) ?? "about.refreshFailed")
6472
6662
  }),
6473
6663
  message !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6474
6664
  className: "dcu-about-message",
@@ -6560,6 +6750,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
6560
6750
  const sessionId = (0, react.useSyncExternalStore)(sessionStore.subscribe, () => sessionStore.getSnapshot().current);
6561
6751
  const [connectors, setConnectors] = (0, react.useState)([]);
6562
6752
  const [state, setState] = (0, react.useState)("loading");
6753
+ const [failure, setFailure] = (0, react.useState)();
6563
6754
  (0, react.useEffect)(() => {
6564
6755
  if (sessionId === void 0) {
6565
6756
  setConnectors([]);
@@ -6568,15 +6759,18 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
6568
6759
  }
6569
6760
  const controller = new AbortController();
6570
6761
  setState("loading");
6571
- fetch(`/api/michengai/codex-ui/connectors?sessionId=${encodeURIComponent(sessionId)}`, { signal: controller.signal }).then(async (response) => {
6572
- if (!response.ok) throw new Error("连接器目录暂不可用。");
6762
+ fetch(`${CODEX_UI_API_ENDPOINTS.connectors}?sessionId=${encodeURIComponent(sessionId)}`, { signal: controller.signal }).then(async (response) => {
6763
+ if (!response.ok) throw new BusinessRequestError(response.status);
6573
6764
  const payload = await response.json();
6574
6765
  if (!Array.isArray(payload.connectors) || !payload.connectors.every(isConnector)) throw new Error("连接器目录返回格式无效。");
6575
6766
  if (!controller.signal.aborted) setConnectors(payload.connectors);
6576
6767
  }).then(() => {
6577
6768
  if (!controller.signal.aborted) setState("ready");
6578
- }).catch(() => {
6579
- if (!controller.signal.aborted) setState("failed");
6769
+ }).catch((error) => {
6770
+ if (!controller.signal.aborted) {
6771
+ setFailure(error);
6772
+ setState("failed");
6773
+ }
6580
6774
  });
6581
6775
  return () => {
6582
6776
  controller.abort();
@@ -6592,7 +6786,8 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
6592
6786
  });
6593
6787
  if (state === "failed") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6594
6788
  className: "dcu-connector-empty",
6595
- children: t("connectors.failed")
6789
+ role: "alert",
6790
+ children: t(businessRequestErrorKey(failure) ?? "connectors.failed")
6596
6791
  });
6597
6792
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6598
6793
  className: "dcu-connector-list",
@@ -6722,7 +6917,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
6722
6917
  "workspace.renameGroup": "重命名分组",
6723
6918
  "workspace.recent": "最近",
6724
6919
  "workspace.recentEmpty": "无聊天",
6725
- "workspace.noChat": "没有聊天",
6920
+ "workspace.noChat": "暂无聊天",
6726
6921
  "workspace.empty": "暂无项目",
6727
6922
  "workspace.newSession": "新建会话",
6728
6923
  "workspace.rename": "重命名项目",
@@ -6770,6 +6965,8 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
6770
6965
  "sessions.openPath": "在资源管理器中打开",
6771
6966
  "sessions.moveWorkspace": "项目",
6772
6967
  "sessions.moveUnavailable": "会话移动服务暂不可用,请重启 DSH 后重试。",
6968
+ "sessions.moveUnauthorized": "登录状态已失效,请刷新页面并重新登录。",
6969
+ "sessions.moveForbidden": "当前访问地址不受信任,或请求来源已被拒绝。",
6773
6970
  "sessions.moveNotFound": "会话或目标项目已不存在,请刷新后重试。",
6774
6971
  "sessions.moveSubagent": "子代理会话不能移动到其他项目。",
6775
6972
  "sessions.moveBusy": "该会话正在移动,请稍后重试。",
@@ -6859,6 +7056,10 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
6859
7056
  "time.minutes": "{count}分",
6860
7057
  "time.hours": "{count}小时",
6861
7058
  "time.days": "{count}天",
7059
+ "errors.unauthorized": "请先登录 DSH,再重试。",
7060
+ "errors.forbidden": "请求被安全检查拒绝,请从可信的 DSH 地址重试。",
7061
+ "errors.serviceUnavailable": "服务暂不可用,请稍后重试。",
7062
+ "workspace.preferencesLocalOnly": "项目偏好尚未同步,当前使用本地缓存。",
6862
7063
  "errors.generic": "操作未完成,请重试。",
6863
7064
  "errors.groupInvalid": "分组信息无效。",
6864
7065
  "errors.workspaceInvalid": "项目标识无效。",
@@ -6976,6 +7177,8 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
6976
7177
  "sessions.openPath": "Open in file explorer",
6977
7178
  "sessions.moveWorkspace": "Project",
6978
7179
  "sessions.moveUnavailable": "Conversation moving is unavailable. Restart DSH and try again.",
7180
+ "sessions.moveUnauthorized": "Your login session has expired. Refresh the page and sign in again.",
7181
+ "sessions.moveForbidden": "The current address is not trusted, or the request origin was rejected.",
6979
7182
  "sessions.moveNotFound": "The conversation or target project no longer exists. Refresh and try again.",
6980
7183
  "sessions.moveSubagent": "Subagent conversations cannot be moved to another project.",
6981
7184
  "sessions.moveBusy": "This conversation is already being moved. Try again shortly.",
@@ -7065,6 +7268,10 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
7065
7268
  "time.minutes": "{count}m",
7066
7269
  "time.hours": "{count}h",
7067
7270
  "time.days": "{count}d",
7271
+ "errors.unauthorized": "Sign in to DSH, then try again.",
7272
+ "errors.forbidden": "The security check rejected this request. Try again from a trusted DSH address.",
7273
+ "errors.serviceUnavailable": "The service is unavailable. Try again later.",
7274
+ "workspace.preferencesLocalOnly": "Workspace preferences are not synced. Using the local cache.",
7068
7275
  "errors.generic": "The action could not be completed. Try again.",
7069
7276
  "errors.groupInvalid": "The group information is invalid.",
7070
7277
  "errors.workspaceInvalid": "The project identifier is invalid.",
@@ -7074,7 +7281,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
7074
7281
  };
7075
7282
  //#endregion
7076
7283
  //#region src/client/host-open-path.ts
7077
- const OPEN_IN_EXPLORER_ENDPOINT = "/api/michengai/codex-ui/open-in-explorer";
7284
+ const OPEN_IN_EXPLORER_ENDPOINT = CODEX_UI_API_ENDPOINTS.openInExplorer;
7078
7285
  /** “在资源管理器中打开”属于明确的系统动作,不应被侧边栏文件预览器接管。 */
7079
7286
  async function openPathInHost(connection, path, fetcher = fetch) {
7080
7287
  let foregroundResponse;
@@ -7086,6 +7293,11 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
7086
7293
  });
7087
7294
  } catch {}
7088
7295
  if (foregroundResponse?.ok) return;
7296
+ if (foregroundResponse !== void 0 && [
7297
+ 401,
7298
+ 403,
7299
+ 503
7300
+ ].includes(foregroundResponse.status)) throw new BusinessRequestError(foregroundResponse.status);
7089
7301
  if (foregroundResponse !== void 0 && foregroundResponse.status !== 404 && foregroundResponse.status !== 501) {
7090
7302
  const payload = await foregroundResponse.json().catch(() => ({}));
7091
7303
  throw new Error(typeof payload.error === "string" ? payload.error : "无法在前台打开资源管理器。");
@@ -7326,7 +7538,7 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
7326
7538
  const OFFICIAL_TURN_MARK_ATTRIBUTE = "data-dcu-official-turn-mark";
7327
7539
  const OFFICIAL_TURN_TOOLTIP_ATTRIBUTE = "data-dcu-official-turn-tooltip";
7328
7540
  const OFFICIAL_TURN_NAVIGATOR_SUPPORTED_ATTRIBUTE = "data-dcu-official-turn-navigator-supported";
7329
- const CAPABILITIES_ENDPOINT = "/api/michengai/codex-ui/dependencies?action=capabilities";
7541
+ const CAPABILITIES_ENDPOINT = `${CODEX_UI_API_ENDPOINTS.dependencies}?action=capabilities`;
7330
7542
  function isOfficialTurnNavigator(element) {
7331
7543
  return element instanceof HTMLElement && element.tagName === "NAV" && element.style.getPropertyValue("--turn-natural-height") !== "" && element.querySelector("button[type=\"button\"][aria-label]") !== null;
7332
7544
  }
package/lib/index.d.mts CHANGED
@@ -4,16 +4,8 @@ type HostRequest = {
4
4
  method?: string;
5
5
  url?: string;
6
6
  headers?: Record<string, string | string[] | undefined>;
7
- socket?: {
8
- remoteAddress?: string;
9
- };
10
7
  [Symbol.asyncIterator]?: () => AsyncIterator<Uint8Array | string>;
11
8
  };
12
- /**
13
- * 依赖安装会改写用户配置并拉起子进程,只允许回环地址上的同源浏览器请求。
14
- * Origin、Host 和 Sec-Fetch-Site 都可被非浏览器客户端伪造,不能单独作为授权依据。
15
- */
16
- declare function crossSiteRequest(request: HostRequest): boolean;
17
9
  /** 把安装错误收成可给浏览器看的文案:我们自己的中文说明保留,带本地路径的底层错误脱敏。 */
18
10
  declare function publicDependencyError(error: unknown): string;
19
11
  declare class RequestBodyTooLargeError extends Error {}
@@ -23,4 +15,4 @@ declare const inject: string[];
23
15
  /** 提供不泄露地址、命令和凭证的连接器目录。 */
24
16
  declare function apply(ctx: Context): void;
25
17
  //#endregion
26
- export { RequestBodyTooLargeError, apply, crossSiteRequest, inject, publicDependencyError, readRequestBody };
18
+ export { RequestBodyTooLargeError, apply, inject, publicDependencyError, readRequestBody };