@xrn1997/dsh-session-delete 0.6.0 → 0.6.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 +5 -4
- package/lib/client.js +296 -101
- package/lib/index.js +269 -173
- package/lib/types/client/api-base.d.ts +19 -0
- package/lib/types/client/context-menu-actions.d.ts +47 -0
- package/lib/types/client/copy.d.ts +8 -0
- package/lib/types/client/delete-confirm.d.ts +2 -2
- package/lib/types/client/index.d.ts +2 -0
- package/lib/types/client/maintenance-settings.d.ts +3 -1
- package/lib/types/client/remote.d.ts +11 -7
- package/lib/types/client/trash-nav.d.ts +5 -1
- package/lib/types/client/trash-view.d.ts +3 -0
- package/lib/types/client/ui/MenuItemButton.d.ts +1 -1
- package/lib/types/client/ui/Toast.d.ts +4 -1
- package/lib/types/index.d.ts +5 -4
- package/lib/types/ports/fs-port.d.ts +10 -0
- package/lib/types/ports/host-port.d.ts +4 -2
- package/lib/types/trash/attachments.d.ts +15 -2
- package/lib/types/verbs/errors.d.ts +3 -1
- package/lib/types/verbs/permanent-removal.d.ts +10 -5
- package/package.json +13 -8
|
@@ -170,6 +170,7 @@ declare const ZH: {
|
|
|
170
170
|
readonly 'detail.role.assistant': "助手";
|
|
171
171
|
readonly 'menu.delete': "删除";
|
|
172
172
|
readonly 'menu.live': "会话正在运行,先停止再删除";
|
|
173
|
+
readonly 'menu.deleteLive': "删除(运行中)";
|
|
173
174
|
readonly 'dialog.title': "删除这个会话?";
|
|
174
175
|
readonly 'dialog.subagents': "含 {n} 个子会话,将一起移入回收站。";
|
|
175
176
|
readonly 'dialog.hint': "会话会移入回收站,之后可以随时恢复。彻底删除是回收站里的另一个动作。";
|
|
@@ -201,6 +202,13 @@ export declare const zhTranslate: Translate;
|
|
|
201
202
|
/**
|
|
202
203
|
* 注册字典并交回本插件的 `t`。服务不在时返回 `zhTranslate`(不抛、不 pending)。
|
|
203
204
|
*
|
|
205
|
+
* **空值判据同时认 `undefined` 与 `null`**:宿主 `ctx.get` 可以回 null(同一条窄镜像的读法见
|
|
206
|
+
* `main-view.ts` 的 `isReadyUiWorkspace`)。这里只判 `undefined` 的版本会把 null 当成"服务在",
|
|
207
|
+
* 下一句 `service.register` 抛错——而本函数跑在**任何槽位注册之前**,抛出去等于整个客户端条目
|
|
208
|
+
* 从页面消失(`apply` 只打一条 warn)。注册 / 绑定自身失败同样退回内置 zh:文案降级远好过没有插件。
|
|
209
|
+
* `bind` 在注册之后才跑,它失败时字典已挂上但没人用——留着无害(宿主只是多一份不用的词典),
|
|
210
|
+
* 不为它补撤销路径再引入新的失败面。
|
|
211
|
+
*
|
|
204
212
|
* 注册必须挂在 `ctx.effect` 上:`register` 返回的 disposer 是**官方契约**(卸载时要把字典摘掉),
|
|
205
213
|
* 而且同一命名空间的同一语言**只能注册一次**——effect 没挂,HMR 重挂就撞 "already has locale"。
|
|
206
214
|
*/
|
|
@@ -9,8 +9,8 @@ import { type DeleteConfirmDeps } from './remote.js';
|
|
|
9
9
|
export declare const TARGET_CARD: {
|
|
10
10
|
readonly padding: "10px 12px";
|
|
11
11
|
readonly background: "var(--dsw-alias-bg-layer-2)";
|
|
12
|
-
readonly border: "0.5px solid var(--
|
|
13
|
-
readonly borderRadius: "var(--
|
|
12
|
+
readonly border: "0.5px solid var(--sd-border-l4)";
|
|
13
|
+
readonly borderRadius: "var(--sd-radius-lg)";
|
|
14
14
|
};
|
|
15
15
|
/** 菜单行写进现场的一条删除请求(槽位投影原样带过来,浏览器半不自己拼 id)。 */
|
|
16
16
|
export interface DeleteRequest {
|
|
@@ -6,6 +6,8 @@ export declare const name = "@xrn1997/dsh-session-delete/client";
|
|
|
6
6
|
* **`locale` 也不在这里**:宿主自己的 `ui-sidebar` 是硬注入它的,但那是"宿主知道自己那一代"的前提;
|
|
7
7
|
* 本插件要跨代活着 ⇒ 走 `ctx.get('locale')` 可选读,缺席时降级到内置 zh 文案(见 `copy.ts` 头注)。
|
|
8
8
|
* 写进 inject 就等于"这一代没有 locale 就不让整个客户端条目激活",而那等于宿主进程死。
|
|
9
|
+
* **`contextMenus` 同理**:0.2.2+ 用 `ctx.get('contextMenus')` 探测,包本身在 package.json 的
|
|
10
|
+
* `dsh.client.inject` 里排到前面;旧宿主没有这个服务时回退 legacy 槽位。
|
|
9
11
|
*/
|
|
10
12
|
export declare const inject: string[];
|
|
11
13
|
/**
|
|
@@ -18,5 +18,7 @@ export interface MaintenanceSettingsProps {
|
|
|
18
18
|
deps: MaintenanceDeps;
|
|
19
19
|
/** 文案(缺省 = 内置 zh;宿主 locale 服务缺席时也是它,见 `copy.ts`)。 */
|
|
20
20
|
t?: Translate;
|
|
21
|
+
/** 宿主 `plugins.bundle.config` 的视图:`summary` 是插件行的一行摘要,本卡只属于详情页。 */
|
|
22
|
+
view?: 'summary' | 'page';
|
|
21
23
|
}
|
|
22
|
-
export declare function MaintenanceSettings({ deps, t }: MaintenanceSettingsProps): ReactElement;
|
|
24
|
+
export declare function MaintenanceSettings({ deps, t, view }: MaintenanceSettingsProps): ReactElement | null;
|
|
@@ -6,10 +6,12 @@
|
|
|
6
6
|
* 没有旧前缀 fallback——支持面是 web UI 与桌面端,二者的标准组合都装 `client-connection`。
|
|
7
7
|
* 官方 remote.<namespace> 仍不可用(第三方拿不到 Typert 描述符的动态发现挂载点)。
|
|
8
8
|
* - 九段的**段名与方法**住 `src/shared/wire.ts` 的结构化段名表(`ROUTES` 每项 `{ path, method }`),
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
9
|
+
* 本文件只投影段名与方法(GET 段直接取 `ROUTES.x.method`,写段把它交给 `post()`)——方法字面量
|
|
10
|
+
* 不在本文件出现第二份;取数地址(官方 `/api` 前缀 + 文档挂载点)归 `src/client/api-base.ts`
|
|
11
|
+
* (根部署下与旧版逐字相同)。
|
|
12
|
+
* 写动作统一走 apply;`attachment` 是唯一二进制段,由 `src/client/attachment-view.tsx` 经同一投影
|
|
13
|
+
* 拼地址,不经过本文件的信封通道;`attachment-orphans`(纯读)与 `attachment-clean`(聚合写)是孤儿
|
|
14
|
+
* 附件的两段。
|
|
13
15
|
* - 信封与官方 unary 面同形:{ok:true,value} / {ok:false,error}。HTTP 往返本身失败才 reject;
|
|
14
16
|
* 业务失败以信封返回,由 unwrapRemoteResult 在注入面抛出。
|
|
15
17
|
* - error 在线上是 {code,message,details?} 普通对象;判别依据 isDSHRemoteError 住在
|
|
@@ -77,9 +79,11 @@ export interface RawSessionDeleteRemote {
|
|
|
77
79
|
empty(): Promise<RemoteResult<PurgeResultLike>>;
|
|
78
80
|
}
|
|
79
81
|
/**
|
|
80
|
-
* exact Fetch 路由的 fetch
|
|
81
|
-
*
|
|
82
|
-
*
|
|
82
|
+
* exact Fetch 路由的 fetch 实现。**同源、带挂载点前缀**:不拼 host、不认 origin——页面本身就是从
|
|
83
|
+
* 宿主页面加载的,同源是这条通道的全部前提;路径只由 `api-base.ts` 从 `document.baseURI` 的目录
|
|
84
|
+
* 与官方 `/api` 前缀拼出(根部署下与旧版逐字相同,反代到 `/dsh/` 时得到 `/dsh/api/...`)。
|
|
85
|
+
* 鉴权归宿主 `/api` bridge(ADR-0033)。所以这条通道**只对**宿主页面打开过、带宿主身份的客户端
|
|
86
|
+
* 成立(凭据是那次访问换来的 cookie,不是插件自己的秘密)。
|
|
83
87
|
*/
|
|
84
88
|
export declare function createHttpRemote(): RawSessionDeleteRemote;
|
|
85
89
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { KeyboardEvent as ReactKeyboardEvent } from 'react';
|
|
1
|
+
import type { KeyboardEvent as ReactKeyboardEvent, RefObject } from 'react';
|
|
2
2
|
import type { TrashEntryLike } from './remote.js';
|
|
3
3
|
/**
|
|
4
4
|
* 导航要的面。`ordered` 是**屏幕上的顺序**(只含展开的组),由面板/选择面算好传进来——
|
|
@@ -22,6 +22,10 @@ export interface TrashNavInput {
|
|
|
22
22
|
toggleCheck: (entryId: string) => void;
|
|
23
23
|
back: () => void;
|
|
24
24
|
focusRow: (entryId: string) => void;
|
|
25
|
+
/** Esc 的作用域(面板根节点;生产入口必须传,测试可传空引用对象)。下钻时清单不在 DOM,
|
|
26
|
+
* 但详情在面板里;**焦点在面板外**的 Esc 不归清单——否则在侧栏或别的面板按 Esc 会退出下钻,
|
|
27
|
+
* 还会把焦点拽进回收站。根还没挂上时无从判断包含关系,Esc 不处理。 */
|
|
28
|
+
scope: RefObject<HTMLElement | null>;
|
|
25
29
|
}
|
|
26
30
|
export interface TrashNav {
|
|
27
31
|
/** `aria-activedescendant` 的那条 id:选中行不在 DOM 里时是 `null`。 */
|
|
@@ -17,6 +17,9 @@ export declare const CARD_SELECTED: CSSProperties;
|
|
|
17
17
|
/**
|
|
18
18
|
* **整页唯一那块实心红**的写法:`variant="primary"` + 在元素上覆盖 primary 那对填充 token。
|
|
19
19
|
* 宿主插件管理页的 danger 按钮就是这个写法(asar @21658274),所以 hover 仍走 `.primary:hover` 类。
|
|
20
|
+
*
|
|
21
|
+
* 覆盖的是**本插件别名层**(`--sd-*`,见 `ui.css` 头注)而不是宿主私有 token:别名在 `body` 上
|
|
22
|
+
* 就把 `var(--dsw-…, 兜底)` 算完并继承下来了,元素上再覆盖底层私有 token 已经传不进继承值。
|
|
20
23
|
*/
|
|
21
24
|
export declare const BULK_DANGER: CSSProperties;
|
|
22
25
|
/**
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* `MenuItemButton`(**照抄** `@deepseek-ai/dsh-client-ui-primitives@0.2.0-rc.2` 的同名组件,出处与三条
|
|
3
3
|
* 改写规则见 `ui.css` 头注):菜单里的一行,宿主菜单容器渲染它、键盘巡游也认它。
|
|
4
4
|
*
|
|
5
|
-
*
|
|
5
|
+
* **形状必须与宿主自己的官方菜单行(pin/rename/fork/archive/session-id)逐字同构**:`<div class=itemWrap>` 里先是可选
|
|
6
6
|
* 的发丝线(`role="separator"`),再是 `<button type="button" role="menuitem">`,按钮内是
|
|
7
7
|
* 图标位 + 标签位(+ 官方的快捷键位)。少一层、换个标签,这一行就会在键盘顺序、hover 底色或
|
|
8
8
|
* `.itemLabel` 的省略号上跟邻行错开。
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* **砍掉的**:`anchor`(把横幅对齐到某个元素的水平中心——本插件的撤销提示就是窗口居中)、
|
|
14
14
|
* `actions[].prefix`(动作文案前的连接词,本插件只用「撤销」两个字)。**没砍 `text`/`icon`/`tone`/
|
|
15
15
|
* `holdMs`/`actions`/`onDone`**:唯一的调用点这几样都在用。
|
|
16
|
+
* **本插件加的**:`paused`(撤销在飞时冻结停留与淡出,失败原文要落回同一条横幅;官方没有这个开关)。
|
|
16
17
|
*/
|
|
17
18
|
import { type ReactElement, type ReactNode } from 'react';
|
|
18
19
|
import './styles.js';
|
|
@@ -32,7 +33,9 @@ export interface ToastProps {
|
|
|
32
33
|
holdMs?: number;
|
|
33
34
|
/** 句尾的行内动作(照着句子的顺序排)。 */
|
|
34
35
|
actions?: readonly ToastAction[] | undefined;
|
|
36
|
+
/** 暂停自动熄灭:这一趟还有下文(撤销在飞),先把横幅留着——失败原文要靠它上屏。 */
|
|
37
|
+
paused?: boolean | undefined;
|
|
35
38
|
/** 淡出完成时调用一次:在这里卸载。 */
|
|
36
39
|
onDone: () => void;
|
|
37
40
|
}
|
|
38
|
-
export declare function Toast({ text, icon, tone, holdMs, actions, onDone }: ToastProps): ReactElement;
|
|
41
|
+
export declare function Toast({ text, icon, tone, holdMs, actions, paused, onDone }: ToastProps): ReactElement;
|
package/lib/types/index.d.ts
CHANGED
|
@@ -10,10 +10,11 @@ export { Config };
|
|
|
10
10
|
* 三项都是在隔离数据根上实测注入成功、且本插件真正用到的宿主服务。**不进 inject 的**:
|
|
11
11
|
* - `remote`:那是**浏览器半**的服务(asar `dsh-api-gateway/lib/client.js`:`super(ctx, "remote")`),
|
|
12
12
|
* Node 半挂的是 `ctx.typertGateway`。把它写进 Node 半的 inject 会让插件永远 pending(同 `slots` 那次的形状)。
|
|
13
|
-
* - `sessions` / `sessionProjectionCache
|
|
14
|
-
* 用(活跃判据走 waterfall,见 src/ports/host-port.ts
|
|
15
|
-
*
|
|
16
|
-
*
|
|
13
|
+
* - `sessions` / `sessionProjectionCache` / `sessionPersistence`:都按 `ctx.get(...)` **可选读**——
|
|
14
|
+
* `sessions` 给 `evictLive` 和 live header 用(活跃判据走 waterfall,见 src/ports/host-port.ts;
|
|
15
|
+
* 服务缺席回 `unknown`),`sessionProjectionCache` 是标题的投影读面,`sessionPersistence` 是
|
|
16
|
+
* `projectDirOf` / `titleOf` 的公开 header 读面(workspaceRegistry 硬注入它,标准组合必有)。
|
|
17
|
+
* inject 一个可能没挂的服务 = 整个插件 pending;标题取不到时 `titleOf` 返回空串,正是契约允许的降级。
|
|
17
18
|
* - `agents`:只给 handle 捕获用(`ctx.get('agents')`;缺席时 `ctx.inject(['agents'])` 等服务就绪再装)。
|
|
18
19
|
* 它同样可能晚于本插件激活,写进插件 inject 只会让整个插件 pending。
|
|
19
20
|
*
|
|
@@ -1,7 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **缺席**只认 ENOENT 与 ENOTDIR("路径中间有一截不是目录"与"不存在"是同一种回答)。
|
|
3
|
+
*
|
|
4
|
+
* EACCES / EIO / ELOOP / 断挂载**不是缺席**:这些读数说明"我们看不见",不是"那里没有"。
|
|
5
|
+
* 破坏性动作(删目录、删附件对象、按"没有引用"清共享图)据此做决定,把读不出折成没有
|
|
6
|
+
* 就是数据消失;ADR-0039 是这条判据的裁决。
|
|
7
|
+
*/
|
|
8
|
+
export declare function isAbsentPath(error: unknown): boolean;
|
|
1
9
|
export interface FsPort {
|
|
2
10
|
/** 全部成员写成属性声明:端口方法会被**解构出来单独调**(`const { sizeOfDir } = port`,见下方
|
|
3
11
|
* 模块级递归的注释),实现体一律不读 `this`。方法简写的隐式 `this: FsPort` 会让
|
|
4
12
|
* `unbound-method` 把这种正常用法报成可疑;契约(返回的 Promise 形状)一字未动。 */
|
|
13
|
+
/** 路径在不在。**只有 ENOENT / ENOTDIR 回 `false`**;权限、盘挂、I/O 等读错误照抛——
|
|
14
|
+
* 调用方拿它当"缺席"判据时,读不出必须是失败,不是"没有"(ADR-0039)。 */
|
|
5
15
|
exists: (p: string) => Promise<boolean>;
|
|
6
16
|
/** 建目录(含中间层)。首删时 `~/.dsh/session-trash/` 还不存在,而 `rename` 不建父目录。 */
|
|
7
17
|
ensureDir: (p: string) => Promise<void>;
|
|
@@ -9,10 +9,12 @@ export interface HostIdentityPort {
|
|
|
9
9
|
* 宿主的「删除工作区」只删注册、保留目录与日志;恢复这类会话时跳过 attach,归入「未分组」。 */
|
|
10
10
|
workspaceExists(workspaceId: string): Promise<boolean>;
|
|
11
11
|
/** 会话落盘的**项目目录名**(`<sessions>/<projectKey(cwd)>`);账本里没有这个会话 ⇒ `undefined`。
|
|
12
|
-
*
|
|
12
|
+
* header 走公开 live/持久化读面;与 `workspaceOf` 同一口径:**未命中是正常的 no-op,不是故障**
|
|
13
|
+
* (存储真故障照抛)。 */
|
|
13
14
|
projectDirOf(sessionId: string): Promise<string | undefined>;
|
|
14
15
|
/** 删除时**尽力**取的会话标题;取不到返回空串,绝不因此让删除失败。
|
|
15
|
-
* 标题只存在于宿主自己的账本/缓存里(`FsPort` 不直读文件)⇒ 取数面归宿主端口,接官方投影缓存 API
|
|
16
|
+
* 标题只存在于宿主自己的账本/缓存里(`FsPort` 不直读文件)⇒ 取数面归宿主端口,接官方投影缓存 API;
|
|
17
|
+
* header 与 `projectDirOf` 走同一个公开读面。 */
|
|
16
18
|
titleOf(sessionId: string): Promise<string>;
|
|
17
19
|
isLive(sessionId: string): Promise<boolean>;
|
|
18
20
|
isArchived(sessionId: string): Promise<boolean>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isAbsentPath } from '../ports/fs-port.js';
|
|
1
2
|
import type { FsPort } from '../ports/fs-port.js';
|
|
2
3
|
import type { SessionDeleteConfig } from '../config.js';
|
|
3
4
|
import { type AttachmentCleanupWire } from '../shared/wire.js';
|
|
@@ -22,8 +23,10 @@ export type AttachmentRef = ImageRef | FileRef;
|
|
|
22
23
|
* 假支若按「是 string」取反会被 TS 收成 `never`(参数本来就是 string),插值就成了 never 读数。
|
|
23
24
|
* 这里判的仍是同一条正则,谓词只是把「形状」写进类型面。 */
|
|
24
25
|
export declare function isAttachmentId(value: unknown): value is `sha256:${string}`;
|
|
25
|
-
/**
|
|
26
|
-
|
|
26
|
+
/** 路径缺席的判据只有一处:`src/ports/fs-port.ts` 的 `isAbsentPath`(ENOENT / ENOTDIR)。
|
|
27
|
+
* `statFile` / `readFile` / `sizeOfDir` 的读错误里,"不在"只认这两枚;权限、盘挂、I/O 错误
|
|
28
|
+
* 都必须露成读不出(ADR-0039),别在这里另写一份只有 ENOENT 的抄本。 */
|
|
29
|
+
export declare const isMissing: typeof isAbsentPath;
|
|
27
30
|
/** 合法附件 ID → 宿主附件库里的绝对路径。`name` 不参与拼接。 */
|
|
28
31
|
export declare function attachmentPathOf(home: string, kind: 'image' | 'file', id: string): string;
|
|
29
32
|
/** 一条消息的 `content[]` 里的附件块;畸形 id / 非附件段一律跳过。 */
|
|
@@ -67,6 +70,16 @@ export interface ImageRemovalPlan {
|
|
|
67
70
|
* 剩余引用源读不出 ⇒ 整体跳过;候选日志读不出 / 附件对象 stat 失败 ⇒ 只跳过那一部分,其余照常。
|
|
68
71
|
*/
|
|
69
72
|
export declare function planImageAttachmentRemoval(deps: AttachmentReadDeps, removedDirs: readonly string[]): Promise<ImageRemovalPlan>;
|
|
73
|
+
/**
|
|
74
|
+
* 执行期复核:计划与真删对象之间隔着一整趟目录删除(秒级),这期间别的会话可能把同一张图
|
|
75
|
+
* (内容寻址 ⇒ 同一个 sha256 id)再引用一次,或派生存储新写一条引用。计划是数据、会过期;
|
|
76
|
+
* 删对象之前用同一套剩余引用扫描再判一次,**只删这一刻仍无引用的那些**(ADR-0041)。
|
|
77
|
+
*
|
|
78
|
+
* 调用时机:会话 / 回收站目录已经删掉之后、`executeImageAttachmentRemoval` 之前——那时被删的
|
|
79
|
+
* 引用源已经不在了,扫到的就是真正的"剩余"。读不出照旧 fail closed:回空计划 + `skipped`,
|
|
80
|
+
* 宁可留下孤儿也不删共享。空计划直接返回(不为零删付一次全 home 扫描)。
|
|
81
|
+
*/
|
|
82
|
+
export declare function recheckImageRemovalExclusivity(deps: AttachmentReadDeps, plan: ImageRemovalPlan): Promise<ImageRemovalPlan>;
|
|
70
83
|
/**
|
|
71
84
|
* 逐文件删;ENOENT 由端口的 `force` 吞掉;其他错误计数并继续。
|
|
72
85
|
*
|
|
@@ -21,5 +21,7 @@ export declare function routeError(code: RouteCode, httpStatus: number, message:
|
|
|
21
21
|
export declare function rollbackReason(label: string, error: unknown): string;
|
|
22
22
|
/** 原错误保留,回滚失败作为 `details.rollbackFailures` 上线;码仍按原错误的动词码,
|
|
23
23
|
* 没有可继承的就落 io。**内层的回滚失败要并进来**:一个成员自己退失败、兄弟也退失败时,
|
|
24
|
-
* 两份失败都得在 details 里,消息也不能出现第二个「回滚未完成」。
|
|
24
|
+
* 两份失败都得在 details 里,消息也不能出现第二个「回滚未完成」。
|
|
25
|
+
* **原错误 details 的其余键原样保留**:孤儿清理的部分回执(`removed` / `freedBytes` /
|
|
26
|
+
* `failedSessionId`)就挂在它上面,整份替换会把已经发生的删除报成 0。 */
|
|
25
27
|
export declare function withRollbackFailures(error: unknown, failures: readonly string[]): VerbError;
|
|
@@ -130,15 +130,20 @@ export declare function planOrphanRemoval(deps: CoreDeps, members: readonly {
|
|
|
130
130
|
*
|
|
131
131
|
* 顺序:整批摘归档集 → 摘有账本的成员的账本 → 逐条回收站行
|
|
132
132
|
* (在才删目录 → 摘清册行 → 通告成员离场)→ 逐条盘上成员(删目录 → 通告成员离场)→ 逐条附件对象。
|
|
133
|
-
* 目录删掉就没有"退回去"
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
* `
|
|
133
|
+
* 目录删掉就没有"退回去"这回事,中途失败**不回滚目录**;已经删掉的由下面的计数器如实交回。
|
|
134
|
+
* **归档态回滚**:`unarchive` 排在所有删除之前(免得留下"会话没了、归档集还挂着"的幽灵 id),
|
|
135
|
+
* 所以中途失败时目录还在、归档位却已经摘了。失败出口把**目录还在**的那些(这一趟没删掉、也不是计划时
|
|
136
|
+
* 就缺席)按删除前的读数重新归档(`isArchived` 先读过一次,不是按 `wasArchived` 猜);目录不在的跳过
|
|
137
|
+
* ——那时恢复归档只会造幽灵 id。
|
|
138
|
+
* 回滚自己的失败走 `details.rollbackFailures`,不让它把原错误吞掉(ADR-0040)。
|
|
139
|
+
* **附件计划在执行期复核**:计划到删对象之间的窗口里新增的引用会让计划过期;删对象前用同一套
|
|
140
|
+
* 剩余引用扫描重判一次,只删这一刻仍无引用的对象(ADR-0041)。
|
|
137
141
|
*
|
|
138
142
|
* 失败形状:
|
|
139
143
|
* - `kind:'orphan'`(orphan-clean)⇒ `io` + `{removed, freedBytes, failedSessionId}`,不伪装成整组没动;
|
|
140
144
|
* - `kind:'trash'`(purge)⇒ 同一个标签、不带 details;
|
|
141
|
-
* - orphan-clean
|
|
145
|
+
* - orphan-clean 的归档实况预读 / unarchive / detach 原样抛出;
|
|
146
|
+
* - 归档态回滚不干净时,原错误带 `details.rollbackFailures`(码仍按原错误的动词码)。
|
|
142
147
|
*
|
|
143
148
|
* 通告只经 `member-presence`(摘活体三态 + `api-session/removed`),不在这里另写一份。
|
|
144
149
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xrn1997/dsh-session-delete",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "在 DeepSeek Harness 里删除会话:删除=移入回收站(可恢复),另设显式彻底删除",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "pnpm@11.25.0",
|
|
@@ -47,6 +47,11 @@
|
|
|
47
47
|
"@deepseek-ai/cordis": "^4.0.4",
|
|
48
48
|
"react": "^18.3.1"
|
|
49
49
|
},
|
|
50
|
+
"peerDependenciesMeta": {
|
|
51
|
+
"react": {
|
|
52
|
+
"optional": true
|
|
53
|
+
}
|
|
54
|
+
},
|
|
50
55
|
"devDependencies": {
|
|
51
56
|
"@deepseek-ai/cordis": "^4.0.4",
|
|
52
57
|
"@eslint/js": "^10.0.1",
|
|
@@ -63,6 +68,8 @@
|
|
|
63
68
|
"jsdom": "^26.1.0",
|
|
64
69
|
"react": "^18.3.1",
|
|
65
70
|
"react-dom": "18.3.1",
|
|
71
|
+
"react-markdown": "^10.1.0",
|
|
72
|
+
"remark-gfm": "^4.0.1",
|
|
66
73
|
"semver": "^7.8.5",
|
|
67
74
|
"tsdown": "0.23.0",
|
|
68
75
|
"typescript": "5.9.3",
|
|
@@ -75,7 +82,8 @@
|
|
|
75
82
|
},
|
|
76
83
|
"client": {
|
|
77
84
|
"inject": [
|
|
78
|
-
"@deepseek-ai/dsh-client-locale"
|
|
85
|
+
"@deepseek-ai/dsh-client-locale",
|
|
86
|
+
"@deepseek-ai/dsh-client-ui-context-menu"
|
|
79
87
|
],
|
|
80
88
|
"platform": "web"
|
|
81
89
|
},
|
|
@@ -85,7 +93,8 @@
|
|
|
85
93
|
"0.2.1-rc.1": "compatible",
|
|
86
94
|
"0.2.1-rc.2": "compatible",
|
|
87
95
|
"0.2.1-rc.3": "compatible",
|
|
88
|
-
"0.2.1-rc.5": "compatible"
|
|
96
|
+
"0.2.1-rc.5": "compatible",
|
|
97
|
+
"0.2.2-rc.1": "compatible"
|
|
89
98
|
}
|
|
90
99
|
}
|
|
91
100
|
},
|
|
@@ -109,9 +118,5 @@
|
|
|
109
118
|
"delete"
|
|
110
119
|
],
|
|
111
120
|
"author": "xrn1997",
|
|
112
|
-
"license": "Apache-2.0"
|
|
113
|
-
"dependencies": {
|
|
114
|
-
"react-markdown": "^10.1.0",
|
|
115
|
-
"remark-gfm": "^4.0.1"
|
|
116
|
-
}
|
|
121
|
+
"license": "Apache-2.0"
|
|
117
122
|
}
|