@michengai/dsh-archive-manager 0.1.37 → 0.1.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,16 @@
4
4
 
5
5
  Published release notes are retained below; new versions are added without removing earlier entries.
6
6
 
7
+ ## 0.1.39 - 2026-09-11
8
+
9
+ - Preserve the Codex UI workspace list, styling, and dedicated interactions when both plugins are installed, while keeping archive management available.
10
+ - Delegate the home workspace picker and session navigation to the official DSH plugin while retaining the custom archive sidebar, directory creation, restore, and batch management, reducing navigation API drift across host upgrades.
11
+ - Isolate sidebar directory synchronization failures so they do not interrupt other plugins registering directory components. If your Profile manually disables the official `ui-workspace`, remove that override before upgrading; otherwise the archive sidebar and settings page cannot load.
12
+
13
+ ## 0.1.38 - 2026-09-11
14
+
15
+ - Support DeepSeek Harness `0.1.5-rc.2` while retaining compatibility with the four previously supported versions.
16
+
7
17
  ## 0.1.37 - 2026-09-10
8
18
 
9
19
  - Fix rebuilt archive summaries remaining unusable on DSH `0.1.5-rc.1`; caches with missing or outdated format versions are rebuilt from the session transcript and reused on subsequent visits.
@@ -4,6 +4,16 @@
4
4
 
5
5
  以下发布说明会持续保留;新增版本时不再删除较早记录。
6
6
 
7
+ ## 0.1.39 - 2026-09-11
8
+
9
+ - 修复与 Codex UI 共存时抢占其工作区列表的问题,保留 Codex UI 的列表样式和专属交互,同时提供归档管理入口。
10
+ - 首页工作区选择与会话导航改由 DSH 官方插件提供;保留自定义归档侧栏、目录添加、恢复和批量管理,减少宿主升级时导航接口不同步的问题。
11
+ - 隔离侧栏目录同步异常,避免影响其他插件注册目录组件。若 Profile 曾手工禁用官方 `ui-workspace`,升级前请移除该覆盖,否则归档侧栏与设置页无法加载。
12
+
13
+ ## 0.1.38 - 2026-09-11
14
+
15
+ - 支持 DeepSeek Harness `0.1.5-rc.2`,保留此前四个已支持版本的兼容路径。
16
+
7
17
  ## 0.1.37 - 2026-09-10
8
18
 
9
19
  - 修复 DSH `0.1.5-rc.1` 中归档摘要重建后缓存仍不可用的问题;缺失版本或旧代际缓存会从会话原文重建,后续访问复用有效缓存。
