dsh-panel-folders 0.0.0-stage → 0.1.1

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
@@ -1,3 +1,54 @@
1
- # Temporary Holding Version
1
+ # dsh-panel-folders
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ 为 **DeepSeek Harness 0.2.2-rc.1** 左侧栏的全局面板入口添加可折叠分组。例如把音乐、小游戏等已安装工具收进「摸鱼工具」,平时只显示一个文件夹。
4
+
5
+ ## 使用
6
+
7
+ 1. 点击左侧栏的 **管理分组**。
8
+ 2. 输入「摸鱼工具」等名称,点击 **创建分组**。
9
+ 3. 在 **入口归属** 中为各工具选择分组;选择 **不分组** 可还原入口。
10
+ 4. 点击侧栏的文件夹展开或折叠,点击其中的工具打开原面板。
11
+
12
+ 新分组默认折叠。支持重命名、删除分组;删除只解除归属,不卸载工具,不关闭当前面板。插件管理入口始终保留在原位置。侧栏收成图标栏时,点击文件夹会展开侧栏及该分组。
13
+
14
+ 分组名称、归属和折叠状态保存到当前浏览器/桌面窗口所在 origin 的 `localStorage`(`dsh-finder:groups:v1`),刷新后恢复,同 origin 的窗口之间同步;不上传服务器,不跨设备同步。清除站点数据会清除分组。存储不可用时显示提醒,并只在当前页面保留修改。
15
+
16
+ 工具暂时停用时保留归属,重新加载后回到原分组;管理窗口中可以移除未加载入口的归属。新安装的工具默认不分组。
17
+
18
+ ## 构建与安装
19
+
20
+ 需要 Node.js 24.9+ 和 DSH **0.2.2-rc.1**。其他 DSH 版本未验证,不应强制豁免版本检查。
21
+
22
+ 在 DSH 插件管理器的第三方插件安装入口输入 `dsh-panel-folders` 即可安装。若已安装过本地测试版 `dsh-finder`,请先将其禁用或卸载,避免两个侧栏插件同时运行;同一 origin 下的分组数据会保留。
23
+
24
+ ```sh
25
+ npm install
26
+ npm run build
27
+ npm test
28
+ npm pack
29
+ ```
30
+
31
+ Web profile 可安装生成的包(将路径替换为实际绝对路径):
32
+
33
+ ```sh
34
+ dsh plugin --profile web add /absolute/path/dsh-panel-folders-0.1.1.tgz
35
+ ```
36
+
37
+ 安装后启用 `dsh-panel-folders` bundle,重启对应 DSH Host 并刷新界面。Desktop 可在 **插件 → 添加插件 → 安装第三方插件** 输入生成的 `.tgz` 的本机绝对路径,安装后启用;npm 安装的 `dsh` 不支持修改 Desktop profile。远程 Host 的路径应指向 Host 上的文件,不是浏览器所在电脑。
38
+
39
+ 本目录的构建和测试不会修改当前用户的 DSH profile。安装会影响所选 profile 的整个侧栏,而不只是一个会话。
40
+
41
+ ## 实现与边界
42
+
43
+ - 管理的是注册到 `sidebar.panellist` 的左侧**全局面板入口**,不包含会话树、右侧栏标签、聊天工具调用,也不创建工具本身。
44
+ - 复用固定版本的 DSH 原生侧栏组件及其未经修改的样式,仅在注册时组合入口过滤与分组导航,保留品牌、新建会话、工作区、设置、原生布局和焦点处理;不搬动 DOM、不依赖混淆后的 CSS 类名。内嵌样式使用本插件的独立标识,避免原生侧栏停用时被清除。
45
+ - 分组管理使用原生 `dialog` 并接入 DSH `useModalLayer`,使窄屏侧栏抽屉中的 Tab / Shift+Tab 只在管理窗口内循环;Escape 先关闭管理窗口并恢复焦点,不会关闭后面的侧栏。
46
+ - bundle patch 停用原生 `ui-sidebar` 条目并插入 `dsh-finder`,避免两个组件争用同一 slot。不要同时安装另一套侧栏替换插件;禁用/移除本 bundle 后,原生侧栏随配置重组恢复。分组数据保留但不再影响原入口。
47
+ - 单层分组;每个入口仅属于一个分组。文件夹按创建顺序、内部入口按加入顺序排列。未分组入口继续遵循 DSH 原有顺序和 Pin 状态。
48
+ - 原生侧栏被打包进浏览器产物;升级 DSH 时必须匹配更新构建依赖和宿主版本约束,而不是仅修改版本号。上游许可见 `THIRD_PARTY_NOTICES.md`。
49
+
50
+ ## 验证
51
+
52
+ `npm test` 覆盖跨组移动、重复归属清理、删除还原、持久化、存储失败和窗口间同步。
53
+
54
+ 已在隔离的 DSH 0.2.2-rc.1 Web profile 中运行实际浏览器验证:插件加载、多个面板入口分组且无重复、原面板交互、折叠后刷新恢复、图标栏展开、重命名、删除后恢复原入口及保留当前页面。另在 600px 宽度的侧栏抽屉中验证 Tab / Shift+Tab 焦点循环、Escape 关闭管理窗口并还原焦点、再次 Escape 关闭侧栏。Desktop 原生窗口未实测。
@@ -0,0 +1,25 @@
1
+ # Third-party notices
2
+
3
+ The browser bundle embeds the sidebar shell from `@deepseek-ai/dsh-client-ui-sidebar` 0.2.2-rc.1. Its registration is composed with the grouping UI; the upstream shell is otherwise unchanged.
4
+
5
+ MIT License
6
+
7
+ Copyright (c) 2026 DeepSeek
8
+
9
+ Permission is hereby granted, free of charge, to any person obtaining a copy
10
+ of this software and associated documentation files (the "Software"), to deal
11
+ in the Software without restriction, including without limitation the rights
12
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
+ copies of the Software, and to permit persons to whom the Software is
14
+ furnished to do so, subject to the following conditions:
15
+
16
+ The above copyright notice and this permission notice shall be included in all
17
+ copies or substantial portions of the Software.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
+ SOFTWARE.
@@ -0,0 +1,6 @@
1
+ # The plugin embeds and composes the native shell; only one shell may register.
2
+ - id: ui-sidebar
3
+ disabled: true
4
+ - insert:
5
+ - id: dsh-finder
6
+ name: 'dsh-panel-folders'
package/lib/client.js ADDED
@@ -0,0 +1,1011 @@
1
+ window.__ModuleLoader__.load({id:'dsh-panel-folders',factory:(require)=>{var module={exports:{}};var exports=module.exports;
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __commonJS = (cb, mod) => function __require() {
9
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
10
+ };
11
+ var __export = (target, all) => {
12
+ for (var name in all)
13
+ __defProp(target, name, { get: all[name], enumerable: true });
14
+ };
15
+ var __copyProps = (to, from, except, desc) => {
16
+ if (from && typeof from === "object" || typeof from === "function") {
17
+ for (let key of __getOwnPropNames(from))
18
+ if (!__hasOwnProp.call(to, key) && key !== except)
19
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
20
+ }
21
+ return to;
22
+ };
23
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
24
+ // If the importer is in node compatibility mode or this is not an ESM
25
+ // file that has been converted to a CommonJS file using a Babel-
26
+ // compatible transform (i.e. "__esModule" has not been set), then set
27
+ // "default" to the CommonJS "module.exports" for node compatibility.
28
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
29
+ mod
30
+ ));
31
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
+
33
+ // native:native-sidebar
34
+ var require_native_sidebar = __commonJS({
35
+ "native:native-sidebar"(exports, module2) {
36
+ module2.exports = ((require2) => {
37
+ var module3 = { exports: {} };
38
+ var exports2 = module3.exports;
39
+ Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" });
40
+ let _deepseek_ai_dsh_client_store = require2("@deepseek-ai/dsh-client-store");
41
+ let _deepseek_ai_dsh_client_ui_slots = require2("@deepseek-ai/dsh-client-ui-slots");
42
+ let react_jsx_runtime = require2("react/jsx-runtime");
43
+ let _deepseek_ai_dsh_client_ui_primitives = require2("@deepseek-ai/dsh-client-ui-primitives");
44
+ let react = require2("react");
45
+ const NO_PANELS = [];
46
+ function createPanelPins() {
47
+ const store = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)({ unpinned: NO_PANELS });
48
+ return {
49
+ unpinned: {
50
+ getSnapshot: () => store.getSnapshot().unpinned,
51
+ subscribe: (listener) => store.subscribe(listener)
52
+ },
53
+ setPinned: (id, pinned) => {
54
+ const current = store.getSnapshot().unpinned;
55
+ if (id === "plugins" || pinned !== current.includes(id)) return;
56
+ store.set({ unpinned: pinned ? current.filter((entry) => entry !== id) : [...current, id] });
57
+ }
58
+ };
59
+ }
60
+ const css$1 = ".IW6AQa_controls{align-items:center;gap:8px;display:flex}.IW6AQa_iconButton{border-radius:var(--dsw-radius-sm);width:28px;height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}@media (hover:hover){.IW6AQa_iconButton:hover{background:var(--dsw-alias-interactive-bg-hover)}}";
61
+ const tagId$1 = "dsh-panel-folders/HeaderLeadingControls.module.css";
62
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
63
+ const tag = document.createElement("style");
64
+ tag.dataset.plugin = "dsh-panel-folders";
65
+ tag.dataset.pluginCss = tagId$1;
66
+ tag.textContent = css$1;
67
+ document.head.appendChild(tag);
68
+ }
69
+ var HeaderLeadingControls_module_css_default = {
70
+ "controls": "IW6AQa_controls",
71
+ "iconButton": "IW6AQa_iconButton"
72
+ };
73
+ function HeaderLeadingControls({ toggleSidebar, startSession, trackEntryClick, useRemoteAccess, useShortcuts, t }) {
74
+ const canStartSession = useRemoteAccess("session/create");
75
+ const desktop = document.documentElement.hasAttribute("data-platform");
76
+ const shortcut = useShortcuts((rows) => rows.find((row) => row.id === "sidebar.left.toggle"));
77
+ const newShortcut = useShortcuts((rows) => rows.find((row) => row.id === "session.new"));
78
+ return (0, react_jsx_runtime.jsxs)("div", {
79
+ className: HeaderLeadingControls_module_css_default.controls,
80
+ children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
81
+ label: t("toggle.open"),
82
+ shortcutKeys: shortcut?.keys,
83
+ delayMs: 500,
84
+ children: (0, react_jsx_runtime.jsx)("button", {
85
+ "data-sidebar-opener": true,
86
+ type: "button",
87
+ className: HeaderLeadingControls_module_css_default.iconButton,
88
+ "aria-label": t("toggle.open"),
89
+ "aria-keyshortcuts": shortcut?.aria,
90
+ onClick: () => {
91
+ toggleSidebar();
92
+ },
93
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPanelLeftOutlineRegular, { size: 16 })
94
+ })
95
+ }), desktop && canStartSession && (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
96
+ label: t("session.new.label"),
97
+ shortcutKeys: newShortcut?.keys,
98
+ delayMs: 500,
99
+ children: (0, react_jsx_runtime.jsx)("button", {
100
+ type: "button",
101
+ className: HeaderLeadingControls_module_css_default.iconButton,
102
+ "aria-label": t("session.new.label"),
103
+ "aria-keyshortcuts": newShortcut?.aria,
104
+ onClick: () => {
105
+ trackEntryClick({
106
+ menu_name: "new_session",
107
+ position: "titlebar"
108
+ });
109
+ startSession();
110
+ },
111
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconNewChatOutlineRegular, { size: 16 })
112
+ })
113
+ })]
114
+ });
115
+ }
116
+ function r(e) {
117
+ var t, f, n = "";
118
+ if ("string" == typeof e || "number" == typeof e) n += e;
119
+ else if ("object" == typeof e) if (Array.isArray(e)) {
120
+ var o = e.length;
121
+ for (t = 0; t < o; t++) e[t] && (f = r(e[t])) && (n && (n += " "), n += f);
122
+ } else for (f in e) e[f] && (n && (n += " "), n += f);
123
+ return n;
124
+ }
125
+ function clsx() {
126
+ for (var e, t, f = 0, n = "", o = arguments.length; f < o; f++) (e = arguments[f]) && (t = r(e)) && (n && (n += " "), n += t);
127
+ return n;
128
+ }
129
+ const css = ".hHd-Xa_root{--dsh-sidebar-inline-padding:8px;--dsh-sidebar-row-padding:12px;--dsh-sidebar-label-gap:6px;--dsh-sidebar-paint-inset:3px;height:100%;padding:6px var(--dsh-sidebar-inline-padding);box-sizing:border-box;background:var(--dsw-specific-sidebar-fill);color:var(--dsw-alias-label-primary);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);flex-direction:column;font-size:14px;display:flex}[data-animating]:not([data-dragging]) .hHd-Xa_root{transition:width var(--ds-transition-duration-slow) var(--ds-ease-in-out)}[data-platform=darwin] .hHd-Xa_root{background:0 0}.hHd-Xa_root.hHd-Xa_collapsed{padding:18px 10px 6px}[data-windows-titlebar] .hHd-Xa_root .hHd-Xa_logoRow{height:40px;margin:0;padding:0}[data-windows-titlebar] .hHd-Xa_toggle{top:calc((var(--dsh-windows-titlebar-height) - 28px) / 2);z-index:30;-webkit-app-region:no-drag;position:fixed;left:12px}[data-windows-titlebar] .hHd-Xa_root.hHd-Xa_collapsed .hHd-Xa_logoRow{height:0}[data-windows-titlebar] .hHd-Xa_root:not(.hHd-Xa_collapsed) .hHd-Xa_brand{padding-left:8px}[data-windows-titlebar] .hHd-Xa_brandIdentity{transform:translateY(1px)}[data-windows-titlebar] .hHd-Xa_brandMark{transform:translate(1px)}[data-windows-titlebar] .hHd-Xa_brandName{font-weight:400}[data-windows-titlebar] .hHd-Xa_root.hHd-Xa_collapsed{padding:0}[data-windows-titlebar] .hHd-Xa_root:not(.hHd-Xa_collapsed) .hHd-Xa_newSession{margin-top:6px}[data-windows-titlebar] .hHd-Xa_collapsed .hHd-Xa_panelList,[data-windows-titlebar] .hHd-Xa_collapsed .hHd-Xa_regionArea,[data-windows-titlebar] .hHd-Xa_collapsed .hHd-Xa_footArea{display:none}html[data-windows-titlebar]:has([data-sidebar-collapsed=true]){--dsh-windows-menu-start:84px}[data-windows-titlebar] .hHd-Xa_collapsed .hHd-Xa_newSession{top:calc((var(--dsh-windows-titlebar-height) - 28px) / 2);z-index:30;-webkit-app-region:no-drag;border:none;margin:0;padding:0;position:fixed;left:48px}[data-windows-titlebar] .hHd-Xa_railIn .hHd-Xa_iconButton,[data-windows-titlebar] .hHd-Xa_railIn .hHd-Xa_newSession{animation:none}[data-windows-titlebar] .hHd-Xa_collapsed .hHd-Xa_toggle,[data-windows-titlebar] .hHd-Xa_collapsed .hHd-Xa_newSession{border-radius:var(--dsw-radius-sm);width:28px;height:28px;color:var(--dsw-alias-label-secondary)}[data-windows-titlebar] .hHd-Xa_collapsed .hHd-Xa_toggle .hHd-Xa_panelIcon{display:inline}.hHd-Xa_root.hHd-Xa_quietBars{--dsh-scrollbar-thumb:transparent;--dsh-scrollbar-thumb-hover:transparent}.hHd-Xa_fading>*{opacity:0;transition:opacity .15s var(--ds-ease-in-out)}.hHd-Xa_wide{animation:hHd-Xa_wide-in .2s var(--ds-ease-in-out)}@keyframes hHd-Xa_wide-in{0%{opacity:0}}.hHd-Xa_railIn .hHd-Xa_iconButton,.hHd-Xa_railIn .hHd-Xa_newSession,.hHd-Xa_railIn .hHd-Xa_panelList,.hHd-Xa_railIn .hHd-Xa_regionArea{animation:hHd-Xa_rail-in .15s var(--ds-ease-in-out) backwards}.hHd-Xa_railIn .hHd-Xa_footArea{animation:hHd-Xa_rail-fade-in .15s var(--ds-ease-in-out) backwards}@keyframes hHd-Xa_rail-in{0%{opacity:0;transform:translate(49px)}}@keyframes hHd-Xa_rail-fade-in{0%{opacity:0}}.hHd-Xa_topStrip{box-sizing:border-box;height:52px;margin:-6px calc(-1 * var(--dsh-sidebar-inline-padding)) 0;flex:none;justify-content:flex-end;align-items:center;padding:0 12px 2px;display:flex}html[data-platform=darwin]:not([data-fullscreen]) .hHd-Xa_root:not(.hHd-Xa_collapsed)>.hHd-Xa_topStrip>.hHd-Xa_toggle{transform:translate(4px)}[data-fullscreen] .hHd-Xa_topStrip{justify-content:flex-start}.hHd-Xa_topStrip+.hHd-Xa_logoRow{margin-top:-12px}.hHd-Xa_logoRow{box-sizing:border-box;flex:none;justify-content:flex-end;align-items:center;gap:8px;height:60px;margin-bottom:0;padding:8px 0 8px 8px;display:flex;overflow:hidden}.hHd-Xa_collapsed .hHd-Xa_logoRow{justify-content:flex-start;height:36px;margin-bottom:12px;padding:0;overflow:visible}.hHd-Xa_brand{min-width:0;color:inherit;cursor:pointer;background:0 0;border:none;flex:1;align-items:center;padding:0;display:inline-flex;overflow:hidden}[data-platform=darwin] .hHd-Xa_brand{cursor:default}.hHd-Xa_brandIdentity{align-items:center;gap:5px;min-width:0;height:24px;display:inline-flex}.hHd-Xa_brandMark{flex:none;justify-content:center;align-items:center;display:inline-flex}.hHd-Xa_brandName{letter-spacing:.04em;align-items:center;gap:6px;min-width:0;height:24px;font-size:18px;font-weight:600;line-height:24px;display:inline-flex}.hHd-Xa_fallbackBrandName{letter-spacing:0;white-space:nowrap;font-size:17px}.hHd-Xa_localBuildBrand{white-space:nowrap;flex-direction:column;flex:none;justify-content:center;align-items:flex-start;gap:1px;height:24px;display:inline-flex}.hHd-Xa_copyVersion{cursor:pointer;-webkit-app-region:no-drag;display:inline-flex}.hHd-Xa_localBuildTitle{letter-spacing:0;font-size:12px;line-height:13px}.hHd-Xa_iconButton{border-radius:var(--dsw-radius-sm);cursor:pointer;width:28px;height:28px;color:var(--dsw-alias-label-secondary);background:0 0;border:none;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex;position:relative}@media (hover:hover){.hHd-Xa_iconButton:hover{background-color:var(--dsw-alias-interactive-bg-hover)}}.hHd-Xa_iconButton.hHd-Xa_toggle:focus-visible{outline:var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:-2px}.hHd-Xa_collapsed .hHd-Xa_iconButton{border-radius:var(--dsw-radius-md);width:36px;height:36px}.hHd-Xa_collapsed .hHd-Xa_toggle .hHd-Xa_panelIcon{display:none}@media (hover:hover){.hHd-Xa_collapsed .hHd-Xa_toggle:hover .hHd-Xa_panelIcon{display:inline}.hHd-Xa_collapsed .hHd-Xa_toggle:hover .hHd-Xa_railMark{display:none}}.hHd-Xa_railMark{justify-content:center;align-items:center;display:inline-flex}.hHd-Xa_collapsed .hHd-Xa_iconButton{color:var(--dsw-alias-label-primary)}.hHd-Xa_buildVersion{height:10px;color:var(--dsw-alias-label-primary-inverted);background:var(--dsw-alias-label-primary);font-family:var(--ds-font-family-code);white-space:nowrap;border-radius:2px;flex:none;align-items:center;padding:0 3px;font-size:6px;font-weight:500;line-height:10px;display:inline-flex}.hHd-Xa_newSession{height:38px;margin:0 calc(var(--dsh-sidebar-paint-inset) + 1px) 10px;box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-button-elevated-fill);color:var(--dsw-alias-label-primary);cursor:pointer;flex:none;justify-content:center;align-items:center;gap:0;padding:8px 12px;font-size:14px;font-weight:500;line-height:22px;display:flex;position:relative;overflow:hidden;container-type:inline-size}@media (hover:hover){.hHd-Xa_newSession:hover{background:var(--dsw-alias-button-floating-hover)}}[data-platform=darwin] :where(.hHd-Xa_root:not([role=dialog])) .hHd-Xa_newSession{background:#ffffff8c}@media (hover:hover){[data-platform=darwin] :where(.hHd-Xa_root:not([role=dialog])) .hHd-Xa_newSession:hover{background:#ffffff4d}}[data-platform=darwin] [data-ds-dark-theme] :where(.hHd-Xa_root:not([role=dialog])) .hHd-Xa_newSession{background:#ffffff26}@media (hover:hover){[data-platform=darwin] [data-ds-dark-theme] :where(.hHd-Xa_root:not([role=dialog])) .hHd-Xa_newSession:hover{background:#fff3}}.hHd-Xa_collapsed .hHd-Xa_newSession{background:0 0;border-color:#0000;align-self:flex-start;gap:0;width:36px;height:36px;margin:0 0 12px;padding:0}@media (hover:hover){.hHd-Xa_collapsed .hHd-Xa_newSession:hover{background-color:var(--dsw-alias-interactive-bg-hover)}}.hHd-Xa_newSessionLabel{white-space:nowrap;max-width:200px;overflow:hidden}.hHd-Xa_collapsed .hHd-Xa_newSessionLabel{max-width:0}.hHd-Xa_newSessionLabelMask{flex:1;min-width:0}.hHd-Xa_newSession:focus-visible .hHd-Xa_newSessionLabelMask:has(+.hHd-Xa_newSessionShortcut){overflow:hidden;mask-image:linear-gradient(90deg,#000 calc(100% - 16px),#0000)}@media (hover:hover){.hHd-Xa_newSession:hover .hHd-Xa_newSessionLabelMask:has(+.hHd-Xa_newSessionShortcut){overflow:hidden;mask-image:linear-gradient(90deg,#000 calc(100% - 16px),#0000)}}.hHd-Xa_newSessionContent{justify-content:center;align-items:center;gap:6px;width:100cqw;display:flex}.hHd-Xa_newSessionContent>svg{flex:none}.hHd-Xa_newSessionShortcut{opacity:0;pointer-events:none;flex:none;font-weight:400;display:inline-flex}.hHd-Xa_newSession:focus-visible .hHd-Xa_newSessionShortcut{opacity:1}@media (hover:hover){.hHd-Xa_newSession:hover .hHd-Xa_newSessionShortcut{opacity:1}}.hHd-Xa_panelList{flex-direction:column;flex:none;gap:2px;margin-bottom:8px;display:flex}.hHd-Xa_panelRow{align-items:center;gap:var(--dsh-sidebar-label-gap);min-height:36px;padding:7px calc(var(--dsh-sidebar-row-padding) - var(--dsh-sidebar-paint-inset));box-sizing:border-box;border:none;border-inline:var(--dsh-sidebar-paint-inset) solid transparent;border-radius:var(--dsw-radius-md);color:var(--dsw-alias-label-primary);font:inherit;text-align:left;cursor:pointer;background:padding-box padding-box;margin:0;line-height:22px;display:flex}@media (hover:hover){.hHd-Xa_panelRow:hover{background-color:var(--dsw-alias-interactive-bg-hover)}}.hHd-Xa_panelRow.hHd-Xa_panelActive{background-color:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.hHd-Xa_panelRow:focus-visible{outline:var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:-2px}.hHd-Xa_moreAnchor{flex-direction:column;display:flex}.hHd-Xa_panelRow[aria-expanded=true]{background-color:var(--dsw-alias-interactive-bg-hover)}.hHd-Xa_moreMenu{width:288px;max-width:calc(100vw - 24px)}.hHd-Xa_panelGlyph{flex:none;justify-content:center;align-items:center;display:inline-flex}.hHd-Xa_panelTitle{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.hHd-Xa_collapsed .hHd-Xa_panelList{gap:12px;margin-bottom:12px}.hHd-Xa_collapsed .hHd-Xa_panelRow{width:36px;height:36px;color:var(--dsw-alias-label-primary);background-clip:border-box;border-inline:0;justify-content:center;margin:0;padding:0}.hHd-Xa_regionArea{min-height:0;margin-left:-4px;margin-right:calc(-1 * var(--dsh-sidebar-inline-padding));flex-direction:column;flex:1;padding-left:4px;display:flex;overflow:hidden}.hHd-Xa_collapsed .hHd-Xa_regionArea{margin-left:0;margin-right:0;padding-left:0}.hHd-Xa_footArea{flex-direction:column;flex:none;display:flex}.hHd-Xa_settingsArea,.hHd-Xa_footerActions{flex:none;width:100%;min-width:0}.hHd-Xa_footerActions{display:flex}.hHd-Xa_collapsed .hHd-Xa_footArea{align-items:center}.hHd-Xa_collapsed .hHd-Xa_settingsArea,.hHd-Xa_collapsed .hHd-Xa_footerActions{justify-content:center;width:auto;display:flex}@media (prefers-reduced-motion:reduce){[data-animating]:not([data-dragging]) .hHd-Xa_root,.hHd-Xa_wide,.hHd-Xa_fading>*,.hHd-Xa_railIn .hHd-Xa_iconButton,.hHd-Xa_railIn .hHd-Xa_newSession,.hHd-Xa_railIn .hHd-Xa_panelList,.hHd-Xa_railIn .hHd-Xa_footArea,.hHd-Xa_railIn .hHd-Xa_regionArea{transition:none;animation:none}}";
130
+ const tagId = "dsh-panel-folders/SidebarRoot.module.css";
131
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
132
+ const tag = document.createElement("style");
133
+ tag.dataset.plugin = "dsh-panel-folders";
134
+ tag.dataset.pluginCss = tagId;
135
+ tag.textContent = css;
136
+ document.head.appendChild(tag);
137
+ }
138
+ var SidebarRoot_module_css_default = {
139
+ "brand": "hHd-Xa_brand",
140
+ "brandIdentity": "hHd-Xa_brandIdentity",
141
+ "brandMark": "hHd-Xa_brandMark",
142
+ "brandName": "hHd-Xa_brandName",
143
+ "buildVersion": "hHd-Xa_buildVersion",
144
+ "collapsed": "hHd-Xa_collapsed",
145
+ "copyVersion": "hHd-Xa_copyVersion",
146
+ "fading": "hHd-Xa_fading",
147
+ "fallbackBrandName": "hHd-Xa_fallbackBrandName",
148
+ "footArea": "hHd-Xa_footArea",
149
+ "footerActions": "hHd-Xa_footerActions",
150
+ "iconButton": "hHd-Xa_iconButton",
151
+ "localBuildBrand": "hHd-Xa_localBuildBrand",
152
+ "localBuildTitle": "hHd-Xa_localBuildTitle",
153
+ "logoRow": "hHd-Xa_logoRow",
154
+ "moreAnchor": "hHd-Xa_moreAnchor",
155
+ "moreMenu": "hHd-Xa_moreMenu",
156
+ "newSession": "hHd-Xa_newSession",
157
+ "newSessionContent": "hHd-Xa_newSessionContent",
158
+ "newSessionLabel": "hHd-Xa_newSessionLabel",
159
+ "newSessionLabelMask": "hHd-Xa_newSessionLabelMask",
160
+ "newSessionShortcut": "hHd-Xa_newSessionShortcut",
161
+ "panelActive": "hHd-Xa_panelActive",
162
+ "panelGlyph": "hHd-Xa_panelGlyph",
163
+ "panelIcon": "hHd-Xa_panelIcon",
164
+ "panelList": "hHd-Xa_panelList",
165
+ "panelRow": "hHd-Xa_panelRow",
166
+ "panelTitle": "hHd-Xa_panelTitle",
167
+ "quietBars": "hHd-Xa_quietBars",
168
+ "rail-fade-in": "hHd-Xa_rail-fade-in",
169
+ "rail-in": "hHd-Xa_rail-in",
170
+ "railIn": "hHd-Xa_railIn",
171
+ "railMark": "hHd-Xa_railMark",
172
+ "regionArea": "hHd-Xa_regionArea",
173
+ "root": "hHd-Xa_root",
174
+ "settingsArea": "hHd-Xa_settingsArea",
175
+ "toggle": "hHd-Xa_toggle",
176
+ "topStrip": "hHd-Xa_topStrip",
177
+ "wide": "hHd-Xa_wide",
178
+ "wide-in": "hHd-Xa_wide-in"
179
+ };
180
+ const COLLAPSE_SETTLE_MS = 150;
181
+ const SCROLLBAR_LINGER_MS = 2e3;
182
+ function localBuildVersion() {
183
+ return `0.2.2-rc.1-c59d10a` + ({}.DSH_CLIENT_GIT_DIRTY === "true" ? "-dirty" : "");
184
+ }
185
+ function officialEntry(id) {
186
+ if (id === "plugins") return "plugin";
187
+ return id === "schedules" ? "cron" : void 0;
188
+ }
189
+ function PanelRow({ id, label, wide, usePanelInfo, selectPanel, trackEntryClick, renderSlot }) {
190
+ const active = usePanelInfo((info) => info.activePanelId === id);
191
+ return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
192
+ label,
193
+ delayMs: 500,
194
+ disabled: wide,
195
+ children: (0, react_jsx_runtime.jsxs)("button", {
196
+ type: "button",
197
+ className: clsx(SidebarRoot_module_css_default.panelRow, active && SidebarRoot_module_css_default.panelActive),
198
+ "aria-label": label,
199
+ "aria-current": active ? "page" : void 0,
200
+ onClick: () => {
201
+ const entry = officialEntry(id);
202
+ if (entry !== void 0) trackEntryClick({
203
+ menu_name: entry,
204
+ position: "sidebar"
205
+ });
206
+ selectPanel(id);
207
+ },
208
+ children: [(0, react_jsx_runtime.jsx)("span", {
209
+ className: SidebarRoot_module_css_default.panelGlyph,
210
+ "aria-hidden": "true",
211
+ children: renderSlot("sidebar.panellist", {
212
+ size: wide ? 16 : 18,
213
+ active
214
+ }, { only: id })
215
+ }), wide && (0, react_jsx_runtime.jsx)("span", {
216
+ className: clsx(SidebarRoot_module_css_default.panelTitle, SidebarRoot_module_css_default.wide),
217
+ children: label
218
+ })]
219
+ })
220
+ });
221
+ }
222
+ function PanelMoreMenu({ wide, label, entries, onOpen, onPinnedChange, trackEntryClick, renderSlot }) {
223
+ const [open, setOpen] = (0, react.useState)(false);
224
+ const onDismiss = () => {
225
+ setOpen(false);
226
+ };
227
+ return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
228
+ open,
229
+ onClose: onDismiss,
230
+ portal: true,
231
+ autoFocus: true,
232
+ className: SidebarRoot_module_css_default.moreAnchor,
233
+ listClassName: SidebarRoot_module_css_default.moreMenu,
234
+ anchor: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
235
+ label,
236
+ delayMs: 500,
237
+ disabled: wide,
238
+ children: (0, react_jsx_runtime.jsxs)("button", {
239
+ type: "button",
240
+ className: SidebarRoot_module_css_default.panelRow,
241
+ "aria-label": label,
242
+ "aria-haspopup": "menu",
243
+ "aria-expanded": open,
244
+ onClick: () => {
245
+ trackEntryClick({
246
+ menu_name: "more",
247
+ position: "sidebar"
248
+ });
249
+ setOpen((value) => !value);
250
+ },
251
+ children: [(0, react_jsx_runtime.jsx)("span", {
252
+ className: SidebarRoot_module_css_default.panelGlyph,
253
+ "aria-hidden": "true",
254
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconAppsAddOutlineRegular, { size: wide ? 16 : 18 })
255
+ }), wide && (0, react_jsx_runtime.jsx)("span", {
256
+ className: clsx(SidebarRoot_module_css_default.panelTitle, SidebarRoot_module_css_default.wide),
257
+ children: label
258
+ })]
259
+ })
260
+ }),
261
+ children: renderSlot("sidebar.panellist.actions", {
262
+ entries,
263
+ onOpen,
264
+ onPinnedChange,
265
+ onDismiss
266
+ })
267
+ });
268
+ }
269
+ function SidebarRoot({ collapsed, width, drawer, startSession, toggleSidebar, selectPanel, setPinned, trackEntryClick, useRemoteAccess, usePanels, useEntryPins, useEntryActions, useShortcuts, usePanelInfo, t, renderSlot }) {
270
+ const panels = usePanels((snapshot) => snapshot);
271
+ const unpinned = useEntryPins((ids) => ids);
272
+ const activePanelId = usePanelInfo((info) => info.activePanelId);
273
+ const hasEntryActions = useEntryActions((registered) => registered);
274
+ const shortcut = useShortcuts((rows) => rows.find((row) => row.id === "sidebar.left.toggle"));
275
+ const newShortcut = useShortcuts((rows) => rows.find((row) => row.id === "session.new"));
276
+ const canStartSession = useRemoteAccess("session/create");
277
+ const toggleLabel = collapsed ? t("toggle.open") : t("toggle.collapse");
278
+ const [settled, setSettled] = (0, react.useState)(collapsed);
279
+ (0, react.useEffect)(() => {
280
+ if (drawer || !collapsed) {
281
+ setSettled(collapsed);
282
+ return;
283
+ }
284
+ const timer = window.setTimeout(() => {
285
+ setSettled(true);
286
+ }, COLLAPSE_SETTLE_MS);
287
+ return () => {
288
+ window.clearTimeout(timer);
289
+ };
290
+ }, [collapsed, drawer]);
291
+ const windowsTitlebar = document.documentElement.hasAttribute("data-windows-titlebar");
292
+ const wide = drawer || (windowsTitlebar ? !collapsed : !collapsed || !settled);
293
+ const openNewSession = () => {
294
+ trackEntryClick({
295
+ menu_name: "new_session",
296
+ position: windowsTitlebar && collapsed ? "titlebar" : "sidebar"
297
+ });
298
+ startSession();
299
+ };
300
+ const captionTooltipSide = windowsTitlebar ? "bottom" : "right";
301
+ const lastWideWidth = (0, react.useRef)(width);
302
+ if (drawer || !collapsed) lastWideWidth.current = width;
303
+ const animateRail = (0, react.useRef)(!collapsed);
304
+ if (drawer || !collapsed) animateRail.current = !collapsed;
305
+ const column = (0, react.useRef)(null);
306
+ const sidebarFocus = (0, react.useRef)(null);
307
+ (0, _deepseek_ai_dsh_client_ui_primitives.useModalLayer)(column, drawer && !collapsed, toggleSidebar);
308
+ (0, react.useLayoutEffect)(() => {
309
+ if (!collapsed) return;
310
+ const ownsMenuFocus = (sidebarFocus.current?.getAttribute("aria-controls")?.split(/\s+/) ?? []).some((id) => document.getElementById(id)?.contains(document.activeElement));
311
+ if (sidebarFocus.current !== document.activeElement && !ownsMenuFocus) return;
312
+ const opener = drawer ? column.current?.ownerDocument.querySelector("[data-sidebar-opener]") : column.current?.querySelector("[data-sidebar-toggle]");
313
+ if (opener != null && !(0, _deepseek_ai_dsh_client_ui_primitives.isBehindModal)(opener)) (0, _deepseek_ai_dsh_client_ui_primitives.focusWithoutRing)(opener, { preventScroll: true });
314
+ }, [drawer, collapsed]);
315
+ const [pointerInside, setPointerInside] = (0, react.useState)(false);
316
+ const lingerTimer = (0, react.useRef)(void 0);
317
+ const armLinger = () => {
318
+ if (lingerTimer.current !== void 0) return;
319
+ lingerTimer.current = window.setTimeout(() => {
320
+ lingerTimer.current = void 0;
321
+ setPointerInside(false);
322
+ }, SCROLLBAR_LINGER_MS);
323
+ };
324
+ const cancelLinger = () => {
325
+ window.clearTimeout(lingerTimer.current);
326
+ lingerTimer.current = void 0;
327
+ };
328
+ (0, react.useEffect)(() => {
329
+ if (!pointerInside) return;
330
+ const onMove = (event) => {
331
+ const rect = column.current?.getBoundingClientRect();
332
+ if (rect === void 0) return;
333
+ if (event.clientX >= rect.left && event.clientX < rect.right && event.clientY >= rect.top && event.clientY < rect.bottom) cancelLinger();
334
+ else armLinger();
335
+ };
336
+ document.addEventListener("pointermove", onMove);
337
+ return () => {
338
+ document.removeEventListener("pointermove", onMove);
339
+ cancelLinger();
340
+ };
341
+ }, [pointerInside]);
342
+ const buildVersion = localBuildVersion();
343
+ const [copiedToast, setCopiedToast] = (0, react.useState)(null);
344
+ const copyVersion = (version) => () => {
345
+ (0, _deepseek_ai_dsh_client_ui_primitives.writeClipboard)(version).then((ok) => {
346
+ if (ok) setCopiedToast((seq) => (seq ?? 0) + 1);
347
+ });
348
+ };
349
+ const darwinDesktop = (0, _deepseek_ai_dsh_client_ui_primitives.isDarwinDesktop)();
350
+ const toggle = (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
351
+ label: toggleLabel,
352
+ shortcutKeys: shortcut?.keys,
353
+ delayMs: 500,
354
+ side: captionTooltipSide,
355
+ portal: drawer,
356
+ children: (0, react_jsx_runtime.jsxs)("button", {
357
+ "data-sidebar-toggle": true,
358
+ "data-modal-autofocus": drawer || void 0,
359
+ type: "button",
360
+ className: clsx(SidebarRoot_module_css_default.iconButton, SidebarRoot_module_css_default.toggle),
361
+ "aria-label": toggleLabel,
362
+ "aria-keyshortcuts": shortcut?.aria,
363
+ onClick: () => {
364
+ toggleSidebar();
365
+ },
366
+ children: [
367
+ !wide && !windowsTitlebar && (0, react_jsx_runtime.jsx)("span", {
368
+ className: SidebarRoot_module_css_default.railMark,
369
+ "aria-hidden": "true",
370
+ children: renderSlot("sidebar.brand.mark", { size: 24 }, { fallback: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.FishLogo, { size: 24 }) })
371
+ }),
372
+ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPanelLeftOutlineRegular, {
373
+ className: SidebarRoot_module_css_default.panelIcon,
374
+ size: wide || windowsTitlebar ? 16 : 18
375
+ }),
376
+ !wide && renderSlot("sidebar.toggle.badge", {})
377
+ ]
378
+ })
379
+ });
380
+ return (0, react_jsx_runtime.jsxs)("div", {
381
+ ref: column,
382
+ onFocusCapture: (event) => {
383
+ sidebarFocus.current = event.target;
384
+ },
385
+ role: drawer ? "dialog" : void 0,
386
+ "data-shortcut-modal": drawer ? "sidebar" : void 0,
387
+ "aria-modal": drawer && !collapsed ? true : void 0,
388
+ "aria-label": drawer ? t("navigation.label") : void 0,
389
+ tabIndex: drawer ? -1 : void 0,
390
+ className: clsx(SidebarRoot_module_css_default.root, !wide && SidebarRoot_module_css_default.collapsed, !wide && animateRail.current && SidebarRoot_module_css_default.railIn, !drawer && collapsed && wide && SidebarRoot_module_css_default.fading, !pointerInside && SidebarRoot_module_css_default.quietBars),
391
+ style: wide ? { width: !drawer && collapsed ? lastWideWidth.current : width } : void 0,
392
+ onPointerEnter: () => {
393
+ cancelLinger();
394
+ setPointerInside(true);
395
+ },
396
+ onPointerLeave: () => {
397
+ armLinger();
398
+ },
399
+ children: [
400
+ darwinDesktop && (0, react_jsx_runtime.jsx)("div", {
401
+ className: SidebarRoot_module_css_default.topStrip,
402
+ "data-window-drag": true,
403
+ children: toggle
404
+ }),
405
+ (0, react_jsx_runtime.jsxs)("div", {
406
+ className: SidebarRoot_module_css_default.logoRow,
407
+ "data-window-drag": true,
408
+ children: [wide && (() => {
409
+ const identity = (0, react_jsx_runtime.jsxs)("span", {
410
+ className: SidebarRoot_module_css_default.brandIdentity,
411
+ "aria-hidden": "true",
412
+ children: [(0, react_jsx_runtime.jsx)("span", {
413
+ className: SidebarRoot_module_css_default.brandMark,
414
+ children: renderSlot("sidebar.brand.mark", { size: 24 }, { fallback: buildVersion === void 0 ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.FishLogo, { size: 24 }) : (0, react_jsx_runtime.jsx)("span", {
415
+ className: SidebarRoot_module_css_default.copyVersion,
416
+ "data-copy-version": true,
417
+ onClick: copyVersion(buildVersion),
418
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.FishLogo, { size: 24 })
419
+ }) })
420
+ }), (0, react_jsx_runtime.jsx)("span", {
421
+ className: SidebarRoot_module_css_default.brandName,
422
+ children: renderSlot("sidebar.brand.name", {}, { fallback: buildVersion === void 0 ? (0, react_jsx_runtime.jsx)("span", {
423
+ className: SidebarRoot_module_css_default.fallbackBrandName,
424
+ children: t("brand.localBuild")
425
+ }) : (0, react_jsx_runtime.jsxs)("span", {
426
+ className: clsx(SidebarRoot_module_css_default.localBuildBrand, SidebarRoot_module_css_default.copyVersion),
427
+ "data-copy-version": true,
428
+ onClick: copyVersion(buildVersion),
429
+ children: [(0, react_jsx_runtime.jsx)("span", {
430
+ className: SidebarRoot_module_css_default.localBuildTitle,
431
+ children: t("brand.localBuild")
432
+ }), (0, react_jsx_runtime.jsx)("span", {
433
+ className: SidebarRoot_module_css_default.buildVersion,
434
+ children: buildVersion
435
+ })]
436
+ }) })
437
+ })]
438
+ });
439
+ return darwinDesktop || !canStartSession ? (0, react_jsx_runtime.jsx)("span", {
440
+ className: clsx(SidebarRoot_module_css_default.brand, SidebarRoot_module_css_default.wide),
441
+ children: identity
442
+ }) : (0, react_jsx_runtime.jsx)("button", {
443
+ type: "button",
444
+ className: clsx(SidebarRoot_module_css_default.brand, SidebarRoot_module_css_default.wide),
445
+ "aria-label": t("session.new.label"),
446
+ "aria-keyshortcuts": newShortcut?.aria,
447
+ onClick: (event) => {
448
+ if (event.target.closest("[data-copy-version]") !== null) return;
449
+ openNewSession();
450
+ },
451
+ children: identity
452
+ });
453
+ })(), !darwinDesktop && toggle]
454
+ }),
455
+ canStartSession && (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
456
+ label: t("session.new.label"),
457
+ shortcutKeys: newShortcut?.keys,
458
+ delayMs: 500,
459
+ side: captionTooltipSide,
460
+ disabled: wide,
461
+ children: (0, react_jsx_runtime.jsxs)("button", {
462
+ type: "button",
463
+ className: SidebarRoot_module_css_default.newSession,
464
+ "aria-label": t("session.new.label"),
465
+ "aria-keyshortcuts": newShortcut?.aria,
466
+ onClick: openNewSession,
467
+ children: [(0, react_jsx_runtime.jsx)("span", {
468
+ className: SidebarRoot_module_css_default.newSessionLabelMask,
469
+ children: (0, react_jsx_runtime.jsxs)("span", {
470
+ className: SidebarRoot_module_css_default.newSessionContent,
471
+ children: [wide ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconNewChatOutlineMedium, { size: 14 }) : (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconNewChatOutlineRegular, { size: windowsTitlebar ? 16 : 18 }), wide && (0, react_jsx_runtime.jsx)("span", {
472
+ className: clsx(SidebarRoot_module_css_default.newSessionLabel, SidebarRoot_module_css_default.wide),
473
+ children: t("session.new")
474
+ })]
475
+ })
476
+ }), wide && newShortcut !== void 0 && newShortcut.keys.length > 0 && (0, react_jsx_runtime.jsx)("span", {
477
+ className: SidebarRoot_module_css_default.newSessionShortcut,
478
+ "aria-hidden": "true",
479
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.ShortcutKeys, { keys: newShortcut.keys })
480
+ })]
481
+ })
482
+ }),
483
+ panels.length > 0 && (0, react_jsx_runtime.jsxs)("nav", {
484
+ className: SidebarRoot_module_css_default.panelList,
485
+ "aria-label": t("panels.label"),
486
+ children: [panels.filter(({ id }) => id === "plugins" || !unpinned.includes(id)).map(({ id, label }) => (0, react_jsx_runtime.jsx)(PanelRow, {
487
+ id,
488
+ label,
489
+ wide,
490
+ usePanelInfo,
491
+ selectPanel,
492
+ trackEntryClick,
493
+ renderSlot
494
+ }, id)), hasEntryActions && (0, react_jsx_runtime.jsx)(PanelMoreMenu, {
495
+ wide,
496
+ label: t("panels.more"),
497
+ entries: panels.filter(({ id }) => id !== "plugins").map(({ id, label }) => ({
498
+ id,
499
+ label,
500
+ pinned: !unpinned.includes(id),
501
+ active: id === activePanelId
502
+ })),
503
+ onOpen: (id) => {
504
+ const entry = officialEntry(id);
505
+ if (entry !== void 0) trackEntryClick({
506
+ menu_name: entry,
507
+ position: "sidebar_more"
508
+ });
509
+ const panel = panels.find((candidate) => candidate.id === id);
510
+ if (panel !== void 0) selectPanel(panel.id);
511
+ },
512
+ onPinnedChange: setPinned,
513
+ trackEntryClick,
514
+ renderSlot
515
+ })]
516
+ }),
517
+ (0, react_jsx_runtime.jsx)("div", {
518
+ className: SidebarRoot_module_css_default.regionArea,
519
+ children: renderSlot("sidebar.workspaces", {
520
+ wide,
521
+ expandSidebar: () => {
522
+ if (collapsed) toggleSidebar();
523
+ }
524
+ })
525
+ }),
526
+ copiedToast !== null && (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Toast, {
527
+ tone: "success",
528
+ text: t("version.copied"),
529
+ onDone: () => {
530
+ setCopiedToast(null);
531
+ }
532
+ }, copiedToast),
533
+ (0, react_jsx_runtime.jsxs)("div", {
534
+ className: SidebarRoot_module_css_default.footArea,
535
+ children: [(0, react_jsx_runtime.jsx)("div", {
536
+ className: SidebarRoot_module_css_default.footerActions,
537
+ children: renderSlot("sidebar.footer.action", { wide })
538
+ }), (0, react_jsx_runtime.jsx)("div", {
539
+ className: SidebarRoot_module_css_default.settingsArea,
540
+ children: renderSlot("sidebar.settings", { wide })
541
+ })]
542
+ })
543
+ ]
544
+ });
545
+ }
546
+ const zh = {
547
+ "session.new": "\u65B0\u4F1A\u8BDD",
548
+ "session.new.label": "\u65B0\u5EFA\u4F1A\u8BDD",
549
+ "toggle.open": "\u6253\u5F00\u4FA7\u8FB9\u680F",
550
+ "toggle.collapse": "\u6536\u8D77\u4FA7\u8FB9\u680F",
551
+ "panels.label": "\u5168\u5C40\u9762\u677F",
552
+ "navigation.label": "\u5BFC\u822A",
553
+ "panels.more": "\u66F4\u591A",
554
+ "version.copied": "\u7248\u672C\u53F7\u590D\u5236\u6210\u529F"
555
+ };
556
+ const en = {
557
+ "session.new": "New Session",
558
+ "session.new.label": "New session",
559
+ "toggle.open": "Open sidebar",
560
+ "toggle.collapse": "Collapse sidebar",
561
+ "panels.label": "Global panels",
562
+ "navigation.label": "Navigation",
563
+ "panels.more": "More",
564
+ "version.copied": "Version copied"
565
+ };
566
+ const ja = {
567
+ "session.new": "\u65B0\u898F\u30BB\u30C3\u30B7\u30E7\u30F3",
568
+ "session.new.label": "\u65B0\u898F\u30BB\u30C3\u30B7\u30E7\u30F3",
569
+ "toggle.open": "\u30B5\u30A4\u30C9\u30D0\u30FC\u3092\u958B\u304F",
570
+ "toggle.collapse": "\u30B5\u30A4\u30C9\u30D0\u30FC\u3092\u6298\u308A\u305F\u305F\u3080",
571
+ "panels.label": "\u30B0\u30ED\u30FC\u30D0\u30EB\u30D1\u30CD\u30EB",
572
+ "navigation.label": "\u30CA\u30D3\u30B2\u30FC\u30B7\u30E7\u30F3",
573
+ "panels.more": "\u305D\u306E\u4ED6",
574
+ "version.copied": "\u30D0\u30FC\u30B8\u30E7\u30F3\u3092\u30B3\u30D4\u30FC\u3057\u307E\u3057\u305F"
575
+ };
576
+ const es = {
577
+ "session.new": "Nueva sesi\xF3n",
578
+ "session.new.label": "Nueva sesi\xF3n",
579
+ "toggle.open": "Abrir barra lateral",
580
+ "toggle.collapse": "Contraer barra lateral",
581
+ "panels.label": "Paneles globales",
582
+ "navigation.label": "Navegaci\xF3n",
583
+ "panels.more": "M\xE1s",
584
+ "version.copied": "Versi\xF3n copiada"
585
+ };
586
+ const fr = {
587
+ "session.new": "Nouvelle s\xE9ance",
588
+ "session.new.label": "Nouvelle s\xE9ance",
589
+ "toggle.open": "Ouvrir la barre lat\xE9rale",
590
+ "toggle.collapse": "R\xE9duire la barre lat\xE9rale",
591
+ "panels.label": "Panneaux globaux",
592
+ "navigation.label": "Navigation",
593
+ "panels.more": "Plus",
594
+ "version.copied": "Version copi\xE9e"
595
+ };
596
+ const de = {
597
+ "session.new": "Neue Sitzung",
598
+ "session.new.label": "Neue Sitzung",
599
+ "toggle.open": "Seitenleiste \xF6ffnen",
600
+ "toggle.collapse": "Seitenleiste einklappen",
601
+ "panels.label": "Globale Bereiche",
602
+ "navigation.label": "Navigation",
603
+ "panels.more": "Mehr",
604
+ "version.copied": "Version kopiert"
605
+ };
606
+ const ru = {
607
+ "session.new": "\u041D\u043E\u0432\u0430\u044F \u0441\u0435\u0441\u0441\u0438\u044F",
608
+ "session.new.label": "\u041D\u043E\u0432\u0430\u044F \u0441\u0435\u0441\u0441\u0438\u044F",
609
+ "toggle.open": "\u041E\u0442\u043A\u0440\u044B\u0442\u044C \u0431\u043E\u043A\u043E\u0432\u0443\u044E \u043F\u0430\u043D\u0435\u043B\u044C",
610
+ "toggle.collapse": "\u0421\u0432\u0435\u0440\u043D\u0443\u0442\u044C \u0431\u043E\u043A\u043E\u0432\u0443\u044E \u043F\u0430\u043D\u0435\u043B\u044C",
611
+ "panels.label": "\u0413\u043B\u043E\u0431\u0430\u043B\u044C\u043D\u044B\u0435 \u043F\u0430\u043D\u0435\u043B\u0438",
612
+ "navigation.label": "\u041D\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u044F",
613
+ "panels.more": "\u0415\u0449\u0451",
614
+ "version.copied": "\u0412\u0435\u0440\u0441\u0438\u044F \u0441\u043A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u043D\u0430"
615
+ };
616
+ const pt = {
617
+ "session.new": "Nova sess\xE3o",
618
+ "session.new.label": "Nova sess\xE3o",
619
+ "toggle.open": "Abrir barra lateral",
620
+ "toggle.collapse": "Recolher barra lateral",
621
+ "panels.label": "Pain\xE9is globais",
622
+ "navigation.label": "Navega\xE7\xE3o",
623
+ "panels.more": "Mais",
624
+ "version.copied": "Vers\xE3o copiada"
625
+ };
626
+ const NS = "sidebar";
627
+ const inject2 = [
628
+ "slots",
629
+ "layout",
630
+ "uiWorkspace",
631
+ "locale",
632
+ "shortcuts"
633
+ ];
634
+ function apply2(ctx) {
635
+ const workspaceNavigation = ctx.get("uiWorkspace");
636
+ ctx.effect(() => ctx.locale.register(NS, {
637
+ zh,
638
+ en,
639
+ ja,
640
+ es,
641
+ fr,
642
+ de,
643
+ ru,
644
+ pt
645
+ }), "ui-sidebar: dictionaries");
646
+ const panels = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)([]);
647
+ const syncPanels = () => {
648
+ const next = ctx.slots.entriesOfSlot("sidebar.panellist").map(({ options }) => {
649
+ const id = options.id;
650
+ return {
651
+ id,
652
+ order: options.order ?? 0,
653
+ label: (0, _deepseek_ai_dsh_client_ui_slots.resolveSlotLabel)(options.label) ?? id
654
+ };
655
+ }).sort((a, b) => a.order - b.order);
656
+ const previous = panels.getSnapshot();
657
+ if (previous.length === next.length && previous.every((panel, index) => {
658
+ const candidate = next[index];
659
+ return panel.id === candidate.id && panel.order === candidate.order && panel.label === candidate.label;
660
+ })) return;
661
+ panels.set(next);
662
+ };
663
+ ctx.effect(() => ctx.slots.subscribe("sidebar.panellist", syncPanels), "ui-sidebar: panel entries");
664
+ ctx.effect(() => ctx.locale.subscribe(syncPanels), "ui-sidebar: panel labels");
665
+ const panelPins = createPanelPins();
666
+ const entryActions = {
667
+ getSnapshot: () => ctx.slots.entriesOfSlot("sidebar.panellist.actions").length > 0,
668
+ subscribe: (listener) => ctx.slots.subscribe("sidebar.panellist.actions", listener)
669
+ };
670
+ const injectProps = () => ({
671
+ startSession: (workspaceId) => {
672
+ workspaceNavigation.startSession(workspaceId);
673
+ },
674
+ toggleSidebar: () => {
675
+ ctx.layout.toggleSidebar();
676
+ },
677
+ selectPanel: (id) => {
678
+ ctx.layout.selectPanel(id);
679
+ },
680
+ setPinned: panelPins.setPinned,
681
+ trackEntryClick: (attributes) => {
682
+ ctx.get("productAnalytics")?.track("sidebar_menu_click", attributes);
683
+ },
684
+ hooks: {
685
+ panels,
686
+ shortcuts: ctx.shortcuts.catalog,
687
+ entryPins: panelPins.unpinned,
688
+ entryActions
689
+ }
690
+ });
691
+ ctx.slots.inject("sidebar", () => ctx.slots.register({
692
+ name: "sidebar",
693
+ locale: NS,
694
+ children: {
695
+ "sidebar.brand.mark": {
696
+ kind: "single",
697
+ scope: "root"
698
+ },
699
+ "sidebar.brand.name": {
700
+ kind: "single",
701
+ scope: "root"
702
+ },
703
+ "sidebar.toggle.badge": {
704
+ kind: "single",
705
+ scope: "root"
706
+ },
707
+ "sidebar.panellist": {
708
+ kind: "list",
709
+ scope: "root"
710
+ },
711
+ "sidebar.panellist.actions": {
712
+ kind: "list",
713
+ scope: "root"
714
+ },
715
+ "sidebar.workspaces": {
716
+ kind: "single",
717
+ scope: "root"
718
+ },
719
+ "sidebar.settings": {
720
+ kind: "single",
721
+ scope: "root"
722
+ },
723
+ "sidebar.footer.action": {
724
+ kind: "list",
725
+ scope: "root"
726
+ }
727
+ },
728
+ inject: injectProps
729
+ }, SidebarRoot));
730
+ ctx.slots.inject("shell.leading", () => ctx.slots.register({
731
+ name: "shell.leading",
732
+ locale: NS,
733
+ inject: injectProps
734
+ }, HeaderLeadingControls));
735
+ syncPanels();
736
+ }
737
+ exports2.apply = apply2;
738
+ exports2.inject = inject2;
739
+ return module3.exports;
740
+ })(require);
741
+ }
742
+ });
743
+
744
+ // src/client.jsx
745
+ var client_exports = {};
746
+ __export(client_exports, {
747
+ apply: () => apply,
748
+ inject: () => inject
749
+ });
750
+ module.exports = __toCommonJS(client_exports);
751
+ var import_react = require("react");
752
+ var import_react_dom = require("react-dom");
753
+ var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
754
+ var import_native_sidebar = __toESM(require_native_sidebar(), 1);
755
+
756
+ // src/groups.js
757
+ var STORAGE_KEY = "dsh-finder:groups:v1";
758
+ var empty = () => ({ version: 1, groups: [] });
759
+ function normalizeState(value) {
760
+ if (value?.version !== 1 || !Array.isArray(value.groups)) return empty();
761
+ const groups = [];
762
+ const ids = /* @__PURE__ */ new Set();
763
+ const entries = /* @__PURE__ */ new Set(["plugins"]);
764
+ for (const group of value.groups) {
765
+ if (!group || typeof group.id !== "string" || !group.id || ids.has(group.id) || typeof group.name !== "string" || !group.name.trim()) continue;
766
+ ids.add(group.id);
767
+ groups.push({
768
+ id: group.id,
769
+ name: group.name.trim().slice(0, 60),
770
+ collapsed: group.collapsed !== false,
771
+ entries: (Array.isArray(group.entries) ? group.entries : []).filter((id) => {
772
+ if (typeof id !== "string" || !id || entries.has(id)) return false;
773
+ entries.add(id);
774
+ return true;
775
+ })
776
+ });
777
+ }
778
+ return { version: 1, groups };
779
+ }
780
+ function assignEntry(state, entryId, groupId) {
781
+ if (entryId === "plugins" || groupId && !state.groups.some((group) => group.id === groupId)) return state;
782
+ return { ...state, groups: state.groups.map((group) => ({
783
+ ...group,
784
+ entries: group.id === groupId ? [...group.entries.filter((id) => id !== entryId), entryId] : group.entries.filter((id) => id !== entryId)
785
+ })) };
786
+ }
787
+ function createGroupStore(storage, events) {
788
+ const listeners = /* @__PURE__ */ new Set();
789
+ let state = empty();
790
+ let warning = "";
791
+ function load(raw) {
792
+ try {
793
+ state = raw === null ? empty() : normalizeState(JSON.parse(raw));
794
+ } catch {
795
+ state = empty();
796
+ warning = "\u5206\u7EC4\u914D\u7F6E\u65E0\u6CD5\u8BFB\u53D6\uFF0C\u5F53\u524D\u663E\u793A\u672A\u5206\u7EC4\u5165\u53E3\u3002";
797
+ }
798
+ }
799
+ try {
800
+ load(storage.getItem(STORAGE_KEY));
801
+ } catch {
802
+ warning = "\u672C\u5730\u5B58\u50A8\u4E0D\u53EF\u7528\uFF0C\u5206\u7EC4\u4EC5\u5728\u5F53\u524D\u9875\u9762\u4FDD\u7559\u3002";
803
+ }
804
+ let snapshot = { state, warning };
805
+ function publish() {
806
+ snapshot = { state, warning };
807
+ for (const listener of listeners) listener();
808
+ }
809
+ const onStorage = (event) => {
810
+ if ((event.key === STORAGE_KEY || event.key === null) && (!event.storageArea || event.storageArea === storage)) {
811
+ warning = "";
812
+ load(event.key === null ? null : event.newValue);
813
+ publish();
814
+ }
815
+ };
816
+ events?.addEventListener("storage", onStorage);
817
+ return {
818
+ getSnapshot: () => snapshot,
819
+ subscribe(listener) {
820
+ listeners.add(listener);
821
+ return () => listeners.delete(listener);
822
+ },
823
+ update(change) {
824
+ state = normalizeState(change(state));
825
+ try {
826
+ storage.setItem(STORAGE_KEY, JSON.stringify(state));
827
+ warning = "";
828
+ } catch {
829
+ warning = "\u4FDD\u5B58\u5931\u8D25\uFF1A\u5206\u7EC4\u4EC5\u5728\u5F53\u524D\u9875\u9762\u4FDD\u7559\uFF0C\u5237\u65B0\u540E\u53EF\u80FD\u4E22\u5931\u3002";
830
+ }
831
+ publish();
832
+ },
833
+ dispose() {
834
+ events?.removeEventListener("storage", onStorage);
835
+ listeners.clear();
836
+ }
837
+ };
838
+ }
839
+
840
+ // src/style.css
841
+ var style_default = ".df-navigation{flex:0 1 auto;min-height:36px;max-height:45%;overflow:auto;color:var(--dsw-alias-label-primary);font:inherit}.df-navigation nav{display:flex;flex-direction:column;gap:2px;padding-bottom:6px}.df-row{display:flex;align-items:center;gap:var(--dsh-sidebar-label-gap,6px);width:100%;min-height:32px;box-sizing:border-box;border:3px solid transparent;border-block-width:0;border-radius:8px;padding:6px 9px;background:transparent;background-clip:padding-box;color:inherit;cursor:pointer;text-align:left;font:inherit;font-size:14px}.df-row:hover{background-color:var(--dsw-alias-interactive-bg-hover,rgba(128,128,128,.12))}.df-row:focus-visible,.df-dialog :focus-visible{outline:2px solid var(--dsw-alias-brand-primary,#4d6bfe);outline-offset:-2px}.df-row.df-active{background-color:var(--dsw-alias-interactive-bg-active,rgba(128,128,128,.18));font-weight:600}.df-label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.df-count,.df-chevron{color:var(--dsw-alias-label-tertiary,#888);font-size:12px}.df-children{margin:2px 0 4px 16px;border-left:1px solid var(--dsw-alias-border-l2,#8884);padding-left:3px}.df-children[hidden]{display:none}.df-glyph,.df-row>svg{display:inline-flex;flex-shrink:0;width:16px;height:16px}.df-manage{color:var(--dsw-alias-label-secondary,#888)}.df-rail .df-row{justify-content:center;padding-inline:4px}.df-hint{font-size:12px;line-height:1.6;color:var(--dsw-alias-label-secondary,#777)}.df-children .df-hint{padding-left:10px}.df-warning{font-size:12px;line-height:1.5;color:var(--dsw-alias-warning-primary,#bc6500);padding:0 8px}.df-sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}.df-dialog{box-sizing:border-box;width:min(560px,calc(100vw - 32px));max-height:85dvh;overflow:auto;border:1px solid var(--dsw-alias-border-l2,#8884);border-radius:16px;padding:24px;background:var(--dsw-alias-bg-base,#fff);color:var(--dsw-alias-label-primary,#222);box-shadow:0 12px 60px #0003;font:14px/1.5 system-ui,sans-serif}.df-dialog::backdrop{background:#0006}.df-dialog header{display:flex;justify-content:space-between;gap:16px}.df-dialog h2{margin:0;font-size:18px}.df-dialog header p{margin:6px 0 16px;color:var(--dsw-alias-label-secondary,#777)}.df-dialog h3{font-size:13px;margin:20px 0 10px}.df-dialog button,.df-dialog input,.df-dialog select{box-sizing:border-box;min-height:34px;border:1px solid var(--dsw-alias-border-l2,#8885);border-radius:7px;padding:6px 10px;background:transparent;color:inherit;font:inherit}.df-dialog button{cursor:pointer;white-space:nowrap}.df-dialog button:hover:enabled{background:var(--dsw-alias-interactive-bg-hover,#8882)}.df-dialog button:disabled{opacity:.4;cursor:default}.df-dialog input{min-width:0}.df-dialog input:invalid{box-shadow:none}.df-dialog select option{background:var(--dsw-alias-bg-base,#fff);color:var(--dsw-alias-label-primary,#222)}.df-create label{display:block;margin-bottom:6px;font-weight:600}.df-create>div,.df-group-editor{display:flex;gap:8px}.df-create input,.df-group-editor input{flex:1;width:0}.df-group-editor{margin-bottom:8px}.df-assignment{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:8px 0;border-bottom:1px solid var(--dsw-alias-border-l2,#8883)}.df-assignment>span{min-width:0;overflow-wrap:anywhere}.df-assignment select{flex:0 0 45%;min-width:0;max-width:60%}@media(max-width:460px){.df-dialog{padding:16px}.df-group-editor{flex-wrap:wrap}.df-group-editor input{flex-basis:100%;width:100%}}\n";
842
+
843
+ // src/client.jsx
844
+ var import_jsx_runtime = require("react/jsx-runtime");
845
+ var inject = import_native_sidebar.default.inject;
846
+ function FolderIcon({ size = 16, open = false }) {
847
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.6", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: open ? "M3 9V6a2 2 0 0 1 2-2h5l2 3h7a2 2 0 0 1 2 2M3 9h18l-3 11H5L3 9Z" : "M3 7a2 2 0 0 1 2-2h5l2 3h7a2 2 0 0 1 2 2v9H3V7Z" }) });
848
+ }
849
+ function GroupEditor({ group, store }) {
850
+ const [name, setName] = (0, import_react.useState)(group.name);
851
+ (0, import_react.useEffect)(() => setName(group.name), [group.name]);
852
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("form", { className: "df-group-editor", onSubmit: (event) => {
853
+ event.preventDefault();
854
+ if (name.trim()) store.update((state) => ({ ...state, groups: state.groups.map((item) => item.id === group.id ? { ...item, name: name.trim() } : item) }));
855
+ }, children: [
856
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { "aria-label": `\u5206\u7EC4\u540D\u79F0\uFF1A${group.name}`, value: name, maxLength: 60, required: true, onChange: (event) => setName(event.target.value) }),
857
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "submit", disabled: !name.trim() || name.trim() === group.name, children: "\u91CD\u547D\u540D" }),
858
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", onClick: () => store.update((state) => ({ ...state, groups: state.groups.filter((item) => item.id !== group.id) })), children: [
859
+ "\u5220\u9664\u5206\u7EC4 ",
860
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "df-sr", children: group.name })
861
+ ] })
862
+ ] });
863
+ }
864
+ function GroupManager({ panels, store, snapshot, onClose }) {
865
+ const dialog = (0, import_react.useRef)(null);
866
+ const heading = (0, import_react.useId)();
867
+ const [name, setName] = (0, import_react.useState)("");
868
+ const { state, warning } = snapshot;
869
+ (0, import_dsh_client_ui_primitives.useModalLayer)(dialog, true, () => dialog.current?.close());
870
+ (0, import_react.useEffect)(() => {
871
+ dialog.current.showModal();
872
+ }, []);
873
+ const membership = new Map(state.groups.flatMap((group) => group.entries.map((id) => [id, group.id])));
874
+ const known = new Set(panels.map((panel) => panel.id));
875
+ const missing = [...membership.keys()].filter((id) => !known.has(id)).map((id) => ({ id, label: `${id}\uFF08\u672A\u52A0\u8F7D\uFF09` }));
876
+ return (0, import_react_dom.createPortal)(/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("dialog", { ref: dialog, className: "df-dialog", role: "dialog", "aria-modal": "true", "data-shortcut-modal": "dsh-finder-groups", "aria-labelledby": heading, onClose, onClick: (event) => {
877
+ if (event.target === event.currentTarget) dialog.current.close();
878
+ }, children: [
879
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("header", { children: [
880
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
881
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { id: heading, children: "\u7BA1\u7406\u4FA7\u680F\u5206\u7EC4" }),
882
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: "\u628A\u5DE5\u5177\u5165\u53E3\u6536\u8FDB\u6587\u4EF6\u5939\uFF0C\u5E73\u65F6\u6298\u53E0\u8D77\u6765\u3002" })
883
+ ] }),
884
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", "aria-label": "\u5173\u95ED\u5206\u7EC4\u7BA1\u7406", onClick: () => dialog.current.close(), children: "\xD7" })
885
+ ] }),
886
+ warning && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { role: "alert", className: "df-warning", children: warning }),
887
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("form", { className: "df-create", onSubmit: (event) => {
888
+ event.preventDefault();
889
+ if (!name.trim()) return;
890
+ store.update((value) => ({ ...value, groups: [...value.groups, { id: crypto.randomUUID(), name: name.trim(), collapsed: true, entries: [] }] }));
891
+ setName("");
892
+ }, children: [
893
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { htmlFor: `${heading}-new`, children: "\u65B0\u5EFA\u5206\u7EC4" }),
894
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
895
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { autoFocus: true, "data-modal-autofocus": true, id: `${heading}-new`, placeholder: "\u4F8B\u5982\uFF1A\u6478\u9C7C\u5DE5\u5177", value: name, maxLength: 60, required: true, onChange: (event) => setName(event.target.value) }),
896
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "submit", disabled: !name.trim(), children: "\u521B\u5EFA\u5206\u7EC4" })
897
+ ] })
898
+ ] }),
899
+ state.groups.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { "aria-label": "\u5DF2\u6709\u5206\u7EC4", children: [
900
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { children: "\u5DF2\u6709\u5206\u7EC4" }),
901
+ state.groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GroupEditor, { group, store }, group.id)),
902
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "df-hint", children: "\u5220\u9664\u5206\u7EC4\u53EA\u8FD8\u539F\u4FA7\u680F\u5165\u53E3\uFF0C\u4E0D\u4F1A\u5378\u8F7D\u5DE5\u5177\u3002" })
903
+ ] }),
904
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { "aria-label": "\u5165\u53E3\u5F52\u5C5E", children: [
905
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { children: "\u5165\u53E3\u5F52\u5C5E" }),
906
+ panels.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "df-hint", children: "\u6682\u65E0\u5DF2\u6CE8\u518C\u7684\u9762\u677F\u5165\u53E3\u3002" }),
907
+ [...panels, ...missing].filter((panel) => panel.id !== "plugins").map((panel) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "df-assignment", children: [
908
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { title: panel.id, children: panel.label }),
909
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", { "aria-label": `${panel.label}\u7684\u5206\u7EC4`, value: membership.get(panel.id) ?? "", onChange: (event) => store.update((value) => assignEntry(value, panel.id, event.target.value)), children: [
910
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "", children: "\u4E0D\u5206\u7EC4" }),
911
+ state.groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: group.id, children: group.name }, group.id))
912
+ ] })
913
+ ] }, panel.id)),
914
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "df-hint", children: "\u63D2\u4EF6\u7BA1\u7406\u4FDD\u7559\u5728\u539F\u4F4D\u7F6E\uFF1B\u8FD9\u91CC\u53EA\u7BA1\u7406\u5DE6\u4FA7\u5168\u5C40\u9762\u677F\u5165\u53E3\uFF0C\u4E0D\u5305\u542B\u4F1A\u8BDD\u4E0E\u53F3\u4FA7\u680F\u3002" })
915
+ ] })
916
+ ] }), document.body);
917
+ }
918
+ function GroupNavigation({ panels, props, store, snapshot, managing, setManaging, wide, expandSidebar }) {
919
+ const { state, warning } = snapshot;
920
+ const byId = new Map(panels.map((panel) => [panel.id, panel]));
921
+ const active = props.usePanelInfo((info) => info.activePanelId);
922
+ const root = (0, import_react.useId)();
923
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: `df-navigation${wide ? "" : " df-rail"}`, children: [
924
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("nav", { "aria-label": "\u5DE5\u5177\u5206\u7EC4", children: [
925
+ state.groups.map((group) => {
926
+ const entries = group.entries.map((id) => byId.get(id)).filter(Boolean);
927
+ const selected = entries.some((entry) => entry.id === active);
928
+ const controls = `${root}-${group.id}`;
929
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "df-group", children: [
930
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { className: `df-row df-folder${selected ? " df-active" : ""}`, type: "button", title: group.name, "aria-label": group.name, "aria-expanded": wide && !group.collapsed, "aria-controls": controls, onClick: () => {
931
+ if (!wide) expandSidebar();
932
+ store.update((value) => ({ ...value, groups: value.groups.map((item) => item.id === group.id ? { ...item, collapsed: wide ? !item.collapsed : false } : item) }));
933
+ }, children: [
934
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FolderIcon, { open: wide && !group.collapsed }),
935
+ wide && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
936
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "df-label", children: group.name }),
937
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "df-count", children: entries.length }),
938
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { "aria-hidden": "true", className: "df-chevron", children: group.collapsed ? "\u203A" : "\u2304" })
939
+ ] }),
940
+ selected && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "df-sr", children: "\uFF0C\u5305\u542B\u5F53\u524D\u9762\u677F" })
941
+ ] }),
942
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { id: controls, hidden: !wide || group.collapsed, className: "df-children", children: [
943
+ entries.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "df-hint", children: "\u6682\u65E0\u5DF2\u52A0\u8F7D\u5165\u53E3" }),
944
+ entries.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", className: `df-row${entry.id === active ? " df-active" : ""}`, "aria-current": entry.id === active ? "page" : void 0, title: entry.label, onClick: () => props.selectPanel(entry.id), children: [
945
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "df-glyph", "aria-hidden": "true", children: props.renderSlot("sidebar.panellist", { size: 16, active: entry.id === active }, { only: entry.id }) }),
946
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "df-label", children: entry.label })
947
+ ] }, entry.id))
948
+ ] })
949
+ ] }, group.id);
950
+ }),
951
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", className: "df-row df-manage", title: "\u7BA1\u7406\u4FA7\u680F\u5206\u7EC4", "aria-label": "\u7BA1\u7406\u4FA7\u680F\u5206\u7EC4", "aria-haspopup": "dialog", onClick: () => setManaging(true), children: [
952
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FolderIcon, {}),
953
+ wide && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "df-label", children: "\u7BA1\u7406\u5206\u7EC4" })
954
+ ] })
955
+ ] }),
956
+ wide && warning && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "df-warning", role: "alert", children: warning }),
957
+ managing && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GroupManager, { panels, store, snapshot, onClose: () => setManaging(false) })
958
+ ] });
959
+ }
960
+ function composeSidebar(NativeSidebar, store) {
961
+ return function FinderSidebar(props) {
962
+ const snapshot = (0, import_react.useSyncExternalStore)(store.subscribe, store.getSnapshot);
963
+ const panels = props.usePanels((value) => value);
964
+ const [managing, setManaging] = (0, import_react.useState)(false);
965
+ const grouped = new Set(snapshot.state.groups.flatMap((group) => group.entries));
966
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
967
+ NativeSidebar,
968
+ {
969
+ ...props,
970
+ usePanels: (selector) => props.usePanels((value) => selector(value.filter((panel) => !grouped.has(panel.id)))),
971
+ renderSlot: (slot, owner, options) => slot === "sidebar.workspaces" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
972
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GroupNavigation, { panels, props, store, snapshot, managing, setManaging, wide: owner.wide, expandSidebar: owner.expandSidebar }),
973
+ props.renderSlot(slot, owner, options)
974
+ ] }) : props.renderSlot(slot, owner, options)
975
+ }
976
+ );
977
+ };
978
+ }
979
+ function apply(ctx) {
980
+ let storage;
981
+ try {
982
+ storage = window.localStorage;
983
+ } catch {
984
+ storage = { getItem() {
985
+ throw new Error("Storage unavailable");
986
+ }, setItem() {
987
+ throw new Error("Storage unavailable");
988
+ } };
989
+ }
990
+ const store = createGroupStore(storage, window);
991
+ ctx.effect(() => () => store.dispose());
992
+ ctx.effect(() => {
993
+ const style = document.createElement("style");
994
+ style.dataset.plugin = "dsh-panel-folders";
995
+ style.textContent = style_default;
996
+ document.head.appendChild(style);
997
+ return () => style.remove();
998
+ });
999
+ const slots = new Proxy(ctx.slots, {
1000
+ get(target, key) {
1001
+ if (key === "register") return (options, Component) => target.register(options, options.name === "sidebar" ? composeSidebar(Component, store) : Component);
1002
+ const value = Reflect.get(target, key);
1003
+ return typeof value === "function" ? value.bind(target) : value;
1004
+ }
1005
+ });
1006
+ return import_native_sidebar.default.apply(new Proxy(ctx, { get(target, key) {
1007
+ return key === "slots" ? slots : Reflect.get(target, key);
1008
+ } }));
1009
+ }
1010
+
1011
+ return module.exports;}});
package/package.json CHANGED
@@ -1,6 +1,45 @@
1
1
  {
2
2
  "name": "dsh-panel-folders",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.1",
4
+ "repository": { "type": "git", "url": "git+https://github.com/FrankieeW/dsh-finder.git" },
5
+ "homepage": "https://github.com/FrankieeW/dsh-finder#readme",
6
+ "bugs": { "url": "https://github.com/FrankieeW/dsh-finder/issues" },
7
+ "description": "Collapsible groups for DeepSeek Harness sidebar launchers",
8
+ "type": "module",
9
+ "main": "./src/index.js",
10
+ "exports": {
11
+ ".": "./src/index.js",
12
+ "./client": "./lib/client.js",
13
+ "./package.json": "./package.json"
14
+ },
15
+ "files": ["src/index.js", "lib", "cordis.patch.yml", "README.md", "THIRD_PARTY_NOTICES.md"],
16
+ "engines": { "node": ">=24.9.0", "dsh": "0.2.2-rc.1" },
17
+ "scripts": {
18
+ "build": "node scripts/build.mjs",
19
+ "test": "node --test test/*.test.js",
20
+ "prepack": "npm run build"
21
+ },
22
+ "dsh": {
23
+ "manifestVersion": 1,
24
+ "bundle": { "patch": "./cordis.patch.yml" },
25
+ "client": {
26
+ "platform": "web",
27
+ "inject": [
28
+ "@deepseek-ai/dsh-api-workspace-controller",
29
+ "@deepseek-ai/dsh-client-ui-renderer",
30
+ "@deepseek-ai/dsh-client-ui-layout",
31
+ "@deepseek-ai/dsh-client-ui-session",
32
+ "@deepseek-ai/dsh-client-ui-workspace",
33
+ "@deepseek-ai/dsh-client-locale",
34
+ "@deepseek-ai/dsh-client-shortcuts"
35
+ ]
36
+ }
37
+ },
38
+ "peerDependencies": { "@deepseek-ai/cordis": "~4.1.0" },
39
+ "devDependencies": {
40
+ "@deepseek-ai/dsh-client-ui-sidebar": "0.2.2-rc.1",
41
+ "esbuild": "^0.25.0",
42
+ "react": "18.3.1",
43
+ "react-dom": "18.3.1"
44
+ }
45
+ }
package/src/index.js ADDED
@@ -0,0 +1,2 @@
1
+ // All sidebar behavior runs in the DSH client.
2
+ export function apply() {}