@xrn1997/dsh-session-delete 0.4.0 → 0.6.0
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 +39 -10
- package/cordis.patch.yml +4 -0
- package/icon.svg +18 -18
- package/lib/client.js +1897 -859
- package/lib/index.js +1803 -1058
- package/lib/types/api/attachment-orphans.d.ts +9 -3
- package/lib/types/api/attachment.d.ts +17 -7
- package/lib/types/api/connection-route.d.ts +23 -0
- package/lib/types/api/dispatch.d.ts +25 -14
- package/lib/types/api/route-table.d.ts +47 -11
- package/lib/types/api/trash-rows.d.ts +3 -3
- package/lib/types/client/batch-bar.d.ts +1 -1
- package/lib/types/client/batch-pick.d.ts +19 -0
- package/lib/types/client/batch-select.d.ts +7 -5
- package/lib/types/client/busy-gate.d.ts +6 -2
- package/lib/types/client/confirm-close.d.ts +4 -1
- package/lib/types/client/context.d.ts +3 -2
- package/lib/types/client/copy.d.ts +54 -4
- package/lib/types/client/delete-confirm.d.ts +1 -1
- package/lib/types/client/delete-menu-item.d.ts +1 -1
- package/lib/types/client/host-rows.d.ts +29 -30
- package/lib/types/client/main-view.d.ts +2 -1
- package/lib/types/client/markdown.d.ts +6 -7
- package/lib/types/client/orphan-maintenance.d.ts +10 -25
- package/lib/types/client/pending-open.d.ts +17 -0
- package/lib/types/client/receipt.d.ts +3 -1
- package/lib/types/client/remote.d.ts +21 -18
- package/lib/types/client/store.d.ts +15 -10
- package/lib/types/client/trash-detail.d.ts +48 -6
- package/lib/types/client/trash-entry.d.ts +1 -1
- package/lib/types/client/trash-nav.d.ts +12 -8
- package/lib/types/client/ui/Toast.d.ts +3 -1
- package/lib/types/client/ui/icons.d.ts +1 -1
- package/lib/types/client/undo-toast.d.ts +2 -1
- package/lib/types/client/use-maintenance-section.d.ts +52 -0
- package/lib/types/client/use-maintenance.d.ts +7 -35
- package/lib/types/client/use-trash-panel-controller.d.ts +35 -14
- package/lib/types/client/use-trash-query.d.ts +10 -8
- package/lib/types/client/use-trash-selection.d.ts +15 -12
- package/lib/types/client/write-seats.d.ts +32 -16
- package/lib/types/client/write-settlement.d.ts +1 -1
- package/lib/types/client/write.d.ts +13 -3
- package/lib/types/config.d.ts +45 -0
- package/lib/types/deps.d.ts +8 -3
- package/lib/types/domain/closure.d.ts +47 -0
- package/lib/types/index.d.ts +13 -12
- package/lib/types/log/zstd-frames.d.ts +2 -3
- package/lib/types/ports/attachments-port.d.ts +40 -0
- package/lib/types/ports/fs-port.d.ts +15 -12
- package/lib/types/ports/host-port.d.ts +4 -5
- package/lib/types/ports/presence-port.d.ts +9 -0
- package/lib/types/shared/wire.d.ts +137 -31
- package/lib/types/trash/attachments.d.ts +10 -1
- package/lib/types/trash/detail.d.ts +32 -22
- package/lib/types/trash/entry.d.ts +7 -1
- package/lib/types/trash/groups.d.ts +6 -1
- package/lib/types/trash/manifest.d.ts +4 -4
- package/lib/types/verbs/batch-carried.d.ts +1 -3
- package/lib/types/verbs/live-admission.d.ts +1 -1
- package/lib/types/verbs/member-presence.d.ts +3 -1
- package/lib/types/verbs/move-group.d.ts +2 -1
- package/lib/types/verbs/orphan-subagents.d.ts +12 -5
- package/lib/types/verbs/permanent-removal.d.ts +39 -10
- package/lib/types/verbs/trash-scope.d.ts +36 -0
- package/locale/en.json +6 -6
- package/locale/zh.json +6 -6
- package/package.json +13 -3
- package/lib/types/api/request-trust.d.ts +0 -45
- package/lib/types/ports/connection-port.d.ts +0 -33
- package/lib/types/verbs/purge-trash.d.ts +0 -35
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { TrashEntry } from '../trash/entry.js';
|
|
2
|
+
import type { RemovalDeps } from '../deps.js';
|
|
3
|
+
import type { PurgeStatsWire } from '../shared/wire.js';
|
|
4
|
+
import { type OrphanGroup } from './orphan-subagents.js';
|
|
5
|
+
/**
|
|
6
|
+
* **清册作用域(trash scope)**:purge 这条写路径的「拿目标」owner。调用方把一份选好读面的清册
|
|
7
|
+
* 快照交进来(写入口 = 真相读;报告入口不经作用域——`/orphans` 直接把 raw 快照交 `loadOrphanGroups`。
|
|
8
|
+
* 选哪一格是路由行 / 批量层的事,ADR-0012 的边界不在这里翻),快照与**收缩视图**从此归本模块、
|
|
9
|
+
* **不外露**:三态判据与按组收缩都仍读 `trash/groups.ts` 的 `claimOf` / `withoutGroup`,这里只**持有**
|
|
10
|
+
* 那份视图,不抄第二遍判据。三个成员的输入输出以 `CONTEXT.md` 的「清册作用域」与下面各成员的
|
|
11
|
+
* 注释为准,头注不重写一遍表面契约。
|
|
12
|
+
*
|
|
13
|
+
* 彻底删除:从回收站里**真的**抹掉一组(或整站),并连带那些"还留在盘上、没被带走"的后代。
|
|
14
|
+
* **这里只做两件事:拿目标、把计划交给执行器**。量目录、筛盘上后代、活体准入与"先退归档集、
|
|
15
|
+
* 再摘账本、最后删目录"的顺序都住 `verbs/permanent-removal.ts`——计划只读,执行器不再量、只在第一笔
|
|
16
|
+
* 写前补一次只读的活体复查,计划是执行前的第一道闸(别在这里再长出一段手写步骤)。
|
|
17
|
+
*
|
|
18
|
+
* **不做回滚**:目录删掉就没有"退回去"这回事(删到一半失败时已删目录不回滚;带部分计数的
|
|
19
|
+
* `details` 回执只属于 `orphan-clean`,purge 的 `removed` / `freedBytes` 仍只在成功回执里给)。
|
|
20
|
+
* 对应地,`kind:'trash'` 的计划失败时执行器只抛那一步的 `io` 与原文、不带 details。
|
|
21
|
+
*
|
|
22
|
+
* 回执里的 `attachments` 原样来自执行器:独占图片在会话目录删完之后才清,附件失败只计数、不改
|
|
23
|
+
* `removed` / `freedBytes`(`skipped` = 有候选或剩余引用源读不出、这一轮部分或整体没清,原因上屏)。
|
|
24
|
+
* 「已被同批前一条带走」的幂等回执**不带** `attachments`——那一趟没有附件读数,缺席与 0 是两件事,
|
|
25
|
+
* 不拿零冒充"清过"(与旧批量回执同形)。
|
|
26
|
+
*/
|
|
27
|
+
export interface TrashScope {
|
|
28
|
+
/** purge 这一组;已被同批带走 ⇒ `{removed:0,freedBytes:0}`;absent(原始快照里就认不出)⇒
|
|
29
|
+
* `trash-empty`,原文点名 id。 */
|
|
30
|
+
purge(id: string): Promise<PurgeStatsWire>;
|
|
31
|
+
/** 清空:全部行一组。 */
|
|
32
|
+
purgeAll(): Promise<PurgeStatsWire>;
|
|
33
|
+
/** 点名根的无主组(根两边去 `session-` 前缀再比);roots 缺席 = 全量。 */
|
|
34
|
+
orphanGroups(roots?: readonly string[]): Promise<readonly OrphanGroup[]>;
|
|
35
|
+
}
|
|
36
|
+
export declare function createTrashScope(deps: RemovalDeps, rows: readonly TrashEntry[]): TrashScope;
|
package/locale/en.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
{
|
|
2
|
-
"meta": {
|
|
3
|
-
"title": "Session Delete",
|
|
4
|
-
"description": "Delete sessions: delete moves them to a recoverable trash, with an explicit permanent delete."
|
|
5
|
-
}
|
|
6
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"meta": {
|
|
3
|
+
"title": "Session Delete",
|
|
4
|
+
"description": "Delete sessions: delete moves them to a recoverable trash, with an explicit permanent delete."
|
|
5
|
+
}
|
|
6
|
+
}
|
package/locale/zh.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
{
|
|
2
|
-
"meta": {
|
|
3
|
-
"title": "会话删除",
|
|
4
|
-
"description": "删除会话:删除 = 移入回收站(可恢复),另设显式的彻底删除。"
|
|
5
|
-
}
|
|
6
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"meta": {
|
|
3
|
+
"title": "会话删除",
|
|
4
|
+
"description": "删除会话:删除 = 移入回收站(可恢复),另设显式的彻底删除。"
|
|
5
|
+
}
|
|
6
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xrn1997/dsh-session-delete",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "在 DeepSeek Harness 里删除会话:删除=移入回收站(可恢复),另设显式彻底删除",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "pnpm@11.25.0",
|
|
@@ -36,8 +36,12 @@
|
|
|
36
36
|
"scripts": {
|
|
37
37
|
"build": "tsdown && tsc -p tsconfig.build.json",
|
|
38
38
|
"typecheck": "tsc --noEmit",
|
|
39
|
+
"lint": "eslint .",
|
|
39
40
|
"test": "vitest run",
|
|
40
|
-
"
|
|
41
|
+
"test:watch": "vitest",
|
|
42
|
+
"pack:dry": "npm pack --dry-run --ignore-scripts",
|
|
43
|
+
"prepack": "npm run build",
|
|
44
|
+
"gates": "pnpm typecheck && pnpm lint && pnpm test && pnpm build && pnpm run pack:dry"
|
|
41
45
|
},
|
|
42
46
|
"peerDependencies": {
|
|
43
47
|
"@deepseek-ai/cordis": "^4.0.4",
|
|
@@ -45,6 +49,7 @@
|
|
|
45
49
|
},
|
|
46
50
|
"devDependencies": {
|
|
47
51
|
"@deepseek-ai/cordis": "^4.0.4",
|
|
52
|
+
"@eslint/js": "^10.0.1",
|
|
48
53
|
"@testing-library/dom": "^10.4.2",
|
|
49
54
|
"@testing-library/jest-dom": "^6.10.0",
|
|
50
55
|
"@testing-library/react": "^16.3.3",
|
|
@@ -52,12 +57,16 @@
|
|
|
52
57
|
"@types/react": "18.3.31",
|
|
53
58
|
"@types/react-dom": "18.3.5",
|
|
54
59
|
"@types/semver": "^7.8.0",
|
|
60
|
+
"eslint": "^10.14.0",
|
|
61
|
+
"eslint-plugin-react-hooks": "^7.1.1",
|
|
62
|
+
"globals": "^17.13.0",
|
|
55
63
|
"jsdom": "^26.1.0",
|
|
56
64
|
"react": "^18.3.1",
|
|
57
65
|
"react-dom": "18.3.1",
|
|
58
66
|
"semver": "^7.8.5",
|
|
59
67
|
"tsdown": "0.23.0",
|
|
60
68
|
"typescript": "5.9.3",
|
|
69
|
+
"typescript-eslint": "^8.72.1",
|
|
61
70
|
"vitest": "3.2.7"
|
|
62
71
|
},
|
|
63
72
|
"dsh": {
|
|
@@ -75,7 +84,8 @@
|
|
|
75
84
|
"0.2.0-rc.2": "compatible",
|
|
76
85
|
"0.2.1-rc.1": "compatible",
|
|
77
86
|
"0.2.1-rc.2": "compatible",
|
|
78
|
-
"0.2.1-rc.3": "compatible"
|
|
87
|
+
"0.2.1-rc.3": "compatible",
|
|
88
|
+
"0.2.1-rc.5": "compatible"
|
|
79
89
|
}
|
|
80
90
|
}
|
|
81
91
|
},
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 请求栅栏:判一条打到 `/dsh-session-delete-api` 的请求归不归本插件办。
|
|
3
|
-
*
|
|
4
|
-
* 两件事分开:**归属**(Host / Origin / Referer 是不是本次部署自己的)与**身份**(远程客户端是不是
|
|
5
|
-
* 宿主的已认证 Web 客户端)。绑定策略归宿主 webserver 配置——它只接受具体接口 IP 字面量、拒绝
|
|
6
|
-
* wildcard——所以「谁能到达」不是本插件能替它决定的事;栅栏本身只防 browser confused deputy,
|
|
7
|
-
* 身份留给宿主(见 ②)。口径与宿主 `/api` 的 `isTrustedApiRequest`(asar
|
|
8
|
-
* `dsh-client-connection/lib/index.js`)对齐,差别只有一条:本模块多查 Referer,因为
|
|
9
|
-
* `GET /attachment` 是二进制段(见末段)。
|
|
10
|
-
*
|
|
11
|
-
* 两条放行支,外加一条缺席规则:
|
|
12
|
-
* ① 头栅栏全过 ∧ 源地址回环 ∧ Host 属于本次部署(回环名 / 监听 bind 字面量)——本机工具与转发落在
|
|
13
|
-
* 回环的桌面壳;
|
|
14
|
-
* ② 宿主 `connection` 服务的 `requestRejection` 放行——远程浏览器。它自带宿主的 Host 白名单
|
|
15
|
-
* (含部署声明的 `trustedHosts`)与「已认证 live peer」,身份就是那次 `dsh web` 打印的 URL 换来的
|
|
16
|
-
* 签名 cookie,不在本插件里复刻;
|
|
17
|
-
* ③ 身份层缺席(`src/ports/connection-port.ts` 报 `absent`,宿主无 `connection` 服务或成员改名)
|
|
18
|
-
* ⇒ 远程一律拒(fail-closed:退回「只有本机」,LAN 上表现为 403 而不是静默放行)。
|
|
19
|
-
*
|
|
20
|
-
* **DNS rebinding 由 Host 归属判据挡**:`Origin === Host` 只证两者同名,不证这个名字属于本部署;
|
|
21
|
-
* 回环 socket 也不构成豁免(重绑到 `127.0.0.1` 的攻击正是回环源地址)。对浏览器来说 Host 是重绑伪造
|
|
22
|
-
* 不了的那个头——它按连接目标填,而 `Origin` 是页面自己的名字——所以归属判定先于任何本机 / 远程
|
|
23
|
-
* 分支,别在它前面加 fast-path。
|
|
24
|
-
*
|
|
25
|
-
* 末段:`GET /attachment` 的响应不是 opaque 的「读不出内容」——页面若已知某个 `sha256:…` 内容哈希,
|
|
26
|
-
* 就能把它当 `<img src>` 跨源渲染出来。那条请求不带 Origin,靠 Referer 判同源挡;宿主 `/api` 没有
|
|
27
|
-
* 二进制段,所以它的栅栏不需要这一条。
|
|
28
|
-
*/
|
|
29
|
-
import type { IncomingMessage } from 'node:http';
|
|
30
|
-
import type { ConnectionPort } from '../ports/connection-port.js';
|
|
31
|
-
export type RequestTrustVerdict = 'allowed' | 'untrusted' | 'unauthenticated';
|
|
32
|
-
export interface RequestTrustFacts {
|
|
33
|
-
/** 监听器绑定的那个具体接口 IP 字面量;老代次没有这个 getter 时为 `undefined`(bind 支退化,仍 fail-closed)。 */
|
|
34
|
-
readonly bindHost: string | undefined;
|
|
35
|
-
/** 宿主的 Web 身份面;端口每次请求惰性解析服务,缺席由它报 `absent`。 */
|
|
36
|
-
readonly connection: ConnectionPort;
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* 这条请求归不归本插件办。`untrusted` = 归属不对(跨源 / 重绑 / 头不成形);`unauthenticated` =
|
|
40
|
-
* 归属对但远程客户端没带宿主身份(原文会提示用 `dsh web` 打印的 URL 打开)。
|
|
41
|
-
*
|
|
42
|
-
* 远程支的两个失败裁决由端口翻译宿主的区分(401 = 缺身份、403 = 归属不对)。身份层缺席(端口报
|
|
43
|
-
* `absent`)一律按归属不对处理:那时没有可换的身份,不能让原文提示用户去补一个不存在的东西。
|
|
44
|
-
*/
|
|
45
|
-
export declare function judgeRequest(req: IncomingMessage, facts: RequestTrustFacts): RequestTrustVerdict;
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 宿主 `connection` 服务(`dsh-client-connection` 的 `HostConnectionService`,`super(ctx, "connection")`)
|
|
3
|
-
* 的窄镜像:`requestRejection(request)` 一次做宿主 `/api` 的那两道——Host/Origin 栅栏与「已认证 live peer」。
|
|
4
|
-
*
|
|
5
|
-
* **每次请求惰性解析服务**,不在激活时取一次:插件与 `client-connection` 的激活顺序没有承诺,取早了
|
|
6
|
-
* 会让远程支永远缺席(LAN 上全 403 且难排查)。`ctx.get` 是同步查表,代价可以忽略。
|
|
7
|
-
*
|
|
8
|
-
* **状态码在这里翻成裁决**(401 = 归属对、缺身份;403 = 归属不对;其余按归属不对处理),
|
|
9
|
-
* 调用方拿到的就是自己的词表,不需要知道宿主用哪个码表达哪件事。成员名与返回值按 asar
|
|
10
|
-
* `dsh-client-connection/lib/index.js` 原文读实。
|
|
11
|
-
*/
|
|
12
|
-
import type { IncomingMessage } from 'node:http';
|
|
13
|
-
import type { Context } from '@deepseek-ai/cordis';
|
|
14
|
-
export type ConnectionVerdict = {
|
|
15
|
-
readonly kind: 'allowed';
|
|
16
|
-
}
|
|
17
|
-
/** 组成里没有这个服务(无 web 组成 / 老代次)——调用方 fail-closed。 */
|
|
18
|
-
| {
|
|
19
|
-
readonly kind: 'absent';
|
|
20
|
-
}
|
|
21
|
-
/** 宿主认可归属,但这条请求没带已认证身份。 */
|
|
22
|
-
| {
|
|
23
|
-
readonly kind: 'unauthenticated';
|
|
24
|
-
}
|
|
25
|
-
/** 宿主不认可归属(Host/Origin 栅栏不过,或它给出的其余状态码)。 */
|
|
26
|
-
| {
|
|
27
|
-
readonly kind: 'untrusted';
|
|
28
|
-
};
|
|
29
|
-
export interface ConnectionPort {
|
|
30
|
-
verdictFor(req: IncomingMessage): ConnectionVerdict;
|
|
31
|
-
}
|
|
32
|
-
/** 成员抛错按「归属不对」拒绝(fail-closed)。 */
|
|
33
|
-
export declare function createConnectionPort(ctx: Context): ConnectionPort;
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import type { TrashEntry } from '../trash/entry.js';
|
|
2
|
-
import type { RemovalDeps } from '../deps.js';
|
|
3
|
-
import type { AttachmentCleanupWire } from '../shared/wire.js';
|
|
4
|
-
/**
|
|
5
|
-
* 彻底删除:从回收站里**真的**抹掉一条(或整组、或整站),并连带那些"还留在盘上、没被带走"的后代。
|
|
6
|
-
*
|
|
7
|
-
* 与另外两个动词的关系(ADR-0002):它的 interface 是"这一组目标 + 一份只读清册快照
|
|
8
|
-
*(targets 缺席 = 清空)";目标由 `verbs/batch-carried.ts` 按组语义算好,批量的"已被同批前一条
|
|
9
|
-
* 带走"判据不在这里。`requestedId` 是唯一的例外参数,但它**不参与任何判据**:只是让
|
|
10
|
-
* `trash-empty` 的原文点得出用户点的是哪一条(原文要上屏,点名承重),批量语义仍在批量层。
|
|
11
|
-
*
|
|
12
|
-
* **这条动词只做两件事:拿目标、把计划交给执行器**。量目录、筛盘上后代、活体准入与"先退归档集、
|
|
13
|
-
* 再摘账本、最后删目录"的顺序都住 `verbs/permanent-removal.ts`——计划只读,执行器只写,计划就是
|
|
14
|
-
* 执行前的闸(别在这里再长出一段手写步骤)。
|
|
15
|
-
*
|
|
16
|
-
* **这条动词不做回滚**:目录删掉就没有"退回去"这回事(删到一半失败时已删目录不回滚;
|
|
17
|
-
* 带部分计数的 `details` 回执只属于 `orphan-clean`,purge 的 `removed` / `freedBytes` 仍只在成功回执里给)。
|
|
18
|
-
* 对应地,`kind:'trash'` 的计划失败时执行器只抛那一步的 `io` 与原文、不带 details。
|
|
19
|
-
*
|
|
20
|
-
* 回执里的 `attachments` 原样来自执行器:独占图片在会话目录删完之后才清,附件失败只计数、不改
|
|
21
|
-
* `removed` / `freedBytes`(`skipped` = 有候选或剩余引用源读不出、这一轮部分或整体没清,原因上屏)。
|
|
22
|
-
*/
|
|
23
|
-
export declare function purgeTrash(deps: RemovalDeps): (
|
|
24
|
-
/** 这一组(只读);`undefined` = 清空。批量层由 `batch-carried.ts` 的 `claimOf` 给出,直调者
|
|
25
|
-
* 按 `trash/groups.ts` 的 `groupOf` 自己算;ghost 父的组只有孩子(不含 `requestedId`),照样清
|
|
26
|
-
* 这一组。 */
|
|
27
|
-
targets: readonly TrashEntry[] | undefined,
|
|
28
|
-
/** **只读**清册快照:批量层已经读过一次就递下来;收缩归 `batch-carried.ts`,动词不碰它。 */
|
|
29
|
-
rows: readonly TrashEntry[],
|
|
30
|
-
/** 只用于 `trash-empty` 的原文要点名用户点的那一条;不参与任何判据(批量语义归 `batch-carried.ts`)。 */
|
|
31
|
-
requestedId?: string) => Promise<{
|
|
32
|
-
removed: number;
|
|
33
|
-
freedBytes: number;
|
|
34
|
-
attachments: AttachmentCleanupWire;
|
|
35
|
-
}>;
|