package/README.md CHANGED
@@ -55,21 +55,21 @@ For a ready-to-use workbench, download [DSH Codex Desktop](https://github.com/Mi
55
55
 
56
56
  ## Prerequisites
57
57
 
58
- - The current source supports DeepSeek Harness `0.1.5-rc.1` and the legacy hosts below. These changes were published in plugin `0.1.35`. Later versions require separate validation.
58
+ - Plugin `0.1.38` supports DeepSeek Harness `0.1.5-rc.2` and retains the four previously supported hosts below. Later versions require separate validation.
59
59
 
60
60
  - A working DeepSeek Harness Web installation with `dsh` available in PowerShell.
61
61
  - Examples use the `web` profile; replace it with the target profile.
62
62
  - Source installation and development require Node.js 22+ and pnpm. npm installation does not require running `pnpm install` separately.
63
63
 
64
- DSH peer dependencies accept only `0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1`; other RCs and stable versions are not automatically accepted. Development dependencies remain pinned to `0.1.5-rc.1`.
64
+ DSH peer dependencies accept only `0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2`; other RCs and stable versions are not automatically accepted. Development dependencies are pinned to `0.1.5-rc.2`.
65
65
 
66
66
  ## Installation
67
67
 
68
68
  Run `pnpm test:compat` to test the same plugin artifacts with isolated host dependencies. The following combinations have passed; this does not claim coverage of every intermediate release:
69
69
 
70
70
  - `pnpm test`: build and run local tests, excluding `test/fixtures`; local host links may affect dependency resolution.
71
- - `pnpm test:matrix`: build, then install four isolated host versions and run the full matrix.
72
- - `pnpm test:latest`: build, then run the six real storage tests against the isolated latest baseline.
71
+ - `pnpm test:matrix`: build, then install five isolated host versions and run the full matrix.
72
+ - `pnpm test:latest`: build, then run the real storage regressions against the isolated latest baseline.
73
73
  - `pnpm test:compat`: validate legacy cache migration and run the full matrix.
74
74
 
75
75
  Do not run `test/fixtures/*.mjs` directly. Fixtures validate the isolated entry point, dependency versions, and resolved paths before loading the host. If local dependencies have drifted, run `pnpm install --frozen-lockfile` to restore declared development dependencies. This does not guarantee removal of undeclared packages or host links under `test/node_modules`; use the isolated commands for compatibility acceptance.
@@ -79,9 +79,10 @@ Do not run `test/fixtures/*.mjs` directly. Fixtures validate the isolated entry
79
79
  | `0.1.0-rc.8` | `4.0.1` | 153 passed |
80
80
  | `0.1.1-rc.2` | `4.0.1` | 153 passed, plus legacy cache migration validation |
81
81
  | `0.1.2-rc.1` | `4.0.2` | 153 passed |
82
- | `0.1.5-rc.1` | `4.0.2` | 156 passed |
82
+ | `0.1.5-rc.1` | `4.0.2` | 162 passed |
83
+ | `0.1.5-rc.2` | `4.0.2` | 162 passed |
83
84
 
84
- Coverage includes workspace navigation, global-panel dismissal, cancellation of stale navigation, sidebar wiring, peer version acceptance, client Remote integration, archive/restore, real JSONL/Zstandard deletion and subagent cascades, and queries/reopened storage after deletion. Tested on Windows / Node.js 24. A real browser acceptance run also passed in an isolated DSH 0.1.5-rc.1 Web Profile: package installation, archive/restore, deletion cancellation and confirmation, subagent cascades, cross-filter batch deletion, workspace selection, returning from global panels, new sessions and forks, content search, and restart persistence. Content search requires an open host query database; it passed after changing the isolated Profile from `openAt: never` to `startup`. The other three versions have isolated automated coverage only; no external model calls were made. The latest storage fixture isolates only the upstream POSIX `fs-ext` import that cannot load on Windows; file operations and native Windows locking still use the official implementation.
85
+ Coverage includes official workspace composition, sidebar shadowing and restoration on unload, directory-slot lifecycles, sidebar wiring, peer version acceptance, client Remote integration, archive/restore, real JSONL/Zstandard deletion and subagent cascades, and queries/reopened storage after deletion. Tested on Windows / Node.js 24. A real browser acceptance run also passed in an isolated DSH 0.1.5-rc.1 Web Profile: package installation, archive/restore, deletion cancellation and confirmation, subagent cascades, cross-filter batch deletion, workspace selection, returning from global panels, new sessions and forks, content search, and restart persistence. Content search requires an open host query database; it passed after changing the isolated Profile from `openAt: never` to `startup`. This release also passed an isolated rc.2 Web smoke run covering settings loading, seeded archive listing, restore, deletion cancellation and confirmation, and restart persistence with dedicated JSONL data. The full rc.1 browser flow was not repeated item by item. The other three versions have isolated automated coverage only; no external model calls were made. The latest storage fixture isolates only the upstream POSIX `fs-ext` import that cannot load on Windows; file operations and native Windows locking still use the official implementation.
85
86
 
86
87
  The installation commands below use the official npm registry.
87
88
 
@@ -106,7 +107,17 @@ dsh --profile web --dump-config
106
107
 
107
108
  To pin a release, replace `@latest` with a specific version such as `@x.y.z`.
108
109
 
109
- The configuration output should contain `workspace-archive-manager` and `ui-workspace-archive-manager`. Restart DSH Web and hard-refresh the browser. Do not copy client files manually: the Settings page and archive menu need the mounted plugin.
110
+ The configuration output should contain `workspace-archive-manager` and `ui-workspace-archive-manager`, with the official `ui-workspace` still enabled. Restart DSH Web and hard-refresh the browser. Do not copy client files manually: the Settings page and archive menu need the mounted plugin.
111
+
112
+ ### Upgrade checks for existing installations
113
+
114
+ Upgrades reload the patch bundled with the plugin; the old bundle needs no manual migration. However, the Profile's own `cordis.patch.yml` is applied after bundles. If it manually sets `ui-workspace` to `disabled: true`, remove that override or change it to `disabled: false`, preserving other configuration.
115
+
116
+ Run `dsh --profile web --dump-config`, confirm that the official `ui-workspace` is enabled, then restart DSH Web and hard-refresh the browser. On supported DSH versions from 0.1.2 onward, disabling that service leaves the archive client waiting for `uiWorkspace`; neither its sidebar nor its archive settings page mounts, which can look unresponsive.
117
+
118
+ Sidebar directory creation depends on the official `sidebar.workspaces.directoryFlow` slot. If the source slot is absent or has no directory component, the entry is hidden without logging a synchronization error; use the official home entry instead. Directory extensions declaring additional child slots cannot be mirrored and produce a warning.
119
+
120
+ A dynamic synchronization failure after mounting logs the source slot, target slot, and component origin when available, attempts to clear existing mirrors, and keeps listening to retry on a subsequent source-slot change. Removing a conflicting entry from the target slot alone does not trigger a retry. An initial synchronization failure instead unsubscribes, attempts cleanup, and rethrows to the mounting caller. After resolving the conflict, remount the archive client, for example by restarting DSH Web and hard-refreshing the browser. If releasing an entry fails during cleanup, that error is logged separately and cleanup continues for the remaining entries.
110
121
 
111
122
  ## Updates
112
123
 
@@ -131,7 +142,9 @@ If the entry is missing after installation or upgrade, restart DSH Web and hard-
131
142
  - Layout validation uses the official backend's initialized absolute root, so a relative root remains stable across host working-directory changes. If that field is unavailable, only an absolute configured root is accepted. An unverified official JSONL layout emits a warning with the session ID and artifact path before falling back to artifact-only deletion.
132
143
  - Directory validation is not a cross-process filesystem lock: do not concurrently move or replace storage directories or change directory links during deletion. Storage paths writable by untrusted processes are not a security isolation boundary.
133
144
  - A live session finishes writing before cleanup to prevent data truncation.
134
- - The plugin replaces DSH’s default workspace and projection services. Install through the DSH profile instead of manually composing the patch.
145
+ - The official `ui-workspace` remains enabled, so the home picker and navigation follow the host. The archive sidebar uses priority `-0.5`, ahead of the official default but behind Codex UI 1.1.2 at `-1`. Codex UI retains its list, styling, and interactions; archive management remains available in settings. Unloading Codex UI restores the archive sidebar; unloading the archive frontend restores the official sidebar. Backend workspace and projection services still use the archive implementations.
146
+ - The sidebar directory entry reuses official leaf components through a separate child slot and follows their registration lifetimes. It does not redeclare official directory slots. Custom directory extensions with additional child slots should use the official home entry; this adapter does not transfer their child-slot permissions.
147
+ - Install through the DSH profile instead of manually composing the patch.
135
148
 
136
149
  ## Secondary development
137
150
 
package/README.zh-CN.md CHANGED
@@ -55,21 +55,21 @@
55
55
 
56
56
  ## 前置条件
57
57
 
58
- - 当前源码已适配 DeepSeek Harness `0.1.5-rc.1`,并保留下表中的旧版兼容路径;已随插件 `0.1.35` 发布到 npm。后续版本需另行验证。
58
+ - 插件 `0.1.38` 支持 DeepSeek Harness `0.1.5-rc.2`,并保留下表中此前四个宿主版本的兼容路径。后续版本需另行验证。
59
59
 
60
60
  - 已可正常运行 DeepSeek Harness Web,且可在 PowerShell 中使用 `dsh`。
61
61
  - 以下示例使用 `web` profile;请替换为实际目标 profile。
62
62
  - 从源码安装或二次开发需要 Node.js 22+ 与 pnpm;仅从 npm 安装无需另外执行 `pnpm install`。
63
63
 
64
- DSH peer 依赖仅接受 `0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1`;不自动接纳其他 RC 或正式版。开发依赖仍固定为 `0.1.5-rc.1`。
64
+ DSH peer 依赖仅接受 `0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2`;不自动接纳其他 RC 或正式版。开发依赖固定为 `0.1.5-rc.2`。
65
65
 
66
66
  ## 安装
67
67
 
68
68
  源码回归使用 `pnpm test:compat`,在隔离依赖环境中运行同一份插件产物,已验证以下组合(不代表覆盖所有中间版本):
69
69
 
70
70
  - `pnpm test`:构建并执行本地常规测试,不包含 `test/fixtures`;实际依赖可能受本机宿主链接影响。
71
- - `pnpm test:matrix`:先构建,再隔离安装四个宿主版本,执行完整矩阵。
72
- - `pnpm test:latest`:先构建,再隔离运行最新版的 6 项真实存储回归。
71
+ - `pnpm test:matrix`:先构建,再隔离安装五个宿主版本,执行完整矩阵。
72
+ - `pnpm test:latest`:先构建,再隔离运行最新版的 真实存储回归。
73
73
  - `pnpm test:compat`:旧缓存迁移验证加完整矩阵。
74
74
 
75
75
  不要直接执行 `test/fixtures/*.mjs`;夹具会在加载宿主前检查隔离入口、依赖版本及实际路径。若本机依赖脱节,可先执行 `pnpm install --frozen-lockfile` 恢复声明的开发依赖;它不保证清理未声明包或 `test/node_modules` 的宿主链接,兼容性验收以隔离命令为准。
@@ -79,9 +79,10 @@ DSH peer 依赖仅接受 `0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1`
79
79
  | `0.1.0-rc.8` | `4.0.1` | 153 项通过 |
80
80
  | `0.1.1-rc.2` | `4.0.1` | 153 项通过,另含旧缓存迁移验证 |
81
81
  | `0.1.2-rc.1` | `4.0.2` | 153 项通过 |
82
- | `0.1.5-rc.1` | `4.0.2` | 156 项通过 |
82
+ | `0.1.5-rc.1` | `4.0.2` | 162 项通过 |
83
+ | `0.1.5-rc.2` | `4.0.2` | 162 项通过 |
83
84
 
84
- 覆盖新版工作区导航、全局面板退出、异步导航取消、侧栏接线、peer 版本接纳、客户端 Remote、归档/恢复、真实 JSONL/Zstandard 删除与子会话级联、删除后重新查询及重新打开存储。验证环境为 Windows / Node.js 24。另已在隔离 DSH 0.1.5-rc.1 Web Profile 中完成真实浏览器验收:包安装、归档恢复、取消与确认删除、子会话级联、跨筛选批量删除、工作区选择、全局面板返回会话、新建与分叉、正文搜索和重启持久性均通过。正文搜索需开启宿主查询数据库;本次将隔离 Profile 的 `openAt: never` 改为 `startup` 后验证通过。其余三个版本仅完成隔离自动测试,未逐版执行浏览器验收;未调用外部模型。新版存储夹具仅隔离上游无法在 Windows 加载的 POSIX `fs-ext` 导入,实际文件操作与 Windows 原生锁仍使用官方实现。
85
+ 覆盖官方工作区插件组合、侧栏覆盖及卸载恢复、目录插槽生命周期、侧栏接线、peer 版本接纳、客户端 Remote、归档/恢复、真实 JSONL/Zstandard 删除与子会话级联、删除后重新查询及重新打开存储。验证环境为 Windows / Node.js 24。另已在隔离 DSH 0.1.5-rc.1 Web Profile 中完成真实浏览器验收:包安装、归档恢复、取消与确认删除、子会话级联、跨筛选批量删除、工作区选择、全局面板返回会话、新建与分叉、正文搜索和重启持久性均通过。正文搜索需开启宿主查询数据库;本次将隔离 Profile 的 `openAt: never` 改为 `startup` 后验证通过。本轮另在隔离 rc.2 Web Profile 完成设置页加载、预置归档记录展示、恢复、取消与确认删除及重启持久性冒烟验收;使用独立 JSONL 测试数据,未逐项重跑 rc.1 的完整浏览器流程。其余三个版本仅完成隔离自动测试;未调用外部模型。新版存储夹具仅隔离上游无法在 Windows 加载的 POSIX `fs-ext` 导入,实际文件操作与 Windows 原生锁仍使用官方实现。
85
86
 
86
87
  以下安装命令使用官方 npm 源。
87
88
 
@@ -106,7 +107,17 @@ dsh --profile web --dump-config
106
107
 
107
108
  需要钉死某一版时,把 `@latest` 换成具体版本,例如 `@x.y.z`。
108
109
 
109
- 配置输出中应包含 `workspace-archive-manager` 与 `ui-workspace-archive-manager`。安装后重启 DSH Web 并在浏览器硬刷新;请勿手工复制客户端文件,否则设置页和归档菜单不会被挂载。
110
+ 配置输出中应包含 `workspace-archive-manager` 与 `ui-workspace-archive-manager`,同时官方 `ui-workspace` 保持启用。安装后重启 DSH Web 并在浏览器硬刷新;请勿手工复制客户端文件,否则设置页和归档菜单不会被挂载。
111
+
112
+ ### 已安装环境升级检查
113
+
114
+ 升级会重新读取插件包内的补丁,无需手工迁移旧 bundle。但 Profile 自己的 `cordis.patch.yml` 在 bundle 之后应用:若曾手工将 `ui-workspace` 设为 `disabled: true`,请移除该覆盖或改为 `disabled: false`,保留其余配置。
115
+
116
+ 运行 `dsh --profile web --dump-config`,确认官方 `ui-workspace` 已启用,再重启 DSH Web 并硬刷新浏览器。在 DSH 0.1.2 及以上受支持版本中,禁用官方服务会让归档客户端等待 `uiWorkspace`,侧栏与归档设置页都不会挂载,可能表现为没有响应。
117
+
118
+ 侧栏添加目录依赖官方 `sidebar.workspaces.directoryFlow` 插槽。源槽不存在或没有目录组件时,该入口会隐藏,不会因此记录同步错误;可使用官方首页入口。带额外子插槽的目录扩展暂不支持镜像,会输出警告。
119
+
120
+ 挂载后的动态同步异常会记录源槽、目标槽及可用的组件来源,并尝试清理已有镜像,保留监听以在后续源槽变化时重试。仅移除目标槽的冲突条目不会触发重试。首次挂载时同步失败则会取消监听、尝试清理并向挂载调用方抛出错误;排除冲突后需重新挂载归档客户端,例如重启 DSH Web 并硬刷新浏览器。清理过程中若有条目释放失败,会另行记录错误并继续清理其余条目。
110
121
 
111
122
  ## 在线更新
112
123
 
@@ -131,7 +142,9 @@ dsh --profile web --dump-config
131
142
  - 布局校验优先使用官方后端初始化时确定的绝对根路径,相对路径配置不再受宿主工作目录变化影响;若无法取得该字段,则只接受绝对路径配置。官方 JSONL 布局校验失败时,会记录包含会话 ID 和工件路径的警告,再降级为仅删除工件。
132
143
  - 目录校验不是跨进程文件锁:删除期间不要由其他进程迁移、替换存储目录或改写目录链接。插件不将可被不可信进程改写的存储路径视为安全隔离边界。
133
144
  - 正在写入的会话会在完成写入后清理,避免截断数据。
134
- - 本插件替换 DSH 默认的工作区和会话投影服务;请仅通过 DSH profile 安装,避免手工拼接补丁配置。
145
+ - 本插件保留官方 `ui-workspace`,首页工作区选择器与导航服务跟随宿主;以优先级 `-0.5` 覆盖官方默认侧栏;与 Codex UI 1.1.2 共存时保留其优先级 `-1` 的列表、样式与交互,归档管理仍在设置页提供。卸载 Codex UI 后恢复归档侧栏;卸载归档前端后恢复官方侧栏。后端工作区和会话投影服务仍由归档实现提供。
146
+ - 侧栏目录入口复用官方目录叶组件,使用独立子插槽,随官方条目加载、卸载同步;不重复声明官方目录插槽。自定义目录扩展若声明额外子插槽,应使用官方首页入口;当前适配不转移其子插槽权限。
147
+ - 请仅通过 DSH profile 安装,避免手工拼接补丁配置。
135
148
 
136
149
  ## 二次开发
137
150
 
package/cordis.patch.yml CHANGED
@@ -1,12 +1,12 @@
1
- # @michengai/dsh-archive-manager 插件补丁:禁用默认服务行,
2
- # 并替换为归档会话管理实现。发布后的安装命令:
1
+ # 保留官方工作区 UI,仅替换归档需要的后端服务。
2
+ # 自定义侧栏通过优先级覆盖插槽;发布后的安装命令:
3
3
  # dsh plugin --profile web add @michengai/dsh-archive-manager
4
4
  - id: workspace
5
5
  disabled: true
6
6
  - id: session-projection-cache
7
7
  disabled: true
8
8
  - id: ui-workspace
9
- disabled: true
9
+ disabled: false
10
10
  - insert:
11
11
  - id: workspace-archive-manager
12
12
  name: '@michengai/dsh-archive-manager/workspace'
package/lib/client.js CHANGED
@@ -1,4 +1,69 @@
1
1
  (() => {
2
+ // src/directory-flow-slot.js
3
+ function mirrorDirectoryFlow(ctx, target) {
4
+ const source = "sidebar.workspaces.directoryFlow";
5
+ return ctx.slots.inject(target, () => ctx.effect(() => {
6
+ const mounted = /* @__PURE__ */ new Map();
7
+ let registrant;
8
+ const release = (entry, dispose) => {
9
+ mounted.delete(entry);
10
+ try {
11
+ dispose();
12
+ } catch (error) {
13
+ console.error(`archive-manager: \u6E05\u7406\u76EE\u5F55\u955C\u50CF\u5931\u8D25 ${source} -> ${target}\uFF08${entry.registrant ?? "\u672A\u77E5\u6765\u6E90"}\uFF09`, error);
14
+ }
15
+ };
16
+ const clearMounted = () => {
17
+ for (const [entry, dispose] of mounted) release(entry, dispose);
18
+ };
19
+ const reconcile = () => {
20
+ registrant = void 0;
21
+ const entries = ctx.slots.entries(source);
22
+ for (const [entry, dispose] of mounted) {
23
+ if (!entries.includes(entry)) {
24
+ release(entry, dispose);
25
+ }
26
+ }
27
+ for (const entry of entries) {
28
+ if (mounted.has(entry)) continue;
29
+ if (Object.keys(entry.children ?? {}).length > 0) {
30
+ console.warn("archive-manager: \u4E0D\u652F\u6301\u5E26\u5B50\u63D2\u69FD\u7684\u76EE\u5F55\u7EC4\u4EF6\uFF0C\u8BF7\u4F7F\u7528\u5B98\u65B9\u9996\u9875\u5165\u53E3");
31
+ continue;
32
+ }
33
+ registrant = entry.registrant;
34
+ mounted.set(entry, ctx.slots.register({
35
+ ...entry.options,
36
+ name: target,
37
+ registrant: entry.registrant,
38
+ inject: entry.inject,
39
+ store: entry.store,
40
+ locale: entry.locale
41
+ }, entry.component));
42
+ }
43
+ };
44
+ const unsubscribe = ctx.on("slots/changed", (key) => {
45
+ if (key !== source) return;
46
+ try {
47
+ reconcile();
48
+ } catch (error) {
49
+ clearMounted();
50
+ console.error(`archive-manager: \u540C\u6B65\u76EE\u5F55\u955C\u50CF\u5931\u8D25 ${source} -> ${target}\uFF08${registrant ?? "\u672A\u77E5\u6765\u6E90"}\uFF09\uFF1B\u8BF7\u4F7F\u7528\u5B98\u65B9\u9996\u9875\u5165\u53E3\uFF0C\u540E\u7EED\u6E90\u63D2\u69FD\u53D8\u5316\u65F6\u91CD\u8BD5`, error);
51
+ }
52
+ });
53
+ try {
54
+ reconcile();
55
+ } catch (error) {
56
+ unsubscribe();
57
+ clearMounted();
58
+ throw error;
59
+ }
60
+ return () => {
61
+ unsubscribe();
62
+ clearMounted();
63
+ };
64
+ }, "dsh-archive-manager: official directory flow"));
65
+ }
66
+
2
67
  // src/plugin-update-ui.js
3
68
  var UPDATE_HEADER = "x-michengai-plugin-update";
4
69
  var STYLE_ID = "michengai-plugin-update-ui";
@@ -1045,7 +1110,7 @@
1045
1110
  };
1046
1111
  }
1047
1112
  const css$2 = '.YDXeBa_projectRow,.YDXeBa_sessionRow{cursor:pointer;user-select:none;color:var(--dsw-alias-label-primary);border-radius:8px;align-items:center;gap:6px;padding:0 8px;display:flex}.YDXeBa_projectRow:hover,.YDXeBa_sessionRow:hover,.YDXeBa_sessionRow.YDXeBa_selected{background:var(--dsw-alias-interactive-bg-hover)}.YDXeBa_searchResultRow{box-sizing:border-box;cursor:pointer;text-align:left;width:100%;min-height:48px;color:var(--dsw-alias-label-primary);background:0 0;border:none;border-radius:8px;flex-direction:column;align-items:stretch;padding:4px 8px;display:flex}.YDXeBa_searchResultRow:hover,.YDXeBa_searchResultRow.YDXeBa_selected{background:var(--dsw-alias-interactive-bg-hover)}.YDXeBa_searchResultHeading{align-items:center;min-width:0;display:flex}.YDXeBa_searchResultTitle{text-overflow:ellipsis;white-space:nowrap;min-width:0;margin-left:4px;font-size:14px;line-height:20px;overflow:hidden}.YDXeBa_searchResultMeta{align-items:center;gap:6px;min-width:0;margin-left:20px;display:flex}.YDXeBa_searchResultWorkspace,.YDXeBa_searchResultSnippet{text-overflow:ellipsis;white-space:nowrap;font-size:12px;line-height:17px;overflow:hidden}.YDXeBa_searchResultWorkspace{max-width:40%;color:var(--dsw-alias-label-tertiary);flex:none}.YDXeBa_searchResultSnippet{min-width:0;color:var(--dsw-alias-label-secondary);flex:1}.YDXeBa_projectRow{box-sizing:border-box;align-items:center;height:34px}.YDXeBa_projectRow .YDXeBa_rowActions{height:20px}.YDXeBa_sessionRow{height:32px;animation:YDXeBa_row-in .15s var(--ds-ease-in-out);gap:0}.YDXeBa_sessionRow .YDXeBa_title{margin:0 6px 0 4px}.YDXeBa_flatSessionRowWithoutStatus .YDXeBa_title{margin-left:0}@keyframes YDXeBa_row-in{0%{opacity:0}}.YDXeBa_slot{width:16px;height:20px;color:var(--dsw-alias-label-tertiary);flex:none;justify-content:center;align-items:center;display:inline-flex}.YDXeBa_visuallyHidden{clip:rect(0 0 0 0);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}.YDXeBa_folderActive{color:var(--dsw-alias-state-business-primary)}.YDXeBa_projectRow .YDXeBa_chevron{display:none}.YDXeBa_projectRow:hover .YDXeBa_chevron{display:inline-flex}.YDXeBa_projectRow:hover .YDXeBa_folder{display:none}.YDXeBa_arrow{transition:transform .15s var(--ds-ease-in-out)}.YDXeBa_arrowOpen{transform:rotate(90deg)}.YDXeBa_projectText{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.YDXeBa_title{text-overflow:ellipsis;white-space:nowrap;min-width:0;font-size:14px;line-height:20px;overflow:hidden}.YDXeBa_renameInput{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-button-elevated-fill);min-width:0;color:inherit;border-radius:4px;outline:none;padding:0 2px;font-size:14px;line-height:20px}.YDXeBa_sessionRow .YDXeBa_title{flex:1}.YDXeBa_meta{text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:20px;overflow:hidden}.YDXeBa_time{color:var(--dsw-alias-label-tertiary);flex:none;font-size:12px;line-height:20px}.YDXeBa_dot{flex:none}.YDXeBa_rowActions{flex:none;align-items:center;gap:12px;display:none}.YDXeBa_projectRow:hover .YDXeBa_rowActions,.YDXeBa_sessionRow:hover .YDXeBa_rowActions,.YDXeBa_projectRow.YDXeBa_menuOpen .YDXeBa_rowActions,.YDXeBa_sessionRow.YDXeBa_menuOpen .YDXeBa_rowActions{display:inline-flex}.YDXeBa_sessionRow:hover .YDXeBa_time,.YDXeBa_sessionRow.YDXeBa_menuOpen .YDXeBa_time{display:none}.YDXeBa_projectRow.YDXeBa_menuOpen,.YDXeBa_sessionRow.YDXeBa_menuOpen{background:var(--dsw-alias-interactive-bg-hover)}.YDXeBa_sessionRow.YDXeBa_dropBefore,.YDXeBa_sessionRow.YDXeBa_dropAfter{position:relative}.YDXeBa_sessionRow.YDXeBa_dropBefore:before,.YDXeBa_sessionRow.YDXeBa_dropAfter:after{content:"";z-index:1;background:linear-gradient(55deg, transparent calc(50% - 1px), var(--dsw-alias-state-business-primary) calc(50% - 1px) calc(50% + 1px), transparent calc(50% + 1px)) 0 0 / 5px 7px no-repeat, linear-gradient(125deg, transparent calc(50% - 1px), var(--dsw-alias-state-business-primary) calc(50% - 1px) calc(50% + 1px), transparent calc(50% + 1px)) 0 5px / 5px 7px no-repeat, linear-gradient(var(--dsw-alias-state-business-primary) 0 0) 4px 5px / calc(100% - 4px) 2px no-repeat;pointer-events:none;height:12px;position:absolute;left:0;right:4px}.YDXeBa_sessionRow.YDXeBa_dropBefore:before{top:-7px}.YDXeBa_sessionRow.YDXeBa_dropAfter:after{bottom:-7px}.YDXeBa_hoverContent{flex-direction:column;gap:8px;display:flex}.YDXeBa_hoverTitle{color:#fff;overflow-wrap:break-word;font-size:14px;line-height:20px}.YDXeBa_hoverPath{color:#cfd3d6;word-break:break-all;font-size:12px;line-height:16px}.YDXeBa_hoverTime{color:#cfd3d6;font-size:12px;line-height:16px}.YDXeBa_hoverStatus{color:#adb2b8;align-items:center;gap:8px;font-size:12px;line-height:20px;display:flex}.YDXeBa_iconButton{cursor:pointer;width:16px;height:16px;color:var(--dsw-alias-label-tertiary);background:0 0;border:none;border-radius:4px;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.YDXeBa_iconButton:hover{color:var(--dsw-alias-label-primary)}.YDXeBa_chevron{color:var(--dsw-alias-label-caption)}@media (prefers-reduced-motion:reduce){.YDXeBa_sessionRow,.YDXeBa_arrow{transition:none;animation:none}}';
1048
- const tagId$2 = "@deepseek-ai/dsh-client-ui-workspace/Rows.module.css";
1113
+ const tagId$2 = "@michengai/dsh-archive-manager/Rows.module.css";
1049
1114
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
1050
1115
  const tag = document.createElement("style");
1051
1116
  tag.dataset.plugin = "@michengai/dsh-archive-manager";
@@ -1511,7 +1576,7 @@
1511
1576
  });
