@sunshaobei/dsh-session-manager 0.0.0-stage → 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/LICENSE +21 -0
- package/README.md +115 -2
- package/README.zh.md +115 -0
- package/client.css +1613 -0
- package/client.js +2189 -0
- package/cordis.patch.yml +16 -0
- package/index.js +78 -0
- package/package.json +61 -4
- package/packages/session-trash-host/lib/index.js +1904 -0
- package/packages/session-trash-host/lib/types/index.d.ts +32 -0
- package/packages/session-trash-host/package.json +26 -0
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Bundle patch for dsh-session-manager.
|
|
2
|
+
#
|
|
3
|
+
# This is a top-level YAML array of loader patch entries — the format
|
|
4
|
+
# `dsh` composes when it boots a profile: each bundle in
|
|
5
|
+
# `dsh.profile.bundles` contributes its patch list, applied in bundle order
|
|
6
|
+
# over the profile root (after dsh-base / dsh-web-app, before the profile's
|
|
7
|
+
# own cordis.patch.yml).
|
|
8
|
+
#
|
|
9
|
+
# The single row mounts the bundle's node half as a host plugin (the row's
|
|
10
|
+
# `name` is a bare package name resolved through the profile's node_modules).
|
|
11
|
+
# The browser half joins the client module graph automatically: this
|
|
12
|
+
# package's manifest declares `dsh.client` (platform: web) and exports
|
|
13
|
+
# "./client", so dsh-client-modules serves that bundle into the browser.
|
|
14
|
+
- insert:
|
|
15
|
+
- id: session-trash
|
|
16
|
+
name: dsh-session-manager
|
package/index.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Node half of the session-trash bundle — a BYTE-STABLE loader shim.
|
|
6
|
+
*
|
|
7
|
+
* Mounted by the loader row `session-trash` (see cordis.patch.yml) in the
|
|
8
|
+
* host plane of the profile process. All real logic lives in
|
|
9
|
+
* ./packages/session-trash-host/lib/index.js ("the impl").
|
|
10
|
+
*
|
|
11
|
+
* WHY A SHIM WITH A CONTENT-HASHED DYNAMIC IMPORT (v0.3.3):
|
|
12
|
+
*
|
|
13
|
+
* Every in-process activation path — the market's hot mount (uninstall →
|
|
14
|
+
* install), a loader entry update, a disable → enable cycle — imports this
|
|
15
|
+
* package by the same module URL, so Node's ESM cache keeps returning the
|
|
16
|
+
* FIRST module object this process ever loaded. A version installed over a
|
|
17
|
+
* running dsh web therefore kept executing the OLD code (observed as:
|
|
18
|
+
* reinstall left the recycle-bin list reading 0 轮对话 while the preview,
|
|
19
|
+
* whose routes are rebuilt per mount, kept working — only a restart
|
|
20
|
+
* reloaded the new files). The shim breaks that stale-module cycle:
|
|
21
|
+
*
|
|
22
|
+
* - This file MUST NEVER CHANGE across versions. A cached old shim is
|
|
23
|
+
* harmless because its only job is to load the CURRENT impl from disk.
|
|
24
|
+
* (Any change to this file itself needs a process restart to apply.)
|
|
25
|
+
* - apply() imports the impl through `?<sha256-of-file>` — identical
|
|
26
|
+
* content reuses the cached module, changed content (a new version on
|
|
27
|
+
* disk) gets a fresh URL and therefore fresh code, in-process.
|
|
28
|
+
*
|
|
29
|
+
* IMPORTANT — no `export default` here. The loader's `unwrapExports`
|
|
30
|
+
* collapses `exports.default ?? exports`, so a default export would discard
|
|
31
|
+
* the module namespace — and with it the named `inject` export — leaving
|
|
32
|
+
* the plugin mounted with no dependencies: `apply()` would run immediately,
|
|
33
|
+
* before the host services exist, and the plugin would silently no-op.
|
|
34
|
+
* With the namespace preserved, cordis sees `{ apply, inject }` and waits
|
|
35
|
+
* for the injected services, exactly like published bundles.
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
/** Implementation module, resolved next to this (possibly cached) shim. */
|
|
39
|
+
const IMPL_URL = new URL('./packages/session-trash-host/lib/index.js', import.meta.url);
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Import the impl, cache-busted by its own content hash. Falls back to the
|
|
43
|
+
* plain URL when the file cannot be read (the import will then surface the
|
|
44
|
+
* real error, or reuse the cached module — the pre-shim behaviour).
|
|
45
|
+
*/
|
|
46
|
+
async function loadImpl() {
|
|
47
|
+
let href = IMPL_URL.href;
|
|
48
|
+
try {
|
|
49
|
+
const bytes = await readFile(IMPL_URL);
|
|
50
|
+
const hash = createHash('sha256').update(bytes).digest('hex').slice(0, 16);
|
|
51
|
+
href = `${IMPL_URL.href}?v=${hash}`;
|
|
52
|
+
} catch {
|
|
53
|
+
// Unreadable impl: fall back to the plain URL so the import itself can
|
|
54
|
+
// surface the real error. (Import failures must NEVER be swallowed
|
|
55
|
+
// here — a fallback to the cached module would silently run old code.)
|
|
56
|
+
}
|
|
57
|
+
return await import(/* @vite-ignore */ href);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export const inject = ['sessionPersistence', 'workspaceRegistry', 'webServer'];
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Mount the host service. Runs only after the injected services are up.
|
|
64
|
+
* @param {import('@deepseek-ai/cordis').Context} ctx
|
|
65
|
+
*/
|
|
66
|
+
export async function apply(ctx) {
|
|
67
|
+
// 防重复:sessionTrashHost 是本插件自身提供的服务,不能声明为 inject,
|
|
68
|
+
// 用 ctx.get() 安全访问(不触发 cordis 属性守卫)。
|
|
69
|
+
if (ctx.get('sessionTrashHost')) return;
|
|
70
|
+
const mod = await loadImpl();
|
|
71
|
+
// Re-check after the await: a concurrent apply may have mounted meanwhile.
|
|
72
|
+
if (ctx.get('sessionTrashHost')) return;
|
|
73
|
+
// NOTE: deliberately NOT returned. A returned fiber is a thenable whose
|
|
74
|
+
// resolved value is the fiber object itself, which cordis's effect
|
|
75
|
+
// collector rejects with "Invalid effect" at boot; returning undefined
|
|
76
|
+
// keeps the battle-tested pre-shim behaviour.
|
|
77
|
+
ctx.plugin(mod.SessionTrashHost);
|
|
78
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,63 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sunshaobei/dsh-session-manager",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.6.0",
|
|
4
|
+
"description": "DSH 会话回收站:会话详情归档入口、回收站多选还原/彻底删除、活跃会话保护。 · Session trash & permanent delete for DeepSeek Harness.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./index.js",
|
|
9
|
+
"./client": "./client.js",
|
|
10
|
+
"./package.json": "./package.json"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"index.js",
|
|
14
|
+
"client.js",
|
|
15
|
+
"client.css",
|
|
16
|
+
"cordis.patch.yml",
|
|
17
|
+
"packages/session-trash-host/lib",
|
|
18
|
+
"packages/session-trash-host/package.json"
|
|
19
|
+
],
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"keywords": [
|
|
22
|
+
"deepseek-harness",
|
|
23
|
+
"dsh",
|
|
24
|
+
"dsh-plugin",
|
|
25
|
+
"cordis",
|
|
26
|
+
"session",
|
|
27
|
+
"trash",
|
|
28
|
+
"recycle-bin",
|
|
29
|
+
"session-management"
|
|
30
|
+
],
|
|
31
|
+
"repository": "https://github.com/sunshaobei/dsh-session-manager.git",
|
|
32
|
+
"homepage": "https://github.com/sunshaobei/dsh-session-manager#readme",
|
|
33
|
+
"bugs": {
|
|
34
|
+
"url": "https://github.com/sunshaobei/dsh-session-manager/issues"
|
|
35
|
+
},
|
|
36
|
+
"dsh": {
|
|
37
|
+
"displayName": "DSH 会话回收站",
|
|
38
|
+
"description": "DSH 会话回收站:会话详情归档入口、回收站多选还原/彻底删除、活跃会话保护。",
|
|
39
|
+
"engines": {
|
|
40
|
+
"dsh": ">=0.2.0-rc.2"
|
|
41
|
+
},
|
|
42
|
+
"homepage": "https://github.com/sunshaobei/dsh-session-manager",
|
|
43
|
+
"repository": "https://github.com/sunshaobei/dsh-session-manager",
|
|
44
|
+
"bundle": {
|
|
45
|
+
"patch": "./cordis.patch.yml"
|
|
46
|
+
},
|
|
47
|
+
"client": {
|
|
48
|
+
"platform": "web",
|
|
49
|
+
"inject": [
|
|
50
|
+
"@deepseek-ai/dsh-client-ui-settings",
|
|
51
|
+
"@deepseek-ai/dsh-client-ui-conversation"
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"scripts": {
|
|
56
|
+
"test": "node --test \"tests/*.test.js\"",
|
|
57
|
+
"prepublishOnly": "npm test",
|
|
58
|
+
"verify:host": "node scripts/verify-real-host.mjs"
|
|
59
|
+
},
|
|
60
|
+
"engines": {
|
|
61
|
+
"node": ">=20"
|
|
62
|
+
}
|
|
63
|
+
}
|