dsh-session-toolbox 0.1.1 → 0.1.3
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 +9 -0
- package/cordis.patch.yml +2 -2
- package/lib/client.js +28 -12
- package/lib/client.js.map +2 -2
- package/lib/{host-v0.1.1.js → host-v0.1.3.js} +7 -6
- package/lib/host.js +7 -6
- package/lib/index.js +7 -6
- package/lib/index.js.map +2 -2
- package/package.json +7 -6
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,15 @@
|
|
|
4
4
|
|
|
5
5
|
本项目遵循 [语义化版本](https://semver.org/lang/zh-CN/)。版本号从 `0.1` 起;DSH 宿主接口(`workspaceRegistry` / `sessionPersistence` / `webServer` 服务面与 `~/.dsh/sessions` 布局)在 0.x 期间按 `0.2.0-rc.2` 基线验证,每次官方升级会重验并在此记录。
|
|
6
6
|
|
|
7
|
+
## 0.1.3
|
|
8
|
+
|
|
9
|
+
- 修复草稿图片反复新增:恢复草稿时派发的合成粘贴会被插件自己的捕获器再次存一份,切会话越多份数越多。现在恢复事件带内部标记、捕获器直接忽略;同时按内容哈希做同会话去重,同一张图即使重复粘贴也只保留一份(新增 2 项回归测试)。
|
|
10
|
+
|
|
11
|
+
## 0.1.2
|
|
12
|
+
|
|
13
|
+
- 修复与 DSH `0.2.1-rc.2` 的不兼容:此前把官方内部包固定为精确版本 `0.2.0-rc.2`,导致 DSH 升级 rc 后被判为不兼容。改为声明 `engines.dsh`(官方优先判定字段,见 `dsh-app-boot` 的 `unmetRequirements`)+ 区间 peer,覆盖 `0.2.0-rc.2` 至 `0.2.x`;`0.3.0` 起仍会正确判为不兼容。
|
|
14
|
+
- 已针对 `@deepseek-ai/dsh-home-paths` / `dsh-atomic-write` `0.2.1-rc.2`、`cordis` `4.0.5` 重跑全部测试(56 项通过)。两版 API 实测一致:`resolveDshHome` / `withFileLock` / `writeFileAtomic` 签名与导出均未变。
|
|
15
|
+
|
|
7
16
|
## 0.1.1
|
|
8
17
|
|
|
9
18
|
- 发布渠道改为 GitHub Release 触发的 npm Trusted Publishing:`publish.yml` 与参考项目 `dsh-multi-router` 对齐,显式安装 `npm@11.19.0`、由版本后缀推导 `NPM_TAG`(稳定版 `latest` / 预发布 `next`),全程 OIDC 签名,仓库不存任何 npm token。
|
package/cordis.patch.yml
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
- insert:
|
|
2
|
-
- id: session-toolbox-v1-0.1.
|
|
3
|
-
name: ./lib/host-v0.1.
|
|
2
|
+
- id: session-toolbox-v1-0.1.3
|
|
3
|
+
name: ./lib/host-v0.1.3.js
|
package/lib/client.js
CHANGED
|
@@ -39,7 +39,7 @@ var import_react = require("react");
|
|
|
39
39
|
// package.json
|
|
40
40
|
var package_default = {
|
|
41
41
|
name: "dsh-session-toolbox",
|
|
42
|
-
version: "0.1.
|
|
42
|
+
version: "0.1.3",
|
|
43
43
|
repository: {
|
|
44
44
|
type: "git",
|
|
45
45
|
url: "https://github.com/AndroidSix/dsh-session-toolbox.git"
|
|
@@ -58,7 +58,8 @@ var package_default = {
|
|
|
58
58
|
"./package.json": "./package.json"
|
|
59
59
|
},
|
|
60
60
|
engines: {
|
|
61
|
-
node: "^22.19.0 || >=24.0.0"
|
|
61
|
+
node: "^22.19.0 || >=24.0.0",
|
|
62
|
+
dsh: "^0.2.0-rc.2 || ^0.2.1-rc.2"
|
|
62
63
|
},
|
|
63
64
|
files: [
|
|
64
65
|
"lib",
|
|
@@ -89,15 +90,15 @@ var package_default = {
|
|
|
89
90
|
},
|
|
90
91
|
peerDependencies: {
|
|
91
92
|
"@deepseek-ai/cordis": "^4.0.4",
|
|
92
|
-
"@deepseek-ai/dsh-atomic-write": "0.2.0-rc.2",
|
|
93
|
-
"@deepseek-ai/dsh-home-paths": "0.2.0-rc.2",
|
|
93
|
+
"@deepseek-ai/dsh-atomic-write": "^0.2.0-rc.2 || ^0.2.1-rc.2",
|
|
94
|
+
"@deepseek-ai/dsh-home-paths": "^0.2.0-rc.2 || ^0.2.1-rc.2",
|
|
94
95
|
"@deepseek-ai/schemastery": "^3.18.4",
|
|
95
96
|
react: "^18.2.0"
|
|
96
97
|
},
|
|
97
98
|
devDependencies: {
|
|
98
99
|
"@deepseek-ai/cordis": "^4.0.4",
|
|
99
|
-
"@deepseek-ai/dsh-atomic-write": "0.2.0-rc.2",
|
|
100
|
-
"@deepseek-ai/dsh-home-paths": "0.2.0-rc.2",
|
|
100
|
+
"@deepseek-ai/dsh-atomic-write": "^0.2.0-rc.2 || ^0.2.1-rc.2",
|
|
101
|
+
"@deepseek-ai/dsh-home-paths": "^0.2.0-rc.2 || ^0.2.1-rc.2",
|
|
101
102
|
"@deepseek-ai/schemastery": "^3.18.4",
|
|
102
103
|
esbuild: "^0.25.0",
|
|
103
104
|
react: "^18.2.0",
|
|
@@ -117,6 +118,7 @@ var package_default = {
|
|
|
117
118
|
var DB_NAME = "dsh-session-toolbox-vault";
|
|
118
119
|
var STORE = "blobs";
|
|
119
120
|
var IMAGE_TYPES = ["image/png", "image/jpeg", "image/webp", "image/gif"];
|
|
121
|
+
var SEED_MARKER = Symbol.for("dsh-session-toolbox.seed");
|
|
120
122
|
var MAX_FILE_BYTES = 10 * 1024 * 1024;
|
|
121
123
|
var DEFAULT_LIMITS = Object.freeze({ enabled: true, maxSizeBytes: 200 * 1024 * 1024, ttlDays: 7 });
|
|
122
124
|
function isImageFile(file) {
|
|
@@ -268,8 +270,14 @@ function createVault(options = {}) {
|
|
|
268
270
|
}
|
|
269
271
|
async function intake(sessionId, files) {
|
|
270
272
|
if (!limits.enabled || sessionId === void 0 || sessionId === "") return;
|
|
273
|
+
const existing = (await allRecords()).filter((record) => record.sessionId === sessionId);
|
|
274
|
+
const seen = new Set(existing.map((record) => record.hash));
|
|
275
|
+
let added = 0;
|
|
271
276
|
for (const item of files) {
|
|
272
277
|
if (!isImageFile(item)) continue;
|
|
278
|
+
const hash = await contentHash(item);
|
|
279
|
+
if (seen.has(hash)) continue;
|
|
280
|
+
seen.add(hash);
|
|
273
281
|
const id = globalThis.crypto?.randomUUID?.() ?? `id-${now()}-${Math.random().toString(36).slice(2)}`;
|
|
274
282
|
const record = {
|
|
275
283
|
key: `${sessionId}__${id}`,
|
|
@@ -278,14 +286,15 @@ function createVault(options = {}) {
|
|
|
278
286
|
name: item.name || "",
|
|
279
287
|
type: item.type,
|
|
280
288
|
size: item.size,
|
|
281
|
-
hash
|
|
289
|
+
hash,
|
|
282
290
|
createdAt: now(),
|
|
283
291
|
seeded: false
|
|
284
292
|
};
|
|
285
293
|
record.blob = item;
|
|
286
294
|
await putRecord(record);
|
|
287
|
-
|
|
295
|
+
added += 1;
|
|
288
296
|
}
|
|
297
|
+
if (added > 0) notice(`\u5DF2\u5907\u4EFD ${added} \u5F20\u8349\u7A3F\u56FE\u7247\uFF08\u4F1A\u8BDD ${sessionId.slice(-6)}\uFF09`);
|
|
289
298
|
void syncHost();
|
|
290
299
|
}
|
|
291
300
|
const readImages = (event) => [...event.clipboardData?.files ?? event.dataTransfer?.files ?? []].filter(isImageFile);
|
|
@@ -328,6 +337,10 @@ function createVault(options = {}) {
|
|
|
328
337
|
}
|
|
329
338
|
const event = new ClipboardEvent("paste", { bubbles: true, cancelable: true });
|
|
330
339
|
Object.defineProperty(event, "clipboardData", { value: fakeClipboardData(files) });
|
|
340
|
+
try {
|
|
341
|
+
Object.defineProperty(event, SEED_MARKER, { value: true });
|
|
342
|
+
} catch {
|
|
343
|
+
}
|
|
331
344
|
try {
|
|
332
345
|
editor.focus?.();
|
|
333
346
|
} catch {
|
|
@@ -408,10 +421,13 @@ function createVault(options = {}) {
|
|
|
408
421
|
} catch {
|
|
409
422
|
}
|
|
410
423
|
}
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
424
|
+
const capture = (event) => {
|
|
425
|
+
if (event[SEED_MARKER] === true) return;
|
|
426
|
+
void intake(currentSession(), readImages(event)).catch(() => {
|
|
427
|
+
});
|
|
428
|
+
};
|
|
429
|
+
document.addEventListener("paste", capture, true);
|
|
430
|
+
document.addEventListener("drop", capture, true);
|
|
415
431
|
document.addEventListener("change", (event) => void intake(currentSession(), fileInputImages(event)).catch(() => {
|
|
416
432
|
}), true);
|
|
417
433
|
teardown = watchMounts();
|
package/lib/client.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/client.jsx", "../package.json", "../src/draft-vault.js"],
|
|
4
|
-
"sourcesContent": ["/**\n * dsh-session-toolbox browser plugin: management page (\u00A74 FR5/FR6, \u00A710 MR6, \u00A711\n * TB2), session context-menu entries, the input-dock vault badge, and the\n * draft vault itself (capture + IndexedDB + synthetic-paste restore; route A).\n * Every official surface is probed (`ctx.get?.`, guarded registrations); no\n * path here may take the native composer down with it (NFR3).\n */\nimport { useEffect, useRef, useState } from 'react';\nimport pkg from '../package.json' with { type: 'json' };\nconst pluginVersion = pkg.version;\nimport { createVault } from './draft-vault.js';\n\nexport const name = 'dsh-session-toolbox-client';\nexport const inject = ['slots'];\nexport const NS = 'dsh-session-toolbox';\nconst ENDPOINT = `/.well-known/${NS}`;\n\nlet vault; // browser-side singleton (IndexedDB + host manifest)\nlet directoryPicker; // ctx.get('directoryPicker') probed at apply time\nconst store = { state: null, error: '', listeners: new Set() };\n\nasync function readResponse(res) {\n\tlet next;\n\ttry { next = JSON.parse(await res.text()); }\n\tcatch { throw new Error(`\u63D2\u4EF6\u540E\u53F0\u672A\u5C31\u7EEA\uFF08HTTP ${res.status}\uFF09\uFF1B\u5B89\u88C5\u6216\u91CD\u542F\u671F\u95F4\u4F1A\u81EA\u52A8\u91CD\u8BD5`); }\n\tif (next === null || typeof next !== 'object' || Array.isArray(next)) throw new Error('\u63D2\u4EF6\u540E\u53F0\u8FD4\u56DE\u4E86\u65E0\u6548\u6570\u636E');\n\tif (!res.ok) throw new Error(next.error ?? `\u64CD\u4F5C\u5931\u8D25\uFF08HTTP ${res.status}\uFF09`);\n\treturn next;\n}\n\n/** GET the shared snapshot; also (re)binds the write key the host rotates. */\nexport let sessionKey = '';\nexport async function loadState() {\n\ttry {\n\t\tconst next = await readResponse(await fetch(ENDPOINT, { cache: 'no-store' }));\n\t\tstore.state = next; store.error = ''; sessionKey = next.key ?? sessionKey;\n\t} catch (error) { store.error = error.message; }\n\tfor (const listener of store.listeners) listener();\n\treturn store.state;\n}\nexport async function callHost(input) {\n\tif (!sessionKey) await loadState();\n\tconst res = await readResponse(await fetch(ENDPOINT, {\n\t\tmethod: 'POST', cache: 'no-store',\n\t\theaders: { 'content-type': 'application/json', 'x-session-toolbox-key': sessionKey },\n\t\tbody: JSON.stringify(input),\n\t}));\n\tsessionKey = res.key ?? sessionKey;\n\tfor (const listener of store.listeners) listener();\n\treturn res;\n}\n\nexport function apply(ctx) {\n\tdirectoryPicker = ctx.get?.('directoryPicker');\n\tconst vaultInstance = vault ??= createVault({\n\t\tendpoint: ENDPOINT,\n\t\tlog: (level, message) => { try { (level === 'error' ? console.warn : console.log)(`[${NS}]`, message); } catch {} },\n\t});\n\tvoid loadState();\n\tconst timer = setInterval(() => void loadState(), 30000);\n\tctx.effect?.(() => () => clearInterval(timer));\n\tvaultInstance.on('change', () => void loadState());\n\tvoid vaultInstance.start();\n\tctx.locale?.register?.(NS, {\n\t\tzh: { 'menu.move': '\u5207\u6362\u5230\u5176\u5B83\u9879\u76EE\u2026', 'menu.trash': '\u79FB\u5165\u56DE\u6536\u7AD9' },\n\t\ten: { 'menu.move': 'Move to another project\u2026', 'menu.trash': 'Move to trash' },\n\t});\n\n\t// Keyed slot (one occupant = package name): the plugin settings page.\n\tctx.slots.inject('plugins.bundle.config', () => ctx.slots.register({ name: 'plugins.bundle.config', key: NS }, KitPage));\n\t// Session context menu: move + trash entries beside the official four.\n\tctx.slots.inject('sidebar.workspaces.session.menu.item', () => ctx.slots.register({ name: 'sidebar.workspaces.session.menu.item', id: 'session-toolbox-move', order: 500, locale: NS }, MoveSessionMenuItem));\n\tctx.slots.inject('sidebar.workspaces.session.menu.item', () => ctx.slots.register({ name: 'sidebar.workspaces.session.menu.item', id: 'session-toolbox-trash', order: 600, locale: NS }, TrashSessionMenuItem));\n\t// Input dock badge (\u00A74 FR5): how many image drafts are backed up here.\n\tctx.slots.inject('conversation.input.dock', () => ctx.slots.register({ name: 'conversation.input.dock', id: 'session-toolbox-vault-badge', order: 5, locale: NS }, VaultBadge));\n}\n\nfunction useKit() {\n\tconst [, bump] = useState(0);\n\tuseEffect(() => {\n\t\tconst listener = () => bump(n => n + 1);\n\t\tstore.listeners.add(listener);\n\t\tvoid loadState();\n\t\treturn () => store.listeners.delete(listener);\n\t}, []);\n\treturn store;\n}\n\nconst styles = `\n.sk{--sk-accent:var(--dsw-alias-state-active-primary,#3a71db);--sk-border:var(--dsw-alias-border-l2,#444);--sk-bg:var(--dsw-alias-bg-layer-1,#202020);--sk-card:var(--dsw-alias-bg-module-platform,#282828);--sk-text:var(--dsw-alias-label-primary,#f4f4f4);--sk-muted:var(--dsw-alias-label-secondary,#b0b0b0);color:var(--sk-text);font:inherit;font-size:14px;line-height:1.6;max-width:1120px}\n.sk *{box-sizing:border-box}.sk h2,.sk h3,.sk p{margin:0}.sk h2{font-size:22px}.sk h3{font-size:16px}.sk .muted,.sk small{color:var(--sk-muted)}\n.sk .box{border:1px solid var(--sk-border);border-radius:12px;padding:18px 20px;background:var(--sk-card);display:flex;flex-direction:column;gap:14px}\n.sk .row{display:flex;gap:10px;align-items:center;flex-wrap:wrap}.sk .stack{display:flex;flex-direction:column;gap:16px}\n.sk button,.sk input,.sk select{font:inherit;color:inherit;border:1px solid var(--sk-border);border-radius:8px;background:var(--sk-bg);min-height:36px;padding:7px 12px}\n.sk button{cursor:pointer}.sk button:hover{background:var(--sk-card)}.sk button:disabled{opacity:.45;cursor:default}\n.sk button.primary{background:var(--sk-accent);color:#fff;border-color:transparent}\n.sk table{width:100%;border-collapse:collapse;font-size:13px}.sk th,.sk td{border-bottom:1px solid var(--sk-border);padding:8px;text-align:left}.sk th{color:var(--sk-muted);font-weight:500}\n.sk .error{color:var(--dsw-alias-state-error-primary,#ef9393)}.sk .good{color:var(--dsw-alias-state-success-primary,#77ca9d)}\n.sk .pill{border:1px solid var(--sk-border);border-radius:100px;padding:2px 10px;font-size:12px;background:var(--sk-bg);display:inline-block}\n.sk .mono{font:12px ui-monospace,monospace;overflow-wrap:anywhere}\n.sk dialog{color:var(--sk-text);background:var(--sk-bg);border:1px solid var(--sk-border);border-radius:14px;width:min(560px,calc(100vw - 32px));padding:0}\n.sk dialog::backdrop{background:#0007}.sk .modal-head{padding:16px 20px;border-bottom:1px solid var(--sk-border);display:flex;justify-content:space-between;align-items:center}\n.sk .modal-body{padding:20px;display:flex;flex-direction:column;gap:14px}\n.sk input.grow{flex:1;min-width:0}\n`;\n\nexport function KitPage() {\n\tconst { state, error } = useKit();\n\tconst [busy, setBusy] = useState(false);\n\tconst [feedback, setFeedback] = useState('');\n\tconst say = message => { setFeedback(message); setTimeout(() => setFeedback(''), 8000); };\n\tconst act = async (input, ok) => {\n\t\tsetBusy(true);\n\t\ttry { const result = await callHost(input); if (ok) say(ok); await loadState(); setBusy(false); return result; }\n\t\tcatch (err) { say(`\u5931\u8D25\uFF1A${err.message}`); setBusy(false); throw err; }\n\t};\n\tconst settings = state?.settings;\n\treturn (\n\t\t<div className=\"sk\">\n\t\t\t<style>{styles}</style>\n\t\t\t<h2>\u4F1A\u8BDD\u5DE5\u5177\u7BB1</h2>\n\t\t\t<p className=\"muted\">\u8349\u7A3F\u4FDD\u9669\u7BB1 \u00B7 \u4F1A\u8BDD\u5207\u6362\u9879\u76EE \u00B7 \u56DE\u6536\u7AD9 \u2014 v{pluginVersion}\u3002\u6570\u636E\u4EC5\u5B58\u672C\u673A\uFF08\u6D4F\u89C8\u5668 IndexedDB + ~/.dsh/session-toolbox/\uFF09\u3002</p>\n\t\t\t{error ? <p className=\"error\">\u540E\u53F0\u8FDE\u63A5\u5931\u8D25\uFF1A{error}</p> : null}\n\t\t\t{feedback ? <p className=\"good\">{feedback}</p> : null}\n\t\t\t<section className=\"box\">\n\t\t\t\t<h3>\u8349\u7A3F\u4FDD\u9669\u7BB1\uFF08\u56FE\u7247\u8349\u7A3F\u6301\u4E45\u5316\uFF09</h3>\n\t\t\t\t{settings ? (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<div className=\"row\">\n\t\t\t\t\t\t\t<label className=\"row\"><input type=\"checkbox\" checked={settings.draftVault?.enabled !== false} disabled={busy}\n\t\t\t\t\t\t\t\tonChange={e => void act({ type: 'settings.update', patch: { draftVault: { ...settings.draftVault, enabled: e.target.checked } } }, e.target.checked ? '\u5DF2\u542F\u7528\u8349\u7A3F\u4FDD\u9669\u7BB1' : '\u5DF2\u505C\u7528\u8349\u7A3F\u4FDD\u9669\u7BB1\uFF08\u6D4F\u89C8\u5668\u4FA7\u5373\u65F6\u751F\u6548\uFF09').catch(() => {})} /> \u542F\u7528</label>\n\t\t\t\t\t\t\t<span className=\"pill\">\u5BB9\u91CF {Math.round((settings.draftVault?.maxSizeBytes ?? 0) / 1048576)} MB</span>\n\t\t\t\t\t\t\t<span className=\"pill\">\u4FDD\u7559 {settings.draftVault?.ttlDays ?? 7} \u5929</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"row\">\n\t\t\t\t\t\t\t<span className=\"muted\">\u6E05\u5355\uFF1A\u5DF2\u5907\u4EFD {state?.vault?.records ?? 0} \u9879 \u00B7 \u7EA6 {fmtBytes(state?.vault?.bytes ?? 0)}\uFF08\u56FE\u7247\u5B57\u8282\u5728 IndexedDB\uFF0C\u8D85\u51FA\u4E0A\u9650\u6309\u6700\u65E7\u6E05\u7406\uFF0C\u4E8B\u4EF6\u4F1A\u663E\u793A\u5728\u8FD9\u91CC\uFF09</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t{state?.vault?.notice ? <p className=\"muted\">{state.vault.notice}</p> : null}\n\t\t\t\t\t\t<div className=\"row\"><button disabled={busy} onClick={() => void act({ type: 'vault.sweep' }, '\u5DF2\u6309 TTL/\u5BB9\u91CF\u6E05\u7406').catch(() => {})}>\u7ACB\u5373\u6574\u7406</button></div>\n\t\t\t\t\t</>\n\t\t\t\t) : <p className=\"muted\">\u7B49\u5F85\u540E\u53F0\u6570\u636E\u2026</p>}\n\t\t\t</section>\n\t\t\t<MoveSection act={act} busy={busy} say={say} state={state} />\n\t\t\t<TrashSection act={act} busy={busy} say={say} state={state} />\n\t\t</div>\n\t);\n}\n\nfunction MoveSection({ act, busy, say, state }) {\n\tconst [sessionId, setSessionId] = useState('');\n\tconst [toCwd, setToCwd] = useState('');\n\tconst [createTarget, setCreateTarget] = useState(false);\n\tconst [plan, setPlan] = useState(null);\n\tconst journal = state?.journal;\n\tconst pick = async () => {\n\t\ttry {\n\t\t\tconst result = await directoryPicker?.pick?.();\n\t\t\tconst value = result?.ok ? result.value : undefined;\n\t\t\tif (typeof value === 'string' && value) setToCwd(value);\n\t\t\telse say('\u5F53\u524D DSH \u672A\u63D0\u4F9B\u76EE\u5F55\u9009\u62E9\u5668\uFF08\u6216\u5DF2\u53D6\u6D88\uFF09\uFF0C\u8BF7\u624B\u52A8\u8F93\u5165\u7EDD\u5BF9\u8DEF\u5F84');\n\t\t} catch (error) { say(`\u76EE\u5F55\u9009\u62E9\u5931\u8D25\uFF1A${error.message}`); }\n\t};\n\treturn (\n\t\t<section className=\"box\">\n\t\t\t<h3>\u4F1A\u8BDD\u5207\u6362\u9879\u76EE</h3>\n\t\t\t{journal && <p className=\"error\">\u5B58\u5728\u672A\u5B8C\u6210\u7684\u8FC1\u79FB\uFF1A{journal.sessionId} \u2192 {journal.toCwd}\uFF08\u5DF2\u5B8C\u6210 {journal.done?.join('/') || '\u65E0'}\uFF09\u3002\n\t\t\t\t<button disabled={busy} onClick={() => void act({ type: 'move.complete' }, '\u8FC1\u79FB\u5DF2\u524D\u6EDA\u5B8C\u6210').catch(() => {})}>\u5B8C\u6210</button>\n\t\t\t\t{' '}<button disabled={busy} onClick={() => void act({ type: 'move.rollback' }, '\u8FC1\u79FB\u5DF2\u56DE\u6EDA').catch(() => {})}>\u56DE\u6EDA</button></p>}\n\t\t\t<div className=\"row\">\n\t\t\t\t<input className=\"grow mono\" placeholder=\"session-\u2026\uFF08\u6216\u4ECE\u4F1A\u8BDD\u53F3\u952E\u83DC\u5355\u53D1\u8D77\uFF09\" value={sessionId} onChange={e => { setSessionId(e.target.value); setPlan(null); }} />\n\t\t\t\t<input className=\"grow mono\" placeholder=\"\u76EE\u6807\u9879\u76EE\u7EDD\u5BF9\u8DEF\u5F84\" value={toCwd} onChange={e => { setToCwd(e.target.value); setPlan(null); }} />\n\t\t\t\t<button onClick={() => void pick()} disabled={busy}>\u6D4F\u89C8\u2026</button>\n\t\t\t</div>\n\t\t\t<label className=\"row\"><input type=\"checkbox\" checked={createTarget} onChange={e => setCreateTarget(e.target.checked)} /> \u76EE\u6807\u4E0D\u5B58\u5728\u65F6\u521B\u5EFA</label>\n\t\t\t<div className=\"row\">\n\t\t\t\t<button disabled={busy || !sessionId || !toCwd} onClick={() => { setBusy(true); setPlan(null); void callHost({ type: 'preflight', sessionId, toCwd, createTarget })\n\t\t\t\t\t.then(result => setPlan(result)).catch(error => say(`\u4F53\u68C0\u5931\u8D25\uFF1A${error.message}`)).finally(() => setBusy(false)); }}>\u4F53\u68C0</button>\n\t\t\t\t<button className=\"primary\" disabled={busy || plan?.toProject === undefined} onClick={() => void act({ type: 'move', sessionId, toCwd, createTarget }, '\u8FC1\u79FB\u5B8C\u6210\uFF1B\u5176\u5B83\u7A97\u53E3\u8BF7\u91CD\u5F00\u8BE5\u4F1A\u8BDD').catch(() => {})}>\u8FC1\u79FB</button>\n\t\t\t</div>\n\t\t\t{plan?.toProject && (\n\t\t\t\t<pre className=\"mono muted\" style={{ whiteSpace: 'pre-wrap' }}>{JSON.stringify({ \u4ECE: plan.fromCwd, \u5230: plan.toCwd, \u539F\u76EE\u5F55: plan.fromProject, \u65B0\u76EE\u5F55: plan.toProject, \u65E5\u5FD7\u6587\u4EF6: plan.logName }, null, 2)}</pre>\n\t\t\t)}\n\t\t\t<p className=\"muted\">\u53EA\u6539 DSH \u5185\u90E8\u5F52\u5C5E\u4E0E\u4F1A\u8BDD\u5934\uFF1B\u5386\u53F2\u4E0D\u53D8\uFF0C\u65E7\u6D88\u606F\u4E2D\u7684\u7EDD\u5BF9\u8DEF\u5F84\u4ECD\u6307\u5411\u539F\u9879\u76EE\uFF08\u5DF2\u77E5\u8BED\u4E49\uFF09\u3002\u8FC1\u79FB\u524D\u8BF7\u5173\u95ED\u8BE5\u4F1A\u8BDD\u3002</p>\n\t\t</section>\n\t);\n}\n\nfunction TrashSection({ act, busy, say, state }) {\n\tconst items = state?.trash ?? [];\n\treturn (\n\t\t<section className=\"box\">\n\t\t\t<h3>\u56DE\u6536\u7AD9</h3>\n\t\t\t<p className=\"muted\">\u5220\u9664\u4F1A\u8BDD = \u5B98\u65B9\u5F52\u6863 + \u5165\u7AD9\u8BB0\u5F55\uFF1B\u5220\u9664\u9879\u76EE\u4FDD\u7559\u5168\u90E8\u4F1A\u8BDD\u65E5\u5FD7\u3002\u5F7B\u5E95\u5220\u9664\u4F1A\u5148\u79FB\u5230\u6682\u5B58\u76EE\u5F55\u518D\u6E05\u7406\uFF0C\u4E2D\u65AD\u53EF\u7528 CLI \u68C0\u51FA\u3002</p>\n\t\t\t{items.length === 0 ? <p className=\"muted\">\uFF08\u7A7A\uFF09</p> : (\n\t\t\t\t<table>\n\t\t\t\t\t<thead><tr><th>\u7C7B\u578B</th><th>\u5BF9\u8C61</th><th>\u6807\u9898 / \u8DEF\u5F84</th><th>\u5165\u7AD9\u65F6\u95F4</th><th /></tr></thead>\n\t\t\t\t\t<tbody>{items.map(item => (\n\t\t\t\t\t\t<tr key={item.itemId}>\n\t\t\t\t\t\t\t<td>{item.kind === 'session' ? '\u4F1A\u8BDD' : '\u9879\u76EE'}</td>\n\t\t\t\t\t\t\t<td className=\"mono\">{shortId(item.targetId)}</td>\n\t\t\t\t\t\t\t<td className=\"mono\">{item.kind === 'session' ? item.snapshot.title || '\uFF08\u65E0\u6807\u9898\uFF09' : item.snapshot.path}</td>\n\t\t\t\t\t\t\t<td>{new Date(item.trashedAt).toLocaleString('zh-CN', { hour12: false })}</td>\n\t\t\t\t\t\t\t<td className=\"row\">\n\t\t\t\t\t\t\t\t<button disabled={busy} onClick={() => void act({ type: 'trash.restore', itemId: item.itemId }, '\u5DF2\u8FD8\u539F\uFF08\u82E5\u5904\u4E8E\u5F52\u6863\u6001\u8BF7\u5148\u5728\u5217\u8868\u91CC\u8FD8\u539F\u5F52\u6863\uFF09').catch(() => {})}>\u8FD8\u539F</button>\n\t\t\t\t\t\t\t\t<button disabled={busy} onClick={() => void act({ type: 'trash.purge', itemId: item.itemId }, '\u5DF2\u5F7B\u5E95\u5220\u9664').catch(() => {})}>\u5F7B\u5E95\u5220\u9664</button>\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t</tr>))}\n\t\t\t\t\t</tbody>\n\t\t\t\t</table>\n\t\t\t)}\n\t\t\t<div className=\"row\">\n\t\t\t\t<span className=\"muted\">\u4FDD\u7559 {state?.settings?.trash?.ttlDays ?? 30} \u5929\uFF1B\u5230\u671F\u81EA\u52A8\u6E05\u7406{state?.settings?.trash?.autoPurge ? '\uFF08\u5DF2\u5F00\uFF09' : '\uFF08\u672A\u5F00\uFF0C\u4EC5\u63D0\u9192\uFF09'}\u3002</span>\n\t\t\t\t<button disabled={busy} onClick={() => void act({ type: 'settings.update', patch: { trash: { ...state?.settings?.trash, autoPurge: !(state?.settings?.trash?.autoPurge) } } }, '\u7B56\u7565\u5DF2\u66F4\u65B0').catch(() => {})}>\u5207\u6362\u81EA\u52A8\u6E05\u7406</button>\n\t\t\t\t<button disabled={busy} onClick={() => void act({ type: 'trash.sweep' }, '\u5DF2\u6309 TTL \u5DE1\u68C0').catch(() => {})}>\u5DE1\u68C0\u5230\u671F\u9879</button>\n\t\t\t</div>\n\t\t</section>\n\t);\n}\n\nconst shortId = id => String(id).length > 18 ? `${String(id).slice(0, 8)}\u2026${String(id).slice(-6)}` : String(id);\nconst fmtBytes = n => n >= 1048576 ? `${(n / 1048576).toFixed(1)} MB` : n >= 1024 ? `${(n / 1024).toFixed(1)} KB` : `${n} B`;\n\n/** Menu entry: move this session to another project (\u00A710 MR6). */\nexport function MoveSessionMenuItem({ sessionId, t }) {\n\tconst [open, setOpen] = useState(false);\n\treturn (\n\t\t<>\n\t\t\t<button role=\"menuitem\" onClick={() => setOpen(true)} style={menuItemStyle}>{t ? t('menu.move') : '\u5207\u6362\u5230\u5176\u5B83\u9879\u76EE\u2026'}</button>\n\t\t\t{open ? <MoveDialog sessionId={sessionId} close={() => setOpen(false)} /> : null}\n\t\t</>\n\t);\n}\n\nexport function TrashSessionMenuItem({ sessionId, t }) {\n\tconst [confirm, setConfirm] = useState(false);\n\tconst [busy, setBusy] = useState(false);\n\tif (confirm) {\n\t\treturn <button role=\"menuitem\" disabled={busy} style={menuItemStyle} onClick={async () => {\n\t\t\tsetBusy(true);\n\t\t\ttry { await callHost({ type: 'trash.session', sessionId }); setConfirm(false); }\n\t\t\tcatch { sayRow(`\u56DE\u6536\u5931\u8D25`); setConfirm(false); }\n\t\t\tsetBusy(false);\n\t\t}}>\u786E\u8BA4\u79FB\u5165\u56DE\u6536\u7AD9\uFF1F\uFF08\u5148\u5F52\u6863\uFF09</button>;\n\t}\n\treturn <button role=\"menuitem\" style={menuItemStyle} onClick={() => setConfirm(true)}>{t ? t('menu.trash') : '\u79FB\u5165\u56DE\u6536\u7AD9'}</button>;\n}\nfunction sayRow(message) { store.error = message; for (const listener of store.listeners) listener(); }\n\nconst menuItemStyle = { background: 'transparent', border: 'none', color: 'inherit', font: 'inherit', padding: '6px 10px', textAlign: 'left', cursor: 'pointer', width: '100%' };\n\nexport function MoveDialog({ sessionId, close }) {\n\tconst ref = useRef(null);\n\tconst [toCwd, setToCwd] = useState('');\n\tconst [createTarget, setCreateTarget] = useState(false);\n\tconst [error, setError] = useState('');\n\tconst [busy, setBusy] = useState(false);\n\tuseEffect(() => { const dialog = ref.current; dialog?.showModal(); return () => { try { dialog?.close(); } catch {} }; }, []);\n\tconst submit = async () => {\n\t\tsetBusy(true); setError('');\n\t\ttry { await callHost({ type: 'move', sessionId, toCwd, createTarget }); close(); }\n\t\tcatch (err) { setError(err.message); setBusy(false); }\n\t};\n\tconst valid = /^\\/|^[A-Za-z]:[\\\\/]/.test(toCwd);\n\treturn (\n\t\t<div className=\"sk\"><style>{styles}</style>\n\t\t\t<dialog ref={ref} onCancel={e => { e.preventDefault(); if (!busy) close(); }}>\n\t\t\t\t<div className=\"modal-head\"><strong>\u4F1A\u8BDD\u5207\u6362\u5230\u5176\u5B83\u9879\u76EE</strong><button onClick={close} disabled={busy}>\u5173\u95ED</button></div>\n\t\t\t\t<div className=\"modal-body\">\n\t\t\t\t\t<p className=\"muted mono\">{sessionId}</p>\n\t\t\t\t\t<input autoFocus className=\"grow mono\" placeholder=\"\u76EE\u6807\u9879\u76EE\u7EDD\u5BF9\u8DEF\u5F84\" value={toCwd} onChange={e => setToCwd(e.target.value)} />\n\t\t\t\t\t<label className=\"row\"><input type=\"checkbox\" checked={createTarget} onChange={e => setCreateTarget(e.target.checked)} /> \u76EE\u5F55\u4E0D\u5B58\u5728\u65F6\u521B\u5EFA</label>\n\t\t\t\t\t{error ? <p className=\"error\">{error}</p> : null}\n\t\t\t\t\t<div className=\"row\"><button className=\"primary\" disabled={busy || !valid} onClick={() => void submit()}>\u4F53\u68C0\u5E76\u8FC1\u79FB</button>\n\t\t\t\t\t\t<span className=\"muted\">\u4F1A\u8BDD\u9700\u7A7A\u95F2\uFF1B\u8FC1\u79FB\u5728\u540E\u53F0\u79BB\u7EBF\u5B8C\u6210\u3002</span></div>\n\t\t\t\t</div>\n\t\t\t</dialog>\n\t\t</div>\n\t);\n}\n\n/** Input-dock badge (\u00A74 FR5): how many image drafts are backed up for this session. */\nexport function VaultBadge({ sessionId }) {\n\tconst [count, setCount] = useState(0);\n\tconst [notice, setNotice] = useState('');\n\tuseEffect(() => {\n\t\tif (vault === undefined) return;\n\t\tlet live = true;\n\t\tconst sync = async () => {\n\t\t\ttry { const value = await vault.countFor(sessionId ?? vault.currentSession()); if (live) setCount(value); }\n\t\t\tcatch { if (live) setCount(0); }\n\t\t\tif (live) setNotice(vault.lastNotice ?? '');\n\t\t};\n\t\tvoid sync();\n\t\tconst listener = () => void sync();\n\t\tvault.on('change', listener);\n\t\twindow.addEventListener(`${NS}-notice`, listener);\n\t\tconst timer = setInterval(listener, 20000);\n\t\treturn () => { live = false; vault.off('change', listener); window.removeEventListener(`${NS}-notice`, listener); clearInterval(timer); };\n\t}, [sessionId]);\n\tif (count === 0) return null; // the notice channel serves the panel; the badge anchors per-session counts\n\treturn <span className=\"sk\"><span className=\"pill\" title={`\u672C\u4F1A\u8BDD\u6709 ${count} \u5F20\u56FE\u7247\u8349\u7A3F\u5DF2\u5907\u4EFD\uFF08\u5207\u6362\u4F1A\u8BDD/\u5237\u65B0/\u91CD\u542F\u540E\u53EF\u6062\u590D\uFF09${notice ? `\uFF5C\u6700\u8FD1\uFF1A${notice}` : ''}`}>\uD83D\uDEDF \u8349\u7A3F\u5907\u4EFD {count}</span></span>;\n}\n", "{\n \"name\": \"dsh-session-toolbox\",\n \"version\": \"0.1.1\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/AndroidSix/dsh-session-toolbox.git\"\n },\n \"description\": \"Draft vault, session-to-project move and a trash bin for DeepSeek Harness\",\n \"type\": \"module\",\n \"main\": \"lib/index.js\",\n \"bin\": {\n \"dsh-session-toolbox\": \"lib/cli.js\"\n },\n \"exports\": {\n \".\": \"./lib/index.js\",\n \"./host\": \"./lib/host.js\",\n \"./client\": \"./lib/client.js\",\n \"./cordis.patch.yml\": \"./cordis.patch.yml\",\n \"./package.json\": \"./package.json\"\n },\n \"engines\": {\n \"node\": \"^22.19.0 || >=24.0.0\"\n },\n \"files\": [\n \"lib\",\n \"cordis.patch.yml\",\n \"README.md\",\n \"LICENSE\",\n \"THIRD_PARTY_NOTICES.md\",\n \"session-toolbox.example.json\",\n \"CHANGELOG.md\"\n ],\n \"dsh\": {\n \"bundle\": {\n \"patch\": \"./cordis.patch.yml\"\n },\n \"client\": {\n \"inject\": [\n \"@deepseek-ai/dsh-client-ui-renderer\"\n ],\n \"platform\": \"web\"\n }\n },\n \"scripts\": {\n \"build\": \"node scripts/build.mjs\",\n \"test\": \"node --test tests/*.test.mjs\",\n \"check\": \"npm run build && npm test && node scripts/check-package.mjs\",\n \"check:tarball\": \"npm run build && node scripts/check-package.mjs --tarball\",\n \"pack:release\": \"npm run build && npm pack --ignore-scripts\"\n },\n \"peerDependencies\": {\n \"@deepseek-ai/cordis\": \"^4.0.4\",\n \"@deepseek-ai/dsh-atomic-write\": \"0.2.0-rc.2\",\n \"@deepseek-ai/dsh-home-paths\": \"0.2.0-rc.2\",\n \"@deepseek-ai/schemastery\": \"^3.18.4\",\n \"react\": \"^18.2.0\"\n },\n \"devDependencies\": {\n \"@deepseek-ai/cordis\": \"^4.0.4\",\n \"@deepseek-ai/dsh-atomic-write\": \"0.2.0-rc.2\",\n \"@deepseek-ai/dsh-home-paths\": \"0.2.0-rc.2\",\n \"@deepseek-ai/schemastery\": \"^3.18.4\",\n \"esbuild\": \"^0.25.0\",\n \"react\": \"^18.2.0\",\n \"react-dom\": \"^18.2.0\"\n },\n \"license\": \"MIT\",\n \"keywords\": [\n \"dsh-plugin\",\n \"deepseek-harness\",\n \"draft-vault\",\n \"session-move\",\n \"trash-bin\"\n ]\n}\n", "/**\n * Draft vault (\u00A74-\u00A79): mirrors image drafts into IndexedDB and replays them\n * through the official paste pipeline. No official internals are touched:\n * capture listens at document-level `paste`/`drop`/file-input `change` (never\n * preventing or stopping the native flow), persistence is browser IndexedDB,\n * and restore re-dispatches a ClipboardEvent carrying a synthetic\n * `clipboardData` (Chromium ignores the ClipboardEventInit clipboardData and\n * exposes it only as a prototype accessor, so the property is shadowed with a\n * defined own property \u2014 the official handler only reads `items`/`getData`,\n * verified against the shipped build).\n *\n * Idempotency is DOM-based and safe by construction:\n * - seeding only happens into an EMPTY attachment rail;\n * - a seed is confirmed by the official handler calling preventDefault() (its\n * documented contract for accepted files);\n * - rail dropping to zero while the session view is mounted means \"sent or\n * user-deleted\" (\u00A7 FR3: both delete the backups); the view unmounting keeps\n * them \u2014 that is exactly the loss this vault repairs.\n */\n\nexport const DB_NAME = 'dsh-session-toolbox-vault';\nexport const STORE = 'blobs';\nexport const IMAGE_TYPES = ['image/png', 'image/jpeg', 'image/webp', 'image/gif'];\nexport const MAX_FILE_BYTES = 10 * 1024 * 1024; // the official per-image admission cap\nexport const DEFAULT_LIMITS = Object.freeze({ enabled: true, maxSizeBytes: 200 * 1024 * 1024, ttlDays: 7 });\n\nexport function isImageFile(file) {\n\treturn file !== undefined && IMAGE_TYPES.includes(file.type) && file.size > 0 && file.size <= MAX_FILE_BYTES;\n}\n\n/** sha256 hex of bytes; crypto.subtle is absent on non-secure origins \u2192 size/name fallback hash. */\nexport async function contentHash(file) {\n\tif (globalThis.crypto?.subtle !== undefined) {\n\t\ttry {\n\t\t\tconst digest = await crypto.subtle.digest('SHA-256', await file.arrayBuffer());\n\t\t\treturn [...new Uint8Array(digest)].map(byte => byte.toString(16).padStart(2, '0')).join('');\n\t\t} catch { /* fall through */ }\n\t}\n\treturn `weak:${file.size}:${file.name}:${file.lastModified}`;\n}\n\nfunction openDb() {\n\tif (typeof indexedDB === 'undefined') throw new Error('IndexedDB unavailable');\n\treturn new Promise((resolve, reject) => {\n\t\tconst request = indexedDB.open(DB_NAME, 1);\n\t\trequest.onupgradeneeded = () => {\n\t\t\tconst database = request.result;\n\t\t\tif (!database.objectStoreNames.contains(STORE)) database.createObjectStore(STORE, { keyPath: 'key' });\n\t\t};\n\t\trequest.onsuccess = () => resolve(request.result);\n\t\trequest.onerror = () => reject(request.error ?? new Error('IndexedDB open failed'));\n\t});\n}\n\n/** Resolve with the request result; reject with its error. */\nfunction done(request) {\n\treturn new Promise((resolve, reject) => {\n\t\trequest.onsuccess = () => resolve(request.result);\n\t\trequest.onerror = () => reject(request.error ?? new Error('vault storage request failed'));\n\t});\n}\n\nfunction storeOp(database, mode, run) {\n\treturn new Promise((resolve, reject) => {\n\t\tlet outcome;\n\t\tconst transaction = database.transaction(STORE, mode);\n\t\ttransaction.onabort = () => reject(transaction.error ?? new Error('vault transaction aborted'));\n\t\ttransaction.onerror = () => reject(transaction.error ?? new Error('vault transaction failed'));\n\t\ttry { outcome = run(transaction.objectStore(STORE)); } catch (error) { reject(error); return; }\n\t\tPromise.resolve(outcome).then(resolve, reject);\n\t});\n}\n\nfunction emitter() {\n\tconst listeners = new Map();\n\treturn {\n\t\ton(event, fn) { if (!listeners.has(event)) listeners.set(event, new Set()); listeners.get(event).add(fn); },\n\t\toff(event, fn) { listeners.get(event)?.delete(fn); },\n\t\temit(event, detail) { for (const fn of [...(listeners.get(event) ?? [])]) { try { fn(detail); } catch {} } },\n\t};\n}\n\nfunction fakeClipboardData(files) {\n\tconst items = files.map(f => ({ kind: 'file', type: f.type, getAsFile: () => f }));\n\treturn { items, files, length: files.length, types: ['Files'], getData: () => '', setData: () => false, clearData: () => {} };\n}\n\nasync function blobToFile(record) {\n\tif (record.blob instanceof File) return record.blob;\n\tconst blob = record.blob instanceof Blob ? record.blob : new Blob([record.blob ?? new Uint8Array()], { type: record.type });\n\treturn new File([blob], record.name ?? '', { type: record.type, lastModified: record.createdAt });\n}\n\n/**\n * @param options - {endpoint, log, now, fetchImpl}\n */\nexport function createVault(options = {}) {\n\tconst log = options.log ?? (() => {});\n\tconst now = options.now ?? (() => Date.now());\n\tconst fetchImpl = options.fetchImpl ?? ((input, init) => fetch(input, init));\n\tconst bus = emitter();\n\tlet dbPromise = null;\n\tlet limits = { ...DEFAULT_LIMITS };\n\tlet lastNotice = '';\n\tlet started = false;\n\tlet teardown = null;\n\tlet hostKey = '';\n\n\tconst db = () => dbPromise ??= openDb();\n\tfunction notice(message) {\n\t\tlastNotice = message;\n\t\tbus.emit('notice', message);\n\t\ttry { globalThis.window?.dispatchEvent?.(new CustomEvent('dsh-session-toolbox-notice', { detail: message })); } catch { /* test envs */ }\n\t}\n\tfunction changed() { bus.emit('change'); }\n\n\t// ---- IndexedDB CRUD -----------------------------------------------------\n\tconst allRecords = async () => {\n\t\tconst database = await db();\n\t\treturn await storeOp(database, 'readonly', store => done(store.getAll()));\n\t};\n\tconst putRecord = async record => {\n\t\tconst database = await db();\n\t\tawait storeOp(database, 'readwrite', store => done(store.put(record)));\n\t};\n\tconst dropRecord = async key => {\n\t\tconst database = await db();\n\t\tawait storeOp(database, 'readwrite', store => done(store.delete(key)));\n\t};\n\n\t/** Best-effort host manifest mirror (status display only; failures invisible). */\n\tasync function syncHost() {\n\t\tconst endpoint = options.endpoint ?? '/.well-known/dsh-session-toolbox';\n\t\ttry {\n\t\t\tif (hostKey === '') {\n\t\t\t\tconst probe = await fetchImpl(endpoint, { cache: 'no-store' });\n\t\t\t\thostKey = (await probe.json()).key ?? '';\n\t\t\t}\n\t\t\tconst records = (await allRecords()).slice(-500).map(({ key, sessionId, attachmentId, name, size, hash, seeded, createdAt }) =>\n\t\t\t\t({ key, sessionId, attachmentId, name, size, hash, seeded, createdAt }));\n\t\t\tawait fetchImpl(endpoint, { method: 'POST', cache: 'no-store', headers: { 'content-type': 'application/json', 'x-session-toolbox-key': hostKey },\n\t\t\t\tbody: JSON.stringify({ type: 'vault.sync', records }) });\n\t\t} catch { /* the manifest is cosmetic; the vault itself is IndexedDB */ }\n\t}\n\n\t// ---- FR4 capacity + TTL --------------------------------------------------\n\tasync function sweep() {\n\t\tconst records = await allRecords();\n\t\tconst ttlMs = limits.ttlDays * 24 * 60 * 60 * 1000;\n\t\tconst keep = [];\n\t\tconst remove = [];\n\t\tfor (const record of records) (now() - (record.createdAt ?? 0) > ttlMs ? remove : keep).push(record);\n\t\tkeep.sort((a, b) => (a.createdAt ?? 0) - (b.createdAt ?? 0));\n\t\tlet bytes = keep.reduce((total, record) => total + (record.size ?? 0), 0);\n\t\twhile (bytes > limits.maxSizeBytes && keep.length > 0) {\n\t\t\tconst oldest = keep.shift();\n\t\t\tbytes -= oldest.size ?? 0;\n\t\t\tremove.push(oldest);\n\t\t}\n\t\tfor (const record of remove) await dropRecord(record.key);\n\t\tif (remove.length > 0) notice(`\u8349\u7A3F\u4FDD\u9669\u7BB1\u5DF2\u6E05\u7406 ${remove.length} \u9879\uFF08\u8D85\u671F/\u8D85\u5BB9\u91CF\uFF09`);\n\t\tchanged();\n\t\treturn { removed: remove.length, kept: keep.length, bytes };\n\t}\n\n\t// ---- FR1 capture ---------------------------------------------------------\n\tasync function intake(sessionId, files) {\n\t\tif (!limits.enabled || sessionId === undefined || sessionId === '') return;\n\t\tfor (const item of files) {\n\t\t\tif (!isImageFile(item)) continue;\n\t\t\tconst id = (globalThis.crypto?.randomUUID?.() ?? `id-${now()}-${Math.random().toString(36).slice(2)}`);\n\t\t\tconst record = { key: `${sessionId}__${id}`, sessionId, attachmentId: id,\n\t\t\t\tname: item.name || '', type: item.type, size: item.size, hash: await contentHash(item), createdAt: now(), seeded: false };\n\t\t\trecord.blob = item;\n\t\t\tawait putRecord(record);\n\t\t\tnotice(`\u5DF2\u5907\u4EFD 1 \u5F20\u8349\u7A3F\u56FE\u7247\uFF08\u4F1A\u8BDD ${sessionId.slice(-6)}\uFF09`);\n\t\t}\n\t\tvoid syncHost();\n\t}\n\n\tconst readImages = event => [...(event.clipboardData?.files ?? event.dataTransfer?.files ?? [])].filter(isImageFile);\n\tconst fileInputImages = event => {\n\t\tconst target = event.target;\n\t\tif (!(target instanceof HTMLInputElement) || target.type !== 'file' || target.files === null) return [];\n\t\treturn [...target.files].filter(isImageFile);\n\t};\n\n\t// ---- DOM discovery (official composer markers) ----------------------------\n\tfunction currentSession() {\n\t\treturn document.querySelector?.('[data-conversation-session]')?.getAttribute?.('data-conversation-session') ?? '';\n\t}\n\tfunction composerRoot() {\n\t\treturn document.querySelector?.('[data-conversation-session] [contenteditable=\"true\"]') ?? undefined;\n\t}\n\tfunction attachmentRail(editor) {\n\t\t// Official structure: attachment cards are imgs with blob: srcs sitting\n\t\t// above the contenteditable root inside the composer bar subtree.\n\t\tconst bar = editor?.closest?.('[data-composer-bar], [data-conversation-region=\"composer\"]') ?? editor?.parentElement?.parentElement?.parentElement;\n\t\tif (bar?.querySelectorAll === undefined) return undefined;\n\t\treturn [...bar.querySelectorAll('img')].filter(img => img.getAttribute?.('src')?.startsWith('blob:'));\n\t}\n\n\t// ---- FR2 restore -----------------------------------------------------------\n\tasync function seedSession(sessionId = currentSession()) {\n\t\tif (sessionId === undefined || sessionId === '' || !limits.enabled) return false;\n\t\tconst editor = composerRoot();\n\t\tif (editor === undefined) return false;\n\t\tconst rail = attachmentRail(editor);\n\t\tif (rail === undefined) return false;\n\t\tif (rail.length > 0) return true; // non-empty: official still holds them (or was seeded before)\n\t\tconst pending = (await allRecords()).filter(record => record.sessionId === sessionId);\n\t\tif (pending.length === 0) return true;\n\t\tconst files = [];\n\t\tfor (const record of pending) {\n\t\t\ttry { files.push(await blobToFile(record)); }\n\t\t\tcatch { await dropRecord(record.key); } // unreadable backup \u2014 drop and move on\n\t\t}\n\t\tif (files.length === 0) { changed(); return false; }\n\t\tconst event = new ClipboardEvent('paste', { bubbles: true, cancelable: true });\n\t\tObject.defineProperty(event, 'clipboardData', { value: fakeClipboardData(files) });\n\t\ttry { editor.focus?.(); } catch { /* ignore */ }\n\t\teditor.dispatchEvent(event);\n\t\tconst accepted = event.defaultPrevented === true;\n\t\tif (accepted) notice(`\u5DF2\u6062\u590D ${files.length} \u5F20\u8349\u7A3F\u56FE\u7247\uFF08\u4F1A\u8BDD ${sessionId.slice(-6)}\uFF09`);\n\t\telse log('warn', 'synthetic paste was not accepted; vault stays idle for this session');\n\t\tchanged();\n\t\treturn accepted;\n\t}\n\n\t// ---- FR3 lifecycle ---------------------------------------------------------\n\tfunction watchSession(sessionId, editor) {\n\t\tlet rail = attachmentRail(editor)?.length ?? 0;\n\t\tconst scope = editor.closest?.('[data-conversation-content]') ?? editor;\n\t\tconst check = async () => {\n\t\t\tconst next = attachmentRail(editor)?.length ?? rail;\n\t\t\tif (next === rail) return;\n\t\t\tif (rail > 0 && next === 0 && scope?.isConnected === true) {\n\t\t\t\t// Sent or manually removed while mounted \u2192 backups retire (\u00A7 FR3).\n\t\t\t\tfor (const record of await allRecords()) if (record.sessionId === sessionId) await dropRecord(record.key);\n\t\t\t\tnotice('\u672C\u4F1A\u8BDD\u8349\u7A3F\u56FE\u7247\u5DF2\u6E05\u7A7A\uFF0C\u5907\u4EFD\u540C\u6B65\u79FB\u9664');\n\t\t\t\tvoid syncHost();\n\t\t\t}\n\t\t\trail = next;\n\t\t\tchanged();\n\t\t};\n\t\tif (typeof MutationObserver !== 'function') return () => {};\n\t\tconst observer = new MutationObserver(() => void check());\n\t\tobserver.observe(scope, { subtree: true, childList: true });\n\t\treturn () => observer.disconnect();\n\t}\n\n\tfunction watchMounts() {\n\t\tlet boundSession = '', dispose = () => {};\n\t\tconst sync = async () => {\n\t\t\tconst sessionId = currentSession();\n\t\t\tconst editor = composerRoot();\n\t\t\tif (sessionId === '' || editor === undefined) return;\n\t\t\tif (sessionId === boundSession && editor.isConnected !== false) return;\n\t\t\tboundSession = sessionId;\n\t\t\tdispose();\n\t\t\tdispose = watchSession(sessionId, editor);\n\t\t\tsetTimeout(() => void seedSession(sessionId).catch(error => log('warn', `vault seed failed: ${error.message}`)), 120);\n\t\t\tvoid sweep().catch(() => {});\n\t\t};\n\t\tconst interval = setInterval(() => void sync(), 5000);\n\t\tif (typeof MutationObserver !== 'function') return () => clearInterval(interval);\n\t\tconst observer = new MutationObserver(() => void sync());\n\t\tobserver.observe(document.documentElement, { subtree: true, childList: true, attributes: true, attributeFilter: ['data-conversation-session'] });\n\t\treturn () => { observer.disconnect(); clearInterval(interval); dispose(); };\n\t}\n\n\treturn {\n\t\ton: bus.on, off: bus.off,\n\t\tget lastNotice() { return lastNotice; },\n\t\tcurrentSession,\n\t\trecords: allRecords,\n\t\tcountFor: async sessionId => {\n\t\t\tconst records = await allRecords();\n\t\t\treturn sessionId === undefined || sessionId === '' ? records.length : records.filter(record => record.sessionId === sessionId).length;\n\t\t},\n\t\tstart: async ({ limits: override } = {}) => {\n\t\t\tif (started || typeof document === 'undefined') return false;\n\t\t\tstarted = true;\n\t\t\tif (override !== undefined) limits = { ...limits, ...override };\n\t\t\telse {\n\t\t\t\ttry {\n\t\t\t\t\tconst res = await fetchImpl(`${options.endpoint ?? '/.well-known/dsh-session-toolbox'}`, { cache: 'no-store' });\n\t\t\t\t\tconst next = await res.json();\n\t\t\t\t\tlimits = { ...limits, ...(next.settings?.draftVault ?? {}) };\n\t\t\t\t} catch { /* defaults hold */ }\n\t\t\t}\n\t\t\tdocument.addEventListener('paste', event => void intake(currentSession(), readImages(event)).catch(() => {}), true);\n\t\t\tdocument.addEventListener('drop', event => void intake(currentSession(), readImages(event)).catch(() => {}), true);\n\t\t\tdocument.addEventListener('change', event => void intake(currentSession(), fileInputImages(event)).catch(() => {}), true);\n\t\t\tteardown = watchMounts();\n\t\t\tvoid sweep().catch(() => {});\n\t\t\tlog('info', 'draft vault started');\n\t\t\treturn true;\n\t\t},\n\t\tstop: () => { if (started) { started = false; teardown?.(); teardown = null; } },\n\t\tsetLimits: next => {\n\t\t\tlimits = { ...limits, ...next };\n\t\t\tif (limits.enabled === false) void (async () => { for (const record of await allRecords()) await dropRecord(record.key); notice('\u8349\u7A3F\u4FDD\u9669\u7BB1\u5DF2\u505C\u7528\uFF0C\u5B58\u91CF\u5DF2\u6E05\u7A7A'); })();\n\t\t},\n\t\tsweep,\n\t\tseedSession,\n\t\tintake,\n\t\twatchMounts,\n\t};\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/**\n * dsh-session-toolbox browser plugin: management page (\u00A74 FR5/FR6, \u00A710 MR6, \u00A711\n * TB2), session context-menu entries, the input-dock vault badge, and the\n * draft vault itself (capture + IndexedDB + synthetic-paste restore; route A).\n * Every official surface is probed (`ctx.get?.`, guarded registrations); no\n * path here may take the native composer down with it (NFR3).\n */\nimport { useEffect, useRef, useState } from 'react';\nimport pkg from '../package.json' with { type: 'json' };\nconst pluginVersion = pkg.version;\nimport { createVault } from './draft-vault.js';\n\nexport const name = 'dsh-session-toolbox-client';\nexport const inject = ['slots'];\nexport const NS = 'dsh-session-toolbox';\nconst ENDPOINT = `/.well-known/${NS}`;\n\nlet vault; // browser-side singleton (IndexedDB + host manifest)\nlet directoryPicker; // ctx.get('directoryPicker') probed at apply time\nconst store = { state: null, error: '', listeners: new Set() };\n\nasync function readResponse(res) {\n\tlet next;\n\ttry { next = JSON.parse(await res.text()); }\n\tcatch { throw new Error(`\u63D2\u4EF6\u540E\u53F0\u672A\u5C31\u7EEA\uFF08HTTP ${res.status}\uFF09\uFF1B\u5B89\u88C5\u6216\u91CD\u542F\u671F\u95F4\u4F1A\u81EA\u52A8\u91CD\u8BD5`); }\n\tif (next === null || typeof next !== 'object' || Array.isArray(next)) throw new Error('\u63D2\u4EF6\u540E\u53F0\u8FD4\u56DE\u4E86\u65E0\u6548\u6570\u636E');\n\tif (!res.ok) throw new Error(next.error ?? `\u64CD\u4F5C\u5931\u8D25\uFF08HTTP ${res.status}\uFF09`);\n\treturn next;\n}\n\n/** GET the shared snapshot; also (re)binds the write key the host rotates. */\nexport let sessionKey = '';\nexport async function loadState() {\n\ttry {\n\t\tconst next = await readResponse(await fetch(ENDPOINT, { cache: 'no-store' }));\n\t\tstore.state = next; store.error = ''; sessionKey = next.key ?? sessionKey;\n\t} catch (error) { store.error = error.message; }\n\tfor (const listener of store.listeners) listener();\n\treturn store.state;\n}\nexport async function callHost(input) {\n\tif (!sessionKey) await loadState();\n\tconst res = await readResponse(await fetch(ENDPOINT, {\n\t\tmethod: 'POST', cache: 'no-store',\n\t\theaders: { 'content-type': 'application/json', 'x-session-toolbox-key': sessionKey },\n\t\tbody: JSON.stringify(input),\n\t}));\n\tsessionKey = res.key ?? sessionKey;\n\tfor (const listener of store.listeners) listener();\n\treturn res;\n}\n\nexport function apply(ctx) {\n\tdirectoryPicker = ctx.get?.('directoryPicker');\n\tconst vaultInstance = vault ??= createVault({\n\t\tendpoint: ENDPOINT,\n\t\tlog: (level, message) => { try { (level === 'error' ? console.warn : console.log)(`[${NS}]`, message); } catch {} },\n\t});\n\tvoid loadState();\n\tconst timer = setInterval(() => void loadState(), 30000);\n\tctx.effect?.(() => () => clearInterval(timer));\n\tvaultInstance.on('change', () => void loadState());\n\tvoid vaultInstance.start();\n\tctx.locale?.register?.(NS, {\n\t\tzh: { 'menu.move': '\u5207\u6362\u5230\u5176\u5B83\u9879\u76EE\u2026', 'menu.trash': '\u79FB\u5165\u56DE\u6536\u7AD9' },\n\t\ten: { 'menu.move': 'Move to another project\u2026', 'menu.trash': 'Move to trash' },\n\t});\n\n\t// Keyed slot (one occupant = package name): the plugin settings page.\n\tctx.slots.inject('plugins.bundle.config', () => ctx.slots.register({ name: 'plugins.bundle.config', key: NS }, KitPage));\n\t// Session context menu: move + trash entries beside the official four.\n\tctx.slots.inject('sidebar.workspaces.session.menu.item', () => ctx.slots.register({ name: 'sidebar.workspaces.session.menu.item', id: 'session-toolbox-move', order: 500, locale: NS }, MoveSessionMenuItem));\n\tctx.slots.inject('sidebar.workspaces.session.menu.item', () => ctx.slots.register({ name: 'sidebar.workspaces.session.menu.item', id: 'session-toolbox-trash', order: 600, locale: NS }, TrashSessionMenuItem));\n\t// Input dock badge (\u00A74 FR5): how many image drafts are backed up here.\n\tctx.slots.inject('conversation.input.dock', () => ctx.slots.register({ name: 'conversation.input.dock', id: 'session-toolbox-vault-badge', order: 5, locale: NS }, VaultBadge));\n}\n\nfunction useKit() {\n\tconst [, bump] = useState(0);\n\tuseEffect(() => {\n\t\tconst listener = () => bump(n => n + 1);\n\t\tstore.listeners.add(listener);\n\t\tvoid loadState();\n\t\treturn () => store.listeners.delete(listener);\n\t}, []);\n\treturn store;\n}\n\nconst styles = `\n.sk{--sk-accent:var(--dsw-alias-state-active-primary,#3a71db);--sk-border:var(--dsw-alias-border-l2,#444);--sk-bg:var(--dsw-alias-bg-layer-1,#202020);--sk-card:var(--dsw-alias-bg-module-platform,#282828);--sk-text:var(--dsw-alias-label-primary,#f4f4f4);--sk-muted:var(--dsw-alias-label-secondary,#b0b0b0);color:var(--sk-text);font:inherit;font-size:14px;line-height:1.6;max-width:1120px}\n.sk *{box-sizing:border-box}.sk h2,.sk h3,.sk p{margin:0}.sk h2{font-size:22px}.sk h3{font-size:16px}.sk .muted,.sk small{color:var(--sk-muted)}\n.sk .box{border:1px solid var(--sk-border);border-radius:12px;padding:18px 20px;background:var(--sk-card);display:flex;flex-direction:column;gap:14px}\n.sk .row{display:flex;gap:10px;align-items:center;flex-wrap:wrap}.sk .stack{display:flex;flex-direction:column;gap:16px}\n.sk button,.sk input,.sk select{font:inherit;color:inherit;border:1px solid var(--sk-border);border-radius:8px;background:var(--sk-bg);min-height:36px;padding:7px 12px}\n.sk button{cursor:pointer}.sk button:hover{background:var(--sk-card)}.sk button:disabled{opacity:.45;cursor:default}\n.sk button.primary{background:var(--sk-accent);color:#fff;border-color:transparent}\n.sk table{width:100%;border-collapse:collapse;font-size:13px}.sk th,.sk td{border-bottom:1px solid var(--sk-border);padding:8px;text-align:left}.sk th{color:var(--sk-muted);font-weight:500}\n.sk .error{color:var(--dsw-alias-state-error-primary,#ef9393)}.sk .good{color:var(--dsw-alias-state-success-primary,#77ca9d)}\n.sk .pill{border:1px solid var(--sk-border);border-radius:100px;padding:2px 10px;font-size:12px;background:var(--sk-bg);display:inline-block}\n.sk .mono{font:12px ui-monospace,monospace;overflow-wrap:anywhere}\n.sk dialog{color:var(--sk-text);background:var(--sk-bg);border:1px solid var(--sk-border);border-radius:14px;width:min(560px,calc(100vw - 32px));padding:0}\n.sk dialog::backdrop{background:#0007}.sk .modal-head{padding:16px 20px;border-bottom:1px solid var(--sk-border);display:flex;justify-content:space-between;align-items:center}\n.sk .modal-body{padding:20px;display:flex;flex-direction:column;gap:14px}\n.sk input.grow{flex:1;min-width:0}\n`;\n\nexport function KitPage() {\n\tconst { state, error } = useKit();\n\tconst [busy, setBusy] = useState(false);\n\tconst [feedback, setFeedback] = useState('');\n\tconst say = message => { setFeedback(message); setTimeout(() => setFeedback(''), 8000); };\n\tconst act = async (input, ok) => {\n\t\tsetBusy(true);\n\t\ttry { const result = await callHost(input); if (ok) say(ok); await loadState(); setBusy(false); return result; }\n\t\tcatch (err) { say(`\u5931\u8D25\uFF1A${err.message}`); setBusy(false); throw err; }\n\t};\n\tconst settings = state?.settings;\n\treturn (\n\t\t<div className=\"sk\">\n\t\t\t<style>{styles}</style>\n\t\t\t<h2>\u4F1A\u8BDD\u5DE5\u5177\u7BB1</h2>\n\t\t\t<p className=\"muted\">\u8349\u7A3F\u4FDD\u9669\u7BB1 \u00B7 \u4F1A\u8BDD\u5207\u6362\u9879\u76EE \u00B7 \u56DE\u6536\u7AD9 \u2014 v{pluginVersion}\u3002\u6570\u636E\u4EC5\u5B58\u672C\u673A\uFF08\u6D4F\u89C8\u5668 IndexedDB + ~/.dsh/session-toolbox/\uFF09\u3002</p>\n\t\t\t{error ? <p className=\"error\">\u540E\u53F0\u8FDE\u63A5\u5931\u8D25\uFF1A{error}</p> : null}\n\t\t\t{feedback ? <p className=\"good\">{feedback}</p> : null}\n\t\t\t<section className=\"box\">\n\t\t\t\t<h3>\u8349\u7A3F\u4FDD\u9669\u7BB1\uFF08\u56FE\u7247\u8349\u7A3F\u6301\u4E45\u5316\uFF09</h3>\n\t\t\t\t{settings ? (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<div className=\"row\">\n\t\t\t\t\t\t\t<label className=\"row\"><input type=\"checkbox\" checked={settings.draftVault?.enabled !== false} disabled={busy}\n\t\t\t\t\t\t\t\tonChange={e => void act({ type: 'settings.update', patch: { draftVault: { ...settings.draftVault, enabled: e.target.checked } } }, e.target.checked ? '\u5DF2\u542F\u7528\u8349\u7A3F\u4FDD\u9669\u7BB1' : '\u5DF2\u505C\u7528\u8349\u7A3F\u4FDD\u9669\u7BB1\uFF08\u6D4F\u89C8\u5668\u4FA7\u5373\u65F6\u751F\u6548\uFF09').catch(() => {})} /> \u542F\u7528</label>\n\t\t\t\t\t\t\t<span className=\"pill\">\u5BB9\u91CF {Math.round((settings.draftVault?.maxSizeBytes ?? 0) / 1048576)} MB</span>\n\t\t\t\t\t\t\t<span className=\"pill\">\u4FDD\u7559 {settings.draftVault?.ttlDays ?? 7} \u5929</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"row\">\n\t\t\t\t\t\t\t<span className=\"muted\">\u6E05\u5355\uFF1A\u5DF2\u5907\u4EFD {state?.vault?.records ?? 0} \u9879 \u00B7 \u7EA6 {fmtBytes(state?.vault?.bytes ?? 0)}\uFF08\u56FE\u7247\u5B57\u8282\u5728 IndexedDB\uFF0C\u8D85\u51FA\u4E0A\u9650\u6309\u6700\u65E7\u6E05\u7406\uFF0C\u4E8B\u4EF6\u4F1A\u663E\u793A\u5728\u8FD9\u91CC\uFF09</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t{state?.vault?.notice ? <p className=\"muted\">{state.vault.notice}</p> : null}\n\t\t\t\t\t\t<div className=\"row\"><button disabled={busy} onClick={() => void act({ type: 'vault.sweep' }, '\u5DF2\u6309 TTL/\u5BB9\u91CF\u6E05\u7406').catch(() => {})}>\u7ACB\u5373\u6574\u7406</button></div>\n\t\t\t\t\t</>\n\t\t\t\t) : <p className=\"muted\">\u7B49\u5F85\u540E\u53F0\u6570\u636E\u2026</p>}\n\t\t\t</section>\n\t\t\t<MoveSection act={act} busy={busy} say={say} state={state} />\n\t\t\t<TrashSection act={act} busy={busy} say={say} state={state} />\n\t\t</div>\n\t);\n}\n\nfunction MoveSection({ act, busy, say, state }) {\n\tconst [sessionId, setSessionId] = useState('');\n\tconst [toCwd, setToCwd] = useState('');\n\tconst [createTarget, setCreateTarget] = useState(false);\n\tconst [plan, setPlan] = useState(null);\n\tconst journal = state?.journal;\n\tconst pick = async () => {\n\t\ttry {\n\t\t\tconst result = await directoryPicker?.pick?.();\n\t\t\tconst value = result?.ok ? result.value : undefined;\n\t\t\tif (typeof value === 'string' && value) setToCwd(value);\n\t\t\telse say('\u5F53\u524D DSH \u672A\u63D0\u4F9B\u76EE\u5F55\u9009\u62E9\u5668\uFF08\u6216\u5DF2\u53D6\u6D88\uFF09\uFF0C\u8BF7\u624B\u52A8\u8F93\u5165\u7EDD\u5BF9\u8DEF\u5F84');\n\t\t} catch (error) { say(`\u76EE\u5F55\u9009\u62E9\u5931\u8D25\uFF1A${error.message}`); }\n\t};\n\treturn (\n\t\t<section className=\"box\">\n\t\t\t<h3>\u4F1A\u8BDD\u5207\u6362\u9879\u76EE</h3>\n\t\t\t{journal && <p className=\"error\">\u5B58\u5728\u672A\u5B8C\u6210\u7684\u8FC1\u79FB\uFF1A{journal.sessionId} \u2192 {journal.toCwd}\uFF08\u5DF2\u5B8C\u6210 {journal.done?.join('/') || '\u65E0'}\uFF09\u3002\n\t\t\t\t<button disabled={busy} onClick={() => void act({ type: 'move.complete' }, '\u8FC1\u79FB\u5DF2\u524D\u6EDA\u5B8C\u6210').catch(() => {})}>\u5B8C\u6210</button>\n\t\t\t\t{' '}<button disabled={busy} onClick={() => void act({ type: 'move.rollback' }, '\u8FC1\u79FB\u5DF2\u56DE\u6EDA').catch(() => {})}>\u56DE\u6EDA</button></p>}\n\t\t\t<div className=\"row\">\n\t\t\t\t<input className=\"grow mono\" placeholder=\"session-\u2026\uFF08\u6216\u4ECE\u4F1A\u8BDD\u53F3\u952E\u83DC\u5355\u53D1\u8D77\uFF09\" value={sessionId} onChange={e => { setSessionId(e.target.value); setPlan(null); }} />\n\t\t\t\t<input className=\"grow mono\" placeholder=\"\u76EE\u6807\u9879\u76EE\u7EDD\u5BF9\u8DEF\u5F84\" value={toCwd} onChange={e => { setToCwd(e.target.value); setPlan(null); }} />\n\t\t\t\t<button onClick={() => void pick()} disabled={busy}>\u6D4F\u89C8\u2026</button>\n\t\t\t</div>\n\t\t\t<label className=\"row\"><input type=\"checkbox\" checked={createTarget} onChange={e => setCreateTarget(e.target.checked)} /> \u76EE\u6807\u4E0D\u5B58\u5728\u65F6\u521B\u5EFA</label>\n\t\t\t<div className=\"row\">\n\t\t\t\t<button disabled={busy || !sessionId || !toCwd} onClick={() => { setBusy(true); setPlan(null); void callHost({ type: 'preflight', sessionId, toCwd, createTarget })\n\t\t\t\t\t.then(result => setPlan(result)).catch(error => say(`\u4F53\u68C0\u5931\u8D25\uFF1A${error.message}`)).finally(() => setBusy(false)); }}>\u4F53\u68C0</button>\n\t\t\t\t<button className=\"primary\" disabled={busy || plan?.toProject === undefined} onClick={() => void act({ type: 'move', sessionId, toCwd, createTarget }, '\u8FC1\u79FB\u5B8C\u6210\uFF1B\u5176\u5B83\u7A97\u53E3\u8BF7\u91CD\u5F00\u8BE5\u4F1A\u8BDD').catch(() => {})}>\u8FC1\u79FB</button>\n\t\t\t</div>\n\t\t\t{plan?.toProject && (\n\t\t\t\t<pre className=\"mono muted\" style={{ whiteSpace: 'pre-wrap' }}>{JSON.stringify({ \u4ECE: plan.fromCwd, \u5230: plan.toCwd, \u539F\u76EE\u5F55: plan.fromProject, \u65B0\u76EE\u5F55: plan.toProject, \u65E5\u5FD7\u6587\u4EF6: plan.logName }, null, 2)}</pre>\n\t\t\t)}\n\t\t\t<p className=\"muted\">\u53EA\u6539 DSH \u5185\u90E8\u5F52\u5C5E\u4E0E\u4F1A\u8BDD\u5934\uFF1B\u5386\u53F2\u4E0D\u53D8\uFF0C\u65E7\u6D88\u606F\u4E2D\u7684\u7EDD\u5BF9\u8DEF\u5F84\u4ECD\u6307\u5411\u539F\u9879\u76EE\uFF08\u5DF2\u77E5\u8BED\u4E49\uFF09\u3002\u8FC1\u79FB\u524D\u8BF7\u5173\u95ED\u8BE5\u4F1A\u8BDD\u3002</p>\n\t\t</section>\n\t);\n}\n\nfunction TrashSection({ act, busy, say, state }) {\n\tconst items = state?.trash ?? [];\n\treturn (\n\t\t<section className=\"box\">\n\t\t\t<h3>\u56DE\u6536\u7AD9</h3>\n\t\t\t<p className=\"muted\">\u5220\u9664\u4F1A\u8BDD = \u5B98\u65B9\u5F52\u6863 + \u5165\u7AD9\u8BB0\u5F55\uFF1B\u5220\u9664\u9879\u76EE\u4FDD\u7559\u5168\u90E8\u4F1A\u8BDD\u65E5\u5FD7\u3002\u5F7B\u5E95\u5220\u9664\u4F1A\u5148\u79FB\u5230\u6682\u5B58\u76EE\u5F55\u518D\u6E05\u7406\uFF0C\u4E2D\u65AD\u53EF\u7528 CLI \u68C0\u51FA\u3002</p>\n\t\t\t{items.length === 0 ? <p className=\"muted\">\uFF08\u7A7A\uFF09</p> : (\n\t\t\t\t<table>\n\t\t\t\t\t<thead><tr><th>\u7C7B\u578B</th><th>\u5BF9\u8C61</th><th>\u6807\u9898 / \u8DEF\u5F84</th><th>\u5165\u7AD9\u65F6\u95F4</th><th /></tr></thead>\n\t\t\t\t\t<tbody>{items.map(item => (\n\t\t\t\t\t\t<tr key={item.itemId}>\n\t\t\t\t\t\t\t<td>{item.kind === 'session' ? '\u4F1A\u8BDD' : '\u9879\u76EE'}</td>\n\t\t\t\t\t\t\t<td className=\"mono\">{shortId(item.targetId)}</td>\n\t\t\t\t\t\t\t<td className=\"mono\">{item.kind === 'session' ? item.snapshot.title || '\uFF08\u65E0\u6807\u9898\uFF09' : item.snapshot.path}</td>\n\t\t\t\t\t\t\t<td>{new Date(item.trashedAt).toLocaleString('zh-CN', { hour12: false })}</td>\n\t\t\t\t\t\t\t<td className=\"row\">\n\t\t\t\t\t\t\t\t<button disabled={busy} onClick={() => void act({ type: 'trash.restore', itemId: item.itemId }, '\u5DF2\u8FD8\u539F\uFF08\u82E5\u5904\u4E8E\u5F52\u6863\u6001\u8BF7\u5148\u5728\u5217\u8868\u91CC\u8FD8\u539F\u5F52\u6863\uFF09').catch(() => {})}>\u8FD8\u539F</button>\n\t\t\t\t\t\t\t\t<button disabled={busy} onClick={() => void act({ type: 'trash.purge', itemId: item.itemId }, '\u5DF2\u5F7B\u5E95\u5220\u9664').catch(() => {})}>\u5F7B\u5E95\u5220\u9664</button>\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t</tr>))}\n\t\t\t\t\t</tbody>\n\t\t\t\t</table>\n\t\t\t)}\n\t\t\t<div className=\"row\">\n\t\t\t\t<span className=\"muted\">\u4FDD\u7559 {state?.settings?.trash?.ttlDays ?? 30} \u5929\uFF1B\u5230\u671F\u81EA\u52A8\u6E05\u7406{state?.settings?.trash?.autoPurge ? '\uFF08\u5DF2\u5F00\uFF09' : '\uFF08\u672A\u5F00\uFF0C\u4EC5\u63D0\u9192\uFF09'}\u3002</span>\n\t\t\t\t<button disabled={busy} onClick={() => void act({ type: 'settings.update', patch: { trash: { ...state?.settings?.trash, autoPurge: !(state?.settings?.trash?.autoPurge) } } }, '\u7B56\u7565\u5DF2\u66F4\u65B0').catch(() => {})}>\u5207\u6362\u81EA\u52A8\u6E05\u7406</button>\n\t\t\t\t<button disabled={busy} onClick={() => void act({ type: 'trash.sweep' }, '\u5DF2\u6309 TTL \u5DE1\u68C0').catch(() => {})}>\u5DE1\u68C0\u5230\u671F\u9879</button>\n\t\t\t</div>\n\t\t</section>\n\t);\n}\n\nconst shortId = id => String(id).length > 18 ? `${String(id).slice(0, 8)}\u2026${String(id).slice(-6)}` : String(id);\nconst fmtBytes = n => n >= 1048576 ? `${(n / 1048576).toFixed(1)} MB` : n >= 1024 ? `${(n / 1024).toFixed(1)} KB` : `${n} B`;\n\n/** Menu entry: move this session to another project (\u00A710 MR6). */\nexport function MoveSessionMenuItem({ sessionId, t }) {\n\tconst [open, setOpen] = useState(false);\n\treturn (\n\t\t<>\n\t\t\t<button role=\"menuitem\" onClick={() => setOpen(true)} style={menuItemStyle}>{t ? t('menu.move') : '\u5207\u6362\u5230\u5176\u5B83\u9879\u76EE\u2026'}</button>\n\t\t\t{open ? <MoveDialog sessionId={sessionId} close={() => setOpen(false)} /> : null}\n\t\t</>\n\t);\n}\n\nexport function TrashSessionMenuItem({ sessionId, t }) {\n\tconst [confirm, setConfirm] = useState(false);\n\tconst [busy, setBusy] = useState(false);\n\tif (confirm) {\n\t\treturn <button role=\"menuitem\" disabled={busy} style={menuItemStyle} onClick={async () => {\n\t\t\tsetBusy(true);\n\t\t\ttry { await callHost({ type: 'trash.session', sessionId }); setConfirm(false); }\n\t\t\tcatch { sayRow(`\u56DE\u6536\u5931\u8D25`); setConfirm(false); }\n\t\t\tsetBusy(false);\n\t\t}}>\u786E\u8BA4\u79FB\u5165\u56DE\u6536\u7AD9\uFF1F\uFF08\u5148\u5F52\u6863\uFF09</button>;\n\t}\n\treturn <button role=\"menuitem\" style={menuItemStyle} onClick={() => setConfirm(true)}>{t ? t('menu.trash') : '\u79FB\u5165\u56DE\u6536\u7AD9'}</button>;\n}\nfunction sayRow(message) { store.error = message; for (const listener of store.listeners) listener(); }\n\nconst menuItemStyle = { background: 'transparent', border: 'none', color: 'inherit', font: 'inherit', padding: '6px 10px', textAlign: 'left', cursor: 'pointer', width: '100%' };\n\nexport function MoveDialog({ sessionId, close }) {\n\tconst ref = useRef(null);\n\tconst [toCwd, setToCwd] = useState('');\n\tconst [createTarget, setCreateTarget] = useState(false);\n\tconst [error, setError] = useState('');\n\tconst [busy, setBusy] = useState(false);\n\tuseEffect(() => { const dialog = ref.current; dialog?.showModal(); return () => { try { dialog?.close(); } catch {} }; }, []);\n\tconst submit = async () => {\n\t\tsetBusy(true); setError('');\n\t\ttry { await callHost({ type: 'move', sessionId, toCwd, createTarget }); close(); }\n\t\tcatch (err) { setError(err.message); setBusy(false); }\n\t};\n\tconst valid = /^\\/|^[A-Za-z]:[\\\\/]/.test(toCwd);\n\treturn (\n\t\t<div className=\"sk\"><style>{styles}</style>\n\t\t\t<dialog ref={ref} onCancel={e => { e.preventDefault(); if (!busy) close(); }}>\n\t\t\t\t<div className=\"modal-head\"><strong>\u4F1A\u8BDD\u5207\u6362\u5230\u5176\u5B83\u9879\u76EE</strong><button onClick={close} disabled={busy}>\u5173\u95ED</button></div>\n\t\t\t\t<div className=\"modal-body\">\n\t\t\t\t\t<p className=\"muted mono\">{sessionId}</p>\n\t\t\t\t\t<input autoFocus className=\"grow mono\" placeholder=\"\u76EE\u6807\u9879\u76EE\u7EDD\u5BF9\u8DEF\u5F84\" value={toCwd} onChange={e => setToCwd(e.target.value)} />\n\t\t\t\t\t<label className=\"row\"><input type=\"checkbox\" checked={createTarget} onChange={e => setCreateTarget(e.target.checked)} /> \u76EE\u5F55\u4E0D\u5B58\u5728\u65F6\u521B\u5EFA</label>\n\t\t\t\t\t{error ? <p className=\"error\">{error}</p> : null}\n\t\t\t\t\t<div className=\"row\"><button className=\"primary\" disabled={busy || !valid} onClick={() => void submit()}>\u4F53\u68C0\u5E76\u8FC1\u79FB</button>\n\t\t\t\t\t\t<span className=\"muted\">\u4F1A\u8BDD\u9700\u7A7A\u95F2\uFF1B\u8FC1\u79FB\u5728\u540E\u53F0\u79BB\u7EBF\u5B8C\u6210\u3002</span></div>\n\t\t\t\t</div>\n\t\t\t</dialog>\n\t\t</div>\n\t);\n}\n\n/** Input-dock badge (\u00A74 FR5): how many image drafts are backed up for this session. */\nexport function VaultBadge({ sessionId }) {\n\tconst [count, setCount] = useState(0);\n\tconst [notice, setNotice] = useState('');\n\tuseEffect(() => {\n\t\tif (vault === undefined) return;\n\t\tlet live = true;\n\t\tconst sync = async () => {\n\t\t\ttry { const value = await vault.countFor(sessionId ?? vault.currentSession()); if (live) setCount(value); }\n\t\t\tcatch { if (live) setCount(0); }\n\t\t\tif (live) setNotice(vault.lastNotice ?? '');\n\t\t};\n\t\tvoid sync();\n\t\tconst listener = () => void sync();\n\t\tvault.on('change', listener);\n\t\twindow.addEventListener(`${NS}-notice`, listener);\n\t\tconst timer = setInterval(listener, 20000);\n\t\treturn () => { live = false; vault.off('change', listener); window.removeEventListener(`${NS}-notice`, listener); clearInterval(timer); };\n\t}, [sessionId]);\n\tif (count === 0) return null; // the notice channel serves the panel; the badge anchors per-session counts\n\treturn <span className=\"sk\"><span className=\"pill\" title={`\u672C\u4F1A\u8BDD\u6709 ${count} \u5F20\u56FE\u7247\u8349\u7A3F\u5DF2\u5907\u4EFD\uFF08\u5207\u6362\u4F1A\u8BDD/\u5237\u65B0/\u91CD\u542F\u540E\u53EF\u6062\u590D\uFF09${notice ? `\uFF5C\u6700\u8FD1\uFF1A${notice}` : ''}`}>\uD83D\uDEDF \u8349\u7A3F\u5907\u4EFD {count}</span></span>;\n}\n", "{\n \"name\": \"dsh-session-toolbox\",\n \"version\": \"0.1.3\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/AndroidSix/dsh-session-toolbox.git\"\n },\n \"description\": \"Draft vault, session-to-project move and a trash bin for DeepSeek Harness\",\n \"type\": \"module\",\n \"main\": \"lib/index.js\",\n \"bin\": {\n \"dsh-session-toolbox\": \"lib/cli.js\"\n },\n \"exports\": {\n \".\": \"./lib/index.js\",\n \"./host\": \"./lib/host.js\",\n \"./client\": \"./lib/client.js\",\n \"./cordis.patch.yml\": \"./cordis.patch.yml\",\n \"./package.json\": \"./package.json\"\n },\n \"engines\": {\n \"node\": \"^22.19.0 || >=24.0.0\",\n \"dsh\": \"^0.2.0-rc.2 || ^0.2.1-rc.2\"\n },\n \"files\": [\n \"lib\",\n \"cordis.patch.yml\",\n \"README.md\",\n \"LICENSE\",\n \"THIRD_PARTY_NOTICES.md\",\n \"session-toolbox.example.json\",\n \"CHANGELOG.md\"\n ],\n \"dsh\": {\n \"bundle\": {\n \"patch\": \"./cordis.patch.yml\"\n },\n \"client\": {\n \"inject\": [\n \"@deepseek-ai/dsh-client-ui-renderer\"\n ],\n \"platform\": \"web\"\n }\n },\n \"scripts\": {\n \"build\": \"node scripts/build.mjs\",\n \"test\": \"node --test tests/*.test.mjs\",\n \"check\": \"npm run build && npm test && node scripts/check-package.mjs\",\n \"check:tarball\": \"npm run build && node scripts/check-package.mjs --tarball\",\n \"pack:release\": \"npm run build && npm pack --ignore-scripts\"\n },\n \"peerDependencies\": {\n \"@deepseek-ai/cordis\": \"^4.0.4\",\n \"@deepseek-ai/dsh-atomic-write\": \"^0.2.0-rc.2 || ^0.2.1-rc.2\",\n \"@deepseek-ai/dsh-home-paths\": \"^0.2.0-rc.2 || ^0.2.1-rc.2\",\n \"@deepseek-ai/schemastery\": \"^3.18.4\",\n \"react\": \"^18.2.0\"\n },\n \"devDependencies\": {\n \"@deepseek-ai/cordis\": \"^4.0.4\",\n \"@deepseek-ai/dsh-atomic-write\": \"^0.2.0-rc.2 || ^0.2.1-rc.2\",\n \"@deepseek-ai/dsh-home-paths\": \"^0.2.0-rc.2 || ^0.2.1-rc.2\",\n \"@deepseek-ai/schemastery\": \"^3.18.4\",\n \"esbuild\": \"^0.25.0\",\n \"react\": \"^18.2.0\",\n \"react-dom\": \"^18.2.0\"\n },\n \"license\": \"MIT\",\n \"keywords\": [\n \"dsh-plugin\",\n \"deepseek-harness\",\n \"draft-vault\",\n \"session-move\",\n \"trash-bin\"\n ]\n}\n", "/**\n * Draft vault (\u00A74-\u00A79): mirrors image drafts into IndexedDB and replays them\n * through the official paste pipeline. No official internals are touched:\n * capture listens at document-level `paste`/`drop`/file-input `change` (never\n * preventing or stopping the native flow), persistence is browser IndexedDB,\n * and restore re-dispatches a ClipboardEvent carrying a synthetic\n * `clipboardData` (Chromium ignores the ClipboardEventInit clipboardData and\n * exposes it only as a prototype accessor, so the property is shadowed with a\n * defined own property \u2014 the official handler only reads `items`/`getData`,\n * verified against the shipped build).\n *\n * Idempotency is DOM-based and safe by construction:\n * - seeding only happens into an EMPTY attachment rail;\n * - a seed is confirmed by the official handler calling preventDefault() (its\n * documented contract for accepted files);\n * - rail dropping to zero while the session view is mounted means \"sent or\n * user-deleted\" (\u00A7 FR3: both delete the backups); the view unmounting keeps\n * them \u2014 that is exactly the loss this vault repairs.\n */\n\nexport const DB_NAME = 'dsh-session-toolbox-vault';\nexport const STORE = 'blobs';\nexport const IMAGE_TYPES = ['image/png', 'image/jpeg', 'image/webp', 'image/gif'];\n/** Marks our own synthetic paste so it is not re-captured as a new draft. */\nconst SEED_MARKER = Symbol.for('dsh-session-toolbox.seed');\n\nexport const MAX_FILE_BYTES = 10 * 1024 * 1024; // the official per-image admission cap\nexport const DEFAULT_LIMITS = Object.freeze({ enabled: true, maxSizeBytes: 200 * 1024 * 1024, ttlDays: 7 });\n\nexport function isImageFile(file) {\n\treturn file !== undefined && IMAGE_TYPES.includes(file.type) && file.size > 0 && file.size <= MAX_FILE_BYTES;\n}\n\n/** sha256 hex of bytes; crypto.subtle is absent on non-secure origins \u2192 size/name fallback hash. */\nexport async function contentHash(file) {\n\tif (globalThis.crypto?.subtle !== undefined) {\n\t\ttry {\n\t\t\tconst digest = await crypto.subtle.digest('SHA-256', await file.arrayBuffer());\n\t\t\treturn [...new Uint8Array(digest)].map(byte => byte.toString(16).padStart(2, '0')).join('');\n\t\t} catch { /* fall through */ }\n\t}\n\treturn `weak:${file.size}:${file.name}:${file.lastModified}`;\n}\n\nfunction openDb() {\n\tif (typeof indexedDB === 'undefined') throw new Error('IndexedDB unavailable');\n\treturn new Promise((resolve, reject) => {\n\t\tconst request = indexedDB.open(DB_NAME, 1);\n\t\trequest.onupgradeneeded = () => {\n\t\t\tconst database = request.result;\n\t\t\tif (!database.objectStoreNames.contains(STORE)) database.createObjectStore(STORE, { keyPath: 'key' });\n\t\t};\n\t\trequest.onsuccess = () => resolve(request.result);\n\t\trequest.onerror = () => reject(request.error ?? new Error('IndexedDB open failed'));\n\t});\n}\n\n/** Resolve with the request result; reject with its error. */\nfunction done(request) {\n\treturn new Promise((resolve, reject) => {\n\t\trequest.onsuccess = () => resolve(request.result);\n\t\trequest.onerror = () => reject(request.error ?? new Error('vault storage request failed'));\n\t});\n}\n\nfunction storeOp(database, mode, run) {\n\treturn new Promise((resolve, reject) => {\n\t\tlet outcome;\n\t\tconst transaction = database.transaction(STORE, mode);\n\t\ttransaction.onabort = () => reject(transaction.error ?? new Error('vault transaction aborted'));\n\t\ttransaction.onerror = () => reject(transaction.error ?? new Error('vault transaction failed'));\n\t\ttry { outcome = run(transaction.objectStore(STORE)); } catch (error) { reject(error); return; }\n\t\tPromise.resolve(outcome).then(resolve, reject);\n\t});\n}\n\nfunction emitter() {\n\tconst listeners = new Map();\n\treturn {\n\t\ton(event, fn) { if (!listeners.has(event)) listeners.set(event, new Set()); listeners.get(event).add(fn); },\n\t\toff(event, fn) { listeners.get(event)?.delete(fn); },\n\t\temit(event, detail) { for (const fn of [...(listeners.get(event) ?? [])]) { try { fn(detail); } catch {} } },\n\t};\n}\n\nfunction fakeClipboardData(files) {\n\tconst items = files.map(f => ({ kind: 'file', type: f.type, getAsFile: () => f }));\n\treturn { items, files, length: files.length, types: ['Files'], getData: () => '', setData: () => false, clearData: () => {} };\n}\n\nasync function blobToFile(record) {\n\tif (record.blob instanceof File) return record.blob;\n\tconst blob = record.blob instanceof Blob ? record.blob : new Blob([record.blob ?? new Uint8Array()], { type: record.type });\n\treturn new File([blob], record.name ?? '', { type: record.type, lastModified: record.createdAt });\n}\n\n/**\n * @param options - {endpoint, log, now, fetchImpl}\n */\nexport function createVault(options = {}) {\n\tconst log = options.log ?? (() => {});\n\tconst now = options.now ?? (() => Date.now());\n\tconst fetchImpl = options.fetchImpl ?? ((input, init) => fetch(input, init));\n\tconst bus = emitter();\n\tlet dbPromise = null;\n\tlet limits = { ...DEFAULT_LIMITS };\n\tlet lastNotice = '';\n\tlet started = false;\n\tlet teardown = null;\n\tlet hostKey = '';\n\n\tconst db = () => dbPromise ??= openDb();\n\tfunction notice(message) {\n\t\tlastNotice = message;\n\t\tbus.emit('notice', message);\n\t\ttry { globalThis.window?.dispatchEvent?.(new CustomEvent('dsh-session-toolbox-notice', { detail: message })); } catch { /* test envs */ }\n\t}\n\tfunction changed() { bus.emit('change'); }\n\n\t// ---- IndexedDB CRUD -----------------------------------------------------\n\tconst allRecords = async () => {\n\t\tconst database = await db();\n\t\treturn await storeOp(database, 'readonly', store => done(store.getAll()));\n\t};\n\tconst putRecord = async record => {\n\t\tconst database = await db();\n\t\tawait storeOp(database, 'readwrite', store => done(store.put(record)));\n\t};\n\tconst dropRecord = async key => {\n\t\tconst database = await db();\n\t\tawait storeOp(database, 'readwrite', store => done(store.delete(key)));\n\t};\n\n\t/** Best-effort host manifest mirror (status display only; failures invisible). */\n\tasync function syncHost() {\n\t\tconst endpoint = options.endpoint ?? '/.well-known/dsh-session-toolbox';\n\t\ttry {\n\t\t\tif (hostKey === '') {\n\t\t\t\tconst probe = await fetchImpl(endpoint, { cache: 'no-store' });\n\t\t\t\thostKey = (await probe.json()).key ?? '';\n\t\t\t}\n\t\t\tconst records = (await allRecords()).slice(-500).map(({ key, sessionId, attachmentId, name, size, hash, seeded, createdAt }) =>\n\t\t\t\t({ key, sessionId, attachmentId, name, size, hash, seeded, createdAt }));\n\t\t\tawait fetchImpl(endpoint, { method: 'POST', cache: 'no-store', headers: { 'content-type': 'application/json', 'x-session-toolbox-key': hostKey },\n\t\t\t\tbody: JSON.stringify({ type: 'vault.sync', records }) });\n\t\t} catch { /* the manifest is cosmetic; the vault itself is IndexedDB */ }\n\t}\n\n\t// ---- FR4 capacity + TTL --------------------------------------------------\n\tasync function sweep() {\n\t\tconst records = await allRecords();\n\t\tconst ttlMs = limits.ttlDays * 24 * 60 * 60 * 1000;\n\t\tconst keep = [];\n\t\tconst remove = [];\n\t\tfor (const record of records) (now() - (record.createdAt ?? 0) > ttlMs ? remove : keep).push(record);\n\t\tkeep.sort((a, b) => (a.createdAt ?? 0) - (b.createdAt ?? 0));\n\t\tlet bytes = keep.reduce((total, record) => total + (record.size ?? 0), 0);\n\t\twhile (bytes > limits.maxSizeBytes && keep.length > 0) {\n\t\t\tconst oldest = keep.shift();\n\t\t\tbytes -= oldest.size ?? 0;\n\t\t\tremove.push(oldest);\n\t\t}\n\t\tfor (const record of remove) await dropRecord(record.key);\n\t\tif (remove.length > 0) notice(`\u8349\u7A3F\u4FDD\u9669\u7BB1\u5DF2\u6E05\u7406 ${remove.length} \u9879\uFF08\u8D85\u671F/\u8D85\u5BB9\u91CF\uFF09`);\n\t\tchanged();\n\t\treturn { removed: remove.length, kept: keep.length, bytes };\n\t}\n\n\t// ---- FR1 capture ---------------------------------------------------------\n\tasync function intake(sessionId, files) {\n\t\tif (!limits.enabled || sessionId === undefined || sessionId === '') return;\n\t\tconst existing = (await allRecords()).filter(record => record.sessionId === sessionId);\n\t\tconst seen = new Set(existing.map(record => record.hash));\n\t\tlet added = 0;\n\t\tfor (const item of files) {\n\t\t\tif (!isImageFile(item)) continue;\n\t\t\tconst hash = await contentHash(item);\n\t\t\tif (seen.has(hash)) continue; // same image already held for this session\n\t\t\tseen.add(hash);\n\t\t\tconst id = (globalThis.crypto?.randomUUID?.() ?? `id-${now()}-${Math.random().toString(36).slice(2)}`);\n\t\t\tconst record = { key: `${sessionId}__${id}`, sessionId, attachmentId: id,\n\t\t\t\tname: item.name || '', type: item.type, size: item.size, hash, createdAt: now(), seeded: false };\n\t\t\trecord.blob = item;\n\t\t\tawait putRecord(record);\n\t\t\tadded += 1;\n\t\t}\n\t\tif (added > 0) notice(`\u5DF2\u5907\u4EFD ${added} \u5F20\u8349\u7A3F\u56FE\u7247\uFF08\u4F1A\u8BDD ${sessionId.slice(-6)}\uFF09`);\n\t\tvoid syncHost();\n\t}\n\n\tconst readImages = event => [...(event.clipboardData?.files ?? event.dataTransfer?.files ?? [])].filter(isImageFile);\n\tconst fileInputImages = event => {\n\t\tconst target = event.target;\n\t\tif (!(target instanceof HTMLInputElement) || target.type !== 'file' || target.files === null) return [];\n\t\treturn [...target.files].filter(isImageFile);\n\t};\n\n\t// ---- DOM discovery (official composer markers) ----------------------------\n\tfunction currentSession() {\n\t\treturn document.querySelector?.('[data-conversation-session]')?.getAttribute?.('data-conversation-session') ?? '';\n\t}\n\tfunction composerRoot() {\n\t\treturn document.querySelector?.('[data-conversation-session] [contenteditable=\"true\"]') ?? undefined;\n\t}\n\tfunction attachmentRail(editor) {\n\t\t// Official structure: attachment cards are imgs with blob: srcs sitting\n\t\t// above the contenteditable root inside the composer bar subtree.\n\t\tconst bar = editor?.closest?.('[data-composer-bar], [data-conversation-region=\"composer\"]') ?? editor?.parentElement?.parentElement?.parentElement;\n\t\tif (bar?.querySelectorAll === undefined) return undefined;\n\t\treturn [...bar.querySelectorAll('img')].filter(img => img.getAttribute?.('src')?.startsWith('blob:'));\n\t}\n\n\t// ---- FR2 restore -----------------------------------------------------------\n\tasync function seedSession(sessionId = currentSession()) {\n\t\tif (sessionId === undefined || sessionId === '' || !limits.enabled) return false;\n\t\tconst editor = composerRoot();\n\t\tif (editor === undefined) return false;\n\t\tconst rail = attachmentRail(editor);\n\t\tif (rail === undefined) return false;\n\t\tif (rail.length > 0) return true; // non-empty: official still holds them (or was seeded before)\n\t\tconst pending = (await allRecords()).filter(record => record.sessionId === sessionId);\n\t\tif (pending.length === 0) return true;\n\t\tconst files = [];\n\t\tfor (const record of pending) {\n\t\t\ttry { files.push(await blobToFile(record)); }\n\t\t\tcatch { await dropRecord(record.key); } // unreadable backup \u2014 drop and move on\n\t\t}\n\t\tif (files.length === 0) { changed(); return false; }\n\t\tconst event = new ClipboardEvent('paste', { bubbles: true, cancelable: true });\n\t\tObject.defineProperty(event, 'clipboardData', { value: fakeClipboardData(files) });\n\t\t// Mark as a restore so our own intake (which observes the same event)\n\t\t// never stores the replayed images as a second fresh draft.\n\t\ttry { Object.defineProperty(event, SEED_MARKER, { value: true }); } catch { /* ignore */ }\n\t\ttry { editor.focus?.(); } catch { /* ignore */ }\n\t\teditor.dispatchEvent(event);\n\t\tconst accepted = event.defaultPrevented === true;\n\t\tif (accepted) notice(`\u5DF2\u6062\u590D ${files.length} \u5F20\u8349\u7A3F\u56FE\u7247\uFF08\u4F1A\u8BDD ${sessionId.slice(-6)}\uFF09`);\n\t\telse log('warn', 'synthetic paste was not accepted; vault stays idle for this session');\n\t\tchanged();\n\t\treturn accepted;\n\t}\n\n\t// ---- FR3 lifecycle ---------------------------------------------------------\n\tfunction watchSession(sessionId, editor) {\n\t\tlet rail = attachmentRail(editor)?.length ?? 0;\n\t\tconst scope = editor.closest?.('[data-conversation-content]') ?? editor;\n\t\tconst check = async () => {\n\t\t\tconst next = attachmentRail(editor)?.length ?? rail;\n\t\t\tif (next === rail) return;\n\t\t\tif (rail > 0 && next === 0 && scope?.isConnected === true) {\n\t\t\t\t// Sent or manually removed while mounted \u2192 backups retire (\u00A7 FR3).\n\t\t\t\tfor (const record of await allRecords()) if (record.sessionId === sessionId) await dropRecord(record.key);\n\t\t\t\tnotice('\u672C\u4F1A\u8BDD\u8349\u7A3F\u56FE\u7247\u5DF2\u6E05\u7A7A\uFF0C\u5907\u4EFD\u540C\u6B65\u79FB\u9664');\n\t\t\t\tvoid syncHost();\n\t\t\t}\n\t\t\trail = next;\n\t\t\tchanged();\n\t\t};\n\t\tif (typeof MutationObserver !== 'function') return () => {};\n\t\tconst observer = new MutationObserver(() => void check());\n\t\tobserver.observe(scope, { subtree: true, childList: true });\n\t\treturn () => observer.disconnect();\n\t}\n\n\tfunction watchMounts() {\n\t\tlet boundSession = '', dispose = () => {};\n\t\tconst sync = async () => {\n\t\t\tconst sessionId = currentSession();\n\t\t\tconst editor = composerRoot();\n\t\t\tif (sessionId === '' || editor === undefined) return;\n\t\t\tif (sessionId === boundSession && editor.isConnected !== false) return;\n\t\t\tboundSession = sessionId;\n\t\t\tdispose();\n\t\t\tdispose = watchSession(sessionId, editor);\n\t\t\tsetTimeout(() => void seedSession(sessionId).catch(error => log('warn', `vault seed failed: ${error.message}`)), 120);\n\t\t\tvoid sweep().catch(() => {});\n\t\t};\n\t\tconst interval = setInterval(() => void sync(), 5000);\n\t\tif (typeof MutationObserver !== 'function') return () => clearInterval(interval);\n\t\tconst observer = new MutationObserver(() => void sync());\n\t\tobserver.observe(document.documentElement, { subtree: true, childList: true, attributes: true, attributeFilter: ['data-conversation-session'] });\n\t\treturn () => { observer.disconnect(); clearInterval(interval); dispose(); };\n\t}\n\n\treturn {\n\t\ton: bus.on, off: bus.off,\n\t\tget lastNotice() { return lastNotice; },\n\t\tcurrentSession,\n\t\trecords: allRecords,\n\t\tcountFor: async sessionId => {\n\t\t\tconst records = await allRecords();\n\t\t\treturn sessionId === undefined || sessionId === '' ? records.length : records.filter(record => record.sessionId === sessionId).length;\n\t\t},\n\t\tstart: async ({ limits: override } = {}) => {\n\t\t\tif (started || typeof document === 'undefined') return false;\n\t\t\tstarted = true;\n\t\t\tif (override !== undefined) limits = { ...limits, ...override };\n\t\t\telse {\n\t\t\t\ttry {\n\t\t\t\t\tconst res = await fetchImpl(`${options.endpoint ?? '/.well-known/dsh-session-toolbox'}`, { cache: 'no-store' });\n\t\t\t\t\tconst next = await res.json();\n\t\t\t\t\tlimits = { ...limits, ...(next.settings?.draftVault ?? {}) };\n\t\t\t\t} catch { /* defaults hold */ }\n\t\t\t}\n\t\t\tconst capture = event => {\n\t\t\t\tif (event[SEED_MARKER] === true) return;\n\t\t\t\tvoid intake(currentSession(), readImages(event)).catch(() => {});\n\t\t\t};\n\t\t\tdocument.addEventListener('paste', capture, true);\n\t\t\tdocument.addEventListener('drop', capture, true);\n\t\t\tdocument.addEventListener('change', event => void intake(currentSession(), fileInputImages(event)).catch(() => {}), true);\n\t\t\tteardown = watchMounts();\n\t\t\tvoid sweep().catch(() => {});\n\t\t\tlog('info', 'draft vault started');\n\t\t\treturn true;\n\t\t},\n\t\tstop: () => { if (started) { started = false; teardown?.(); teardown = null; } },\n\t\tsetLimits: next => {\n\t\t\tlimits = { ...limits, ...next };\n\t\t\tif (limits.enabled === false) void (async () => { for (const record of await allRecords()) await dropRecord(record.key); notice('\u8349\u7A3F\u4FDD\u9669\u7BB1\u5DF2\u505C\u7528\uFF0C\u5B58\u91CF\u5DF2\u6E05\u7A7A'); })();\n\t\t},\n\t\tsweep,\n\t\tseedSession,\n\t\tintake,\n\t\twatchMounts,\n\t};\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["store", "name", "setBusy"]
|
|
7
7
|
}
|
|
@@ -19,7 +19,7 @@ import { resolveDshHome } from "@deepseek-ai/dsh-home-paths";
|
|
|
19
19
|
// package.json
|
|
20
20
|
var package_default = {
|
|
21
21
|
name: "dsh-session-toolbox",
|
|
22
|
-
version: "0.1.
|
|
22
|
+
version: "0.1.3",
|
|
23
23
|
repository: {
|
|
24
24
|
type: "git",
|
|
25
25
|
url: "https://github.com/AndroidSix/dsh-session-toolbox.git"
|
|
@@ -38,7 +38,8 @@ var package_default = {
|
|
|
38
38
|
"./package.json": "./package.json"
|
|
39
39
|
},
|
|
40
40
|
engines: {
|
|
41
|
-
node: "^22.19.0 || >=24.0.0"
|
|
41
|
+
node: "^22.19.0 || >=24.0.0",
|
|
42
|
+
dsh: "^0.2.0-rc.2 || ^0.2.1-rc.2"
|
|
42
43
|
},
|
|
43
44
|
files: [
|
|
44
45
|
"lib",
|
|
@@ -69,15 +70,15 @@ var package_default = {
|
|
|
69
70
|
},
|
|
70
71
|
peerDependencies: {
|
|
71
72
|
"@deepseek-ai/cordis": "^4.0.4",
|
|
72
|
-
"@deepseek-ai/dsh-atomic-write": "0.2.0-rc.2",
|
|
73
|
-
"@deepseek-ai/dsh-home-paths": "0.2.0-rc.2",
|
|
73
|
+
"@deepseek-ai/dsh-atomic-write": "^0.2.0-rc.2 || ^0.2.1-rc.2",
|
|
74
|
+
"@deepseek-ai/dsh-home-paths": "^0.2.0-rc.2 || ^0.2.1-rc.2",
|
|
74
75
|
"@deepseek-ai/schemastery": "^3.18.4",
|
|
75
76
|
react: "^18.2.0"
|
|
76
77
|
},
|
|
77
78
|
devDependencies: {
|
|
78
79
|
"@deepseek-ai/cordis": "^4.0.4",
|
|
79
|
-
"@deepseek-ai/dsh-atomic-write": "0.2.0-rc.2",
|
|
80
|
-
"@deepseek-ai/dsh-home-paths": "0.2.0-rc.2",
|
|
80
|
+
"@deepseek-ai/dsh-atomic-write": "^0.2.0-rc.2 || ^0.2.1-rc.2",
|
|
81
|
+
"@deepseek-ai/dsh-home-paths": "^0.2.0-rc.2 || ^0.2.1-rc.2",
|
|
81
82
|
"@deepseek-ai/schemastery": "^3.18.4",
|
|
82
83
|
esbuild: "^0.25.0",
|
|
83
84
|
react: "^18.2.0",
|
package/lib/host.js
CHANGED
|
@@ -19,7 +19,7 @@ import { resolveDshHome } from "@deepseek-ai/dsh-home-paths";
|
|
|
19
19
|
// package.json
|
|
20
20
|
var package_default = {
|
|
21
21
|
name: "dsh-session-toolbox",
|
|
22
|
-
version: "0.1.
|
|
22
|
+
version: "0.1.3",
|
|
23
23
|
repository: {
|
|
24
24
|
type: "git",
|
|
25
25
|
url: "https://github.com/AndroidSix/dsh-session-toolbox.git"
|
|
@@ -38,7 +38,8 @@ var package_default = {
|
|
|
38
38
|
"./package.json": "./package.json"
|
|
39
39
|
},
|
|
40
40
|
engines: {
|
|
41
|
-
node: "^22.19.0 || >=24.0.0"
|
|
41
|
+
node: "^22.19.0 || >=24.0.0",
|
|
42
|
+
dsh: "^0.2.0-rc.2 || ^0.2.1-rc.2"
|
|
42
43
|
},
|
|
43
44
|
files: [
|
|
44
45
|
"lib",
|
|
@@ -69,15 +70,15 @@ var package_default = {
|
|
|
69
70
|
},
|
|
70
71
|
peerDependencies: {
|
|
71
72
|
"@deepseek-ai/cordis": "^4.0.4",
|
|
72
|
-
"@deepseek-ai/dsh-atomic-write": "0.2.0-rc.2",
|
|
73
|
-
"@deepseek-ai/dsh-home-paths": "0.2.0-rc.2",
|
|
73
|
+
"@deepseek-ai/dsh-atomic-write": "^0.2.0-rc.2 || ^0.2.1-rc.2",
|
|
74
|
+
"@deepseek-ai/dsh-home-paths": "^0.2.0-rc.2 || ^0.2.1-rc.2",
|
|
74
75
|
"@deepseek-ai/schemastery": "^3.18.4",
|
|
75
76
|
react: "^18.2.0"
|
|
76
77
|
},
|
|
77
78
|
devDependencies: {
|
|
78
79
|
"@deepseek-ai/cordis": "^4.0.4",
|
|
79
|
-
"@deepseek-ai/dsh-atomic-write": "0.2.0-rc.2",
|
|
80
|
-
"@deepseek-ai/dsh-home-paths": "0.2.0-rc.2",
|
|
80
|
+
"@deepseek-ai/dsh-atomic-write": "^0.2.0-rc.2 || ^0.2.1-rc.2",
|
|
81
|
+
"@deepseek-ai/dsh-home-paths": "^0.2.0-rc.2 || ^0.2.1-rc.2",
|
|
81
82
|
"@deepseek-ai/schemastery": "^3.18.4",
|
|
82
83
|
esbuild: "^0.25.0",
|
|
83
84
|
react: "^18.2.0",
|
package/lib/index.js
CHANGED
|
@@ -19,7 +19,7 @@ import { resolveDshHome } from "@deepseek-ai/dsh-home-paths";
|
|
|
19
19
|
// package.json
|
|
20
20
|
var package_default = {
|
|
21
21
|
name: "dsh-session-toolbox",
|
|
22
|
-
version: "0.1.
|
|
22
|
+
version: "0.1.3",
|
|
23
23
|
repository: {
|
|
24
24
|
type: "git",
|
|
25
25
|
url: "https://github.com/AndroidSix/dsh-session-toolbox.git"
|
|
@@ -38,7 +38,8 @@ var package_default = {
|
|
|
38
38
|
"./package.json": "./package.json"
|
|
39
39
|
},
|
|
40
40
|
engines: {
|
|
41
|
-
node: "^22.19.0 || >=24.0.0"
|
|
41
|
+
node: "^22.19.0 || >=24.0.0",
|
|
42
|
+
dsh: "^0.2.0-rc.2 || ^0.2.1-rc.2"
|
|
42
43
|
},
|
|
43
44
|
files: [
|
|
44
45
|
"lib",
|
|
@@ -69,15 +70,15 @@ var package_default = {
|
|
|
69
70
|
},
|
|
70
71
|
peerDependencies: {
|
|
71
72
|
"@deepseek-ai/cordis": "^4.0.4",
|
|
72
|
-
"@deepseek-ai/dsh-atomic-write": "0.2.0-rc.2",
|
|
73
|
-
"@deepseek-ai/dsh-home-paths": "0.2.0-rc.2",
|
|
73
|
+
"@deepseek-ai/dsh-atomic-write": "^0.2.0-rc.2 || ^0.2.1-rc.2",
|
|
74
|
+
"@deepseek-ai/dsh-home-paths": "^0.2.0-rc.2 || ^0.2.1-rc.2",
|
|
74
75
|
"@deepseek-ai/schemastery": "^3.18.4",
|
|
75
76
|
react: "^18.2.0"
|
|
76
77
|
},
|
|
77
78
|
devDependencies: {
|
|
78
79
|
"@deepseek-ai/cordis": "^4.0.4",
|
|
79
|
-
"@deepseek-ai/dsh-atomic-write": "0.2.0-rc.2",
|
|
80
|
-
"@deepseek-ai/dsh-home-paths": "0.2.0-rc.2",
|
|
80
|
+
"@deepseek-ai/dsh-atomic-write": "^0.2.0-rc.2 || ^0.2.1-rc.2",
|
|
81
|
+
"@deepseek-ai/dsh-home-paths": "^0.2.0-rc.2 || ^0.2.1-rc.2",
|
|
81
82
|
"@deepseek-ai/schemastery": "^3.18.4",
|
|
82
83
|
esbuild: "^0.25.0",
|
|
83
84
|
react: "^18.2.0",
|
package/lib/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.mjs", "../package.json"],
|
|
4
|
-
"sourcesContent": ["/**\n * dsh-session-toolbox host plugin: draft vault manifest mirror (\u00A74 FR1), session\n * move (\u00A710) and trash bin (\u00A711) for DeepSeek Harness. Every official surface\n * is reached through `ctx.get(...)` service names probed at runtime; a missing\n * capability degrades that feature to a visible \"unavailable\" state \u2014 never a\n * crash, never a patch (NFR3 / \u00A710 MN1). The plugin declares no hard `inject`\n * dependencies so it can never block host boot.\n */\nimport { mkdir, realpath, stat } from 'node:fs/promises';\nimport { join, resolve } from 'node:path';\nimport z from '@deepseek-ai/schemastery';\nimport { resolveDshHome } from '@deepseek-ai/dsh-home-paths';\nimport { guardJournal, guardLedger, guardManifest, guardSettings, JsonDocument } from './store.mjs';\nimport { MoveEngine } from './move.mjs';\nimport { TrashEngine } from './trash.mjs';\nimport { apiHandler, dispatch } from './api.mjs';\nimport pkg from '../package.json' with { type: 'json' };\nconst pluginVersion = pkg.version;\n\nexport const name = 'dsh-session-toolbox';\nexport const inject = [];\n// schemastery has no `.optional()`; empty defaults mean \"unset\" (apply() treats '' as absent).\nexport const Config = z.object({\n\tconfigFile: z.string().description('Directory for session-toolbox data (defaults to <DSH_HOME>/session-toolbox)').default(''),\n\tdshHome: z.string().description('Override the DSH home whose sessions/ storage the tool manages (advanced)').default(''),\n});\n\nexport function defaultKitRoot() {\n\treturn join(resolveDshHome(), 'session-toolbox');\n}\n\nexport async function apply(ctx, options = {}) {\n\tconst dshHome = resolve(options.dshHome || resolveDshHome());\n\tconst root = resolve(options.configFile || join(dshHome, 'session-toolbox'));\n\tawait mkdir(root, { recursive: true, mode: 0o700 });\n\tconst capabilities = {\n\t\tworkspaceRegistry: ctx.get('workspaceRegistry') !== undefined,\n\t\tsessions: ctx.get('sessions') !== undefined,\n\t\tsessionPersistence: ctx.get('sessionPersistence') !== undefined,\n\t\twebServer: false, // flips true when the optional webServer inject fires\n\t};\n\tconst settingsDoc = new JsonDocument(root, 'session-toolbox.json', { version: 1 }, guardSettings);\n\tconst journalDoc = new JsonDocument(root, 'journal.json', { version: 1, active: null }, guardJournal);\n\tconst ledgerDoc = new JsonDocument(root, 'trash.json', { version: 1, items: [] }, guardLedger);\n\tconst manifestDoc = new JsonDocument(root, 'vault-manifest.json', { version: 1, records: [] }, guardManifest);\n\n\tlet settingsCache = await settingsDoc.read().catch(() => ({ trash: {}, draftVault: {} }));\n\tlet journalCache = null;\n\ttry { journalCache = (await journalDoc.read()).active; }\n\tcatch (error) { ctx.logger?.warn?.(`session-toolbox: journal unreadable \u2014 ${error.message}`); }\n\tif (journalCache !== null) ctx.logger?.warn?.(`session-toolbox: unresolved move journal for ${journalCache.sessionId}; complete or roll it back from the panel or CLI`);\n\n\tconst move = new MoveEngine({\n\t\troot,\n\t\tsessionsRoot: join(dshHome, 'sessions'),\n\t\tprojcacheRoot: join(dshHome, 'storages', 'session_projcache', 'sessions'),\n\t\tjournal: journalDoc,\n\t\tcapabilities: hostCapabilities(ctx),\n\t});\n\tconst trash = new TrashEngine({\n\t\tadapter: registryAdapter(ctx),\n\t\tsessions: () => (ctx.get('sessions')?.list() ?? []).map(session => session.header?.id).filter(id => typeof id === 'string'),\n\t\tsessionsRoot: join(dshHome, 'sessions'),\n\t\tprojcacheRoot: join(dshHome, 'storages', 'session_projcache', 'sessions'),\n\t\tkitRoot: root,\n\t\tledger: ledgerDoc,\n\t\tvault: { dropSession: sessionId => manifestDoc.update(current => ({ ...current, records: current.records.filter(record => record.sessionId !== sessionId) })) },\n\t\tjournal: () => journalCache,\n\t\tsettings: () => settingsCache.trash ?? {},\n\t});\n\n\tconst kit = {\n\t\tsettings: settingsDoc,\n\t\tmanifest: manifestDoc,\n\t\tjournal: journalDoc,\n\t\tmove,\n\t\ttrash,\n\t\tupdateSettings: async patch => {\n\t\t\tconst next = await settingsDoc.update(current => deepMerge(current, patch));\n\t\t\tsettingsCache = next;\n\t\t\treturn next;\n\t\t},\n\t\tvaultSync: async records => {\n\t\t\tconst manifest = await manifestDoc.update(() => ({\n\t\t\t\tversion: 1,\n\t\t\t\trecords: (Array.isArray(records) ? records : []).filter(record => typeof record.sessionId === 'string' && typeof record.attachmentId === 'string')\n\t\t\t\t\t.slice(-2000)\n\t\t\t\t\t.map(record => ({ sessionId: record.sessionId, attachmentId: record.attachmentId,\n\t\t\t\t\t\tname: String(record.name ?? ''), size: Number(record.size) || 0, hash: String(record.hash ?? ''),\n\t\t\t\t\t\tcreatedAt: Number(record.createdAt) || Date.now() })),\n\t\t\t}));\n\t\t\treturn manifest;\n\t\t},\n\t\tstate: async () => {\n\t\t\tconst settings = await settingsDoc.read();\n\t\t\tsettingsCache = settings;\n\t\t\tconst journal = (await journalDoc.read().catch(() => ({ active: journalCache }))).active;\n\t\t\tjournalCache = journal;\n\t\t\tconst manifest = await manifestDoc.read();\n\t\t\treturn {\n\t\t\t\tpluginVersion,\n\t\t\t\tcapabilities,\n\t\t\t\tsettings,\n\t\t\t\tjournal,\n\t\t\t\ttrash: await trash.items(),\n\t\t\t\t// Bytes live in browser IndexedDB; the manifest mirrors their metadata only.\n\t\t\t\tvault: { records: manifest.records.length, bytes: manifest.records.reduce((total, record) => total + (record.size ?? 0), 0) },\n\t\t\t\trecovery: journal === null ? null : `\u672A\u5B8C\u6210\u8FC1\u79FB\uFF1A${journal.sessionId} \u2192 ${journal.toCwd}\uFF08\u5DF2\u5B8C\u6210 ${journal.done.join('/') || '\u65E0'}\uFF09`,\n\t\t\t};\n\t\t},\n\t\taction: input => dispatch(kit, input),\n\t};\n\n\tctx.inject?.(['webServer'], webCtx => {\n\t\tcapabilities.webServer = true;\n\t\twebCtx.effect(() => webCtx.webServer.register({ kind: 'exact', path: '/.well-known/dsh-session-toolbox', handler: apiHandler(kit) }));\n\t});\n\n\t// Expose the kit in-process (cordis plugins must return nothing; the service\n\t// is the surface other plugins or future official hooks can reach).\n\tctx.provide('sessionToolbox', kit);\n\n\tctx.effect(() => () => {});\n\tctx.logger?.info?.('dsh-session-toolbox ready', JSON.stringify({ version: pluginVersion, capabilities }));\n}\n\n/**\n * Host capabilities for the move engine (\u00A710 MR5). Services are fetched lazily\n * through `ctx.get`; a missing one raises a stable error the UI can show.\n */\nexport function hostCapabilities(ctx) {\n\treturn {\n\t\tsessionLive: sessionId => {\n\t\t\tconst sessions = ctx.get('sessions');\n\t\t\treturn sessions ? sessions.list().some(session => session.header?.id === sessionId) : false;\n\t\t},\n\t\tlistHeaders: async () => {\n\t\t\tconst persistence = ctx.get('sessionPersistence');\n\t\t\tif (persistence?.list !== undefined) return (await persistence.list()).map(snapshot => snapshot.header);\n\t\t\tconst registry = ctx.get('workspaceRegistry');\n\t\t\tif (registry?.listStoredHeaders !== undefined) return await registry.listStoredHeaders();\n\t\t\tthrow new Error('no session-persistence service in this DSH build');\n\t\t},\n\t\t/** Drop stale header entries so `attachSession` validates the NEW on-disk cwd (\u00A710 MR4). */\n\t\trefreshHeaderCache: async () => {\n\t\t\tconst registry = ctx.get('workspaceRegistry');\n\t\t\tif (typeof registry?.replaceHeaderIndex !== 'function') return;\n\t\t\tawait registry.replaceHeaderIndex(await registry.listStoredHeaders());\n\t\t},\n\t\t/** Ledger step (\u00A710 MR2 step 2): source detach \u2192 target create \u2192 attach. */\n\t\tmoveLedger: async (sessionId, fromCwd, toCwd) => {\n\t\t\tconst registry = ctx.get('workspaceRegistry');\n\t\t\tif (registry === undefined) throw new Error('workspaceRegistry unavailable in this DSH build');\n\t\t\tconst canonicalFrom = fromCwd === undefined ? undefined : await realpath(fromCwd).catch(() => fromCwd);\n\t\t\tconst source = canonicalFrom === undefined ? undefined : await registry.resolveByPath(canonicalFrom);\n\t\t\tif (source !== undefined) await source.detachSession(sessionId);\n\t\t\tlet target = await registry.resolveByPath(toCwd);\n\t\t\tif (target === undefined) {\n\t\t\t\tif (!(await stat(toCwd).then(s => s.isDirectory(), () => false))) throw new Error(`target directory ${toCwd} does not exist`);\n\t\t\t\ttarget = await registry.create(toCwd);\n\t\t\t}\n\t\t\tawait target.attachSession(sessionId);\n\t\t},\n\t\tresyncIndex: async () => {\n\t\t\t// \u00A710.8-3: the sqlite query index reconciles against persistence lazily on\n\t\t\t// every query path; there is nothing explicit to call in this build.\n\t\t\treturn ctx.get('sessionQuery') !== undefined ? 'lazy' : 'unavailable';\n\t\t},\n\t};\n}\n\n/**\n * The narrow adapter the trash engine runs every official effect through\n * (\u00A711 TB5). Workspace deletion keeps session logs (\u00A711.1-2); bootstrap only\n * re-claims non-archived unaccounted sessions \u2014 which is why trashing a project\n * archives its sessions first, and restoring re-registers + attaches +\n * unarchives in order.\n */\nexport function registryAdapter(ctx) {\n\tconst registry = () => {\n\t\tconst value = ctx.get('workspaceRegistry');\n\t\tif (value === undefined) throw Object.assign(new Error('workspaceRegistry unavailable'), { code: 'no-capability' });\n\t\treturn value;\n\t};\n\treturn {\n\t\tsessionKnown: async sessionId => {\n\t\t\tconst rows = registry();\n\t\t\treturn typeof rows.sessionKnown === 'function' ? await rows.sessionKnown(sessionId) : false;\n\t\t},\n\t\tarchivedSet: async () => new Set(registry().archivedSessionIds ?? []),\n\t\tpinnedSet: async () => new Set(registry().pinnedSessionIds ?? []),\n\t\tlocateSession: async sessionId => {\n\t\t\tfor (const entity of registry().list()) {\n\t\t\t\tconst ids = entity.sessionIds ?? [];\n\t\t\t\tif (!ids.includes(sessionId)) continue;\n\t\t\t\tconst at = ids.indexOf(sessionId);\n\t\t\t\treturn { workspaceId: entity.id, beforeId: at + 1 < ids.length ? ids[at + 1] : null, title: null };\n\t\t\t}\n\t\t\treturn { workspaceId: null, beforeId: null, title: null };\n\t\t},\n\t\tworkspaceSnapshot: async workspaceId => {\n\t\t\tconst rows = registry();\n\t\t\tconst entity = rows.get(workspaceId);\n\t\t\tif (entity === undefined) return undefined;\n\t\t\tconst ids = entity.sessionIds ?? [];\n\t\t\tconst archived = new Set(rows.archivedSessionIds ?? []);\n\t\t\tconst pinned = new Set(rows.pinnedSessionIds ?? []);\n\t\t\tconst order = rows.list().map(row => row.id);\n\t\t\tconst at = order.indexOf(entity.id);\n\t\t\treturn {\n\t\t\t\tworkspaceId: entity.id, path: entity.path, title: entity.title,\n\t\t\t\tbeforeId: at > 0 ? order[at - 1] : null,\n\t\t\t\tsessions: ids.map((sessionId, index) => ({ sessionId,\n\t\t\t\t\tpreviouslyArchived: archived.has(sessionId),\n\t\t\t\t\tpreviouslyPinned: pinned.has(sessionId),\n\t\t\t\t\tbeforeId: index + 1 < ids.length ? ids[index + 1] : null })),\n\t\t\t};\n\t\t},\n\t\tarchiveSession: (sessionId, options) => registry().archiveSession(sessionId, options),\n\t\tunarchiveSession: sessionId => registry().unarchiveSession(sessionId),\n\t\tpinSession: sessionId => registry().pinSession(sessionId),\n\t\tunpinSession: sessionId => registry().unpinSession(sessionId),\n\t\tdeleteWorkspace: workspaceId => registry().delete(workspaceId),\n\t\trepairSlot: async (sessionId, workspaceId, beforeId) => {\n\t\t\tconst entity = registry().get(workspaceId);\n\t\t\tif (entity === undefined) return;\n\t\t\tif (!entity.sessionIds?.includes(sessionId)) await entity.attachSession(sessionId);\n\t\t\tif (beforeId !== null && entity.sessionIds?.includes(beforeId)) await entity.insertSessionBefore(sessionId, beforeId);\n\t\t},\n\t\trestoreWorkspace: async snapshot => {\n\t\t\tconst rows = registry();\n\t\t\tlet entity = rows.list().find(row => row.path === snapshot.path);\n\t\t\tif (entity === undefined) {\n\t\t\t\tawait mkdir(snapshot.path, { recursive: true }).catch(() => {});\n\t\t\t\tentity = await rows.create(snapshot.path, snapshot.title);\n\t\t\t}\n\t\t\tfor (const row of [...snapshot.sessions].reverse()) await entity.attachSession(row.sessionId).catch(() => {});\n\t\t\tif (snapshot.beforeId !== null && entity.id !== snapshot.beforeId) await rows.insertBefore(entity.id, snapshot.beforeId).catch(() => {});\n\t\t\treturn entity;\n\t\t},\n\t\tpurgeSession: async () => ctx.get('sessionPersistence')?.delete === undefined ? 'unavailable' : 'present',\n\t};\n}\n\nfunction deepMerge(base, patch) {\n\tconst next = { ...base };\n\tfor (const [key, value] of Object.entries(patch ?? {})) {\n\t\tnext[key] = value !== null && typeof value === 'object' && !Array.isArray(value) ? deepMerge(base[key] ?? {}, value) : value;\n\t}\n\treturn next;\n}\n", "{\n \"name\": \"dsh-session-toolbox\",\n \"version\": \"0.1.1\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/AndroidSix/dsh-session-toolbox.git\"\n },\n \"description\": \"Draft vault, session-to-project move and a trash bin for DeepSeek Harness\",\n \"type\": \"module\",\n \"main\": \"lib/index.js\",\n \"bin\": {\n \"dsh-session-toolbox\": \"lib/cli.js\"\n },\n \"exports\": {\n \".\": \"./lib/index.js\",\n \"./host\": \"./lib/host.js\",\n \"./client\": \"./lib/client.js\",\n \"./cordis.patch.yml\": \"./cordis.patch.yml\",\n \"./package.json\": \"./package.json\"\n },\n \"engines\": {\n \"node\": \"^22.19.0 || >=24.0.0\"\n },\n \"files\": [\n \"lib\",\n \"cordis.patch.yml\",\n \"README.md\",\n \"LICENSE\",\n \"THIRD_PARTY_NOTICES.md\",\n \"session-toolbox.example.json\",\n \"CHANGELOG.md\"\n ],\n \"dsh\": {\n \"bundle\": {\n \"patch\": \"./cordis.patch.yml\"\n },\n \"client\": {\n \"inject\": [\n \"@deepseek-ai/dsh-client-ui-renderer\"\n ],\n \"platform\": \"web\"\n }\n },\n \"scripts\": {\n \"build\": \"node scripts/build.mjs\",\n \"test\": \"node --test tests/*.test.mjs\",\n \"check\": \"npm run build && npm test && node scripts/check-package.mjs\",\n \"check:tarball\": \"npm run build && node scripts/check-package.mjs --tarball\",\n \"pack:release\": \"npm run build && npm pack --ignore-scripts\"\n },\n \"peerDependencies\": {\n \"@deepseek-ai/cordis\": \"^4.0.4\",\n \"@deepseek-ai/dsh-atomic-write\": \"0.2.0-rc.2\",\n \"@deepseek-ai/dsh-home-paths\": \"0.2.0-rc.2\",\n \"@deepseek-ai/schemastery\": \"^3.18.4\",\n \"react\": \"^18.2.0\"\n },\n \"devDependencies\": {\n \"@deepseek-ai/cordis\": \"^4.0.4\",\n \"@deepseek-ai/dsh-atomic-write\": \"0.2.0-rc.2\",\n \"@deepseek-ai/dsh-home-paths\": \"0.2.0-rc.2\",\n \"@deepseek-ai/schemastery\": \"^3.18.4\",\n \"esbuild\": \"^0.25.0\",\n \"react\": \"^18.2.0\",\n \"react-dom\": \"^18.2.0\"\n },\n \"license\": \"MIT\",\n \"keywords\": [\n \"dsh-plugin\",\n \"deepseek-harness\",\n \"draft-vault\",\n \"session-move\",\n \"trash-bin\"\n ]\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;AAQA,SAAS,OAAO,UAAU,YAAY;AACtC,SAAS,MAAM,eAAe;AAC9B,OAAO,OAAO;AACd,SAAS,sBAAsB;;;ACX/B;AAAA,EACE,MAAQ;AAAA,EACR,SAAW;AAAA,EACX,YAAc;AAAA,IACZ,MAAQ;AAAA,IACR,KAAO;AAAA,EACT;AAAA,EACA,aAAe;AAAA,EACf,MAAQ;AAAA,EACR,MAAQ;AAAA,EACR,KAAO;AAAA,IACL,uBAAuB;AAAA,EACzB;AAAA,EACA,SAAW;AAAA,IACT,KAAK;AAAA,IACL,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,sBAAsB;AAAA,IACtB,kBAAkB;AAAA,EACpB;AAAA,EACA,SAAW;AAAA,IACT,MAAQ;AAAA,
|
|
4
|
+
"sourcesContent": ["/**\n * dsh-session-toolbox host plugin: draft vault manifest mirror (\u00A74 FR1), session\n * move (\u00A710) and trash bin (\u00A711) for DeepSeek Harness. Every official surface\n * is reached through `ctx.get(...)` service names probed at runtime; a missing\n * capability degrades that feature to a visible \"unavailable\" state \u2014 never a\n * crash, never a patch (NFR3 / \u00A710 MN1). The plugin declares no hard `inject`\n * dependencies so it can never block host boot.\n */\nimport { mkdir, realpath, stat } from 'node:fs/promises';\nimport { join, resolve } from 'node:path';\nimport z from '@deepseek-ai/schemastery';\nimport { resolveDshHome } from '@deepseek-ai/dsh-home-paths';\nimport { guardJournal, guardLedger, guardManifest, guardSettings, JsonDocument } from './store.mjs';\nimport { MoveEngine } from './move.mjs';\nimport { TrashEngine } from './trash.mjs';\nimport { apiHandler, dispatch } from './api.mjs';\nimport pkg from '../package.json' with { type: 'json' };\nconst pluginVersion = pkg.version;\n\nexport const name = 'dsh-session-toolbox';\nexport const inject = [];\n// schemastery has no `.optional()`; empty defaults mean \"unset\" (apply() treats '' as absent).\nexport const Config = z.object({\n\tconfigFile: z.string().description('Directory for session-toolbox data (defaults to <DSH_HOME>/session-toolbox)').default(''),\n\tdshHome: z.string().description('Override the DSH home whose sessions/ storage the tool manages (advanced)').default(''),\n});\n\nexport function defaultKitRoot() {\n\treturn join(resolveDshHome(), 'session-toolbox');\n}\n\nexport async function apply(ctx, options = {}) {\n\tconst dshHome = resolve(options.dshHome || resolveDshHome());\n\tconst root = resolve(options.configFile || join(dshHome, 'session-toolbox'));\n\tawait mkdir(root, { recursive: true, mode: 0o700 });\n\tconst capabilities = {\n\t\tworkspaceRegistry: ctx.get('workspaceRegistry') !== undefined,\n\t\tsessions: ctx.get('sessions') !== undefined,\n\t\tsessionPersistence: ctx.get('sessionPersistence') !== undefined,\n\t\twebServer: false, // flips true when the optional webServer inject fires\n\t};\n\tconst settingsDoc = new JsonDocument(root, 'session-toolbox.json', { version: 1 }, guardSettings);\n\tconst journalDoc = new JsonDocument(root, 'journal.json', { version: 1, active: null }, guardJournal);\n\tconst ledgerDoc = new JsonDocument(root, 'trash.json', { version: 1, items: [] }, guardLedger);\n\tconst manifestDoc = new JsonDocument(root, 'vault-manifest.json', { version: 1, records: [] }, guardManifest);\n\n\tlet settingsCache = await settingsDoc.read().catch(() => ({ trash: {}, draftVault: {} }));\n\tlet journalCache = null;\n\ttry { journalCache = (await journalDoc.read()).active; }\n\tcatch (error) { ctx.logger?.warn?.(`session-toolbox: journal unreadable \u2014 ${error.message}`); }\n\tif (journalCache !== null) ctx.logger?.warn?.(`session-toolbox: unresolved move journal for ${journalCache.sessionId}; complete or roll it back from the panel or CLI`);\n\n\tconst move = new MoveEngine({\n\t\troot,\n\t\tsessionsRoot: join(dshHome, 'sessions'),\n\t\tprojcacheRoot: join(dshHome, 'storages', 'session_projcache', 'sessions'),\n\t\tjournal: journalDoc,\n\t\tcapabilities: hostCapabilities(ctx),\n\t});\n\tconst trash = new TrashEngine({\n\t\tadapter: registryAdapter(ctx),\n\t\tsessions: () => (ctx.get('sessions')?.list() ?? []).map(session => session.header?.id).filter(id => typeof id === 'string'),\n\t\tsessionsRoot: join(dshHome, 'sessions'),\n\t\tprojcacheRoot: join(dshHome, 'storages', 'session_projcache', 'sessions'),\n\t\tkitRoot: root,\n\t\tledger: ledgerDoc,\n\t\tvault: { dropSession: sessionId => manifestDoc.update(current => ({ ...current, records: current.records.filter(record => record.sessionId !== sessionId) })) },\n\t\tjournal: () => journalCache,\n\t\tsettings: () => settingsCache.trash ?? {},\n\t});\n\n\tconst kit = {\n\t\tsettings: settingsDoc,\n\t\tmanifest: manifestDoc,\n\t\tjournal: journalDoc,\n\t\tmove,\n\t\ttrash,\n\t\tupdateSettings: async patch => {\n\t\t\tconst next = await settingsDoc.update(current => deepMerge(current, patch));\n\t\t\tsettingsCache = next;\n\t\t\treturn next;\n\t\t},\n\t\tvaultSync: async records => {\n\t\t\tconst manifest = await manifestDoc.update(() => ({\n\t\t\t\tversion: 1,\n\t\t\t\trecords: (Array.isArray(records) ? records : []).filter(record => typeof record.sessionId === 'string' && typeof record.attachmentId === 'string')\n\t\t\t\t\t.slice(-2000)\n\t\t\t\t\t.map(record => ({ sessionId: record.sessionId, attachmentId: record.attachmentId,\n\t\t\t\t\t\tname: String(record.name ?? ''), size: Number(record.size) || 0, hash: String(record.hash ?? ''),\n\t\t\t\t\t\tcreatedAt: Number(record.createdAt) || Date.now() })),\n\t\t\t}));\n\t\t\treturn manifest;\n\t\t},\n\t\tstate: async () => {\n\t\t\tconst settings = await settingsDoc.read();\n\t\t\tsettingsCache = settings;\n\t\t\tconst journal = (await journalDoc.read().catch(() => ({ active: journalCache }))).active;\n\t\t\tjournalCache = journal;\n\t\t\tconst manifest = await manifestDoc.read();\n\t\t\treturn {\n\t\t\t\tpluginVersion,\n\t\t\t\tcapabilities,\n\t\t\t\tsettings,\n\t\t\t\tjournal,\n\t\t\t\ttrash: await trash.items(),\n\t\t\t\t// Bytes live in browser IndexedDB; the manifest mirrors their metadata only.\n\t\t\t\tvault: { records: manifest.records.length, bytes: manifest.records.reduce((total, record) => total + (record.size ?? 0), 0) },\n\t\t\t\trecovery: journal === null ? null : `\u672A\u5B8C\u6210\u8FC1\u79FB\uFF1A${journal.sessionId} \u2192 ${journal.toCwd}\uFF08\u5DF2\u5B8C\u6210 ${journal.done.join('/') || '\u65E0'}\uFF09`,\n\t\t\t};\n\t\t},\n\t\taction: input => dispatch(kit, input),\n\t};\n\n\tctx.inject?.(['webServer'], webCtx => {\n\t\tcapabilities.webServer = true;\n\t\twebCtx.effect(() => webCtx.webServer.register({ kind: 'exact', path: '/.well-known/dsh-session-toolbox', handler: apiHandler(kit) }));\n\t});\n\n\t// Expose the kit in-process (cordis plugins must return nothing; the service\n\t// is the surface other plugins or future official hooks can reach).\n\tctx.provide('sessionToolbox', kit);\n\n\tctx.effect(() => () => {});\n\tctx.logger?.info?.('dsh-session-toolbox ready', JSON.stringify({ version: pluginVersion, capabilities }));\n}\n\n/**\n * Host capabilities for the move engine (\u00A710 MR5). Services are fetched lazily\n * through `ctx.get`; a missing one raises a stable error the UI can show.\n */\nexport function hostCapabilities(ctx) {\n\treturn {\n\t\tsessionLive: sessionId => {\n\t\t\tconst sessions = ctx.get('sessions');\n\t\t\treturn sessions ? sessions.list().some(session => session.header?.id === sessionId) : false;\n\t\t},\n\t\tlistHeaders: async () => {\n\t\t\tconst persistence = ctx.get('sessionPersistence');\n\t\t\tif (persistence?.list !== undefined) return (await persistence.list()).map(snapshot => snapshot.header);\n\t\t\tconst registry = ctx.get('workspaceRegistry');\n\t\t\tif (registry?.listStoredHeaders !== undefined) return await registry.listStoredHeaders();\n\t\t\tthrow new Error('no session-persistence service in this DSH build');\n\t\t},\n\t\t/** Drop stale header entries so `attachSession` validates the NEW on-disk cwd (\u00A710 MR4). */\n\t\trefreshHeaderCache: async () => {\n\t\t\tconst registry = ctx.get('workspaceRegistry');\n\t\t\tif (typeof registry?.replaceHeaderIndex !== 'function') return;\n\t\t\tawait registry.replaceHeaderIndex(await registry.listStoredHeaders());\n\t\t},\n\t\t/** Ledger step (\u00A710 MR2 step 2): source detach \u2192 target create \u2192 attach. */\n\t\tmoveLedger: async (sessionId, fromCwd, toCwd) => {\n\t\t\tconst registry = ctx.get('workspaceRegistry');\n\t\t\tif (registry === undefined) throw new Error('workspaceRegistry unavailable in this DSH build');\n\t\t\tconst canonicalFrom = fromCwd === undefined ? undefined : await realpath(fromCwd).catch(() => fromCwd);\n\t\t\tconst source = canonicalFrom === undefined ? undefined : await registry.resolveByPath(canonicalFrom);\n\t\t\tif (source !== undefined) await source.detachSession(sessionId);\n\t\t\tlet target = await registry.resolveByPath(toCwd);\n\t\t\tif (target === undefined) {\n\t\t\t\tif (!(await stat(toCwd).then(s => s.isDirectory(), () => false))) throw new Error(`target directory ${toCwd} does not exist`);\n\t\t\t\ttarget = await registry.create(toCwd);\n\t\t\t}\n\t\t\tawait target.attachSession(sessionId);\n\t\t},\n\t\tresyncIndex: async () => {\n\t\t\t// \u00A710.8-3: the sqlite query index reconciles against persistence lazily on\n\t\t\t// every query path; there is nothing explicit to call in this build.\n\t\t\treturn ctx.get('sessionQuery') !== undefined ? 'lazy' : 'unavailable';\n\t\t},\n\t};\n}\n\n/**\n * The narrow adapter the trash engine runs every official effect through\n * (\u00A711 TB5). Workspace deletion keeps session logs (\u00A711.1-2); bootstrap only\n * re-claims non-archived unaccounted sessions \u2014 which is why trashing a project\n * archives its sessions first, and restoring re-registers + attaches +\n * unarchives in order.\n */\nexport function registryAdapter(ctx) {\n\tconst registry = () => {\n\t\tconst value = ctx.get('workspaceRegistry');\n\t\tif (value === undefined) throw Object.assign(new Error('workspaceRegistry unavailable'), { code: 'no-capability' });\n\t\treturn value;\n\t};\n\treturn {\n\t\tsessionKnown: async sessionId => {\n\t\t\tconst rows = registry();\n\t\t\treturn typeof rows.sessionKnown === 'function' ? await rows.sessionKnown(sessionId) : false;\n\t\t},\n\t\tarchivedSet: async () => new Set(registry().archivedSessionIds ?? []),\n\t\tpinnedSet: async () => new Set(registry().pinnedSessionIds ?? []),\n\t\tlocateSession: async sessionId => {\n\t\t\tfor (const entity of registry().list()) {\n\t\t\t\tconst ids = entity.sessionIds ?? [];\n\t\t\t\tif (!ids.includes(sessionId)) continue;\n\t\t\t\tconst at = ids.indexOf(sessionId);\n\t\t\t\treturn { workspaceId: entity.id, beforeId: at + 1 < ids.length ? ids[at + 1] : null, title: null };\n\t\t\t}\n\t\t\treturn { workspaceId: null, beforeId: null, title: null };\n\t\t},\n\t\tworkspaceSnapshot: async workspaceId => {\n\t\t\tconst rows = registry();\n\t\t\tconst entity = rows.get(workspaceId);\n\t\t\tif (entity === undefined) return undefined;\n\t\t\tconst ids = entity.sessionIds ?? [];\n\t\t\tconst archived = new Set(rows.archivedSessionIds ?? []);\n\t\t\tconst pinned = new Set(rows.pinnedSessionIds ?? []);\n\t\t\tconst order = rows.list().map(row => row.id);\n\t\t\tconst at = order.indexOf(entity.id);\n\t\t\treturn {\n\t\t\t\tworkspaceId: entity.id, path: entity.path, title: entity.title,\n\t\t\t\tbeforeId: at > 0 ? order[at - 1] : null,\n\t\t\t\tsessions: ids.map((sessionId, index) => ({ sessionId,\n\t\t\t\t\tpreviouslyArchived: archived.has(sessionId),\n\t\t\t\t\tpreviouslyPinned: pinned.has(sessionId),\n\t\t\t\t\tbeforeId: index + 1 < ids.length ? ids[index + 1] : null })),\n\t\t\t};\n\t\t},\n\t\tarchiveSession: (sessionId, options) => registry().archiveSession(sessionId, options),\n\t\tunarchiveSession: sessionId => registry().unarchiveSession(sessionId),\n\t\tpinSession: sessionId => registry().pinSession(sessionId),\n\t\tunpinSession: sessionId => registry().unpinSession(sessionId),\n\t\tdeleteWorkspace: workspaceId => registry().delete(workspaceId),\n\t\trepairSlot: async (sessionId, workspaceId, beforeId) => {\n\t\t\tconst entity = registry().get(workspaceId);\n\t\t\tif (entity === undefined) return;\n\t\t\tif (!entity.sessionIds?.includes(sessionId)) await entity.attachSession(sessionId);\n\t\t\tif (beforeId !== null && entity.sessionIds?.includes(beforeId)) await entity.insertSessionBefore(sessionId, beforeId);\n\t\t},\n\t\trestoreWorkspace: async snapshot => {\n\t\t\tconst rows = registry();\n\t\t\tlet entity = rows.list().find(row => row.path === snapshot.path);\n\t\t\tif (entity === undefined) {\n\t\t\t\tawait mkdir(snapshot.path, { recursive: true }).catch(() => {});\n\t\t\t\tentity = await rows.create(snapshot.path, snapshot.title);\n\t\t\t}\n\t\t\tfor (const row of [...snapshot.sessions].reverse()) await entity.attachSession(row.sessionId).catch(() => {});\n\t\t\tif (snapshot.beforeId !== null && entity.id !== snapshot.beforeId) await rows.insertBefore(entity.id, snapshot.beforeId).catch(() => {});\n\t\t\treturn entity;\n\t\t},\n\t\tpurgeSession: async () => ctx.get('sessionPersistence')?.delete === undefined ? 'unavailable' : 'present',\n\t};\n}\n\nfunction deepMerge(base, patch) {\n\tconst next = { ...base };\n\tfor (const [key, value] of Object.entries(patch ?? {})) {\n\t\tnext[key] = value !== null && typeof value === 'object' && !Array.isArray(value) ? deepMerge(base[key] ?? {}, value) : value;\n\t}\n\treturn next;\n}\n", "{\n \"name\": \"dsh-session-toolbox\",\n \"version\": \"0.1.3\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/AndroidSix/dsh-session-toolbox.git\"\n },\n \"description\": \"Draft vault, session-to-project move and a trash bin for DeepSeek Harness\",\n \"type\": \"module\",\n \"main\": \"lib/index.js\",\n \"bin\": {\n \"dsh-session-toolbox\": \"lib/cli.js\"\n },\n \"exports\": {\n \".\": \"./lib/index.js\",\n \"./host\": \"./lib/host.js\",\n \"./client\": \"./lib/client.js\",\n \"./cordis.patch.yml\": \"./cordis.patch.yml\",\n \"./package.json\": \"./package.json\"\n },\n \"engines\": {\n \"node\": \"^22.19.0 || >=24.0.0\",\n \"dsh\": \"^0.2.0-rc.2 || ^0.2.1-rc.2\"\n },\n \"files\": [\n \"lib\",\n \"cordis.patch.yml\",\n \"README.md\",\n \"LICENSE\",\n \"THIRD_PARTY_NOTICES.md\",\n \"session-toolbox.example.json\",\n \"CHANGELOG.md\"\n ],\n \"dsh\": {\n \"bundle\": {\n \"patch\": \"./cordis.patch.yml\"\n },\n \"client\": {\n \"inject\": [\n \"@deepseek-ai/dsh-client-ui-renderer\"\n ],\n \"platform\": \"web\"\n }\n },\n \"scripts\": {\n \"build\": \"node scripts/build.mjs\",\n \"test\": \"node --test tests/*.test.mjs\",\n \"check\": \"npm run build && npm test && node scripts/check-package.mjs\",\n \"check:tarball\": \"npm run build && node scripts/check-package.mjs --tarball\",\n \"pack:release\": \"npm run build && npm pack --ignore-scripts\"\n },\n \"peerDependencies\": {\n \"@deepseek-ai/cordis\": \"^4.0.4\",\n \"@deepseek-ai/dsh-atomic-write\": \"^0.2.0-rc.2 || ^0.2.1-rc.2\",\n \"@deepseek-ai/dsh-home-paths\": \"^0.2.0-rc.2 || ^0.2.1-rc.2\",\n \"@deepseek-ai/schemastery\": \"^3.18.4\",\n \"react\": \"^18.2.0\"\n },\n \"devDependencies\": {\n \"@deepseek-ai/cordis\": \"^4.0.4\",\n \"@deepseek-ai/dsh-atomic-write\": \"^0.2.0-rc.2 || ^0.2.1-rc.2\",\n \"@deepseek-ai/dsh-home-paths\": \"^0.2.0-rc.2 || ^0.2.1-rc.2\",\n \"@deepseek-ai/schemastery\": \"^3.18.4\",\n \"esbuild\": \"^0.25.0\",\n \"react\": \"^18.2.0\",\n \"react-dom\": \"^18.2.0\"\n },\n \"license\": \"MIT\",\n \"keywords\": [\n \"dsh-plugin\",\n \"deepseek-harness\",\n \"draft-vault\",\n \"session-move\",\n \"trash-bin\"\n ]\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-session-toolbox",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/AndroidSix/dsh-session-toolbox.git"
|
|
@@ -19,7 +19,8 @@
|
|
|
19
19
|
"./package.json": "./package.json"
|
|
20
20
|
},
|
|
21
21
|
"engines": {
|
|
22
|
-
"node": "^22.19.0 || >=24.0.0"
|
|
22
|
+
"node": "^22.19.0 || >=24.0.0",
|
|
23
|
+
"dsh": "^0.2.0-rc.2 || ^0.2.1-rc.2"
|
|
23
24
|
},
|
|
24
25
|
"files": [
|
|
25
26
|
"lib",
|
|
@@ -50,15 +51,15 @@
|
|
|
50
51
|
},
|
|
51
52
|
"peerDependencies": {
|
|
52
53
|
"@deepseek-ai/cordis": "^4.0.4",
|
|
53
|
-
"@deepseek-ai/dsh-atomic-write": "0.2.0-rc.2",
|
|
54
|
-
"@deepseek-ai/dsh-home-paths": "0.2.0-rc.2",
|
|
54
|
+
"@deepseek-ai/dsh-atomic-write": "^0.2.0-rc.2 || ^0.2.1-rc.2",
|
|
55
|
+
"@deepseek-ai/dsh-home-paths": "^0.2.0-rc.2 || ^0.2.1-rc.2",
|
|
55
56
|
"@deepseek-ai/schemastery": "^3.18.4",
|
|
56
57
|
"react": "^18.2.0"
|
|
57
58
|
},
|
|
58
59
|
"devDependencies": {
|
|
59
60
|
"@deepseek-ai/cordis": "^4.0.4",
|
|
60
|
-
"@deepseek-ai/dsh-atomic-write": "0.2.0-rc.2",
|
|
61
|
-
"@deepseek-ai/dsh-home-paths": "0.2.0-rc.2",
|
|
61
|
+
"@deepseek-ai/dsh-atomic-write": "^0.2.0-rc.2 || ^0.2.1-rc.2",
|
|
62
|
+
"@deepseek-ai/dsh-home-paths": "^0.2.0-rc.2 || ^0.2.1-rc.2",
|
|
62
63
|
"@deepseek-ai/schemastery": "^3.18.4",
|
|
63
64
|
"esbuild": "^0.25.0",
|
|
64
65
|
"react": "^18.2.0",
|