1512
1577
  }
1513
1578
  const css$1 = "._G5b-a_modalAction{min-width:72px}._G5b-a_modalError,._G5b-a_menuStatus{margin-top:8px;font-size:12px;line-height:18px}._G5b-a_modalError{color:var(--dsw-alias-state-error-primary)}._G5b-a_menuStatus{color:var(--dsw-alias-label-secondary)}";
1514
- const tagId$1 = "@deepseek-ai/dsh-client-ui-workspace/WorkspacePicker.module.css";
1579
+ const tagId$1 = "@michengai/dsh-archive-manager/WorkspacePicker.module.css";
1515
1580
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
1516
1581
  const tag = document.createElement("style");
1517
1582
  tag.dataset.plugin = "@michengai/dsh-archive-manager";
@@ -1649,22 +1714,8 @@
1649
1714
  })
1650
1715
  ] });
1651
1716
  }
1652
- function WorkspacePicker({ open, anchorRef, useWorkspaces, selectedId, onPick, onClose, createWorkspace, useDirectoryFlow, renderSlot, t }) {
1653
- return (0, react_jsx_runtime.jsx)(WorkspacePickFlow, {
1654
- t,
1655
- open,
1656
- anchorRef,
1657
- useWorkspaces,
1658
- createWorkspace,
1659
- useDirectoryFlow,
1660
- renderDirectoryFlow: (owner) => renderSlot("conversation.hero.workspace.directoryFlow", owner),
1661
- selectedId,
1662
- onPick,
1663
- onClose
1664
- });
1665
- }
1666
1717
  const css = '.qDHVXG_root{--dsh-session-list-edge-inset:var(--dsh-sidebar-inline-padding);--dsh-session-list-scrollbar-width:8px;--dsh-session-list-scrollbar-offset:2px;box-sizing:border-box;min-height:0;padding-right:var(--dsh-session-list-edge-inset);flex-direction:column;flex:1;display:flex}.qDHVXG_root.qDHVXG_rail{padding-right:0}.qDHVXG_iconButton{cursor:pointer;width:28px;height:28px;color:var(--dsw-alias-label-secondary);background:0 0;border:none;border-radius:50%;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.qDHVXG_iconButton:hover{background:var(--dsw-alias-interactive-bg-hover)}.qDHVXG_sectionHeader{box-sizing:border-box;height:36px;color:var(--dsw-alias-label-tertiary);border-radius:12px;flex:none;justify-content:flex-end;align-items:center;gap:4px;margin-bottom:4px;padding-left:4px;display:flex;overflow:hidden}.qDHVXG_root:not(.qDHVXG_rail) .qDHVXG_sectionHeader{margin-top:2px;margin-right:-4px}.qDHVXG_sectionLabel{white-space:nowrap;opacity:1;visibility:visible;min-width:0;max-width:45%;transition:max-width .18s var(--ds-ease-in-out), margin-right .18s var(--ds-ease-in-out), opacity .12s var(--ds-ease-in-out), transform .18s var(--ds-ease-in-out), visibility 0s linear;flex:none;line-height:20px;overflow:hidden}.qDHVXG_sectionLabelHidden{opacity:0;visibility:hidden;max-width:0;margin-right:-4px;transition-delay:0s,0s,0s,0s,.18s;transform:translate(-4px)}.qDHVXG_searchSlot{box-sizing:border-box;min-width:0;max-width:28px;transition:max-width .18s var(--ds-ease-in-out), padding-left .18s var(--ds-ease-in-out);flex:1;align-items:center;margin-left:auto;padding-left:0;display:flex}.qDHVXG_searchSlotExpanded{max-width:100%;padding-left:0}.qDHVXG_headerActions{opacity:1;visibility:visible;max-width:60px;transition:max-width .18s var(--ds-ease-in-out), opacity .12s var(--ds-ease-in-out), transform .18s var(--ds-ease-in-out), visibility 0s linear;flex:none;align-items:center;gap:4px;display:flex;overflow:hidden}.qDHVXG_headerActionsHidden{opacity:0;visibility:hidden;pointer-events:none;max-width:0;transition-delay:0s,0s,0s,.18s;transform:translate(4px)}.qDHVXG_search{box-sizing:border-box;cursor:text;width:100%;height:28px;color:var(--dsw-alias-label-secondary);transition:width .18s var(--ds-ease-in-out), padding .18s var(--ds-ease-in-out), border-color .18s var(--ds-ease-in-out), background-color .18s var(--ds-ease-in-out);background:0 0;border:none;border-radius:50%;flex:none;align-items:center;gap:0;margin:0;padding:0;display:flex;overflow:hidden}.qDHVXG_searchExpanded{border:1px solid var(--dsw-alias-border-l2);width:calc(100% + 4px);height:30px;color:var(--dsw-alias-label-caption);background:0 0;border-radius:10px;margin-inline:-2px;padding:0 4px 0 0}.qDHVXG_searchButton{cursor:pointer;width:28px;height:28px;color:inherit;background:0 0;border:none;border-radius:50%;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.qDHVXG_searchExpanded .qDHVXG_searchButton{width:28px;height:30px}.qDHVXG_searchButton:hover{background:var(--dsw-alias-interactive-bg-hover)}.qDHVXG_searchExpanded .qDHVXG_searchButton:hover{background:0 0}.qDHVXG_searchInput{opacity:0;pointer-events:none;width:0;min-width:0;color:var(--dsw-alias-label-primary);transition:opacity .12s var(--ds-ease-in-out);background:0 0;border:none;outline:none;flex:1;font-size:13px;line-height:18px}.qDHVXG_searchExpanded .qDHVXG_searchInput{opacity:1;pointer-events:auto;margin-left:-2px}.qDHVXG_searchInput::placeholder{color:var(--dsw-alias-label-tertiary)}.qDHVXG_clearButton{cursor:pointer;width:24px;height:24px;color:var(--dsw-alias-label-secondary);background:0 0;border:none;border-radius:50%;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.qDHVXG_clearButton:hover{background:var(--dsw-alias-interactive-bg-hover)}.qDHVXG_rail .qDHVXG_sectionHeader{justify-content:flex-start;gap:0;margin-bottom:12px;padding-left:0}.qDHVXG_rail .qDHVXG_headerActions{max-width:none}.qDHVXG_rail .qDHVXG_iconButton{width:36px;height:36px;color:var(--dsw-alias-label-primary)}.qDHVXG_rail .qDHVXG_search{background:0 0;border-color:#0000;gap:0;width:36px;height:36px;margin:0 0 12px;padding:0}.qDHVXG_rail .qDHVXG_searchButton{width:36px;height:36px;color:var(--dsw-alias-label-primary)}.qDHVXG_rail .qDHVXG_searchButton:hover{background:var(--dsw-alias-interactive-bg-hover)}.qDHVXG_listArea{min-height:0;margin-left:-4px;margin-right:calc(-1 * var(--dsh-session-list-edge-inset));flex-direction:column;flex:1;padding-left:4px;display:flex;overflow:visible}.qDHVXG_rail .qDHVXG_listArea{margin-left:0;margin-right:0;padding-left:0}.qDHVXG_treeBody{flex-direction:column;flex:1;min-height:0;display:flex;position:relative}.qDHVXG_fade{left:0;right:var(--dsh-session-list-edge-inset);background:linear-gradient(to bottom, transparent, var(--dsw-specific-sidebar-fill));pointer-events:none;height:24px;position:absolute;bottom:0}.qDHVXG_wide{animation:qDHVXG_wide-in .2s var(--ds-ease-in-out)}@keyframes qDHVXG_wide-in{0%{opacity:0}}.qDHVXG_list{min-height:0;margin-left:-4px;margin-right:var(--dsh-session-list-scrollbar-offset);padding-left:4px;padding-right:calc(var(--dsh-session-list-edge-inset) - var(--dsh-session-list-scrollbar-width) - var(--dsh-session-list-scrollbar-offset));scrollbar-gutter:stable;flex:1;padding-bottom:16px;overflow-y:auto}.qDHVXG_flatList>*+*,.qDHVXG_searchTree>[role=treeitem]+[role=treeitem],.qDHVXG_groupSection>*+*{margin-top:2px}.qDHVXG_searchStatus,.qDHVXG_searchWarning{color:var(--dsw-alias-label-tertiary);padding:10px 12px;font-size:12px;line-height:18px}.qDHVXG_searchWarning{color:var(--dsw-alias-label-secondary)}.qDHVXG_groupSection{position:relative}.qDHVXG_groupSection+.qDHVXG_groupSection{margin-top:4px}.qDHVXG_listTopDropIndicator,.qDHVXG_workspaceDropBefore:before,.qDHVXG_workspaceDropAfter:after{content:"";z-index:1;background:linear-gradient(55deg, transparent calc(50% - 1px), var(--dsw-alias-state-business-primary) calc(50% - 1px) calc(50% + 1px), transparent calc(50% + 1px)) 0 0 / 5px 7px no-repeat, linear-gradient(125deg, transparent calc(50% - 1px), var(--dsw-alias-state-business-primary) calc(50% - 1px) calc(50% + 1px), transparent calc(50% + 1px)) 0 5px / 5px 7px no-repeat, linear-gradient(var(--dsw-alias-state-business-primary) 0 0) 4px 5px / calc(100% - 4px) 2px no-repeat;pointer-events:none;height:12px;position:absolute;left:0;right:0}.qDHVXG_listTopDropIndicator{top:-8px;left:0;right:var(--dsh-session-list-edge-inset)}.qDHVXG_listTopDropActive>.qDHVXG_workspaceDropBefore:first-child:before{display:none}.qDHVXG_workspaceDropBefore:before{top:-8px}.qDHVXG_workspaceDropAfter:after{bottom:-8px}.qDHVXG_sessionOverflowButton{cursor:pointer;text-align:left;width:100%;height:28px;color:var(--dsw-alias-label-tertiary);background:0 0;border:none;border-radius:8px;padding:0 12px 0 28px;font-size:12px}.qDHVXG_groupSection>.qDHVXG_sessionOverflowButton{margin-top:0}.qDHVXG_sessionOverflowButton:hover{color:var(--dsw-alias-label-secondary);background:0 0}.qDHVXG_empty{color:var(--dsw-alias-label-tertiary);padding:16px 12px;font-size:13px}.qDHVXG_renameInput{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);width:100%;height:44px;color:var(--dsw-alias-label-primary);background:0 0;border-radius:22px;outline:none;padding:7px 14px;font-size:14px;font-weight:400;line-height:22px}.qDHVXG_renameInput:disabled{color:var(--dsw-alias-label-dimmed)}.qDHVXG_renameError{color:var(--dsw-alias-state-error-primary);margin-top:8px;font-size:12px;line-height:18px}.qDHVXG_deleteAction:not(:disabled){color:var(--dsw-alias-state-error-primary)}.qDHVXG_deleteStatus{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px}@media (prefers-reduced-motion:reduce){.qDHVXG_wide{animation:none}.qDHVXG_search,.qDHVXG_sectionLabel,.qDHVXG_searchSlot,.qDHVXG_searchInput,.qDHVXG_headerActions{transition:none}}';
