dsh-session-toolbox 0.1.10 → 0.1.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,12 @@
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.11
8
+
9
+ - **修复「切换会话到其它项目」总是报 `session … is live`**:此前的判定是「`sessions.list()` 里是否包含该会话」,但那返回的是**宿主已加载的全部会话**,只要文件打开过就算「运行中」,几乎任何会话都无法迁移。现改用官方的 `workspace/session-activity` 事件:只有出现 `{kind:'turn'}`(真正有一轮在跑,含等待审批/回答)才阻止迁移。
10
+ - **修复已发送截图仍被重复插回输入框**(0.1.10 未覆盖真实场景):附件栏探测用的选择器 `[data-composer-bar]` 在官方 UI 中**并不存在**,真实容器是 `[data-composer-seat]`(带 `data-conversation-region="composer"`)。选择器始终落空 → 探测永远得到 0 张卡片 → 发送检测永不触发、恢复时也总认为「输入框是空的」。现已改用真实容器,并同时接受 `blob:` 与 `data:image/` 两种预览源。
11
+ - 测试桩改为模拟真实 composer 结构(此前只应答 `conversation-content`,所有探测都走兜底路径,所以测试全绿但真实场景失败)。
12
+
7
13
  ## 0.1.10
8
14
 
9
15
  - **修复已发送的截图在切回会话后被重复插回输入框**。此前判断「已发送」靠附件栏从有到无的跳变:切回会话时附件栏本来就是空的,这个跳变永远不会发生,于是每次切回都把旧图重新粘贴一遍。
package/cordis.patch.yml CHANGED
@@ -1,3 +1,3 @@
1
1
  - insert:
2
- - id: session-toolbox-v1-0.1.10
3
- name: ./lib/host-v0.1.10.js
2
+ - id: session-toolbox-v1-0.1.11
3
+ name: ./lib/host-v0.1.11.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.10",
42
+ version: "0.1.11",
43
43
  repository: {
44
44
  type: "git",
45
45
  url: "https://github.com/AndroidSix/dsh-session-toolbox.git"
@@ -311,9 +311,13 @@ function createVault(options = {}) {
311
311
  return document.querySelector?.('[data-conversation-session] [contenteditable="true"]') ?? void 0;
312
312
  }
313
313
  function attachmentRail(editor) {
314
- const bar = editor?.closest?.('[data-composer-bar], [data-conversation-region="composer"]') ?? editor?.parentElement?.parentElement?.parentElement;
315
- if (bar?.querySelectorAll === void 0) return void 0;
316
- return [...bar.querySelectorAll("img")].filter((img) => img.getAttribute?.("src")?.startsWith("blob:"));
314
+ const seat = editor?.closest?.('[data-composer-seat], [data-conversation-region="composer"]');
315
+ const root = seat ?? editor?.parentElement?.parentElement?.parentElement;
316
+ if (root?.querySelectorAll === void 0) return void 0;
317
+ return [...root.querySelectorAll("img")].filter((img) => {
318
+ const src = img.getAttribute?.("src") ?? "";
319
+ return src.startsWith("blob:") || src.startsWith("data:image/");
320
+ });
317
321
  }
318
322
  async function seedSession(sessionId = currentSession()) {
319
323
  if (sessionId === void 0 || sessionId === "" || !limits.enabled) return false;
@@ -322,7 +326,7 @@ function createVault(options = {}) {
322
326
  const rail = attachmentRail(editor);
323
327
  if (rail === void 0) return false;
324
328
  if (rail.length > 0) return true;
325
- const pending = (await allRecords()).filter((record) => record.sessionId === sessionId && !record.sentAt);
329
+ const pending = (await allRecords()).filter((record) => record.sessionId === sessionId && !record.sentAt && !record.delivered);
326
330
  if (pending.length === 0) return true;
327
331
  const files = [];
328
332
  for (const record of pending) {
@@ -350,7 +354,7 @@ function createVault(options = {}) {
350
354
  const accepted = event.defaultPrevented === true;
351
355
  if (accepted) notice(`\u5DF2\u6062\u590D ${files.length} \u5F20\u8349\u7A3F\u56FE\u7247\uFF08\u4F1A\u8BDD ${sessionId.slice(-6)}\uFF09`);
352
356
  else log("warn", "synthetic paste was not accepted; vault stays idle for this session");
353
- if (accepted) for (const record of pending) await putRecord({ ...record, seeded: true });
357
+ if (accepted) for (const record of pending) await putRecord({ ...record, seeded: true, delivered: now() });
354
358
  changed();
355
359
  return accepted;
356
360
  }
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';\n// `locale` is a real service, so it must be injected before use: cordis throws\n// on property access for a service that was never injected (it does not return\n// undefined), which is what surfaced as \"cannot get property \\\"locale\\\" without\n// inject\" on the plugin page.\nexport const inject = ['slots', 'locale'];\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\t// `locale` is injected above, so the service is guaranteed here; registering\n\t// inside ctx.effect keeps the dictionaries disposable across hot reloads\n\t// (same shape as the official client plugins).\n\tctx.effect(() => ctx.locale.register(NS, {\n\t\tzh: { 'menu.move': '\u5207\u6362\u5230\u5176\u5B83\u9879\u76EE\u2026', 'menu.trash': '\u5F52\u6863\u5230\u5F52\u6863\u6C60' },\n\t\ten: { 'menu.move': 'Move to another project\u2026', 'menu.trash': 'Archive' },\n\t}), 'session-toolbox: dictionaries');\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 \u5F52\u6863\u6C60 \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\t// Known projects, so the target can be picked by name instead of typed as a path.\n\tconst projects = state?.projects ?? [];\n\t// Which project the typed session currently belongs to (computed host-side).\n\tconst [fromProject, setFromProject] = useState(null);\n\tuseEffect(() => {\n\t\tif (!sessionId) { setFromProject(null); return; }\n\t\tlet alive = true;\n\t\tvoid callHost({ type: 'project.of', sessionId })\n\t\t\t.then(result => { if (alive) setFromProject(result?.project ?? null); })\n\t\t\t.catch(() => { if (alive) setFromProject(null); });\n\t\treturn () => { alive = false; };\n\t}, [sessionId]);\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{projects.length > 0 && (\n\t\t\t\t\t<select className=\"grow\" value={projects.some(p => p.path === toCwd) ? toCwd : ''}\n\t\t\t\t\t\tonChange={e => { setToCwd(e.target.value); setPlan(null); }}>\n\t\t\t\t\t\t<option value=\"\">\u9009\u62E9\u76EE\u6807\u9879\u76EE\u2026</option>\n\t\t\t\t\t\t{projects.map(project => (\n\t\t\t\t\t\t\t<option key={project.id} value={project.path} disabled={fromProject?.path === project.path}>\n\t\t\t\t\t\t\t\t{project.title}\uFF08{project.sessions} \u4E2A\u4F1A\u8BDD\uFF09{fromProject?.path === project.path ? ' \u2014 \u5F53\u524D\u9879\u76EE' : ''}\n\t\t\t\t\t\t\t</option>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</select>\n\t\t\t\t)}\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{sessionId && (\n\t\t\t\t<p className=\"muted\">\n\t\t\t\t\t\u5F53\u524D\u9879\u76EE\uFF1A{fromProject === null ? '\uFF08\u672A\u627E\u5230\u8BE5\u4F1A\u8BDD\uFF0C\u6216\u5B83\u4E0D\u5C5E\u4E8E\u4EFB\u4F55\u9879\u76EE\uFF09'\n\t\t\t\t\t\t: <><strong>{fromProject.title}</strong>{' '}<span className=\"mono\">{fromProject.path}</span></>}\n\t\t\t\t</p>\n\t\t\t)}\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>\u5F52\u6863\u6C60</h3>\n\t\t\t<p className=\"muted\">\n\t\t\t\tDSH \u6CA1\u6709\u72EC\u7ACB\u7684\u300C\u5220\u9664\u4F1A\u8BDD\u300D\u2014\u2014\u4F1A\u8BDD\u53EA\u80FD<b>\u5F52\u6863</b>\u3002\u8FD9\u91CC\u5C31\u662F\u5B98\u65B9\u7684\u5F52\u6863\u6C60\uFF1A\u5165\u6C60\u7684\u4F1A\u8BDD\u4ECD\u7136\u662F\u5B98\u65B9\u5F52\u6863\u72B6\u6001\uFF08\u4FA7\u680F\u7684\u5F52\u6863\u89C6\u56FE\u91CC\u540C\u6837\u80FD\u770B\u5230\uFF09\uFF0C\u672C\u63D2\u4EF6\u989D\u5916\u8BB0\u5F55\u4E86\u5B83\u5165\u6C60\u65F6\u7684<b>\u9879\u76EE\u5F52\u5C5E\u3001\u5217\u8868\u4F4D\u7F6E\u4E0E\u7F6E\u9876\u72B6\u6001</b>\uFF0C\u56E0\u6B64\u53EF\u4EE5\u4E00\u952E\u8FD8\u539F\u5230\u539F\u4F4D\u3002\n\t\t\t\t\u5F52\u6863\u9879\u76EE\u5219\u4FDD\u7559\u5168\u90E8\u4F1A\u8BDD\u65E5\u5FD7\uFF0C\u53EA\u79FB\u9664\u9879\u76EE\u6CE8\u518C\u8868\u9879\u3002\u5F7B\u5E95\u5220\u9664\u4F1A\u5148\u79FB\u5165\u6682\u5B58\u76EE\u5F55\u518D\u6E05\u7406\uFF0C\u4E2D\u65AD\u53EF\u7528 CLI \u68C0\u51FA\u3002\n\t\t\t</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\u6C60\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\u5230\u539F\u4F4D').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\u79FB\u51FA{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\u5F52\u6863\uFF1F\uFF08\u4F1A\u8BDD\u5C06\u8FDB\u5165\u5F52\u6863\u6C60\uFF09</button>;\n\t}\n\treturn <button role=\"menuitem\" style={menuItemStyle} onClick={() => setConfirm(true)}>{t ? t('menu.trash') : '\u5F52\u6863\u5230\u5F52\u6863\u6C60'}</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\t// Same project picker as the panel: the dialog is what the context menu opens,\n\t// so it must not fall back to typing a path by hand.\n\tconst [projects, setProjects] = useState([]);\n\tconst [fromProject, setFromProject] = useState(null);\n\tuseEffect(() => { const dialog = ref.current; dialog?.showModal(); return () => { try { dialog?.close(); } catch {} }; }, []);\n\tuseEffect(() => {\n\t\tlet alive = true;\n\t\tvoid loadState().then(next => { if (alive) setProjects(next?.projects ?? []); }).catch(() => {});\n\t\tvoid callHost({ type: 'project.of', sessionId })\n\t\t\t.then(result => { if (alive) setFromProject(result?.project ?? null); })\n\t\t\t.catch(() => { if (alive) setFromProject(null); });\n\t\treturn () => { alive = false; };\n\t}, [sessionId]);\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<p className=\"muted\">\n\t\t\t\t\t\t\u5F53\u524D\u9879\u76EE\uFF1A{fromProject === null ? '\uFF08\u672A\u627E\u5230\uFF0C\u6216\u4E0D\u5C5E\u4E8E\u4EFB\u4F55\u9879\u76EE\uFF09'\n\t\t\t\t\t\t: <><strong>{fromProject.title}</strong>{' '}<span className=\"mono\">{fromProject.path}</span></>}\n\t\t\t\t\t</p>\n\t\t\t\t\t{projects.length > 0 && (\n\t\t\t\t\t\t<select className=\"grow\" value={projects.some(p => p.path === toCwd) ? toCwd : ''}\n\t\t\t\t\t\t\tonChange={e => setToCwd(e.target.value)}>\n\t\t\t\t\t\t\t<option value=\"\">\u9009\u62E9\u76EE\u6807\u9879\u76EE\u2026</option>\n\t\t\t\t\t\t\t{projects.map(project => (\n\t\t\t\t\t\t\t\t<option key={project.id} value={project.path} disabled={fromProject?.path === project.path}>\n\t\t\t\t\t\t\t\t\t{project.title}\uFF08{project.sessions} \u4E2A\u4F1A\u8BDD\uFF09{fromProject?.path === project.path ? ' \u2014 \u5F53\u524D\u9879\u76EE' : ''}\n\t\t\t\t\t\t\t\t</option>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</select>\n\t\t\t\t\t)}\n\t\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)} />\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.10\",\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, sentAt }) =>\n\t\t\t\t({ key, sessionId, attachmentId, name, size, hash, seeded, createdAt, sentAt: sentAt ?? 0 }));\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(), sentAt: 0, 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\t// Never resurrect images that already travelled with a sent message: that is\n\t\t// what duplicated screenshots whenever a session was switched back to.\n\t\tconst pending = (await allRecords()).filter(record => record.sessionId === sessionId && !record.sentAt);\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\t// A restore hands the images back to the official composer; they now live\n\t\t// there (and will be retired when sent), so keep a single copy in the vault.\n\t\tif (accepted) for (const record of pending) await putRecord({ ...record, seeded: true });\n\t\tchanged();\n\t\treturn accepted;\n\t}\n\n\t// ---- FR3 lifecycle ---------------------------------------------------------\n\t/**\n\t * Mark a session's backed-up drafts as already sent, so they are never\n\t * replayed into the composer again.\n\t *\n\t * Inferring \"sent\" from the attachment rail reaching zero used to miss the\n\t * common case: the rail is already empty by the time the session mounts\n\t * again, so the transition never happened while we were watching and the\n\t * old images were restored on every switch. Observing the composer while it\n\t * is mounted (below) plus this explicit retirement keeps the vault honest.\n\t */\n\tasync function retireSession(sessionId, reason) {\n\t\tlet retired = 0;\n\t\tfor (const record of await allRecords()) {\n\t\t\tif (record.sessionId !== sessionId || record.sentAt) continue;\n\t\t\tawait putRecord({ ...record, sentAt: now() });\n\t\t\tretired += 1;\n\t\t}\n\t\tif (retired > 0) {\n\t\t\tnotice(reason === 'sent'\n\t\t\t\t? `\u672C\u4F1A\u8BDD\u8349\u7A3F\u5DF2\u968F\u6D88\u606F\u53D1\u9001\uFF0C${retired} \u5F20\u5907\u4EFD\u4E0D\u518D\u6062\u590D`\n\t\t\t\t: `\u672C\u4F1A\u8BDD\u8349\u7A3F\u5DF2\u6E05\u7A7A\uFF0C${retired} \u5F20\u5907\u4EFD\u4E0D\u518D\u6062\u590D`);\n\t\t\tvoid syncHost();\n\t\t}\n\t\tchanged();\n\t\treturn retired;\n\t}\n\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// Cards disappeared while the composer was mounted: the message was\n\t\t\t\t// sent (or the user removed them), so retire the backups for good.\n\t\t\t\tawait retireSession(sessionId, 'sent');\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\n\t\t// Belt and braces: listen for the send gesture itself, so a fast unmount\n\t\t// (enter then immediately switch away) still retires the drafts.\n\t\tconst onKeyDown = event => {\n\t\t\tif (event.key !== 'Enter' || event.shiftKey || event.isComposing) return;\n\t\t\tconst target = event.target;\n\t\t\tif (target?.closest?.('[data-conversation-session]') === null || target?.closest?.('[data-conversation-session]') === undefined) return;\n\t\t\tif ((attachmentRail(editor)?.length ?? 0) > 0) void retireSession(sessionId, 'sent');\n\t\t};\n\t\tdocument.addEventListener('keydown', onKeyDown, true);\n\t\treturn () => { observer.disconnect(); document.removeEventListener('keydown', onKeyDown, true); };\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\t/** Retire a session's unsent drafts (called when its images were sent). */\n\t\tretire: async (sessionId = currentSession(), reason = 'sent') => retireSession(sessionId, reason),\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';\n// `locale` is a real service, so it must be injected before use: cordis throws\n// on property access for a service that was never injected (it does not return\n// undefined), which is what surfaced as \"cannot get property \\\"locale\\\" without\n// inject\" on the plugin page.\nexport const inject = ['slots', 'locale'];\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\t// `locale` is injected above, so the service is guaranteed here; registering\n\t// inside ctx.effect keeps the dictionaries disposable across hot reloads\n\t// (same shape as the official client plugins).\n\tctx.effect(() => ctx.locale.register(NS, {\n\t\tzh: { 'menu.move': '\u5207\u6362\u5230\u5176\u5B83\u9879\u76EE\u2026', 'menu.trash': '\u5F52\u6863\u5230\u5F52\u6863\u6C60' },\n\t\ten: { 'menu.move': 'Move to another project\u2026', 'menu.trash': 'Archive' },\n\t}), 'session-toolbox: dictionaries');\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 \u5F52\u6863\u6C60 \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\t// Known projects, so the target can be picked by name instead of typed as a path.\n\tconst projects = state?.projects ?? [];\n\t// Which project the typed session currently belongs to (computed host-side).\n\tconst [fromProject, setFromProject] = useState(null);\n\tuseEffect(() => {\n\t\tif (!sessionId) { setFromProject(null); return; }\n\t\tlet alive = true;\n\t\tvoid callHost({ type: 'project.of', sessionId })\n\t\t\t.then(result => { if (alive) setFromProject(result?.project ?? null); })\n\t\t\t.catch(() => { if (alive) setFromProject(null); });\n\t\treturn () => { alive = false; };\n\t}, [sessionId]);\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{projects.length > 0 && (\n\t\t\t\t\t<select className=\"grow\" value={projects.some(p => p.path === toCwd) ? toCwd : ''}\n\t\t\t\t\t\tonChange={e => { setToCwd(e.target.value); setPlan(null); }}>\n\t\t\t\t\t\t<option value=\"\">\u9009\u62E9\u76EE\u6807\u9879\u76EE\u2026</option>\n\t\t\t\t\t\t{projects.map(project => (\n\t\t\t\t\t\t\t<option key={project.id} value={project.path} disabled={fromProject?.path === project.path}>\n\t\t\t\t\t\t\t\t{project.title}\uFF08{project.sessions} \u4E2A\u4F1A\u8BDD\uFF09{fromProject?.path === project.path ? ' \u2014 \u5F53\u524D\u9879\u76EE' : ''}\n\t\t\t\t\t\t\t</option>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</select>\n\t\t\t\t)}\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{sessionId && (\n\t\t\t\t<p className=\"muted\">\n\t\t\t\t\t\u5F53\u524D\u9879\u76EE\uFF1A{fromProject === null ? '\uFF08\u672A\u627E\u5230\u8BE5\u4F1A\u8BDD\uFF0C\u6216\u5B83\u4E0D\u5C5E\u4E8E\u4EFB\u4F55\u9879\u76EE\uFF09'\n\t\t\t\t\t\t: <><strong>{fromProject.title}</strong>{' '}<span className=\"mono\">{fromProject.path}</span></>}\n\t\t\t\t</p>\n\t\t\t)}\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>\u5F52\u6863\u6C60</h3>\n\t\t\t<p className=\"muted\">\n\t\t\t\tDSH \u6CA1\u6709\u72EC\u7ACB\u7684\u300C\u5220\u9664\u4F1A\u8BDD\u300D\u2014\u2014\u4F1A\u8BDD\u53EA\u80FD<b>\u5F52\u6863</b>\u3002\u8FD9\u91CC\u5C31\u662F\u5B98\u65B9\u7684\u5F52\u6863\u6C60\uFF1A\u5165\u6C60\u7684\u4F1A\u8BDD\u4ECD\u7136\u662F\u5B98\u65B9\u5F52\u6863\u72B6\u6001\uFF08\u4FA7\u680F\u7684\u5F52\u6863\u89C6\u56FE\u91CC\u540C\u6837\u80FD\u770B\u5230\uFF09\uFF0C\u672C\u63D2\u4EF6\u989D\u5916\u8BB0\u5F55\u4E86\u5B83\u5165\u6C60\u65F6\u7684<b>\u9879\u76EE\u5F52\u5C5E\u3001\u5217\u8868\u4F4D\u7F6E\u4E0E\u7F6E\u9876\u72B6\u6001</b>\uFF0C\u56E0\u6B64\u53EF\u4EE5\u4E00\u952E\u8FD8\u539F\u5230\u539F\u4F4D\u3002\n\t\t\t\t\u5F52\u6863\u9879\u76EE\u5219\u4FDD\u7559\u5168\u90E8\u4F1A\u8BDD\u65E5\u5FD7\uFF0C\u53EA\u79FB\u9664\u9879\u76EE\u6CE8\u518C\u8868\u9879\u3002\u5F7B\u5E95\u5220\u9664\u4F1A\u5148\u79FB\u5165\u6682\u5B58\u76EE\u5F55\u518D\u6E05\u7406\uFF0C\u4E2D\u65AD\u53EF\u7528 CLI \u68C0\u51FA\u3002\n\t\t\t</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\u6C60\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\u5230\u539F\u4F4D').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\u79FB\u51FA{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\u5F52\u6863\uFF1F\uFF08\u4F1A\u8BDD\u5C06\u8FDB\u5165\u5F52\u6863\u6C60\uFF09</button>;\n\t}\n\treturn <button role=\"menuitem\" style={menuItemStyle} onClick={() => setConfirm(true)}>{t ? t('menu.trash') : '\u5F52\u6863\u5230\u5F52\u6863\u6C60'}</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\t// Same project picker as the panel: the dialog is what the context menu opens,\n\t// so it must not fall back to typing a path by hand.\n\tconst [projects, setProjects] = useState([]);\n\tconst [fromProject, setFromProject] = useState(null);\n\tuseEffect(() => { const dialog = ref.current; dialog?.showModal(); return () => { try { dialog?.close(); } catch {} }; }, []);\n\tuseEffect(() => {\n\t\tlet alive = true;\n\t\tvoid loadState().then(next => { if (alive) setProjects(next?.projects ?? []); }).catch(() => {});\n\t\tvoid callHost({ type: 'project.of', sessionId })\n\t\t\t.then(result => { if (alive) setFromProject(result?.project ?? null); })\n\t\t\t.catch(() => { if (alive) setFromProject(null); });\n\t\treturn () => { alive = false; };\n\t}, [sessionId]);\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<p className=\"muted\">\n\t\t\t\t\t\t\u5F53\u524D\u9879\u76EE\uFF1A{fromProject === null ? '\uFF08\u672A\u627E\u5230\uFF0C\u6216\u4E0D\u5C5E\u4E8E\u4EFB\u4F55\u9879\u76EE\uFF09'\n\t\t\t\t\t\t: <><strong>{fromProject.title}</strong>{' '}<span className=\"mono\">{fromProject.path}</span></>}\n\t\t\t\t\t</p>\n\t\t\t\t\t{projects.length > 0 && (\n\t\t\t\t\t\t<select className=\"grow\" value={projects.some(p => p.path === toCwd) ? toCwd : ''}\n\t\t\t\t\t\t\tonChange={e => setToCwd(e.target.value)}>\n\t\t\t\t\t\t\t<option value=\"\">\u9009\u62E9\u76EE\u6807\u9879\u76EE\u2026</option>\n\t\t\t\t\t\t\t{projects.map(project => (\n\t\t\t\t\t\t\t\t<option key={project.id} value={project.path} disabled={fromProject?.path === project.path}>\n\t\t\t\t\t\t\t\t\t{project.title}\uFF08{project.sessions} \u4E2A\u4F1A\u8BDD\uFF09{fromProject?.path === project.path ? ' \u2014 \u5F53\u524D\u9879\u76EE' : ''}\n\t\t\t\t\t\t\t\t</option>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</select>\n\t\t\t\t\t)}\n\t\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)} />\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.11\",\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, sentAt }) =>\n\t\t\t\t({ key, sessionId, attachmentId, name, size, hash, seeded, createdAt, sentAt: sentAt ?? 0 }));\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(), sentAt: 0, 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\t/**\n\t * Image cards currently sitting in the composer.\n\t *\n\t * The official composer region is `[data-composer-seat]` (carrying\n\t * `data-conversation-region=\"composer\"`); the old selector also looked for a\n\t * `data-composer-bar` attribute that the current UI never emits, which made\n\t * every lookup fall through to a brittle parentElement walk and usually\n\t * return zero cards. A zero rail in turn defeated both the send detector and\n\t * the \"composer already holds them\" guard.\n\t */\n\tfunction attachmentRail(editor) {\n\t\tconst seat = editor?.closest?.('[data-composer-seat], [data-conversation-region=\"composer\"]');\n\t\tconst root = seat ?? editor?.parentElement?.parentElement?.parentElement;\n\t\tif (root?.querySelectorAll === undefined) return undefined;\n\t\treturn [...root.querySelectorAll('img')].filter(img => {\n\t\t\tconst src = img.getAttribute?.('src') ?? '';\n\t\t\treturn src.startsWith('blob:') || src.startsWith('data:image/');\n\t\t});\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\t// Never resurrect images that already travelled with a sent message. Two\n\t\t// independent guards: an explicit sent flag, and a \"already handed back to\n\t\t// the composer\" flag so a single batch is dispatched at most once even if\n\t\t// the rail probe misses the cards.\n\t\tconst pending = (await allRecords()).filter(record => record.sessionId === sessionId && !record.sentAt && !record.delivered);\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\t// A restore hands the images back to the official composer; they now live\n\t\t// there (and will be retired when sent), so keep a single copy in the vault.\n\t\tif (accepted) for (const record of pending) await putRecord({ ...record, seeded: true, delivered: now() });\n\t\tchanged();\n\t\treturn accepted;\n\t}\n\n\t// ---- FR3 lifecycle ---------------------------------------------------------\n\t/**\n\t * Mark a session's backed-up drafts as already sent, so they are never\n\t * replayed into the composer again.\n\t *\n\t * Inferring \"sent\" from the attachment rail reaching zero used to miss the\n\t * common case: the rail is already empty by the time the session mounts\n\t * again, so the transition never happened while we were watching and the\n\t * old images were restored on every switch. Observing the composer while it\n\t * is mounted (below) plus this explicit retirement keeps the vault honest.\n\t */\n\tasync function retireSession(sessionId, reason) {\n\t\tlet retired = 0;\n\t\tfor (const record of await allRecords()) {\n\t\t\tif (record.sessionId !== sessionId || record.sentAt) continue;\n\t\t\tawait putRecord({ ...record, sentAt: now() });\n\t\t\tretired += 1;\n\t\t}\n\t\tif (retired > 0) {\n\t\t\tnotice(reason === 'sent'\n\t\t\t\t? `\u672C\u4F1A\u8BDD\u8349\u7A3F\u5DF2\u968F\u6D88\u606F\u53D1\u9001\uFF0C${retired} \u5F20\u5907\u4EFD\u4E0D\u518D\u6062\u590D`\n\t\t\t\t: `\u672C\u4F1A\u8BDD\u8349\u7A3F\u5DF2\u6E05\u7A7A\uFF0C${retired} \u5F20\u5907\u4EFD\u4E0D\u518D\u6062\u590D`);\n\t\t\tvoid syncHost();\n\t\t}\n\t\tchanged();\n\t\treturn retired;\n\t}\n\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// Cards disappeared while the composer was mounted: the message was\n\t\t\t\t// sent (or the user removed them), so retire the backups for good.\n\t\t\t\tawait retireSession(sessionId, 'sent');\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\n\t\t// Belt and braces: listen for the send gesture itself, so a fast unmount\n\t\t// (enter then immediately switch away) still retires the drafts.\n\t\tconst onKeyDown = event => {\n\t\t\tif (event.key !== 'Enter' || event.shiftKey || event.isComposing) return;\n\t\t\tconst target = event.target;\n\t\t\tif (target?.closest?.('[data-conversation-session]') === null || target?.closest?.('[data-conversation-session]') === undefined) return;\n\t\t\tif ((attachmentRail(editor)?.length ?? 0) > 0) void retireSession(sessionId, 'sent');\n\t\t};\n\t\tdocument.addEventListener('keydown', onKeyDown, true);\n\t\treturn () => { observer.disconnect(); document.removeEventListener('keydown', onKeyDown, true); };\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\t/** Retire a session's unsent drafts (called when its images were sent). */\n\t\tretire: async (sessionId = currentSession(), reason = 'sent') => retireSession(sessionId, reason),\n\t\tintake,\n\t\twatchMounts,\n\t};\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,mBAA4C;;;ACP5C;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,IACR,KAAO;AAAA,EACT;AAAA,EACA,OAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,KAAO;AAAA,IACL,QAAU;AAAA,MACR,OAAS;AAAA,IACX;AAAA,IACA,QAAU;AAAA,MACR,QAAU;AAAA,QACR;AAAA,MACF;AAAA,MACA,UAAY;AAAA,IACd;AAAA,EACF;AAAA,EACA,SAAW;AAAA,IACT,OAAS;AAAA,IACT,MAAQ;AAAA,IACR,OAAS;AAAA,IACT,iBAAiB;AAAA,IACjB,gBAAgB;AAAA,EAClB;AAAA,EACA,kBAAoB;AAAA,IAClB,uBAAuB;AAAA,IACvB,iCAAiC;AAAA,IACjC,+BAA+B;AAAA,IAC/B,4BAA4B;AAAA,IAC5B,OAAS;AAAA,EACX;AAAA,EACA,iBAAmB;AAAA,IACjB,uBAAuB;AAAA,IACvB,iCAAiC;AAAA,IACjC,+BAA+B;AAAA,IAC/B,4BAA4B;AAAA,IAC5B,SAAW;AAAA,IACX,OAAS;AAAA,IACT,aAAa;AAAA,EACf;AAAA,EACA,SAAW;AAAA,EACX,UAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACvDO,IAAM,UAAU;AAChB,IAAM,QAAQ;AACd,IAAM,cAAc,CAAC,aAAa,cAAc,cAAc,WAAW;AAEhF,IAAM,cAAc,OAAO,IAAI,0BAA0B;AAElD,IAAM,iBAAiB,KAAK,OAAO;AACnC,IAAM,iBAAiB,OAAO,OAAO,EAAE,SAAS,MAAM,cAAc,MAAM,OAAO,MAAM,SAAS,EAAE,CAAC;AAEnG,SAAS,YAAY,MAAM;AACjC,SAAO,SAAS,UAAa,YAAY,SAAS,KAAK,IAAI,KAAK,KAAK,OAAO,KAAK,KAAK,QAAQ;AAC/F;AAGA,eAAsB,YAAY,MAAM;AACvC,MAAI,WAAW,QAAQ,WAAW,QAAW;AAC5C,QAAI;AACH,YAAM,SAAS,MAAM,OAAO,OAAO,OAAO,WAAW,MAAM,KAAK,YAAY,CAAC;AAC7E,aAAO,CAAC,GAAG,IAAI,WAAW,MAAM,CAAC,EAAE,IAAI,UAAQ,KAAK,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAAE,KAAK,EAAE;AAAA,IAC3F,QAAQ;AAAA,IAAqB;AAAA,EAC9B;AACA,SAAO,QAAQ,KAAK,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,YAAY;AAC3D;AAEA,SAAS,SAAS;AACjB,MAAI,OAAO,cAAc,YAAa,OAAM,IAAI,MAAM,uBAAuB;AAC7E,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACvC,UAAM,UAAU,UAAU,KAAK,SAAS,CAAC;AACzC,YAAQ,kBAAkB,MAAM;AAC/B,YAAM,WAAW,QAAQ;AACzB,UAAI,CAAC,SAAS,iBAAiB,SAAS,KAAK,EAAG,UAAS,kBAAkB,OAAO,EAAE,SAAS,MAAM,CAAC;AAAA,IACrG;AACA,YAAQ,YAAY,MAAM,QAAQ,QAAQ,MAAM;AAChD,YAAQ,UAAU,MAAM,OAAO,QAAQ,SAAS,IAAI,MAAM,uBAAuB,CAAC;AAAA,EACnF,CAAC;AACF;AAGA,SAAS,KAAK,SAAS;AACtB,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACvC,YAAQ,YAAY,MAAM,QAAQ,QAAQ,MAAM;AAChD,YAAQ,UAAU,MAAM,OAAO,QAAQ,SAAS,IAAI,MAAM,8BAA8B,CAAC;AAAA,EAC1F,CAAC;AACF;AAEA,SAAS,QAAQ,UAAU,MAAM,KAAK;AACrC,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACvC,QAAI;AACJ,UAAM,cAAc,SAAS,YAAY,OAAO,IAAI;AACpD,gBAAY,UAAU,MAAM,OAAO,YAAY,SAAS,IAAI,MAAM,2BAA2B,CAAC;AAC9F,gBAAY,UAAU,MAAM,OAAO,YAAY,SAAS,IAAI,MAAM,0BAA0B,CAAC;AAC7F,QAAI;AAAE,gBAAU,IAAI,YAAY,YAAY,KAAK,CAAC;AAAA,IAAG,SAAS,OAAO;AAAE,aAAO,KAAK;AAAG;AAAA,IAAQ;AAC9F,YAAQ,QAAQ,OAAO,EAAE,KAAK,SAAS,MAAM;AAAA,EAC9C,CAAC;AACF;AAEA,SAAS,UAAU;AAClB,QAAM,YAAY,oBAAI,IAAI;AAC1B,SAAO;AAAA,IACN,GAAG,OAAO,IAAI;AAAE,UAAI,CAAC,UAAU,IAAI,KAAK,EAAG,WAAU,IAAI,OAAO,oBAAI,IAAI,CAAC;AAAG,gBAAU,IAAI,KAAK,EAAE,IAAI,EAAE;AAAA,IAAG;AAAA,IAC1G,IAAI,OAAO,IAAI;AAAE,gBAAU,IAAI,KAAK,GAAG,OAAO,EAAE;AAAA,IAAG;AAAA,IACnD,KAAK,OAAO,QAAQ;AAAE,iBAAW,MAAM,CAAC,GAAI,UAAU,IAAI,KAAK,KAAK,CAAC,CAAE,GAAG;AAAE,YAAI;AAAE,aAAG,MAAM;AAAA,QAAG,QAAQ;AAAA,QAAC;AAAA,MAAE;AAAA,IAAE;AAAA,EAC5G;AACD;AAEA,SAAS,kBAAkB,OAAO;AACjC,QAAM,QAAQ,MAAM,IAAI,QAAM,EAAE,MAAM,QAAQ,MAAM,EAAE,MAAM,WAAW,MAAM,EAAE,EAAE;AACjF,SAAO,EAAE,OAAO,OAAO,QAAQ,MAAM,QAAQ,OAAO,CAAC,OAAO,GAAG,SAAS,MAAM,IAAI,SAAS,MAAM,OAAO,WAAW,MAAM;AAAA,EAAC,EAAE;AAC7H;AAEA,eAAe,WAAW,QAAQ;AACjC,MAAI,OAAO,gBAAgB,KAAM,QAAO,OAAO;AAC/C,QAAM,OAAO,OAAO,gBAAgB,OAAO,OAAO,OAAO,IAAI,KAAK,CAAC,OAAO,QAAQ,IAAI,WAAW,CAAC,GAAG,EAAE,MAAM,OAAO,KAAK,CAAC;AAC1H,SAAO,IAAI,KAAK,CAAC,IAAI,GAAG,OAAO,QAAQ,IAAI,EAAE,MAAM,OAAO,MAAM,cAAc,OAAO,UAAU,CAAC;AACjG;AAKO,SAAS,YAAY,UAAU,CAAC,GAAG;AACzC,QAAM,MAAM,QAAQ,QAAQ,MAAM;AAAA,EAAC;AACnC,QAAM,MAAM,QAAQ,QAAQ,MAAM,KAAK,IAAI;AAC3C,QAAM,YAAY,QAAQ,cAAc,CAAC,OAAO,SAAS,MAAM,OAAO,IAAI;AAC1E,QAAM,MAAM,QAAQ;AACpB,MAAI,YAAY;AAChB,MAAI,SAAS,EAAE,GAAG,eAAe;AACjC,MAAI,aAAa;AACjB,MAAI,UAAU;AACd,MAAI,WAAW;AACf,MAAI,UAAU;AAEd,QAAM,KAAK,MAAM,cAAc,OAAO;AACtC,WAAS,OAAO,SAAS;AACxB,iBAAa;AACb,QAAI,KAAK,UAAU,OAAO;AAC1B,QAAI;AAAE,iBAAW,QAAQ,gBAAgB,IAAI,YAAY,8BAA8B,EAAE,QAAQ,QAAQ,CAAC,CAAC;AAAA,IAAG,QAAQ;AAAA,IAAkB;AAAA,EACzI;AACA,WAAS,UAAU;AAAE,QAAI,KAAK,QAAQ;AAAA,EAAG;AAGzC,QAAM,aAAa,YAAY;AAC9B,UAAM,WAAW,MAAM,GAAG;AAC1B,WAAO,MAAM,QAAQ,UAAU,YAAY,CAAAA,WAAS,KAAKA,OAAM,OAAO,CAAC,CAAC;AAAA,EACzE;AACA,QAAM,YAAY,OAAM,WAAU;AACjC,UAAM,WAAW,MAAM,GAAG;AAC1B,UAAM,QAAQ,UAAU,aAAa,CAAAA,WAAS,KAAKA,OAAM,IAAI,MAAM,CAAC,CAAC;AAAA,EACtE;AACA,QAAM,aAAa,OAAM,QAAO;AAC/B,UAAM,WAAW,MAAM,GAAG;AAC1B,UAAM,QAAQ,UAAU,aAAa,CAAAA,WAAS,KAAKA,OAAM,OAAO,GAAG,CAAC,CAAC;AAAA,EACtE;AAGA,iBAAe,WAAW;AACzB,UAAM,WAAW,QAAQ,YAAY;AACrC,QAAI;AACH,UAAI,YAAY,IAAI;AACnB,cAAM,QAAQ,MAAM,UAAU,UAAU,EAAE,OAAO,WAAW,CAAC;AAC7D,mBAAW,MAAM,MAAM,KAAK,GAAG,OAAO;AAAA,MACvC;AACA,YAAM,WAAW,MAAM,WAAW,GAAG,MAAM,IAAI,EAAE,IAAI,CAAC,EAAE,KAAK,WAAW,cAAc,MAAAC,OAAM,MAAM,MAAM,QAAQ,WAAW,OAAO,OAChI,EAAE,KAAK,WAAW,cAAc,MAAAA,OAAM,MAAM,MAAM,QAAQ,WAAW,QAAQ,UAAU,EAAE,EAAE;AAC7F,YAAM,UAAU,UAAU;AAAA,QAAE,QAAQ;AAAA,QAAQ,OAAO;AAAA,QAAY,SAAS,EAAE,gBAAgB,oBAAoB,yBAAyB,QAAQ;AAAA,QAC9I,MAAM,KAAK,UAAU,EAAE,MAAM,cAAc,QAAQ,CAAC;AAAA,MAAE,CAAC;AAAA,IACzD,QAAQ;AAAA,IAAgE;AAAA,EACzE;AAGA,iBAAe,QAAQ;AACtB,UAAM,UAAU,MAAM,WAAW;AACjC,UAAM,QAAQ,OAAO,UAAU,KAAK,KAAK,KAAK;AAC9C,UAAM,OAAO,CAAC;AACd,UAAM,SAAS,CAAC;AAChB,eAAW,UAAU,QAAS,EAAC,IAAI,KAAK,OAAO,aAAa,KAAK,QAAQ,SAAS,MAAM,KAAK,MAAM;AACnG,SAAK,KAAK,CAAC,GAAG,OAAO,EAAE,aAAa,MAAM,EAAE,aAAa,EAAE;AAC3D,QAAI,QAAQ,KAAK,OAAO,CAAC,OAAO,WAAW,SAAS,OAAO,QAAQ,IAAI,CAAC;AACxE,WAAO,QAAQ,OAAO,gBAAgB,KAAK,SAAS,GAAG;AACtD,YAAM,SAAS,KAAK,MAAM;AAC1B,eAAS,OAAO,QAAQ;AACxB,aAAO,KAAK,MAAM;AAAA,IACnB;AACA,eAAW,UAAU,OAAQ,OAAM,WAAW,OAAO,GAAG;AACxD,QAAI,OAAO,SAAS,EAAG,QAAO,oDAAY,OAAO,MAAM,oDAAY;AACnE,YAAQ;AACR,WAAO,EAAE,SAAS,OAAO,QAAQ,MAAM,KAAK,QAAQ,MAAM;AAAA,EAC3D;AAGA,iBAAe,OAAO,WAAW,OAAO;AACvC,QAAI,CAAC,OAAO,WAAW,cAAc,UAAa,cAAc,GAAI;AACpE,UAAM,YAAY,MAAM,WAAW,GAAG,OAAO,YAAU,OAAO,cAAc,SAAS;AACrF,UAAM,OAAO,IAAI,IAAI,SAAS,IAAI,YAAU,OAAO,IAAI,CAAC;AACxD,QAAI,QAAQ;AACZ,eAAW,QAAQ,OAAO;AACzB,UAAI,CAAC,YAAY,IAAI,EAAG;AACxB,YAAM,OAAO,MAAM,YAAY,IAAI;AACnC,UAAI,KAAK,IAAI,IAAI,EAAG;AACpB,WAAK,IAAI,IAAI;AACb,YAAM,KAAM,WAAW,QAAQ,aAAa,KAAK,MAAM,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC,CAAC;AACnG,YAAM,SAAS;AAAA,QAAE,KAAK,GAAG,SAAS,KAAK,EAAE;AAAA,QAAI;AAAA,QAAW,cAAc;AAAA,QACrE,MAAM,KAAK,QAAQ;AAAA,QAAI,MAAM,KAAK;AAAA,QAAM,MAAM,KAAK;AAAA,QAAM;AAAA,QAAM,WAAW,IAAI;AAAA,QAAG,QAAQ;AAAA,QAAG,QAAQ;AAAA,MAAM;AAC3G,aAAO,OAAO;AACd,YAAM,UAAU,MAAM;AACtB,eAAS;AAAA,IACV;AACA,QAAI,QAAQ,EAAG,QAAO,sBAAO,KAAK,qDAAa,UAAU,MAAM,EAAE,CAAC,QAAG;AACrE,SAAK,SAAS;AAAA,EACf;AAEA,QAAM,aAAa,WAAS,CAAC,GAAI,MAAM,eAAe,SAAS,MAAM,cAAc,SAAS,CAAC,CAAE,EAAE,OAAO,WAAW;AACnH,QAAM,kBAAkB,WAAS;AAChC,UAAM,SAAS,MAAM;AACrB,QAAI,EAAE,kBAAkB,qBAAqB,OAAO,SAAS,UAAU,OAAO,UAAU,KAAM,QAAO,CAAC;AACtG,WAAO,CAAC,GAAG,OAAO,KAAK,EAAE,OAAO,WAAW;AAAA,EAC5C;AAGA,WAAS,iBAAiB;AACzB,WAAO,SAAS,gBAAgB,6BAA6B,GAAG,eAAe,2BAA2B,KAAK;AAAA,EAChH;AACA,WAAS,eAAe;AACvB,WAAO,SAAS,gBAAgB,sDAAsD,KAAK;AAAA,EAC5F;AAWA,WAAS,eAAe,QAAQ;AAC/B,UAAM,OAAO,QAAQ,UAAU,6DAA6D;AAC5F,UAAM,OAAO,QAAQ,QAAQ,eAAe,eAAe;AAC3D,QAAI,MAAM,qBAAqB,OAAW,QAAO;AACjD,WAAO,CAAC,GAAG,KAAK,iBAAiB,KAAK,CAAC,EAAE,OAAO,SAAO;AACtD,YAAM,MAAM,IAAI,eAAe,KAAK,KAAK;AACzC,aAAO,IAAI,WAAW,OAAO,KAAK,IAAI,WAAW,aAAa;AAAA,IAC/D,CAAC;AAAA,EACF;AAGA,iBAAe,YAAY,YAAY,eAAe,GAAG;AACxD,QAAI,cAAc,UAAa,cAAc,MAAM,CAAC,OAAO,QAAS,QAAO;AAC3E,UAAM,SAAS,aAAa;AAC5B,QAAI,WAAW,OAAW,QAAO;AACjC,UAAM,OAAO,eAAe,MAAM;AAClC,QAAI,SAAS,OAAW,QAAO;AAC/B,QAAI,KAAK,SAAS,EAAG,QAAO;AAK5B,UAAM,WAAW,MAAM,WAAW,GAAG,OAAO,YAAU,OAAO,cAAc,aAAa,CAAC,OAAO,UAAU,CAAC,OAAO,SAAS;AAC3H,QAAI,QAAQ,WAAW,EAAG,QAAO;AACjC,UAAM,QAAQ,CAAC;AACf,eAAW,UAAU,SAAS;AAC7B,UAAI;AAAE,cAAM,KAAK,MAAM,WAAW,MAAM,CAAC;AAAA,MAAG,QACtC;AAAE,cAAM,WAAW,OAAO,GAAG;AAAA,MAAG;AAAA,IACvC;AACA,QAAI,MAAM,WAAW,GAAG;AAAE,cAAQ;AAAG,aAAO;AAAA,IAAO;AACnD,UAAM,QAAQ,IAAI,eAAe,SAAS,EAAE,SAAS,MAAM,YAAY,KAAK,CAAC;AAC7E,WAAO,eAAe,OAAO,iBAAiB,EAAE,OAAO,kBAAkB,KAAK,EAAE,CAAC;AAGjF,QAAI;AAAE,aAAO,eAAe,OAAO,aAAa,EAAE,OAAO,KAAK,CAAC;AAAA,IAAG,QAAQ;AAAA,IAAe;AACzF,QAAI;AAAE,aAAO,QAAQ;AAAA,IAAG,QAAQ;AAAA,IAAe;AAC/C,WAAO,cAAc,KAAK;AAC1B,UAAM,WAAW,MAAM,qBAAqB;AAC5C,QAAI,SAAU,QAAO,sBAAO,MAAM,MAAM,qDAAa,UAAU,MAAM,EAAE,CAAC,QAAG;AAAA,QACtE,KAAI,QAAQ,qEAAqE;AAGtF,QAAI,SAAU,YAAW,UAAU,QAAS,OAAM,UAAU,EAAE,GAAG,QAAQ,QAAQ,MAAM,WAAW,IAAI,EAAE,CAAC;AACzG,YAAQ;AACR,WAAO;AAAA,EACR;AAaA,iBAAe,cAAc,WAAW,QAAQ;AAC/C,QAAI,UAAU;AACd,eAAW,UAAU,MAAM,WAAW,GAAG;AACxC,UAAI,OAAO,cAAc,aAAa,OAAO,OAAQ;AACrD,YAAM,UAAU,EAAE,GAAG,QAAQ,QAAQ,IAAI,EAAE,CAAC;AAC5C,iBAAW;AAAA,IACZ;AACA,QAAI,UAAU,GAAG;AAChB,aAAO,WAAW,SACf,2EAAe,OAAO,gDACtB,yDAAY,OAAO,6CAAU;AAChC,WAAK,SAAS;AAAA,IACf;AACA,YAAQ;AACR,WAAO;AAAA,EACR;AAEA,WAAS,aAAa,WAAW,QAAQ;AACxC,QAAI,OAAO,eAAe,MAAM,GAAG,UAAU;AAC7C,UAAM,QAAQ,OAAO,UAAU,6BAA6B,KAAK;AACjE,UAAM,QAAQ,YAAY;AACzB,YAAM,OAAO,eAAe,MAAM,GAAG,UAAU;AAC/C,UAAI,SAAS,KAAM;AACnB,UAAI,OAAO,KAAK,SAAS,KAAK,OAAO,gBAAgB,MAAM;AAG1D,cAAM,cAAc,WAAW,MAAM;AAAA,MACtC;AACA,aAAO;AACP,cAAQ;AAAA,IACT;AACA,QAAI,OAAO,qBAAqB,WAAY,QAAO,MAAM;AAAA,IAAC;AAC1D,UAAM,WAAW,IAAI,iBAAiB,MAAM,KAAK,MAAM,CAAC;AACxD,aAAS,QAAQ,OAAO,EAAE,SAAS,MAAM,WAAW,KAAK,CAAC;AAI1D,UAAM,YAAY,WAAS;AAC1B,UAAI,MAAM,QAAQ,WAAW,MAAM,YAAY,MAAM,YAAa;AAClE,YAAM,SAAS,MAAM;AACrB,UAAI,QAAQ,UAAU,6BAA6B,MAAM,QAAQ,QAAQ,UAAU,6BAA6B,MAAM,OAAW;AACjI,WAAK,eAAe,MAAM,GAAG,UAAU,KAAK,EAAG,MAAK,cAAc,WAAW,MAAM;AAAA,IACpF;AACA,aAAS,iBAAiB,WAAW,WAAW,IAAI;AACpD,WAAO,MAAM;AAAE,eAAS,WAAW;AAAG,eAAS,oBAAoB,WAAW,WAAW,IAAI;AAAA,IAAG;AAAA,EACjG;AAEA,WAAS,cAAc;AACtB,QAAI,eAAe,IAAI,UAAU,MAAM;AAAA,IAAC;AACxC,UAAM,OAAO,YAAY;AACxB,YAAM,YAAY,eAAe;AACjC,YAAM,SAAS,aAAa;AAC5B,UAAI,cAAc,MAAM,WAAW,OAAW;AAC9C,UAAI,cAAc,gBAAgB,OAAO,gBAAgB,MAAO;AAChE,qBAAe;AACf,cAAQ;AACR,gBAAU,aAAa,WAAW,MAAM;AACxC,iBAAW,MAAM,KAAK,YAAY,SAAS,EAAE,MAAM,WAAS,IAAI,QAAQ,sBAAsB,MAAM,OAAO,EAAE,CAAC,GAAG,GAAG;AACpH,WAAK,MAAM,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC;AAAA,IAC5B;AACA,UAAM,WAAW,YAAY,MAAM,KAAK,KAAK,GAAG,GAAI;AACpD,QAAI,OAAO,qBAAqB,WAAY,QAAO,MAAM,cAAc,QAAQ;AAC/E,UAAM,WAAW,IAAI,iBAAiB,MAAM,KAAK,KAAK,CAAC;AACvD,aAAS,QAAQ,SAAS,iBAAiB,EAAE,SAAS,MAAM,WAAW,MAAM,YAAY,MAAM,iBAAiB,CAAC,2BAA2B,EAAE,CAAC;AAC/I,WAAO,MAAM;AAAE,eAAS,WAAW;AAAG,oBAAc,QAAQ;AAAG,cAAQ;AAAA,IAAG;AAAA,EAC3E;AAEA,SAAO;AAAA,IACN,IAAI,IAAI;AAAA,IAAI,KAAK,IAAI;AAAA,IACrB,IAAI,aAAa;AAAE,aAAO;AAAA,IAAY;AAAA,IACtC;AAAA,IACA,SAAS;AAAA,IACT,UAAU,OAAM,cAAa;AAC5B,YAAM,UAAU,MAAM,WAAW;AACjC,aAAO,cAAc,UAAa,cAAc,KAAK,QAAQ,SAAS,QAAQ,OAAO,YAAU,OAAO,cAAc,SAAS,EAAE;AAAA,IAChI;AAAA,IACA,OAAO,OAAO,EAAE,QAAQ,SAAS,IAAI,CAAC,MAAM;AAC3C,UAAI,WAAW,OAAO,aAAa,YAAa,QAAO;AACvD,gBAAU;AACV,UAAI,aAAa,OAAW,UAAS,EAAE,GAAG,QAAQ,GAAG,SAAS;AAAA,WACzD;AACJ,YAAI;AACH,gBAAM,MAAM,MAAM,UAAU,GAAG,QAAQ,YAAY,kCAAkC,IAAI,EAAE,OAAO,WAAW,CAAC;AAC9G,gBAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,mBAAS,EAAE,GAAG,QAAQ,GAAI,KAAK,UAAU,cAAc,CAAC,EAAG;AAAA,QAC5D,QAAQ;AAAA,QAAsB;AAAA,MAC/B;AACA,YAAM,UAAU,WAAS;AACxB,YAAI,MAAM,WAAW,MAAM,KAAM;AACjC,aAAK,OAAO,eAAe,GAAG,WAAW,KAAK,CAAC,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AAAA,MAChE;AACA,eAAS,iBAAiB,SAAS,SAAS,IAAI;AAChD,eAAS,iBAAiB,QAAQ,SAAS,IAAI;AAC/C,eAAS,iBAAiB,UAAU,WAAS,KAAK,OAAO,eAAe,GAAG,gBAAgB,KAAK,CAAC,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC,GAAG,IAAI;AACxH,iBAAW,YAAY;AACvB,WAAK,MAAM,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC;AAC3B,UAAI,QAAQ,qBAAqB;AACjC,aAAO;AAAA,IACR;AAAA,IACA,MAAM,MAAM;AAAE,UAAI,SAAS;AAAE,kBAAU;AAAO,mBAAW;AAAG,mBAAW;AAAA,MAAM;AAAA,IAAE;AAAA,IAC/E,WAAW,UAAQ;AAClB,eAAS,EAAE,GAAG,QAAQ,GAAG,KAAK;AAC9B,UAAI,OAAO,YAAY,MAAO,OAAM,YAAY;AAAE,mBAAW,UAAU,MAAM,WAAW,EAAG,OAAM,WAAW,OAAO,GAAG;AAAG,eAAO,sFAAgB;AAAA,MAAG,GAAG;AAAA,IACvJ;AAAA,IACA;AAAA,IACA;AAAA;AAAA,IAEA,QAAQ,OAAO,YAAY,eAAe,GAAG,SAAS,WAAW,cAAc,WAAW,MAAM;AAAA,IAChG;AAAA,IACA;AAAA,EACD;AACD;;;AFjQG;AArHH,IAAM,gBAAgB,gBAAI;AAGnB,IAAM,OAAO;AAKb,IAAM,SAAS,CAAC,SAAS,QAAQ;AACjC,IAAM,KAAK;AAClB,IAAM,WAAW,gBAAgB,EAAE;AAEnC,IAAI;AACJ,IAAI;AACJ,IAAM,QAAQ,EAAE,OAAO,MAAM,OAAO,IAAI,WAAW,oBAAI,IAAI,EAAE;AAE7D,eAAe,aAAa,KAAK;AAChC,MAAI;AACJ,MAAI;AAAE,WAAO,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC;AAAA,EAAG,QACrC;AAAE,UAAM,IAAI,MAAM,wDAAgB,IAAI,MAAM,sFAAgB;AAAA,EAAG;AACrE,MAAI,SAAS,QAAQ,OAAO,SAAS,YAAY,MAAM,QAAQ,IAAI,EAAG,OAAM,IAAI,MAAM,oEAAa;AACnG,MAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,KAAK,SAAS,sCAAa,IAAI,MAAM,QAAG;AACrE,SAAO;AACR;AAGO,IAAI,aAAa;AACxB,eAAsB,YAAY;AACjC,MAAI;AACH,UAAM,OAAO,MAAM,aAAa,MAAM,MAAM,UAAU,EAAE,OAAO,WAAW,CAAC,CAAC;AAC5E,UAAM,QAAQ;AAAM,UAAM,QAAQ;AAAI,iBAAa,KAAK,OAAO;AAAA,EAChE,SAAS,OAAO;AAAE,UAAM,QAAQ,MAAM;AAAA,EAAS;AAC/C,aAAW,YAAY,MAAM,UAAW,UAAS;AACjD,SAAO,MAAM;AACd;AACA,eAAsB,SAAS,OAAO;AACrC,MAAI,CAAC,WAAY,OAAM,UAAU;AACjC,QAAM,MAAM,MAAM,aAAa,MAAM,MAAM,UAAU;AAAA,IACpD,QAAQ;AAAA,IAAQ,OAAO;AAAA,IACvB,SAAS,EAAE,gBAAgB,oBAAoB,yBAAyB,WAAW;AAAA,IACnF,MAAM,KAAK,UAAU,KAAK;AAAA,EAC3B,CAAC,CAAC;AACF,eAAa,IAAI,OAAO;AACxB,aAAW,YAAY,MAAM,UAAW,UAAS;AACjD,SAAO;AACR;AAEO,SAAS,MAAM,KAAK;AAC1B,oBAAkB,IAAI,MAAM,iBAAiB;AAC7C,QAAM,gBAAgB,UAAU,YAAY;AAAA,IAC3C,UAAU;AAAA,IACV,KAAK,CAAC,OAAO,YAAY;AAAE,UAAI;AAAE,SAAC,UAAU,UAAU,QAAQ,OAAO,QAAQ,KAAK,IAAI,EAAE,KAAK,OAAO;AAAA,MAAG,QAAQ;AAAA,MAAC;AAAA,IAAE;AAAA,EACnH,CAAC;AACD,OAAK,UAAU;AACf,QAAM,QAAQ,YAAY,MAAM,KAAK,UAAU,GAAG,GAAK;AACvD,MAAI,SAAS,MAAM,MAAM,cAAc,KAAK,CAAC;AAC7C,gBAAc,GAAG,UAAU,MAAM,KAAK,UAAU,CAAC;AACjD,OAAK,cAAc,MAAM;AAIzB,MAAI,OAAO,MAAM,IAAI,OAAO,SAAS,IAAI;AAAA,IACxC,IAAI,EAAE,aAAa,oDAAY,cAAc,uCAAS;AAAA,IACtD,IAAI,EAAE,aAAa,iCAA4B,cAAc,UAAU;AAAA,EACxE,CAAC,GAAG,+BAA+B;AAGnC,MAAI,MAAM,OAAO,yBAAyB,MAAM,IAAI,MAAM,SAAS,EAAE,MAAM,yBAAyB,KAAK,GAAG,GAAG,OAAO,CAAC;AAEvH,MAAI,MAAM,OAAO,wCAAwC,MAAM,IAAI,MAAM,SAAS,EAAE,MAAM,wCAAwC,IAAI,wBAAwB,OAAO,KAAK,QAAQ,GAAG,GAAG,mBAAmB,CAAC;AAC5M,MAAI,MAAM,OAAO,wCAAwC,MAAM,IAAI,MAAM,SAAS,EAAE,MAAM,wCAAwC,IAAI,yBAAyB,OAAO,KAAK,QAAQ,GAAG,GAAG,oBAAoB,CAAC;AAE9M,MAAI,MAAM,OAAO,2BAA2B,MAAM,IAAI,MAAM,SAAS,EAAE,MAAM,2BAA2B,IAAI,+BAA+B,OAAO,GAAG,QAAQ,GAAG,GAAG,UAAU,CAAC;AAC/K;AAEA,SAAS,SAAS;AACjB,QAAM,CAAC,EAAE,IAAI,QAAI,uBAAS,CAAC;AAC3B,8BAAU,MAAM;AACf,UAAM,WAAW,MAAM,KAAK,OAAK,IAAI,CAAC;AACtC,UAAM,UAAU,IAAI,QAAQ;AAC5B,SAAK,UAAU;AACf,WAAO,MAAM,MAAM,UAAU,OAAO,QAAQ;AAAA,EAC7C,GAAG,CAAC,CAAC;AACL,SAAO;AACR;AAEA,IAAM,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkBR,SAAS,UAAU;AACzB,QAAM,EAAE,OAAO,MAAM,IAAI,OAAO;AAChC,QAAM,CAAC,MAAMC,QAAO,QAAI,uBAAS,KAAK;AACtC,QAAM,CAAC,UAAU,WAAW,QAAI,uBAAS,EAAE;AAC3C,QAAM,MAAM,aAAW;AAAE,gBAAY,OAAO;AAAG,eAAW,MAAM,YAAY,EAAE,GAAG,GAAI;AAAA,EAAG;AACxF,QAAM,MAAM,OAAO,OAAO,OAAO;AAChC,IAAAA,SAAQ,IAAI;AACZ,QAAI;AAAE,YAAM,SAAS,MAAM,SAAS,KAAK;AAAG,UAAI,GAAI,KAAI,EAAE;AAAG,YAAM,UAAU;AAAG,MAAAA,SAAQ,KAAK;AAAG,aAAO;AAAA,IAAQ,SACxG,KAAK;AAAE,UAAI,qBAAM,IAAI,OAAO,EAAE;AAAG,MAAAA,SAAQ,KAAK;AAAG,YAAM;AAAA,IAAK;AAAA,EACpE;AACA,QAAM,WAAW,OAAO;AACxB,SACC,6CAAC,SAAI,WAAU,MACd;AAAA,gDAAC,WAAO,kBAAO;AAAA,IACf,4CAAC,QAAG,4CAAK;AAAA,IACT,6CAAC,OAAE,WAAU,SAAQ;AAAA;AAAA,MAAyB;AAAA,MAAc;AAAA,OAAiD;AAAA,IAC5G,QAAQ,6CAAC,OAAE,WAAU,SAAQ;AAAA;AAAA,MAAQ;AAAA,OAAM,IAAO;AAAA,IAClD,WAAW,4CAAC,OAAE,WAAU,QAAQ,oBAAS,IAAO;AAAA,IACjD,6CAAC,aAAQ,WAAU,OAClB;AAAA,kDAAC,QAAG,kGAAc;AAAA,MACjB,WACA,4EACC;AAAA,qDAAC,SAAI,WAAU,OACd;AAAA,uDAAC,WAAM,WAAU,OAAM;AAAA;AAAA,cAAC;AAAA;AAAA,gBAAM,MAAK;AAAA,gBAAW,SAAS,SAAS,YAAY,YAAY;AAAA,gBAAO,UAAU;AAAA,gBACxG,UAAU,OAAK,KAAK,IAAI,EAAE,MAAM,mBAAmB,OAAO,EAAE,YAAY,EAAE,GAAG,SAAS,YAAY,SAAS,EAAE,OAAO,QAAQ,EAAE,EAAE,GAAG,EAAE,OAAO,UAAU,qDAAa,8GAAoB,EAAE,MAAM,MAAM;AAAA,gBAAC,CAAC;AAAA;AAAA,YAAG;AAAA,YAAE;AAAA,aAAG;AAAA,UAChN,6CAAC,UAAK,WAAU,QAAO;AAAA;AAAA,YAAI,KAAK,OAAO,SAAS,YAAY,gBAAgB,KAAK,OAAO;AAAA,YAAE;AAAA,aAAG;AAAA,UAC7F,6CAAC,UAAK,WAAU,QAAO;AAAA;AAAA,YAAI,SAAS,YAAY,WAAW;AAAA,YAAE;AAAA,aAAE;AAAA,WAChE;AAAA,QACA,4CAAC,SAAI,WAAU,OACd,uDAAC,UAAK,WAAU,SAAQ;AAAA;AAAA,UAAQ,OAAO,OAAO,WAAW;AAAA,UAAE;AAAA,UAAQ,SAAS,OAAO,OAAO,SAAS,CAAC;AAAA,UAAE;AAAA,WAAoC,GAC3I;AAAA,QACC,OAAO,OAAO,SAAS,4CAAC,OAAE,WAAU,SAAS,gBAAM,MAAM,QAAO,IAAO;AAAA,QACxE,4CAAC,SAAI,WAAU,OAAM,sDAAC,YAAO,UAAU,MAAM,SAAS,MAAM,KAAK,IAAI,EAAE,MAAM,cAAc,GAAG,2CAAa,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC,GAAG,sCAAI,GAAS;AAAA,SAC5I,IACG,4CAAC,OAAE,WAAU,SAAQ,wDAAO;AAAA,OACjC;AAAA,IACA,4CAAC,eAAY,KAAU,MAAY,KAAU,OAAc;AAAA,IAC3D,4CAAC,gBAAa,KAAU,MAAY,KAAU,OAAc;AAAA,KAC7D;AAEF;AAEA,SAAS,YAAY,EAAE,KAAK,MAAM,KAAK,MAAM,GAAG;AAC/C,QAAM,CAAC,WAAW,YAAY,QAAI,uBAAS,EAAE;AAC7C,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAS,EAAE;AACrC,QAAM,CAAC,cAAc,eAAe,QAAI,uBAAS,KAAK;AACtD,QAAM,CAAC,MAAM,OAAO,QAAI,uBAAS,IAAI;AACrC,QAAM,UAAU,OAAO;AAEvB,QAAM,WAAW,OAAO,YAAY,CAAC;AAErC,QAAM,CAAC,aAAa,cAAc,QAAI,uBAAS,IAAI;AACnD,8BAAU,MAAM;AACf,QAAI,CAAC,WAAW;AAAE,qBAAe,IAAI;AAAG;AAAA,IAAQ;AAChD,QAAI,QAAQ;AACZ,SAAK,SAAS,EAAE,MAAM,cAAc,UAAU,CAAC,EAC7C,KAAK,YAAU;AAAE,UAAI,MAAO,gBAAe,QAAQ,WAAW,IAAI;AAAA,IAAG,CAAC,EACtE,MAAM,MAAM;AAAE,UAAI,MAAO,gBAAe,IAAI;AAAA,IAAG,CAAC;AAClD,WAAO,MAAM;AAAE,cAAQ;AAAA,IAAO;AAAA,EAC/B,GAAG,CAAC,SAAS,CAAC;AACd,QAAM,OAAO,YAAY;AACxB,QAAI;AACH,YAAM,SAAS,MAAM,iBAAiB,OAAO;AAC7C,YAAM,QAAQ,QAAQ,KAAK,OAAO,QAAQ;AAC1C,UAAI,OAAO,UAAU,YAAY,MAAO,UAAS,KAAK;AAAA,UACjD,KAAI,mKAAiC;AAAA,IAC3C,SAAS,OAAO;AAAE,UAAI,6CAAU,MAAM,OAAO,EAAE;AAAA,IAAG;AAAA,EACnD;AACA,SACC,6CAAC,aAAQ,WAAU,OAClB;AAAA,gDAAC,QAAG,kDAAM;AAAA,IACT,WAAW,6CAAC,OAAE,WAAU,SAAQ;AAAA;AAAA,MAAU,QAAQ;AAAA,MAAU;AAAA,MAAI,QAAQ;AAAA,MAAM;AAAA,MAAM,QAAQ,MAAM,KAAK,GAAG,KAAK;AAAA,MAAI;AAAA,MACnH,4CAAC,YAAO,UAAU,MAAM,SAAS,MAAM,KAAK,IAAI,EAAE,MAAM,gBAAgB,GAAG,4CAAS,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC,GAAG,0BAAE;AAAA,MACxG;AAAA,MAAI,4CAAC,YAAO,UAAU,MAAM,SAAS,MAAM,KAAK,IAAI,EAAE,MAAM,gBAAgB,GAAG,gCAAO,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC,GAAG,0BAAE;AAAA,OAAS;AAAA,IACtH,6CAAC,SAAI,WAAU,OACd;AAAA,kDAAC,WAAM,WAAU,aAAY,aAAY,0FAAwB,OAAO,WAAW,UAAU,OAAK;AAAE,qBAAa,EAAE,OAAO,KAAK;AAAG,gBAAQ,IAAI;AAAA,MAAG,GAAG;AAAA,MACnJ,SAAS,SAAS,KAClB;AAAA,QAAC;AAAA;AAAA,UAAO,WAAU;AAAA,UAAO,OAAO,SAAS,KAAK,OAAK,EAAE,SAAS,KAAK,IAAI,QAAQ;AAAA,UAC9E,UAAU,OAAK;AAAE,qBAAS,EAAE,OAAO,KAAK;AAAG,oBAAQ,IAAI;AAAA,UAAG;AAAA,UAC1D;AAAA,wDAAC,YAAO,OAAM,IAAG,wDAAO;AAAA,YACvB,SAAS,IAAI,aACb,6CAAC,YAAwB,OAAO,QAAQ,MAAM,UAAU,aAAa,SAAS,QAAQ,MACpF;AAAA,sBAAQ;AAAA,cAAM;AAAA,cAAE,QAAQ;AAAA,cAAS;AAAA,cAAM,aAAa,SAAS,QAAQ,OAAO,qCAAY;AAAA,iBAD7E,QAAQ,EAErB,CACA;AAAA;AAAA;AAAA,MACF;AAAA,MAED,4CAAC,WAAM,WAAU,aAAY,aAAY,oDAAW,OAAO,OAAO,UAAU,OAAK;AAAE,iBAAS,EAAE,OAAO,KAAK;AAAG,gBAAQ,IAAI;AAAA,MAAG,GAAG;AAAA,MAC/H,4CAAC,YAAO,SAAS,MAAM,KAAK,KAAK,GAAG,UAAU,MAAM,gCAAG;AAAA,OACxD;AAAA,IACC,aACA,6CAAC,OAAE,WAAU,SAAQ;AAAA;AAAA,MACd,gBAAgB,OAAO,iHAC1B,4EAAE;AAAA,oDAAC,YAAQ,sBAAY,OAAM;AAAA,QAAU;AAAA,QAAI,4CAAC,UAAK,WAAU,QAAQ,sBAAY,MAAK;AAAA,SAAO;AAAA,OAC/F;AAAA,IAED,6CAAC,WAAM,WAAU,OAAM;AAAA,kDAAC,WAAM,MAAK,YAAW,SAAS,cAAc,UAAU,OAAK,gBAAgB,EAAE,OAAO,OAAO,GAAG;AAAA,MAAE;AAAA,OAAS;AAAA,IAClI,6CAAC,SAAI,WAAU,OACd;AAAA,kDAAC,YAAO,UAAU,QAAQ,CAAC,aAAa,CAAC,OAAO,SAAS,MAAM;AAAE,gBAAQ,IAAI;AAAG,gBAAQ,IAAI;AAAG,aAAK,SAAS,EAAE,MAAM,aAAa,WAAW,OAAO,aAAa,CAAC,EAChK,KAAK,YAAU,QAAQ,MAAM,CAAC,EAAE,MAAM,WAAS,IAAI,iCAAQ,MAAM,OAAO,EAAE,CAAC,EAAE,QAAQ,MAAM,QAAQ,KAAK,CAAC;AAAA,MAAG,GAAG,0BAAE;AAAA,MACnH,4CAAC,YAAO,WAAU,WAAU,UAAU,QAAQ,MAAM,cAAc,QAAW,SAAS,MAAM,KAAK,IAAI,EAAE,MAAM,QAAQ,WAAW,OAAO,aAAa,GAAG,4FAAiB,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC,GAAG,0BAAE;AAAA,OAC9L;AAAA,IACC,MAAM,aACN,4CAAC,SAAI,WAAU,cAAa,OAAO,EAAE,YAAY,WAAW,GAAI,eAAK,UAAU,EAAE,QAAG,KAAK,SAAS,QAAG,KAAK,OAAO,oBAAK,KAAK,aAAa,oBAAK,KAAK,WAAW,0BAAM,KAAK,QAAQ,GAAG,MAAM,CAAC,GAAE;AAAA,IAE7L,4CAAC,OAAE,WAAU,SAAQ,mTAAqD;AAAA,KAC3E;AAEF;AAEA,SAAS,aAAa,EAAE,KAAK,MAAM,KAAK,MAAM,GAAG;AAChD,QAAM,QAAQ,OAAO,SAAS,CAAC;AAC/B,SACC,6CAAC,aAAQ,WAAU,OAClB;AAAA,gDAAC,QAAG,gCAAG;AAAA,IACP,6CAAC,OAAE,WAAU,SAAQ;AAAA;AAAA,MACC,4CAAC,OAAE,0BAAE;AAAA,MAAI;AAAA,MAAuD,4CAAC,OAAE,kGAAc;AAAA,MAAI;AAAA,OAE3G;AAAA,IACC,MAAM,WAAW,IAAI,4CAAC,OAAE,WAAU,SAAQ,gCAAG,IAC7C,6CAAC,WACA;AAAA,kDAAC,WAAM,uDAAC,QAAG;AAAA,oDAAC,QAAG,0BAAE;AAAA,QAAK,4CAAC,QAAG,0BAAE;AAAA,QAAK,4CAAC,QAAG,yCAAO;AAAA,QAAK,4CAAC,QAAG,sCAAI;AAAA,QAAK,4CAAC,QAAG;AAAA,SAAE,GAAK;AAAA,MACzE,4CAAC,WAAO,gBAAM,IAAI,UACjB,6CAAC,QACA;AAAA,oDAAC,QAAI,eAAK,SAAS,YAAY,iBAAO,gBAAK;AAAA,QAC3C,4CAAC,QAAG,WAAU,QAAQ,kBAAQ,KAAK,QAAQ,GAAE;AAAA,QAC7C,4CAAC,QAAG,WAAU,QAAQ,eAAK,SAAS,YAAY,KAAK,SAAS,SAAS,mCAAU,KAAK,SAAS,MAAK;AAAA,QACpG,4CAAC,QAAI,cAAI,KAAK,KAAK,SAAS,EAAE,eAAe,SAAS,EAAE,QAAQ,MAAM,CAAC,GAAE;AAAA,QACzE,6CAAC,QAAG,WAAU,OACb;AAAA,sDAAC,YAAO,UAAU,MAAM,SAAS,MAAM,KAAK,IAAI,EAAE,MAAM,iBAAiB,QAAQ,KAAK,OAAO,GAAG,sCAAQ,EAAE,MAAM,MAAM;AAAA,UAAC,CAAC,GAAG,0BAAE;AAAA,UAC7H,4CAAC,YAAO,UAAU,MAAM,SAAS,MAAM,KAAK,IAAI,EAAE,MAAM,eAAe,QAAQ,KAAK,OAAO,GAAG,gCAAO,EAAE,MAAM,MAAM;AAAA,UAAC,CAAC,GAAG,sCAAI;AAAA,WAC7H;AAAA,WARQ,KAAK,MASd,CAAM,GACP;AAAA,OACD;AAAA,IAED,6CAAC,SAAI,WAAU,OACd;AAAA,mDAAC,UAAK,WAAU,SAAQ;AAAA;AAAA,QAAI,OAAO,UAAU,OAAO,WAAW;AAAA,QAAG;AAAA,QAAU,OAAO,UAAU,OAAO,YAAY,6BAAS;AAAA,QAAW;AAAA,SAAC;AAAA,MACrI,4CAAC,YAAO,UAAU,MAAM,SAAS,MAAM,KAAK,IAAI,EAAE,MAAM,mBAAmB,OAAO,EAAE,OAAO,EAAE,GAAG,OAAO,UAAU,OAAO,WAAW,CAAE,OAAO,UAAU,OAAO,UAAW,EAAE,EAAE,GAAG,gCAAO,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC,GAAG,kDAAM;AAAA,MAC/M,4CAAC,YAAO,UAAU,MAAM,SAAS,MAAM,KAAK,IAAI,EAAE,MAAM,cAAc,GAAG,+BAAW,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC,GAAG,4CAAK;AAAA,OAC7G;AAAA,KACD;AAEF;AAEA,IAAM,UAAU,QAAM,OAAO,EAAE,EAAE,SAAS,KAAK,GAAG,OAAO,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC,SAAI,OAAO,EAAE,EAAE,MAAM,EAAE,CAAC,KAAK,OAAO,EAAE;AAC9G,IAAM,WAAW,OAAK,KAAK,UAAU,IAAI,IAAI,SAAS,QAAQ,CAAC,CAAC,QAAQ,KAAK,OAAO,IAAI,IAAI,MAAM,QAAQ,CAAC,CAAC,QAAQ,GAAG,CAAC;AAGjH,SAAS,oBAAoB,EAAE,WAAW,EAAE,GAAG;AACrD,QAAM,CAAC,MAAM,OAAO,QAAI,uBAAS,KAAK;AACtC,SACC,4EACC;AAAA,gDAAC,YAAO,MAAK,YAAW,SAAS,MAAM,QAAQ,IAAI,GAAG,OAAO,eAAgB,cAAI,EAAE,WAAW,IAAI,oDAAW;AAAA,IAC5G,OAAO,4CAAC,cAAW,WAAsB,OAAO,MAAM,QAAQ,KAAK,GAAG,IAAK;AAAA,KAC7E;AAEF;AAEO,SAAS,qBAAqB,EAAE,WAAW,EAAE,GAAG;AACtD,QAAM,CAAC,SAAS,UAAU,QAAI,uBAAS,KAAK;AAC5C,QAAM,CAAC,MAAMA,QAAO,QAAI,uBAAS,KAAK;AACtC,MAAI,SAAS;AACZ,WAAO,4CAAC,YAAO,MAAK,YAAW,UAAU,MAAM,OAAO,eAAe,SAAS,YAAY;AACzF,MAAAA,SAAQ,IAAI;AACZ,UAAI;AAAE,cAAM,SAAS,EAAE,MAAM,iBAAiB,UAAU,CAAC;AAAG,mBAAW,KAAK;AAAA,MAAG,QACzE;AAAE,eAAO,0BAAM;AAAG,mBAAW,KAAK;AAAA,MAAG;AAC3C,MAAAA,SAAQ,KAAK;AAAA,IACd,GAAG,wGAAe;AAAA,EACnB;AACA,SAAO,4CAAC,YAAO,MAAK,YAAW,OAAO,eAAe,SAAS,MAAM,WAAW,IAAI,GAAI,cAAI,EAAE,YAAY,IAAI,wCAAS;AACvH;AACA,SAAS,OAAO,SAAS;AAAE,QAAM,QAAQ;AAAS,aAAW,YAAY,MAAM,UAAW,UAAS;AAAG;AAEtG,IAAM,gBAAgB,EAAE,YAAY,eAAe,QAAQ,QAAQ,OAAO,WAAW,MAAM,WAAW,SAAS,YAAY,WAAW,QAAQ,QAAQ,WAAW,OAAO,OAAO;AAExK,SAAS,WAAW,EAAE,WAAW,MAAM,GAAG;AAChD,QAAM,UAAM,qBAAO,IAAI;AACvB,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAS,EAAE;AACrC,QAAM,CAAC,cAAc,eAAe,QAAI,uBAAS,KAAK;AACtD,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAS,EAAE;AACrC,QAAM,CAAC,MAAMA,QAAO,QAAI,uBAAS,KAAK;AAGtC,QAAM,CAAC,UAAU,WAAW,QAAI,uBAAS,CAAC,CAAC;AAC3C,QAAM,CAAC,aAAa,cAAc,QAAI,uBAAS,IAAI;AACnD,8BAAU,MAAM;AAAE,UAAM,SAAS,IAAI;AAAS,YAAQ,UAAU;AAAG,WAAO,MAAM;AAAE,UAAI;AAAE,gBAAQ,MAAM;AAAA,MAAG,QAAQ;AAAA,MAAC;AAAA,IAAE;AAAA,EAAG,GAAG,CAAC,CAAC;AAC5H,8BAAU,MAAM;AACf,QAAI,QAAQ;AACZ,SAAK,UAAU,EAAE,KAAK,UAAQ;AAAE,UAAI,MAAO,aAAY,MAAM,YAAY,CAAC,CAAC;AAAA,IAAG,CAAC,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAC/F,SAAK,SAAS,EAAE,MAAM,cAAc,UAAU,CAAC,EAC7C,KAAK,YAAU;AAAE,UAAI,MAAO,gBAAe,QAAQ,WAAW,IAAI;AAAA,IAAG,CAAC,EACtE,MAAM,MAAM;AAAE,UAAI,MAAO,gBAAe,IAAI;AAAA,IAAG,CAAC;AAClD,WAAO,MAAM;AAAE,cAAQ;AAAA,IAAO;AAAA,EAC/B,GAAG,CAAC,SAAS,CAAC;AACd,QAAM,SAAS,YAAY;AAC1B,IAAAA,SAAQ,IAAI;AAAG,aAAS,EAAE;AAC1B,QAAI;AAAE,YAAM,SAAS,EAAE,MAAM,QAAQ,WAAW,OAAO,aAAa,CAAC;AAAG,YAAM;AAAA,IAAG,SAC1E,KAAK;AAAE,eAAS,IAAI,OAAO;AAAG,MAAAA,SAAQ,KAAK;AAAA,IAAG;AAAA,EACtD;AACA,QAAM,QAAQ,sBAAsB,KAAK,KAAK;AAC9C,SACC,6CAAC,SAAI,WAAU,MAAK;AAAA,gDAAC,WAAO,kBAAO;AAAA,IAClC,6CAAC,YAAO,KAAU,UAAU,OAAK;AAAE,QAAE,eAAe;AAAG,UAAI,CAAC,KAAM,OAAM;AAAA,IAAG,GAC1E;AAAA,mDAAC,SAAI,WAAU,cAAa;AAAA,oDAAC,YAAO,oEAAS;AAAA,QAAS,4CAAC,YAAO,SAAS,OAAO,UAAU,MAAM,0BAAE;AAAA,SAAS;AAAA,MACzG,6CAAC,SAAI,WAAU,cACd;AAAA,oDAAC,OAAE,WAAU,cAAc,qBAAU;AAAA,QACrC,6CAAC,OAAE,WAAU,SAAQ;AAAA;AAAA,UACd,gBAAgB,OAAO,yFAC3B,4EAAE;AAAA,wDAAC,YAAQ,sBAAY,OAAM;AAAA,YAAU;AAAA,YAAI,4CAAC,UAAK,WAAU,QAAQ,sBAAY,MAAK;AAAA,aAAO;AAAA,WAC9F;AAAA,QACC,SAAS,SAAS,KAClB;AAAA,UAAC;AAAA;AAAA,YAAO,WAAU;AAAA,YAAO,OAAO,SAAS,KAAK,OAAK,EAAE,SAAS,KAAK,IAAI,QAAQ;AAAA,YAC9E,UAAU,OAAK,SAAS,EAAE,OAAO,KAAK;AAAA,YACtC;AAAA,0DAAC,YAAO,OAAM,IAAG,wDAAO;AAAA,cACvB,SAAS,IAAI,aACb,6CAAC,YAAwB,OAAO,QAAQ,MAAM,UAAU,aAAa,SAAS,QAAQ,MACpF;AAAA,wBAAQ;AAAA,gBAAM;AAAA,gBAAE,QAAQ;AAAA,gBAAS;AAAA,gBAAM,aAAa,SAAS,QAAQ,OAAO,qCAAY;AAAA,mBAD7E,QAAQ,EAErB,CACA;AAAA;AAAA;AAAA,QACF;AAAA,QAED,4CAAC,WAAM,WAAU,aAAY,aAAY,oDAAW,OAAO,OAAO,UAAU,OAAK,SAAS,EAAE,OAAO,KAAK,GAAG;AAAA,QAC3G,6CAAC,WAAM,WAAU,OAAM;AAAA,sDAAC,WAAM,MAAK,YAAW,SAAS,cAAc,UAAU,OAAK,gBAAgB,EAAE,OAAO,OAAO,GAAG;AAAA,UAAE;AAAA,WAAS;AAAA,QACjI,QAAQ,4CAAC,OAAE,WAAU,SAAS,iBAAM,IAAO;AAAA,QAC5C,6CAAC,SAAI,WAAU,OAAM;AAAA,sDAAC,YAAO,WAAU,WAAU,UAAU,QAAQ,CAAC,OAAO,SAAS,MAAM,KAAK,OAAO,GAAG,4CAAK;AAAA,UAC7G,4CAAC,UAAK,WAAU,SAAQ,8GAAgB;AAAA,WAAO;AAAA,SACjD;AAAA,OACD;AAAA,KACD;AAEF;AAGO,SAAS,WAAW,EAAE,UAAU,GAAG;AACzC,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAS,CAAC;AACpC,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAAS,EAAE;AACvC,8BAAU,MAAM;AACf,QAAI,UAAU,OAAW;AACzB,QAAI,OAAO;AACX,UAAM,OAAO,YAAY;AACxB,UAAI;AAAE,cAAM,QAAQ,MAAM,MAAM,SAAS,aAAa,MAAM,eAAe,CAAC;AAAG,YAAI,KAAM,UAAS,KAAK;AAAA,MAAG,QACpG;AAAE,YAAI,KAAM,UAAS,CAAC;AAAA,MAAG;AAC/B,UAAI,KAAM,WAAU,MAAM,cAAc,EAAE;AAAA,IAC3C;AACA,SAAK,KAAK;AACV,UAAM,WAAW,MAAM,KAAK,KAAK;AACjC,UAAM,GAAG,UAAU,QAAQ;AAC3B,WAAO,iBAAiB,GAAG,EAAE,WAAW,QAAQ;AAChD,UAAM,QAAQ,YAAY,UAAU,GAAK;AACzC,WAAO,MAAM;AAAE,aAAO;AAAO,YAAM,IAAI,UAAU,QAAQ;AAAG,aAAO,oBAAoB,GAAG,EAAE,WAAW,QAAQ;AAAG,oBAAc,KAAK;AAAA,IAAG;AAAA,EACzI,GAAG,CAAC,SAAS,CAAC;AACd,MAAI,UAAU,EAAG,QAAO;AACxB,SAAO,4CAAC,UAAK,WAAU,MAAK,uDAAC,UAAK,WAAU,QAAO,OAAO,4BAAQ,KAAK,0IAA4B,SAAS,2BAAO,MAAM,KAAK,EAAE,IAAI;AAAA;AAAA,IAAS;AAAA,KAAM,GAAO;AAC3J;",
6
6
  "names": ["store", "name", "setBusy"]
7
7
  }
@@ -20,7 +20,7 @@ import { resolveDshHome } from "@deepseek-ai/dsh-home-paths";
20
20
  // package.json
21
21
  var package_default = {
22
22
  name: "dsh-session-toolbox",
23
- version: "0.1.10",
23
+ version: "0.1.11",
24
24
  repository: {
25
25
  type: "git",
26
26
  url: "https://github.com/AndroidSix/dsh-session-toolbox.git"
@@ -253,9 +253,25 @@ async function applyInner(ctx, options = {}) {
253
253
  }
254
254
  function hostCapabilities(ctx) {
255
255
  return {
256
+ /**
257
+ * Whether a session is actively working.
258
+ *
259
+ * The old check asked whether `sessions.list()` contained the id, but that
260
+ * list holds every session the host has loaded — a session that is merely
261
+ * open (or was opened at some point) counted as live and blocked every
262
+ * move. The official activity hook is `workspace/session-activity`: a
263
+ * `turn` entry means a turn is in flight (including one waiting on an
264
+ * approval or an answer), which is exactly what must not be relocated.
265
+ */
256
266
  sessionLive: (sessionId) => {
257
- const sessions = ctx.get("sessions");
258
- return sessions ? sessions.list().some((session) => session.header?.id === sessionId) : false;
267
+ try {
268
+ const activities = ctx.waterfall?.("workspace/session-activity", { sessionId }, () => []);
269
+ if (activities === void 0) return false;
270
+ if (typeof activities?.then === "function") return false;
271
+ return Array.isArray(activities) && activities.some((entry) => entry?.kind === "turn");
272
+ } catch {
273
+ return false;
274
+ }
259
275
  },
260
276
  listHeaders: async () => {
261
277
  const persistence = ctx.get("sessionPersistence");
package/lib/host.js CHANGED
@@ -20,7 +20,7 @@ import { resolveDshHome } from "@deepseek-ai/dsh-home-paths";
20
20
  // package.json
21
21
  var package_default = {
22
22
  name: "dsh-session-toolbox",
23
- version: "0.1.10",
23
+ version: "0.1.11",
24
24
  repository: {
25
25
  type: "git",
26
26
  url: "https://github.com/AndroidSix/dsh-session-toolbox.git"
@@ -253,9 +253,25 @@ async function applyInner(ctx, options = {}) {
253
253
  }
254
254
  function hostCapabilities(ctx) {
255
255
  return {
256
+ /**
257
+ * Whether a session is actively working.
258
+ *
259
+ * The old check asked whether `sessions.list()` contained the id, but that
260
+ * list holds every session the host has loaded — a session that is merely
261
+ * open (or was opened at some point) counted as live and blocked every
262
+ * move. The official activity hook is `workspace/session-activity`: a
263
+ * `turn` entry means a turn is in flight (including one waiting on an
264
+ * approval or an answer), which is exactly what must not be relocated.
265
+ */
256
266
  sessionLive: (sessionId) => {
257
- const sessions = ctx.get("sessions");
258
- return sessions ? sessions.list().some((session) => session.header?.id === sessionId) : false;
267
+ try {
268
+ const activities = ctx.waterfall?.("workspace/session-activity", { sessionId }, () => []);
269
+ if (activities === void 0) return false;
270
+ if (typeof activities?.then === "function") return false;
271
+ return Array.isArray(activities) && activities.some((entry) => entry?.kind === "turn");
272
+ } catch {
273
+ return false;
274
+ }
259
275
  },
260
276
  listHeaders: async () => {
261
277
  const persistence = ctx.get("sessionPersistence");
package/lib/index.js CHANGED
@@ -20,7 +20,7 @@ import { resolveDshHome } from "@deepseek-ai/dsh-home-paths";
20
20
  // package.json
21
21
  var package_default = {
22
22
  name: "dsh-session-toolbox",
23
- version: "0.1.10",
23
+ version: "0.1.11",
24
24
  repository: {
25
25
  type: "git",
26
26
  url: "https://github.com/AndroidSix/dsh-session-toolbox.git"
@@ -253,9 +253,25 @@ async function applyInner(ctx, options = {}) {
253
253
  }
254
254
  function hostCapabilities(ctx) {
255
255
  return {
256
+ /**
257
+ * Whether a session is actively working.
258
+ *
259
+ * The old check asked whether `sessions.list()` contained the id, but that
260
+ * list holds every session the host has loaded — a session that is merely
261
+ * open (or was opened at some point) counted as live and blocked every
262
+ * move. The official activity hook is `workspace/session-activity`: a
263
+ * `turn` entry means a turn is in flight (including one waiting on an
264
+ * approval or an answer), which is exactly what must not be relocated.
265
+ */
256
266
  sessionLive: (sessionId) => {
257
- const sessions = ctx.get("sessions");
258
- return sessions ? sessions.list().some((session) => session.header?.id === sessionId) : false;
267
+ try {
268
+ const activities = ctx.waterfall?.("workspace/session-activity", { sessionId }, () => []);
269
+ if (activities === void 0) return false;
270
+ if (typeof activities?.then === "function") return false;
271
+ return Array.isArray(activities) && activities.some((entry) => entry?.kind === "turn");
272
+ } catch {
273
+ return false;
274
+ }
259
275
  },
260
276
  listHeaders: async () => {
261
277
  const persistence = ctx.get("sessionPersistence");
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 { appendFileSync } from 'node:fs';\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\ttry {\n\t\treturn await applyInner(ctx, options);\n\t} catch (error) {\n\t\t// A failing third-party plugin must never take the whole app down.\n\t\t// Record the real stack so the failure is diagnosable, then degrade.\n\t\trecordStartupFailure(error);\n\t\tconst hint = /Cannot find package|ERR_MODULE_NOT_FOUND/.test(String(error?.message ?? error))\n\t\t\t? '\uFF08\u4F9D\u8D56\u7F3A\u5931\uFF1A\u8BF7\u4ECE\u63D2\u4EF6\u9875\u5378\u8F7D\u540E\u91CD\u65B0\u5B89\u88C5\uFF0C\u8BA9\u5305\u7BA1\u7406\u5668\u91CD\u65B0\u62C9\u53D6 peer \u4F9D\u8D56\uFF09'\n\t\t\t: '';\n\t\tctx.logger?.warn?.(`session-toolbox: disabled after startup error${hint} \u2014 ${error?.message ?? error}`);\n\t}\n}\n\n/** Absolute path of the startup-failure log, next to the plugin's other state. */\nfunction startupFailureLog() {\n\ttry {\n\t\treturn join(resolve(resolveDshHome()), 'session-toolbox', 'startup-error.log');\n\t} catch { return ''; }\n}\n\n/** Append a startup failure (with stack) so a failed activation stays diagnosable. */\nfunction recordStartupFailure(error) {\n\tconst file = startupFailureLog();\n\tif (file === '') return;\n\ttry {\n\t\tconst detail = `${new Date().toISOString()}\\n${error?.stack ?? String(error)}\\n\\n`;\n\t\tappendFileSync(file, detail, { mode: 0o600 });\n\t} catch { /* diagnostics must never throw */ }\n}\n\nasync function applyInner(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\t/** All known projects (id/path/title/session count) for the move picker. */\n\tconst listProjects = ctx => {\n\t\tconst registry = ctx.get('workspaceRegistry');\n\t\tif (registry === undefined) return [];\n\t\treturn registry.list().map(row => ({\n\t\t\tid: row.id,\n\t\t\tpath: row.path,\n\t\t\ttitle: row.title ?? row.path,\n\t\t\tsessions: (row.sessionIds ?? []).length,\n\t\t})).sort((a, b) => a.title.localeCompare(b.title));\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\tprojects: listProjects(ctx),\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\t/** The project a session currently belongs to (null when unknown). */\n\t\tprojectOf: async sessionId => {\n\t\t\tif (sessionId === '') return null;\n\t\t\tconst registry = ctx.get('workspaceRegistry');\n\t\t\tif (registry === undefined) return null;\n\t\t\tfor (const row of registry.list()) {\n\t\t\t\tif ((row.sessionIds ?? []).includes(sessionId)) {\n\t\t\t\t\treturn { id: row.id, path: row.path, title: row.title ?? row.path };\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\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.10\",\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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",
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 { appendFileSync } from 'node:fs';\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\ttry {\n\t\treturn await applyInner(ctx, options);\n\t} catch (error) {\n\t\t// A failing third-party plugin must never take the whole app down.\n\t\t// Record the real stack so the failure is diagnosable, then degrade.\n\t\trecordStartupFailure(error);\n\t\tconst hint = /Cannot find package|ERR_MODULE_NOT_FOUND/.test(String(error?.message ?? error))\n\t\t\t? '\uFF08\u4F9D\u8D56\u7F3A\u5931\uFF1A\u8BF7\u4ECE\u63D2\u4EF6\u9875\u5378\u8F7D\u540E\u91CD\u65B0\u5B89\u88C5\uFF0C\u8BA9\u5305\u7BA1\u7406\u5668\u91CD\u65B0\u62C9\u53D6 peer \u4F9D\u8D56\uFF09'\n\t\t\t: '';\n\t\tctx.logger?.warn?.(`session-toolbox: disabled after startup error${hint} \u2014 ${error?.message ?? error}`);\n\t}\n}\n\n/** Absolute path of the startup-failure log, next to the plugin's other state. */\nfunction startupFailureLog() {\n\ttry {\n\t\treturn join(resolve(resolveDshHome()), 'session-toolbox', 'startup-error.log');\n\t} catch { return ''; }\n}\n\n/** Append a startup failure (with stack) so a failed activation stays diagnosable. */\nfunction recordStartupFailure(error) {\n\tconst file = startupFailureLog();\n\tif (file === '') return;\n\ttry {\n\t\tconst detail = `${new Date().toISOString()}\\n${error?.stack ?? String(error)}\\n\\n`;\n\t\tappendFileSync(file, detail, { mode: 0o600 });\n\t} catch { /* diagnostics must never throw */ }\n}\n\nasync function applyInner(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\t/** All known projects (id/path/title/session count) for the move picker. */\n\tconst listProjects = ctx => {\n\t\tconst registry = ctx.get('workspaceRegistry');\n\t\tif (registry === undefined) return [];\n\t\treturn registry.list().map(row => ({\n\t\t\tid: row.id,\n\t\t\tpath: row.path,\n\t\t\ttitle: row.title ?? row.path,\n\t\t\tsessions: (row.sessionIds ?? []).length,\n\t\t})).sort((a, b) => a.title.localeCompare(b.title));\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\tprojects: listProjects(ctx),\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\t/** The project a session currently belongs to (null when unknown). */\n\t\tprojectOf: async sessionId => {\n\t\t\tif (sessionId === '') return null;\n\t\t\tconst registry = ctx.get('workspaceRegistry');\n\t\t\tif (registry === undefined) return null;\n\t\t\tfor (const row of registry.list()) {\n\t\t\t\tif ((row.sessionIds ?? []).includes(sessionId)) {\n\t\t\t\t\treturn { id: row.id, path: row.path, title: row.title ?? row.path };\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\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\t/**\n\t\t * Whether a session is actively working.\n\t\t *\n\t\t * The old check asked whether `sessions.list()` contained the id, but that\n\t\t * list holds every session the host has loaded \u2014 a session that is merely\n\t\t * open (or was opened at some point) counted as live and blocked every\n\t\t * move. The official activity hook is `workspace/session-activity`: a\n\t\t * `turn` entry means a turn is in flight (including one waiting on an\n\t\t * approval or an answer), which is exactly what must not be relocated.\n\t\t */\n\t\tsessionLive: sessionId => {\n\t\t\ttry {\n\t\t\t\tconst activities = ctx.waterfall?.('workspace/session-activity', { sessionId }, () => []);\n\t\t\t\tif (activities === undefined) return false;\n\t\t\t\t// While the waterfall is still resolving it is a thenable; treat an\n\t\t\t\t// unresolved answer as \"not busy\" rather than blocking the move.\n\t\t\t\tif (typeof activities?.then === 'function') return false;\n\t\t\t\treturn Array.isArray(activities) && activities.some(entry => entry?.kind === 'turn');\n\t\t\t} catch {\n\t\t\t\treturn false;\n\t\t\t}\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.11\",\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": ["ctx"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-session-toolbox",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/AndroidSix/dsh-session-toolbox.git"