1667
- const tagId = "@deepseek-ai/dsh-client-ui-workspace/WorkspaceBrowser.module.css";
1718
+ const tagId = "@michengai/dsh-archive-manager/WorkspaceBrowser.module.css";
1668
1719
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
1669
1720
  const tag = document.createElement("style");
1670
1721
  tag.dataset.plugin = "@michengai/dsh-archive-manager";
@@ -2718,7 +2769,7 @@
2718
2769
  useWorkspaces,
2719
2770
  createWorkspace,
2720
2771
  useDirectoryFlow,
2721
- renderDirectoryFlow: (owner) => renderSlot("sidebar.workspaces.directoryFlow", owner),
2772
+ renderDirectoryFlow: (owner) => renderSlot(DIRECTORY_FLOW_SLOT, owner),
2722
2773
  addOnly: true,
2723
2774
  side: "right",
2724
2775
  onPick: (workspaceId) => {
@@ -3729,14 +3780,16 @@
3729
3780
  "time.years": "{n}y",
3730
3781
  "time.ago": "{t} ago"
3731
3782
  };
3732
- const NS = "workspace";
3783
+ const NS = "archive-manager-workspace";
3784
+ const DIRECTORY_FLOW_SLOT = "archiveManager.sidebar.directoryFlow";
3733
3785
  const inject = [
3734
3786
  "slots",
3735
3787
  "sessions",
3736
3788
  "workspaces",
3737
3789
  "locale",
3738
3790
  "remote",
3739
- "typert"
3791
+ "typert",
3792
+ ...hasSplitClientStore ? ["uiWorkspace"] : []
3740
3793
  ];
3741
3794
  function bindObservable(source) {
3742
3795
  return {
@@ -3744,173 +3797,6 @@
3744
3797
  subscribe: source.subscribe.bind(source)
3745
3798
  };
3746
3799
  }
3747
- class DirectoryBrowseError extends Error {
3748
- constructor(rpcError) {
3749
- super(`directory browse failed: ${rpcError.code}: ${rpcError.message}`);
3750
- this.name = "DirectoryBrowseError";
3751
- this.rpcError = rpcError;
3752
- }
3753
- }
3754
- function provideUiWorkspace(ctx) {
3755
- if (ctx.get("uiWorkspace") !== void 0) return () => {
3756
- };
3757
- const sessions = ctx.sessions;
3758
- const workspaces = ctx.workspaces;
3759
- const connecting = /* @__PURE__ */ new Map();
3760
- const lifetime = new AbortController();
3761
- const layoutAt = () => ctx.get("layout");
3762
- const beginNavigation = () => {
3763
- const signal = layoutAt()?.beginNavigation?.();
3764
- return signal === void 0 ? lifetime.signal : AbortSignal.any([signal, lifetime.signal]);
3765
- };
3766
- const recentWorkspace = () => {
3767
- const workspaceState = workspaces.list.getSnapshot();
3768
- const sessionState = sessions.list.getSnapshot();
3769
- let selected;
3770
- let selectedTime = Number.NEGATIVE_INFINITY;
3771
- for (const workspace of workspaceState.items ?? []) {
3772
- let latest = Number.NEGATIVE_INFINITY;
3773
- for (const sessionId of workspace.sessionIds) {
3774
- const session = sessionState.byId[sessionId];
3775
- if (session !== void 0) latest = Math.max(latest, session.updatedAt);
3776
- }
3777
- if (latest === Number.NEGATIVE_INFINITY) latest = Date.parse(workspace.createdAt);
3778
- if (selected === void 0 || latest > selectedTime) {
3779
- selected = workspace.workspaceId;
3780
- selectedTime = latest;
3781
- }
3782
- }
3783
- return selected;
3784
- };
3785
- const directoryPicker = () => ctx.get("remote.directoryPicker") ?? ctx.get("remote")?.directoryPicker;
3786
- const service = {
3787
- connectWorkspace(workspaceId) {
3788
- const workspaceState = workspaces.list.getSnapshot();
3789
- const workspace = (workspaceState.items ?? []).find((item) => item.workspaceId === workspaceId);
3790
- if (workspace === void 0) return Promise.reject(new Error(`uiWorkspace.connectWorkspace: unknown workspace ${workspaceId}`));
3791
- const inflight = connecting.get(workspaceId);
3792
- if (inflight !== void 0) return inflight;
3793
- const sessionState = sessions.list.getSnapshot();
3794
- const archived = new Set(workspaceState.archivedSessionIds ?? []);
3795
- for (const id of sessionState.ids) {
3796
- const summary = sessionState.byId[id];
3797
- if (summary !== void 0 && summary.blank && summary.cwd === workspace.path && workspace.sessionIds.includes(summary.id) && !archived.has(summary.id)) return Promise.resolve(summary.id);
3798
- }
3799
- const attempt = sessions.create({ workspaceId }).finally(() => {
3800
- connecting.delete(workspaceId);
3801
- });
3802
- connecting.set(workspaceId, attempt);
3803
- return attempt;
3804
- },
3805
- /** 打开指定会话,并从新版全局面板回到对话。 */
3806
- openSession(sessionId) {
3807
- if (lifetime.signal.aborted) return;
3808
- sessions.open(sessionId);
3809
- layoutAt()?.selectPanel?.(null);
3810
- },
3811
- /** 创建或复用工作区会话;导航仍有效时先交接草稿,失败向调用方传播。 */
3812
- async openWorkspace(workspaceId, beforeOpen) {
3813
- const navigation = beginNavigation();
3814
- const sessionId = await service.connectWorkspace(workspaceId);
3815
- if (navigation.aborted) return;
3816
- beforeOpen?.(sessionId);
3817
- if (!navigation.aborted) service.openSession(sessionId);
3818
- },
3819
- /** 分叉落盘后仅在导航未取消时打开结果,保留失败语义。 */
3820
- async forkSession(sessionId) {
3821
- const navigation = beginNavigation();
3822
- const childId = await sessions.fork({ sessionId, increaseTitle: true });
3823
- if (!navigation.aborted) service.openSession(childId);
3824
- },
3825
- startSession(workspaceId) {
3826
- const workspaceState = workspaces.list.getSnapshot();
3827
- const sessionState = sessions.list.getSnapshot();
3828
- const currentWorkspaceId = sessionState.current === void 0 ? void 0 : (workspaceState.items ?? []).find((item) => item.sessionIds.includes(sessionState.current))?.workspaceId;
3829
- const recent = workspaceState.phase === "ready" && sessionState.phase === "ready" ? recentWorkspace() : void 0;
3830
- const target = workspaceId ?? currentWorkspaceId ?? recent;
3831
- if (target === void 0) {
3832
- sessions.clear();
3833
- layoutAt()?.selectPanel?.(null);
3834
- return;
3835
- }
3836
- void service.openWorkspace(target).catch((reason) => {
3837
- console.warn("new session failed:", reason);
3838
- });
3839
- },
3840
- archiveSession(sessionId) {
3841
- return workspaces.archiveSession(sessionId);
3842
- },
3843
- async pickDirectory() {
3844
- const picker = directoryPicker();
3845
- if (picker === void 0) throw new Error("directory picker is unavailable");
3846
- const result = await picker.pick();
3847
- if (!result.ok) throw new Error(`directory picker failed: ${result.error.message}`);
3848
- return result.value;
3849
- },
3850
- async listDirectory(path, signal) {
3851
- const picker = directoryPicker();
3852
- if (picker === void 0) throw new Error("directory picker is unavailable");
3853
- const result = await picker.list(path, signal);
3854
- if (!result.ok) throw new DirectoryBrowseError(result.error);
3855
- return result.value;
3856
- },
3857
- async createDirectory(path, name) {
3858
- const picker = directoryPicker();
3859
- if (picker === void 0) throw new Error("directory picker is unavailable");
3860
- const result = await picker.createDirectory(path, name);
3861
- if (!result.ok) throw new DirectoryBrowseError(result.error);
3862
- return result.value;
3863
- }
3864
- };
3865
- const dispose = ctx.provide("uiWorkspace", service);
3866
- ctx.slots.provideRoot?.({ hooks: { workspaces: workspaces.list } });
3867
- ctx.effect(() => {
3868
- let initial = "waiting";
3869
- let disposed = false;
3870
- const reconcile = () => {
3871
- if (disposed) return;
3872
- const workspaceState = workspaces.list.getSnapshot();
3873
- const sessionState = sessions.list.getSnapshot();
3874
- if (sessionState.current !== void 0 && (workspaceState.archivedSessionIds ?? []).includes(sessionState.current)) {
3875
- sessions.clear();
3876
- return;
3877
- }
3878
- if (initial !== "waiting" || workspaceState.phase !== "ready" || sessionState.phase !== "ready") return;
3879
- if (sessionState.current !== void 0) {
3880
- initial = "done";
3881
- return;
3882
- }
3883
- const target = recentWorkspace();
3884
- if (target === void 0) {
3885
- initial = "done";
3886
- return;
3887
- }
3888
- initial = "connecting";
3889
- void service.connectWorkspace(target).then((sessionId) => {
3890
- if (disposed) return;
3891
- if (sessions.list.getSnapshot().current === void 0) sessions.open(sessionId);
3892
- initial = "done";
3893
- }, (reason) => {
3894
- if (disposed) return;
3895
- initial = "waiting";
3896
- console.warn("initial workspace selection failed:", reason);
3897
- });
3898
- };
3899
- const disposeWorkspaces = workspaces.list.subscribe(reconcile);
3900
- const disposeSessions = sessions.list.subscribe(reconcile);
3901
- reconcile();
3902
- return () => {
3903
- disposed = true;
3904
- lifetime.abort();
3905
- disposeSessions();
3906
- disposeWorkspaces();
3907
- };
3908
- }, "dsh-archive-manager: uiWorkspace navigation policy");
3909
- return () => {
3910
- lifetime.abort();
3911
- dispose();
3912
- };
3913
- }
3914
3800
  async function archiveWorkspaceSessionsAndRefresh(registry, workspaceId, refresh) {
3915
3801
  const result = await registry.archiveWorkspaceSessions(workspaceId);
3916
3802
  if (!result.ok) throw new Error(result.error.message);
@@ -3922,11 +3808,8 @@
3922
3808
  let disposeRemote = () => {
3923
3809
  };
3924
3810
  if (remote !== void 0) disposeRemote = await remote.$mount(ARCHIVE_MANAGER_REMOTE);
3925
- const disposeUiWorkspace = hasSplitClientStore ? provideUiWorkspace(ctx) : () => {
3926
- };
3927
3811
  applyWorkspaceBrowser(ctx);
3928
3812
  return async () => {
3929
- disposeUiWorkspace();
3930
3813
  await disposeRemote();
3931
3814
  };
3932
3815
  }
@@ -3954,8 +3837,7 @@
3954
3837
  getSnapshot: () => ctx.slots.entries(hole).length > 0,
3955
3838
  subscribe: (listener) => ctx.slots.subscribe(hole, listener)
3956
3839
  });
3957
- const browserFlowSource = flowSource("sidebar.workspaces.directoryFlow");
3958
- const pickerFlowSource = flowSource("conversation.hero.workspace.directoryFlow");
3840
+ const browserFlowSource = flowSource(DIRECTORY_FLOW_SLOT);
3959
3841
  const refreshSessionList = async () => {
3960
3842
  if (typeof ctx.sessions.refresh !== "function") return;
3961
3843
  try {
@@ -4060,13 +3942,11 @@
4060
3942
  createWorkspace: (input) => ctx.workspaces.create(input),
4061
3943
  hooks: { directoryFlow: browserFlowSource }
4062
3944
  });
4063
- const pickerInjected = () => ({
4064
- createWorkspace: (input) => ctx.workspaces.create(input),
4065
- hooks: { directoryFlow: pickerFlowSource }
4066
- });
4067
3945
  ctx.slots.inject("sidebar.workspaces", () => ctx.slots.register({
4068
3946
  name: "sidebar.workspaces",
4069
- children: { "sidebar.workspaces.directoryFlow": {
3947
+ // 显示顺序:Codex UI(-1)→ 归档(-0.5)→ 官方默认(0)。
3948
+ priority: -0.5,
3949
+ children: { [DIRECTORY_FLOW_SLOT]: {
4070
3950
  kind: "single",
4071
3951
  scope: "root"
4072
3952
  } },
@@ -4074,15 +3954,7 @@
4074
3954
  inject: browserInjected,
4075
3955
  locale: NS
4076
3956
  }, WorkspaceBrowser));
4077
- ctx.slots.inject("conversation.hero.workspace", () => ctx.slots.register({
4078
- name: "conversation.hero.workspace",
4079
- children: { "conversation.hero.workspace.directoryFlow": {
4080
- kind: "single",
4081
- scope: "root"
4082
- } },
4083
- inject: pickerInjected,
4084
- locale: NS
4085
- }, WorkspacePicker));
3957
+ mirrorDirectoryFlow(ctx, DIRECTORY_FLOW_SLOT);
4086
3958
  ctx.slots.inject("settings.section", () => ctx.slots.register({
4087
3959
  name: "settings.section",
4088
3960
  id: "archived-sessions",
@@ -4124,7 +3996,6 @@
4124
3996
  createWorkspaceViewStore,
4125
3997
  bindObservable,
4126
3998
  hasSplitClientStore,
4127
- provideUiWorkspace,
4128
3999
  groupByWorkspace,
4129
4000
  byRecency,
4130
4001
  ARCHIVE_MANAGER_REMOTE