dsh-sessions-manager 3.5.2 → 3.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +2 -2
- package/README.md +2 -2
- package/lib/client.js +9 -2
- package/lib/client.js.map +2 -2
- package/lib/index.js +132 -119
- package/lib/index.js.map +4 -4
- package/package.json +1 -1
- package/src/client/index.jsx +16 -3
- package/src/compat/persistence.js +2 -0
- package/src/index.js +23 -2
package/lib/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/index.js", "../src/zstd-frame.js", "../src/markdown.js", "../src/star-index.js", "../src/storage-stats.js", "../src/auto-archive.js", "../src/session-meta-cache.js", "../src/title-persist-index.js", "../src/
|
|
4
|
-
"sourcesContent": ["// dsh-sessions-manager \u2014 host half.\n//\n// Serves /archived-sessions/* JSON routes (list / restore / restore-many /\n// delete / delete-many / sessions / workspaces / move) over the host\n// `webServer`. The browser Settings sections (\"\u5F52\u6863\u4F1A\u8BDD\" & \"\u79FB\u52A8\u4F1A\u8BDD\") talk to\n// these. Reads/writes the durable workspace archive set\n// (workspaceRegistry + storageDomain), folds titles/dates/workspace tags from\n// session persistence, physically removes a session's log file on delete, and\n// relocates a conversation (session) between workspaces on move.\nimport { mkdir, readFile, realpath, rename, stat, unlink, writeFile } from 'node:fs/promises'\nimport { basename, dirname, isAbsolute, join } from 'node:path'\nimport { readFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { rewriteFrame0CwdInMemory, scanZstdFrames } from './zstd-frame.js'\nimport { createSessionMarkdownBuilder } from './markdown.js'\nimport { createStarIndex } from './star-index.js'\nimport { aggregateStorage } from './storage-stats.js'\nimport { createAutoArchiveStore, pickInactiveCandidates } from './auto-archive.js'\nimport { createSessionMetaCache, fingerprintOf, isPersistableFingerprint } from './session-meta-cache.js'\nimport { createTitleIndexStore } from './title-persist-index.js'\nimport { createPersistenceAdapter } from './compat/persistence.js'\nimport { detectCapabilities, requireCapability } from './compat/capabilities.js'\nimport { pathOwnsSession } from './path-guard.js'\nimport { purgeSessionArtifacts, moveSessionToCwd } from './handle-era-ops.js'\n\n\nexport const name = 'dsh-sessions-manager'\nexport const inject = ['webServer', 'workspaceRegistry', 'sessionPersistence', 'sessionQuery', 'storageDomain']\n\nconst MAX_TITLE = 80\n// Recycle bin (\u56DE\u6536\u7AD9): normal deletes land here instead of being erased.\nconst TRASH_DIR = process.env.DSH_SESSIONS_MANAGER_TRASH_DIR || join(homedir(), '.dsh', 'sessions-manager-trash')\nconst TRASH_INDEX = join(TRASH_DIR, 'index.json')\nconst TRASH_SCHEMA_VERSION = 2\nconst DEFAULT_TRASH_SETTINGS = Object.freeze({ retentionDays: 0 })\n// -- per-session detail aggregation (v2.0: \u53D6 Zephyr-vibe buildDetails \u7CBE\u534E) --\n// \u8BC6\u522B\u201C\u641C\u7D22/\u6293\u53D6\u201D\u7C7B\u5DE5\u5177\uFF0C\u7528\u6765\u6536\u96C6 fetch \u8BB0\u5F55\u3002\nconst FETCH_TOOL_RE = /search|fetch|download|browse/i\nconst MAX_FETCHES = 12 // fetch \u8BB0\u5F55\u4E0A\u9650\uFF08\u9632\u54CD\u5E94\u8FC7\u5927\uFF09\nconst MAX_FILES = 20 // write/edit \u6587\u4EF6\u5217\u8868\u4E0A\u9650\nconst MAX_STORAGE_TOP = 50 // \u5B58\u50A8\u6392\u884C\u8FD4\u56DE\u4E0A\u9650\uFF08\u9632\u54CD\u5E94\u8FC7\u5927\uFF09\n\nfunction json(res, value, status = 200) {\n res.writeHead(status, { 'content-type': 'application/json; charset=utf-8', 'cache-control': 'no-store' })\n res.end(JSON.stringify(value))\n}\n\nfunction errorStatus(error) {\n return error && Number.isInteger(error.status) ? error.status : 500\n}\n\n// \u6781\u7B80\u5E76\u53D1\u95F8\uFF1A\u6574\u672C\u65E5\u5FD7\u8BFB\u53D6\uFF08\u8BE6\u60C5 / \u5BFC\u51FA\uFF09\u540C\u65F6\u6700\u591A max \u4E2A\u5728\u8DD1\uFF0C\u6392\u961F\u7B49\u5F85\u3002\n// \u9632\u6B62\u6279\u91CF\u5BFC\u51FA\u628A\u5BBF\u4E3B CPU/\u5185\u5B58\u6253\u6EE1\uFF08SessionHandle \u4E16\u4EE3\u9010\u5757\u89E3\u7801\u4ECD\u662F CPU \u6D3B\uFF09\u3002\nfunction createLimiter(max) {\n let active = 0\n const queue = []\n return async function run(fn) {\n if (active >= max) await new Promise((resolve) => queue.push(resolve))\n active++\n try { return await fn() } finally {\n active--\n const next = queue.shift()\n if (next) next()\n }\n }\n}\n\nasync function readJsonBody(req) {\n const chunks = []\n let total = 0\n for await (const chunk of req) {\n chunks.push(chunk)\n total += chunk.length\n if (total > 1 << 20) return null\n }\n try {\n return JSON.parse(Buffer.concat(chunks).toString('utf8'))\n } catch {\n return null\n }\n}\n\nfunction parseIds(body) {\n const raw = body && body.sessionIds\n if (!Array.isArray(raw)) return null\n const ids = []\n for (const v of raw) if (typeof v === 'string' && isSafeSessionId(v)) ids.push(v)\n return ids\n}\n\nfunction isSafeSessionId(value) {\n return typeof value === 'string' && value.length > 0 && value.length <= 200 && !/[\\\\/\\0]/.test(value) && value !== '.' && value !== '..'\n}\n\nfunction requireSessionId(value) {\n if (!isSafeSessionId(value)) {\n const error = new Error('\u65E0\u6548\u7684 sessionId')\n error.status = 400\n throw error\n }\n return value\n}\n\n// Best-effort: figure out which conversation is the host's *currently active*\n// one. DSH's in-memory session store (ctx.sessions) keeps EVERY instantiated\n// session alive even after you switch away in the UI, so \"is it in\n// ctx.sessions\" is NOT the same as \"is it the active conversation\". We probe a\n// few known accessors for the active id; if none is available we return null\n// and callers should treat the session as movable (the move path is\n// crash-safe via backup+rollback and re-syncs the live object afterwards).\nfunction getActiveSessionId(context) {\n try {\n const a = context.get('activeSession')\n if (a != null) return (a && a.id != null) ? a.id : (typeof a === 'string' ? a : null)\n } catch (e) { /* no such key */ }\n try {\n const c = context.get('currentSession')\n if (c != null) return (c && c.id != null) ? c.id : (typeof c === 'string' ? c : null)\n } catch (e) { /* no such key */ }\n try {\n const store = context.get('sessions')\n if (store && store.active && store.active.id != null) return store.active.id\n } catch (e) { /* no such key */ }\n return null\n}\n\nfunction foldTitle(events) {\n let found = null\n let firstUser = null\n for (const ev of events) {\n if (ev.type === 'session/title' && ev.data && typeof ev.data.title === 'string' && ev.data.title.length) {\n found = ev.data.title\n }\n if (firstUser === null && ev.type === 'user/message' && ev.data && Array.isArray(ev.data.content)) {\n const txt = ev.data.content.filter((b) => b && b.type === 'text').map((b) => b.text).filter(Boolean).join(' ').trim()\n if (txt) firstUser = txt\n }\n }\n return found || firstUser || null\n}\n\nexport function apply(ctx) {\n const w = ctx.workspaceRegistry\n const sp = ctx.sessionPersistence\n const persistence = createPersistenceAdapter(sp)\n const capabilities = detectCapabilities({ persistence: sp, workspaceRegistry: w })\n const sq = ctx.sessionQuery\n const dom = () => ctx.storageDomain.get('workspace')\n const authorityTitleCache = new Map()\n // \u4F1A\u8BDD\u539F\u59CB\u5143\u6570\u636E\u7F13\u5B58\uFF08title / cwd / createdAt\uFF09\uFF0C\u6309\u65E5\u5FD7\u6587\u4EF6 (mtime, size) \u6307\u7EB9\u6821\u9A8C\u3002\n // \u89C1 src/session-meta-cache.js \u7684\u8BF4\u660E\uFF1A\u5217\u8868\u6784\u5EFA\u539F\u672C\u6BCF\u6761\u4F1A\u8BDD\u90FD\u8981\u6574\u672C\u89E3\u538B\u65E5\u5FD7\uFF0C\n // \u8FD9\u4E2A\u7F13\u5B58\u8BA9\u300C\u65E5\u5FD7\u6CA1\u53D8\u300D\u7684\u4F1A\u8BDD\u76F4\u63A5\u8DF3\u8FC7\u89E3\u7801\u3002\n const metaCache = createSessionMetaCache()\n // \u6301\u4E45\u6807\u9898\u7D22\u5F15\uFF08\u51B7\u542F\u52A8\u52A0\u901F\uFF09\uFF1AmetaCache \u662F\u8FDB\u7A0B\u5185\u7684\uFF0C\u91CD\u542F\u5373\u7A7A\u2014\u2014\u7B2C\u4E00\u6B21\u5217\u8868\n // \u4ECD\u8981\u5168\u5E93\u89E3\u7801\u3002\u7D22\u5F15\u6309\u540C\u6837\u7684 (mtime, size) \u6307\u7EB9\u5B58\u89E3\u7801\u7ED3\u679C\uFF0C\u6307\u7EB9\u6CA1\u53D8\u7684\u4F1A\u8BDD\n // \u91CD\u542F\u540E\u4E5F\u76F4\u63A5\u590D\u7528\u3002\u89C1 src/title-persist-index.js\u3002\n const titleIndex = createTitleIndexStore({ dir: TRASH_DIR, file: join(TRASH_DIR, 'title-index.json') })\n\n // P4\uFF1A\u5BF9\u300C\u5185\u5B58\u7F13\u5B58\u672A\u547D\u4E2D\u300D\u7684\u4F1A\u8BDD\u67E5\u6301\u4E45\u7D22\u5F15\uFF0C\u6307\u7EB9\u4E00\u81F4\u624D\u53EF\u4FE1\u3002\n // \u8FD4\u56DE Map<id, meta>\uFF1B\u8C03\u7528\u65B9\u5E94\u628A\u547D\u4E2D\u6761\u76EE\u56DE\u586B metaCache \u5E76\u4ECE missing \u91CC\u5254\u9664\u3002\n // revision \u6307\u7EB9\uFF08SessionHandle \u4E16\u4EE3\uFF09\u8DF3\u8FC7\u6301\u4E45\u7D22\u5F15\uFF1A\u8DE8\u8FDB\u7A0B\u65E0\u610F\u4E49\u3002\n async function hydrateFromPersist(ids, statsById) {\n const hits = new Map()\n if (!ids || !ids.length) return hits\n let store\n try { store = await titleIndex.entries() } catch (e) { return hits }\n for (const id of ids) {\n const stat = statsById.get(id)\n const entry = store && store[id]\n if (!stat || !entry) continue\n const fp = fingerprintOf(stat)\n if (!isPersistableFingerprint(fp)) continue\n if (fp && entry.fingerprint === fp) {\n hits.set(id, { title: entry.title, cwd: entry.cwd, createdAt: entry.createdAt })\n }\n }\n return hits\n }\n\n // \u628A\u672C\u6279\u771F\u6B63\u89E3\u7801\u51FA\u7684\u5143\u6570\u636E\u5F02\u6B65\u56DE\u5199\u6301\u4E45\u7D22\u5F15\uFF08fire-and-forget\uFF1A\u7D22\u5F15\u53EA\u662F\n // \u52A0\u901F\u5668\uFF0C\u5199\u5931\u8D25\u4E0D\u5F71\u54CD\u54CD\u5E94\uFF0C\u961F\u5217\u5185\u90E8\u5DF2\u4E32\u884C\u5316 + \u539F\u5B50\u66FF\u6362\uFF09\u3002\n // \u26A0\uFE0F revision \u6307\u7EB9\uFF08SessionHandle \u4E16\u4EE3\uFF09\u7EDD\u4E0D\u843D\u76D8\uFF1A\u5B83\u53EA\u5728\u5F53\u524D service\n // \u5B9E\u4F8B\u5185\u6709\u610F\u4E49\uFF0C\u8DE8\u8FDB\u7A0B\u6BD4\u8F83\u65E0\u610F\u4E49\uFF0C\u8BEF\u7528\u4F1A\u628A\u9648\u65E7\u6570\u636E\u5F53\u65B0\u9C9C\u6570\u636E\u3002\n function persistDecoded(decoded, statsById) {\n if (!decoded || !decoded.size) return\n const batch = {}\n const now = Date.now()\n for (const [id, meta] of decoded) {\n const fp = fingerprintOf(statsById.get(id))\n if (!isPersistableFingerprint(fp)) continue\n batch[id] = { title: meta.title, cwd: meta.cwd, createdAt: meta.createdAt, fingerprint: fp, updatedAt: now }\n }\n if (!Object.keys(batch).length) return\n titleIndex.merge(batch).catch(() => {})\n }\n\n // \u4ECE\u6295\u5F71\u5FEB\u7167\u91CC\u62BD\u51FA\u5143\u6570\u636E\uFF1B\u5FEB\u7167\u7F3A\u5931/\u5F02\u5E38\u65F6\u8FD4\u56DE\u96F6\u503C meta\uFF08\u8C03\u7528\u65B9\u51B3\u5B9A\u515C\u5E95\uFF09\u3002\n function metaFromSnapshot(o) {\n let title = null, createdAt = null, cwd = null\n if (o) {\n if (o.title && o.title.title) title = String(o.title.title)\n if (o.session) { cwd = o.session.cwd || null; createdAt = o.session.createdAt || null }\n }\n return { title, cwd, createdAt }\n }\n\n // \u6295\u5F71\u5FEB\u7167\u7684\u4E24\u79CD\u8FD4\u56DE\u5F62\u6001\u90FD\u517C\u5BB9\uFF1A\u65B0\u7248 runtime \u8FD4\u56DE settled \u7ED3\u679C\n // \uFF08{ status: 'fulfilled', value }\uFF09\uFF0C\u8001\u7248\u672C\u76F4\u63A5\u8FD4\u56DE\u5FEB\u7167\u672C\u8EAB\u3002\n function unwrapSnapshot(result) {\n if (!result) return null\n if (result.status === 'fulfilled') return result.value || null\n if (result.status === 'rejected') return null\n return result\n }\n\n async function archivedState() {\n const d = dom()\n if (!d) throw new Error('workspace domain is not open')\n return d.global.get()\n }\n\n async function writeArchived(nextIds) {\n const d = dom()\n if (!d) throw new Error('workspace domain is not open')\n const cur = d.global.get()\n const next = Object.assign({}, cur, { archivedSessionIds: nextIds })\n await d.global.set(next)\n // Keep the registry's in-memory cache in sync so the live sidebar refreshes.\n if (w && 'state' in w) { try { w.state = next } catch (e) { /* best-effort */ } }\n return next\n }\n\n let archiveMutation = Promise.resolve()\n function mutateArchived(mutator) {\n const operation = archiveMutation.then(async () => {\n const state = await archivedState()\n const list = (state.archivedSessionIds || []).map(String)\n const result = await mutator(list)\n if (result.next) await writeArchived(result.next)\n return result.value\n })\n archiveMutation = operation.catch(() => {})\n return operation\n }\n\n let wsByPath = {}\n\n // \u628A\u539F\u59CB\u5143\u6570\u636E\u6E32\u67D3\u6210\u5217\u8868\u9879\u3002\u7F13\u5B58\u547D\u4E2D\u4E0E\u89E3\u7801\u4E24\u6761\u8DEF\u5F84\u5171\u7528\uFF0C\u4FDD\u8BC1\u8F93\u51FA\u4E00\u81F4\u3002\n function buildItem(key, meta, usage, exposeUsage) {\n const cwd = meta.cwd || null\n const ws = cwd ? wsByPath[cwd] : undefined\n const title = meta.title || null\n const display = title ? (String(title).length > MAX_TITLE ? String(title).slice(0, MAX_TITLE) + '\u2026' : String(title)) : null\n const base = {\n sessionId: key,\n title: display,\n createdAt: meta.createdAt || null,\n workspacePath: cwd,\n workspaceTitle: (ws && ws.title) ? ws.title : null,\n workspaceGone: !!(cwd && !ws),\n hasWorkspace: !!cwd,\n }\n // sizeBytes / updatedAt \u53EA\u5728\u9700\u8981\u7684\u8DEF\u7531\uFF08\u5B58\u50A8\u5206\u6790 / \u81EA\u52A8\u5F52\u6863\uFF09\u91CC\u5E26\u4E0A\uFF1A\n // \u5B83\u4EEC\u672C\u5C31\u6765\u81EA usage\uFF0C\u9644\u5E26\u8F93\u51FA\u5BF9\u5217\u8868\u6E32\u67D3\u65E0\u76CA\u3002\n if (exposeUsage && usage) {\n if (usage.sizeById && usage.sizeById.has(key)) base.sizeBytes = usage.sizeById.get(key)\n if (usage.mtimeById && usage.mtimeById.has(key)) base.updatedAt = usage.mtimeById.get(key)\n }\n return base\n }\n\n // Resolve one session's display metadata.\n //\n // \u6210\u672C\u6A21\u578B\uFF08issue #1\uFF09\uFF1A\u4E0B\u9762\u7684\u89E3\u7801\u8DEF\u5F84\u4F1A\u628A\u6574\u672C .jsonl.zstd \u9010\u5E27\u89E3\u538B\u3001\u9010\u884C\n // JSON.parse\uFF0C\u53EA\u4E3A\u6298\u53E0\u51FA\u6807\u9898\u2014\u2014\u5927\u5E93\u4E0A\u4E00\u6B21\u5168\u8868\u8981\u51E0\u79D2\u963B\u585E\u5F0F CPU\u3002\u65E5\u5FD7\u5185\u5BB9\u6CA1\u53D8\n // \u5C31\u610F\u5473\u7740\u6298\u53E0\u7ED3\u679C\u4E0D\u53EF\u80FD\u53D8\uFF08legacy \u7528 (mtime, size) \u6587\u4EF6\u6307\u7EB9\uFF1BSessionHandle\n // \u4E16\u4EE3\u7528\u5B98\u65B9 snapshot.revision\uFF09\uFF0C\u547D\u4E2D\u5373\u76F4\u63A5\u590D\u7528\uFF0C\u8DF3\u8FC7\u6574\u672C\u89E3\u7801\u3002\n //\n // 0.1.3-alpha \u517C\u5BB9\uFF08\u907F\u514D\u653E\u5927\u5B98\u65B9\u5DF2\u77E5\u7684\u5386\u53F2\u4F1A\u8BDD\u52A0\u8F7D\u6027\u80FD\u56DE\u9000\uFF09\uFF1A\n // - cwd/createdAt \u4F18\u5148\u6765\u81EA list() \u5FEB\u7167\u7684 snapshot.header\uFF1B\n // - \u6807\u9898\u4F18\u5148\u6765\u81EA\u6279\u91CF readTitleSnapshots\uFF1B\n // - **\u6807\u9898\u7F3A\u5931\u7EDD\u4E0D\u5355\u72EC\u89E6\u53D1\u6574\u672C\u65E5\u5FD7\u89E3\u7801**\u2014\u2014\u65E0\u6807\u9898\u5C31\u663E\u793A\u300C(\u65E0\u6807\u9898)\u300D\u3002\n // \u53EA\u6709\u5728\u62FF\u4E0D\u5230 cwd\uFF08\u5DE5\u4F5C\u533A\u5F52\u5C5E\u5931\u6548\uFF09\u6216 runtime \u5B8C\u5168\u6CA1\u6709\u6807\u9898\u6295\u5F71\u80FD\u529B\u65F6\n // \u624D\u56DE\u9000\u5230\u65E5\u5FD7\u89E3\u7801\uFF0C\u4E14\u8BE5\u89E3\u7801\u8D70 inspectSession \u5206\u5757\u6298\u53E0\uFF0C\u4E0D\u505A\u6574\u672C\u9A7B\u7559\u3002\n async function resolveOne(id, usage, opts = {}) {\n const key = String(id)\n const statInfo = usage ? (usage.statsById ? usage.statsById.get(key) : null)\n || { mtimeMs: usage.mtimeById && usage.mtimeById.get(key), size: usage.sizeById && usage.sizeById.get(key) } : null\n const cached = metaCache.get(key, statInfo)\n if (cached) return buildItem(key, cached, usage, opts.exposeUsage)\n\n let meta = { title: null, cwd: null, createdAt: null }\n // \u7B2C\u4E00\u6765\u6E90\uFF1Alist() \u8FD4\u56DE\u7684 SessionPersistenceSnapshot.header\uFF080.1.3+ \u5B98\u65B9\n // \u5951\u7EA6\u91CC header \u643A\u5E26 cwd/createdAt\uFF0C\u65E0\u9700\u4EFB\u4F55\u65E5\u5FD7\u8BFB\u53D6\uFF09\u3002\n if (opts.listHeader) {\n if (typeof opts.listHeader.cwd === 'string') meta.cwd = opts.listHeader.cwd\n if (opts.listHeader.createdAt != null) meta.createdAt = opts.listHeader.createdAt\n }\n if (opts.preloaded !== undefined) {\n const projected = metaFromSnapshot(unwrapSnapshot(opts.preloaded))\n if (projected.title) meta.title = projected.title\n if (!meta.cwd && projected.cwd) meta.cwd = projected.cwd\n if (!meta.createdAt && projected.createdAt) meta.createdAt = projected.createdAt\n } else if (typeof sq.readTitleSnapshot === 'function') {\n try {\n const projected = metaFromSnapshot(await sq.readTitleSnapshot(id))\n if (projected.title) meta.title = projected.title\n if (!meta.cwd && projected.cwd) meta.cwd = projected.cwd\n if (!meta.createdAt && projected.createdAt) meta.createdAt = projected.createdAt\n } catch (e) { /* fall through */ }\n }\n // cwd \u7F3A\u5931 \u2192 \u5DE5\u4F5C\u533A\u5F52\u5C5E\u5931\u6548\uFF0C\u503C\u5F97\u4E00\u6B21\u89E3\u7801\u515C\u5E95\uFF08cwd \u5728 header \u91CC\uFF0C\u901A\u5E38\n // \u5FEB\u7167\u5DF2\u5E26\u56DE\uFF0C\u8FD9\u91CC\u53EA\u5728\u5FEB\u7167\u7F3A cwd \u65F6\u53D1\u751F\uFF09\u3002runtime \u5B8C\u5168\u6CA1\u6709\u6807\u9898\u6295\u5F71\u80FD\u529B\n // \u65F6\uFF08\u8001\u540E\u7AEF\u65E0 readTitleSnapshot\uFF09\uFF0C\u89E3\u7801\u540C\u65F6\u515C\u5E95\u6807\u9898\u3002\n const projectionAvailable = typeof sq.readTitleSnapshot === 'function' || typeof sq.readTitleSnapshots === 'function'\n if (!meta.cwd || (!meta.title && !projectionAvailable)) {\n try {\n let foldedTitle = null\n const summary = await persistence.inspectSession(key, {\n onEvents: (events) => { if (!foldedTitle) foldedTitle = foldTitle(events) },\n })\n if (summary && summary.meta) {\n if (!meta.cwd) meta.cwd = summary.meta.cwd || null\n if (!meta.createdAt) meta.createdAt = summary.meta.createdAt || null\n }\n if (!meta.title && foldedTitle) meta.title = foldedTitle\n } catch (e2) { /* keep what we have */ }\n }\n metaCache.set(key, statInfo, meta)\n // \u672C\u6761\u662F\u300C\u771F\u89E3\u7801\u300D\u51FA\u6765\u7684\uFF1A\u4EA4\u7ED9\u8C03\u7528\u65B9\u56DE\u5199\u6301\u4E45\u6807\u9898\u7D22\u5F15\uFF08P4 \u51B7\u542F\u52A8\u52A0\u901F\uFF09\u3002\n if (opts.collectDecoded && statInfo) opts.collectDecoded(key, meta)\n return buildItem(key, meta, usage, opts.exposeUsage)\n }\n\n // Disk usage + last-write time for every session, in one pass. Also produces\n // the per-id change token (`statsById`) that drives the metadata cache:\n // - SessionHandle \u4E16\u4EE3\uFF080.1.3+\uFF09\uFF1A\u516C\u5171\u670D\u52A1\u4E0D\u518D\u66B4\u9732 locate/raw \u8DEF\u5F84\uFF0C\n // snapshot.revision\uFF08list \u4E00\u6B21\u5C31\u5E26\u56DE\uFF09\u5C31\u662F\u5B98\u65B9\u552F\u4E00\u53D8\u66F4\u4EE4\u724C\uFF1B\n // - legacy\uFF1A\u6CBF\u7528 sp.locate + \u4E00\u6B21 stat \u7684 (mtime, size) \u6587\u4EF6\u6307\u7EB9\u3002\n // mtime doubles as the session's last-activity time \u2014 appending an event\n // rewrites the log, so the file's last write tracks the conversation's last\n // turn. It errs safe: a log we relocated (move) gets a fresh mtime and\n // therefore looks *more* active than it is, which can only delay an\n // auto-archive, never cause a wrong one. Handle-era runtimes provide no\n // activity timestamp at all; auto-archive must then skip instead of guessing\n // (see autoArchiveSweep).\n // entries \u53EF\u7531\u8C03\u7528\u65B9\u4F20\u5165\u590D\u7528\uFF08\u5217\u8868\u6784\u5EFA\u91CC\u5DF2\u7ECF sp.list() \u8FC7\u4E00\u6B21\uFF0C\u907F\u514D\u91CD\u590D\u5217\u76EE\u5F55\uFF09\u3002\n async function collectUsage(preloadedEntries) {\n const sizeById = new Map()\n const mtimeById = new Map()\n const statsById = new Map()\n let entries = null\n if (Array.isArray(preloadedEntries)) entries = preloadedEntries\n else { try { entries = await persistence.listEntries() } catch (e) { entries = [] } }\n if (!Array.isArray(entries)) entries = []\n const CHUNK = 8\n for (let i = 0; i < entries.length; i += CHUNK) {\n await Promise.all(entries.slice(i, i + CHUNK).map(async (entry) => {\n const header = entry && entry.header ? entry.header : entry\n const id = entry && entry.id != null ? String(entry.id) : (header && header.id != null ? String(header.id) : null)\n if (!id) return\n // SessionHandle \u4E16\u4EE3\uFF1Asnapshot\uFF08header/revision/sizeBytes\uFF09\u662F\u6743\u5A01\u8F7B\u91CF\n // \u89C2\u5BDF\uFF0C\u7EDD\u4E0D\u518D\u7ED5\u9053\u79C1\u6709\u78C1\u76D8\u8DEF\u5F84\u8865 stat\u3002\n if (entry && typeof entry.revision === 'string' && entry.revision) {\n if (Number.isFinite(entry.sizeBytes)) sizeById.set(id, Number(entry.sizeBytes))\n statsById.set(id, { revision: entry.revision })\n return\n }\n if (entry && Number.isFinite(entry.sizeBytes)) sizeById.set(id, Number(entry.sizeBytes))\n try {\n const loc = persistence.locate(header)\n if (!loc || typeof loc.path !== 'string' || !loc.path) return\n const st = await stat(loc.path)\n if (!st) return\n if (typeof st.size === 'number') sizeById.set(id, st.size)\n if (typeof st.mtimeMs === 'number' && st.mtimeMs > 0) {\n mtimeById.set(id, Math.floor(st.mtimeMs))\n statsById.set(id, { mtimeMs: Math.floor(st.mtimeMs), size: typeof st.size === 'number' ? st.size : undefined })\n }\n } catch (e) { /* best-effort: an unreadable log just stays unknown */ }\n }))\n }\n return { sizeById, mtimeById, statsById, hasActivityData: mtimeById.size > 0 }\n }\n\n // Restore (unarchive) one session; throws on failure.\n async function restoreOne(sid) {\n requireSessionId(sid)\n return mutateArchived((list) => list.includes(sid)\n ? { next: list.filter((x) => x !== sid), value: { ok: true, restored: true } }\n : { next: null, value: { ok: true, restored: false } })\n }\n\n // ---- Recycle bin (\u56DE\u6536\u7AD9) helpers ----------------------------------------\n let trashMutation = Promise.resolve()\n function normalizeTrashStore(raw) {\n if (Array.isArray(raw)) return { schemaVersion: TRASH_SCHEMA_VERSION, settings: { ...DEFAULT_TRASH_SETTINGS }, items: raw, purgedSessionIds: [] }\n const settings = raw && typeof raw.settings === 'object' ? raw.settings : {}\n const retentionDays = Number.isInteger(settings.retentionDays) && settings.retentionDays >= 0 ? settings.retentionDays : 0\n return {\n schemaVersion: TRASH_SCHEMA_VERSION,\n settings: { retentionDays },\n items: raw && Array.isArray(raw.items) ? raw.items : [],\n purgedSessionIds: raw && Array.isArray(raw.purgedSessionIds) ? [...new Set(raw.purgedSessionIds.filter(isSafeSessionId).map(String))] : [],\n }\n }\n async function readTrashStore() {\n try { return normalizeTrashStore(JSON.parse(readFileSync(TRASH_INDEX, 'utf8'))) } catch (e) { return normalizeTrashStore(null) }\n }\n async function readTrash() { return (await readTrashStore()).items }\n async function writeTrashStore(store) {\n await mkdir(TRASH_DIR, { recursive: true })\n const tmp = join(TRASH_DIR, `.index-${process.pid}-${Date.now()}.tmp`)\n await writeFile(tmp, JSON.stringify(normalizeTrashStore(store), null, 2), { encoding: 'utf8', mode: 0o600 })\n await rename(tmp, TRASH_INDEX)\n }\n function mutateTrash(mutator) {\n const operation = trashMutation.then(async () => {\n const store = await readTrashStore()\n const result = await mutator(store)\n await writeTrashStore(store)\n return result\n })\n trashMutation = operation.catch(() => {})\n return operation\n }\n\n // ---- Starred sessions (\u6536\u85CF, schema v3) -----------------------------------\n // User marks, kept in the plugin's own index (never touches DSH logs). Stars\n // survive archive & soft-delete \u2014 both are reversible \u2014 and are dropped only\n // when the session is really gone (purge, or externally removed; the latter\n // is caught by gcStars during list builds).\n const stars = createStarIndex()\n // Auto-archive settings live in their own schema-v4 store, off by default.\n const autoArchive = createAutoArchiveStore()\n\n async function gcStars(validIds) {\n try {\n const store = await stars.read()\n const valid = new Set(validIds.map(String))\n const gone = store.starredSessionIds.filter((id) => !valid.has(id))\n if (gone.length) await stars.removeIds(gone)\n } catch (e) { /* best-effort */ }\n }\n\n // Soft-delete one session: record it in the recycle-bin index but KEEP its\n // log in the original workspace directory. Moving the file out (and detaching\n // it from the workspace) orphaned the session into DSH's \"\u672A\u5206\u7EC4\" group and\n // made restore land in \u672A\u5206\u7EC4 instead of the original workspace \u2014 so we leave\n // the file where it is and let the sidebar DOM shim hide the row instead.\n async function deleteOne(sid) {\n requireSessionId(sid)\n // Soft-delete is always allowed \u2014 including the currently-active conversation.\n // The log file stays in its original workspace dir (recorded in the \u56DE\u6536\u7AD9\n // index below), so the live session is unaffected and the entry stays\n // recoverable from \u56DE\u6536\u7AD9. (Move, by contrast, physically relocates the file\n // and still guards the active session in moveTargetWorkspace.)\n let header = null\n let cwd = null\n let title = null\n let removedPath = null\n let persistenceEntry = null\n try {\n const entries = await persistence.listEntries()\n const found = entries.find((entry) => entry.id === sid) || null\n persistenceEntry = found\n header = found ? found.header : null\n if (header) {\n const loc = persistence.locate(header)\n if (loc && typeof loc.path === 'string') removedPath = loc.path\n cwd = header.cwd || null\n title = header.title || (header.meta && header.meta.title) || null\n }\n if (!title) {\n // \u6807\u9898\u515C\u5E95\u4F18\u5148\u8D70\u5355\u4F1A\u8BDD\u6807\u9898\u6295\u5F71\uFF08\u5FEB\u7167\u7EA7\uFF0C\u4E0D\u8BFB\u65E5\u5FD7\uFF09\uFF1B\u6295\u5F71\u4E5F\u6CA1\u6709\u65F6\u624D\n // \u5206\u5757\u89E3\u7801\u65E5\u5FD7\u6298\u53E0\u6807\u9898\uFF08inspectSession \u5206\u5757\uFF0C\u4E0D\u6574\u672C\u9A7B\u7559\u5185\u5B58\uFF09\u3002\n if (typeof sq.readTitleSnapshot === 'function') {\n try {\n const snap = unwrapSnapshot(await sq.readTitleSnapshot(sid))\n if (snap && snap.title && snap.title.title) title = String(snap.title.title)\n if (snap && snap.session) { if (!cwd) cwd = snap.session.cwd || null }\n } catch (e) { /* fall through */ }\n }\n }\n if (!title) {\n try {\n let folded = null\n const summary = await persistence.inspectSession(sid, {\n onEvents: (events) => { if (!folded) folded = foldTitle(events) },\n })\n if (summary && summary.meta && !cwd) cwd = summary.meta.cwd || null\n title = folded\n } catch (e) { /* best-effort */ }\n }\n } catch (e) { /* best-effort */ }\n // Record in the trash index only \u2014 the log stays in its workspace dir.\n if (!header && !removedPath) {\n const error = new Error('\u627E\u4E0D\u5230\u8BE5\u4F1A\u8BDD')\n error.status = 404\n throw error\n }\n const archived = await mutateArchived((list) => ({ next: null, value: list.includes(sid) })).catch(() => false)\n await mutateTrash((store) => {\n const entry = {\n sessionId: sid, title: title || cwd || sid, cwd: cwd || null,\n header: header || null, originalPath: removedPath || null,\n sizeBytes: persistenceEntry && Number.isFinite(persistenceEntry.sizeBytes) ? persistenceEntry.sizeBytes : null,\n wasArchived: archived, deletedAt: Date.now(),\n }\n const at = store.items.findIndex((t) => String(t.sessionId) === sid)\n if (at >= 0) store.items[at] = entry\n else store.items.push(entry)\n store.purgedSessionIds = store.purgedSessionIds.filter((id) => id !== sid)\n })\n return { ok: true, trashed: true }\n }\n\n // \u6062\u590D\u524D\u7684\u5E95\u5C42\u6821\u9A8C\uFF080.1.3 \u5951\u7EA6\u4E0B restoreIndexedSession \u4E0D\u518D\u65E0\u6761\u4EF6\u53EF\u7528\uFF09\uFF1A\n // 1. \u5E95\u5C42 stored session \u4ECD\u5B58\u5728\uFF08live / stat / list \u4E09\u7EA7\u5224\u5B9A\uFF09\uFF1B\n // 2. \u65E5\u5FD7\u6587\u4EF6\u4ECD\u5728\u539F\u5904\uFF08\u8F6F\u5220\u9664\u4E0D\u52A8\u6587\u4EF6\uFF0CoriginalPath \u4E22\u5931\u5373\u5916\u90E8\u7834\u574F\uFF09\uFF1B\n // 3. \u5DE5\u4F5C\u533A\u4E22\u5931\u4E0D\u7B97\u5931\u8D25\u2014\u2014\u4F1A\u8BDD\u4ECD\u53EF\u6062\u590D\uFF0CUI \u4EE5 workspaceGone \u63D0\u793A\u3002\n // \u8FD4\u56DE { ok:true, workspaceGone, verified } \u6216 { ok:false, status, code, message }\u3002\n // verified=false \u8868\u793A\u65E0\u6CD5\u6838\u9A8C\u65E5\u5FD7\u6587\u4EF6\uFF08SessionHandle \u4E16\u4EE3\u65E0 locate\uFF09\uFF0C\u6309\n // \u7D22\u5F15\u4E3A\u51C6\u653E\u884C\uFF0C\u4F46\u7EDD\u4E0D\u5047\u88C5\u6821\u9A8C\u8FC7\u3002\n async function verifyTrashRestore(sid) {\n const sessions = ctx.get('sessions')\n if (sessions && sessions.get && sessions.get(sid)) {\n return { ok: true, workspaceGone: false, verified: true }\n }\n let exists = false\n let header = null\n try {\n const stat = await persistence.statSession(sid)\n if (stat) { exists = true; header = stat.header }\n } catch (e) { /* stat \u7F3A\u5931\u6216\u5931\u8D25\uFF1A\u843D\u5165 legacy \u5224\u5B9A */ }\n if (!exists) {\n try {\n const entries = await persistence.listEntries()\n const found = entries.find((entry) => entry.id === sid)\n if (found) { exists = true; header = found.header }\n } catch (e) { /* list \u5931\u8D25\uFF1A\u7EE7\u7EED\u8D70\u9519\u8BEF\u5206\u652F */ }\n }\n if (!exists) {\n const store = await readTrashStore()\n if (store.purgedSessionIds.map(String).includes(sid)) {\n return { ok: false, status: 410, code: 'DSM_SESSION_PURGED', message: '\u8BE5\u4F1A\u8BDD\u5DF2\u5F7B\u5E95\u5220\u9664\uFF0C\u65E0\u6CD5\u4ECE\u56DE\u6536\u7AD9\u6062\u590D' }\n }\n return { ok: false, status: 409, code: 'DSM_SESSION_MISSING', message: '\u5E95\u5C42\u4F1A\u8BDD\u5DF2\u4E0D\u5B58\u5728\uFF08\u53EF\u80FD\u88AB\u5916\u90E8\u5220\u9664\u6216\u91CD\u5EFA\uFF09\uFF0C\u65E0\u6CD5\u6062\u590D' }\n }\n // \u8F6F\u5220\u9664\u628A\u65E5\u5FD7\u7559\u5728\u539F\u5DE5\u4F5C\u533A\u76EE\u5F55\uFF1BoriginalPath \u6D88\u5931 = \u5916\u90E8\u7834\u574F\u3002\n // \u65E0\u6CD5\u6838\u9A8C\uFF08\u65E0 locate / \u65E0\u8BB0\u5F55\uFF09\u65F6\u653E\u884C\u4F46\u5982\u5B9E\u6807\u6CE8\u3002\n let verified = false\n const store = await readTrashStore()\n const entry = store.items.find((t) => String(t.sessionId) === sid)\n let originalPath = entry && typeof entry.originalPath === 'string' ? entry.originalPath : null\n if (!originalPath && header) {\n const loc = persistence.locate(header)\n if (loc && typeof loc.path === 'string') originalPath = loc.path\n }\n if (originalPath) {\n const existsOnDisk = await stat(originalPath).then(() => true).catch(() => false)\n if (!existsOnDisk) {\n return { ok: false, status: 409, code: 'DSM_SESSION_LOG_MISSING', message: '\u56DE\u6536\u7AD9\u7D22\u5F15\u4ECD\u8BB0\u5F55\u8BE5\u4F1A\u8BDD\uFF0C\u4F46\u5176\u65E5\u5FD7\u6587\u4EF6\u5DF2\u6D88\u5931\uFF08\u53EF\u80FD\u88AB\u5916\u90E8\u79FB\u52A8\u6216\u5220\u9664\uFF09' }\n }\n verified = true\n }\n let workspaceGone = false\n const cwd = (header && header.cwd) || (entry && entry.cwd) || null\n if (cwd) {\n try { workspaceGone = !w.list().some((ent) => ent.path === cwd) } catch (e) { workspaceGone = false }\n }\n return { ok: true, workspaceGone, verified }\n }\n\n // Restore a trashed session: the log never left its original workspace dir,\n // so we just drop it from the recycle-bin index and the sidebar reveals it in\n // its original workspace (no move / no re-attach needed). Repeated restores\n // fail with an accurate 404 \u2014 there is no second entry to restore.\n async function restoreFromTrash(sid) {\n requireSessionId(sid)\n requireCapability(capabilities, 'restoreIndexedSession')\n let outcome = null\n await mutateTrash(async (store) => {\n const entry = store.items.find((t) => String(t.sessionId) === sid)\n if (!entry) {\n if (store.purgedSessionIds.map(String).includes(sid)) {\n const error = new Error('\u8BE5\u4F1A\u8BDD\u5DF2\u5F7B\u5E95\u5220\u9664\uFF0C\u65E0\u6CD5\u4ECE\u56DE\u6536\u7AD9\u6062\u590D')\n error.status = 410\n error.code = 'DSM_SESSION_PURGED'\n throw error\n }\n const error = new Error('\u56DE\u6536\u7AD9\u4E2D\u627E\u4E0D\u5230\u8BE5\u4F1A\u8BDD\uFF08\u53EF\u80FD\u5DF2\u6062\u590D\u8FC7\uFF09')\n error.status = 404\n error.code = 'DSM_TRASH_NOT_FOUND'\n throw error\n }\n // Verify BEFORE removing the durable entry: if verification fails the\n // mutator throws, mutateTrash does not write, and the item remains\n // recoverable instead of disappearing into an inconsistent state.\n const verification = await verifyTrashRestore(sid)\n if (!verification.ok) {\n const error = new Error(verification.message)\n error.status = verification.status\n error.code = verification.code\n throw error\n }\n // Restore the pre-delete archive state before removing the durable trash\n // entry. If this fails, mutateTrash does not write and the item remains\n // recoverable instead of disappearing into an inconsistent state.\n if (entry.wasArchived === false) await restoreOne(sid)\n store.items = store.items.filter((t) => String(t.sessionId) !== sid)\n store.purgedSessionIds = store.purgedSessionIds.filter((id) => id !== sid)\n outcome = { ok: true, restored: true, workspaceGone: verification.workspaceGone, verified: verification.verified }\n })\n return outcome || { ok: true, restored: true }\n }\n\n // Permanently erase a trashed session: physically delete its log (still in\n // the original workspace dir) and detach it from any workspace so DSH drops it.\n async function purgeFromTrash(sid) {\n requireSessionId(sid)\n requireCapability(capabilities, 'purge')\n let purged = false\n await mutateTrash(async (store) => {\n const entry = store.items.find((t) => String(t.sessionId) === sid)\n if (!entry) { const error = new Error('\u56DE\u6536\u7AD9\u4E2D\u627E\u4E0D\u5230\u8BE5\u4F1A\u8BDD'); error.status = 404; throw error }\n let target = null\n try {\n const entries = await persistence.listEntries()\n const current = entries.find((entry) => entry.id === sid)\n const located = current && persistence.locate(current.header)\n if (located && typeof located.path === 'string') target = located.path\n } catch (e) {}\n if (!target && typeof entry.originalPath === 'string') target = entry.originalPath\n if (!target) {\n const error = new Error('\u65E0\u6CD5\u786E\u8BA4\u8BE5\u4F1A\u8BDD\u7684\u7269\u7406\u65E5\u5FD7\u4F4D\u7F6E\uFF0C\u5DF2\u505C\u6B62\u6C38\u4E45\u5220\u9664')\n error.status = 409\n throw error\n }\n // JSONL persistence stores logs as\n // .../<sessionId>/session.jsonl.zstd\n // Older backends may instead include the id in the filename itself.\n // pathOwnsSession accepts both layouts on POSIX and Windows separators\n // and rejects every unrelated path (including id-substring collisions)\n // before any unlink.\n const targetOwnsSession = pathOwnsSession(target, sid)\n if (target && !targetOwnsSession) {\n const error = new Error('\u65E5\u5FD7\u8DEF\u5F84\u4E0E\u4F1A\u8BDD ID \u4E0D\u5339\u914D\uFF0C\u5DF2\u505C\u6B62\u6C38\u4E45\u5220\u9664')\n error.status = 409\n throw error\n }\n // Persist the tombstone before any irreversible work. A crash after this\n // point may leave the trash item retryable, but can never resurrect the\n // session in a later list baseline.\n if (!store.purgedSessionIds.includes(sid)) store.purgedSessionIds.push(sid)\n await writeTrashStore(store)\n // A freshly-created or recently-opened Session can remain resident after\n // its file is unlinked. Flush once, then use SessionStore's entered-record\n // detach capability so DSH emits host/session-removed and the client list\n // drops the row instead of resurrecting it from live memory.\n try {\n const sessions = ctx.get('sessions')\n const liveSession = sessions && sessions.get && sessions.get(sid)\n if (liveSession && typeof sessions.flush === 'function') await sessions.flush(liveSession)\n const entered = sessions && sessions.store && sessions.store.get && sessions.store.get(sid)\n if (liveSession && (!entered || typeof entered.detach !== 'function')) throw new Error('\u5BBF\u4E3B\u672A\u63D0\u4F9B live Session detach \u80FD\u529B')\n if (entered && typeof entered.detach === 'function') entered.detach()\n // session/disposed starts an asynchronous persistence retirement. Wait\n // for it before unlinking, otherwise its final drain can race the file\n // deletion and briefly (or permanently) republish an orphan that the\n // official sidebar groups under \u201C\u672A\u5206\u7EC4\u201D.\n const retirement = sp && sp.retirements && sp.retirements.get && sp.retirements.get(sid)\n if (retirement && typeof retirement.then === 'function') await retirement\n } catch (e) {\n const error = new Error('\u65E0\u6CD5\u4ECE\u5BBF\u4E3B\u5185\u5B58\u79FB\u9664\u4F1A\u8BDD\uFF0C\u5DF2\u505C\u6B62\u6C38\u4E45\u5220\u9664\uFF1A' + String((e && e.message) || e))\n error.status = 409\n throw error\n }\n if (target && persistence.kind === 'session-handle' && locatedHeader) {\n // handle \u65F6\u4EE3\uFF1A\u5199\u6240\u6709\u6743\u63A2\u6D4B\uFF08\u6D3B\u8DC3\u5199\u8005 409\uFF09\u2192 \u6574\u76EE\u5F55\u5220\u9664 \u2192 \u5B98\u65B9 stat \u590D\u6838\u3002\n // \u5185\u90E8\u590D\u7528\u4E0E\u79FB\u52A8\u540C\u4E00\u5957\u8DEF\u5F84\u5B88\u536B\uFF1B\u5220\u9664\u5931\u8D25\u4F1A\u5E26 status \u5192\u6CE1\u3002\n await purgeSessionArtifacts(sp, sid, locatedHeader)\n } else if (target) {\n try { await unlink(target) } catch (e) { if (e && e.code !== 'ENOENT') throw new Error('\u5220\u9664\u6587\u4EF6\u5931\u8D25\uFF1A' + String((e && e.message) || e)) }\n }\n try { for (const ent of w.list()) { if (ent.sessionIds.includes(sid)) { try { await ent.detachSession(sid) } catch (e) {} } } } catch (e) {}\n try { if (w.sessionPaths && w.sessionPaths.delete) w.sessionPaths.delete(sid) } catch (e) {}\n try { if (w.headers && w.headers.delete) w.headers.delete(sid) } catch (e) {}\n await restoreOne(sid)\n // Rebuild from the post-unlink disk baseline before reporting success.\n // Merely deleting the two Maps above does not notify/rebuild Workspace\n // entities, leaving the client with an orphaned \u201C\u672A\u5206\u7EC4\u201D snapshot.\n try { await reindexRegistry() } catch (e) { /* tombstone still prevents resurrection */ }\n store.items = store.items.filter((t) => String(t.sessionId) !== sid)\n purged = true\n })\n if (!purged) throw new Error('\u5F7B\u5E95\u5220\u9664\u5931\u8D25')\n stars.removeIds([sid]).catch(() => {})\n return { ok: true, purged: true }\n }\n\n async function trashSettings(next) {\n if (next === undefined) return (await readTrashStore()).settings\n const days = Number(next.retentionDays)\n if (!Number.isInteger(days) || ![0, 7, 30, 90].includes(days)) {\n const error = new Error('retentionDays \u4EC5\u652F\u6301 0\u30017\u300130\u300190')\n error.status = 400\n throw error\n }\n await mutateTrash((store) => { store.settings = { retentionDays: days } })\n return (await readTrashStore()).settings\n }\n\n async function cleanupExpiredTrash() {\n if (!capabilities.actions.purge.available) return 0\n const store = await readTrashStore()\n const days = store.settings.retentionDays\n if (!days) return 0\n const cutoff = Date.now() - days * 86400000\n const ids = store.items.filter((item) => Number(item.deletedAt) > 0 && Number(item.deletedAt) < cutoff).map((item) => String(item.sessionId))\n let count = 0\n for (const sid of ids) { try { await purgeFromTrash(sid); count++ } catch (e) {} }\n return count\n }\n\n // ---- \"move conversation between workspaces\" helper -----------------------\n // DSH binds a conversation to the workspace whose canonical directory path\n // equals the session's stored cwd. Moving it therefore means: (1) adopt the\n // target path as a workspace (create if needed), (2) durably relocate the\n // session's log so its header carries the new cwd, and (3) reassign the\n // workspace membership (detach everywhere, attach to target). The log\n // relocation goes through the persistence service's own encoder (handles the\n // zstd artifact encoding) with a backup + rollback so a failure never leaves\n // the session half-moved.\n\n async function moveTargetWorkspace(rawPath) {\n if (typeof rawPath !== 'string' || !rawPath.trim()) throw new Error('\u7F3A\u5C11\u76EE\u6807\u5DE5\u4F5C\u533A\u8DEF\u5F84')\n let p = String(rawPath).trim()\n if (p.startsWith('~/')) p = join(homedir(), p.slice(2))\n if (!isAbsolute(p)) p = join(homedir(), p)\n let canonical = null\n try { canonical = await realpath(p) } catch (e) { canonical = null }\n if (canonical === null) {\n await mkdir(p, { recursive: true })\n canonical = await realpath(p)\n }\n return { canonical, entity: await w.create(canonical, basename(canonical) || 'workspace') }\n }\n\n async function moveOne(sid, targetPath) {\n requireCapability(capabilities, 'move')\n // Only block the *active* conversation. ctx.sessions keeps instantiated\n // sessions alive after you switch away, so the old check (sessions.get(sid))\n // wrongly rejected every opened session \u2014 you could never move one you'd\n // merely looked at. When the host exposes no active-session accessor we\n // can't prove activeness, so we allow the move; the relocation below is\n // crash-safe (backup + rollback) and re-syncs the live object.\n const activeId = getActiveSessionId(ctx)\n if (activeId != null && String(activeId) === String(sid)) {\n throw new Error('\u8BE5\u4F1A\u8BDD\u5F53\u524D\u5904\u4E8E\u6253\u5F00\u72B6\u6001\uFF0C\u8BF7\u5148\u5207\u6362\u5230\u522B\u7684\u4F1A\u8BDD\u518D\u79FB\u52A8\u3002')\n }\n const r = await persistence.readSession(sid, 0)\n if (!r || !r.meta) throw new Error('\u65E0\u6CD5\u8BFB\u53D6\u8BE5\u4F1A\u8BDD\u7684\u65E5\u5FD7')\n const meta = r.meta\n const events = r.events\n const oldCwd = meta.cwd || null\n\n const { canonical, entity: target } = await moveTargetWorkspace(targetPath)\n\n if (oldCwd) {\n let oldCanon = null\n try { oldCanon = await realpath(oldCwd) } catch (e) { oldCanon = null }\n if (oldCanon === canonical) {\n return { ok: true, already: true, workspaceId: target.id, workspaceTitle: target.title }\n }\n }\n\n const newHeader = Object.assign({}, meta, { cwd: canonical })\n\n // 1) Decide relocation strategy. `sessionPersistence.create()` rejects\n // (\"already exists in this backend\") for ANY session the host has\n // instantiated into its in-memory `states` \u2014 and DSH instantiates *every*\n // session it can find on disk at startup, including ARCHIVED ones. So a\n // supposedly \"closed\" archived session is NOT safe for the create()+append()\n // path; create() will throw. The only universally safe move is to physically\n // relocate the on-disk log (rewriting frame0's cwd) and redirect the live\n // object + persistence state. We still attempt create()+append() as the\n // fast path for genuinely-virgin session ids, but on an already-exists\n // collision we fall back to the relocate path. That covers live, archived,\n // and restored sessions alike.\n const live = ctx.get('sessions')\n const liveObj = live && live.get && live.get(sid)\n const isOpen = !!liveObj\n\n const ALREADY_EXISTS_RE = /already exists in this backend/i\n\n // Physically relocate a session's on-disk log to `newHeader`'s cwd,\n // rewriting frame0's cwd so sp.list()/reindex attribute it correctly.\n // Returns true if a relocation actually happened.\n const relocateLog = async (header, newHeaderObj) => {\n const oldPath = locatePath(header)\n const newPath = locatePath(newHeaderObj)\n if (!oldPath || !newPath || oldPath === newPath) return false\n const backupPath = `${oldPath}.move-backup-${Date.now()}`\n const stagedPath = `${newPath}.move-stage-${process.pid}-${Date.now()}`\n let destinationInstalled = false\n try {\n // Ensure the destination project directory exists (rename does not\n // create it). Without this, the rename silently no-ops on ENOENT and\n // the log stays put while workspace.json is wrongly updated.\n await mkdir(dirname(newPath), { recursive: true })\n try {\n await stat(newPath)\n throw new Error('\u79FB\u52A8\u5931\u8D25\uFF1A\u76EE\u6807\u4F4D\u7F6E\u5DF2\u5B58\u5728\u540C\u540D\u4F1A\u8BDD\u65E5\u5FD7')\n } catch (e) {\n if (e && e.code !== 'ENOENT') throw e\n }\n await rename(oldPath, backupPath) // keep the original byte-identical until verification succeeds\n const original = await readFile(backupPath)\n const originalFrames = scanZstdFrames(original).frames\n if (originalFrames.length === 0) throw new Error('\u79FB\u52A8\u524D\u6821\u9A8C\u5931\u8D25\uFF1A\u4F1A\u8BDD\u65E5\u5FD7\u6CA1\u6709\u5B8C\u6574 zstd \u5E27')\n const rewritten = rewriteFrame0CwdInMemory(original, canonical)\n const rewrittenFrames = scanZstdFrames(rewritten).frames\n if (rewrittenFrames.length !== originalFrames.length) throw new Error('\u79FB\u52A8\u540E\u6821\u9A8C\u5931\u8D25\uFF1A\u4F1A\u8BDD\u65E5\u5FD7\u5E27\u6570\u53D1\u751F\u53D8\u5316')\n const originalTail = original.subarray(originalFrames[0].end)\n const rewrittenTail = rewritten.subarray(rewrittenFrames[0].end)\n if (!originalTail.equals(rewrittenTail)) throw new Error('\u79FB\u52A8\u540E\u6821\u9A8C\u5931\u8D25\uFF1A\u4F1A\u8BDD\u4E8B\u4EF6\u5185\u5BB9\u53D1\u751F\u53D8\u5316')\n await writeFile(stagedPath, rewritten, { mode: 0o600 })\n await rename(stagedPath, newPath)\n destinationInstalled = true\n await unlink(backupPath)\n } catch (e) {\n try { await unlink(stagedPath) } catch (_) {}\n if (destinationInstalled) { try { await unlink(newPath) } catch (_) {} }\n try { await rename(backupPath, oldPath) } catch (_) {}\n if (e && e.code !== 'ENOENT') throw e\n return false\n }\n return true\n }\n\n const locatePath = (header) => {\n let fn = null\n try { if (typeof sp.locate === 'function') fn = sp.locate.bind(sp) } catch (e) {}\n if (!fn && sp.backend && typeof sp.backend.locate === 'function') fn = sp.backend.locate.bind(sp.backend)\n if (!fn) return null\n try {\n const loc = fn(header)\n if (loc && typeof loc.path === 'string') return loc.path\n if (typeof loc === 'string') return loc\n } catch (e) {}\n return null\n }\n\n // Rewriting frame0's cwd now lives in src/zstd-frame.js so it can be\n // regression-tested directly. See that module for why frame boundaries are\n // validated by decompression and why a non-session frame0 is rejected\n // instead of rewritten.\n\n if (persistence.kind === 'session-handle') {\n // \u8BFB\u4E8B\u4EF6\u4E4B\u540E\u7684\u53CC revision \u6821\u9A8C\uFF1A\u4E24\u6B21\u91C7\u6837\u4E4B\u95F4 revision \u4ECD\u5728\u53D8\uFF0C\u8BF4\u660E\u65E5\u5FD7\n // \u8FD8\u5728\u88AB\u5199\u5165\uFF0C\u4E2D\u6B62\u800C\u4E0D\u662F\u590D\u5236\u51FA\u5206\u53C9\u526F\u672C\uFF08\u8BFB\u53D6\u671F\u95F4\u7684\u5199\u5165\u7531 ops \u5185\u7684\n // rename-aside + \u5B98\u65B9\u5199\u6240\u6709\u6743\u63A2\u6D4B\u515C\u5E95\uFF09\u3002\n const stat1 = await persistence.statSession(sid)\n if (stat1 && stat1.revision) {\n const stat2 = await persistence.statSession(sid)\n if (stat2 && stat2.revision !== stat1.revision) {\n throw new Error('\u8BE5\u4F1A\u8BDD\u5728\u79FB\u52A8\u51C6\u5907\u671F\u95F4\u53D1\u751F\u4E86\u53D8\u5316\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002')\n }\n }\n try {\n await moveSessionToCwd({ sp, sid, header: meta, canonical, events, inheritedEventCount: r.inheritedEventCount })\n } catch (e) {\n if (e && e.status) throw e\n throw new Error('\u79FB\u52A8\u4F1A\u8BDD\u65E5\u5FD7\u5931\u8D25\uFF1A' + String((e && e.message) || e))\n }\n } else if (isOpen) {\n // Live session: relocate the on-disk log (rewriting frame0's cwd to the\n // new path) and redirect the live object + persistence state. We must\n // rewrite frame0, not just rename: sp.list() reads frame0's cwd from\n // disk, and WorkspaceEntity.sessionIds filters by that exact cwd. A bare\n // rename would leave frame0 pointing at the old workspace, so reindex /\n // restart would keep attributing the session to the wrong workspace.\n if (!await relocateLog(meta, newHeader)) throw new Error('\u79FB\u52A8\u5931\u8D25\uFF1A\u65E0\u6CD5\u786E\u8BA4\u4F1A\u8BDD\u65E5\u5FD7\u5DF2\u8FC1\u79FB\u5230\u76EE\u6807\u5DE5\u4F5C\u533A')\n // Redirect the persistence state's cwd so future appends land in newPath.\n try {\n const st = sp.states && sp.states.get && sp.states.get(sid)\n if (st && st.meta) st.meta = Object.assign({}, st.meta, { cwd: canonical })\n } catch (e) { /* best-effort */ }\n } else {\n // Closed session: try the fast create()+append() path first. But DSH\n // instantiates *all* on-disk sessions (including archived ones) into its\n // in-memory states at startup, so create() usually throws\n // \"already exists in this backend\". On that collision we fall back to a\n // physical relocate of the existing log (rewriting frame0's cwd), which\n // is safe and needs no create().\n let oldPath = null\n try {\n const loc = locatePath(meta)\n if (loc && typeof loc === 'string') oldPath = loc\n else if (loc && loc.path) oldPath = loc.path\n } catch (e) { oldPath = null }\n\n if (typeof sp.create !== 'function' || typeof sp.append !== 'function') {\n // No create primitive: must relocate the existing log directly.\n if (!await relocateLog(meta, newHeader)) throw new Error('\u79FB\u52A8\u5931\u8D25\uFF1A\u65E0\u6CD5\u786E\u8BA4\u4F1A\u8BDD\u65E5\u5FD7\u5DF2\u8FC1\u79FB\u5230\u76EE\u6807\u5DE5\u4F5C\u533A')\n } else {\n const backupPath = oldPath ? `${oldPath}.move-backup-${Date.now()}` : null\n if (backupPath) { try { await rename(oldPath, backupPath) } catch (e) { if (e && e.code !== 'ENOENT') throw new Error('\u79FB\u52A8\u5931\u8D25\uFF1A\u65E0\u6CD5\u5907\u4EFD\u65E7\u7684\u4F1A\u8BDD\u65E5\u5FD7') } }\n const restore = async () => { if (backupPath) { try { await rename(backupPath, oldPath) } catch (_) {} } }\n try {\n await sp.create(newHeader)\n await sp.append(sid, events)\n const check = await persistence.readSession(sid, 0)\n if (!check || !check.meta || check.meta.cwd !== canonical) {\n throw new Error('\u79FB\u52A8\u540E\u6821\u9A8C\u5931\u8D25\uFF1A\u4F1A\u8BDD\u5DE5\u4F5C\u76EE\u5F55\u672A\u6B63\u786E\u66F4\u65B0')\n }\n if (backupPath) { try { await unlink(backupPath) } catch (e) {} }\n } catch (e) {\n if (ALREADY_EXISTS_RE.test(String((e && e.message) || e))) {\n // Collision: the session is already materialized in states (archived\n // or previously opened). Fall back to physically relocating the log.\n await restore()\n if (!await relocateLog(meta, newHeader)) throw new Error('\u79FB\u52A8\u5931\u8D25\uFF1A\u65E0\u6CD5\u786E\u8BA4\u4F1A\u8BDD\u65E5\u5FD7\u5DF2\u8FC1\u79FB\u5230\u76EE\u6807\u5DE5\u4F5C\u533A')\n } else {\n await restore()\n throw new Error('\u79FB\u52A8\u4F1A\u8BDD\u65E5\u5FD7\u5931\u8D25\uFF1A' + String((e && e.message) || e))\n }\n }\n }\n }\n\n // Keep the live (in-memory) session object consistent with the relocated\n // log so the host doesn't keep appending to the old path. This MUST happen\n // before attachSession(): WorkspaceEntity.attachSession() validates the\n // session by reading live.header first, and if it still carries the old cwd\n // the realpath check will fail on the old (now missing) directory.\n try {\n if (liveObj) {\n if ('header' in liveObj) liveObj.header = newHeader\n if ('cwd' in liveObj) liveObj.cwd = canonical\n if ('meta' in liveObj) liveObj.meta = newHeader\n }\n } catch (e) { /* best-effort */ }\n\n // 2) Reassign workspace membership (durable records + in-memory index).\n for (const ent of w.list()) {\n try { await ent.detachSession(sid) } catch (e) { /* ignore */ }\n }\n if (w.headers && typeof w.headers.set === 'function') w.headers.set(sid, newHeader)\n if (w.sessionPaths && typeof w.sessionPaths.set === 'function') w.sessionPaths.set(sid, canonical)\n await target.attachSession(sid)\n\n // Verify the membership actually landed on the target workspace. DSH's\n // WorkspaceEntity.attachSession persists asynchronously; if it silently\n // no-ops (e.g. the session's durable cwd still points elsewhere) the UI\n // would show \"moved\" while the sidebar keeps the old grouping. Fail loud\n // instead of returning a fake success.\n const verified = (() => {\n try { return target.sessionIds.includes(sid) } catch (e) { return false }\n })()\n if (!verified) {\n throw new Error('\u79FB\u52A8\u540E\u6821\u9A8C\u5931\u8D25\uFF1A\u4F1A\u8BDD\u672A\u51FA\u73B0\u5728\u76EE\u6807\u5DE5\u4F5C\u533A\uFF0C\u8BF7\u91CD\u8BD5\u6216\u91CD\u542F DSH\u3002')\n }\n\n return {\n ok: true,\n moved: true,\n workspaceId: target.id,\n workspaceTitle: target.title,\n workspacePath: canonical,\n }\n }\n\n // Force the host's WorkspaceRegistry to rebuild its in-memory sessionPath\n // index from the durable persistence headers. DSH's WorkspaceEntity.sessionIds\n // is a *getter* that filters record.sessionIds by `host.sessionPath(id) ===\n // record.path`; that sessionPath Map is only repopulated at startup (bootstrap\n // + indexHeaders). So even after a successful move writes the durable cwd,\n // the running process keeps attributing the session to its OLD workspace until\n // a restart \u2014 unless we reindex here. Calling this right after move makes the\n // sidebar reflect the new grouping with NO restart required.\n async function reindexRegistry() {\n const reg = w\n if (!reg || typeof reg.replaceHeaderIndex !== 'function') return false\n let entries = null\n try { entries = await persistence.listEntries() } catch (e) { entries = null }\n if (!entries || !Array.isArray(entries)) return false\n await reg.replaceHeaderIndex(entries.map((entry) => entry.header))\n if (typeof reg.rebuildEntities === 'function') reg.rebuildEntities()\n return true\n }\n\n async function listWorkspaces() {\n const out = []\n try {\n for (const ent of w.list()) out.push({ workspaceId: ent.id, title: ent.title, path: ent.path })\n } catch (e) { /* ignore */ }\n return out\n }\n\n // Archive (hide) one session: adds its id to the durable archive set so it\n // is dropped out of the sidebar. DSH requires the session to exist (live or\n // persisted) \u2014 a genuine miss surfaces as an error.\n async function archiveOne(sid) {\n requireSessionId(sid)\n return mutateArchived(async (list) => {\n if (list.includes(sid)) return { next: null, value: { ok: true, archived: false } }\n await w.archiveSession(sid)\n // archiveSession owns the durable write; keep this operation serialized\n // with restoreOne so two requests cannot overwrite each other's state.\n return { next: null, value: { ok: true, archived: true } }\n })\n }\n\n // \u6279\u91CF\u6295\u5F71\uFF1A\u4E00\u6B21\u8C03\u7528\u628A\u591A\u6761\u4F1A\u8BDD\u7684\u6807\u9898/header \u62FF\u51FA\u6765\uFF0C\u907F\u514D\u9010\u6761\u89E6\u53D1\u6574\u672C\u89E3\u7801\u3002\n // \u8001 runtime \u6CA1\u6709 readTitleSnapshots \u65F6\u8FD4\u56DE\u7A7A Map\uFF0C\u8C03\u7528\u65B9\u81EA\u7136\u56DE\u9000\u5230\u9010\u6761\u6295\u5F71\n // \uFF08\u529F\u80FD\u4E0D\u53D7\u5F71\u54CD\uFF0C\u53EA\u662F\u5C11\u4E86\u8FD9\u5C42\u4F18\u5316\u2014\u2014\u63D2\u4EF6\u4E0D\u80FD\u5047\u8BBE\u5BF9\u65B9\u7684 runtime \u7248\u672C\uFF09\u3002\n async function projectTitles(ids) {\n const out = new Map()\n if (!ids || !ids.length) return out\n if (typeof sq.readTitleSnapshots !== 'function') return out\n try {\n const results = await sq.readTitleSnapshots(ids)\n if (!Array.isArray(results)) return out\n results.forEach((result, index) => {\n const id = String(ids[index])\n out.set(id, unwrapSnapshot(result))\n })\n } catch (e) { /* \u6279\u91CF\u5931\u8D25\uFF1A\u9010\u6761\u56DE\u9000 */ }\n return out\n }\n\n // opts.usage: expose sizeBytes + updatedAt on each item (storage analysis and\n // the auto-archive sweep need them; the panel list does not).\n //\n // \u6027\u80FD\u8981\u70B9\uFF08issue #1 + 0.1.3-alpha \u9002\u914D\uFF09\uFF1A\n // 1. sp.list() \u53EA\u8C03\u4E00\u6B21\uFF08\u539F\u5148\u5217\u4E86\u4E24\u904D\u76EE\u5F55\uFF09\n // 2. \u53D8\u66F4\u4EE4\u724C\u4F18\u5148\u6765\u81EA list \u5FEB\u7167\uFF1Alegacy \u8D70 locate+stat\uFF0CSessionHandle \u4E16\u4EE3\n // \u76F4\u63A5\u7528 snapshot.revision\uFF08\u65E0 locate \u53EF\u7528\uFF0C\u4E5F\u7EDD\u4E0D\u7ED5\u79C1\u6709\u8DEF\u5F84\u8865 stat\uFF09\n // 3. \u672A\u547D\u4E2D\u7F13\u5B58\u7684\u4F1A\u8BDD\u8D70**\u4E00\u6B21**\u6279\u91CF\u6295\u5F71\uFF08sq.readTitleSnapshots\uFF09\uFF0C\u800C\u4E0D\u662F\u9010\u6761\n async function allSessionItemsDetailed(opts = {}) {\n let entries = []\n let headersOk = false\n try {\n entries = await persistence.listEntries()\n headersOk = Array.isArray(entries)\n if (!headersOk) entries = []\n } catch (e) { entries = [] }\n const entryById = new Map(entries.map((entry) => [entry.id, entry]))\n let live = ctx.get('sessions')\n const ids = entries.map((entry) => entry.id)\n if (live) { try { live.list().forEach((s) => { const sid = String(s.id); if (!ids.includes(sid)) ids.push(sid) }) } catch (e) { /* ignore */ } }\n // Exclude sessions already moved to the recycle bin (\u8F6F\u5220\u9664): they live in\n // \u56DE\u6536\u7AD9, not in \u4F1A\u8BDD\u7BA1\u7406, so the panel won't re-list them after a delete.\n // purged tombstone \u53EA\u5BF9\u300C\u5F53\u524D\u4E0D\u5B58\u5728\u7684 id\u300D\u7EE7\u7EED\u9690\u85CF\uFF1A\u82E5\u540C id \u4F1A\u8BDD\u540E\u6765\u91CD\u65B0\n // \u51FA\u73B0\uFF08\u91CD\u5EFA/\u6362\u7ED1\u5B9A\uFF09\uFF0C\u5893\u7891\u5FC5\u987B\u8BA9\u4F4D\uFF0C\u4E0D\u80FD\u6C38\u4E45\u538B\u4F4F\u65B0\u4F1A\u8BDD\u3002\n let hiddenIds = new Set()\n try {\n const store = await readTrashStore()\n const present = new Set(ids)\n hiddenIds = new Set([\n ...store.items.map((t) => String(t.sessionId)),\n ...store.purgedSessionIds.map(String).filter((id) => !present.has(id)),\n ])\n } catch (e) {}\n const visibleIds = ids.filter((id) => !hiddenIds.has(id))\n wsByPath = {}\n try { for (const ent of w.list()) wsByPath[ent.path] = ent } catch (e) { wsByPath = {} }\n const currentArchived = new Set((await archivedState().catch(() => ({ archivedSessionIds: [] }))).archivedSessionIds || [])\n const items = []\n const usage = await collectUsage(entries)\n // \u5148\u6309\u6307\u7EB9\u628A\u300C\u7F13\u5B58\u547D\u4E2D\u300D\u4E0E\u300C\u9700\u8981\u89E3\u7801\u300D\u5206\u5F00\uFF0C\u53EA\u5BF9\u540E\u8005\u505A\u6279\u91CF\u6295\u5F71\u3002\n const statsById = new Map(visibleIds.map((id) => [\n id,\n (usage.statsById && usage.statsById.get(id)) || { mtimeMs: usage.mtimeById.get(id), size: usage.sizeById.get(id) },\n ]))\n const { missing } = metaCache.partition(visibleIds, statsById)\n // P4\uFF1Amissing \u91CC\u5148\u67E5\u6301\u4E45\u6807\u9898\u7D22\u5F15\uFF08\u51B7\u542F\u52A8\u8DF3\u8FC7\u6574\u672C\u89E3\u7801\uFF09\uFF0C\u547D\u4E2D\u7684\u56DE\u586B\u5185\u5B58\u7F13\u5B58\u3002\n const persisted = await hydrateFromPersist(missing, statsById)\n for (const [id, meta] of persisted) metaCache.set(id, statsById.get(id), meta)\n const stillMissing = missing.filter((id) => !persisted.has(id))\n const snapshotById = await projectTitles(stillMissing)\n const decoded = new Map()\n const collectDecoded = (id, meta) => { decoded.set(id, meta) }\n const CHUNK = 6\n for (let i = 0; i < visibleIds.length; i += CHUNK) {\n // Arrow wrapper on purpose: Array#map passes (value, index, array), and\n // resolveOne's second and third arguments are fixed here.\n const res2 = await Promise.all(visibleIds.slice(i, i + CHUNK).map((id) => {\n const entry = entryById.get(id)\n return resolveOne(id, usage, {\n exposeUsage: !!(opts && opts.usage),\n listHeader: entry ? entry.header : null,\n preloaded: snapshotById.has(id) ? snapshotById.get(id) : undefined,\n collectDecoded,\n })\n }))\n for (const it of res2) items.push({ ...it, archived: currentArchived.has(it.sessionId) })\n }\n persistDecoded(decoded, statsById)\n // Annotate stars; GC only when we have a trustworthy id baseline, so a\n // failing sp.list() can never wipe the whole index.\n let starredSet = new Set()\n try { starredSet = new Set((await stars.read()).starredSessionIds) } catch (e) {}\n for (const it of items) it.starred = starredSet.has(String(it.sessionId))\n if (headersOk) await gcStars(ids)\n return { items, usage }\n }\n\n async function allSessionItems(opts = {}) {\n return (await allSessionItemsDetailed(opts)).items\n }\n\n // ---- Storage usage + auto-archive ---------------------------------------\n\n // Read-only rollup: per-workspace totals plus the largest sessions. The\n // aggregation itself is a pure function (src/storage-stats.js).\n async function buildStorage(opts = {}) {\n const items = await allSessionItems({ usage: true })\n const raw = Number(opts && opts.topN)\n const topN = Number.isInteger(raw) && raw > 0 ? Math.min(raw, MAX_STORAGE_TOP) : 10\n return aggregateStorage(items, { topN })\n }\n\n // Archive conversations that have been idle past the configured window.\n //\n // Deliberately lazy \u2014 there is no timer. The sweep runs when the panel reads\n // its settings (and on demand), at most once a day: a background interval\n // would keep the host process alive and would archive conversations while\n // nobody is looking at the panel.\n async function autoArchiveSweep(opts = {}) {\n const store = await autoArchive.read()\n const days = store.settings.inactiveDays\n if (!days) return { ok: true, skipped: 'disabled', archived: 0 }\n const now = Date.now()\n if (!(opts && opts.force) && autoArchive.isFresh(store, now)) {\n return { ok: true, skipped: 'throttled', archived: 0, lastRunAt: store.lastRunAt, lastArchivedCount: store.lastArchivedCount }\n }\n const { items, usage } = await allSessionItemsDetailed({ usage: true })\n // SessionHandle \u4E16\u4EE3\u6CA1\u6709\u53EF\u9760\u7684\u300C\u6700\u540E\u6D3B\u8DC3\u65F6\u95F4\u300D\uFF08\u65E0 locate/mtime\uFF0C\u5FEB\u7167\u4E5F\u4E0D\n // \u643A\u5E26\u4E8B\u4EF6\u65F6\u95F4\uFF09\u3002\u65E0\u6CD5\u8BC1\u660E\u4F1A\u8BDD\u95F2\u7F6E \u2192 \u4E00\u5F8B\u8DF3\u8FC7\uFF0C\u7EDD\u4E0D\u731C\u6D4B\uFF08\u5B81\u53EF\u6F0F\u5F52\u6863\uFF0C\n // \u4E0D\u80FD\u9519\u5F52\u6863\uFF09\u3002UI \u4F1A\u5982\u5B9E\u5C55\u793A\u8BE5\u964D\u7EA7\u3002\n if (!usage.hasActivityData) {\n return {\n ok: true, skipped: 'no-activity-data', archived: 0,\n note: '\u5F53\u524D DSH \u7248\u672C\u672A\u63D0\u4F9B\u53EF\u9760\u7684\u6700\u540E\u6D3B\u8DC3\u65F6\u95F4\uFF0C\u81EA\u52A8\u5F52\u6863\u5DF2\u8DF3\u8FC7\uFF1B\u4E0D\u4F1A\u57FA\u4E8E\u731C\u6D4B\u5F52\u6863\u4EFB\u4F55\u4F1A\u8BDD\u3002',\n }\n }\n const candidates = pickInactiveCandidates(items, {\n inactiveDays: days,\n skipStarred: store.settings.skipStarred,\n activeSessionId: getActiveSessionId(ctx),\n now,\n })\n let archived = 0\n const failed = []\n for (const sid of candidates) {\n try {\n const result = await archiveOne(sid)\n if (result && result.archived) archived++\n } catch (e) {\n failed.push({ sessionId: sid, error: String((e && e.message) || e) })\n }\n }\n await autoArchive.recordRun(archived, now)\n return { ok: true, archived, candidates: candidates.length, failed, lastRunAt: now }\n }\n\n // \u4FA7\u680F\u6743\u5A01\u6570\u636E\uFF1A\u6807\u9898 + \u56DE\u6536\u7AD9 id \u96C6\u5408\u3002\n //\n // \u6807\u9898\u539F\u5148\u300C\u9996\u6B21\u8C03\u7528\u7B97\u4E00\u6B21\u5C31\u6C38\u4E45\u7F13\u5B58\u300D\uFF0C\u65E5\u5FD7\u4E4B\u540E\u518D\u53D8\u4E5F\u4E0D\u4F1A\u66F4\u65B0\u2014\u2014\u6807\u9898\u4F1A\u9648\u65E7\u3002\n // \u73B0\u5728\u590D\u7528 metaCache\uFF1A\u6BCF\u6B21\u8C03\u7528\u53EA stat \u4E00\u904D\uFF0C\u65E5\u5FD7\u6CA1\u53D8\u76F4\u63A5\u53D6\u7F13\u5B58\uFF0C\u53D8\u4E86\u624D\u91CD\u89E3\u7801\uFF0C\n // \u65E2\u4E0D\u4F1A\u9648\u65E7\u4E5F\u4E0D\u4F1A\u56DE\u5230\u300C\u6BCF\u6B21\u5168\u91CF\u89E3\u7801\u300D\u3002\n async function sidebarAuthority() {\n const ids = []\n let entries = []\n try { entries = await persistence.listEntries() } catch (e) { entries = [] }\n if (!Array.isArray(entries)) entries = []\n for (const entry of entries) ids.push(entry.id)\n const sessions = ctx.get('sessions')\n try { if (sessions) sessions.list().forEach((session) => { const sid = String(session.id); if (!ids.includes(sid)) ids.push(sid) }) } catch (e) {}\n const store = await readTrashStore()\n // \u5893\u7891\u53EA\u5BF9\u300C\u5F53\u524D\u4E0D\u5B58\u5728\u300D\u7684 id \u7EE7\u7EED\u8F93\u51FA\uFF1B\u540C id \u4F1A\u8BDD\u91CD\u65B0\u51FA\u73B0\u65F6\u5FC5\u987B\u8BA9\u4F4D\u3002\n const present = new Set(ids)\n const activeTombstones = store.purgedSessionIds.map(String).filter((id) => !present.has(id))\n if (ids.length) {\n const usage = await collectUsage(entries)\n const statsById = new Map(ids.map((id) => [\n id,\n (usage.statsById && usage.statsById.get(id)) || { mtimeMs: usage.mtimeById.get(id), size: usage.sizeById.get(id) },\n ]))\n const { cached, missing } = metaCache.partition(ids, statsById)\n // P4\uFF1A\u4E0E\u5217\u8868\u6784\u5EFA\u5171\u7528\u6301\u4E45\u6807\u9898\u7D22\u5F15\uFF0C\u51B7\u542F\u52A8\u96F6\u89E3\u7801\u3002\n const persisted = await hydrateFromPersist(missing, statsById)\n for (const [id, meta] of persisted) metaCache.set(id, statsById.get(id), meta)\n const rest = missing.filter((id) => !persisted.has(id))\n const snapshotById = await projectTitles(rest)\n const decoded = new Map()\n const collectDecoded = (id, meta) => { decoded.set(id, meta) }\n for (const id of ids) {\n let meta = cached.get(id) || persisted.get(id) || null\n if (!meta) {\n const entry = entries.find((e) => e.id === id)\n const snapshot = snapshotById.has(id)\n ? snapshotById.get(id)\n : (typeof sq.readTitleSnapshot === 'function' ? await sq.readTitleSnapshot(id).catch(() => null) : null)\n const next = metaFromSnapshot(snapshot)\n if (entry && entry.header) {\n if (!next.cwd && typeof entry.header.cwd === 'string') next.cwd = entry.header.cwd\n if (!next.createdAt && entry.header.createdAt != null) next.createdAt = entry.header.createdAt\n }\n metaCache.set(id, statsById.get(id), next)\n if (statsById.get(id)) collectDecoded(id, next)\n meta = next\n }\n if (meta && meta.title) authorityTitleCache.set(id, String(meta.title))\n }\n persistDecoded(decoded, statsById)\n }\n return {\n titles: Object.fromEntries(authorityTitleCache),\n trashedSessionIds: store.items.map((item) => String(item.sessionId)),\n purgedSessionIds: activeTombstones,\n }\n }\n\n // \u805A\u5408\u4E00\u6761\u4F1A\u8BDD\u7684\u8BE6\u60C5\uFF08\u78C1\u76D8\u5360\u7528 / \u8F6E\u6B21\u00B7\u6B65\u6570\u00B7\u6D88\u606F\u6570 / \u5DE5\u5177\u7EDF\u8BA1 / fetch /\n // write/edit \u6587\u4EF6 / \u8840\u7EDF parent/children/subagents\uFF09\u3002live \u4E0E\u6301\u4E45\u5316\u4F1A\u8BDD\u90FD\u53EF\u8BFB\u3002\n // \u6240\u6709\u7EDF\u8BA1\u5BF9\u672A\u77E5\u4E8B\u4EF6\u7C7B\u578B\u5BB9\u9519\uFF1Bfetch \u4E0E files \u505A\u4E0A\u9650\u622A\u65AD\uFF0Cfiles \u7528 stat \u8FC7\u6EE4\n // \u78C1\u76D8\u4E0A\u5DF2\u4E0D\u5B58\u5728\u7684\u8DEF\u5F84\uFF0C\u907F\u514D\u8BE6\u60C5\u9762\u677F\u5217\u51FA\u5DF2\u5220\u9664\u6587\u4EF6\u3002\n // \u6301\u4E45\u5316\u4F1A\u8BDD\u8D70 inspectSession \u5206\u5757\u6298\u53E0\uFF1A\u5927\u65E5\u5FD7\u4E0D\u518D\u6574\u672C\u9A7B\u7559\u5185\u5B58\uFF080.1.3-alpha\n // \u5DF2\u77E5\u5386\u53F2\u4F1A\u8BDD\u52A0\u8F7D\u6027\u80FD\u56DE\u9000\uFF0C\u8FD9\u91CC\u907F\u514D\u653E\u5927\u5B83\uFF09\u3002\n async function buildDetails(sid, signal) {\n const sessions = ctx.get('sessions')\n const live = sessions && sessions.get(sid)\n let meta = null\n let lastTime = 0\n const fileSet = new Map()\n const stats = {\n turns: 0, steps: 0, userMessages: 0, assistantMessages: 0,\n toolCalls: 0, attachments: 0, toolCounts: {}, fetches: [],\n }\n const turnSeen = new Set()\n const stepSeen = new Set()\n\n const absorb = (ev) => {\n if (ev && typeof ev.time === 'number' && ev.time > lastTime) lastTime = ev.time\n const d = (ev && ev.data && typeof ev.data === 'object') ? ev.data : {}\n const type = ev && ev.type\n switch (type) {\n case 'turn/start':\n if (typeof d.turn === 'number') turnSeen.add(d.turn)\n break\n case 'step/start':\n if (typeof d.step === 'number') stepSeen.add(d.step)\n break\n case 'user/message':\n stats.userMessages++\n if (Array.isArray(d.content)) for (const b of d.content) if (b && b.type === 'image') stats.attachments++\n break\n case 'assistant/message':\n stats.assistantMessages++\n break\n case 'tool/call': {\n stats.toolCalls++\n const tn = typeof d.name === 'string' && d.name ? d.name : 'tool'\n stats.toolCounts[tn] = (stats.toolCounts[tn] || 0) + 1\n if (FETCH_TOOL_RE.test(tn)) {\n let query\n try {\n const a = typeof d.arguments === 'string' ? JSON.parse(d.arguments) : d.arguments\n query = typeof a?.query === 'string' ? a.query : typeof a?.url === 'string' ? a.url : typeof a?.q === 'string' ? a.q : undefined\n } catch (e) { query = undefined }\n stats.fetches.push({ tool: tn, ...(query && query !== '' ? { query } : {}) })\n }\n if (tn === 'write' || tn === 'edit') {\n let argsJ\n try { argsJ = typeof d.arguments === 'string' ? JSON.parse(d.arguments) : d.arguments } catch (e) { break }\n const fp = argsJ && typeof argsJ.file_path === 'string' && argsJ.file_path ? argsJ.file_path : undefined\n if (fp !== undefined && !fileSet.has(fp)) fileSet.set(fp, tn)\n }\n break\n }\n }\n }\n\n if (live !== void 0) {\n meta = (live && live.header) || null\n try { (Array.isArray(live.events) ? [...live.events] : []).forEach(absorb) } catch (e) { /* empty */ }\n } else {\n const summary = await persistence.inspectSession(sid, { signal, onEvents: (batch) => { for (const ev of batch) absorb(ev) } })\n if (!summary || !summary.meta) throw new Error('\u627E\u4E0D\u5230\u8BE5\u4F1A\u8BDD\u7684\u8BB0\u5F55\uFF08\u4F1A\u8BDD\u4E0D\u5B58\u5728\uFF09')\n meta = summary.meta\n }\n stats.turns = turnSeen.size\n stats.steps = stepSeen.size\n let sizeBytes = null\n if (live === void 0) {\n // SessionHandle \u4E16\u4EE3\uFF1A\u5FEB\u7167\u76F4\u63A5\u5E26 sizeBytes\uFF08\u5B98\u65B9 JSONL \u540E\u7AEF\u5EC9\u4EF7\u63D0\u4F9B\uFF09\uFF1B\n // \u62FF\u4E0D\u5230\u518D\u9000\u56DE locate + stat\uFF08legacy\uFF09\u3002\u7EDD\u4E0D\u4F2A\u9020 0\u3002\n try {\n const stat = await persistence.statSession(sid)\n if (stat && Number.isFinite(stat.sizeBytes)) sizeBytes = stat.sizeBytes\n } catch (e) { /* fall through */ }\n }\n if (sizeBytes === null) {\n try {\n // rc.8 \u7684 sessionPersistence \u540E\u7AEF\u6CA1\u6709 artifactInfo\uFF1B\u7528 locate(meta) \u62FF\u65E5\u5FD7\n // \u6587\u4EF6\u771F\u5B9E\u8DEF\u5F84\u540E stat \u51FA\u5B57\u8282\u6570\uFF08\u78C1\u76D8\u5360\u7528\uFF09\u3002\n const loc = persistence.locate(meta)\n if (loc && typeof loc.path === 'string' && loc.path) {\n const st = await stat(loc.path)\n if (st && typeof st.size === 'number') sizeBytes = st.size\n }\n } catch (e) { sizeBytes = null }\n }\n if (stats.fetches.length > MAX_FETCHES) stats.fetches = stats.fetches.slice(0, MAX_FETCHES)\n const fileEntries = [...fileSet.entries()].slice(0, MAX_FILES * 2)\n const exists = await Promise.all(fileEntries.map(([p]) => stat(p).then(() => true).catch(() => false)))\n const files = fileEntries\n .filter((_, i) => exists[i])\n .map(([path, tool]) => ({ path, tool }))\n .slice(0, MAX_FILES)\n // lineage\uFF1A\u5206\u53C9\u5B50\u4F1A\u8BDD\uFF08\u975E subagent\uFF09\u4E0E\u5B50\u4EE3\u7406\uFF08origin==='subagent'\uFF09\uFF0Csource \u53BB\u91CD\u3002\n const lineage = {\n parentSessionId: (meta && typeof meta.parentSession === 'string') ? meta.parentSession : null,\n children: [],\n subagents: [],\n }\n const childrenSet = new Set()\n const subagentSet = new Set()\n try {\n if (typeof sp.list === 'function') {\n for (const entry of await persistence.listEntries()) {\n const h = entry.header\n if (String(h.parentSession) !== String(sid)) continue\n if (h.origin === 'subagent') subagentSet.add(h.id); else childrenSet.add(h.id)\n }\n }\n } catch (e) { /* best-effort */ }\n if (sessions) {\n try {\n sessions.list().forEach((s) => {\n if (String(s.header.parentSession) !== String(sid)) return\n if (s.header.origin === 'subagent') subagentSet.add(s.id); else childrenSet.add(s.id)\n })\n } catch (e) { /* best-effort */ }\n }\n lineage.children = [...childrenSet]\n lineage.subagents = [...subagentSet]\n return {\n sessionId: sid,\n sizeBytes,\n createdAt: (meta && typeof meta.createdAt === 'number') ? meta.createdAt : null,\n updatedAt: Math.max(lastTime || 0, (meta && typeof meta.createdAt === 'number' ? meta.createdAt : 0)) || null,\n files,\n stats,\n lineage,\n }\n }\n\n ctx.effect(() => {\n const disposers = []\n\n if (typeof ctx.on === 'function') disposers.push(ctx.on('session/event', (session, event) => {\n if (event && event.type === 'session/title' && event.data && typeof event.data.title === 'string') {\n authorityTitleCache.set(String(session.id), event.data.title)\n }\n }))\n\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/capabilities',\n handler: async (req, res) => json(res, capabilities),\n }))\n\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/list',\n handler: async (req, res) => {\n try {\n const state = await archivedState()\n const ids = state.archivedSessionIds || []\n // Only surface archived ids that still exist (materialized log or live).\n // Deleted sessions keep a hidden archive id but no log, so they drop out here.\n let materialized = new Set()\n let live = ctx.get('sessions')\n try {\n const entries = await persistence.listEntries()\n materialized = new Set(entries.map((entry) => entry.id))\n } catch (e) { /* best-effort */ }\n const trashStore = await readTrashStore()\n // \u5893\u7891\u53EA\u5BF9\u300C\u5F53\u524D\u4E0D\u5B58\u5728\u300D\u7684 id \u751F\u6548\uFF1B\u540C id \u4F1A\u8BDD\u91CD\u65B0\u51FA\u73B0\u65F6\u8BA9\u4F4D\u3002\n const present = new Set([\n ...materialized,\n ...ids.map(String),\n ...(live && typeof live.list === 'function' ? live.list().map((s) => String(s.id)) : []),\n ])\n const tombstones = trashStore.purgedSessionIds.map(String).filter((id) => !present.has(id))\n const hidden = new Set([...trashStore.items.map((item) => String(item.sessionId)), ...tombstones])\n const idStrs = ids.map(String).filter((id) => !hidden.has(id) && (materialized.has(id) || (live && live.get(id))))\n wsByPath = {}\n try { for (const ent of w.list()) wsByPath[ent.path] = ent } catch (e) { wsByPath = {} }\n const items = []\n const CHUNK = 6\n for (let i = 0; i < idStrs.length; i += CHUNK) {\n const res2 = await Promise.all(idStrs.slice(i, i + CHUNK).map((id) => resolveOne(id)))\n items.push.apply(items, res2)\n }\n json(res, { items })\n } catch (e) {\n json(res, { error: String((e && e.message) || e) }, 500)\n }\n },\n }))\n\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/restore',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const sid = body && typeof body.sessionId === 'string' ? body.sessionId : null\n if (!sid) return json(res, { ok: false, error: 'missing sessionId' }, 400)\n json(res, await restoreOne(sid))\n } catch (e) {\n json(res, { ok: false, error: String((e && e.message) || e) }, errorStatus(e))\n }\n },\n }))\n\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/restore-many',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const ids = parseIds(body)\n if (!ids || ids.length === 0) return json(res, { ok: false, error: 'missing sessionIds' }, 400)\n const results = []\n for (const sid of ids) {\n try { results.push({ sessionId: sid, ok: true, ...(await restoreOne(sid)) }) }\n catch (e) { results.push({ sessionId: sid, ok: false, code: e && e.code, error: String((e && e.message) || e) }) }\n }\n json(res, { ok: true, restored: results.filter((r) => r.ok).length, results })\n } catch (e) {\n json(res, { ok: false, code: e && e.code, error: String((e && e.message) || e) }, errorStatus(e))\n }\n },\n }))\n\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/delete',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const sid = body && typeof body.sessionId === 'string' ? body.sessionId : null\n if (!sid) return json(res, { ok: false, error: 'missing sessionId' }, 400)\n const out = await deleteOne(sid)\n // \u65E5\u5FD7\u88AB\u642C\u8FDB\u56DE\u6536\u7AD9\uFF08\u6587\u4EF6\u5DF2\u4E0D\u5728\u539F\u5904\uFF09\uFF1A\u4E22\u5F03\u7F13\u5B58\u6761\u76EE\uFF0C\u907F\u514D\u4E0B\u6B21 stat \u5931\u8D25\n // \u65F6\u6B8B\u7559\u65E7\u5143\u6570\u636E\u3002\n metaCache.invalidate(sid)\n json(res, out)\n } catch (e) {\n json(res, { ok: false, error: String((e && e.message) || e) }, errorStatus(e))\n }\n },\n }))\n\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/delete-many',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const ids = parseIds(body)\n if (!ids || ids.length === 0) return json(res, { ok: false, error: 'missing sessionIds' }, 400)\n const results = []\n for (const sid of ids) {\n try { results.push({ sessionId: sid, ok: true, ...(await deleteOne(sid)) }); metaCache.invalidate(sid) }\n catch (e) { results.push({ sessionId: sid, ok: false, error: String((e && e.message) || e) }) }\n }\n json(res, { ok: true, deleted: results.filter((r) => r.ok).length, results })\n } catch (e) {\n json(res, { ok: false, code: e && e.code, error: String((e && e.message) || e) }, errorStatus(e))\n }\n },\n }))\n\n // ---- Recycle bin (\u56DE\u6536\u7AD9) routes ----------------------------------------\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/trash/list',\n handler: async (req, res) => {\n try {\n await cleanupExpiredTrash()\n const list = await readTrash()\n list.sort((a, b) => (b.deletedAt || 0) - (a.deletedAt || 0))\n const store = await readTrashStore()\n json(res, { schemaVersion: store.schemaVersion, settings: store.settings, purgedSessionIds: store.purgedSessionIds, items: list })\n } catch (e) {\n json(res, { ok: false, error: String((e && e.message) || e) }, errorStatus(e))\n }\n },\n }))\n\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/trash/settings',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const settings = body && Object.prototype.hasOwnProperty.call(body, 'retentionDays')\n ? await trashSettings({ retentionDays: body.retentionDays })\n : await trashSettings()\n json(res, { ok: true, settings })\n } catch (e) {\n json(res, { ok: false, error: String((e && e.message) || e) }, errorStatus(e))\n }\n },\n }))\n\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/trash/verify',\n handler: async (req, res) => {\n try {\n const items = await readTrash()\n const results = await Promise.all(items.map(async (item) => {\n if (typeof item.originalPath !== 'string' || !item.originalPath) {\n return { sessionId: item.sessionId, status: 'unverified', originalPath: null }\n }\n const exists = await stat(item.originalPath).then(() => true).catch(() => false)\n return { sessionId: item.sessionId, status: exists ? 'ok' : 'missing', originalPath: item.originalPath }\n }))\n json(res, {\n ok: true,\n healthy: results.filter((r) => r.status === 'ok').length,\n missing: results.filter((r) => r.status === 'missing').length,\n unverified: results.filter((r) => r.status === 'unverified').length,\n results,\n })\n } catch (e) {\n json(res, { ok: false, error: String((e && e.message) || e) }, errorStatus(e))\n }\n },\n }))\n\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/trash/restore',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const sid = body && typeof body.sessionId === 'string' ? body.sessionId : null\n if (!sid) return json(res, { ok: false, error: 'missing sessionId' }, 400)\n const out = await restoreFromTrash(sid)\n metaCache.invalidate(sid)\n json(res, out)\n } catch (e) {\n json(res, { ok: false, code: e && e.code, error: String((e && e.message) || e) }, errorStatus(e))\n }\n },\n }))\n\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/trash/purge',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const sid = body && typeof body.sessionId === 'string' ? body.sessionId : null\n if (!sid) return json(res, { ok: false, error: 'missing sessionId' }, 400)\n const out = await purgeFromTrash(sid)\n metaCache.invalidate(sid)\n // \u5F7B\u5E95\u5220\u9664\uFF1A\u6301\u4E45\u6807\u9898\u7D22\u5F15\u91CC\u7684\u6761\u76EE\u4E00\u5E76\u6E05\u6389\uFF08issue #1 P4\uFF09\u3002\n titleIndex.remove([sid]).catch(() => {})\n json(res, out)\n } catch (e) {\n json(res, { ok: false, code: e && e.code, error: String((e && e.message) || e) }, errorStatus(e))\n }\n },\n }))\n\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/trash/purge-many',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const ids = parseIds(body)\n if (!ids || ids.length === 0) return json(res, { ok: false, error: 'missing sessionIds' }, 400)\n const results = []\n for (const sid of ids) {\n try { results.push({ sessionId: sid, ok: true, ...(await purgeFromTrash(sid)) }); metaCache.invalidate(sid); titleIndex.remove([sid]).catch(() => {}) }\n catch (e) { results.push({ sessionId: sid, ok: false, error: String((e && e.message) || e) }) }\n }\n json(res, { ok: true, purged: results.filter((r) => r.ok).length, results })\n } catch (e) {\n json(res, { ok: false, code: e && e.code, error: String((e && e.message) || e) }, errorStatus(e))\n }\n },\n }))\n\n // All conversations (for the \"\u79FB\u52A8\u4F1A\u8BDD\" panel).\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/sessions',\n handler: async (req, res) => {\n try {\n json(res, { items: await allSessionItems() })\n } catch (e) {\n json(res, { error: String((e && e.message) || e) }, 500)\n }\n },\n }))\n\n // Star / unstar one or many sessions (\u6536\u85CF, schema v3).\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/star/set',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const starred = !!(body && body.starred)\n let ids = parseIds(body)\n if ((!ids || ids.length === 0) && body && typeof body.sessionId === 'string') {\n ids = isSafeSessionId(body.sessionId) ? [body.sessionId] : null\n }\n if (!ids || ids.length === 0) return json(res, { ok: false, error: 'missing sessionId' }, 400)\n const starredSessionIds = await stars.setStarred(ids, starred)\n json(res, { ok: true, starredSessionIds })\n } catch (e) {\n json(res, { ok: false, error: String((e && e.message) || e) }, errorStatus(e))\n }\n },\n }))\n\n // Human-readable Markdown export (one session). Raw-log ZIP export is\n // dsh's own GET /api/session.export \u2014 we deliberately do not duplicate it\n // (see reports/HANDOFF-dsh-sessions-manager-roadmap.md \u00A72.4).\n //\n // 0.1.3 \u517C\u5BB9\uFF1A\u65E5\u5FD7\u7ECF inspectSession \u5206\u5757\u8BFB\u53D6\uFF08SessionHandle.read \u7684\n // offset/length \u6709\u754C\u5207\u7247\uFF09\uFF0C\u6D41\u5F0F\u6E32\u67D3 Markdown\uFF0C\u5BA2\u6237\u7AEF\u65AD\u5F00\u5373\u53D6\u6D88\uFF08signal\uFF09\uFF0C\n // \u5E76\u53D7\u5168\u5C40\u5E76\u53D1\u95F8\u7EA6\u675F\u2014\u2014\u5927\u65E5\u5FD7\u4E0D\u518D\u4E00\u6B21\u6027\u6574\u672C\u9A7B\u7559\u5185\u5B58\u3002\n const exportLimiter = createLimiter(2)\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/export-md',\n handler: async (req, res) => {\n try {\n const url = new URL(req.url, 'http://localhost')\n const sid = url.searchParams.get('sessionId')\n requireSessionId(sid)\n const ac = new AbortController()\n res.on('close', () => { if (!res.writableEnded) ac.abort() })\n const md = await exportLimiter(async () => {\n const builder = createSessionMarkdownBuilder({ id: sid })\n const summary = await persistence.inspectSession(sid, {\n signal: ac.signal,\n onEvents: (batch) => builder.addEvents(batch),\n })\n if (!summary || !summary.meta) {\n const error = new Error('\u65E0\u6CD5\u8BFB\u53D6\u8BE5\u4F1A\u8BDD\u7684\u65E5\u5FD7')\n error.status = 404\n throw error\n }\n // meta \u5728\u6D41\u7ED3\u675F\u540E\u624D\u6743\u5A01\uFF08header \u6765\u81EA open \u56DE\u5305\uFF09\uFF1Bfinish \u8986\u5199 front matter\u3002\n return builder.finish({ ...summary.meta, id: sid })\n })\n res.writeHead(200, {\n 'content-type': 'text/markdown; charset=utf-8',\n 'content-disposition': `attachment; filename=\"dsh-session-${sid}.md\"`,\n 'cache-control': 'no-store',\n })\n res.end(md)\n } catch (e) {\n json(res, { error: String((e && e.message) || e) }, errorStatus(e))\n }\n },\n }))\n\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/sidebar-state',\n handler: async (req, res) => {\n try {\n json(res, await sidebarAuthority())\n } catch (e) {\n json(res, { error: String((e && e.message) || e) }, errorStatus(e))\n }\n },\n }))\n\n // Available target workspaces (for the move picker).\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/workspaces',\n handler: async (req, res) => {\n try {\n json(res, { items: await listWorkspaces() })\n } catch (e) {\n json(res, { error: String((e && e.message) || e) }, 500)\n }\n },\n }))\n\n // Move one conversation to a target workspace (existing path or a new one).\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/move',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const sid = body && typeof body.sessionId === 'string' ? body.sessionId : null\n const target = body && typeof body.targetPath === 'string' ? body.targetPath : null\n if (!sid) return json(res, { ok: false, error: 'missing sessionId' }, 400)\n if (!target) return json(res, { ok: false, error: 'missing targetPath' }, 400)\n const moved = await moveOne(sid, target)\n // \u79FB\u52A8\u4F1A\u6539\u5199\u65E5\u5FD7 frame0 \u7684 cwd\uFF1A\u5143\u6570\u636E\uFF08cwd\uFF09\u5DF2\u53D8\uFF0C\u4E3B\u52A8\u4E22\u5F03\u7F13\u5B58\u6761\u76EE\uFF0C\n // \u4E0D\u7B49 mtime \u6307\u7EB9\u81EA\u7136\u5931\u6548\uFF08Windows \u4E0A mtime \u7CBE\u5EA6\u8F83\u7C97\uFF0C\u6307\u7EB9\u53EF\u80FD\u4E0D\u53D8\uFF09\u3002\n metaCache.invalidate(sid)\n // Reindex the host's in-memory sessionPath index so the sidebar\n // reflects the new grouping immediately (no DSH restart needed).\n // Do this before replying: drag/drop and menu clients treat a 2xx\n // response as the commit point and must never announce success while\n // the sidebar still holds the old workspace index.\n try { await reindexRegistry() } catch (e) { /* best-effort */ }\n json(res, { sessionId: sid, ...moved })\n } catch (e) {\n json(res, { ok: false, code: e && e.code, error: String((e && e.message) || e) }, errorStatus(e))\n }\n },\n }))\n\n // Archive (hide) one session.\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/archive',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const sid = body && typeof body.sessionId === 'string' ? body.sessionId : null\n if (!sid) return json(res, { ok: false, error: 'missing sessionId' }, 400)\n json(res, { sessionId: sid, ...(await archiveOne(sid)) })\n } catch (e) {\n json(res, { ok: false, error: String((e && e.message) || e) }, 500)\n }\n },\n }))\n\n // Archive (hide) many sessions.\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/archive-many',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const ids = parseIds(body)\n if (!ids || ids.length === 0) return json(res, { ok: false, error: 'missing sessionIds' }, 400)\n const results = []\n for (const sid of ids) {\n try { results.push({ sessionId: sid, ok: true, ...(await archiveOne(sid)) }) }\n catch (e) { results.push({ sessionId: sid, ok: false, error: String((e && e.message) || e) }) }\n }\n json(res, { ok: true, archived: results.filter((r) => r.ok).length, results })\n } catch (e) {\n json(res, { ok: false, error: String((e && e.message) || e) }, 500)\n }\n },\n }))\n\n // Per-session details (v2.0): disk usage, turn/step/message counts, tool\n // usage, fetch records, write/edit files, and lineage.\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/details',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const sid = body && typeof body.sessionId === 'string' ? body.sessionId : null\n if (!sid) return json(res, { ok: false, error: 'missing sessionId' }, 400)\n // \u5BA2\u6237\u7AEF\u65AD\u5F00\u65F6\u53D6\u6D88\u5206\u5757\u8BFB\u53D6\uFF0C\u907F\u514D\u4E3A\u5DF2\u79BB\u5F00\u7684\u8BF7\u6C42\u7EE7\u7EED\u89E3\u7801\u6574\u672C\u65E5\u5FD7\u3002\n const ac = new AbortController()\n res.on('close', () => { if (!res.writableEnded) ac.abort() })\n json(res, await buildDetails(sid, ac.signal))\n } catch (e) {\n json(res, { error: String((e && e.message) || e) }, (e && e.status) ? e.status : 500)\n }\n },\n }))\n\n // Storage usage rollup (read-only): per-workspace totals + largest sessions.\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/storage',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n json(res, await buildStorage({ topN: body && body.topN }))\n } catch (e) {\n json(res, { error: String((e && e.message) || e) }, 500)\n }\n },\n }))\n\n // Auto-archive settings. A plain read (no patch keys) doubles as the lazy\n // sweep trigger \u2014 that is how the once-a-day cleanup gets a chance to run\n // without a background timer. The sweep runs in the background so opening\n // the panel never waits on it (P5, issue #1): the sweep itself already\n // reuses the metadata caches, and this keeps the settings read latency\n // independent of library size.\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/auto-archive/settings',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const patch = {}\n if (body && Object.prototype.hasOwnProperty.call(body, 'inactiveDays')) patch.inactiveDays = body.inactiveDays\n if (body && Object.prototype.hasOwnProperty.call(body, 'skipStarred')) patch.skipStarred = body.skipStarred\n const isPatch = Object.keys(patch).length > 0\n const settings = isPatch\n ? await autoArchive.update(patch)\n : (await autoArchive.read()).settings\n let sweep\n if (isPatch) {\n // \u663E\u5F0F\u4FDD\u5B58\u8BBE\u7F6E\uFF1A\u4FDD\u6301\u300C\u4FDD\u5B58\u5373\u751F\u6548\u300D\u7684\u540C\u6B65 sweep\uFF08\u542B\u521A\u542F\u7528\u65F6\u7684\u9996\u6B21\u5F52\u6863\uFF09\u3002\n sweep = await autoArchiveSweep()\n } else {\n // \u9762\u677F\u6253\u5F00\u7684\u7EAF\u8BFB\u53D6\uFF1Asweep \u8F6C\u540E\u53F0\u6267\u884C\uFF0C\u6253\u5F00\u5EF6\u8FDF\u4E0E\u5E93\u5927\u5C0F\u89E3\u8026\n //\uFF08P5\uFF0Cissue #1\uFF09\u3002sweep \u672C\u8EAB\u5DF2\u590D\u7528\u5143\u6570\u636E\u7F13\u5B58 + \u6301\u4E45\u6807\u9898\u7D22\u5F15\u3002\n void autoArchiveSweep().catch(() => {})\n sweep = { triggered: true }\n }\n const store = await autoArchive.read()\n json(res, {\n ok: true,\n settings,\n lastRunAt: store.lastRunAt,\n lastArchivedCount: store.lastArchivedCount,\n sweep,\n })\n } catch (e) {\n json(res, { ok: false, error: String((e && e.message) || e) }, errorStatus(e))\n }\n },\n }))\n\n // Run the auto-archive sweep right now, ignoring the once-a-day throttle.\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/auto-archive/run',\n handler: async (req, res) => {\n try {\n const sweep = await autoArchiveSweep({ force: true })\n const store = await autoArchive.read()\n json(res, { ok: true, ...sweep, settings: store.settings, lastRunAt: store.lastRunAt, lastArchivedCount: store.lastArchivedCount })\n } catch (e) {\n json(res, { ok: false, error: String((e && e.message) || e) }, 500)\n }\n },\n }))\n\n return () => { for (const d of disposers) d() }\n }, 'dsh-sessions-manager: routes')\n}\n", "// dsh-sessions-manager \u2014 zstd frame helpers.\n//\n// DSH persists session logs as a sequence of concatenated zstd frames. The\n// FIRST frame must be exactly one line: the session header JSON (type\n// 'session'). The persistence layer enforces this on startup\n// (assertZstdHeaderFrame), so any corruption of frame0 takes down the whole\n// web profile.\n//\n// Moving a session between workspaces requires rewriting frame0's `cwd`\n// without re-encoding the rest of the log. That rewrite is where a bad frame\n// boundary can silently destroy a session \u2014 hence the defensive checks here.\n\nimport zlib from 'node:zlib'\nimport { readFileSync, writeFileSync } from 'node:fs'\n\n// zstd magic bytes are 28 B5 2F FD; read as a little-endian uint32 that is\n// 0xFD2FB528 (4247762216).\nexport const ZSTD_MAGIC = 0xFD2FB528\n\nconst CHECKSUM_OPTS = { params: { [zlib.constants.ZSTD_c_checksumFlag]: 1 } }\n\n/**\n * Parse complete concatenated Zstandard frames without decompressing them.\n * Invalid complete structure rejects; EOF inside the final frame is reported\n * as torn rather than guessed from magic bytes occurring in compressed data.\n *\n * @param {Buffer} buf\n * @param {number} maxFrames\n * @returns {{frames: Array<{start:number,end:number}>, tornStart?: number}}\n */\nexport function scanZstdFrames(buf, maxFrames = Number.POSITIVE_INFINITY) {\n const frames = []\n let offset = 0\n while (offset < buf.length) {\n const start = offset\n if (buf.length - offset < 4) return { frames, tornStart: start }\n if (buf.readUInt32LE(offset) !== ZSTD_MAGIC) {\n throw new Error(`\u4F1A\u8BDD\u65E5\u5FD7\u683C\u5F0F\u5F02\u5E38\uFF08\u5B57\u8282 ${offset} \u7684 zstd magic \u65E0\u6548\uFF09`)\n }\n offset += 4\n if (offset === buf.length) return { frames, tornStart: start }\n\n const descriptor = buf.readUInt8(offset++)\n if ((descriptor & 0x18) !== 0) throw new Error(`\u4F1A\u8BDD\u65E5\u5FD7\u683C\u5F0F\u5F02\u5E38\uFF08\u5B57\u8282 ${offset - 1} \u4F7F\u7528\u4FDD\u7559\u5E27\u5934\u4F4D\uFF09`)\n const contentSizeFlag = descriptor >>> 6\n const singleSegment = (descriptor & 0x20) !== 0\n const checksum = (descriptor & 0x04) !== 0\n const dictionaryFlag = descriptor & 0x03\n const dictionaryBytes = dictionaryFlag === 3 ? 4 : dictionaryFlag\n const contentSizeBytes = contentSizeFlag === 0 ? (singleSegment ? 1 : 0) : 1 << contentSizeFlag\n const remainingHeaderBytes = (singleSegment ? 0 : 1) + dictionaryBytes + contentSizeBytes\n if (buf.length - offset < remainingHeaderBytes) return { frames, tornStart: start }\n offset += remainingHeaderBytes\n\n for (;;) {\n if (buf.length - offset < 3) return { frames, tornStart: start }\n const blockHeader = buf.readUIntLE(offset, 3)\n offset += 3\n const lastBlock = (blockHeader & 1) !== 0\n const blockType = (blockHeader >>> 1) & 0x03\n const blockSize = blockHeader >>> 3\n if (blockType === 0x03) throw new Error(`\u4F1A\u8BDD\u65E5\u5FD7\u683C\u5F0F\u5F02\u5E38\uFF08\u5B57\u8282 ${offset - 3} \u4F7F\u7528\u4FDD\u7559\u5757\u7C7B\u578B\uFF09`)\n const payloadBytes = blockType === 0x01 ? 1 : blockSize\n if (buf.length - offset < payloadBytes) return { frames, tornStart: start }\n offset += payloadBytes\n if (lastBlock) break\n }\n if (checksum) {\n if (buf.length - offset < 4) return { frames, tornStart: start }\n offset += 4\n }\n frames.push({ start, end: offset })\n if (frames.length === maxFrames) return { frames }\n }\n return { frames }\n}\n\n/** Backward-compatible frame-start view used by diagnostics and tests. */\nexport function findZstdFrameStarts(buf) {\n return scanZstdFrames(buf).frames.map((frame) => frame.start)\n}\n\nfunction firstFrame(buf) {\n const scan = scanZstdFrames(buf, 1)\n const frame = scan.frames[0]\n if (!frame) throw new Error('\u4F1A\u8BDD\u65E5\u5FD7\u683C\u5F0F\u5F02\u5E38\uFF08\u65E0\u5B8C\u6574 zstd \u5E27\uFF09')\n return frame\n}\n\n/**\n * Rewrite the `cwd` field of a session log's first frame, leaving all\n * subsequent frames byte-identical.\n *\n * Refuses to write anything unless frame0 is a session header. A corrupted\n * frame0 (e.g. an `agent/inbox/spliced` event) is reported as an error rather\n * than being re-serialized back to disk \u2014 rewriting it would bake the\n * corruption in permanently and make the file unrecoverable.\n *\n * @param {string} filePath path to session.jsonl.zstd\n * @param {string} newCwd workspace path to write into frame0\n * @throws {Error} when the log has no zstd frame or frame0 is not a session header\n */\nexport function rewriteFrame0Cwd(filePath, newCwd) {\n const buf = readFileSync(filePath)\n const frame = firstFrame(buf)\n const end0 = frame.end\n const frame0 = buf.subarray(frame.start, end0)\n const text = zlib.zstdDecompressSync(frame0).toString('utf8')\n const nl = text.indexOf('\\n')\n const line = nl >= 0 ? text.slice(0, nl) : text\n const obj = JSON.parse(line)\n if (obj.type !== 'session') {\n throw new Error(`\u4F1A\u8BDD\u65E5\u5FD7\u683C\u5F0F\u5F02\u5E38\uFF08\u5E270 \u4E0D\u662F session header\uFF0C\u5B9E\u9645 type=${obj.type}\uFF09`)\n }\n if (obj.cwd === newCwd) return // already correct, no rewrite needed\n obj.cwd = newCwd\n const newFrame0 = zlib.zstdCompressSync(JSON.stringify(obj) + '\\n', CHECKSUM_OPTS)\n const rest = buf.subarray(end0)\n writeFileSync(filePath, Buffer.concat([newFrame0, rest]))\n}\n\n/**\n * Non-destructive variant of rewriteFrame0Cwd: returns the rewritten buffer\n * instead of touching the file on disk. Used by tests.\n *\n * @param {Buffer} buf\n * @param {string} newCwd\n * @returns {Buffer} rewritten log\n */\nexport function rewriteFrame0CwdInMemory(buf, newCwd) {\n const frame = firstFrame(buf)\n const end0 = frame.end\n const frame0 = buf.subarray(frame.start, end0)\n const text = zlib.zstdDecompressSync(frame0).toString('utf8')\n const nl = text.indexOf('\\n')\n const line = nl >= 0 ? text.slice(0, nl) : text\n const obj = JSON.parse(line)\n if (obj.type !== 'session') {\n throw new Error(`\u4F1A\u8BDD\u65E5\u5FD7\u683C\u5F0F\u5F02\u5E38\uFF08\u5E270 \u4E0D\u662F session header\uFF0C\u5B9E\u9645 type=${obj.type}\uFF09`)\n }\n obj.cwd = newCwd\n const newFrame0 = zlib.zstdCompressSync(JSON.stringify(obj) + '\\n', CHECKSUM_OPTS)\n const rest = buf.subarray(end0)\n return Buffer.concat([newFrame0, rest])\n}\n\n/**\n * Build a multi-frame session log buffer (header frame + event frames),\n * matching the layout DSH's persistence layer writes. Used by tests.\n *\n * @param {object} header session header (must have type: 'session')\n * @param {object[]} events subsequent records, one zstd frame each\n * @returns {Buffer}\n */\nexport function buildSessionLog(header, events = []) {\n const frames = [JSON.stringify(header) + '\\n', ...events.map((e) => JSON.stringify(e) + '\\n')]\n return Buffer.concat(frames.map((f) => zlib.zstdCompressSync(Buffer.from(f, 'utf8'), CHECKSUM_OPTS)))\n}\n\n/**\n * Read frame0 of a session log and return the parsed header line.\n *\n * @param {Buffer} buf\n * @returns {{obj: object, lineCount: number}}\n */\nexport function readFrame0(buf) {\n const frame = firstFrame(buf)\n const text = zlib.zstdDecompressSync(buf.subarray(frame.start, frame.end)).toString('utf8')\n const lines = text.split('\\n').filter((l) => l.length > 0)\n return { obj: JSON.parse(lines[0]), lineCount: lines.length }\n}\n", "// Render a session log as human-readable Markdown.\n//\n// Pure: no DOM, no I/O, no dsh imports. Everything it needs arrives as\n// arguments, so the renderer is unit-testable without a running host.\n//\n// Field shapes below were read off real session logs (2026-09-01), not guessed:\n// user/message data.content = [{ type:'text', text } | { type:'image', ... }]\n// assistant/message data.message.content = [{ type:'text'|'reasoning'|'tool-call', ... }]\n// tool/call data.{name, arguments} (arguments is a JSON *string*)\n// tool/result data.message.content = [{ type:'tool-result', content:[{type:'text',text}] }]\n// Note the asymmetry: user text lives at data.content, assistant text one level\n// deeper at data.message.content. Streaming deltas (`assistant/chunk`,\n// `text-chunks`, `reasoning-chunks`) are never rendered \u2014 `assistant/message`\n// already carries the final text for each step.\n\nconst MAX_TOOL_ARG = 200\n\nfunction isoTime(value) {\n if (typeof value !== 'number' || !Number.isFinite(value) || value <= 0) return null\n try { return new Date(value).toISOString() } catch { return null }\n}\n\nfunction yamlString(value) {\n return `\"${String(value).replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"').replace(/\\r?\\n/g, '\\\\n')}\"`\n}\n\nfunction blocksOf(value) {\n return Array.isArray(value) ? value.filter((b) => b && typeof b === 'object') : []\n}\n\n// Join the text blocks of a content array; image blocks are counted separately.\nfunction textFromBlocks(blocks) {\n const parts = []\n for (const block of blocks) {\n if (block.type === 'text' && typeof block.text === 'string') parts.push(block.text)\n }\n return parts.join('\\n\\n').trim()\n}\n\nfunction imageCountOf(blocks) {\n let count = 0\n for (const block of blocks) if (block.type === 'image') count++\n return count\n}\n\nfunction reasoningFromBlocks(blocks) {\n const parts = []\n for (const block of blocks) {\n if (block.type === 'reasoning' && typeof block.text === 'string' && block.text.trim()) parts.push(block.text.trim())\n }\n return parts.join('\\n\\n')\n}\n\n// A short, human-usable summary of one tool call's arguments.\nexport function summarizeToolArguments(name, rawArguments) {\n let parsed = null\n if (typeof rawArguments === 'string') {\n try { parsed = JSON.parse(rawArguments) } catch { parsed = null }\n } else if (rawArguments && typeof rawArguments === 'object') {\n parsed = rawArguments\n }\n if (parsed === null) return typeof rawArguments === 'string' ? rawArguments.slice(0, MAX_TOOL_ARG) : ''\n if (typeof parsed !== 'object') return String(parsed).slice(0, MAX_TOOL_ARG)\n const preferred = ['command', 'file_path', 'path', 'query', 'url', 'pattern']\n for (const key of preferred) {\n if (typeof parsed[key] === 'string' && parsed[key].trim()) return parsed[key]\n }\n const keys = Object.keys(parsed)\n if (keys.length === 0) return ''\n const rest = {}\n for (const key of keys.slice(0, 6)) {\n const value = parsed[key]\n rest[key] = typeof value === 'string' ? value : JSON.stringify(value)\n }\n return JSON.stringify(rest).slice(0, MAX_TOOL_ARG)\n}\n\n// Shared event fold. `out` accumulates markdown lines; both the one-shot\n// renderer and the streaming builder (large-log export, see export-md route)\n// consume it so their output is byte-identical for the same events.\nfunction createMarkdownFold(out, header, options) {\n const includeReasoning = options.includeReasoning === true\n const includeToolResults = options.includeToolResults === true\n let title = typeof header.title === 'string' && header.title.trim() ? header.title.trim() : null\n let turn = null\n return {\n get title() { return title },\n // The last session/title event wins \u2014 DSH may retitle a session later on.\n add(events) {\n const list = Array.isArray(events) ? events : []\n for (const ev of list) {\n if (!ev || typeof ev !== 'object') continue\n const data = ev.data && typeof ev.data === 'object' ? ev.data : {}\n const type = ev.type\n\n if (type === 'session/title' && data && typeof data.title === 'string' && data.title.trim()) {\n title = data.title.trim()\n continue\n }\n\n if (type === 'turn/start') {\n const next = Number.isInteger(data.turn) ? data.turn : null\n if (next !== null && next !== turn) {\n turn = next\n out.push('', `## \u7B2C ${turn} \u8F6E`)\n }\n continue\n }\n\n if (type === 'user/message') {\n const blocks = blocksOf(data.content)\n const text = textFromBlocks(blocks)\n const images = imageCountOf(blocks)\n if (!text && images === 0) continue\n out.push('', '### \u7528\u6237', '')\n if (text) out.push(text)\n for (let i = 0; i < images; i++) out.push('', ``)\n continue\n }\n\n if (type === 'assistant/message') {\n const message = data.message && typeof data.message === 'object' ? data.message : {}\n const blocks = blocksOf(message.content)\n const text = textFromBlocks(blocks)\n const reasoning = includeReasoning ? reasoningFromBlocks(blocks) : ''\n if (!text && !reasoning) continue\n out.push('', '### \u52A9\u624B', '')\n if (reasoning) out.push('> \u601D\u8003\uFF1A' + reasoning.split('\\n').join('\\n> '), '')\n if (text) out.push(text)\n continue\n }\n\n if (type === 'tool/call') {\n const name = typeof data.name === 'string' && data.name ? data.name : 'tool'\n const summary = summarizeToolArguments(name, data.arguments)\n out.push('', `### \u5DE5\u5177\u8C03\u7528\uFF1A\\`${name}\\``, '')\n out.push(summary ? '```\\n' + summary + '\\n```' : '\uFF08\u65E0\u53C2\u6570\uFF09')\n continue\n }\n\n if (type === 'tool/result' && includeToolResults) {\n const message = data.message && typeof data.message === 'object' ? data.message : {}\n const blocks = blocksOf(message.content)\n let text = ''\n for (const block of blocks) {\n if (block.type === 'tool-result') text = textFromBlocks(blocksOf(block.content))\n }\n if (text) out.push('', '<details><summary>\u5DE5\u5177\u7ED3\u679C</summary>', '', '```\\n' + text.slice(0, 2000) + '\\n```', '', '</details>')\n }\n }\n },\n }\n}\n\n/**\n * Render one session as Markdown.\n * @param {object} meta - Session header (`{ id, cwd, createdAt, title? }`).\n * @param {Array<object>} events - Session events as stored in the log.\n * @param {object} [options]\n * @param {boolean} [options.includeReasoning=false] - Emit assistant reasoning blocks.\n * @param {boolean} [options.includeToolResults=false] - Emit tool results.\n * @param {number} [options.exportedAt] - Override the export timestamp (tests).\n * @returns {string} Markdown document.\n */\nexport function renderSessionMarkdown(meta, events, options = {}) {\n const header = meta && typeof meta === 'object' ? meta : {}\n const out = []\n\n const fold = createMarkdownFold(out, header, options)\n fold.add(events)\n const title = fold.title\n\n const front = ['---']\n if (title) front.push(`title: ${yamlString(title)}`)\n if (typeof header.id === 'string' && header.id) front.push(`sessionId: ${yamlString(header.id)}`)\n if (typeof header.cwd === 'string' && header.cwd) front.push(`cwd: ${yamlString(header.cwd)}`)\n const created = isoTime(header.createdAt)\n if (created) front.push(`createdAt: ${created}`)\n const exported = isoTime(options.exportedAt)\n if (exported) front.push(`exportedAt: ${exported}`)\n front.push('---')\n\n const doc = [front.join('\\n')]\n if (title) doc.push('', `# ${title}`)\n doc.push(...out, '')\n return doc.join('\\n')\n}\n\n/**\n * Streaming variant of {@link renderSessionMarkdown} for chunked log reads\n * (SessionHandle.read offset/length). Feed event batches in log order via\n * `addEvents`; call `finish()` to get the same markdown document the one-shot\n * renderer would produce. Only the final title (last session/title event)\n * lands in the front matter, so streaming cannot be wrong about it.\n *\n * `finish(metaOverride)` \u2014 when the caller streams first and only learns the\n * authoritative header afterwards (adapter inspectSession returns `meta` with\n * the summary), pass it here; it replaces the constructor `meta` for the front\n * matter fields (id / cwd / createdAt). Title always comes from the folded\n * events, never from the override.\n */\nexport function createSessionMarkdownBuilder(meta, options = {}) {\n const header = meta && typeof meta === 'object' ? meta : {}\n const body = []\n const fold = createMarkdownFold(body, header, options)\n return {\n addEvents(events) { fold.add(events) },\n finish(metaOverride) {\n const effective = metaOverride && typeof metaOverride === 'object' ? metaOverride : header\n const title = fold.title\n const front = ['---']\n if (title) front.push(`title: ${yamlString(title)}`)\n if (typeof effective.id === 'string' && effective.id) front.push(`sessionId: ${yamlString(effective.id)}`)\n if (typeof effective.cwd === 'string' && effective.cwd) front.push(`cwd: ${yamlString(effective.cwd)}`)\n const created = isoTime(effective.createdAt)\n if (created) front.push(`createdAt: ${created}`)\n const exported = isoTime(options.exportedAt)\n if (exported) front.push(`exportedAt: ${exported}`)\n front.push('---')\n const doc = [front.join('\\n')]\n if (title) doc.push('', `# ${title}`)\n doc.push(...body, '')\n return doc.join('\\n')\n },\n }\n}\n", "// Durable \"starred sessions\" index (schema v3).\n//\n// Deliberately mirrors the recycle-bin index in src/index.js: version field,\n// automatic upgrade of older shapes, atomic write (tmp + rename) and a single\n// chained mutation queue so two concurrent requests can never clobber each\n// other. Extracted from the host bundle so it can be unit-tested directly \u2014\n// pass `dir` to point the index at a temp directory.\nimport { mkdir, rename, writeFile } from 'node:fs/promises'\nimport { readFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\n\n// v3 is the first star schema; it starts at 3 so it can never be confused with\n// the recycle bin's v1/v2 documents even if a file is copied between them.\nexport const STAR_SCHEMA_VERSION = 3\n\nconst DEFAULT_STAR_DIR = join(homedir(), '.dsh', 'sessions-manager')\n\nfunction isSafeSessionId(value) {\n return typeof value === 'string' && value.length > 0 && value.length <= 200 && !/[\\\\/\\0]/.test(value) && value !== '.' && value !== '..'\n}\n\n/**\n * Coerce anything on disk (or nothing at all) into a valid v3 store.\n * Accepts a bare array of ids (the pre-schema shape) and upgrades it.\n */\nexport function normalizeStarStore(raw) {\n const legacy = Array.isArray(raw) ? raw : null\n const source = legacy || (raw && typeof raw === 'object' ? raw : null)\n const ids = source && Array.isArray(source.starredSessionIds) ? source.starredSessionIds : (legacy || [])\n const clean = []\n const seen = new Set()\n for (const id of ids) {\n // Strings only: silently coercing a number into an id would let junk into\n // the index and mask a caller bug.\n if (!isSafeSessionId(id)) continue\n if (seen.has(id)) continue\n seen.add(id)\n clean.push(id)\n }\n return { schemaVersion: STAR_SCHEMA_VERSION, starredSessionIds: clean }\n}\n\n/**\n * Open the star index.\n * @param {object} [options]\n * @param {string} [options.dir] - Directory holding the index (tests inject a temp dir).\n * @param {string} [options.indexPath] - Full index path, overriding `dir`.\n */\nexport function createStarIndex(options = {}) {\n const dir = options.dir || process.env.DSH_SESSIONS_MANAGER_STAR_DIR || DEFAULT_STAR_DIR\n const indexPath = options.indexPath || join(dir, 'star.json')\n let mutation = Promise.resolve()\n\n async function read() {\n try {\n return normalizeStarStore(JSON.parse(readFileSync(indexPath, 'utf8')))\n } catch {\n return normalizeStarStore(null)\n }\n }\n\n async function write(store) {\n await mkdir(dir, { recursive: true })\n const tmp = join(dir, `.star-${process.pid}-${Date.now()}.tmp`)\n await writeFile(tmp, JSON.stringify(normalizeStarStore(store), null, 2), { encoding: 'utf8', mode: 0o600 })\n await rename(tmp, indexPath)\n }\n\n // Serialize read-modify-write cycles: every mutator sees the store as left by\n // the previous one, and a rejected mutator still keeps the chain alive.\n function mutate(mutator) {\n const operation = mutation.then(async () => {\n const store = await read()\n const result = await mutator(store)\n await write(store)\n return result\n })\n mutation = operation.catch(() => {})\n return operation\n }\n\n /**\n * Star or unstar sessions.\n * @param {string[]} ids - Session ids to change.\n * @param {boolean} starred - true to star, false to unstar.\n * @returns {Promise<string[]>} The full starred set after the change.\n */\n function setStarred(ids, starred) {\n const wanted = (Array.isArray(ids) ? ids : []).filter(isSafeSessionId).map(String)\n return mutate((store) => {\n const set = new Set(store.starredSessionIds)\n for (const id of wanted) {\n if (starred) set.add(id)\n else set.delete(id)\n }\n store.starredSessionIds = [...set]\n return store.starredSessionIds\n })\n }\n\n // Drop ids once their session is gone (purged / deleted), otherwise the index\n // would grow forever with ids that can never be listed again.\n function removeIds(ids) {\n return setStarred(ids, false)\n }\n\n return { read, write, mutate, setStarred, removeIds, indexPath, dir }\n}\n", "// Storage usage aggregation (pure, no I/O).\n//\n// Kept out of the host bundle so it can be unit-tested directly\n// (tests/storage-stats.test.js). Takes the session items the host already\n// builds (with `sizeBytes` filled in) and rolls them up per workspace plus a\n// \"largest sessions\" leaderboard.\n//\n// Sessions without a workspace path land in a single \"\u672A\u5206\u7EC4\" bucket \u2014 that is\n// DSH's own label for orphans, so the panel speaks the same language as the\n// sidebar.\n\nexport const UNGROUPED_KEY = '__ungrouped__'\n\nfunction isFiniteSize(value) {\n return typeof value === 'number' && Number.isFinite(value) && value >= 0\n}\n\n/**\n * Roll session sizes up per workspace and pick the largest sessions.\n *\n * @param {Array<{sessionId: string, title?: string|null, workspacePath?: string|null,\n * workspaceTitle?: string|null, sizeBytes?: number|null}>} items\n * @param {object} [options]\n * @param {number} [options.topN=10] - How many entries the leaderboard holds.\n * @returns {{\n * totalBytes: number,\n * sessionCount: number,\n * sizedSessions: number,\n * unknownSessions: number,\n * workspaces: Array<{key: string, path: string|null, title: string|null,\n * bytes: number, sessions: number, share: number}>,\n * top: Array<{sessionId: string, title: string|null, workspacePath: string|null,\n * workspaceTitle: string|null, sizeBytes: number}>\n * }}\n */\nexport function aggregateStorage(items, options = {}) {\n const topN = Number.isInteger(options.topN) && options.topN > 0 ? options.topN : 10\n const list = Array.isArray(items) ? items : []\n\n const buckets = new Map()\n const sized = []\n let totalBytes = 0\n let unknownSessions = 0\n // Counted entries only: sessionCount must always equal\n // sizedSessions + unknownSessions, or the panel would show a total that\n // disagrees with its own breakdown.\n let counted = 0\n\n for (const item of list) {\n if (!item || item.sessionId == null) continue\n counted++\n const id = String(item.sessionId)\n const path = item.workspacePath ? String(item.workspacePath) : null\n const key = path || UNGROUPED_KEY\n\n let bucket = buckets.get(key)\n if (!bucket) {\n bucket = { key, path, title: item.workspaceTitle ? String(item.workspaceTitle) : null, bytes: 0, sessions: 0 }\n buckets.set(key, bucket)\n }\n bucket.sessions++\n\n if (isFiniteSize(item.sizeBytes)) {\n bucket.bytes += item.sizeBytes\n totalBytes += item.sizeBytes\n sized.push({\n sessionId: id,\n title: item.title || null,\n workspacePath: path,\n workspaceTitle: bucket.title,\n sizeBytes: item.sizeBytes,\n })\n } else {\n unknownSessions++\n }\n }\n\n const workspaces = [...buckets.values()]\n .sort((a, b) => (b.bytes - a.bytes) || (b.sessions - a.sessions) || a.key.localeCompare(b.key))\n .map((bucket) => ({ ...bucket, share: totalBytes > 0 ? bucket.bytes / totalBytes : 0 }))\n\n const top = sized\n .sort((a, b) => (b.sizeBytes - a.sizeBytes) || a.sessionId.localeCompare(b.sessionId))\n .slice(0, topN)\n\n return {\n totalBytes,\n sessionCount: counted,\n sizedSessions: sized.length,\n unknownSessions,\n workspaces,\n top,\n }\n}\n", "// Durable \"auto-archive\" settings (schema v4) + the pure candidate rule.\n//\n// Auto-archive hides conversations that have been idle for N days. It is OFF\n// by default: archiving rewrites durable workspace state, so the plugin must\n// never touch a conversation the user has not asked it to.\n//\n// Deliberately mirrors the star index (src/star-index.js): version field,\n// defensive coercion of whatever is on disk, atomic write (tmp + rename) and a\n// single chained mutation queue. The candidate rule lives here as a pure\n// function so it can be tested without a DSH host.\nimport { mkdir, rename, writeFile } from 'node:fs/promises'\nimport { readFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\n\n// v4 keeps clear of the recycle bin's v1/v2 and the star index's v3, so a\n// copied or mixed-up file can never be silently accepted as another store.\nexport const AUTO_ARCHIVE_SCHEMA_VERSION = 4\n\n// Allowed idle windows. 0 = disabled. Deliberately coarse: a free-form number\n// would let a typo schedule archiving \"tomorrow\" for every conversation.\nexport const INACTIVE_DAY_OPTIONS = Object.freeze([0, 30, 60, 90])\n\nconst DAY_MS = 86400000\n// Re-run at most once per day: the sweep is triggered by panel reads, and a\n// user flipping settings back and forth must not archive in a loop.\nexport const RUN_INTERVAL_MS = DAY_MS\n\nconst DEFAULT_DIR = join(homedir(), '.dsh', 'sessions-manager')\n\n/**\n * Coerce anything on disk (or nothing at all) into a valid v4 store.\n */\nexport function normalizeAutoArchiveStore(raw) {\n const source = raw && typeof raw === 'object' && !Array.isArray(raw) ? raw : {}\n const settings = source.settings && typeof source.settings === 'object' ? source.settings : {}\n const inactiveDays = INACTIVE_DAY_OPTIONS.includes(settings.inactiveDays) ? settings.inactiveDays : 0\n return {\n schemaVersion: AUTO_ARCHIVE_SCHEMA_VERSION,\n settings: {\n inactiveDays,\n // Starred sessions are an explicit \"keep\" mark, so they are skipped\n // unless the user opts out.\n skipStarred: settings.skipStarred !== false,\n },\n lastRunAt: Number.isFinite(source.lastRunAt) ? source.lastRunAt : null,\n lastArchivedCount: Number.isInteger(source.lastArchivedCount) && source.lastArchivedCount >= 0 ? source.lastArchivedCount : 0,\n }\n}\n\n/**\n * Which sessions should be auto-archived right now? Pure \u2014 no I/O, no host.\n *\n * The rule is intentionally conservative: anything we cannot prove is idle\n * (unknown last-activity, already archived, starred, currently open) is left\n * alone. A wrong archive is a visible regression; a missed one is invisible.\n *\n * @param {Array<{sessionId: string, archived?: boolean, starred?: boolean,\n * updatedAt?: number|null}>} items\n * @param {object} options\n * @param {number} options.inactiveDays - Idle window in days (0 disables).\n * @param {number} [options.now] - Reference timestamp (tests inject it).\n * @param {boolean} [options.skipStarred=true] - Keep starred sessions.\n * @param {string|null} [options.activeSessionId] - Never archive the open one.\n * @returns {string[]} Session ids to archive.\n */\nexport function pickInactiveCandidates(items, options = {}) {\n const days = options.inactiveDays\n if (!INACTIVE_DAY_OPTIONS.includes(days) || days === 0) return []\n const now = Number.isFinite(options.now) ? options.now : Date.now()\n const cutoff = now - days * DAY_MS\n const skipStarred = options.skipStarred !== false\n const activeId = options.activeSessionId != null ? String(options.activeSessionId) : null\n const list = Array.isArray(items) ? items : []\n\n const out = []\n const seen = new Set()\n for (const item of list) {\n if (!item || item.sessionId == null) continue\n const id = String(item.sessionId)\n if (seen.has(id)) continue\n if (item.archived) continue\n if (skipStarred && item.starred) continue\n if (activeId !== null && id === activeId) continue\n const updatedAt = Number(item.updatedAt)\n // No usable timestamp \u2192 cannot prove it is idle \u2192 leave it alone.\n if (!Number.isFinite(updatedAt) || updatedAt <= 0) continue\n if (updatedAt < cutoff) { seen.add(id); out.push(id) }\n }\n return out\n}\n\n/**\n * Open the auto-archive settings store.\n * @param {object} [options]\n * @param {string} [options.dir] - Directory holding the index (tests inject a temp dir).\n * @param {string} [options.indexPath] - Full index path, overriding `dir`.\n */\nexport function createAutoArchiveStore(options = {}) {\n const dir = options.dir || process.env.DSH_SESSIONS_MANAGER_AUTO_ARCHIVE_DIR || DEFAULT_DIR\n const indexPath = options.indexPath || join(dir, 'auto-archive.json')\n let mutation = Promise.resolve()\n\n async function read() {\n try {\n return normalizeAutoArchiveStore(JSON.parse(readFileSync(indexPath, 'utf8')))\n } catch {\n return normalizeAutoArchiveStore(null)\n }\n }\n\n async function write(store) {\n await mkdir(dir, { recursive: true })\n const tmp = join(dir, `.auto-archive-${process.pid}-${Date.now()}.tmp`)\n await writeFile(tmp, JSON.stringify(normalizeAutoArchiveStore(store), null, 2), { encoding: 'utf8', mode: 0o600 })\n await rename(tmp, indexPath)\n }\n\n function mutate(mutator) {\n const operation = mutation.then(async () => {\n const store = await read()\n const result = await mutator(store)\n await write(store)\n return result\n })\n mutation = operation.catch(() => {})\n return operation\n }\n\n /**\n * Merge a partial settings patch.\n * @param {{inactiveDays?: number, skipStarred?: boolean}} patch\n * @returns {Promise<object>} The store's settings after the change.\n */\n function update(patch = {}) {\n return mutate((store) => {\n if (Object.prototype.hasOwnProperty.call(patch, 'inactiveDays')) {\n const days = Number(patch.inactiveDays)\n if (!INACTIVE_DAY_OPTIONS.includes(days)) {\n const error = new Error(`inactiveDays \u4EC5\u652F\u6301 ${INACTIVE_DAY_OPTIONS.join('\u3001')}`)\n error.status = 400\n throw error\n }\n store.settings.inactiveDays = days\n }\n if (Object.prototype.hasOwnProperty.call(patch, 'skipStarred')) {\n store.settings.skipStarred = !!patch.skipStarred\n }\n return store.settings\n })\n }\n\n /** Record that a sweep ran, so the once-a-day throttle can skip the next one. */\n function recordRun(count, at = Date.now()) {\n return mutate((store) => {\n store.lastRunAt = at\n store.lastArchivedCount = Number.isInteger(count) && count >= 0 ? count : 0\n return store\n })\n }\n\n /** True when a sweep already ran within RUN_INTERVAL_MS. */\n function isFresh(store, now = Date.now()) {\n return Number.isFinite(store && store.lastRunAt) && (now - store.lastRunAt) < RUN_INTERVAL_MS\n }\n\n return { read, write, mutate, update, recordRun, isFresh, indexPath, dir }\n}\n", "// session-meta-cache.js \u2014 \u4F1A\u8BDD\u300C\u539F\u59CB\u5143\u6570\u636E\u300D\u5185\u5B58\u7F13\u5B58\uFF08\u6309\u65E5\u5FD7\u5185\u5BB9\u6307\u7EB9\u6821\u9A8C\uFF09\u3002\n//\n// \u80CC\u666F\uFF08issue #1\uFF09\uFF1A\u5217\u8868\u6784\u5EFA\u539F\u672C\u5BF9\u6BCF\u6761\u4F1A\u8BDD\u8C03\u7528 readTitleSnapshot\uFF0C\u800C\u8BE5\u8C03\u7528\u4F1A\u628A\n// \u4F1A\u8BDD\u65E5\u5FD7\uFF08.jsonl.zstd\uFF09\u7684**\u6240\u6709 zstd \u5E27**\u9010\u5E27\u89E3\u538B\u3001\u9010\u884C JSON.parse\uFF0C\u53EA\u4E3A\u6298\u53E0\u51FA\n// \u6700\u65B0\u6807\u9898\u3002\u5927\u5E93\uFF08\u6570\u5341\u6761\u4F1A\u8BDD\u3001\u5341\u4E07\u7EA7\u5E27\uFF09\u4E00\u6B21\u5168\u8868\u8981\u51E0\u79D2 CPU\uFF0C\u4E14\u89E3\u7801\u662F\u540C\u6B65\u5757\uFF0C\n// \u4F1A\u963B\u585E\u5BBF\u4E3B\u4E8B\u4EF6\u5FAA\u73AF\uFF0C\u8FDE\u7D2F session.history \u4E4B\u7C7B\u7684 RPC \u8D85\u65F6\u3002\n//\n// \u6307\u7EB9\u6709\u4E24\u79CD\u6765\u6E90\uFF08\u6309 runtime \u80FD\u529B\u81EA\u52A8\u9009\u62E9\uFF0C\u8C03\u7528\u65B9\u6784\u9020 stat \u5BF9\u8C61\uFF09\uFF1A\n//\n// 1. \u6587\u4EF6\u6307\u7EB9\uFF08legacy runtime\uFF09\uFF1A\u8BB0\u4E0B\u65E5\u5FD7\u7684 (mtimeMs, size)\u3002\u4EFB\u4F55\n// append/\u6539\u540D/\u79FB\u52A8\u90FD\u4F1A\u66F4\u65B0 mtime\uFF0C\u6240\u4EE5\u300Cstat \u76F8\u540C \u21D2 \u5185\u5BB9\u6CA1\u53D8\u300D\u3002\n// \u8BE5\u6307\u7EB9\u53EF\u8DE8\u8FDB\u7A0B\u6301\u4E45\u5316\uFF08title-persist-index \u7528\u5B83\u505A\u51B7\u542F\u52A8\u52A0\u901F\uFF09\u3002\n//\n// 2. revision \u6307\u7EB9\uFF08SessionHandle \u4E16\u4EE3 runtime\uFF0C0.1.3+\uFF09\uFF1AsessionPersistence\n// \u7684 list()/stat() \u8FD4\u56DE SessionPersistenceSnapshot\uFF0C\u5176 `revision` \u662F\n// **\u4E0D\u900F\u660E\u53D8\u66F4\u4EE4\u724C**\u3002\u5B98\u65B9\u5951\u7EA6\uFF1A\u540C\u4E00 service \u5B9E\u4F8B\u3001\u540C\u4E00 session id \u5185\uFF0C\n// revision \u76F8\u7B49\u53EF\u89C6\u4E3A\u65E5\u5FD7\u672A\u53D8\uFF1B\u9664\u6B64\u4E4B\u5916 revision \u4E0D\u505A\u4EFB\u4F55\u627F\u8BFA\u3002\n// \u26A0\uFE0F \u56E0\u6B64 revision \u6307\u7EB9**\u7EDD\u4E0D\u80FD\u5199\u5165\u8DE8\u8FDB\u7A0B\u7684\u6301\u4E45\u7F13\u5B58**\uFF08\u4E0D\u540C\u8FDB\u7A0B/\u91CD\u542F\u540E\n// revision \u503C\u65E0\u610F\u4E49\uFF0C\u8BEF\u7528\u53EF\u80FD\u628A\u9648\u65E7\u6570\u636E\u5F53\u65B0\u9C9C\u6570\u636E\uFF09\u3002\u6301\u4E45\u7D22\u5F15\u843D\u76D8\u524D\u5FC5\u987B\n// \u7528 isPersistableFingerprint() \u8FC7\u6EE4\u3002\n//\n// \u4E3A\u4EC0\u4E48\u81EA\u5DF1\u5B9E\u73B0\u800C\u4E0D\u7528 runtime \u7684 prepared \u7F13\u5B58\uFF1A\u63D2\u4EF6\u4E0D\u80FD\u5047\u8BBE\u5BF9\u65B9\u7684 runtime \u7248\u672C\uFF0C\n// runtime \u4FA7\u7684\u7F13\u5B58\u5BB9\u91CF/\u547D\u4E2D\u7B56\u7565\u5404\u7248\u672C\u4E0D\u540C\u3002\u672C\u6A21\u5757\u53EA\u7528\u7EAF\u6570\u636E\u5224\u5B9A\uFF0C\u4EFB\u4F55\u7248\u672C\u884C\u4E3A\u4E00\u81F4\u3002\n//\n// \u5931\u6548\u7B56\u7565\uFF1A\n// 1. \u6307\u7EB9\u6821\u9A8C\uFF1Arevision \u4E0D\u76F8\u7B49 / mtimeMs \u6216 size \u4EFB\u4E00\u53D8\u5316\u5373\u89C6\u4E3A\u8FC7\u671F\n// 2. TTL\uFF1A\u4EC5\u5BF9\u6587\u4EF6\u6307\u7EB9\u751F\u6548\uFF08\u9632 mtime \u7CBE\u5EA6/\u65F6\u949F\u56DE\u62E8\uFF09\uFF1Brevision \u76F8\u7B49\u5373\u6743\u5A01\uFF0C\n// \u4E0D\u53D7 TTL \u5F71\u54CD\uFF08\u5B98\u65B9\u5951\u7EA6\u660E\u6587\u5141\u8BB8 treat equal revisions as unchanged\uFF09\n// 3. \u663E\u5F0F invalidate\uFF1A\u5220\u9664 / \u79FB\u52A8 / \u5F52\u6863\u7B49\u5BBF\u4E3B\u64CD\u4F5C\u540E\u4E3B\u52A8\u4E22\u5F03\u5BF9\u5E94\u6761\u76EE\n//\n// \u7EAF\u903B\u8F91\u4E0E\u526F\u4F5C\u7528\u5206\u79BB\uFF1AisFresh / partitionByCache \u90FD\u662F\u7EAF\u51FD\u6570\uFF0C\u4FBF\u4E8E\u5355\u6D4B\u3002\n\nconst DEFAULT_TTL_MS = 5 * 60 * 1000\nconst DEFAULT_MAX = 4000\n\nconst REVISION_PREFIX = 'rev:'\n\n// \u6587\u4EF6\u6307\u7EB9\uFF1A\u53EA\u6709\u540C\u65F6\u62FF\u5230 mtime \u4E0E size \u624D\u53EF\u4FE1\u3002\n// \u62FF\u4E0D\u5230 stat \u4FE1\u606F\u65F6\u8FD4\u56DE null\u2014\u2014\u8868\u793A\u300C\u65E0\u6CD5\u6821\u9A8C\u300D\uFF0C\u8C03\u7528\u65B9\u5FC5\u987B\u6309\u672A\u547D\u4E2D\u5904\u7406\uFF0C\n// \u7EDD\u4E0D\u80FD\u5728\u6709\u7591\u95EE\u65F6\u8FD4\u56DE\u65E7\u6570\u636E\u3002\nexport function fingerprintOf(stat) {\n if (!stat || typeof stat !== 'object') return null\n // revision \u6307\u7EB9\u4F18\u5148\uFF1ASessionHandle \u4E16\u4EE3\u6CA1\u6709\u53EF\u9760\u7684 locate/stat\uFF0C\n // snapshot.revision \u662F\u5B98\u65B9\u63D0\u4F9B\u7684\u552F\u4E00\u53D8\u66F4\u4EE4\u724C\u3002\n if (typeof stat.revision === 'string' && stat.revision.length > 0) {\n return REVISION_PREFIX + stat.revision\n }\n const mtimeMs = stat.mtimeMs\n const size = stat.size\n if (typeof mtimeMs !== 'number' || !Number.isFinite(mtimeMs) || mtimeMs <= 0) return null\n if (typeof size !== 'number' || !Number.isFinite(size) || size < 0) return null\n return `${Math.floor(mtimeMs)}:${size}`\n}\n\n// revision \u6307\u7EB9\u53EA\u5728\u5F53\u524D service \u5B9E\u4F8B\u5185\u6709\u610F\u4E49\uFF0C\u7EDD\u4E0D\u80FD\u843D\u76D8\u4F5C\u4E3A\u8DE8\u8FDB\u7A0B\u6307\u7EB9\u3002\n// title-persist-index \u7B49\u6301\u4E45\u5316\u5C42\u5FC5\u987B\u5728\u5199\u5165\u524D\u7528\u5B83\u8FC7\u6EE4\u3002\nexport function isPersistableFingerprint(fingerprint) {\n return typeof fingerprint === 'string' && fingerprint !== '' && !fingerprint.startsWith(REVISION_PREFIX)\n}\n\n// \u7F13\u5B58\u6761\u76EE\u662F\u5426\u4ECD\u7136\u65B0\u9C9C\uFF08\u7EAF\u51FD\u6570\uFF09\u3002\n// stat \u4F20 { revision } \u6216 { mtimeMs, size }\uFF1B\u4E24\u7C7B\u6307\u7EB9\u4E0D\u80FD\u4E92\u76F8\u5339\u914D\u3002\nexport function isFresh(entry, stat, now, ttlMs = DEFAULT_TTL_MS) {\n if (!entry) return false\n const fp = fingerprintOf(stat)\n if (!fp) return false\n if (entry.fingerprint !== fp) return false\n if (typeof entry.at !== 'number') return false\n // revision \u6307\u7EB9\u4E0D\u53D7 TTL \u7EA6\u675F\uFF1A\u5951\u7EA6\u5141\u8BB8\u628A\u76F8\u7B49 revision \u89C6\u4E3A\u65E5\u5FD7\u672A\u53D8\u3002\n if (fp.startsWith(REVISION_PREFIX)) return true\n return (now - entry.at) <= ttlMs\n}\n\n// \u628A\u4E00\u6279 id \u5206\u6210\u300C\u547D\u4E2D\u7F13\u5B58\u300D\u4E0E\u300C\u9700\u8981\u89E3\u7801\u300D\u4E24\u7EC4\uFF08\u7EAF\u51FD\u6570\uFF0C\u4FBF\u4E8E\u5355\u6D4B\uFF09\u3002\n// statsById: Map<id, {mtimeMs, size} | {revision}>\uFF1Bcache: \u4E0E SessionMetaCache \u540C\u6784\u7684 Map\u3002\nexport function partitionByCache(ids, statsById, cache, now = Date.now(), ttlMs = DEFAULT_TTL_MS) {\n const cached = new Map()\n const missing = []\n for (const id of ids) {\n const entry = cache && cache.get(String(id))\n const stat = statsById && statsById.get(String(id))\n if (isFresh(entry, stat, now, ttlMs) && entry && entry.meta) {\n cached.set(String(id), entry.meta)\n } else {\n missing.push(String(id))\n }\n }\n return { cached, missing }\n}\n\nexport function createSessionMetaCache(opts = {}) {\n const ttlMs = Number.isFinite(opts.ttlMs) ? opts.ttlMs : DEFAULT_TTL_MS\n const max = Number.isInteger(opts.max) && opts.max > 0 ? opts.max : DEFAULT_MAX\n const map = new Map()\n let hits = 0\n let misses = 0\n\n return {\n // \u547D\u4E2D\u8FD4\u56DE meta\uFF0C\u672A\u547D\u4E2D/\u65E0\u6CD5\u6821\u9A8C\u8FD4\u56DE null\u3002\n get(id, stat) {\n const key = String(id)\n const entry = map.get(key)\n if (isFresh(entry, stat, Date.now(), ttlMs)) {\n hits++\n // LRU\uFF1A\u547D\u4E2D\u540E\u79FB\u5230\u672B\u5C3E\uFF0C\u5BB9\u91CF\u6EE1\u65F6\u4F18\u5148\u6DD8\u6C70\u6700\u4E45\u672A\u7528\u3002\n map.delete(key)\n map.set(key, entry)\n return entry.meta\n }\n misses++\n return null\n },\n set(id, stat, meta) {\n if (!meta) return null\n const fp = fingerprintOf(stat)\n // \u65E0\u6CD5\u7B97\u51FA\u6307\u7EB9\uFF08\u6CA1 stat / revision \u7F3A\u5931 / stat \u5931\u8D25\uFF09\u65F6\u4E0D\u5199\u7F13\u5B58\uFF1A\n // \u5199\u8FDB\u53BB\u5C31\u518D\u4E5F\u65E0\u6CD5\u53EF\u9760\u5931\u6548\u3002\n if (!fp) return null\n const key = String(id)\n map.delete(key)\n map.set(key, { fingerprint: fp, at: Date.now(), meta })\n if (map.size > max) {\n // \u6DD8\u6C70\u6700\u4E45\u672A\u7528\u7684\u4E00\u4E2A\uFF08Map \u4FDD\u6301\u63D2\u5165\u987A\u5E8F\uFF0C\u9996\u4E2A\u5373\u6700\u65E7\uFF09\u3002\n const oldest = map.keys().next().value\n if (oldest !== undefined) map.delete(oldest)\n }\n return meta\n },\n // \u6279\u91CF\u5224\u5B9A\uFF1A\u4E00\u6B21\u7B97\u51FA\u300C\u547D\u4E2D\u7F13\u5B58\u300D\u4E0E\u300C\u9700\u8981\u89E3\u7801\u300D\u4E24\u7EC4\uFF0C\u4F9B\u5217\u8868\u6784\u5EFA\u505A\u6279\u91CF\u6295\u5F71\u3002\n partition(ids, statsById) {\n return partitionByCache(ids, statsById, map, Date.now(), ttlMs)\n },\n invalidate(id) {\n if (id == null) return false\n const key = String(id)\n const had = map.has(key)\n map.delete(key)\n return had\n },\n clear() { map.clear() },\n get size() { return map.size },\n stats() { return { size: map.size, hits, misses, ttlMs } },\n }\n}\n", "// title-persist-index.js \u2014 \u4F1A\u8BDD\u6807\u9898/\u5143\u6570\u636E\u7684**\u78C1\u76D8**\u5C0F\u7D22\u5F15\uFF08P4\uFF0Cissue #1\uFF09\u3002\n//\n// metaCache\uFF08session-meta-cache.js\uFF09\u89E3\u51B3\u7684\u662F\u300C\u8FDB\u7A0B\u5185\u91CD\u590D\u89E3\u7801\u300D\uFF1B\u672C\u6A21\u5757\u89E3\u51B3\n// \u7684\u662F\u51B7\u542F\u52A8\uFF1A\u63D2\u4EF6\u91CD\u542F\u540E\u5185\u5B58\u7F13\u5B58\u4E3A\u7A7A\uFF0C\u7B2C\u4E00\u6B21\u5217\u8868\u6784\u5EFA\u4ECD\u8981\u5168\u5E93\u89E3\u7801\u4E00\u6B21\u3002\n// \u628A\u89E3\u7801\u51FA\u7684\u5143\u6570\u636E\u8FDE\u540C\u6587\u4EF6\u6307\u7EB9\u539F\u5B50\u5199\u8FDB\u4E00\u4E2A JSON \u7D22\u5F15\uFF0C\u91CD\u542F\u540E\u5217\u8868\u53EA\u9700\n// \u4E00\u6B21\u7D22\u5F15\u8BFB + \u6307\u7EB9\u6BD4\u5BF9\uFF0C\u6307\u7EB9\u6CA1\u53D8\u7684\u4F1A\u8BDD\u96F6\u89E3\u7801\u3002\n//\n// \u7ED3\u6784\u4EFF trash \u7684\u539F\u5B50\u5199\u7D22\u5F15\uFF1A{ schemaVersion, entries: { [sessionId]: entry } }\n// entry = { title, cwd, createdAt, fingerprint, updatedAt }\n// fingerprint \u5373 session-meta-cache.js \u7684 fingerprintOf(stat) \u4EA7\u51FA\n// \uFF08\"<mtimeMs>:<size>\"\uFF09\uFF0C\u6BD4\u5BF9\u4E00\u81F4\u5373\u53EF\u4FE1\u4EFB\u6761\u76EE\u5185\u5BB9\u3002\n//\n// \u5199\u5165\u65F6\u673A\u7531\u8C03\u7528\u65B9\u51B3\u5B9A\uFF08\u5217\u8868\u6784\u5EFA\u6536\u5C3E\u6279\u91CF\u56DE\u5199\u3001purge \u65F6\u6E05\u7406\uFF09\uFF0C\u672C\u6A21\u5757\u53EA\n// \u63D0\u4F9B\uFF1A\u8BFB\u53D6\u7F13\u5B58\u3001\u5408\u5E76\u5199\u5165\uFF08\u4E32\u884C\u5316 + \u539F\u5B50\u66FF\u6362\uFF09\u3001\u6309 id \u5220\u9664\u3002\u4EFB\u4F55\u6587\u4EF6\n// \u635F\u574F\u90FD\u6309\u7A7A\u7D22\u5F15\u5904\u7406\uFF0C\u7EDD\u4E0D\u963B\u585E\u5217\u8868\u6784\u5EFA\u3002\n//\n// \u5355\u5B9E\u4F8B\u5047\u8BBE\uFF1A\u4E00\u4E2A\u8FDB\u7A0B\u5185\u53EA apply \u4E00\u4E2A\u63D2\u4EF6\u5B9E\u4F8B\uFF08\u751F\u4EA7\u5373\u5982\u6B64\uFF09\uFF0C\u5B9E\u4F8B\u95F4\u7684\n// \u5185\u5B58\u526F\u672C\u4E0D\u4E92\u76F8\u540C\u6B65\u2014\u2014\u8DE8\u300C\u91CD\u542F\u300D\u4EE5\u843D\u76D8\u5185\u5BB9\u4E3A\u51C6\uFF08\u6D4B\u8BD5\u4EA6\u6309\u6B64\u65AD\u8A00\uFF09\u3002\n\nimport { mkdir, readFile, rename, writeFile } from 'node:fs/promises'\nimport { dirname, join } from 'node:path'\n\nexport const TITLE_INDEX_SCHEMA_VERSION = 1\n\nconst MAX_ENTRIES = 20000\n\n// \u6761\u76EE\u53EA\u4FDD\u7559\u53EF\u5E8F\u5217\u5316\u4E14\u5BF9\u5217\u8868\u6709\u7528\u7684\u5B57\u6BB5\uFF1B\u6307\u7EB9\u7F3A\u5931\u7684\u6761\u76EE\u65E0\u6CD5\u6821\u9A8C\uFF0C\u76F4\u63A5\u4E22\u5F03\u2014\u2014\n// \u5B81\u53EF\u4E0B\u6B21\u91CD\u89E3\u7801\uFF0C\u4E5F\u4E0D\u80FD\u628A\u65E0\u6CD5\u5931\u6548\u7684\u6570\u636E\u5F53\u771F\u3002\n// \u26A0\uFE0F revision \u6307\u7EB9\uFF08\"rev:\u2026\"\uFF09\u53EA\u5728\u5F53\u524D service \u5B9E\u4F8B\u5185\u6709\u610F\u4E49\uFF08\u5B98\u65B9 0.1.3 \u5951\u7EA6\uFF1A\n// opaque token, same instance + same session id\uFF09\uFF0C\u7EDD\u4E0D\u80FD\u843D\u76D8\u4F5C\u4E3A\u8DE8\u8FDB\u7A0B\u6307\u7EB9\u2014\u2014\n// \u8FD9\u91CC\u4F5C\u4E3A\u6700\u540E\u9632\u7EBF\u518D\u6B21\u62E6\u622A\uFF08\u8C03\u7528\u65B9 session-meta-cache.isPersistableFingerprint\n// \u5DF2\u5148\u884C\u8FC7\u6EE4\uFF09\u3002\nexport function normalizeEntry(raw) {\n if (!raw || typeof raw !== 'object') return null\n const title = typeof raw.title === 'string' ? raw.title : null\n const cwd = typeof raw.cwd === 'string' ? raw.cwd : null\n const createdAt = typeof raw.createdAt === 'number' ? raw.createdAt : null\n const fingerprint = typeof raw.fingerprint === 'string' && raw.fingerprint ? raw.fingerprint : null\n const updatedAt = typeof raw.updatedAt === 'number' ? raw.updatedAt : 0\n if (!fingerprint || fingerprint.startsWith('rev:')) return null\n if (!title && !cwd) return null\n return { title, cwd, createdAt, fingerprint, updatedAt }\n}\n\nexport function normalizeTitleIndex(raw) {\n const entries = {}\n if (raw && typeof raw === 'object' && raw.entries && typeof raw.entries === 'object') {\n for (const [id, entry] of Object.entries(raw.entries)) {\n if (typeof id !== 'string' || !id || id.length > 200) continue\n const normalized = normalizeEntry(entry)\n if (normalized) entries[id] = normalized\n }\n }\n return { schemaVersion: TITLE_INDEX_SCHEMA_VERSION, entries }\n}\n\n// \u7EAF\u5408\u5E76\uFF1Aright \u8986\u76D6 left \u540C id \u6761\u76EE\uFF1B\u622A\u65AD\u5230 MAX_ENTRIES\uFF08\u4FDD\u7559 updatedAt \u65B0\u7684\uFF09\u3002\nexport function mergeEntries(left, right) {\n const merged = { ...left }\n for (const [id, entry] of Object.entries(right)) merged[id] = entry\n const ids = Object.keys(merged)\n if (ids.length > MAX_ENTRIES) {\n ids.sort((a, b) => (merged[a].updatedAt || 0) - (merged[b].updatedAt || 0))\n for (const id of ids.slice(0, ids.length - MAX_ENTRIES)) delete merged[id]\n }\n return merged\n}\n\nexport function createTitleIndexStore({ dir, file }) {\n let cache = null\n let chain = Promise.resolve()\n const path = file || join(dir, 'title-index.json')\n\n async function readRaw() {\n try {\n return normalizeTitleIndex(JSON.parse(await readFile(path, 'utf8')))\n } catch (e) {\n return normalizeTitleIndex(null)\n }\n }\n\n // \u6240\u6709\u5199\u64CD\u4F5C\u4E32\u884C\u5316\uFF08\u4EFF trash \u7684 mutate \u961F\u5217\uFF09\uFF0C\u907F\u514D\u5E76\u53D1 merge \u4E92\u76F8\u8986\u76D6\u3002\n function enqueue(mutator) {\n const operation = chain.then(async () => {\n const store = cache || (cache = (await readRaw()).entries)\n await mutator(store)\n return store\n })\n chain = operation.catch(() => {})\n return operation\n }\n\n return {\n // \u53EA\u8BFB\uFF1A\u5185\u5B58\u4F18\u5148\uFF0C\u672A\u52A0\u8F7D\u8FC7\u624D\u843D\u76D8\u4E00\u6B21\u3002\u7EDD\u4E0D\u629B\u9519\u3002\n async entries() {\n if (cache) return cache\n cache = (await readRaw()).entries\n return cache\n },\n // \u6279\u91CF\u5408\u5E76\u5199\u5165\uFF08\u539F\u5B50\u66FF\u6362\uFF09\u3002\u5931\u8D25\u9759\u9ED8\uFF1A\u7D22\u5F15\u53EA\u662F\u52A0\u901F\u5668\uFF0C\u574F\u4E86\u4E0B\u6B21\u91CD\u89E3\u7801\u3002\n async merge(batch) {\n const right = {}\n for (const [id, entry] of Object.entries(batch || {})) {\n const normalized = normalizeEntry(entry)\n if (normalized) right[String(id)] = normalized\n }\n if (!Object.keys(right).length) return false\n await enqueue(async (store) => {\n const next = mergeEntries(store, right)\n await mkdir(dirname(path), { recursive: true })\n const tmp = join(dirname(path), `.title-index-${process.pid}-${Date.now()}.tmp`)\n await writeFile(tmp, JSON.stringify({ schemaVersion: TITLE_INDEX_SCHEMA_VERSION, entries: next }), { encoding: 'utf8', mode: 0o600 })\n await rename(tmp, path)\n cache = next\n })\n return true\n },\n async remove(ids) {\n const wanted = new Set((ids || []).map(String))\n if (!wanted.size) return false\n await enqueue(async (store) => {\n let changed = false\n for (const id of wanted) {\n if (id in store) { delete store[id]; changed = true }\n }\n if (!changed) return\n await mkdir(dirname(path), { recursive: true })\n const tmp = join(dirname(path), `.title-index-${process.pid}-${Date.now()}.tmp`)\n await writeFile(tmp, JSON.stringify({ schemaVersion: TITLE_INDEX_SCHEMA_VERSION, entries: store }), { encoding: 'utf8', mode: 0o600 })\n await rename(tmp, path)\n })\n return true\n },\n }\n}\n\n// \u5224\u5B9A\u6301\u4E45\u6761\u76EE\u80FD\u5426\u5F53\u4F5C\u5F53\u524D\u65E5\u5FD7\u7684\u89E3\u7801\u7ED3\u679C\uFF1A\u6307\u7EB9\u4E00\u81F4\u5373\u53EF\uFF08\u4E0E\u5185\u5B58\u7F13\u5B58\u540C\u4E00\u6807\u51C6\uFF09\u3002\nexport function persistEntryUsable(entry, stat) {\n const normalized = normalizeEntry(entry)\n if (!normalized || !stat) return null\n return normalized.fingerprint === stat.fingerprint ? normalized : null\n}\n", "// Compatibility boundary for the two DSH persistence generations supported by\n// dsh-sessions-manager. Business code consumes normalized headers and complete\n// inspections; it never needs to know whether DSH returned a legacy header or\n// a handle-era SessionPersistenceSnapshot.\n//\n// Handle-era notes (official contract, dsh-v0.1.3-alpha.1):\n// - `SessionHandle.read(offset?, length?, options?)` returns a bounded slice\n// of the valid contiguous log; an offset at/past the end returns [].\n// - Every handle is single-owner state: `close()` MUST run exactly once on\n// every path, including throws and aborts (the contract exposes\n// `SessionHandleClosedError` for operations after close).\n// - `stat(id)` \u2192 `SessionPersistenceSnapshot | undefined`; `snapshot.revision`\n// is an opaque change token valid ONLY within one service instance and one\n// session id (see src/session-meta-cache.js).\n\nconst DEFAULT_CHUNK = 400\n// \u9632\u5FA1\u4E0A\u9650\uFF1A\u4E00\u6B21 inspect \u7684\u5206\u5757\u5FAA\u73AF\u7EDD\u4E0D\u80FD\u65E0\u9650\u81EA\u65CB\uFF08\u540E\u7AEF read \u884C\u4E3A\u5F02\u5E38\u65F6\u5FEB\u901F\u5931\u8D25\uFF09\u3002\nconst MAX_CHUNKS = 20000\n\nfunction normalizeReadResult(events) {\n if (Array.isArray(events)) return events\n if (events && typeof events[Symbol.iterator] === 'function') return [...events]\n return []\n}\n\nasync function closeQuietly(handle) {\n try { if (handle && typeof handle.close === 'function') await handle.close() } catch (e) { /* close \u662F\u5E42\u7B49\u515C\u5E95\uFF0C\u4E8C\u6B21\u5931\u8D25\u5FFD\u7565 */ }\n}\n\nfunction asHeader(value) {\n if (!value || typeof value !== 'object') return null\n const candidate = value.header && typeof value.header === 'object' ? value.header : value\n return candidate.id == null ? null : candidate\n}\n\nexport function normalizePersistenceEntry(value) {\n const header = asHeader(value)\n if (!header) return null\n const snapshot = value && value.header === header ? value : null\n return {\n header,\n snapshot,\n id: String(header.id),\n sizeBytes: snapshot && Number.isFinite(snapshot.sizeBytes) ? Number(snapshot.sizeBytes) : null,\n eventCount: snapshot && Number.isSafeInteger(snapshot.eventCount) ? snapshot.eventCount : null,\n revision: snapshot && typeof snapshot.revision === 'string' && snapshot.revision ? snapshot.revision : null,\n }\n}\n\nexport function normalizePersistenceList(values) {\n if (!Array.isArray(values)) return []\n return values.map(normalizePersistenceEntry).filter(Boolean)\n}\n\nexport function createPersistenceAdapter(service) {\n if (!service || typeof service.list !== 'function') throw new TypeError('sessionPersistence.list is required')\n\n const hasStat = typeof service.stat === 'function'\n const kind = typeof service.open === 'function' ? 'session-handle' : 'legacy'\n\n async function listEntries(options) {\n return normalizePersistenceList(await service.list(options))\n }\n\n // Handle-era only: the official lightweight observation. Returns the\n // normalized snapshot entry, or null when the session does not exist.\n // Never falls back to reading the log \u2014 callers use it for existence\n // checks and revision-based cache validation only.\n async function statSession(id) {\n if (!hasStat) return null\n const snapshot = await service.stat(id)\n return snapshot ? normalizePersistenceEntry(snapshot) : null\n }\n\n // Read one bounded slice through a SessionHandle. The caller owns the\n // handle lifecycle; this helper only guarantees close on read failure \u2014\n // the surrounding try/finally in the chunk drivers below is authoritative.\n async function readChunk(handle, offset, length, signal) {\n if (signal && signal.aborted) {\n const error = new Error('\u4F1A\u8BDD\u8BFB\u53D6\u5DF2\u53D6\u6D88')\n error.code = 'DSM_READ_ABORTED'\n throw error\n }\n const events = await handle.read(offset, length, signal ? { signal } : undefined)\n return normalizeReadResult(events)\n }\n\n // Sequential chunk driver shared by inspectSession / readSession. Opens the\n // handle itself so every code path (success, mid-chunk throw, abort) closes\n // it exactly once in `finally`.\n async function readChunks(id, { offset = 0, chunkSize = DEFAULT_CHUNK, signal, onEvents }) {\n if (typeof service.open !== 'function') throw new Error('\u5F53\u524D DSH \u6301\u4E45\u5316\u670D\u52A1\u4E0D\u652F\u6301\u8BFB\u53D6\u4F1A\u8BDD')\n const handle = await service.open(id, 'read')\n if (!handle || typeof handle.read !== 'function' || typeof handle.close !== 'function') {\n await closeQuietly(handle)\n throw new Error('DSH \u8FD4\u56DE\u4E86\u65E0\u6548\u7684 SessionHandle')\n }\n let cursor = Number.isSafeInteger(offset) && offset >= 0 ? offset : 0\n let total = 0\n try {\n for (let round = 0; round < MAX_CHUNKS; round++) {\n const events = await readChunk(handle, cursor, chunkSize, signal)\n if (events.length === 0) break\n cursor += events.length\n total += events.length\n if (onEvents) await onEvents(events, { offset: cursor - events.length, total })\n if (events.length < chunkSize) break\n }\n } finally {\n await closeQuietly(handle)\n }\n return {\n meta: handle.header || handle.meta || null,\n inheritedEventCount: Number.isSafeInteger(handle.inheritedEventCount) ? handle.inheritedEventCount : 0,\n eventCount: total,\n }\n }\n\n // Streamed full inspection: folds the log chunk-by-chunk through `onEvents`\n // so \u8BE6\u60C5 / \u5BFC\u51FA never materialize a whole large log in memory. `signal`\n // (AbortSignal) cancels before the next chunk; the handle closes on every\n // path. Legacy runtimes have no bounded read \u2014 readFrom already returns the\n // complete log, which becomes a single onEvents batch.\n async function inspectSession(id, opts = {}) {\n const chunkSize = Number.isSafeInteger(opts.chunkSize) && opts.chunkSize > 0 ? opts.chunkSize : DEFAULT_CHUNK\n if (typeof service.open === 'function') {\n // \u53D6\u6D88\u53D1\u751F\u5728 open \u4E4B\u524D\uFF1A\u8FDE handle \u90FD\u4E0D\u53BB\u5F00\u3002\n if (opts.signal && opts.signal.aborted) {\n const error = new Error('\u4F1A\u8BDD\u8BFB\u53D6\u5DF2\u53D6\u6D88')\n error.code = 'DSM_READ_ABORTED'\n throw error\n }\n return readChunks(id, { offset: opts.offset || 0, chunkSize, signal: opts.signal, onEvents: opts.onEvents })\n }\n if (typeof service.readFrom !== 'function') throw new Error('\u5F53\u524D DSH \u6301\u4E45\u5316\u670D\u52A1\u4E0D\u652F\u6301\u8BFB\u53D6\u4F1A\u8BDD')\n if (opts.signal && opts.signal.aborted) {\n const error = new Error('\u4F1A\u8BDD\u8BFB\u53D6\u5DF2\u53D6\u6D88')\n error.code = 'DSM_READ_ABORTED'\n throw error\n }\n const result = await service.readFrom(id, opts.offset || 0)\n const events = normalizeReadResult(result && result.events)\n if (opts.onEvents && events.length) await opts.onEvents(events, { offset: opts.offset || 0, total: events.length })\n return {\n meta: result && result.meta ? result.meta : null,\n inheritedEventCount: result && Number.isSafeInteger(result.inheritedEventCount) ? result.inheritedEventCount : 0,\n eventCount: events.length,\n }\n }\n\n // Complete read (legacy convenience shape). Internally chunked; callers that\n // stream should prefer inspectSession so large logs never buffer whole.\n async function readSession(id, offset = 0) {\n if (typeof service.readFrom === 'function') {\n const result = await service.readFrom(id, offset)\n return {\n meta: result && result.meta ? result.meta : null,\n inheritedEventCount: result && Number.isSafeInteger(result.inheritedEventCount) ? result.inheritedEventCount : 0,\n events: result && Array.isArray(result.events) ? result.events : [],\n }\n }\n const events = []\n const summary = await readChunks(id, { offset, onEvents: (batch) => { events.push(...batch) } })\n return {\n meta: summary.meta,\n inheritedEventCount: summary.inheritedEventCount,\n events,\n }\n }\n\n function locate(header) {\n if (typeof service.locate === 'function') return service.locate(header)\n return null\n }\n\n // \u843D\u76D8\u6821\u9A8C\u7248\u5B9A\u4F4D\uFF1Alegacy \u8D70\u5B98\u65B9 locate\uFF1Bhandle \u65F6\u4EE3\u5B98\u65B9\u6536\u8D70\u4E86 locate\uFF0C\u6539\u7531\n // handle-era-paths \u7684\u4E09\u5C42\u5B88\u536B\u63A8\u5BFC\uFF08root \u5B9E\u4F8B\u5B57\u6BB5 \u2192 \u76EE\u5F55\u7ED3\u6784 \u2192 id \u5F52\u5C5E\uFF09\uFF0C\n // \u4EFB\u4E00\u5C42\u5931\u8D25\u8FD4\u56DE null\uFF0C\u8C03\u7528\u65B9\u5B89\u5168\u964D\u7EA7\u3002\u8FD4\u56DE { path, sessionDir|null }\u3002\n async function locateVerified(header) {\n if (typeof service.locate === 'function') {\n try {\n const loc = service.locate(header)\n if (loc && typeof loc.path === 'string') return { path: loc.path, sessionDir: null }\n } catch (e) { /* \u843D\u5230\u63A8\u5BFC */ }\n }\n const artifacts = await locateSessionArtifacts(service, header)\n return artifacts ? { path: artifacts.logPath, sessionDir: artifacts.sessionDir } : null\n }\n\n return { kind, listEntries, readSession, inspectSession, statSession, locate, locateVerified, hasStat }\n}\n", "// Capability matrix for the two DSH persistence generations. Every user-visible\n// action gets its own availability flag plus a Chinese reason, so the UI can\n// disable buttons honestly and the host routes can refuse with a stable error.\n//\n// Guiding rule (revised 2026-09-06 by explicit user decision): the official\n// SessionHandle-era contract (dsh-v0.1.3-alpha.1) exposes NO delete and NO\n// relocation \u2014 but legacy implementations were never pure-public either (they\n// used the official `locate` to find the path, then acted on the filesystem\n// directly). The user chose to keep that semi-official approach in the handle\n// era: private-path operations ARE allowed, but only through the guarded\n// derivation in src/handle-era-paths.js (backend root instance field \u2192 session\n// directory structure \u2192 id ownership) plus handle-era-ops.js (writer probe,\n// backup + rollback). Any derivation failure degrades to \"unavailable\".\n//\n// Action vocabulary (canonical):\n// readInspection read/list/stat the stored log (read-only)\n// archive archive/unarchive via workspaceRegistry (a marking op)\n// softTrash move a session into the plugin recycle bin (log stays put)\n// restoreIndexedSession restore a trashed session after verifying the\n// underlying stored session still exists\n// physicalPurge irreversibly delete the stored log (guarded fs rm)\n// relocateSession move a session across workspaces (changes header cwd)\n//\n// Legacy aliases (read / trash / restoreTrash / purge / move) are kept so the\n// client and older routes keep working during the transition.\n\nfunction action(available, reason = null) {\n return { available: !!available, reason: available ? null : reason }\n}\n\nexport function detectCapabilities({ persistence, workspaceRegistry }) {\n const handleApi = !!(persistence && typeof persistence.open === 'function')\n const legacyRead = !!(persistence && typeof persistence.readFrom === 'function')\n const legacyLocate = !!(persistence && (typeof persistence.locate === 'function'\n || (persistence.backend && typeof persistence.backend.locate === 'function')))\n // handle \u65F6\u4EE3\uFF1Aroot \u5FC5\u987B\u76F4\u63A5\u8BFB\u81EA\u540E\u7AEF\u5B9E\u4F8B\u5B57\u6BB5\uFF08session-persistence-jsonl \u7684\n // `root`\uFF09\uFF0C\u62FF\u4E0D\u5230\u6574\u4F53\u964D\u7EA7\u2014\u2014\u7EDD\u4E0D\u731C\u8DEF\u5F84\u3002\n const handleEraRoot = !!(handleApi && persistence\n && typeof persistence.root === 'string' && persistence.root.length > 0)\n const canVerifyExistence = !!(handleApi || legacyRead\n || (persistence && typeof persistence.stat === 'function'))\n const readOk = legacyRead || handleApi\n const workspaceInternals = !!(workspaceRegistry\n && workspaceRegistry.headers && workspaceRegistry.sessionPaths\n && typeof workspaceRegistry.replaceHeaderIndex === 'function')\n\n const matrix = {\n readInspection: action(readOk, '\u5F53\u524D DSH \u672A\u63D0\u4F9B\u53EF\u8BC6\u522B\u7684\u4F1A\u8BDD\u8BFB\u53D6\u63A5\u53E3'),\n archive: action(!!(workspaceRegistry && typeof workspaceRegistry.archiveSession === 'function'), '\u5F53\u524D DSH \u672A\u63D0\u4F9B\u5F52\u6863\u63A5\u53E3'),\n softTrash: action(readOk, '\u5F53\u524D DSH \u65E0\u6CD5\u8BFB\u53D6\u4F1A\u8BDD\uFF0C\u4E0D\u80FD\u5B89\u5168\u79FB\u5165\u56DE\u6536\u7AD9'),\n // \u6062\u590D\u4E0D\u518D\u65E0\u6761\u4EF6\u5BA3\u79F0\u53EF\u7528\uFF1A\u5FC5\u987B\u80FD\u6821\u9A8C\u5E95\u5C42\u4F1A\u8BDD\u4ECD\u5B58\u5728\uFF08stat \u6216 list\uFF09\uFF0C\n // \u5426\u5219\u6062\u590D\u53EA\u4F1A\u5236\u9020\u4E00\u6761\u6307\u5411\u5DF2\u6D88\u5931\u65E5\u5FD7\u7684\u50F5\u5C38\u6761\u76EE\u3002\n restoreIndexedSession: action(canVerifyExistence, '\u5F53\u524D DSH \u65E0\u6CD5\u6821\u9A8C\u5E95\u5C42\u4F1A\u8BDD\u662F\u5426\u5B58\u5728\uFF0C\u4E0D\u80FD\u5B89\u5168\u6062\u590D'),\n physicalPurge: action(\n (!handleApi && legacyLocate) || (handleApi && handleEraRoot && canVerifyExistence),\n handleApi && !handleEraRoot\n ? '\u65E0\u6CD5\u4ECE\u5F53\u524D DSH \u540E\u7AEF\u786E\u8BA4\u4F1A\u8BDD\u5B58\u50A8\u6839\u76EE\u5F55\uFF0C\u5DF2\u505C\u6B62\u7269\u7406\u5220\u9664\u4EE5\u4FDD\u62A4\u6570\u636E\u5B89\u5168'\n : '\u5F53\u524D DSH \u7248\u672C\u5C1A\u672A\u63D0\u4F9B\u7ECF\u8FC7\u9A8C\u8BC1\u7684\u5B89\u5168\u6C38\u4E45\u5220\u9664\u80FD\u529B\uFF1B\u79FB\u5165\u56DE\u6536\u7AD9\u4E0D\u4F1A\u91CA\u653E\u78C1\u76D8\u7A7A\u95F4',\n ),\n relocateSession: action(\n (!handleApi && legacyRead && legacyLocate && workspaceInternals)\n || (handleApi && handleEraRoot && readOk && workspaceInternals),\n handleApi && !workspaceInternals\n ? '\u5F53\u524D DSH \u672A\u63D0\u4F9B\u5DE5\u4F5C\u533A\u6CE8\u518C\u8868\u5185\u90E8\u7ED3\u6784\uFF0C\u8DE8\u5DE5\u4F5C\u533A\u79FB\u52A8\u540E\u65E0\u6CD5\u5373\u65F6\u5237\u65B0\u5206\u7EC4'\n : handleApi && !handleEraRoot\n ? '\u65E0\u6CD5\u4ECE\u5F53\u524D DSH \u540E\u7AEF\u786E\u8BA4\u4F1A\u8BDD\u5B58\u50A8\u6839\u76EE\u5F55\uFF0C\u5DF2\u505C\u6B62\u79FB\u52A8\u4EE5\u4FDD\u62A4\u6570\u636E\u5B89\u5168'\n : '\u5F53\u524D DSH \u7248\u672C\u5C1A\u672A\u63D0\u4F9B\u7ECF\u8FC7\u9A8C\u8BC1\u7684\u8DE8\u5DE5\u4F5C\u533A\u8FC1\u79FB\u80FD\u529B',\n ),\n }\n // Legacy aliases for existing client/routes/tests.\n matrix.read = matrix.readInspection\n matrix.trash = matrix.softTrash\n matrix.restoreTrash = matrix.restoreIndexedSession\n matrix.purge = matrix.physicalPurge\n matrix.move = matrix.relocateSession\n\n return {\n persistence: handleApi ? 'session-handle' : 'legacy',\n actions: matrix,\n }\n}\n\nexport function requireCapability(capabilities, name) {\n const value = capabilities && capabilities.actions && capabilities.actions[name]\n if (value && value.available) return\n const error = new Error((value && value.reason) || `\u5F53\u524D\u73AF\u5883\u4E0D\u652F\u6301 ${name}`)\n error.status = 409\n error.code = 'DSM_CAPABILITY_UNAVAILABLE'\n throw error\n}\n", "// path-guard.js \u2014 \u56DE\u6536\u7AD9/\u5F7B\u5E95\u5220\u9664\u524D\u7684\u300C\u65E5\u5FD7\u8DEF\u5F84\u5F52\u5C5E\u300D\u6821\u9A8C\uFF08\u7EAF\u51FD\u6570\uFF09\u3002\n//\n// purgeFromTrash \u5728\u7269\u7406 unlink \u524D\u5FC5\u987B\u786E\u8BA4\u76EE\u6807\u8DEF\u5F84\u771F\u7684\u5C5E\u4E8E\u8BE5\u4F1A\u8BDD\uFF0C\u9632\u6B62\u628A\n// \u65E0\u5173\u6587\u4EF6\u5220\u6389\u3002\u65E7\u5B9E\u73B0\u7528 `basename(dirname(target)) === sid`\uFF0C\u53EA\u5BF9 POSIX\n// \u5206\u9694\u7B26\u6210\u7ACB\uFF1AWindows \u98CE\u683C\u8DEF\u5F84\uFF08`C:\\\\\u2026\\\\<sid>\\\\session.jsonl.zstd`\uFF09\u5728\n// POSIX \u7248 path.basename \u4E0B\u6574\u4E32\u662F\u4E00\u4E2A basename\uFF0C\u6821\u9A8C\u4F1A\u9519\u8BEF\u62D2\u7EDD\uFF1B\u53CD\u8FC7\u6765\uFF0C\n// \u6DF7\u5408\u5206\u9694\u7B26\u6216 URL \u7F16\u7801\u8DEF\u5F84\u4E5F\u53EF\u80FD\u9020\u6210\u8BEF\u653E\u884C\u3002\u8FD9\u91CC\u7EDF\u4E00\u6309\u4E24\u79CD\u5206\u9694\u7B26\u5207\u5206\uFF0C\n// \u5E76\u5904\u7406\u76D8\u7B26\u524D\u7F00\u4E0E\u5C3E\u90E8\u659C\u6760\u3002\n//\n// \u63A5\u53D7\u4E24\u79CD\u5B98\u65B9/\u5386\u53F2\u5E03\u5C40\uFF1A\n// .../<sessionId>/session.jsonl.zstd \uFF08\u76EE\u5F55\u540D = \u4F1A\u8BDD id\uFF09\n// .../<sessionId>.jsonl.zstd \uFF08\u65E7\u540E\u7AEF\uFF1A\u6587\u4EF6\u540D\u542B\u4F1A\u8BDD id\uFF09\n\nfunction splitSegments(target) {\n return String(target)\n .replace(/[\\\\/]+$/, '')\n .split(/[\\\\/]/)\n .filter((seg) => seg.length > 0)\n}\n\n// \u53BB\u6389 Windows \u76D8\u7B26\u6BB5\uFF08\"C:\"\uFF09\uFF0C\u4FDD\u7559\u5176\u4F59\u6BB5\u3002POSIX \u8DEF\u5F84\u4E0D\u542B\u76D8\u7B26\u6BB5\uFF1A\n// \u4E00\u4E2A\u540D\u4E3A \"C:\" \u7684\u76EE\u5F55\u6BB5\u5728 macOS/Linux \u4E0A\u5408\u6CD5\u4F46\u6781\u7F55\u89C1\uFF0C\u628A\u5B83\u5F53\u76D8\u7B26\n// \u5904\u7406\u5BF9\u300C\u4F1A\u8BDD id \u5F52\u5C5E\u300D\u5224\u65AD\u6CA1\u6709\u5F71\u54CD\uFF08id \u4E0D\u4F1A\u662F \"C:\"\uFF09\u3002\nfunction stripDriveLetter(segments) {\n return segments.length > 0 && /^[A-Za-z]:$/.test(segments[0]) ? segments.slice(1) : segments\n}\n\n/**\n * Does `target` plausibly own `sid`'s stored log?\n * @param {string} target - absolute-ish log path reported by the backend or the trash index.\n * @param {string} sid - session id (already validated by isSafeSessionId: no separators).\n * @returns {boolean}\n */\nexport function pathOwnsSession(target, sid) {\n if (typeof target !== 'string' || target.length === 0) return false\n if (typeof sid !== 'string' || sid.length === 0) return false\n const segments = stripDriveLetter(splitSegments(target))\n if (segments.length === 0) return false\n const file = segments[segments.length - 1]\n // Layout 1: the session id owns the parent directory.\n if (segments.length >= 2 && segments[segments.length - 2] === sid) return true\n // Layout 2: legacy flat layout \u2014 the id is part of the file name itself.\n // Only a *standalone token* match counts: `sid` embedded in a longer id\n // (abc \u2194 abcdef) must NOT pass, otherwise a purge of `abc` could delete\n // `abcdef`'s log. Extension punctuation (\".jsonl.zstd\") is not id-glue.\n if (file.includes(sid)) {\n const ID_CHAR = /[A-Za-z0-9_-]/\n let from = 0\n while (true) {\n const at = file.indexOf(sid, from)\n if (at < 0) return false\n const before = at > 0 ? file[at - 1] : ''\n const after = at + sid.length < file.length ? file[at + sid.length] : ''\n if (!(before && ID_CHAR.test(before)) && !(after && ID_CHAR.test(after))) return true\n from = at + 1\n }\n }\n return false\n}\n", "// Handle-era destructive/moving operations (dsh-v0.1.3-alpha.1).\n//\n// 2026-09-06 \u7528\u6237\u51B3\u7B56\uFF1A\u8FD9\u4E24\u7C7B\u80FD\u529B\u5728 legacy \u65F6\u4EE3\u672C\u5C31\u662F\u300C\u5B98\u65B9 locate \u67E5\u8DEF\u5F84 +\n// \u76F4\u63A5\u6587\u4EF6\u7CFB\u7EDF\u64CD\u4F5C\u300D\u7684\u534A\u5B98\u65B9\u5B9E\u73B0\uFF1Bhandle \u65F6\u4EE3\u5B98\u65B9\u6536\u8D70 locate \u540E\uFF0C\u6539\u4E3A\u7531\n// src/handle-era-paths.js \u7684\u4E09\u5C42\u5B88\u536B\u63A8\u5BFC\u8DEF\u5F84\u3002\u672C\u6A21\u5757\u5B9E\u73B0\u4E24\u4E2A\u64CD\u4F5C\u6838\u5FC3\uFF0C\u4E3B\u8DEF\u5F84\n// \u5C3D\u91CF\u8D70\u5B98\u65B9\u516C\u5171 API\uFF08create/append/flush/close/stat/open\uFF09\uFF0C\u6587\u4EF6\u7CFB\u7EDF\u64CD\u4F5C\u4EC5\u9650\n// \u4E8E\u300C\u628A\u65E7\u65E5\u5FD7\u6539\u540D\u5907\u4EFD / \u5220\u9664\u4F1A\u8BDD\u76EE\u5F55\u300D\u8FD9\u4E24\u6B65\uFF0C\u5E76\u4E14\u5168\u90E8\u6709\u5907\u4EFD\u56DE\u6EDA\u6216\u524D\u7F6E\u63A2\u6D4B\uFF1A\n//\n// - moveSessionToCwd: revision \u524D\u540E\u6821\u9A8C\uFF08\u8C03\u7528\u65B9\uFF09\u2192 \u5B98\u65B9 create+append \u91CD\u653E\n// \u4E3A\u4E3B\u8DEF\u5F84\uFF1B\u540E\u7AEF\u5DF2\u6709\u540C id \u5E7D\u7075\u65F6\u56DE\u9000\u5230 frame0 cwd \u6539\u5199\u642C\u8FD0\uFF08\u590D\u7528\n// zstd-frame.js\uFF0C\u4E0E legacy relocateLog \u540C\u4E00\u5957\u6821\u9A8C\uFF09\u3002\u4EFB\u4F55\u5931\u8D25\u90FD\u4F1A\u628A\u5907\u4EFD\n// \u6539\u540D\u56DE\u539F\u4F4D\u5E76\u6E05\u7406\u76EE\u6807\u76EE\u5F55\uFF0C\u7EDD\u4E0D\u7559\u4E0B\u534A\u79FB\u52A8\u72B6\u6001\u3002\n// - purgeSessionArtifacts: \u5B98\u65B9 open(id,'write') \u63A2\u6D4B\u5E76\u77ED\u6682\u63A5\u7BA1\u5199\u6240\u6709\u6743\n// \uFF08\u6D3B\u8DC3\u5199\u8005 \u2192 409 \u62D2\u7EDD\uFF09\uFF0C\u7136\u540E\u6574\u76EE\u5F55\u5220\u9664\u4F1A\u8BDD\u76EE\u5F55\uFF08basename \u5DF2\u7531\u8DEF\u5F84\n// \u5B88\u536B\u9A8C\u8BC1\uFF09\uFF0C\u6700\u540E\u4EE5\u5B98\u65B9 stat \u590D\u6838\u8BE5 id \u5DF2\u6D88\u5931\u3002\n//\n// \u6D3B\u8DC3\u5199\u8005\u7B56\u7565\uFF1A\u4E24\u4E2A\u64CD\u4F5C\u90FD\u62D2\u7EDD\u300C\u6B63\u5728\u8FDB\u884C\u4E2D\u300D\u7684\u4F1A\u8BDD\uFF0C\u800C\u4E0D\u662F\u7167 legacy \u90A3\u6837\n// \u6539\u5199\u6D3B\u8DC3\u5BF9\u8C61\u2014\u2014handle \u65F6\u4EE3\u7684\u5199\u53E5\u67C4\u6240\u6709\u6743\u5728\u5B98\u65B9 tracker \u5185\u90E8\uFF0C\u4E0E\u5176\u6253\u8865\u4E01\n// \u4E0D\u5982\u5982\u5B9E\u62D2\u7EDD\uFF0C\u98CE\u9669\u9762\u66F4\u5C0F\u3002\n\nimport { mkdir, readFile, rename, rm, unlink, writeFile } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport { rewriteFrame0CwdInMemory, scanZstdFrames } from './zstd-frame.js'\nimport { deriveSessionDir, locateSessionArtifacts } from './handle-era-paths.js'\n\nconst MOVE_BATCH = 400\n\nfunction conflictError(message) {\n const error = new Error(message)\n error.status = 409\n error.code = 'DSM_SESSION_BUSY'\n return error\n}\n\nfunction failureText(e) {\n return `${(e && e.name) || ''} ${(e && e.message) || e}`\n}\n\nfunction isAlreadyOwned(e) {\n return /already owned/i.test(failureText(e))\n}\n\nfunction isAlreadyExists(e) {\n return /already exists/i.test(failureText(e))\n}\n\nasync function closeQuietly(handle) {\n try { if (handle && typeof handle.close === 'function') await handle.close() } catch (e) { /* \u76EE\u5F55\u53EF\u80FD\u5DF2\u88AB\u5220\uFF0Clease \u91CA\u653E\u5931\u8D25\u53EF\u5FFD\u7565 */ }\n}\n\n// \u5B98\u65B9\u5199\u6240\u6709\u6743\u63A2\u6D4B\uFF1A\u80FD open(id,'write') \u5C31\u8BC1\u660E\u5F53\u524D\u6CA1\u6709\u6D3B\u8DC3\u5199\u8005\uFF08\u987A\u5E26\u8BA9\u5B98\u65B9\n// \u8DEF\u5F84 flush \u4E00\u6B21\uFF09\uFF0C\u62FF\u5230\u540E\u7ACB\u5373\u91CA\u653E\u3002\u771F\u6B63\u7684\u5E76\u53D1\u4FDD\u62A4\u6765\u81EA\u968F\u540E\u7684 rename-aside\n// \uFF08\u65E7\u65E5\u5FD7\u6D88\u5931\u540E\uFF0C\u8FDF\u5230\u7684\u5199\u8005\u4F1A\u5728\u5B98\u65B9 open \u5904\u5E72\u51C0\u5730 NotFound\uFF0C\u800C\u4E0D\u662F\u5199\u574F\u6570\u636E\uFF09\u3002\nexport async function ensureNoActiveWriter(sp, sid) {\n let handle = null\n try {\n handle = await sp.open(sid, 'write')\n } catch (e) {\n if (isAlreadyOwned(e)) throw conflictError('\u8BE5\u4F1A\u8BDD\u6B63\u5728\u8FDB\u884C\u4E2D\uFF08\u5B58\u5728\u6D3B\u8DC3\u5199\u5165\uFF09\uFF0C\u8BF7\u5148\u5207\u6362\u5230\u522B\u7684\u4F1A\u8BDD\u518D\u64CD\u4F5C\u3002')\n throw e\n }\n await closeQuietly(handle)\n}\n\n// \u5F7B\u5E95\u5220\u9664\u4E00\u4E2A\u4F1A\u8BDD\u7684\u5168\u90E8\u7269\u7406\u4EA7\u7269\u3002header \u5FC5\u987B\u6765\u81EA\u5B98\u65B9 list/stat\uFF08\u643A\u5E26\u771F\u5B9E cwd\uFF09\u3002\n// \u8FD4\u56DE\u88AB\u5220\u9664\u7684 artifacts\uFF08\u4F9B\u4E0A\u5C42\u8BB0\u5F55 originalPath \u7B49\uFF09\u3002\nexport async function purgeSessionArtifacts(sp, sid, header) {\n const artifacts = await locateSessionArtifacts(sp, header)\n if (!artifacts) {\n const error = new Error('\u65E0\u6CD5\u5B9A\u4F4D\u8BE5\u4F1A\u8BDD\u7684\u7269\u7406\u65E5\u5FD7\u76EE\u5F55\uFF0C\u5DF2\u505C\u6B62\u6C38\u4E45\u5220\u9664')\n error.status = 409\n throw error\n }\n let writer = null\n try {\n writer = await sp.open(sid, 'write')\n } catch (e) {\n if (isAlreadyOwned(e)) throw conflictError('\u8BE5\u4F1A\u8BDD\u6B63\u5728\u8FDB\u884C\u4E2D\uFF08\u5B58\u5728\u6D3B\u8DC3\u5199\u5165\uFF09\uFF0C\u65E0\u6CD5\u5F7B\u5E95\u5220\u9664\u3002')\n throw e\n }\n // \u53E5\u67C4\u4ECE\u672A append \u8FC7\uFF0C\u5148\u91CA\u653E\u518D\u5220\u76EE\u5F55\uFF08Windows \u4E0A\u6253\u5F00\u4E2D\u7684\u6587\u4EF6\u65E0\u6CD5\u5220\u9664\uFF09\u3002\n await closeQuietly(writer)\n writer = null\n try {\n // \u6574\u76EE\u5F55\u79FB\u9664\uFF08\u542B lease \u7B49\u4F1A\u8BDD\u672C\u5730\u6587\u4EF6\uFF09\u3002basename === encodeSegment(id)\n // \u4E0E\u300C\u89C4\u8303 generation \u5728\u4F4D\u300D\u90FD\u5DF2\u5728 locateSessionArtifacts \u9A8C\u8BC1\u8FC7\u3002\n await rm(artifacts.sessionDir, { recursive: true, force: true })\n } catch (e) {\n const error = new Error('\u5220\u9664\u4F1A\u8BDD\u65E5\u5FD7\u5931\u8D25\uFF1A' + String((e && e.message) || e))\n error.status = 500\n throw error\n }\n // \u5B98\u65B9\u89C6\u89D2\u590D\u6838\uFF1A\u8BE5 id \u5FC5\u987B\u5DF2\u4ECE\u540E\u7AEF\u6D88\u5931\u3002\n if (typeof sp.stat === 'function') {\n const after = await sp.stat(sid).catch(() => undefined)\n if (after) {\n const error = new Error('\u5220\u9664\u540E\u5B98\u65B9 stat \u4ECD\u80FD\u770B\u5230\u8BE5\u4F1A\u8BDD\uFF0C\u5DF2\u4E2D\u6B62\uFF08\u76EE\u5F55\u53EF\u80FD\u88AB\u5E76\u53D1\u91CD\u5EFA\uFF09')\n error.status = 500\n throw error\n }\n }\n return artifacts\n}\n\n// frame0 \u6539\u5199\u56DE\u9000\uFF1A\u628A\u5907\u4EFD\u65E5\u5FD7\u7684 frame0 cwd \u6539\u5199\u4E3A\u76EE\u6807\u5DE5\u4F5C\u533A\u540E\u642C\u5165\u76EE\u6807\u4F1A\u8BDD\u76EE\u5F55\u3002\n// \u6821\u9A8C\u4E0E legacy relocateLog \u5B8C\u5168\u4E00\u81F4\uFF1A\u5E27\u6570\u4E0D\u53D8 + frame0 \u4E4B\u5916\u5B57\u8282\u9010\u4F4D\u76F8\u7B49\u3002\nasync function relocateRewrittenBackup({ sid, canonical, backupPath, artifacts }) {\n const original = await readFile(backupPath)\n const frames = scanZstdFrames(original).frames\n if (frames.length === 0) throw new Error('\u79FB\u52A8\u524D\u6821\u9A8C\u5931\u8D25\uFF1A\u4F1A\u8BDD\u65E5\u5FD7\u6CA1\u6709\u5B8C\u6574 zstd \u5E27')\n const rewritten = rewriteFrame0CwdInMemory(original, canonical)\n const rewrittenFrames = scanZstdFrames(rewritten).frames\n if (rewrittenFrames.length !== frames.length) throw new Error('\u79FB\u52A8\u540E\u6821\u9A8C\u5931\u8D25\uFF1A\u4F1A\u8BDD\u65E5\u5FD7\u5E27\u6570\u53D1\u751F\u53D8\u5316')\n if (!original.subarray(frames[0].end).equals(rewritten.subarray(rewrittenFrames[0].end))) {\n throw new Error('\u79FB\u52A8\u540E\u6821\u9A8C\u5931\u8D25\uFF1A\u4F1A\u8BDD\u4E8B\u4EF6\u5185\u5BB9\u53D1\u751F\u53D8\u5316')\n }\n const targetDir = deriveSessionDir(artifacts.root, canonical, sid)\n await mkdir(targetDir, { recursive: true })\n const staged = join(targetDir, `.move-stage-${process.pid}-${Date.now()}`)\n await writeFile(staged, rewritten, { mode: 0o600 })\n await rename(staged, join(targetDir, artifacts.generationFiles[0]))\n return targetDir\n}\n\n// \u8DE8\u5DE5\u4F5C\u533A\u79FB\u52A8\u6838\u5FC3\u3002events \u4E3A\u5B8C\u6574\u4E8B\u4EF6\u6570\u7EC4\uFF08\u5B98\u65B9 read \u8DEF\u5F84\u8BFB\u56DE\uFF0Cseq \u4FDD\u6301\u539F\u503C\uFF09\u3002\n// seeded\uFF08fork \u6EAF\u6E90\uFF09\u65E5\u5FD7\u7684\u7269\u7406\u4E8B\u4EF6 seq \u4E0D\u4ECE 0 \u8D77\u6B65\u65F6\uFF0C\u5B98\u65B9 assertContiguous\n// \u4F1A\u62D2\u7EDD\u76F4\u5F55\u2014\u2014\u6B64\u65F6\u628A\u526F\u672C\u65E5\u5FD7\u7684 seq \u91CD\u6392\u4E3A 0 \u8D77\u6B65\uFF08\u4EC5\u526F\u672C\u7684\u5B58\u50A8\u5E8F\uFF0C\u4E8B\u4EF6\u5185\u5BB9\n// \u4E0D\u53D8\uFF09\uFF0C\u5E76\u5728 create \u65F6\u5982\u5B9E\u643A\u5E26 inheritedEventCount \u6EAF\u6E90\u3002\nexport async function moveSessionToCwd({ sp, sid, header, canonical, events = [], inheritedEventCount = 0 }) {\n const artifacts = await locateSessionArtifacts(sp, header)\n if (!artifacts) {\n const error = new Error('\u65E0\u6CD5\u5B9A\u4F4D\u8BE5\u4F1A\u8BDD\u7684\u7269\u7406\u65E5\u5FD7\uFF0C\u5DF2\u505C\u6B62\u79FB\u52A8')\n error.status = 409\n throw error\n }\n await ensureNoActiveWriter(sp, sid)\n const newHeader = Object.assign({}, header, { cwd: canonical })\n const firstSeq = events.length ? Number(events[0].seq) : 0\n const replay = firstSeq !== 0 ? events.map((event, index) => ({ ...event, seq: index })) : events\n const createOptions = header.isSeeded && Number.isSafeInteger(inheritedEventCount) && inheritedEventCount > 0\n ? { inheritedEventCount }\n : undefined\n const backupPath = `${artifacts.logPath}.move-backup-${process.pid}-${Date.now()}`\n await rename(artifacts.logPath, backupPath)\n let writer = null\n try {\n try {\n writer = await sp.create(newHeader, createOptions)\n for (let i = 0; i < replay.length; i += MOVE_BATCH) {\n await writer.append(replay.slice(i, i + MOVE_BATCH))\n }\n await writer.flush()\n await writer.close()\n writer = null\n } catch (e) {\n if (isAlreadyExists(e)) {\n // \u540E\u7AEF\u5185\u5B58\u91CC\u5DF2\u6709\u540C id \u8BB0\u5F55\uFF08created-but-unmaterialized \u5E7D\u7075\u7B49\uFF09\uFF1A\n // \u56DE\u9000\u5230 frame0 \u6539\u5199\u642C\u8FD0\uFF0C\u4E0D\u518D\u8D70 create\u3002\n await relocateRewrittenBackup({ sid, canonical, backupPath, artifacts })\n } else {\n throw e\n }\n }\n // \u5B98\u65B9\u89C6\u89D2\u6821\u9A8C\uFF1A\u65B0 cwd \u5FC5\u987B\u751F\u6548\uFF1B\u4E8B\u4EF6\u6570\u4E00\u81F4\uFF08snapshot.eventCount \u7F3A\u7701\u65F6\u8DF3\u8FC7\uFF09\u3002\n if (typeof sp.stat !== 'function') throw new Error('\u79FB\u52A8\u540E\u65E0\u6CD5\u6821\u9A8C\uFF1A\u540E\u7AEF\u672A\u63D0\u4F9B stat')\n const after = await sp.stat(sid)\n if (!after || !after.header || after.header.cwd !== canonical) {\n throw new Error('\u79FB\u52A8\u540E\u6821\u9A8C\u5931\u8D25\uFF1A\u4F1A\u8BDD\u5DE5\u4F5C\u76EE\u5F55\u672A\u6B63\u786E\u66F4\u65B0')\n }\n if (Number.isSafeInteger(after.eventCount) && events.length > 0 && after.eventCount !== events.length) {\n throw new Error(`\u79FB\u52A8\u540E\u6821\u9A8C\u5931\u8D25\uFF1A\u4E8B\u4EF6\u6570\u4E0D\u4E00\u81F4\uFF08\u6E90 ${events.length}\uFF0C\u526F\u672C ${after.eventCount}\uFF09`)\n }\n } catch (e) {\n // \u56DE\u6EDA\uFF1A\u6E05\u6389\u76EE\u6807\u76EE\u5F55\u91CC\u7684\u534A\u6210\u54C1\uFF0C\u628A\u5907\u4EFD\u6539\u540D\u56DE\u539F\u4F4D\u3002\n await closeQuietly(writer)\n try { await rm(deriveSessionDir(artifacts.root, canonical, sid), { recursive: true, force: true }) } catch (_) {}\n try { await rename(backupPath, artifacts.logPath) } catch (_) {}\n if (e && e.status) throw e\n const error = new Error('\u79FB\u52A8\u4F1A\u8BDD\u65E5\u5FD7\u5931\u8D25\uFF1A' + String((e && e.message) || e))\n error.status = 500\n throw error\n }\n try { await unlink(backupPath) } catch (e) { /* \u5907\u4EFD\u6E05\u7406\u5931\u8D25\u4E0D\u963B\u585E\u6210\u529F\u7ED3\u679C */ }\n return { sessionDir: deriveSessionDir(artifacts.root, canonical, sid) }\n}\n", "// Private-path derivation for the SessionHandle era (dsh-v0.1.3-alpha.1).\n//\n// \u8BBE\u8BA1\u88C1\u51B3\uFF082026-09-06\uFF0C\u7528\u6237\u660E\u786E\u51B3\u7B56\uFF09\uFF1A\u5B98\u65B9\u516C\u5171\u5951\u7EA6\u4E0D\u542B delete/move\uFF0C\u800C\u8FD9\u4E24\u7C7B\n// \u80FD\u529B\u5728 legacy \u65F6\u4EE3\u672C\u6765\u5C31\u662F\u300C\u5B98\u65B9 locate \u67E5\u8DEF\u5F84 + \u76F4\u63A5\u6587\u4EF6\u7CFB\u7EDF\u64CD\u4F5C\u300D\u7684\u534A\u5B98\u65B9\n// \u5B9E\u73B0\u3002\u7528\u6237\u636E\u6B64\u653E\u5F03 v3.5.2 \u65E9\u524D\u300C\u53EA\u8D70\u516C\u5171\u5951\u7EA6\u300D\u7684\u81EA\u6211\u9650\u5236\uFF0C\u8981\u6C42\u6CBF\u7528\u540C\u4E00\u601D\u8DEF\n// \u5728 handle \u65F6\u4EE3\u6062\u590D\u300C\u5F7B\u5E95\u5220\u9664\u300D\u4E0E\u300C\u8DE8\u5DE5\u4F5C\u533A\u79FB\u52A8\u300D\u3002\u672C\u6A21\u5757\u628A\u5B98\u65B9\n// session-persistence-jsonl \u540E\u7AEF\u7684\u786E\u5B9A\u6027\u76EE\u5F55\u5E03\u5C40\u79FB\u690D\u4E3A\u53EF\u6821\u9A8C\u7684\u8DEF\u5F84\u63A8\u5BFC\uFF0C\u5E76\u914D\n// \u4E09\u5C42\u5B88\u536B\uFF0C\u4EFB\u4F55\u4E00\u5C42\u4E0D\u6EE1\u8DB3\u90FD\u89C6\u4E3A\u300C\u63A8\u5BFC\u5931\u8D25\u300D\u8FD4\u56DE null\uFF08\u8C03\u7528\u65B9\u5B89\u5168\u964D\u7EA7\u4E3A\u7981\u7528\uFF09\uFF1A\n//\n// 1. root \u5FC5\u987B\u76F4\u63A5\u8BFB\u81EA\u540E\u7AEF\u5B9E\u4F8B\u5B57\u6BB5\uFF08`sp.root`\uFF0C\u6784\u5EFA\u4EA7\u7269\u91CC\u662F\u666E\u901A\u5B9E\u4F8B\u5C5E\u6027\uFF09\uFF0C\n// \u7EDD\u4E0D\u731C\u6D4B\u3001\u7EDD\u4E0D\u626B\u63CF\u78C1\u76D8\u53CD\u63A8\u3002\n// 2. \u4F1A\u8BDD\u76EE\u5F55 basename \u5FC5\u987B\u7B49\u4E8E encodeSegment(id)\uFF0C\u4E14\u76EE\u5F55\u5185\u5FC5\u987B\u5B58\u5728\u81F3\u5C11\u4E00\u4E2A\n// \u89C4\u8303 generation \u6587\u4EF6\uFF08session.vN.jsonl[.zstd]\uFF1B\u4E34\u65F6/\u975E\u89C4\u8303\u540D\u4E0D\u7B97\uFF09\u3002\n// 3. \u6700\u7EC8\u65E5\u5FD7\u8DEF\u5F84\u8FD8\u8981\u8FC7 pathOwnsSession \u7684 id \u5F52\u5C5E\u6821\u9A8C\uFF08\u542B\u5B50\u4E32\u78B0\u649E\u62D2\u7EDD\uFF09\u2014\u2014\n// \u56E0\u6B64\u542B\u5F02\u4F53\u5B57\u7B26\u7684 id\uFF08\u7F16\u7801\u540E\u76EE\u5F55\u540D \u2260 id\uFF09\u4F1A\u5B89\u5168\u964D\u7EA7\u4E3A\u4E0D\u53EF\u7528\u3002\n//\n// \u5E03\u5C40\u89C4\u5219\u79FB\u690D\u81EA\u5B98\u65B9\u6784\u5EFA\u4EA7\u7269\uFF08session-persistence-jsonl/lib/index.js\uFF09\uFF1A\n// projectDir(root, cwd) = root / projectKey(cwd) \uFF08cwd \u7F3A\u7701 \u2192 _no-cwd\uFF09\n// sessionDir(root, cwd, id) = projectDir / encodeSegment(id)\n// generationLogFilename = `session.vN.jsonl` + `.zstd`\uFF08compression=zstd\uFF09\n// projectKey: \u5206\u9694\u7B26\u4E0E `:` \u2192 `-`\uFF1B[A-Za-z0-9._-] \u4FDD\u7559\uFF1B\u5176\u4F59 \u2192 `~XXXX`\n// \uFF08charCode \u7684\u56DB\u4F4D\u5927\u5199\u5341\u516D\u8FDB\u5236\uFF09\uFF1B\u53BB\u524D\u5BFC `-`\uFF1B\u622A\u65AD 251\uFF1B\u7A7A\u4E32\u56DE\u9000 `root`\u3002\n// encodeSegment: \u540C\u6837\u7684 `~XXXX` \u8F6C\u4E49\uFF08`.`/`..` \u4F8B\u5916\uFF09\u3002\n\nimport { readdir, stat } from 'node:fs/promises'\nimport { basename, join } from 'node:path'\nimport { pathOwnsSession } from './path-guard.js'\n\nconst GENERATION_LOG_RE = /^session\\.v\\d+\\.jsonl(\\.zst(d)?)?$/\n\nfunction isSafeChar(ch) {\n return ch !== '~' && /^[A-Za-z0-9._-]$/.test(ch)\n}\n\nexport function projectKeyFor(cwd) {\n const s = String(cwd)\n if (s.length === 0) throw new Error('cannot encode an empty project path')\n let readable = ''\n let separatorRun = false\n for (let i = 0; i < s.length; i++) {\n const ch = s[i]\n if (ch === '/' || ch === '\\\\' || ch === ':') {\n if (!separatorRun) readable += '-'\n separatorRun = true\n } else if (isSafeChar(ch)) {\n readable += ch\n separatorRun = false\n } else {\n readable += '~' + s.charCodeAt(i).toString(16).toUpperCase().padStart(4, '0')\n separatorRun = false\n }\n }\n return '--' + ((readable.replace(/^-+/, '') || 'root').slice(0, 251)) + '--'\n}\n\nexport function encodeSegmentFor(raw) {\n const s = String(raw)\n if (s.length === 0) throw new Error('cannot encode an empty path segment')\n if (s === '.') return '~002E'\n if (s === '..') return '~002E~002E'\n let out = ''\n for (let i = 0; i < s.length; i++) {\n const ch = s[i]\n out += isSafeChar(ch) ? ch : '~' + s.charCodeAt(i).toString(16).toUpperCase().padStart(4, '0')\n }\n return out\n}\n\n// \u540E\u7AEF\u5B9E\u4F8B\u7684 root \u53EA\u5728\u300C\u5B9E\u4F8B\u5B57\u6BB5\u786E\u5B9E\u643A\u5E26\u975E\u7A7A\u5B57\u7B26\u4E32\u300D\u65F6\u53EF\u4FE1\uFF1B\u62FF\u4E0D\u5230\u5C31\u6574\u4F53\u964D\u7EA7\u3002\nexport function resolveSessionRoot(sp) {\n const root = sp && typeof sp === 'object' ? sp.root : undefined\n return typeof root === 'string' && root.length > 0 ? root : null\n}\n\nexport function deriveSessionDir(root, cwd, id) {\n const project = cwd === undefined || cwd === null || cwd === ''\n ? join(root, '_no-cwd')\n : join(root, projectKeyFor(cwd))\n return join(project, encodeSegmentFor(id))\n}\n\n// \u7EAF\u63A8\u5BFC\uFF08\u4E0D\u505A\u78C1\u76D8\u6821\u9A8C\uFF09\u3002\u4F9B\u6D4B\u8BD5\u4E0E\u4E0A\u5C42\u7EC4\u5408\u4F7F\u7528\u3002\nexport function deriveGenerationLogPath(root, cwd, id, { compression = 'zstd' } = {}) {\n return join(deriveSessionDir(root, cwd, id), `session.v2.jsonl${compression === 'zstd' ? '.zstd' : ''}`)\n}\n\n// \u5B9A\u4F4D\u4E00\u4E2A\u5DF2\u843D\u76D8\u4F1A\u8BDD\u7684\u5168\u90E8\u7269\u7406\u5750\u6807\uFF1B\u4E09\u5C42\u5B88\u536B\u5728\u6B64\u6C47\u5408\u3002\u8FD4\u56DE\n// { root, projectDir, sessionDir, logPath, generationFiles }\n// \u6216 null\uFF08root \u4E0D\u53EF\u7528 / \u76EE\u5F55\u4E0D\u5B58\u5728 / \u65E0\u89C4\u8303 generation / id \u5F52\u5C5E\u6821\u9A8C\u62D2\u7EDD\uFF09\u3002\nexport async function locateSessionArtifacts(sp, header) {\n const root = resolveSessionRoot(sp)\n if (!root || !header || header.id == null) return null\n const sid = String(header.id)\n let sessionDir\n try {\n sessionDir = deriveSessionDir(root, header.cwd, sid)\n } catch (e) {\n return null\n }\n if (basename(sessionDir) !== encodeSegmentFor(sid)) return null\n let entries\n try {\n const st = await stat(sessionDir)\n if (!st.isDirectory()) return null\n entries = await readdir(sessionDir)\n } catch (e) {\n return null\n }\n const generationFiles = entries.filter((name) => GENERATION_LOG_RE.test(name))\n if (generationFiles.length === 0) return null\n // \u4F18\u5148 current generation\uFF08v2 \u2192 \u6700\u9AD8\u7248\u672C\u53F7\uFF09\uFF0C\u4FDD\u6301\u786E\u5B9A\u6027\u3002\n generationFiles.sort((a, b) => {\n const va = Number((a.match(/^session\\.v(\\d+)\\./) || [])[1] || 0)\n const vb = Number((b.match(/^session\\.v(\\d+)\\./) || [])[1] || 0)\n return vb - va\n })\n const logPath = join(sessionDir, generationFiles[0])\n if (!pathOwnsSession(logPath, sid)) return null\n return {\n root,\n projectDir: join(root, header.cwd === undefined || header.cwd === null || header.cwd === '' ? '_no-cwd' : projectKeyFor(header.cwd)),\n sessionDir,\n logPath,\n generationFiles,\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["mkdir", "readFile", "rename", "stat", "unlink", "writeFile", "basename", "dirname", "join", "readFileSync", "homedir", "name", "mkdir", "rename", "writeFile", "readFileSync", "homedir", "join", "isFresh", "stat", "mkdir", "rename", "writeFile", "join", "
|
|
3
|
+
"sources": ["../src/index.js", "../src/zstd-frame.js", "../src/markdown.js", "../src/star-index.js", "../src/storage-stats.js", "../src/auto-archive.js", "../src/session-meta-cache.js", "../src/title-persist-index.js", "../src/handle-era-paths.js", "../src/path-guard.js", "../src/compat/persistence.js", "../src/compat/capabilities.js", "../src/handle-era-ops.js"],
|
|
4
|
+
"sourcesContent": ["// dsh-sessions-manager \u2014 host half.\n//\n// Serves /archived-sessions/* JSON routes (list / restore / restore-many /\n// delete / delete-many / sessions / workspaces / move) over the host\n// `webServer`. The browser Settings sections (\"\u5F52\u6863\u4F1A\u8BDD\" & \"\u79FB\u52A8\u4F1A\u8BDD\") talk to\n// these. Reads/writes the durable workspace archive set\n// (workspaceRegistry + storageDomain), folds titles/dates/workspace tags from\n// session persistence, physically removes a session's log file on delete, and\n// relocates a conversation (session) between workspaces on move.\nimport { mkdir, readFile, realpath, rename, stat, unlink, writeFile } from 'node:fs/promises'\nimport { basename, dirname, isAbsolute, join } from 'node:path'\nimport { readFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { rewriteFrame0CwdInMemory, scanZstdFrames } from './zstd-frame.js'\nimport { createSessionMarkdownBuilder } from './markdown.js'\nimport { createStarIndex } from './star-index.js'\nimport { aggregateStorage } from './storage-stats.js'\nimport { createAutoArchiveStore, pickInactiveCandidates } from './auto-archive.js'\nimport { createSessionMetaCache, fingerprintOf, isPersistableFingerprint } from './session-meta-cache.js'\nimport { createTitleIndexStore } from './title-persist-index.js'\nimport { createPersistenceAdapter } from './compat/persistence.js'\nimport { detectCapabilities, requireCapability } from './compat/capabilities.js'\nimport { pathOwnsSession } from './path-guard.js'\nimport { purgeSessionArtifacts, moveSessionToCwd } from './handle-era-ops.js'\n\n\nexport const name = 'dsh-sessions-manager'\nexport const inject = ['webServer', 'workspaceRegistry', 'sessionPersistence', 'sessionQuery', 'storageDomain']\n\nconst MAX_TITLE = 80\n// Recycle bin (\u56DE\u6536\u7AD9): normal deletes land here instead of being erased.\nconst TRASH_DIR = process.env.DSH_SESSIONS_MANAGER_TRASH_DIR || join(homedir(), '.dsh', 'sessions-manager-trash')\nconst TRASH_INDEX = join(TRASH_DIR, 'index.json')\nconst TRASH_SCHEMA_VERSION = 2\nconst DEFAULT_TRASH_SETTINGS = Object.freeze({ retentionDays: 0 })\n// -- per-session detail aggregation (v2.0: \u53D6 Zephyr-vibe buildDetails \u7CBE\u534E) --\n// \u8BC6\u522B\u201C\u641C\u7D22/\u6293\u53D6\u201D\u7C7B\u5DE5\u5177\uFF0C\u7528\u6765\u6536\u96C6 fetch \u8BB0\u5F55\u3002\nconst FETCH_TOOL_RE = /search|fetch|download|browse/i\nconst MAX_FETCHES = 12 // fetch \u8BB0\u5F55\u4E0A\u9650\uFF08\u9632\u54CD\u5E94\u8FC7\u5927\uFF09\nconst MAX_FILES = 20 // write/edit \u6587\u4EF6\u5217\u8868\u4E0A\u9650\nconst MAX_STORAGE_TOP = 50 // \u5B58\u50A8\u6392\u884C\u8FD4\u56DE\u4E0A\u9650\uFF08\u9632\u54CD\u5E94\u8FC7\u5927\uFF09\n\nfunction json(res, value, status = 200) {\n res.writeHead(status, { 'content-type': 'application/json; charset=utf-8', 'cache-control': 'no-store' })\n res.end(JSON.stringify(value))\n}\n\nfunction errorStatus(error) {\n return error && Number.isInteger(error.status) ? error.status : 500\n}\n\n// \u6781\u7B80\u5E76\u53D1\u95F8\uFF1A\u6574\u672C\u65E5\u5FD7\u8BFB\u53D6\uFF08\u8BE6\u60C5 / \u5BFC\u51FA\uFF09\u540C\u65F6\u6700\u591A max \u4E2A\u5728\u8DD1\uFF0C\u6392\u961F\u7B49\u5F85\u3002\n// \u9632\u6B62\u6279\u91CF\u5BFC\u51FA\u628A\u5BBF\u4E3B CPU/\u5185\u5B58\u6253\u6EE1\uFF08SessionHandle \u4E16\u4EE3\u9010\u5757\u89E3\u7801\u4ECD\u662F CPU \u6D3B\uFF09\u3002\nfunction createLimiter(max) {\n let active = 0\n const queue = []\n return async function run(fn) {\n if (active >= max) await new Promise((resolve) => queue.push(resolve))\n active++\n try { return await fn() } finally {\n active--\n const next = queue.shift()\n if (next) next()\n }\n }\n}\n\nasync function readJsonBody(req) {\n const chunks = []\n let total = 0\n for await (const chunk of req) {\n chunks.push(chunk)\n total += chunk.length\n if (total > 1 << 20) return null\n }\n try {\n return JSON.parse(Buffer.concat(chunks).toString('utf8'))\n } catch {\n return null\n }\n}\n\nfunction parseIds(body) {\n const raw = body && body.sessionIds\n if (!Array.isArray(raw)) return null\n const ids = []\n for (const v of raw) if (typeof v === 'string' && isSafeSessionId(v)) ids.push(v)\n return ids\n}\n\nfunction isSafeSessionId(value) {\n return typeof value === 'string' && value.length > 0 && value.length <= 200 && !/[\\\\/\\0]/.test(value) && value !== '.' && value !== '..'\n}\n\nfunction requireSessionId(value) {\n if (!isSafeSessionId(value)) {\n const error = new Error('\u65E0\u6548\u7684 sessionId')\n error.status = 400\n throw error\n }\n return value\n}\n\n// Best-effort: figure out which conversation is the host's *currently active*\n// one. DSH's in-memory session store (ctx.sessions) keeps EVERY instantiated\n// session alive even after you switch away in the UI, so \"is it in\n// ctx.sessions\" is NOT the same as \"is it the active conversation\". We probe a\n// few known accessors for the active id; if none is available we return null\n// and callers should treat the session as movable (the move path is\n// crash-safe via backup+rollback and re-syncs the live object afterwards).\nfunction getActiveSessionId(context) {\n try {\n const a = context.get('activeSession')\n if (a != null) return (a && a.id != null) ? a.id : (typeof a === 'string' ? a : null)\n } catch (e) { /* no such key */ }\n try {\n const c = context.get('currentSession')\n if (c != null) return (c && c.id != null) ? c.id : (typeof c === 'string' ? c : null)\n } catch (e) { /* no such key */ }\n try {\n const store = context.get('sessions')\n if (store && store.active && store.active.id != null) return store.active.id\n } catch (e) { /* no such key */ }\n return null\n}\n\nfunction foldTitle(events) {\n let found = null\n let firstUser = null\n for (const ev of events) {\n if (ev.type === 'session/title' && ev.data && typeof ev.data.title === 'string' && ev.data.title.length) {\n found = ev.data.title\n }\n if (firstUser === null && ev.type === 'user/message' && ev.data && Array.isArray(ev.data.content)) {\n const txt = ev.data.content.filter((b) => b && b.type === 'text').map((b) => b.text).filter(Boolean).join(' ').trim()\n if (txt) firstUser = txt\n }\n }\n return found || firstUser || null\n}\n\nexport function apply(ctx) {\n const w = ctx.workspaceRegistry\n const sp = ctx.sessionPersistence\n const persistence = createPersistenceAdapter(sp)\n const capabilities = detectCapabilities({ persistence: sp, workspaceRegistry: w })\n const sq = ctx.sessionQuery\n const dom = () => ctx.storageDomain.get('workspace')\n const authorityTitleCache = new Map()\n // \u4F1A\u8BDD\u539F\u59CB\u5143\u6570\u636E\u7F13\u5B58\uFF08title / cwd / createdAt\uFF09\uFF0C\u6309\u65E5\u5FD7\u6587\u4EF6 (mtime, size) \u6307\u7EB9\u6821\u9A8C\u3002\n // \u89C1 src/session-meta-cache.js \u7684\u8BF4\u660E\uFF1A\u5217\u8868\u6784\u5EFA\u539F\u672C\u6BCF\u6761\u4F1A\u8BDD\u90FD\u8981\u6574\u672C\u89E3\u538B\u65E5\u5FD7\uFF0C\n // \u8FD9\u4E2A\u7F13\u5B58\u8BA9\u300C\u65E5\u5FD7\u6CA1\u53D8\u300D\u7684\u4F1A\u8BDD\u76F4\u63A5\u8DF3\u8FC7\u89E3\u7801\u3002\n const metaCache = createSessionMetaCache()\n // \u6301\u4E45\u6807\u9898\u7D22\u5F15\uFF08\u51B7\u542F\u52A8\u52A0\u901F\uFF09\uFF1AmetaCache \u662F\u8FDB\u7A0B\u5185\u7684\uFF0C\u91CD\u542F\u5373\u7A7A\u2014\u2014\u7B2C\u4E00\u6B21\u5217\u8868\n // \u4ECD\u8981\u5168\u5E93\u89E3\u7801\u3002\u7D22\u5F15\u6309\u540C\u6837\u7684 (mtime, size) \u6307\u7EB9\u5B58\u89E3\u7801\u7ED3\u679C\uFF0C\u6307\u7EB9\u6CA1\u53D8\u7684\u4F1A\u8BDD\n // \u91CD\u542F\u540E\u4E5F\u76F4\u63A5\u590D\u7528\u3002\u89C1 src/title-persist-index.js\u3002\n const titleIndex = createTitleIndexStore({ dir: TRASH_DIR, file: join(TRASH_DIR, 'title-index.json') })\n\n // P4\uFF1A\u5BF9\u300C\u5185\u5B58\u7F13\u5B58\u672A\u547D\u4E2D\u300D\u7684\u4F1A\u8BDD\u67E5\u6301\u4E45\u7D22\u5F15\uFF0C\u6307\u7EB9\u4E00\u81F4\u624D\u53EF\u4FE1\u3002\n // \u8FD4\u56DE Map<id, meta>\uFF1B\u8C03\u7528\u65B9\u5E94\u628A\u547D\u4E2D\u6761\u76EE\u56DE\u586B metaCache \u5E76\u4ECE missing \u91CC\u5254\u9664\u3002\n // revision \u6307\u7EB9\uFF08SessionHandle \u4E16\u4EE3\uFF09\u8DF3\u8FC7\u6301\u4E45\u7D22\u5F15\uFF1A\u8DE8\u8FDB\u7A0B\u65E0\u610F\u4E49\u3002\n async function hydrateFromPersist(ids, statsById) {\n const hits = new Map()\n if (!ids || !ids.length) return hits\n let store\n try { store = await titleIndex.entries() } catch (e) { return hits }\n for (const id of ids) {\n const stat = statsById.get(id)\n const entry = store && store[id]\n if (!stat || !entry) continue\n const fp = fingerprintOf(stat)\n if (!isPersistableFingerprint(fp)) continue\n if (fp && entry.fingerprint === fp) {\n hits.set(id, { title: entry.title, cwd: entry.cwd, createdAt: entry.createdAt })\n }\n }\n return hits\n }\n\n // \u628A\u672C\u6279\u771F\u6B63\u89E3\u7801\u51FA\u7684\u5143\u6570\u636E\u5F02\u6B65\u56DE\u5199\u6301\u4E45\u7D22\u5F15\uFF08fire-and-forget\uFF1A\u7D22\u5F15\u53EA\u662F\n // \u52A0\u901F\u5668\uFF0C\u5199\u5931\u8D25\u4E0D\u5F71\u54CD\u54CD\u5E94\uFF0C\u961F\u5217\u5185\u90E8\u5DF2\u4E32\u884C\u5316 + \u539F\u5B50\u66FF\u6362\uFF09\u3002\n // \u26A0\uFE0F revision \u6307\u7EB9\uFF08SessionHandle \u4E16\u4EE3\uFF09\u7EDD\u4E0D\u843D\u76D8\uFF1A\u5B83\u53EA\u5728\u5F53\u524D service\n // \u5B9E\u4F8B\u5185\u6709\u610F\u4E49\uFF0C\u8DE8\u8FDB\u7A0B\u6BD4\u8F83\u65E0\u610F\u4E49\uFF0C\u8BEF\u7528\u4F1A\u628A\u9648\u65E7\u6570\u636E\u5F53\u65B0\u9C9C\u6570\u636E\u3002\n function persistDecoded(decoded, statsById) {\n if (!decoded || !decoded.size) return\n const batch = {}\n const now = Date.now()\n for (const [id, meta] of decoded) {\n const fp = fingerprintOf(statsById.get(id))\n if (!isPersistableFingerprint(fp)) continue\n batch[id] = { title: meta.title, cwd: meta.cwd, createdAt: meta.createdAt, fingerprint: fp, updatedAt: now }\n }\n if (!Object.keys(batch).length) return\n titleIndex.merge(batch).catch(() => {})\n }\n\n // \u4ECE\u6295\u5F71\u5FEB\u7167\u91CC\u62BD\u51FA\u5143\u6570\u636E\uFF1B\u5FEB\u7167\u7F3A\u5931/\u5F02\u5E38\u65F6\u8FD4\u56DE\u96F6\u503C meta\uFF08\u8C03\u7528\u65B9\u51B3\u5B9A\u515C\u5E95\uFF09\u3002\n function metaFromSnapshot(o) {\n let title = null, createdAt = null, cwd = null\n if (o) {\n if (o.title && o.title.title) title = String(o.title.title)\n if (o.session) { cwd = o.session.cwd || null; createdAt = o.session.createdAt || null }\n }\n return { title, cwd, createdAt }\n }\n\n // \u6295\u5F71\u5FEB\u7167\u7684\u4E24\u79CD\u8FD4\u56DE\u5F62\u6001\u90FD\u517C\u5BB9\uFF1A\u65B0\u7248 runtime \u8FD4\u56DE settled \u7ED3\u679C\n // \uFF08{ status: 'fulfilled', value }\uFF09\uFF0C\u8001\u7248\u672C\u76F4\u63A5\u8FD4\u56DE\u5FEB\u7167\u672C\u8EAB\u3002\n function unwrapSnapshot(result) {\n if (!result) return null\n if (result.status === 'fulfilled') return result.value || null\n if (result.status === 'rejected') return null\n return result\n }\n\n async function archivedState() {\n const d = dom()\n if (!d) throw new Error('workspace domain is not open')\n return d.global.get()\n }\n\n async function writeArchived(nextIds) {\n const d = dom()\n if (!d) throw new Error('workspace domain is not open')\n const cur = d.global.get()\n const next = Object.assign({}, cur, { archivedSessionIds: nextIds })\n await d.global.set(next)\n // Keep the registry's in-memory cache in sync so the live sidebar refreshes.\n if (w && 'state' in w) { try { w.state = next } catch (e) { /* best-effort */ } }\n return next\n }\n\n let archiveMutation = Promise.resolve()\n function mutateArchived(mutator) {\n const operation = archiveMutation.then(async () => {\n const state = await archivedState()\n const list = (state.archivedSessionIds || []).map(String)\n const result = await mutator(list)\n if (result.next) await writeArchived(result.next)\n return result.value\n })\n archiveMutation = operation.catch(() => {})\n return operation\n }\n\n let wsByPath = {}\n\n // \u628A\u539F\u59CB\u5143\u6570\u636E\u6E32\u67D3\u6210\u5217\u8868\u9879\u3002\u7F13\u5B58\u547D\u4E2D\u4E0E\u89E3\u7801\u4E24\u6761\u8DEF\u5F84\u5171\u7528\uFF0C\u4FDD\u8BC1\u8F93\u51FA\u4E00\u81F4\u3002\n function buildItem(key, meta, usage, exposeUsage) {\n const cwd = meta.cwd || null\n const ws = cwd ? wsByPath[cwd] : undefined\n const title = meta.title || null\n const display = title ? (String(title).length > MAX_TITLE ? String(title).slice(0, MAX_TITLE) + '\u2026' : String(title)) : null\n const base = {\n sessionId: key,\n title: display,\n createdAt: meta.createdAt || null,\n workspacePath: cwd,\n workspaceTitle: (ws && ws.title) ? ws.title : null,\n workspaceGone: !!(cwd && !ws),\n hasWorkspace: !!cwd,\n }\n // sizeBytes / updatedAt \u53EA\u5728\u9700\u8981\u7684\u8DEF\u7531\uFF08\u5B58\u50A8\u5206\u6790 / \u81EA\u52A8\u5F52\u6863\uFF09\u91CC\u5E26\u4E0A\uFF1A\n // \u5B83\u4EEC\u672C\u5C31\u6765\u81EA usage\uFF0C\u9644\u5E26\u8F93\u51FA\u5BF9\u5217\u8868\u6E32\u67D3\u65E0\u76CA\u3002\n if (exposeUsage && usage) {\n if (usage.sizeById && usage.sizeById.has(key)) base.sizeBytes = usage.sizeById.get(key)\n if (usage.mtimeById && usage.mtimeById.has(key)) base.updatedAt = usage.mtimeById.get(key)\n }\n return base\n }\n\n // Resolve one session's display metadata.\n //\n // \u6210\u672C\u6A21\u578B\uFF08issue #1\uFF09\uFF1A\u4E0B\u9762\u7684\u89E3\u7801\u8DEF\u5F84\u4F1A\u628A\u6574\u672C .jsonl.zstd \u9010\u5E27\u89E3\u538B\u3001\u9010\u884C\n // JSON.parse\uFF0C\u53EA\u4E3A\u6298\u53E0\u51FA\u6807\u9898\u2014\u2014\u5927\u5E93\u4E0A\u4E00\u6B21\u5168\u8868\u8981\u51E0\u79D2\u963B\u585E\u5F0F CPU\u3002\u65E5\u5FD7\u5185\u5BB9\u6CA1\u53D8\n // \u5C31\u610F\u5473\u7740\u6298\u53E0\u7ED3\u679C\u4E0D\u53EF\u80FD\u53D8\uFF08legacy \u7528 (mtime, size) \u6587\u4EF6\u6307\u7EB9\uFF1BSessionHandle\n // \u4E16\u4EE3\u7528\u5B98\u65B9 snapshot.revision\uFF09\uFF0C\u547D\u4E2D\u5373\u76F4\u63A5\u590D\u7528\uFF0C\u8DF3\u8FC7\u6574\u672C\u89E3\u7801\u3002\n //\n // 0.1.3-alpha \u517C\u5BB9\uFF08\u907F\u514D\u653E\u5927\u5B98\u65B9\u5DF2\u77E5\u7684\u5386\u53F2\u4F1A\u8BDD\u52A0\u8F7D\u6027\u80FD\u56DE\u9000\uFF09\uFF1A\n // - cwd/createdAt \u4F18\u5148\u6765\u81EA list() \u5FEB\u7167\u7684 snapshot.header\uFF1B\n // - \u6807\u9898\u4F18\u5148\u6765\u81EA\u6279\u91CF readTitleSnapshots\uFF1B\n // - **\u6807\u9898\u7F3A\u5931\u7EDD\u4E0D\u5355\u72EC\u89E6\u53D1\u6574\u672C\u65E5\u5FD7\u89E3\u7801**\u2014\u2014\u65E0\u6807\u9898\u5C31\u663E\u793A\u300C(\u65E0\u6807\u9898)\u300D\u3002\n // \u53EA\u6709\u5728\u62FF\u4E0D\u5230 cwd\uFF08\u5DE5\u4F5C\u533A\u5F52\u5C5E\u5931\u6548\uFF09\u6216 runtime \u5B8C\u5168\u6CA1\u6709\u6807\u9898\u6295\u5F71\u80FD\u529B\u65F6\n // \u624D\u56DE\u9000\u5230\u65E5\u5FD7\u89E3\u7801\uFF0C\u4E14\u8BE5\u89E3\u7801\u8D70 inspectSession \u5206\u5757\u6298\u53E0\uFF0C\u4E0D\u505A\u6574\u672C\u9A7B\u7559\u3002\n async function resolveOne(id, usage, opts = {}) {\n const key = String(id)\n const statInfo = usage ? (usage.statsById ? usage.statsById.get(key) : null)\n || { mtimeMs: usage.mtimeById && usage.mtimeById.get(key), size: usage.sizeById && usage.sizeById.get(key) } : null\n const cached = metaCache.get(key, statInfo)\n if (cached) return buildItem(key, cached, usage, opts.exposeUsage)\n\n let meta = { title: null, cwd: null, createdAt: null }\n // \u7B2C\u4E00\u6765\u6E90\uFF1Alist() \u8FD4\u56DE\u7684 SessionPersistenceSnapshot.header\uFF080.1.3+ \u5B98\u65B9\n // \u5951\u7EA6\u91CC header \u643A\u5E26 cwd/createdAt\uFF0C\u65E0\u9700\u4EFB\u4F55\u65E5\u5FD7\u8BFB\u53D6\uFF09\u3002\n if (opts.listHeader) {\n if (typeof opts.listHeader.cwd === 'string') meta.cwd = opts.listHeader.cwd\n if (opts.listHeader.createdAt != null) meta.createdAt = opts.listHeader.createdAt\n }\n if (opts.preloaded !== undefined) {\n const projected = metaFromSnapshot(unwrapSnapshot(opts.preloaded))\n if (projected.title) meta.title = projected.title\n if (!meta.cwd && projected.cwd) meta.cwd = projected.cwd\n if (!meta.createdAt && projected.createdAt) meta.createdAt = projected.createdAt\n } else if (typeof sq.readTitleSnapshot === 'function') {\n try {\n const projected = metaFromSnapshot(await sq.readTitleSnapshot(id))\n if (projected.title) meta.title = projected.title\n if (!meta.cwd && projected.cwd) meta.cwd = projected.cwd\n if (!meta.createdAt && projected.createdAt) meta.createdAt = projected.createdAt\n } catch (e) { /* fall through */ }\n }\n // cwd \u7F3A\u5931 \u2192 \u5DE5\u4F5C\u533A\u5F52\u5C5E\u5931\u6548\uFF0C\u503C\u5F97\u4E00\u6B21\u89E3\u7801\u515C\u5E95\uFF08cwd \u5728 header \u91CC\uFF0C\u901A\u5E38\n // \u5FEB\u7167\u5DF2\u5E26\u56DE\uFF0C\u8FD9\u91CC\u53EA\u5728\u5FEB\u7167\u7F3A cwd \u65F6\u53D1\u751F\uFF09\u3002runtime \u5B8C\u5168\u6CA1\u6709\u6807\u9898\u6295\u5F71\u80FD\u529B\n // \u65F6\uFF08\u8001\u540E\u7AEF\u65E0 readTitleSnapshot\uFF09\uFF0C\u89E3\u7801\u540C\u65F6\u515C\u5E95\u6807\u9898\u3002\n const projectionAvailable = typeof sq.readTitleSnapshot === 'function' || typeof sq.readTitleSnapshots === 'function'\n if (!meta.cwd || (!meta.title && !projectionAvailable)) {\n try {\n let foldedTitle = null\n const summary = await persistence.inspectSession(key, {\n onEvents: (events) => { if (!foldedTitle) foldedTitle = foldTitle(events) },\n })\n if (summary && summary.meta) {\n if (!meta.cwd) meta.cwd = summary.meta.cwd || null\n if (!meta.createdAt) meta.createdAt = summary.meta.createdAt || null\n }\n if (!meta.title && foldedTitle) meta.title = foldedTitle\n } catch (e2) { /* keep what we have */ }\n }\n metaCache.set(key, statInfo, meta)\n // \u672C\u6761\u662F\u300C\u771F\u89E3\u7801\u300D\u51FA\u6765\u7684\uFF1A\u4EA4\u7ED9\u8C03\u7528\u65B9\u56DE\u5199\u6301\u4E45\u6807\u9898\u7D22\u5F15\uFF08P4 \u51B7\u542F\u52A8\u52A0\u901F\uFF09\u3002\n if (opts.collectDecoded && statInfo) opts.collectDecoded(key, meta)\n return buildItem(key, meta, usage, opts.exposeUsage)\n }\n\n // Disk usage + last-write time for every session, in one pass. Also produces\n // the per-id change token (`statsById`) that drives the metadata cache:\n // - SessionHandle \u4E16\u4EE3\uFF080.1.3+\uFF09\uFF1A\u516C\u5171\u670D\u52A1\u4E0D\u518D\u66B4\u9732 locate/raw \u8DEF\u5F84\uFF0C\n // snapshot.revision\uFF08list \u4E00\u6B21\u5C31\u5E26\u56DE\uFF09\u5C31\u662F\u5B98\u65B9\u552F\u4E00\u53D8\u66F4\u4EE4\u724C\uFF1B\n // - legacy\uFF1A\u6CBF\u7528 sp.locate + \u4E00\u6B21 stat \u7684 (mtime, size) \u6587\u4EF6\u6307\u7EB9\u3002\n // mtime doubles as the session's last-activity time \u2014 appending an event\n // rewrites the log, so the file's last write tracks the conversation's last\n // turn. It errs safe: a log we relocated (move) gets a fresh mtime and\n // therefore looks *more* active than it is, which can only delay an\n // auto-archive, never cause a wrong one. Handle-era runtimes provide no\n // activity timestamp at all; auto-archive must then skip instead of guessing\n // (see autoArchiveSweep).\n // entries \u53EF\u7531\u8C03\u7528\u65B9\u4F20\u5165\u590D\u7528\uFF08\u5217\u8868\u6784\u5EFA\u91CC\u5DF2\u7ECF sp.list() \u8FC7\u4E00\u6B21\uFF0C\u907F\u514D\u91CD\u590D\u5217\u76EE\u5F55\uFF09\u3002\n async function collectUsage(preloadedEntries) {\n const sizeById = new Map()\n const mtimeById = new Map()\n const statsById = new Map()\n let entries = null\n if (Array.isArray(preloadedEntries)) entries = preloadedEntries\n else { try { entries = await persistence.listEntries() } catch (e) { entries = [] } }\n if (!Array.isArray(entries)) entries = []\n const CHUNK = 8\n for (let i = 0; i < entries.length; i += CHUNK) {\n await Promise.all(entries.slice(i, i + CHUNK).map(async (entry) => {\n const header = entry && entry.header ? entry.header : entry\n const id = entry && entry.id != null ? String(entry.id) : (header && header.id != null ? String(header.id) : null)\n if (!id) return\n // SessionHandle \u4E16\u4EE3\uFF1Asnapshot\uFF08header/revision/sizeBytes\uFF09\u662F\u6743\u5A01\u8F7B\u91CF\n // \u89C2\u5BDF\uFF0C\u7EDD\u4E0D\u518D\u7ED5\u9053\u79C1\u6709\u78C1\u76D8\u8DEF\u5F84\u8865 stat\u3002\n if (entry && typeof entry.revision === 'string' && entry.revision) {\n if (Number.isFinite(entry.sizeBytes)) sizeById.set(id, Number(entry.sizeBytes))\n statsById.set(id, { revision: entry.revision })\n return\n }\n if (entry && Number.isFinite(entry.sizeBytes)) sizeById.set(id, Number(entry.sizeBytes))\n try {\n const loc = persistence.locate(header)\n if (!loc || typeof loc.path !== 'string' || !loc.path) return\n const st = await stat(loc.path)\n if (!st) return\n if (typeof st.size === 'number') sizeById.set(id, st.size)\n if (typeof st.mtimeMs === 'number' && st.mtimeMs > 0) {\n mtimeById.set(id, Math.floor(st.mtimeMs))\n statsById.set(id, { mtimeMs: Math.floor(st.mtimeMs), size: typeof st.size === 'number' ? st.size : undefined })\n }\n } catch (e) { /* best-effort: an unreadable log just stays unknown */ }\n }))\n }\n return { sizeById, mtimeById, statsById, hasActivityData: mtimeById.size > 0 }\n }\n\n // Restore (unarchive) one session; throws on failure.\n async function restoreOne(sid) {\n requireSessionId(sid)\n return mutateArchived((list) => list.includes(sid)\n ? { next: list.filter((x) => x !== sid), value: { ok: true, restored: true } }\n : { next: null, value: { ok: true, restored: false } })\n }\n\n // ---- Recycle bin (\u56DE\u6536\u7AD9) helpers ----------------------------------------\n let trashMutation = Promise.resolve()\n function normalizeTrashStore(raw) {\n if (Array.isArray(raw)) return { schemaVersion: TRASH_SCHEMA_VERSION, settings: { ...DEFAULT_TRASH_SETTINGS }, items: raw, purgedSessionIds: [] }\n const settings = raw && typeof raw.settings === 'object' ? raw.settings : {}\n const retentionDays = Number.isInteger(settings.retentionDays) && settings.retentionDays >= 0 ? settings.retentionDays : 0\n return {\n schemaVersion: TRASH_SCHEMA_VERSION,\n settings: { retentionDays },\n items: raw && Array.isArray(raw.items) ? raw.items : [],\n purgedSessionIds: raw && Array.isArray(raw.purgedSessionIds) ? [...new Set(raw.purgedSessionIds.filter(isSafeSessionId).map(String))] : [],\n }\n }\n async function readTrashStore() {\n try { return normalizeTrashStore(JSON.parse(readFileSync(TRASH_INDEX, 'utf8'))) } catch (e) { return normalizeTrashStore(null) }\n }\n async function readTrash() { return (await readTrashStore()).items }\n async function writeTrashStore(store) {\n await mkdir(TRASH_DIR, { recursive: true })\n const tmp = join(TRASH_DIR, `.index-${process.pid}-${Date.now()}.tmp`)\n await writeFile(tmp, JSON.stringify(normalizeTrashStore(store), null, 2), { encoding: 'utf8', mode: 0o600 })\n await rename(tmp, TRASH_INDEX)\n }\n function mutateTrash(mutator) {\n const operation = trashMutation.then(async () => {\n const store = await readTrashStore()\n const result = await mutator(store)\n await writeTrashStore(store)\n return result\n })\n trashMutation = operation.catch(() => {})\n return operation\n }\n\n // ---- Starred sessions (\u6536\u85CF, schema v3) -----------------------------------\n // User marks, kept in the plugin's own index (never touches DSH logs). Stars\n // survive archive & soft-delete \u2014 both are reversible \u2014 and are dropped only\n // when the session is really gone (purge, or externally removed; the latter\n // is caught by gcStars during list builds).\n const stars = createStarIndex()\n // Auto-archive settings live in their own schema-v4 store, off by default.\n const autoArchive = createAutoArchiveStore()\n\n async function gcStars(validIds) {\n try {\n const store = await stars.read()\n const valid = new Set(validIds.map(String))\n const gone = store.starredSessionIds.filter((id) => !valid.has(id))\n if (gone.length) await stars.removeIds(gone)\n } catch (e) { /* best-effort */ }\n }\n\n // Soft-delete one session: record it in the recycle-bin index but KEEP its\n // log in the original workspace directory. Moving the file out (and detaching\n // it from the workspace) orphaned the session into DSH's \"\u672A\u5206\u7EC4\" group and\n // made restore land in \u672A\u5206\u7EC4 instead of the original workspace \u2014 so we leave\n // the file where it is and let the sidebar DOM shim hide the row instead.\n async function deleteOne(sid) {\n requireSessionId(sid)\n // Soft-delete is always allowed \u2014 including the currently-active conversation.\n // The log file stays in its original workspace dir (recorded in the \u56DE\u6536\u7AD9\n // index below), so the live session is unaffected and the entry stays\n // recoverable from \u56DE\u6536\u7AD9. (Move, by contrast, physically relocates the file\n // and still guards the active session in moveTargetWorkspace.)\n let header = null\n let cwd = null\n let title = null\n let removedPath = null\n let persistenceEntry = null\n try {\n const entries = await persistence.listEntries()\n const found = entries.find((entry) => entry.id === sid) || null\n persistenceEntry = found\n header = found ? found.header : null\n if (header) {\n const loc = persistence.locate(header)\n if (loc && typeof loc.path === 'string') removedPath = loc.path\n cwd = header.cwd || null\n title = header.title || (header.meta && header.meta.title) || null\n }\n if (!title) {\n // \u6807\u9898\u515C\u5E95\u4F18\u5148\u8D70\u5355\u4F1A\u8BDD\u6807\u9898\u6295\u5F71\uFF08\u5FEB\u7167\u7EA7\uFF0C\u4E0D\u8BFB\u65E5\u5FD7\uFF09\uFF1B\u6295\u5F71\u4E5F\u6CA1\u6709\u65F6\u624D\n // \u5206\u5757\u89E3\u7801\u65E5\u5FD7\u6298\u53E0\u6807\u9898\uFF08inspectSession \u5206\u5757\uFF0C\u4E0D\u6574\u672C\u9A7B\u7559\u5185\u5B58\uFF09\u3002\n if (typeof sq.readTitleSnapshot === 'function') {\n try {\n const snap = unwrapSnapshot(await sq.readTitleSnapshot(sid))\n if (snap && snap.title && snap.title.title) title = String(snap.title.title)\n if (snap && snap.session) { if (!cwd) cwd = snap.session.cwd || null }\n } catch (e) { /* fall through */ }\n }\n }\n if (!title) {\n try {\n let folded = null\n const summary = await persistence.inspectSession(sid, {\n onEvents: (events) => { if (!folded) folded = foldTitle(events) },\n })\n if (summary && summary.meta && !cwd) cwd = summary.meta.cwd || null\n title = folded\n } catch (e) { /* best-effort */ }\n }\n } catch (e) { /* best-effort */ }\n // Record in the trash index only \u2014 the log stays in its workspace dir.\n if (!header && !removedPath) {\n const error = new Error('\u627E\u4E0D\u5230\u8BE5\u4F1A\u8BDD')\n error.status = 404\n throw error\n }\n const archived = await mutateArchived((list) => ({ next: null, value: list.includes(sid) })).catch(() => false)\n await mutateTrash((store) => {\n const entry = {\n sessionId: sid, title: title || cwd || sid, cwd: cwd || null,\n header: header || null, originalPath: removedPath || null,\n sizeBytes: persistenceEntry && Number.isFinite(persistenceEntry.sizeBytes) ? persistenceEntry.sizeBytes : null,\n wasArchived: archived, deletedAt: Date.now(),\n }\n const at = store.items.findIndex((t) => String(t.sessionId) === sid)\n if (at >= 0) store.items[at] = entry\n else store.items.push(entry)\n store.purgedSessionIds = store.purgedSessionIds.filter((id) => id !== sid)\n })\n return { ok: true, trashed: true }\n }\n\n // \u6062\u590D\u524D\u7684\u5E95\u5C42\u6821\u9A8C\uFF080.1.3 \u5951\u7EA6\u4E0B restoreIndexedSession \u4E0D\u518D\u65E0\u6761\u4EF6\u53EF\u7528\uFF09\uFF1A\n // 1. \u5E95\u5C42 stored session \u4ECD\u5B58\u5728\uFF08live / stat / list \u4E09\u7EA7\u5224\u5B9A\uFF09\uFF1B\n // 2. \u65E5\u5FD7\u6587\u4EF6\u4ECD\u5728\u539F\u5904\uFF08\u8F6F\u5220\u9664\u4E0D\u52A8\u6587\u4EF6\uFF0CoriginalPath \u4E22\u5931\u5373\u5916\u90E8\u7834\u574F\uFF09\uFF1B\n // 3. \u5DE5\u4F5C\u533A\u4E22\u5931\u4E0D\u7B97\u5931\u8D25\u2014\u2014\u4F1A\u8BDD\u4ECD\u53EF\u6062\u590D\uFF0CUI \u4EE5 workspaceGone \u63D0\u793A\u3002\n // \u8FD4\u56DE { ok:true, workspaceGone, verified } \u6216 { ok:false, status, code, message }\u3002\n // verified=false \u8868\u793A\u65E0\u6CD5\u6838\u9A8C\u65E5\u5FD7\u6587\u4EF6\uFF08SessionHandle \u4E16\u4EE3\u65E0 locate\uFF09\uFF0C\u6309\n // \u7D22\u5F15\u4E3A\u51C6\u653E\u884C\uFF0C\u4F46\u7EDD\u4E0D\u5047\u88C5\u6821\u9A8C\u8FC7\u3002\n async function verifyTrashRestore(sid) {\n const sessions = ctx.get('sessions')\n if (sessions && sessions.get && sessions.get(sid)) {\n return { ok: true, workspaceGone: false, verified: true }\n }\n let exists = false\n let header = null\n try {\n const stat = await persistence.statSession(sid)\n if (stat) { exists = true; header = stat.header }\n } catch (e) { /* stat \u7F3A\u5931\u6216\u5931\u8D25\uFF1A\u843D\u5165 legacy \u5224\u5B9A */ }\n if (!exists) {\n try {\n const entries = await persistence.listEntries()\n const found = entries.find((entry) => entry.id === sid)\n if (found) { exists = true; header = found.header }\n } catch (e) { /* list \u5931\u8D25\uFF1A\u7EE7\u7EED\u8D70\u9519\u8BEF\u5206\u652F */ }\n }\n if (!exists) {\n const store = await readTrashStore()\n if (store.purgedSessionIds.map(String).includes(sid)) {\n return { ok: false, status: 410, code: 'DSM_SESSION_PURGED', message: '\u8BE5\u4F1A\u8BDD\u5DF2\u5F7B\u5E95\u5220\u9664\uFF0C\u65E0\u6CD5\u4ECE\u56DE\u6536\u7AD9\u6062\u590D' }\n }\n return { ok: false, status: 409, code: 'DSM_SESSION_MISSING', message: '\u5E95\u5C42\u4F1A\u8BDD\u5DF2\u4E0D\u5B58\u5728\uFF08\u53EF\u80FD\u88AB\u5916\u90E8\u5220\u9664\u6216\u91CD\u5EFA\uFF09\uFF0C\u65E0\u6CD5\u6062\u590D' }\n }\n // \u8F6F\u5220\u9664\u628A\u65E5\u5FD7\u7559\u5728\u539F\u5DE5\u4F5C\u533A\u76EE\u5F55\uFF1BoriginalPath \u6D88\u5931 = \u5916\u90E8\u7834\u574F\u3002\n // \u65E0\u6CD5\u6838\u9A8C\uFF08\u65E0 locate / \u65E0\u8BB0\u5F55\uFF09\u65F6\u653E\u884C\u4F46\u5982\u5B9E\u6807\u6CE8\u3002\n let verified = false\n const store = await readTrashStore()\n const entry = store.items.find((t) => String(t.sessionId) === sid)\n let originalPath = entry && typeof entry.originalPath === 'string' ? entry.originalPath : null\n if (!originalPath && header) {\n // handle \u65F6\u4EE3\u5B98\u65B9\u6536\u8D70\u4E86 locate\uFF0C\u7528\u5B88\u536B\u5F0F\u63A8\u5BFC\uFF08root \u2192 \u76EE\u5F55\u7ED3\u6784 \u2192 id \u5F52\u5C5E\uFF09\n // \u4EE3\u66FF\uFF1A\u63A8\u5BFC\u6210\u529F\u4E14\u6587\u4EF6\u5728\u76D8 = \u771F\u6838\u9A8C\u901A\u8FC7\uFF0C\u800C\u4E0D\u662F\u6807\u6CE8 unverified \u653E\u884C\u3002\n const loc = await persistence.locateVerified(header).catch(() => null)\n if (loc && typeof loc.path === 'string') originalPath = loc.path\n }\n if (originalPath) {\n const existsOnDisk = await stat(originalPath).then(() => true).catch(() => false)\n if (!existsOnDisk) {\n return { ok: false, status: 409, code: 'DSM_SESSION_LOG_MISSING', message: '\u56DE\u6536\u7AD9\u7D22\u5F15\u4ECD\u8BB0\u5F55\u8BE5\u4F1A\u8BDD\uFF0C\u4F46\u5176\u65E5\u5FD7\u6587\u4EF6\u5DF2\u6D88\u5931\uFF08\u53EF\u80FD\u88AB\u5916\u90E8\u79FB\u52A8\u6216\u5220\u9664\uFF09' }\n }\n verified = true\n }\n let workspaceGone = false\n const cwd = (header && header.cwd) || (entry && entry.cwd) || null\n if (cwd) {\n try { workspaceGone = !w.list().some((ent) => ent.path === cwd) } catch (e) { workspaceGone = false }\n }\n return { ok: true, workspaceGone, verified }\n }\n\n // Restore a trashed session: the log never left its original workspace dir,\n // so we just drop it from the recycle-bin index and the sidebar reveals it in\n // its original workspace (no move / no re-attach needed). Repeated restores\n // fail with an accurate 404 \u2014 there is no second entry to restore.\n async function restoreFromTrash(sid) {\n requireSessionId(sid)\n requireCapability(capabilities, 'restoreIndexedSession')\n let outcome = null\n await mutateTrash(async (store) => {\n const entry = store.items.find((t) => String(t.sessionId) === sid)\n if (!entry) {\n if (store.purgedSessionIds.map(String).includes(sid)) {\n const error = new Error('\u8BE5\u4F1A\u8BDD\u5DF2\u5F7B\u5E95\u5220\u9664\uFF0C\u65E0\u6CD5\u4ECE\u56DE\u6536\u7AD9\u6062\u590D')\n error.status = 410\n error.code = 'DSM_SESSION_PURGED'\n throw error\n }\n const error = new Error('\u56DE\u6536\u7AD9\u4E2D\u627E\u4E0D\u5230\u8BE5\u4F1A\u8BDD\uFF08\u53EF\u80FD\u5DF2\u6062\u590D\u8FC7\uFF09')\n error.status = 404\n error.code = 'DSM_TRASH_NOT_FOUND'\n throw error\n }\n // Verify BEFORE removing the durable entry: if verification fails the\n // mutator throws, mutateTrash does not write, and the item remains\n // recoverable instead of disappearing into an inconsistent state.\n const verification = await verifyTrashRestore(sid)\n if (!verification.ok) {\n const error = new Error(verification.message)\n error.status = verification.status\n error.code = verification.code\n throw error\n }\n // Restore the pre-delete archive state before removing the durable trash\n // entry. If this fails, mutateTrash does not write and the item remains\n // recoverable instead of disappearing into an inconsistent state.\n if (entry.wasArchived === false) await restoreOne(sid)\n store.items = store.items.filter((t) => String(t.sessionId) !== sid)\n store.purgedSessionIds = store.purgedSessionIds.filter((id) => id !== sid)\n outcome = { ok: true, restored: true, workspaceGone: verification.workspaceGone, verified: verification.verified }\n })\n return outcome || { ok: true, restored: true }\n }\n\n // Permanently erase a trashed session: physically delete its log (still in\n // the original workspace dir) and detach it from any workspace so DSH drops it.\n async function purgeFromTrash(sid) {\n requireSessionId(sid)\n requireCapability(capabilities, 'purge')\n let purged = false\n await mutateTrash(async (store) => {\n const entry = store.items.find((t) => String(t.sessionId) === sid)\n if (!entry) { const error = new Error('\u56DE\u6536\u7AD9\u4E2D\u627E\u4E0D\u5230\u8BE5\u4F1A\u8BDD'); error.status = 404; throw error }\n let target = null\n let locatedHeader = null\n try {\n const entries = await persistence.listEntries()\n const current = entries.find((entry) => entry.id === sid)\n locatedHeader = current ? current.header : null\n // locateVerified\uFF1Alegacy \u8D70\u5B98\u65B9 locate\uFF1Bhandle \u65F6\u4EE3\u5B98\u65B9\u6536\u8D70\u4E86 locate\uFF0C\n // \u6539\u7531\u4E09\u5C42\u5B88\u536B\u63A8\u5BFC\uFF08root \u2192 \u76EE\u5F55\u7ED3\u6784 \u2192 id \u5F52\u5C5E\uFF09\uFF0C\u5931\u8D25\u8FD4\u56DE null\u3002\n // \u6BD4\u4EC5\u9760\u56DE\u6536\u7AD9\u6761\u76EE\u91CC\u7684 originalPath \u66F4\u53EF\u9760\uFF1AoriginalPath \u8FC7\u671F\u6216\u7F3A\u5931\u65F6\n // \u4ECD\u80FD\u4ECE\u5F53\u524D\u5B58\u50A8\u5E03\u5C40\u91CD\u65B0\u63A8\u5BFC\u3002\n const located = current ? await persistence.locateVerified(current.header) : null\n if (located && typeof located.path === 'string') target = located.path\n } catch (e) {}\n // \u5E7D\u7075\u8BB0\u5F55\u515C\u5E95\uFF1A\u4F1A\u8BDD\u4E0D\u5728 list \u91CC\uFF08\u540E\u7AEF\u7D22\u5F15\u6EDE\u540E/\u7D22\u5F15\u7F3A\u5931\uFF09\u4F46\u65E5\u5FD7\u4ECD\u5728\u76D8\u4E0A\u3002\n // \u7528 statSession \u62FF\u5B98\u65B9 header\uFF0C\u518D\u8D70\u5B88\u536B\u63A8\u5BFC\uFF0C\u907F\u514D\u9000\u5316\u6210\u300C\u53EA\u5220\u5355\u6587\u4EF6\u300D\n // \u6216\u76F4\u63A5 409 \u62D2\u7EDD\u3002\n if (!locatedHeader && typeof persistence.statSession === 'function') {\n try {\n const snap = await persistence.statSession(sid)\n if (snap && snap.header) {\n locatedHeader = snap.header\n const located = await persistence.locateVerified(snap.header)\n if (located && typeof located.path === 'string') target = located.path\n }\n } catch (e) {}\n }\n if (!target && typeof entry.originalPath === 'string') target = entry.originalPath\n if (!target) {\n const error = new Error('\u65E0\u6CD5\u786E\u8BA4\u8BE5\u4F1A\u8BDD\u7684\u7269\u7406\u65E5\u5FD7\u4F4D\u7F6E\uFF0C\u5DF2\u505C\u6B62\u6C38\u4E45\u5220\u9664')\n error.status = 409\n throw error\n }\n // JSONL persistence stores logs as\n // .../<sessionId>/session.jsonl.zstd\n // Older backends may instead include the id in the filename itself.\n // pathOwnsSession accepts both layouts on POSIX and Windows separators\n // and rejects every unrelated path (including id-substring collisions)\n // before any unlink.\n const targetOwnsSession = pathOwnsSession(target, sid)\n if (target && !targetOwnsSession) {\n const error = new Error('\u65E5\u5FD7\u8DEF\u5F84\u4E0E\u4F1A\u8BDD ID \u4E0D\u5339\u914D\uFF0C\u5DF2\u505C\u6B62\u6C38\u4E45\u5220\u9664')\n error.status = 409\n throw error\n }\n // Persist the tombstone before any irreversible work. A crash after this\n // point may leave the trash item retryable, but can never resurrect the\n // session in a later list baseline.\n if (!store.purgedSessionIds.includes(sid)) store.purgedSessionIds.push(sid)\n await writeTrashStore(store)\n // A freshly-created or recently-opened Session can remain resident after\n // its file is unlinked. Flush once, then use SessionStore's entered-record\n // detach capability so DSH emits host/session-removed and the client list\n // drops the row instead of resurrecting it from live memory.\n try {\n const sessions = ctx.get('sessions')\n const liveSession = sessions && sessions.get && sessions.get(sid)\n if (liveSession && typeof sessions.flush === 'function') await sessions.flush(liveSession)\n const entered = sessions && sessions.store && sessions.store.get && sessions.store.get(sid)\n if (liveSession && (!entered || typeof entered.detach !== 'function')) throw new Error('\u5BBF\u4E3B\u672A\u63D0\u4F9B live Session detach \u80FD\u529B')\n if (entered && typeof entered.detach === 'function') entered.detach()\n // session/disposed starts an asynchronous persistence retirement. Wait\n // for it before unlinking, otherwise its final drain can race the file\n // deletion and briefly (or permanently) republish an orphan that the\n // official sidebar groups under \u201C\u672A\u5206\u7EC4\u201D.\n const retirement = sp && sp.retirements && sp.retirements.get && sp.retirements.get(sid)\n if (retirement && typeof retirement.then === 'function') await retirement\n } catch (e) {\n const error = new Error('\u65E0\u6CD5\u4ECE\u5BBF\u4E3B\u5185\u5B58\u79FB\u9664\u4F1A\u8BDD\uFF0C\u5DF2\u505C\u6B62\u6C38\u4E45\u5220\u9664\uFF1A' + String((e && e.message) || e))\n error.status = 409\n throw error\n }\n if (target && persistence.kind === 'session-handle' && locatedHeader) {\n // handle \u65F6\u4EE3\uFF1A\u5199\u6240\u6709\u6743\u63A2\u6D4B\uFF08\u6D3B\u8DC3\u5199\u8005 409\uFF09\u2192 \u6574\u76EE\u5F55\u5220\u9664 \u2192 \u5B98\u65B9 stat \u590D\u6838\u3002\n // \u5185\u90E8\u590D\u7528\u4E0E\u79FB\u52A8\u540C\u4E00\u5957\u8DEF\u5F84\u5B88\u536B\uFF1B\u5220\u9664\u5931\u8D25\u4F1A\u5E26 status \u5192\u6CE1\u3002\n await purgeSessionArtifacts(sp, sid, locatedHeader)\n } else if (target) {\n try { await unlink(target) } catch (e) { if (e && e.code !== 'ENOENT') throw new Error('\u5220\u9664\u6587\u4EF6\u5931\u8D25\uFF1A' + String((e && e.message) || e)) }\n }\n try { for (const ent of w.list()) { if (ent.sessionIds.includes(sid)) { try { await ent.detachSession(sid) } catch (e) {} } } } catch (e) {}\n try { if (w.sessionPaths && w.sessionPaths.delete) w.sessionPaths.delete(sid) } catch (e) {}\n try { if (w.headers && w.headers.delete) w.headers.delete(sid) } catch (e) {}\n await restoreOne(sid)\n // Rebuild from the post-unlink disk baseline before reporting success.\n // Merely deleting the two Maps above does not notify/rebuild Workspace\n // entities, leaving the client with an orphaned \u201C\u672A\u5206\u7EC4\u201D snapshot.\n try { await reindexRegistry() } catch (e) { /* tombstone still prevents resurrection */ }\n store.items = store.items.filter((t) => String(t.sessionId) !== sid)\n purged = true\n })\n if (!purged) throw new Error('\u5F7B\u5E95\u5220\u9664\u5931\u8D25')\n stars.removeIds([sid]).catch(() => {})\n return { ok: true, purged: true }\n }\n\n async function trashSettings(next) {\n if (next === undefined) return (await readTrashStore()).settings\n const days = Number(next.retentionDays)\n if (!Number.isInteger(days) || ![0, 7, 30, 90].includes(days)) {\n const error = new Error('retentionDays \u4EC5\u652F\u6301 0\u30017\u300130\u300190')\n error.status = 400\n throw error\n }\n await mutateTrash((store) => { store.settings = { retentionDays: days } })\n return (await readTrashStore()).settings\n }\n\n async function cleanupExpiredTrash() {\n if (!capabilities.actions.purge.available) return 0\n const store = await readTrashStore()\n const days = store.settings.retentionDays\n if (!days) return 0\n const cutoff = Date.now() - days * 86400000\n const ids = store.items.filter((item) => Number(item.deletedAt) > 0 && Number(item.deletedAt) < cutoff).map((item) => String(item.sessionId))\n let count = 0\n for (const sid of ids) { try { await purgeFromTrash(sid); count++ } catch (e) {} }\n return count\n }\n\n // ---- \"move conversation between workspaces\" helper -----------------------\n // DSH binds a conversation to the workspace whose canonical directory path\n // equals the session's stored cwd. Moving it therefore means: (1) adopt the\n // target path as a workspace (create if needed), (2) durably relocate the\n // session's log so its header carries the new cwd, and (3) reassign the\n // workspace membership (detach everywhere, attach to target). The log\n // relocation goes through the persistence service's own encoder (handles the\n // zstd artifact encoding) with a backup + rollback so a failure never leaves\n // the session half-moved.\n\n async function moveTargetWorkspace(rawPath) {\n if (typeof rawPath !== 'string' || !rawPath.trim()) throw new Error('\u7F3A\u5C11\u76EE\u6807\u5DE5\u4F5C\u533A\u8DEF\u5F84')\n let p = String(rawPath).trim()\n if (p.startsWith('~/')) p = join(homedir(), p.slice(2))\n if (!isAbsolute(p)) p = join(homedir(), p)\n let canonical = null\n try { canonical = await realpath(p) } catch (e) { canonical = null }\n if (canonical === null) {\n await mkdir(p, { recursive: true })\n canonical = await realpath(p)\n }\n return { canonical, entity: await w.create(canonical, basename(canonical) || 'workspace') }\n }\n\n async function moveOne(sid, targetPath) {\n requireCapability(capabilities, 'move')\n // Only block the *active* conversation. ctx.sessions keeps instantiated\n // sessions alive after you switch away, so the old check (sessions.get(sid))\n // wrongly rejected every opened session \u2014 you could never move one you'd\n // merely looked at. When the host exposes no active-session accessor we\n // can't prove activeness, so we allow the move; the relocation below is\n // crash-safe (backup + rollback) and re-syncs the live object.\n const activeId = getActiveSessionId(ctx)\n if (activeId != null && String(activeId) === String(sid)) {\n throw new Error('\u8BE5\u4F1A\u8BDD\u5F53\u524D\u5904\u4E8E\u6253\u5F00\u72B6\u6001\uFF0C\u8BF7\u5148\u5207\u6362\u5230\u522B\u7684\u4F1A\u8BDD\u518D\u79FB\u52A8\u3002')\n }\n const r = await persistence.readSession(sid, 0)\n if (!r || !r.meta) throw new Error('\u65E0\u6CD5\u8BFB\u53D6\u8BE5\u4F1A\u8BDD\u7684\u65E5\u5FD7')\n const meta = r.meta\n const events = r.events\n const oldCwd = meta.cwd || null\n\n const { canonical, entity: target } = await moveTargetWorkspace(targetPath)\n\n if (oldCwd) {\n let oldCanon = null\n try { oldCanon = await realpath(oldCwd) } catch (e) { oldCanon = null }\n if (oldCanon === canonical) {\n return { ok: true, already: true, workspaceId: target.id, workspaceTitle: target.title }\n }\n }\n\n const newHeader = Object.assign({}, meta, { cwd: canonical })\n\n // 1) Decide relocation strategy. `sessionPersistence.create()` rejects\n // (\"already exists in this backend\") for ANY session the host has\n // instantiated into its in-memory `states` \u2014 and DSH instantiates *every*\n // session it can find on disk at startup, including ARCHIVED ones. So a\n // supposedly \"closed\" archived session is NOT safe for the create()+append()\n // path; create() will throw. The only universally safe move is to physically\n // relocate the on-disk log (rewriting frame0's cwd) and redirect the live\n // object + persistence state. We still attempt create()+append() as the\n // fast path for genuinely-virgin session ids, but on an already-exists\n // collision we fall back to the relocate path. That covers live, archived,\n // and restored sessions alike.\n const live = ctx.get('sessions')\n const liveObj = live && live.get && live.get(sid)\n const isOpen = !!liveObj\n\n const ALREADY_EXISTS_RE = /already exists in this backend/i\n\n // Physically relocate a session's on-disk log to `newHeader`'s cwd,\n // rewriting frame0's cwd so sp.list()/reindex attribute it correctly.\n // Returns true if a relocation actually happened.\n const relocateLog = async (header, newHeaderObj) => {\n const oldPath = locatePath(header)\n const newPath = locatePath(newHeaderObj)\n if (!oldPath || !newPath || oldPath === newPath) return false\n const backupPath = `${oldPath}.move-backup-${Date.now()}`\n const stagedPath = `${newPath}.move-stage-${process.pid}-${Date.now()}`\n let destinationInstalled = false\n try {\n // Ensure the destination project directory exists (rename does not\n // create it). Without this, the rename silently no-ops on ENOENT and\n // the log stays put while workspace.json is wrongly updated.\n await mkdir(dirname(newPath), { recursive: true })\n try {\n await stat(newPath)\n throw new Error('\u79FB\u52A8\u5931\u8D25\uFF1A\u76EE\u6807\u4F4D\u7F6E\u5DF2\u5B58\u5728\u540C\u540D\u4F1A\u8BDD\u65E5\u5FD7')\n } catch (e) {\n if (e && e.code !== 'ENOENT') throw e\n }\n await rename(oldPath, backupPath) // keep the original byte-identical until verification succeeds\n const original = await readFile(backupPath)\n const originalFrames = scanZstdFrames(original).frames\n if (originalFrames.length === 0) throw new Error('\u79FB\u52A8\u524D\u6821\u9A8C\u5931\u8D25\uFF1A\u4F1A\u8BDD\u65E5\u5FD7\u6CA1\u6709\u5B8C\u6574 zstd \u5E27')\n const rewritten = rewriteFrame0CwdInMemory(original, canonical)\n const rewrittenFrames = scanZstdFrames(rewritten).frames\n if (rewrittenFrames.length !== originalFrames.length) throw new Error('\u79FB\u52A8\u540E\u6821\u9A8C\u5931\u8D25\uFF1A\u4F1A\u8BDD\u65E5\u5FD7\u5E27\u6570\u53D1\u751F\u53D8\u5316')\n const originalTail = original.subarray(originalFrames[0].end)\n const rewrittenTail = rewritten.subarray(rewrittenFrames[0].end)\n if (!originalTail.equals(rewrittenTail)) throw new Error('\u79FB\u52A8\u540E\u6821\u9A8C\u5931\u8D25\uFF1A\u4F1A\u8BDD\u4E8B\u4EF6\u5185\u5BB9\u53D1\u751F\u53D8\u5316')\n await writeFile(stagedPath, rewritten, { mode: 0o600 })\n await rename(stagedPath, newPath)\n destinationInstalled = true\n await unlink(backupPath)\n } catch (e) {\n try { await unlink(stagedPath) } catch (_) {}\n if (destinationInstalled) { try { await unlink(newPath) } catch (_) {} }\n try { await rename(backupPath, oldPath) } catch (_) {}\n if (e && e.code !== 'ENOENT') throw e\n return false\n }\n return true\n }\n\n const locatePath = (header) => {\n let fn = null\n try { if (typeof sp.locate === 'function') fn = sp.locate.bind(sp) } catch (e) {}\n if (!fn && sp.backend && typeof sp.backend.locate === 'function') fn = sp.backend.locate.bind(sp.backend)\n if (!fn) return null\n try {\n const loc = fn(header)\n if (loc && typeof loc.path === 'string') return loc.path\n if (typeof loc === 'string') return loc\n } catch (e) {}\n return null\n }\n\n // Rewriting frame0's cwd now lives in src/zstd-frame.js so it can be\n // regression-tested directly. See that module for why frame boundaries are\n // validated by decompression and why a non-session frame0 is rejected\n // instead of rewritten.\n\n if (persistence.kind === 'session-handle') {\n // \u8BFB\u4E8B\u4EF6\u4E4B\u540E\u7684\u53CC revision \u6821\u9A8C\uFF1A\u4E24\u6B21\u91C7\u6837\u4E4B\u95F4 revision \u4ECD\u5728\u53D8\uFF0C\u8BF4\u660E\u65E5\u5FD7\n // \u8FD8\u5728\u88AB\u5199\u5165\uFF0C\u4E2D\u6B62\u800C\u4E0D\u662F\u590D\u5236\u51FA\u5206\u53C9\u526F\u672C\uFF08\u8BFB\u53D6\u671F\u95F4\u7684\u5199\u5165\u7531 ops \u5185\u7684\n // rename-aside + \u5B98\u65B9\u5199\u6240\u6709\u6743\u63A2\u6D4B\u515C\u5E95\uFF09\u3002\n const stat1 = await persistence.statSession(sid)\n if (stat1 && stat1.revision) {\n const stat2 = await persistence.statSession(sid)\n if (stat2 && stat2.revision !== stat1.revision) {\n throw new Error('\u8BE5\u4F1A\u8BDD\u5728\u79FB\u52A8\u51C6\u5907\u671F\u95F4\u53D1\u751F\u4E86\u53D8\u5316\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002')\n }\n }\n try {\n await moveSessionToCwd({ sp, sid, header: meta, canonical, events, inheritedEventCount: r.inheritedEventCount })\n } catch (e) {\n if (e && e.status) throw e\n throw new Error('\u79FB\u52A8\u4F1A\u8BDD\u65E5\u5FD7\u5931\u8D25\uFF1A' + String((e && e.message) || e))\n }\n } else if (isOpen) {\n // Live session: relocate the on-disk log (rewriting frame0's cwd to the\n // new path) and redirect the live object + persistence state. We must\n // rewrite frame0, not just rename: sp.list() reads frame0's cwd from\n // disk, and WorkspaceEntity.sessionIds filters by that exact cwd. A bare\n // rename would leave frame0 pointing at the old workspace, so reindex /\n // restart would keep attributing the session to the wrong workspace.\n if (!await relocateLog(meta, newHeader)) throw new Error('\u79FB\u52A8\u5931\u8D25\uFF1A\u65E0\u6CD5\u786E\u8BA4\u4F1A\u8BDD\u65E5\u5FD7\u5DF2\u8FC1\u79FB\u5230\u76EE\u6807\u5DE5\u4F5C\u533A')\n // Redirect the persistence state's cwd so future appends land in newPath.\n try {\n const st = sp.states && sp.states.get && sp.states.get(sid)\n if (st && st.meta) st.meta = Object.assign({}, st.meta, { cwd: canonical })\n } catch (e) { /* best-effort */ }\n } else {\n // Closed session: try the fast create()+append() path first. But DSH\n // instantiates *all* on-disk sessions (including archived ones) into its\n // in-memory states at startup, so create() usually throws\n // \"already exists in this backend\". On that collision we fall back to a\n // physical relocate of the existing log (rewriting frame0's cwd), which\n // is safe and needs no create().\n let oldPath = null\n try {\n const loc = locatePath(meta)\n if (loc && typeof loc === 'string') oldPath = loc\n else if (loc && loc.path) oldPath = loc.path\n } catch (e) { oldPath = null }\n\n if (typeof sp.create !== 'function' || typeof sp.append !== 'function') {\n // No create primitive: must relocate the existing log directly.\n if (!await relocateLog(meta, newHeader)) throw new Error('\u79FB\u52A8\u5931\u8D25\uFF1A\u65E0\u6CD5\u786E\u8BA4\u4F1A\u8BDD\u65E5\u5FD7\u5DF2\u8FC1\u79FB\u5230\u76EE\u6807\u5DE5\u4F5C\u533A')\n } else {\n const backupPath = oldPath ? `${oldPath}.move-backup-${Date.now()}` : null\n if (backupPath) { try { await rename(oldPath, backupPath) } catch (e) { if (e && e.code !== 'ENOENT') throw new Error('\u79FB\u52A8\u5931\u8D25\uFF1A\u65E0\u6CD5\u5907\u4EFD\u65E7\u7684\u4F1A\u8BDD\u65E5\u5FD7') } }\n const restore = async () => { if (backupPath) { try { await rename(backupPath, oldPath) } catch (_) {} } }\n try {\n await sp.create(newHeader)\n await sp.append(sid, events)\n const check = await persistence.readSession(sid, 0)\n if (!check || !check.meta || check.meta.cwd !== canonical) {\n throw new Error('\u79FB\u52A8\u540E\u6821\u9A8C\u5931\u8D25\uFF1A\u4F1A\u8BDD\u5DE5\u4F5C\u76EE\u5F55\u672A\u6B63\u786E\u66F4\u65B0')\n }\n if (backupPath) { try { await unlink(backupPath) } catch (e) {} }\n } catch (e) {\n if (ALREADY_EXISTS_RE.test(String((e && e.message) || e))) {\n // Collision: the session is already materialized in states (archived\n // or previously opened). Fall back to physically relocating the log.\n await restore()\n if (!await relocateLog(meta, newHeader)) throw new Error('\u79FB\u52A8\u5931\u8D25\uFF1A\u65E0\u6CD5\u786E\u8BA4\u4F1A\u8BDD\u65E5\u5FD7\u5DF2\u8FC1\u79FB\u5230\u76EE\u6807\u5DE5\u4F5C\u533A')\n } else {\n await restore()\n throw new Error('\u79FB\u52A8\u4F1A\u8BDD\u65E5\u5FD7\u5931\u8D25\uFF1A' + String((e && e.message) || e))\n }\n }\n }\n }\n\n // Keep the live (in-memory) session object consistent with the relocated\n // log so the host doesn't keep appending to the old path. This MUST happen\n // before attachSession(): WorkspaceEntity.attachSession() validates the\n // session by reading live.header first, and if it still carries the old cwd\n // the realpath check will fail on the old (now missing) directory.\n try {\n if (liveObj) {\n if ('header' in liveObj) liveObj.header = newHeader\n if ('cwd' in liveObj) liveObj.cwd = canonical\n if ('meta' in liveObj) liveObj.meta = newHeader\n }\n } catch (e) { /* best-effort */ }\n\n // 2) Reassign workspace membership (durable records + in-memory index).\n for (const ent of w.list()) {\n try { await ent.detachSession(sid) } catch (e) { /* ignore */ }\n }\n if (w.headers && typeof w.headers.set === 'function') w.headers.set(sid, newHeader)\n if (w.sessionPaths && typeof w.sessionPaths.set === 'function') w.sessionPaths.set(sid, canonical)\n await target.attachSession(sid)\n\n // Verify the membership actually landed on the target workspace. DSH's\n // WorkspaceEntity.attachSession persists asynchronously; if it silently\n // no-ops (e.g. the session's durable cwd still points elsewhere) the UI\n // would show \"moved\" while the sidebar keeps the old grouping. Fail loud\n // instead of returning a fake success.\n const verified = (() => {\n try { return target.sessionIds.includes(sid) } catch (e) { return false }\n })()\n if (!verified) {\n throw new Error('\u79FB\u52A8\u540E\u6821\u9A8C\u5931\u8D25\uFF1A\u4F1A\u8BDD\u672A\u51FA\u73B0\u5728\u76EE\u6807\u5DE5\u4F5C\u533A\uFF0C\u8BF7\u91CD\u8BD5\u6216\u91CD\u542F DSH\u3002')\n }\n\n return {\n ok: true,\n moved: true,\n workspaceId: target.id,\n workspaceTitle: target.title,\n workspacePath: canonical,\n }\n }\n\n // Force the host's WorkspaceRegistry to rebuild its in-memory sessionPath\n // index from the durable persistence headers. DSH's WorkspaceEntity.sessionIds\n // is a *getter* that filters record.sessionIds by `host.sessionPath(id) ===\n // record.path`; that sessionPath Map is only repopulated at startup (bootstrap\n // + indexHeaders). So even after a successful move writes the durable cwd,\n // the running process keeps attributing the session to its OLD workspace until\n // a restart \u2014 unless we reindex here. Calling this right after move makes the\n // sidebar reflect the new grouping with NO restart required.\n async function reindexRegistry() {\n const reg = w\n if (!reg || typeof reg.replaceHeaderIndex !== 'function') return false\n let entries = null\n try { entries = await persistence.listEntries() } catch (e) { entries = null }\n if (!entries || !Array.isArray(entries)) return false\n await reg.replaceHeaderIndex(entries.map((entry) => entry.header))\n if (typeof reg.rebuildEntities === 'function') reg.rebuildEntities()\n return true\n }\n\n async function listWorkspaces() {\n const out = []\n try {\n for (const ent of w.list()) out.push({ workspaceId: ent.id, title: ent.title, path: ent.path })\n } catch (e) { /* ignore */ }\n return out\n }\n\n // Archive (hide) one session: adds its id to the durable archive set so it\n // is dropped out of the sidebar. DSH requires the session to exist (live or\n // persisted) \u2014 a genuine miss surfaces as an error.\n async function archiveOne(sid) {\n requireSessionId(sid)\n return mutateArchived(async (list) => {\n if (list.includes(sid)) return { next: null, value: { ok: true, archived: false } }\n await w.archiveSession(sid)\n // archiveSession owns the durable write; keep this operation serialized\n // with restoreOne so two requests cannot overwrite each other's state.\n return { next: null, value: { ok: true, archived: true } }\n })\n }\n\n // \u6279\u91CF\u6295\u5F71\uFF1A\u4E00\u6B21\u8C03\u7528\u628A\u591A\u6761\u4F1A\u8BDD\u7684\u6807\u9898/header \u62FF\u51FA\u6765\uFF0C\u907F\u514D\u9010\u6761\u89E6\u53D1\u6574\u672C\u89E3\u7801\u3002\n // \u8001 runtime \u6CA1\u6709 readTitleSnapshots \u65F6\u8FD4\u56DE\u7A7A Map\uFF0C\u8C03\u7528\u65B9\u81EA\u7136\u56DE\u9000\u5230\u9010\u6761\u6295\u5F71\n // \uFF08\u529F\u80FD\u4E0D\u53D7\u5F71\u54CD\uFF0C\u53EA\u662F\u5C11\u4E86\u8FD9\u5C42\u4F18\u5316\u2014\u2014\u63D2\u4EF6\u4E0D\u80FD\u5047\u8BBE\u5BF9\u65B9\u7684 runtime \u7248\u672C\uFF09\u3002\n async function projectTitles(ids) {\n const out = new Map()\n if (!ids || !ids.length) return out\n if (typeof sq.readTitleSnapshots !== 'function') return out\n try {\n const results = await sq.readTitleSnapshots(ids)\n if (!Array.isArray(results)) return out\n results.forEach((result, index) => {\n const id = String(ids[index])\n out.set(id, unwrapSnapshot(result))\n })\n } catch (e) { /* \u6279\u91CF\u5931\u8D25\uFF1A\u9010\u6761\u56DE\u9000 */ }\n return out\n }\n\n // opts.usage: expose sizeBytes + updatedAt on each item (storage analysis and\n // the auto-archive sweep need them; the panel list does not).\n //\n // \u6027\u80FD\u8981\u70B9\uFF08issue #1 + 0.1.3-alpha \u9002\u914D\uFF09\uFF1A\n // 1. sp.list() \u53EA\u8C03\u4E00\u6B21\uFF08\u539F\u5148\u5217\u4E86\u4E24\u904D\u76EE\u5F55\uFF09\n // 2. \u53D8\u66F4\u4EE4\u724C\u4F18\u5148\u6765\u81EA list \u5FEB\u7167\uFF1Alegacy \u8D70 locate+stat\uFF0CSessionHandle \u4E16\u4EE3\n // \u76F4\u63A5\u7528 snapshot.revision\uFF08\u65E0 locate \u53EF\u7528\uFF0C\u4E5F\u7EDD\u4E0D\u7ED5\u79C1\u6709\u8DEF\u5F84\u8865 stat\uFF09\n // 3. \u672A\u547D\u4E2D\u7F13\u5B58\u7684\u4F1A\u8BDD\u8D70**\u4E00\u6B21**\u6279\u91CF\u6295\u5F71\uFF08sq.readTitleSnapshots\uFF09\uFF0C\u800C\u4E0D\u662F\u9010\u6761\n async function allSessionItemsDetailed(opts = {}) {\n let entries = []\n let headersOk = false\n try {\n entries = await persistence.listEntries()\n headersOk = Array.isArray(entries)\n if (!headersOk) entries = []\n } catch (e) { entries = [] }\n const entryById = new Map(entries.map((entry) => [entry.id, entry]))\n let live = ctx.get('sessions')\n const ids = entries.map((entry) => entry.id)\n if (live) { try { live.list().forEach((s) => { const sid = String(s.id); if (!ids.includes(sid)) ids.push(sid) }) } catch (e) { /* ignore */ } }\n // Exclude sessions already moved to the recycle bin (\u8F6F\u5220\u9664): they live in\n // \u56DE\u6536\u7AD9, not in \u4F1A\u8BDD\u7BA1\u7406, so the panel won't re-list them after a delete.\n // purged tombstone \u53EA\u5BF9\u300C\u5F53\u524D\u4E0D\u5B58\u5728\u7684 id\u300D\u7EE7\u7EED\u9690\u85CF\uFF1A\u82E5\u540C id \u4F1A\u8BDD\u540E\u6765\u91CD\u65B0\n // \u51FA\u73B0\uFF08\u91CD\u5EFA/\u6362\u7ED1\u5B9A\uFF09\uFF0C\u5893\u7891\u5FC5\u987B\u8BA9\u4F4D\uFF0C\u4E0D\u80FD\u6C38\u4E45\u538B\u4F4F\u65B0\u4F1A\u8BDD\u3002\n let hiddenIds = new Set()\n try {\n const store = await readTrashStore()\n const present = new Set(ids)\n hiddenIds = new Set([\n ...store.items.map((t) => String(t.sessionId)),\n ...store.purgedSessionIds.map(String).filter((id) => !present.has(id)),\n ])\n } catch (e) {}\n const visibleIds = ids.filter((id) => !hiddenIds.has(id))\n wsByPath = {}\n try { for (const ent of w.list()) wsByPath[ent.path] = ent } catch (e) { wsByPath = {} }\n const currentArchived = new Set((await archivedState().catch(() => ({ archivedSessionIds: [] }))).archivedSessionIds || [])\n const items = []\n const usage = await collectUsage(entries)\n // \u5148\u6309\u6307\u7EB9\u628A\u300C\u7F13\u5B58\u547D\u4E2D\u300D\u4E0E\u300C\u9700\u8981\u89E3\u7801\u300D\u5206\u5F00\uFF0C\u53EA\u5BF9\u540E\u8005\u505A\u6279\u91CF\u6295\u5F71\u3002\n const statsById = new Map(visibleIds.map((id) => [\n id,\n (usage.statsById && usage.statsById.get(id)) || { mtimeMs: usage.mtimeById.get(id), size: usage.sizeById.get(id) },\n ]))\n const { missing } = metaCache.partition(visibleIds, statsById)\n // P4\uFF1Amissing \u91CC\u5148\u67E5\u6301\u4E45\u6807\u9898\u7D22\u5F15\uFF08\u51B7\u542F\u52A8\u8DF3\u8FC7\u6574\u672C\u89E3\u7801\uFF09\uFF0C\u547D\u4E2D\u7684\u56DE\u586B\u5185\u5B58\u7F13\u5B58\u3002\n const persisted = await hydrateFromPersist(missing, statsById)\n for (const [id, meta] of persisted) metaCache.set(id, statsById.get(id), meta)\n const stillMissing = missing.filter((id) => !persisted.has(id))\n const snapshotById = await projectTitles(stillMissing)\n const decoded = new Map()\n const collectDecoded = (id, meta) => { decoded.set(id, meta) }\n const CHUNK = 6\n for (let i = 0; i < visibleIds.length; i += CHUNK) {\n // Arrow wrapper on purpose: Array#map passes (value, index, array), and\n // resolveOne's second and third arguments are fixed here.\n const res2 = await Promise.all(visibleIds.slice(i, i + CHUNK).map((id) => {\n const entry = entryById.get(id)\n return resolveOne(id, usage, {\n exposeUsage: !!(opts && opts.usage),\n listHeader: entry ? entry.header : null,\n preloaded: snapshotById.has(id) ? snapshotById.get(id) : undefined,\n collectDecoded,\n })\n }))\n for (const it of res2) items.push({ ...it, archived: currentArchived.has(it.sessionId) })\n }\n persistDecoded(decoded, statsById)\n // Annotate stars; GC only when we have a trustworthy id baseline, so a\n // failing sp.list() can never wipe the whole index.\n let starredSet = new Set()\n try { starredSet = new Set((await stars.read()).starredSessionIds) } catch (e) {}\n for (const it of items) it.starred = starredSet.has(String(it.sessionId))\n if (headersOk) await gcStars(ids)\n return { items, usage }\n }\n\n async function allSessionItems(opts = {}) {\n return (await allSessionItemsDetailed(opts)).items\n }\n\n // ---- Storage usage + auto-archive ---------------------------------------\n\n // Read-only rollup: per-workspace totals plus the largest sessions. The\n // aggregation itself is a pure function (src/storage-stats.js).\n async function buildStorage(opts = {}) {\n const items = await allSessionItems({ usage: true })\n const raw = Number(opts && opts.topN)\n const topN = Number.isInteger(raw) && raw > 0 ? Math.min(raw, MAX_STORAGE_TOP) : 10\n return aggregateStorage(items, { topN })\n }\n\n // Archive conversations that have been idle past the configured window.\n //\n // Deliberately lazy \u2014 there is no timer. The sweep runs when the panel reads\n // its settings (and on demand), at most once a day: a background interval\n // would keep the host process alive and would archive conversations while\n // nobody is looking at the panel.\n async function autoArchiveSweep(opts = {}) {\n const store = await autoArchive.read()\n const days = store.settings.inactiveDays\n if (!days) return { ok: true, skipped: 'disabled', archived: 0 }\n const now = Date.now()\n if (!(opts && opts.force) && autoArchive.isFresh(store, now)) {\n return { ok: true, skipped: 'throttled', archived: 0, lastRunAt: store.lastRunAt, lastArchivedCount: store.lastArchivedCount }\n }\n const { items, usage } = await allSessionItemsDetailed({ usage: true })\n // SessionHandle \u4E16\u4EE3\u6CA1\u6709\u53EF\u9760\u7684\u300C\u6700\u540E\u6D3B\u8DC3\u65F6\u95F4\u300D\uFF08\u65E0 locate/mtime\uFF0C\u5FEB\u7167\u4E5F\u4E0D\n // \u643A\u5E26\u4E8B\u4EF6\u65F6\u95F4\uFF09\u3002\u65E0\u6CD5\u8BC1\u660E\u4F1A\u8BDD\u95F2\u7F6E \u2192 \u4E00\u5F8B\u8DF3\u8FC7\uFF0C\u7EDD\u4E0D\u731C\u6D4B\uFF08\u5B81\u53EF\u6F0F\u5F52\u6863\uFF0C\n // \u4E0D\u80FD\u9519\u5F52\u6863\uFF09\u3002UI \u4F1A\u5982\u5B9E\u5C55\u793A\u8BE5\u964D\u7EA7\u3002\n if (!usage.hasActivityData) {\n return {\n ok: true, skipped: 'no-activity-data', archived: 0,\n note: '\u5F53\u524D DSH \u7248\u672C\u672A\u63D0\u4F9B\u53EF\u9760\u7684\u6700\u540E\u6D3B\u8DC3\u65F6\u95F4\uFF0C\u81EA\u52A8\u5F52\u6863\u5DF2\u8DF3\u8FC7\uFF1B\u4E0D\u4F1A\u57FA\u4E8E\u731C\u6D4B\u5F52\u6863\u4EFB\u4F55\u4F1A\u8BDD\u3002',\n }\n }\n const candidates = pickInactiveCandidates(items, {\n inactiveDays: days,\n skipStarred: store.settings.skipStarred,\n activeSessionId: getActiveSessionId(ctx),\n now,\n })\n let archived = 0\n const failed = []\n for (const sid of candidates) {\n try {\n const result = await archiveOne(sid)\n if (result && result.archived) archived++\n } catch (e) {\n failed.push({ sessionId: sid, error: String((e && e.message) || e) })\n }\n }\n await autoArchive.recordRun(archived, now)\n return { ok: true, archived, candidates: candidates.length, failed, lastRunAt: now }\n }\n\n // \u4FA7\u680F\u6743\u5A01\u6570\u636E\uFF1A\u6807\u9898 + \u56DE\u6536\u7AD9 id \u96C6\u5408\u3002\n //\n // \u6807\u9898\u539F\u5148\u300C\u9996\u6B21\u8C03\u7528\u7B97\u4E00\u6B21\u5C31\u6C38\u4E45\u7F13\u5B58\u300D\uFF0C\u65E5\u5FD7\u4E4B\u540E\u518D\u53D8\u4E5F\u4E0D\u4F1A\u66F4\u65B0\u2014\u2014\u6807\u9898\u4F1A\u9648\u65E7\u3002\n // \u73B0\u5728\u590D\u7528 metaCache\uFF1A\u6BCF\u6B21\u8C03\u7528\u53EA stat \u4E00\u904D\uFF0C\u65E5\u5FD7\u6CA1\u53D8\u76F4\u63A5\u53D6\u7F13\u5B58\uFF0C\u53D8\u4E86\u624D\u91CD\u89E3\u7801\uFF0C\n // \u65E2\u4E0D\u4F1A\u9648\u65E7\u4E5F\u4E0D\u4F1A\u56DE\u5230\u300C\u6BCF\u6B21\u5168\u91CF\u89E3\u7801\u300D\u3002\n async function sidebarAuthority() {\n const ids = []\n let entries = []\n try { entries = await persistence.listEntries() } catch (e) { entries = [] }\n if (!Array.isArray(entries)) entries = []\n for (const entry of entries) ids.push(entry.id)\n const sessions = ctx.get('sessions')\n try { if (sessions) sessions.list().forEach((session) => { const sid = String(session.id); if (!ids.includes(sid)) ids.push(sid) }) } catch (e) {}\n const store = await readTrashStore()\n // \u5893\u7891\u53EA\u5BF9\u300C\u5F53\u524D\u4E0D\u5B58\u5728\u300D\u7684 id \u7EE7\u7EED\u8F93\u51FA\uFF1B\u540C id \u4F1A\u8BDD\u91CD\u65B0\u51FA\u73B0\u65F6\u5FC5\u987B\u8BA9\u4F4D\u3002\n const present = new Set(ids)\n const activeTombstones = store.purgedSessionIds.map(String).filter((id) => !present.has(id))\n if (ids.length) {\n const usage = await collectUsage(entries)\n const statsById = new Map(ids.map((id) => [\n id,\n (usage.statsById && usage.statsById.get(id)) || { mtimeMs: usage.mtimeById.get(id), size: usage.sizeById.get(id) },\n ]))\n const { cached, missing } = metaCache.partition(ids, statsById)\n // P4\uFF1A\u4E0E\u5217\u8868\u6784\u5EFA\u5171\u7528\u6301\u4E45\u6807\u9898\u7D22\u5F15\uFF0C\u51B7\u542F\u52A8\u96F6\u89E3\u7801\u3002\n const persisted = await hydrateFromPersist(missing, statsById)\n for (const [id, meta] of persisted) metaCache.set(id, statsById.get(id), meta)\n const rest = missing.filter((id) => !persisted.has(id))\n const snapshotById = await projectTitles(rest)\n const decoded = new Map()\n const collectDecoded = (id, meta) => { decoded.set(id, meta) }\n for (const id of ids) {\n let meta = cached.get(id) || persisted.get(id) || null\n if (!meta) {\n const entry = entries.find((e) => e.id === id)\n const snapshot = snapshotById.has(id)\n ? snapshotById.get(id)\n : (typeof sq.readTitleSnapshot === 'function' ? await sq.readTitleSnapshot(id).catch(() => null) : null)\n const next = metaFromSnapshot(snapshot)\n if (entry && entry.header) {\n if (!next.cwd && typeof entry.header.cwd === 'string') next.cwd = entry.header.cwd\n if (!next.createdAt && entry.header.createdAt != null) next.createdAt = entry.header.createdAt\n }\n metaCache.set(id, statsById.get(id), next)\n if (statsById.get(id)) collectDecoded(id, next)\n meta = next\n }\n if (meta && meta.title) authorityTitleCache.set(id, String(meta.title))\n }\n persistDecoded(decoded, statsById)\n }\n return {\n titles: Object.fromEntries(authorityTitleCache),\n trashedSessionIds: store.items.map((item) => String(item.sessionId)),\n purgedSessionIds: activeTombstones,\n }\n }\n\n // \u805A\u5408\u4E00\u6761\u4F1A\u8BDD\u7684\u8BE6\u60C5\uFF08\u78C1\u76D8\u5360\u7528 / \u8F6E\u6B21\u00B7\u6B65\u6570\u00B7\u6D88\u606F\u6570 / \u5DE5\u5177\u7EDF\u8BA1 / fetch /\n // write/edit \u6587\u4EF6 / \u8840\u7EDF parent/children/subagents\uFF09\u3002live \u4E0E\u6301\u4E45\u5316\u4F1A\u8BDD\u90FD\u53EF\u8BFB\u3002\n // \u6240\u6709\u7EDF\u8BA1\u5BF9\u672A\u77E5\u4E8B\u4EF6\u7C7B\u578B\u5BB9\u9519\uFF1Bfetch \u4E0E files \u505A\u4E0A\u9650\u622A\u65AD\uFF0Cfiles \u7528 stat \u8FC7\u6EE4\n // \u78C1\u76D8\u4E0A\u5DF2\u4E0D\u5B58\u5728\u7684\u8DEF\u5F84\uFF0C\u907F\u514D\u8BE6\u60C5\u9762\u677F\u5217\u51FA\u5DF2\u5220\u9664\u6587\u4EF6\u3002\n // \u6301\u4E45\u5316\u4F1A\u8BDD\u8D70 inspectSession \u5206\u5757\u6298\u53E0\uFF1A\u5927\u65E5\u5FD7\u4E0D\u518D\u6574\u672C\u9A7B\u7559\u5185\u5B58\uFF080.1.3-alpha\n // \u5DF2\u77E5\u5386\u53F2\u4F1A\u8BDD\u52A0\u8F7D\u6027\u80FD\u56DE\u9000\uFF0C\u8FD9\u91CC\u907F\u514D\u653E\u5927\u5B83\uFF09\u3002\n async function buildDetails(sid, signal) {\n const sessions = ctx.get('sessions')\n const live = sessions && sessions.get(sid)\n let meta = null\n let lastTime = 0\n const fileSet = new Map()\n const stats = {\n turns: 0, steps: 0, userMessages: 0, assistantMessages: 0,\n toolCalls: 0, attachments: 0, toolCounts: {}, fetches: [],\n }\n const turnSeen = new Set()\n const stepSeen = new Set()\n\n const absorb = (ev) => {\n if (ev && typeof ev.time === 'number' && ev.time > lastTime) lastTime = ev.time\n const d = (ev && ev.data && typeof ev.data === 'object') ? ev.data : {}\n const type = ev && ev.type\n switch (type) {\n case 'turn/start':\n if (typeof d.turn === 'number') turnSeen.add(d.turn)\n break\n case 'step/start':\n if (typeof d.step === 'number') stepSeen.add(d.step)\n break\n case 'user/message':\n stats.userMessages++\n if (Array.isArray(d.content)) for (const b of d.content) if (b && b.type === 'image') stats.attachments++\n break\n case 'assistant/message':\n stats.assistantMessages++\n break\n case 'tool/call': {\n stats.toolCalls++\n const tn = typeof d.name === 'string' && d.name ? d.name : 'tool'\n stats.toolCounts[tn] = (stats.toolCounts[tn] || 0) + 1\n if (FETCH_TOOL_RE.test(tn)) {\n let query\n try {\n const a = typeof d.arguments === 'string' ? JSON.parse(d.arguments) : d.arguments\n query = typeof a?.query === 'string' ? a.query : typeof a?.url === 'string' ? a.url : typeof a?.q === 'string' ? a.q : undefined\n } catch (e) { query = undefined }\n stats.fetches.push({ tool: tn, ...(query && query !== '' ? { query } : {}) })\n }\n if (tn === 'write' || tn === 'edit') {\n let argsJ\n try { argsJ = typeof d.arguments === 'string' ? JSON.parse(d.arguments) : d.arguments } catch (e) { break }\n const fp = argsJ && typeof argsJ.file_path === 'string' && argsJ.file_path ? argsJ.file_path : undefined\n if (fp !== undefined && !fileSet.has(fp)) fileSet.set(fp, tn)\n }\n break\n }\n }\n }\n\n if (live !== void 0) {\n meta = (live && live.header) || null\n try { (Array.isArray(live.events) ? [...live.events] : []).forEach(absorb) } catch (e) { /* empty */ }\n } else {\n const summary = await persistence.inspectSession(sid, { signal, onEvents: (batch) => { for (const ev of batch) absorb(ev) } })\n if (!summary || !summary.meta) throw new Error('\u627E\u4E0D\u5230\u8BE5\u4F1A\u8BDD\u7684\u8BB0\u5F55\uFF08\u4F1A\u8BDD\u4E0D\u5B58\u5728\uFF09')\n meta = summary.meta\n }\n stats.turns = turnSeen.size\n stats.steps = stepSeen.size\n let sizeBytes = null\n if (live === void 0) {\n // SessionHandle \u4E16\u4EE3\uFF1A\u5FEB\u7167\u76F4\u63A5\u5E26 sizeBytes\uFF08\u5B98\u65B9 JSONL \u540E\u7AEF\u5EC9\u4EF7\u63D0\u4F9B\uFF09\uFF1B\n // \u62FF\u4E0D\u5230\u518D\u9000\u56DE locate + stat\uFF08legacy\uFF09\u3002\u7EDD\u4E0D\u4F2A\u9020 0\u3002\n try {\n const stat = await persistence.statSession(sid)\n if (stat && Number.isFinite(stat.sizeBytes)) sizeBytes = stat.sizeBytes\n } catch (e) { /* fall through */ }\n }\n if (sizeBytes === null) {\n try {\n // rc.8 \u7684 sessionPersistence \u540E\u7AEF\u6CA1\u6709 artifactInfo\uFF1B\u7528 locate(meta) \u62FF\u65E5\u5FD7\n // \u6587\u4EF6\u771F\u5B9E\u8DEF\u5F84\u540E stat \u51FA\u5B57\u8282\u6570\uFF08\u78C1\u76D8\u5360\u7528\uFF09\u3002\n const loc = persistence.locate(meta)\n if (loc && typeof loc.path === 'string' && loc.path) {\n const st = await stat(loc.path)\n if (st && typeof st.size === 'number') sizeBytes = st.size\n }\n } catch (e) { sizeBytes = null }\n }\n if (stats.fetches.length > MAX_FETCHES) stats.fetches = stats.fetches.slice(0, MAX_FETCHES)\n const fileEntries = [...fileSet.entries()].slice(0, MAX_FILES * 2)\n const exists = await Promise.all(fileEntries.map(([p]) => stat(p).then(() => true).catch(() => false)))\n const files = fileEntries\n .filter((_, i) => exists[i])\n .map(([path, tool]) => ({ path, tool }))\n .slice(0, MAX_FILES)\n // lineage\uFF1A\u5206\u53C9\u5B50\u4F1A\u8BDD\uFF08\u975E subagent\uFF09\u4E0E\u5B50\u4EE3\u7406\uFF08origin==='subagent'\uFF09\uFF0Csource \u53BB\u91CD\u3002\n const lineage = {\n parentSessionId: (meta && typeof meta.parentSession === 'string') ? meta.parentSession : null,\n children: [],\n subagents: [],\n }\n const childrenSet = new Set()\n const subagentSet = new Set()\n try {\n if (typeof sp.list === 'function') {\n for (const entry of await persistence.listEntries()) {\n const h = entry.header\n if (String(h.parentSession) !== String(sid)) continue\n if (h.origin === 'subagent') subagentSet.add(h.id); else childrenSet.add(h.id)\n }\n }\n } catch (e) { /* best-effort */ }\n if (sessions) {\n try {\n sessions.list().forEach((s) => {\n if (String(s.header.parentSession) !== String(sid)) return\n if (s.header.origin === 'subagent') subagentSet.add(s.id); else childrenSet.add(s.id)\n })\n } catch (e) { /* best-effort */ }\n }\n lineage.children = [...childrenSet]\n lineage.subagents = [...subagentSet]\n return {\n sessionId: sid,\n sizeBytes,\n createdAt: (meta && typeof meta.createdAt === 'number') ? meta.createdAt : null,\n updatedAt: Math.max(lastTime || 0, (meta && typeof meta.createdAt === 'number' ? meta.createdAt : 0)) || null,\n files,\n stats,\n lineage,\n }\n }\n\n ctx.effect(() => {\n const disposers = []\n\n if (typeof ctx.on === 'function') disposers.push(ctx.on('session/event', (session, event) => {\n if (event && event.type === 'session/title' && event.data && typeof event.data.title === 'string') {\n authorityTitleCache.set(String(session.id), event.data.title)\n }\n }))\n\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/capabilities',\n handler: async (req, res) => json(res, capabilities),\n }))\n\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/list',\n handler: async (req, res) => {\n try {\n const state = await archivedState()\n const ids = state.archivedSessionIds || []\n // Only surface archived ids that still exist (materialized log or live).\n // Deleted sessions keep a hidden archive id but no log, so they drop out here.\n let materialized = new Set()\n let live = ctx.get('sessions')\n try {\n const entries = await persistence.listEntries()\n materialized = new Set(entries.map((entry) => entry.id))\n } catch (e) { /* best-effort */ }\n const trashStore = await readTrashStore()\n // \u5893\u7891\u53EA\u5BF9\u300C\u5F53\u524D\u4E0D\u5B58\u5728\u300D\u7684 id \u751F\u6548\uFF1B\u540C id \u4F1A\u8BDD\u91CD\u65B0\u51FA\u73B0\u65F6\u8BA9\u4F4D\u3002\n const present = new Set([\n ...materialized,\n ...ids.map(String),\n ...(live && typeof live.list === 'function' ? live.list().map((s) => String(s.id)) : []),\n ])\n const tombstones = trashStore.purgedSessionIds.map(String).filter((id) => !present.has(id))\n const hidden = new Set([...trashStore.items.map((item) => String(item.sessionId)), ...tombstones])\n const idStrs = ids.map(String).filter((id) => !hidden.has(id) && (materialized.has(id) || (live && live.get(id))))\n wsByPath = {}\n try { for (const ent of w.list()) wsByPath[ent.path] = ent } catch (e) { wsByPath = {} }\n const items = []\n const CHUNK = 6\n for (let i = 0; i < idStrs.length; i += CHUNK) {\n const res2 = await Promise.all(idStrs.slice(i, i + CHUNK).map((id) => resolveOne(id)))\n items.push.apply(items, res2)\n }\n json(res, { items })\n } catch (e) {\n json(res, { error: String((e && e.message) || e) }, 500)\n }\n },\n }))\n\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/restore',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const sid = body && typeof body.sessionId === 'string' ? body.sessionId : null\n if (!sid) return json(res, { ok: false, error: 'missing sessionId' }, 400)\n json(res, await restoreOne(sid))\n } catch (e) {\n json(res, { ok: false, error: String((e && e.message) || e) }, errorStatus(e))\n }\n },\n }))\n\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/restore-many',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const ids = parseIds(body)\n if (!ids || ids.length === 0) return json(res, { ok: false, error: 'missing sessionIds' }, 400)\n const results = []\n for (const sid of ids) {\n try { results.push({ sessionId: sid, ok: true, ...(await restoreOne(sid)) }) }\n catch (e) { results.push({ sessionId: sid, ok: false, code: e && e.code, error: String((e && e.message) || e) }) }\n }\n json(res, { ok: true, restored: results.filter((r) => r.ok).length, results })\n } catch (e) {\n json(res, { ok: false, code: e && e.code, error: String((e && e.message) || e) }, errorStatus(e))\n }\n },\n }))\n\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/delete',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const sid = body && typeof body.sessionId === 'string' ? body.sessionId : null\n if (!sid) return json(res, { ok: false, error: 'missing sessionId' }, 400)\n const out = await deleteOne(sid)\n // \u65E5\u5FD7\u88AB\u642C\u8FDB\u56DE\u6536\u7AD9\uFF08\u6587\u4EF6\u5DF2\u4E0D\u5728\u539F\u5904\uFF09\uFF1A\u4E22\u5F03\u7F13\u5B58\u6761\u76EE\uFF0C\u907F\u514D\u4E0B\u6B21 stat \u5931\u8D25\n // \u65F6\u6B8B\u7559\u65E7\u5143\u6570\u636E\u3002\n metaCache.invalidate(sid)\n json(res, out)\n } catch (e) {\n json(res, { ok: false, error: String((e && e.message) || e) }, errorStatus(e))\n }\n },\n }))\n\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/delete-many',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const ids = parseIds(body)\n if (!ids || ids.length === 0) return json(res, { ok: false, error: 'missing sessionIds' }, 400)\n const results = []\n for (const sid of ids) {\n try { results.push({ sessionId: sid, ok: true, ...(await deleteOne(sid)) }); metaCache.invalidate(sid) }\n catch (e) { results.push({ sessionId: sid, ok: false, error: String((e && e.message) || e) }) }\n }\n json(res, { ok: true, deleted: results.filter((r) => r.ok).length, results })\n } catch (e) {\n json(res, { ok: false, code: e && e.code, error: String((e && e.message) || e) }, errorStatus(e))\n }\n },\n }))\n\n // ---- Recycle bin (\u56DE\u6536\u7AD9) routes ----------------------------------------\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/trash/list',\n handler: async (req, res) => {\n try {\n await cleanupExpiredTrash()\n const list = await readTrash()\n list.sort((a, b) => (b.deletedAt || 0) - (a.deletedAt || 0))\n const store = await readTrashStore()\n json(res, { schemaVersion: store.schemaVersion, settings: store.settings, purgedSessionIds: store.purgedSessionIds, items: list })\n } catch (e) {\n json(res, { ok: false, error: String((e && e.message) || e) }, errorStatus(e))\n }\n },\n }))\n\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/trash/settings',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const settings = body && Object.prototype.hasOwnProperty.call(body, 'retentionDays')\n ? await trashSettings({ retentionDays: body.retentionDays })\n : await trashSettings()\n json(res, { ok: true, settings })\n } catch (e) {\n json(res, { ok: false, error: String((e && e.message) || e) }, errorStatus(e))\n }\n },\n }))\n\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/trash/verify',\n handler: async (req, res) => {\n try {\n const items = await readTrash()\n const results = await Promise.all(items.map(async (item) => {\n if (typeof item.originalPath !== 'string' || !item.originalPath) {\n return { sessionId: item.sessionId, status: 'unverified', originalPath: null }\n }\n const exists = await stat(item.originalPath).then(() => true).catch(() => false)\n return { sessionId: item.sessionId, status: exists ? 'ok' : 'missing', originalPath: item.originalPath }\n }))\n json(res, {\n ok: true,\n healthy: results.filter((r) => r.status === 'ok').length,\n missing: results.filter((r) => r.status === 'missing').length,\n unverified: results.filter((r) => r.status === 'unverified').length,\n results,\n })\n } catch (e) {\n json(res, { ok: false, error: String((e && e.message) || e) }, errorStatus(e))\n }\n },\n }))\n\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/trash/restore',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const sid = body && typeof body.sessionId === 'string' ? body.sessionId : null\n if (!sid) return json(res, { ok: false, error: 'missing sessionId' }, 400)\n const out = await restoreFromTrash(sid)\n metaCache.invalidate(sid)\n json(res, out)\n } catch (e) {\n json(res, { ok: false, code: e && e.code, error: String((e && e.message) || e) }, errorStatus(e))\n }\n },\n }))\n\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/trash/purge',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const sid = body && typeof body.sessionId === 'string' ? body.sessionId : null\n if (!sid) return json(res, { ok: false, error: 'missing sessionId' }, 400)\n const out = await purgeFromTrash(sid)\n metaCache.invalidate(sid)\n // \u5F7B\u5E95\u5220\u9664\uFF1A\u6301\u4E45\u6807\u9898\u7D22\u5F15\u91CC\u7684\u6761\u76EE\u4E00\u5E76\u6E05\u6389\uFF08issue #1 P4\uFF09\u3002\n titleIndex.remove([sid]).catch(() => {})\n json(res, out)\n } catch (e) {\n json(res, { ok: false, code: e && e.code, error: String((e && e.message) || e) }, errorStatus(e))\n }\n },\n }))\n\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/trash/purge-many',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const ids = parseIds(body)\n if (!ids || ids.length === 0) return json(res, { ok: false, error: 'missing sessionIds' }, 400)\n const results = []\n for (const sid of ids) {\n try { results.push({ sessionId: sid, ok: true, ...(await purgeFromTrash(sid)) }); metaCache.invalidate(sid); titleIndex.remove([sid]).catch(() => {}) }\n catch (e) { results.push({ sessionId: sid, ok: false, error: String((e && e.message) || e) }) }\n }\n json(res, { ok: true, purged: results.filter((r) => r.ok).length, results })\n } catch (e) {\n json(res, { ok: false, code: e && e.code, error: String((e && e.message) || e) }, errorStatus(e))\n }\n },\n }))\n\n // All conversations (for the \"\u79FB\u52A8\u4F1A\u8BDD\" panel).\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/sessions',\n handler: async (req, res) => {\n try {\n json(res, { items: await allSessionItems() })\n } catch (e) {\n json(res, { error: String((e && e.message) || e) }, 500)\n }\n },\n }))\n\n // Star / unstar one or many sessions (\u6536\u85CF, schema v3).\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/star/set',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const starred = !!(body && body.starred)\n let ids = parseIds(body)\n if ((!ids || ids.length === 0) && body && typeof body.sessionId === 'string') {\n ids = isSafeSessionId(body.sessionId) ? [body.sessionId] : null\n }\n if (!ids || ids.length === 0) return json(res, { ok: false, error: 'missing sessionId' }, 400)\n const starredSessionIds = await stars.setStarred(ids, starred)\n json(res, { ok: true, starredSessionIds })\n } catch (e) {\n json(res, { ok: false, error: String((e && e.message) || e) }, errorStatus(e))\n }\n },\n }))\n\n // Human-readable Markdown export (one session). Raw-log ZIP export is\n // dsh's own GET /api/session.export \u2014 we deliberately do not duplicate it\n // (see reports/HANDOFF-dsh-sessions-manager-roadmap.md \u00A72.4).\n //\n // 0.1.3 \u517C\u5BB9\uFF1A\u65E5\u5FD7\u7ECF inspectSession \u5206\u5757\u8BFB\u53D6\uFF08SessionHandle.read \u7684\n // offset/length \u6709\u754C\u5207\u7247\uFF09\uFF0C\u6D41\u5F0F\u6E32\u67D3 Markdown\uFF0C\u5BA2\u6237\u7AEF\u65AD\u5F00\u5373\u53D6\u6D88\uFF08signal\uFF09\uFF0C\n // \u5E76\u53D7\u5168\u5C40\u5E76\u53D1\u95F8\u7EA6\u675F\u2014\u2014\u5927\u65E5\u5FD7\u4E0D\u518D\u4E00\u6B21\u6027\u6574\u672C\u9A7B\u7559\u5185\u5B58\u3002\n const exportLimiter = createLimiter(2)\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/export-md',\n handler: async (req, res) => {\n try {\n const url = new URL(req.url, 'http://localhost')\n const sid = url.searchParams.get('sessionId')\n requireSessionId(sid)\n const ac = new AbortController()\n res.on('close', () => { if (!res.writableEnded) ac.abort() })\n const md = await exportLimiter(async () => {\n const builder = createSessionMarkdownBuilder({ id: sid })\n const summary = await persistence.inspectSession(sid, {\n signal: ac.signal,\n onEvents: (batch) => builder.addEvents(batch),\n })\n if (!summary || !summary.meta) {\n const error = new Error('\u65E0\u6CD5\u8BFB\u53D6\u8BE5\u4F1A\u8BDD\u7684\u65E5\u5FD7')\n error.status = 404\n throw error\n }\n // meta \u5728\u6D41\u7ED3\u675F\u540E\u624D\u6743\u5A01\uFF08header \u6765\u81EA open \u56DE\u5305\uFF09\uFF1Bfinish \u8986\u5199 front matter\u3002\n return builder.finish({ ...summary.meta, id: sid })\n })\n res.writeHead(200, {\n 'content-type': 'text/markdown; charset=utf-8',\n 'content-disposition': `attachment; filename=\"dsh-session-${sid}.md\"`,\n 'cache-control': 'no-store',\n })\n res.end(md)\n } catch (e) {\n json(res, { error: String((e && e.message) || e) }, errorStatus(e))\n }\n },\n }))\n\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/sidebar-state',\n handler: async (req, res) => {\n try {\n json(res, await sidebarAuthority())\n } catch (e) {\n json(res, { error: String((e && e.message) || e) }, errorStatus(e))\n }\n },\n }))\n\n // Available target workspaces (for the move picker).\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/workspaces',\n handler: async (req, res) => {\n try {\n json(res, { items: await listWorkspaces() })\n } catch (e) {\n json(res, { error: String((e && e.message) || e) }, 500)\n }\n },\n }))\n\n // Move one conversation to a target workspace (existing path or a new one).\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/move',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const sid = body && typeof body.sessionId === 'string' ? body.sessionId : null\n const target = body && typeof body.targetPath === 'string' ? body.targetPath : null\n if (!sid) return json(res, { ok: false, error: 'missing sessionId' }, 400)\n if (!target) return json(res, { ok: false, error: 'missing targetPath' }, 400)\n const moved = await moveOne(sid, target)\n // \u79FB\u52A8\u4F1A\u6539\u5199\u65E5\u5FD7 frame0 \u7684 cwd\uFF1A\u5143\u6570\u636E\uFF08cwd\uFF09\u5DF2\u53D8\uFF0C\u4E3B\u52A8\u4E22\u5F03\u7F13\u5B58\u6761\u76EE\uFF0C\n // \u4E0D\u7B49 mtime \u6307\u7EB9\u81EA\u7136\u5931\u6548\uFF08Windows \u4E0A mtime \u7CBE\u5EA6\u8F83\u7C97\uFF0C\u6307\u7EB9\u53EF\u80FD\u4E0D\u53D8\uFF09\u3002\n metaCache.invalidate(sid)\n // Reindex the host's in-memory sessionPath index so the sidebar\n // reflects the new grouping immediately (no DSH restart needed).\n // Do this before replying: drag/drop and menu clients treat a 2xx\n // response as the commit point and must never announce success while\n // the sidebar still holds the old workspace index.\n try { await reindexRegistry() } catch (e) { /* best-effort */ }\n json(res, { sessionId: sid, ...moved })\n } catch (e) {\n json(res, { ok: false, code: e && e.code, error: String((e && e.message) || e) }, errorStatus(e))\n }\n },\n }))\n\n // Archive (hide) one session.\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/archive',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const sid = body && typeof body.sessionId === 'string' ? body.sessionId : null\n if (!sid) return json(res, { ok: false, error: 'missing sessionId' }, 400)\n json(res, { sessionId: sid, ...(await archiveOne(sid)) })\n } catch (e) {\n json(res, { ok: false, error: String((e && e.message) || e) }, 500)\n }\n },\n }))\n\n // Archive (hide) many sessions.\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/archive-many',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const ids = parseIds(body)\n if (!ids || ids.length === 0) return json(res, { ok: false, error: 'missing sessionIds' }, 400)\n const results = []\n for (const sid of ids) {\n try { results.push({ sessionId: sid, ok: true, ...(await archiveOne(sid)) }) }\n catch (e) { results.push({ sessionId: sid, ok: false, error: String((e && e.message) || e) }) }\n }\n json(res, { ok: true, archived: results.filter((r) => r.ok).length, results })\n } catch (e) {\n json(res, { ok: false, error: String((e && e.message) || e) }, 500)\n }\n },\n }))\n\n // Per-session details (v2.0): disk usage, turn/step/message counts, tool\n // usage, fetch records, write/edit files, and lineage.\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/details',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const sid = body && typeof body.sessionId === 'string' ? body.sessionId : null\n if (!sid) return json(res, { ok: false, error: 'missing sessionId' }, 400)\n // \u5BA2\u6237\u7AEF\u65AD\u5F00\u65F6\u53D6\u6D88\u5206\u5757\u8BFB\u53D6\uFF0C\u907F\u514D\u4E3A\u5DF2\u79BB\u5F00\u7684\u8BF7\u6C42\u7EE7\u7EED\u89E3\u7801\u6574\u672C\u65E5\u5FD7\u3002\n const ac = new AbortController()\n res.on('close', () => { if (!res.writableEnded) ac.abort() })\n json(res, await buildDetails(sid, ac.signal))\n } catch (e) {\n json(res, { error: String((e && e.message) || e) }, (e && e.status) ? e.status : 500)\n }\n },\n }))\n\n // Storage usage rollup (read-only): per-workspace totals + largest sessions.\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/storage',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n json(res, await buildStorage({ topN: body && body.topN }))\n } catch (e) {\n json(res, { error: String((e && e.message) || e) }, 500)\n }\n },\n }))\n\n // Auto-archive settings. A plain read (no patch keys) doubles as the lazy\n // sweep trigger \u2014 that is how the once-a-day cleanup gets a chance to run\n // without a background timer. The sweep runs in the background so opening\n // the panel never waits on it (P5, issue #1): the sweep itself already\n // reuses the metadata caches, and this keeps the settings read latency\n // independent of library size.\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/auto-archive/settings',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const patch = {}\n if (body && Object.prototype.hasOwnProperty.call(body, 'inactiveDays')) patch.inactiveDays = body.inactiveDays\n if (body && Object.prototype.hasOwnProperty.call(body, 'skipStarred')) patch.skipStarred = body.skipStarred\n const isPatch = Object.keys(patch).length > 0\n const settings = isPatch\n ? await autoArchive.update(patch)\n : (await autoArchive.read()).settings\n let sweep\n if (isPatch) {\n // \u663E\u5F0F\u4FDD\u5B58\u8BBE\u7F6E\uFF1A\u4FDD\u6301\u300C\u4FDD\u5B58\u5373\u751F\u6548\u300D\u7684\u540C\u6B65 sweep\uFF08\u542B\u521A\u542F\u7528\u65F6\u7684\u9996\u6B21\u5F52\u6863\uFF09\u3002\n sweep = await autoArchiveSweep()\n } else {\n // \u9762\u677F\u6253\u5F00\u7684\u7EAF\u8BFB\u53D6\uFF1Asweep \u8F6C\u540E\u53F0\u6267\u884C\uFF0C\u6253\u5F00\u5EF6\u8FDF\u4E0E\u5E93\u5927\u5C0F\u89E3\u8026\n //\uFF08P5\uFF0Cissue #1\uFF09\u3002sweep \u672C\u8EAB\u5DF2\u590D\u7528\u5143\u6570\u636E\u7F13\u5B58 + \u6301\u4E45\u6807\u9898\u7D22\u5F15\u3002\n void autoArchiveSweep().catch(() => {})\n sweep = { triggered: true }\n }\n const store = await autoArchive.read()\n json(res, {\n ok: true,\n settings,\n lastRunAt: store.lastRunAt,\n lastArchivedCount: store.lastArchivedCount,\n sweep,\n })\n } catch (e) {\n json(res, { ok: false, error: String((e && e.message) || e) }, errorStatus(e))\n }\n },\n }))\n\n // Run the auto-archive sweep right now, ignoring the once-a-day throttle.\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/auto-archive/run',\n handler: async (req, res) => {\n try {\n const sweep = await autoArchiveSweep({ force: true })\n const store = await autoArchive.read()\n json(res, { ok: true, ...sweep, settings: store.settings, lastRunAt: store.lastRunAt, lastArchivedCount: store.lastArchivedCount })\n } catch (e) {\n json(res, { ok: false, error: String((e && e.message) || e) }, 500)\n }\n },\n }))\n\n return () => { for (const d of disposers) d() }\n }, 'dsh-sessions-manager: routes')\n}\n", "// dsh-sessions-manager \u2014 zstd frame helpers.\n//\n// DSH persists session logs as a sequence of concatenated zstd frames. The\n// FIRST frame must be exactly one line: the session header JSON (type\n// 'session'). The persistence layer enforces this on startup\n// (assertZstdHeaderFrame), so any corruption of frame0 takes down the whole\n// web profile.\n//\n// Moving a session between workspaces requires rewriting frame0's `cwd`\n// without re-encoding the rest of the log. That rewrite is where a bad frame\n// boundary can silently destroy a session \u2014 hence the defensive checks here.\n\nimport zlib from 'node:zlib'\nimport { readFileSync, writeFileSync } from 'node:fs'\n\n// zstd magic bytes are 28 B5 2F FD; read as a little-endian uint32 that is\n// 0xFD2FB528 (4247762216).\nexport const ZSTD_MAGIC = 0xFD2FB528\n\nconst CHECKSUM_OPTS = { params: { [zlib.constants.ZSTD_c_checksumFlag]: 1 } }\n\n/**\n * Parse complete concatenated Zstandard frames without decompressing them.\n * Invalid complete structure rejects; EOF inside the final frame is reported\n * as torn rather than guessed from magic bytes occurring in compressed data.\n *\n * @param {Buffer} buf\n * @param {number} maxFrames\n * @returns {{frames: Array<{start:number,end:number}>, tornStart?: number}}\n */\nexport function scanZstdFrames(buf, maxFrames = Number.POSITIVE_INFINITY) {\n const frames = []\n let offset = 0\n while (offset < buf.length) {\n const start = offset\n if (buf.length - offset < 4) return { frames, tornStart: start }\n if (buf.readUInt32LE(offset) !== ZSTD_MAGIC) {\n throw new Error(`\u4F1A\u8BDD\u65E5\u5FD7\u683C\u5F0F\u5F02\u5E38\uFF08\u5B57\u8282 ${offset} \u7684 zstd magic \u65E0\u6548\uFF09`)\n }\n offset += 4\n if (offset === buf.length) return { frames, tornStart: start }\n\n const descriptor = buf.readUInt8(offset++)\n if ((descriptor & 0x18) !== 0) throw new Error(`\u4F1A\u8BDD\u65E5\u5FD7\u683C\u5F0F\u5F02\u5E38\uFF08\u5B57\u8282 ${offset - 1} \u4F7F\u7528\u4FDD\u7559\u5E27\u5934\u4F4D\uFF09`)\n const contentSizeFlag = descriptor >>> 6\n const singleSegment = (descriptor & 0x20) !== 0\n const checksum = (descriptor & 0x04) !== 0\n const dictionaryFlag = descriptor & 0x03\n const dictionaryBytes = dictionaryFlag === 3 ? 4 : dictionaryFlag\n const contentSizeBytes = contentSizeFlag === 0 ? (singleSegment ? 1 : 0) : 1 << contentSizeFlag\n const remainingHeaderBytes = (singleSegment ? 0 : 1) + dictionaryBytes + contentSizeBytes\n if (buf.length - offset < remainingHeaderBytes) return { frames, tornStart: start }\n offset += remainingHeaderBytes\n\n for (;;) {\n if (buf.length - offset < 3) return { frames, tornStart: start }\n const blockHeader = buf.readUIntLE(offset, 3)\n offset += 3\n const lastBlock = (blockHeader & 1) !== 0\n const blockType = (blockHeader >>> 1) & 0x03\n const blockSize = blockHeader >>> 3\n if (blockType === 0x03) throw new Error(`\u4F1A\u8BDD\u65E5\u5FD7\u683C\u5F0F\u5F02\u5E38\uFF08\u5B57\u8282 ${offset - 3} \u4F7F\u7528\u4FDD\u7559\u5757\u7C7B\u578B\uFF09`)\n const payloadBytes = blockType === 0x01 ? 1 : blockSize\n if (buf.length - offset < payloadBytes) return { frames, tornStart: start }\n offset += payloadBytes\n if (lastBlock) break\n }\n if (checksum) {\n if (buf.length - offset < 4) return { frames, tornStart: start }\n offset += 4\n }\n frames.push({ start, end: offset })\n if (frames.length === maxFrames) return { frames }\n }\n return { frames }\n}\n\n/** Backward-compatible frame-start view used by diagnostics and tests. */\nexport function findZstdFrameStarts(buf) {\n return scanZstdFrames(buf).frames.map((frame) => frame.start)\n}\n\nfunction firstFrame(buf) {\n const scan = scanZstdFrames(buf, 1)\n const frame = scan.frames[0]\n if (!frame) throw new Error('\u4F1A\u8BDD\u65E5\u5FD7\u683C\u5F0F\u5F02\u5E38\uFF08\u65E0\u5B8C\u6574 zstd \u5E27\uFF09')\n return frame\n}\n\n/**\n * Rewrite the `cwd` field of a session log's first frame, leaving all\n * subsequent frames byte-identical.\n *\n * Refuses to write anything unless frame0 is a session header. A corrupted\n * frame0 (e.g. an `agent/inbox/spliced` event) is reported as an error rather\n * than being re-serialized back to disk \u2014 rewriting it would bake the\n * corruption in permanently and make the file unrecoverable.\n *\n * @param {string} filePath path to session.jsonl.zstd\n * @param {string} newCwd workspace path to write into frame0\n * @throws {Error} when the log has no zstd frame or frame0 is not a session header\n */\nexport function rewriteFrame0Cwd(filePath, newCwd) {\n const buf = readFileSync(filePath)\n const frame = firstFrame(buf)\n const end0 = frame.end\n const frame0 = buf.subarray(frame.start, end0)\n const text = zlib.zstdDecompressSync(frame0).toString('utf8')\n const nl = text.indexOf('\\n')\n const line = nl >= 0 ? text.slice(0, nl) : text\n const obj = JSON.parse(line)\n if (obj.type !== 'session') {\n throw new Error(`\u4F1A\u8BDD\u65E5\u5FD7\u683C\u5F0F\u5F02\u5E38\uFF08\u5E270 \u4E0D\u662F session header\uFF0C\u5B9E\u9645 type=${obj.type}\uFF09`)\n }\n if (obj.cwd === newCwd) return // already correct, no rewrite needed\n obj.cwd = newCwd\n const newFrame0 = zlib.zstdCompressSync(JSON.stringify(obj) + '\\n', CHECKSUM_OPTS)\n const rest = buf.subarray(end0)\n writeFileSync(filePath, Buffer.concat([newFrame0, rest]))\n}\n\n/**\n * Non-destructive variant of rewriteFrame0Cwd: returns the rewritten buffer\n * instead of touching the file on disk. Used by tests.\n *\n * @param {Buffer} buf\n * @param {string} newCwd\n * @returns {Buffer} rewritten log\n */\nexport function rewriteFrame0CwdInMemory(buf, newCwd) {\n const frame = firstFrame(buf)\n const end0 = frame.end\n const frame0 = buf.subarray(frame.start, end0)\n const text = zlib.zstdDecompressSync(frame0).toString('utf8')\n const nl = text.indexOf('\\n')\n const line = nl >= 0 ? text.slice(0, nl) : text\n const obj = JSON.parse(line)\n if (obj.type !== 'session') {\n throw new Error(`\u4F1A\u8BDD\u65E5\u5FD7\u683C\u5F0F\u5F02\u5E38\uFF08\u5E270 \u4E0D\u662F session header\uFF0C\u5B9E\u9645 type=${obj.type}\uFF09`)\n }\n obj.cwd = newCwd\n const newFrame0 = zlib.zstdCompressSync(JSON.stringify(obj) + '\\n', CHECKSUM_OPTS)\n const rest = buf.subarray(end0)\n return Buffer.concat([newFrame0, rest])\n}\n\n/**\n * Build a multi-frame session log buffer (header frame + event frames),\n * matching the layout DSH's persistence layer writes. Used by tests.\n *\n * @param {object} header session header (must have type: 'session')\n * @param {object[]} events subsequent records, one zstd frame each\n * @returns {Buffer}\n */\nexport function buildSessionLog(header, events = []) {\n const frames = [JSON.stringify(header) + '\\n', ...events.map((e) => JSON.stringify(e) + '\\n')]\n return Buffer.concat(frames.map((f) => zlib.zstdCompressSync(Buffer.from(f, 'utf8'), CHECKSUM_OPTS)))\n}\n\n/**\n * Read frame0 of a session log and return the parsed header line.\n *\n * @param {Buffer} buf\n * @returns {{obj: object, lineCount: number}}\n */\nexport function readFrame0(buf) {\n const frame = firstFrame(buf)\n const text = zlib.zstdDecompressSync(buf.subarray(frame.start, frame.end)).toString('utf8')\n const lines = text.split('\\n').filter((l) => l.length > 0)\n return { obj: JSON.parse(lines[0]), lineCount: lines.length }\n}\n", "// Render a session log as human-readable Markdown.\n//\n// Pure: no DOM, no I/O, no dsh imports. Everything it needs arrives as\n// arguments, so the renderer is unit-testable without a running host.\n//\n// Field shapes below were read off real session logs (2026-09-01), not guessed:\n// user/message data.content = [{ type:'text', text } | { type:'image', ... }]\n// assistant/message data.message.content = [{ type:'text'|'reasoning'|'tool-call', ... }]\n// tool/call data.{name, arguments} (arguments is a JSON *string*)\n// tool/result data.message.content = [{ type:'tool-result', content:[{type:'text',text}] }]\n// Note the asymmetry: user text lives at data.content, assistant text one level\n// deeper at data.message.content. Streaming deltas (`assistant/chunk`,\n// `text-chunks`, `reasoning-chunks`) are never rendered \u2014 `assistant/message`\n// already carries the final text for each step.\n\nconst MAX_TOOL_ARG = 200\n\nfunction isoTime(value) {\n if (typeof value !== 'number' || !Number.isFinite(value) || value <= 0) return null\n try { return new Date(value).toISOString() } catch { return null }\n}\n\nfunction yamlString(value) {\n return `\"${String(value).replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"').replace(/\\r?\\n/g, '\\\\n')}\"`\n}\n\nfunction blocksOf(value) {\n return Array.isArray(value) ? value.filter((b) => b && typeof b === 'object') : []\n}\n\n// Join the text blocks of a content array; image blocks are counted separately.\nfunction textFromBlocks(blocks) {\n const parts = []\n for (const block of blocks) {\n if (block.type === 'text' && typeof block.text === 'string') parts.push(block.text)\n }\n return parts.join('\\n\\n').trim()\n}\n\nfunction imageCountOf(blocks) {\n let count = 0\n for (const block of blocks) if (block.type === 'image') count++\n return count\n}\n\nfunction reasoningFromBlocks(blocks) {\n const parts = []\n for (const block of blocks) {\n if (block.type === 'reasoning' && typeof block.text === 'string' && block.text.trim()) parts.push(block.text.trim())\n }\n return parts.join('\\n\\n')\n}\n\n// A short, human-usable summary of one tool call's arguments.\nexport function summarizeToolArguments(name, rawArguments) {\n let parsed = null\n if (typeof rawArguments === 'string') {\n try { parsed = JSON.parse(rawArguments) } catch { parsed = null }\n } else if (rawArguments && typeof rawArguments === 'object') {\n parsed = rawArguments\n }\n if (parsed === null) return typeof rawArguments === 'string' ? rawArguments.slice(0, MAX_TOOL_ARG) : ''\n if (typeof parsed !== 'object') return String(parsed).slice(0, MAX_TOOL_ARG)\n const preferred = ['command', 'file_path', 'path', 'query', 'url', 'pattern']\n for (const key of preferred) {\n if (typeof parsed[key] === 'string' && parsed[key].trim()) return parsed[key]\n }\n const keys = Object.keys(parsed)\n if (keys.length === 0) return ''\n const rest = {}\n for (const key of keys.slice(0, 6)) {\n const value = parsed[key]\n rest[key] = typeof value === 'string' ? value : JSON.stringify(value)\n }\n return JSON.stringify(rest).slice(0, MAX_TOOL_ARG)\n}\n\n// Shared event fold. `out` accumulates markdown lines; both the one-shot\n// renderer and the streaming builder (large-log export, see export-md route)\n// consume it so their output is byte-identical for the same events.\nfunction createMarkdownFold(out, header, options) {\n const includeReasoning = options.includeReasoning === true\n const includeToolResults = options.includeToolResults === true\n let title = typeof header.title === 'string' && header.title.trim() ? header.title.trim() : null\n let turn = null\n return {\n get title() { return title },\n // The last session/title event wins \u2014 DSH may retitle a session later on.\n add(events) {\n const list = Array.isArray(events) ? events : []\n for (const ev of list) {\n if (!ev || typeof ev !== 'object') continue\n const data = ev.data && typeof ev.data === 'object' ? ev.data : {}\n const type = ev.type\n\n if (type === 'session/title' && data && typeof data.title === 'string' && data.title.trim()) {\n title = data.title.trim()\n continue\n }\n\n if (type === 'turn/start') {\n const next = Number.isInteger(data.turn) ? data.turn : null\n if (next !== null && next !== turn) {\n turn = next\n out.push('', `## \u7B2C ${turn} \u8F6E`)\n }\n continue\n }\n\n if (type === 'user/message') {\n const blocks = blocksOf(data.content)\n const text = textFromBlocks(blocks)\n const images = imageCountOf(blocks)\n if (!text && images === 0) continue\n out.push('', '### \u7528\u6237', '')\n if (text) out.push(text)\n for (let i = 0; i < images; i++) out.push('', ``)\n continue\n }\n\n if (type === 'assistant/message') {\n const message = data.message && typeof data.message === 'object' ? data.message : {}\n const blocks = blocksOf(message.content)\n const text = textFromBlocks(blocks)\n const reasoning = includeReasoning ? reasoningFromBlocks(blocks) : ''\n if (!text && !reasoning) continue\n out.push('', '### \u52A9\u624B', '')\n if (reasoning) out.push('> \u601D\u8003\uFF1A' + reasoning.split('\\n').join('\\n> '), '')\n if (text) out.push(text)\n continue\n }\n\n if (type === 'tool/call') {\n const name = typeof data.name === 'string' && data.name ? data.name : 'tool'\n const summary = summarizeToolArguments(name, data.arguments)\n out.push('', `### \u5DE5\u5177\u8C03\u7528\uFF1A\\`${name}\\``, '')\n out.push(summary ? '```\\n' + summary + '\\n```' : '\uFF08\u65E0\u53C2\u6570\uFF09')\n continue\n }\n\n if (type === 'tool/result' && includeToolResults) {\n const message = data.message && typeof data.message === 'object' ? data.message : {}\n const blocks = blocksOf(message.content)\n let text = ''\n for (const block of blocks) {\n if (block.type === 'tool-result') text = textFromBlocks(blocksOf(block.content))\n }\n if (text) out.push('', '<details><summary>\u5DE5\u5177\u7ED3\u679C</summary>', '', '```\\n' + text.slice(0, 2000) + '\\n```', '', '</details>')\n }\n }\n },\n }\n}\n\n/**\n * Render one session as Markdown.\n * @param {object} meta - Session header (`{ id, cwd, createdAt, title? }`).\n * @param {Array<object>} events - Session events as stored in the log.\n * @param {object} [options]\n * @param {boolean} [options.includeReasoning=false] - Emit assistant reasoning blocks.\n * @param {boolean} [options.includeToolResults=false] - Emit tool results.\n * @param {number} [options.exportedAt] - Override the export timestamp (tests).\n * @returns {string} Markdown document.\n */\nexport function renderSessionMarkdown(meta, events, options = {}) {\n const header = meta && typeof meta === 'object' ? meta : {}\n const out = []\n\n const fold = createMarkdownFold(out, header, options)\n fold.add(events)\n const title = fold.title\n\n const front = ['---']\n if (title) front.push(`title: ${yamlString(title)}`)\n if (typeof header.id === 'string' && header.id) front.push(`sessionId: ${yamlString(header.id)}`)\n if (typeof header.cwd === 'string' && header.cwd) front.push(`cwd: ${yamlString(header.cwd)}`)\n const created = isoTime(header.createdAt)\n if (created) front.push(`createdAt: ${created}`)\n const exported = isoTime(options.exportedAt)\n if (exported) front.push(`exportedAt: ${exported}`)\n front.push('---')\n\n const doc = [front.join('\\n')]\n if (title) doc.push('', `# ${title}`)\n doc.push(...out, '')\n return doc.join('\\n')\n}\n\n/**\n * Streaming variant of {@link renderSessionMarkdown} for chunked log reads\n * (SessionHandle.read offset/length). Feed event batches in log order via\n * `addEvents`; call `finish()` to get the same markdown document the one-shot\n * renderer would produce. Only the final title (last session/title event)\n * lands in the front matter, so streaming cannot be wrong about it.\n *\n * `finish(metaOverride)` \u2014 when the caller streams first and only learns the\n * authoritative header afterwards (adapter inspectSession returns `meta` with\n * the summary), pass it here; it replaces the constructor `meta` for the front\n * matter fields (id / cwd / createdAt). Title always comes from the folded\n * events, never from the override.\n */\nexport function createSessionMarkdownBuilder(meta, options = {}) {\n const header = meta && typeof meta === 'object' ? meta : {}\n const body = []\n const fold = createMarkdownFold(body, header, options)\n return {\n addEvents(events) { fold.add(events) },\n finish(metaOverride) {\n const effective = metaOverride && typeof metaOverride === 'object' ? metaOverride : header\n const title = fold.title\n const front = ['---']\n if (title) front.push(`title: ${yamlString(title)}`)\n if (typeof effective.id === 'string' && effective.id) front.push(`sessionId: ${yamlString(effective.id)}`)\n if (typeof effective.cwd === 'string' && effective.cwd) front.push(`cwd: ${yamlString(effective.cwd)}`)\n const created = isoTime(effective.createdAt)\n if (created) front.push(`createdAt: ${created}`)\n const exported = isoTime(options.exportedAt)\n if (exported) front.push(`exportedAt: ${exported}`)\n front.push('---')\n const doc = [front.join('\\n')]\n if (title) doc.push('', `# ${title}`)\n doc.push(...body, '')\n return doc.join('\\n')\n },\n }\n}\n", "// Durable \"starred sessions\" index (schema v3).\n//\n// Deliberately mirrors the recycle-bin index in src/index.js: version field,\n// automatic upgrade of older shapes, atomic write (tmp + rename) and a single\n// chained mutation queue so two concurrent requests can never clobber each\n// other. Extracted from the host bundle so it can be unit-tested directly \u2014\n// pass `dir` to point the index at a temp directory.\nimport { mkdir, rename, writeFile } from 'node:fs/promises'\nimport { readFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\n\n// v3 is the first star schema; it starts at 3 so it can never be confused with\n// the recycle bin's v1/v2 documents even if a file is copied between them.\nexport const STAR_SCHEMA_VERSION = 3\n\nconst DEFAULT_STAR_DIR = join(homedir(), '.dsh', 'sessions-manager')\n\nfunction isSafeSessionId(value) {\n return typeof value === 'string' && value.length > 0 && value.length <= 200 && !/[\\\\/\\0]/.test(value) && value !== '.' && value !== '..'\n}\n\n/**\n * Coerce anything on disk (or nothing at all) into a valid v3 store.\n * Accepts a bare array of ids (the pre-schema shape) and upgrades it.\n */\nexport function normalizeStarStore(raw) {\n const legacy = Array.isArray(raw) ? raw : null\n const source = legacy || (raw && typeof raw === 'object' ? raw : null)\n const ids = source && Array.isArray(source.starredSessionIds) ? source.starredSessionIds : (legacy || [])\n const clean = []\n const seen = new Set()\n for (const id of ids) {\n // Strings only: silently coercing a number into an id would let junk into\n // the index and mask a caller bug.\n if (!isSafeSessionId(id)) continue\n if (seen.has(id)) continue\n seen.add(id)\n clean.push(id)\n }\n return { schemaVersion: STAR_SCHEMA_VERSION, starredSessionIds: clean }\n}\n\n/**\n * Open the star index.\n * @param {object} [options]\n * @param {string} [options.dir] - Directory holding the index (tests inject a temp dir).\n * @param {string} [options.indexPath] - Full index path, overriding `dir`.\n */\nexport function createStarIndex(options = {}) {\n const dir = options.dir || process.env.DSH_SESSIONS_MANAGER_STAR_DIR || DEFAULT_STAR_DIR\n const indexPath = options.indexPath || join(dir, 'star.json')\n let mutation = Promise.resolve()\n\n async function read() {\n try {\n return normalizeStarStore(JSON.parse(readFileSync(indexPath, 'utf8')))\n } catch {\n return normalizeStarStore(null)\n }\n }\n\n async function write(store) {\n await mkdir(dir, { recursive: true })\n const tmp = join(dir, `.star-${process.pid}-${Date.now()}.tmp`)\n await writeFile(tmp, JSON.stringify(normalizeStarStore(store), null, 2), { encoding: 'utf8', mode: 0o600 })\n await rename(tmp, indexPath)\n }\n\n // Serialize read-modify-write cycles: every mutator sees the store as left by\n // the previous one, and a rejected mutator still keeps the chain alive.\n function mutate(mutator) {\n const operation = mutation.then(async () => {\n const store = await read()\n const result = await mutator(store)\n await write(store)\n return result\n })\n mutation = operation.catch(() => {})\n return operation\n }\n\n /**\n * Star or unstar sessions.\n * @param {string[]} ids - Session ids to change.\n * @param {boolean} starred - true to star, false to unstar.\n * @returns {Promise<string[]>} The full starred set after the change.\n */\n function setStarred(ids, starred) {\n const wanted = (Array.isArray(ids) ? ids : []).filter(isSafeSessionId).map(String)\n return mutate((store) => {\n const set = new Set(store.starredSessionIds)\n for (const id of wanted) {\n if (starred) set.add(id)\n else set.delete(id)\n }\n store.starredSessionIds = [...set]\n return store.starredSessionIds\n })\n }\n\n // Drop ids once their session is gone (purged / deleted), otherwise the index\n // would grow forever with ids that can never be listed again.\n function removeIds(ids) {\n return setStarred(ids, false)\n }\n\n return { read, write, mutate, setStarred, removeIds, indexPath, dir }\n}\n", "// Storage usage aggregation (pure, no I/O).\n//\n// Kept out of the host bundle so it can be unit-tested directly\n// (tests/storage-stats.test.js). Takes the session items the host already\n// builds (with `sizeBytes` filled in) and rolls them up per workspace plus a\n// \"largest sessions\" leaderboard.\n//\n// Sessions without a workspace path land in a single \"\u672A\u5206\u7EC4\" bucket \u2014 that is\n// DSH's own label for orphans, so the panel speaks the same language as the\n// sidebar.\n\nexport const UNGROUPED_KEY = '__ungrouped__'\n\nfunction isFiniteSize(value) {\n return typeof value === 'number' && Number.isFinite(value) && value >= 0\n}\n\n/**\n * Roll session sizes up per workspace and pick the largest sessions.\n *\n * @param {Array<{sessionId: string, title?: string|null, workspacePath?: string|null,\n * workspaceTitle?: string|null, sizeBytes?: number|null}>} items\n * @param {object} [options]\n * @param {number} [options.topN=10] - How many entries the leaderboard holds.\n * @returns {{\n * totalBytes: number,\n * sessionCount: number,\n * sizedSessions: number,\n * unknownSessions: number,\n * workspaces: Array<{key: string, path: string|null, title: string|null,\n * bytes: number, sessions: number, share: number}>,\n * top: Array<{sessionId: string, title: string|null, workspacePath: string|null,\n * workspaceTitle: string|null, sizeBytes: number}>\n * }}\n */\nexport function aggregateStorage(items, options = {}) {\n const topN = Number.isInteger(options.topN) && options.topN > 0 ? options.topN : 10\n const list = Array.isArray(items) ? items : []\n\n const buckets = new Map()\n const sized = []\n let totalBytes = 0\n let unknownSessions = 0\n // Counted entries only: sessionCount must always equal\n // sizedSessions + unknownSessions, or the panel would show a total that\n // disagrees with its own breakdown.\n let counted = 0\n\n for (const item of list) {\n if (!item || item.sessionId == null) continue\n counted++\n const id = String(item.sessionId)\n const path = item.workspacePath ? String(item.workspacePath) : null\n const key = path || UNGROUPED_KEY\n\n let bucket = buckets.get(key)\n if (!bucket) {\n bucket = { key, path, title: item.workspaceTitle ? String(item.workspaceTitle) : null, bytes: 0, sessions: 0 }\n buckets.set(key, bucket)\n }\n bucket.sessions++\n\n if (isFiniteSize(item.sizeBytes)) {\n bucket.bytes += item.sizeBytes\n totalBytes += item.sizeBytes\n sized.push({\n sessionId: id,\n title: item.title || null,\n workspacePath: path,\n workspaceTitle: bucket.title,\n sizeBytes: item.sizeBytes,\n })\n } else {\n unknownSessions++\n }\n }\n\n const workspaces = [...buckets.values()]\n .sort((a, b) => (b.bytes - a.bytes) || (b.sessions - a.sessions) || a.key.localeCompare(b.key))\n .map((bucket) => ({ ...bucket, share: totalBytes > 0 ? bucket.bytes / totalBytes : 0 }))\n\n const top = sized\n .sort((a, b) => (b.sizeBytes - a.sizeBytes) || a.sessionId.localeCompare(b.sessionId))\n .slice(0, topN)\n\n return {\n totalBytes,\n sessionCount: counted,\n sizedSessions: sized.length,\n unknownSessions,\n workspaces,\n top,\n }\n}\n", "// Durable \"auto-archive\" settings (schema v4) + the pure candidate rule.\n//\n// Auto-archive hides conversations that have been idle for N days. It is OFF\n// by default: archiving rewrites durable workspace state, so the plugin must\n// never touch a conversation the user has not asked it to.\n//\n// Deliberately mirrors the star index (src/star-index.js): version field,\n// defensive coercion of whatever is on disk, atomic write (tmp + rename) and a\n// single chained mutation queue. The candidate rule lives here as a pure\n// function so it can be tested without a DSH host.\nimport { mkdir, rename, writeFile } from 'node:fs/promises'\nimport { readFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\n\n// v4 keeps clear of the recycle bin's v1/v2 and the star index's v3, so a\n// copied or mixed-up file can never be silently accepted as another store.\nexport const AUTO_ARCHIVE_SCHEMA_VERSION = 4\n\n// Allowed idle windows. 0 = disabled. Deliberately coarse: a free-form number\n// would let a typo schedule archiving \"tomorrow\" for every conversation.\nexport const INACTIVE_DAY_OPTIONS = Object.freeze([0, 30, 60, 90])\n\nconst DAY_MS = 86400000\n// Re-run at most once per day: the sweep is triggered by panel reads, and a\n// user flipping settings back and forth must not archive in a loop.\nexport const RUN_INTERVAL_MS = DAY_MS\n\nconst DEFAULT_DIR = join(homedir(), '.dsh', 'sessions-manager')\n\n/**\n * Coerce anything on disk (or nothing at all) into a valid v4 store.\n */\nexport function normalizeAutoArchiveStore(raw) {\n const source = raw && typeof raw === 'object' && !Array.isArray(raw) ? raw : {}\n const settings = source.settings && typeof source.settings === 'object' ? source.settings : {}\n const inactiveDays = INACTIVE_DAY_OPTIONS.includes(settings.inactiveDays) ? settings.inactiveDays : 0\n return {\n schemaVersion: AUTO_ARCHIVE_SCHEMA_VERSION,\n settings: {\n inactiveDays,\n // Starred sessions are an explicit \"keep\" mark, so they are skipped\n // unless the user opts out.\n skipStarred: settings.skipStarred !== false,\n },\n lastRunAt: Number.isFinite(source.lastRunAt) ? source.lastRunAt : null,\n lastArchivedCount: Number.isInteger(source.lastArchivedCount) && source.lastArchivedCount >= 0 ? source.lastArchivedCount : 0,\n }\n}\n\n/**\n * Which sessions should be auto-archived right now? Pure \u2014 no I/O, no host.\n *\n * The rule is intentionally conservative: anything we cannot prove is idle\n * (unknown last-activity, already archived, starred, currently open) is left\n * alone. A wrong archive is a visible regression; a missed one is invisible.\n *\n * @param {Array<{sessionId: string, archived?: boolean, starred?: boolean,\n * updatedAt?: number|null}>} items\n * @param {object} options\n * @param {number} options.inactiveDays - Idle window in days (0 disables).\n * @param {number} [options.now] - Reference timestamp (tests inject it).\n * @param {boolean} [options.skipStarred=true] - Keep starred sessions.\n * @param {string|null} [options.activeSessionId] - Never archive the open one.\n * @returns {string[]} Session ids to archive.\n */\nexport function pickInactiveCandidates(items, options = {}) {\n const days = options.inactiveDays\n if (!INACTIVE_DAY_OPTIONS.includes(days) || days === 0) return []\n const now = Number.isFinite(options.now) ? options.now : Date.now()\n const cutoff = now - days * DAY_MS\n const skipStarred = options.skipStarred !== false\n const activeId = options.activeSessionId != null ? String(options.activeSessionId) : null\n const list = Array.isArray(items) ? items : []\n\n const out = []\n const seen = new Set()\n for (const item of list) {\n if (!item || item.sessionId == null) continue\n const id = String(item.sessionId)\n if (seen.has(id)) continue\n if (item.archived) continue\n if (skipStarred && item.starred) continue\n if (activeId !== null && id === activeId) continue\n const updatedAt = Number(item.updatedAt)\n // No usable timestamp \u2192 cannot prove it is idle \u2192 leave it alone.\n if (!Number.isFinite(updatedAt) || updatedAt <= 0) continue\n if (updatedAt < cutoff) { seen.add(id); out.push(id) }\n }\n return out\n}\n\n/**\n * Open the auto-archive settings store.\n * @param {object} [options]\n * @param {string} [options.dir] - Directory holding the index (tests inject a temp dir).\n * @param {string} [options.indexPath] - Full index path, overriding `dir`.\n */\nexport function createAutoArchiveStore(options = {}) {\n const dir = options.dir || process.env.DSH_SESSIONS_MANAGER_AUTO_ARCHIVE_DIR || DEFAULT_DIR\n const indexPath = options.indexPath || join(dir, 'auto-archive.json')\n let mutation = Promise.resolve()\n\n async function read() {\n try {\n return normalizeAutoArchiveStore(JSON.parse(readFileSync(indexPath, 'utf8')))\n } catch {\n return normalizeAutoArchiveStore(null)\n }\n }\n\n async function write(store) {\n await mkdir(dir, { recursive: true })\n const tmp = join(dir, `.auto-archive-${process.pid}-${Date.now()}.tmp`)\n await writeFile(tmp, JSON.stringify(normalizeAutoArchiveStore(store), null, 2), { encoding: 'utf8', mode: 0o600 })\n await rename(tmp, indexPath)\n }\n\n function mutate(mutator) {\n const operation = mutation.then(async () => {\n const store = await read()\n const result = await mutator(store)\n await write(store)\n return result\n })\n mutation = operation.catch(() => {})\n return operation\n }\n\n /**\n * Merge a partial settings patch.\n * @param {{inactiveDays?: number, skipStarred?: boolean}} patch\n * @returns {Promise<object>} The store's settings after the change.\n */\n function update(patch = {}) {\n return mutate((store) => {\n if (Object.prototype.hasOwnProperty.call(patch, 'inactiveDays')) {\n const days = Number(patch.inactiveDays)\n if (!INACTIVE_DAY_OPTIONS.includes(days)) {\n const error = new Error(`inactiveDays \u4EC5\u652F\u6301 ${INACTIVE_DAY_OPTIONS.join('\u3001')}`)\n error.status = 400\n throw error\n }\n store.settings.inactiveDays = days\n }\n if (Object.prototype.hasOwnProperty.call(patch, 'skipStarred')) {\n store.settings.skipStarred = !!patch.skipStarred\n }\n return store.settings\n })\n }\n\n /** Record that a sweep ran, so the once-a-day throttle can skip the next one. */\n function recordRun(count, at = Date.now()) {\n return mutate((store) => {\n store.lastRunAt = at\n store.lastArchivedCount = Number.isInteger(count) && count >= 0 ? count : 0\n return store\n })\n }\n\n /** True when a sweep already ran within RUN_INTERVAL_MS. */\n function isFresh(store, now = Date.now()) {\n return Number.isFinite(store && store.lastRunAt) && (now - store.lastRunAt) < RUN_INTERVAL_MS\n }\n\n return { read, write, mutate, update, recordRun, isFresh, indexPath, dir }\n}\n", "// session-meta-cache.js \u2014 \u4F1A\u8BDD\u300C\u539F\u59CB\u5143\u6570\u636E\u300D\u5185\u5B58\u7F13\u5B58\uFF08\u6309\u65E5\u5FD7\u5185\u5BB9\u6307\u7EB9\u6821\u9A8C\uFF09\u3002\n//\n// \u80CC\u666F\uFF08issue #1\uFF09\uFF1A\u5217\u8868\u6784\u5EFA\u539F\u672C\u5BF9\u6BCF\u6761\u4F1A\u8BDD\u8C03\u7528 readTitleSnapshot\uFF0C\u800C\u8BE5\u8C03\u7528\u4F1A\u628A\n// \u4F1A\u8BDD\u65E5\u5FD7\uFF08.jsonl.zstd\uFF09\u7684**\u6240\u6709 zstd \u5E27**\u9010\u5E27\u89E3\u538B\u3001\u9010\u884C JSON.parse\uFF0C\u53EA\u4E3A\u6298\u53E0\u51FA\n// \u6700\u65B0\u6807\u9898\u3002\u5927\u5E93\uFF08\u6570\u5341\u6761\u4F1A\u8BDD\u3001\u5341\u4E07\u7EA7\u5E27\uFF09\u4E00\u6B21\u5168\u8868\u8981\u51E0\u79D2 CPU\uFF0C\u4E14\u89E3\u7801\u662F\u540C\u6B65\u5757\uFF0C\n// \u4F1A\u963B\u585E\u5BBF\u4E3B\u4E8B\u4EF6\u5FAA\u73AF\uFF0C\u8FDE\u7D2F session.history \u4E4B\u7C7B\u7684 RPC \u8D85\u65F6\u3002\n//\n// \u6307\u7EB9\u6709\u4E24\u79CD\u6765\u6E90\uFF08\u6309 runtime \u80FD\u529B\u81EA\u52A8\u9009\u62E9\uFF0C\u8C03\u7528\u65B9\u6784\u9020 stat \u5BF9\u8C61\uFF09\uFF1A\n//\n// 1. \u6587\u4EF6\u6307\u7EB9\uFF08legacy runtime\uFF09\uFF1A\u8BB0\u4E0B\u65E5\u5FD7\u7684 (mtimeMs, size)\u3002\u4EFB\u4F55\n// append/\u6539\u540D/\u79FB\u52A8\u90FD\u4F1A\u66F4\u65B0 mtime\uFF0C\u6240\u4EE5\u300Cstat \u76F8\u540C \u21D2 \u5185\u5BB9\u6CA1\u53D8\u300D\u3002\n// \u8BE5\u6307\u7EB9\u53EF\u8DE8\u8FDB\u7A0B\u6301\u4E45\u5316\uFF08title-persist-index \u7528\u5B83\u505A\u51B7\u542F\u52A8\u52A0\u901F\uFF09\u3002\n//\n// 2. revision \u6307\u7EB9\uFF08SessionHandle \u4E16\u4EE3 runtime\uFF0C0.1.3+\uFF09\uFF1AsessionPersistence\n// \u7684 list()/stat() \u8FD4\u56DE SessionPersistenceSnapshot\uFF0C\u5176 `revision` \u662F\n// **\u4E0D\u900F\u660E\u53D8\u66F4\u4EE4\u724C**\u3002\u5B98\u65B9\u5951\u7EA6\uFF1A\u540C\u4E00 service \u5B9E\u4F8B\u3001\u540C\u4E00 session id \u5185\uFF0C\n// revision \u76F8\u7B49\u53EF\u89C6\u4E3A\u65E5\u5FD7\u672A\u53D8\uFF1B\u9664\u6B64\u4E4B\u5916 revision \u4E0D\u505A\u4EFB\u4F55\u627F\u8BFA\u3002\n// \u26A0\uFE0F \u56E0\u6B64 revision \u6307\u7EB9**\u7EDD\u4E0D\u80FD\u5199\u5165\u8DE8\u8FDB\u7A0B\u7684\u6301\u4E45\u7F13\u5B58**\uFF08\u4E0D\u540C\u8FDB\u7A0B/\u91CD\u542F\u540E\n// revision \u503C\u65E0\u610F\u4E49\uFF0C\u8BEF\u7528\u53EF\u80FD\u628A\u9648\u65E7\u6570\u636E\u5F53\u65B0\u9C9C\u6570\u636E\uFF09\u3002\u6301\u4E45\u7D22\u5F15\u843D\u76D8\u524D\u5FC5\u987B\n// \u7528 isPersistableFingerprint() \u8FC7\u6EE4\u3002\n//\n// \u4E3A\u4EC0\u4E48\u81EA\u5DF1\u5B9E\u73B0\u800C\u4E0D\u7528 runtime \u7684 prepared \u7F13\u5B58\uFF1A\u63D2\u4EF6\u4E0D\u80FD\u5047\u8BBE\u5BF9\u65B9\u7684 runtime \u7248\u672C\uFF0C\n// runtime \u4FA7\u7684\u7F13\u5B58\u5BB9\u91CF/\u547D\u4E2D\u7B56\u7565\u5404\u7248\u672C\u4E0D\u540C\u3002\u672C\u6A21\u5757\u53EA\u7528\u7EAF\u6570\u636E\u5224\u5B9A\uFF0C\u4EFB\u4F55\u7248\u672C\u884C\u4E3A\u4E00\u81F4\u3002\n//\n// \u5931\u6548\u7B56\u7565\uFF1A\n// 1. \u6307\u7EB9\u6821\u9A8C\uFF1Arevision \u4E0D\u76F8\u7B49 / mtimeMs \u6216 size \u4EFB\u4E00\u53D8\u5316\u5373\u89C6\u4E3A\u8FC7\u671F\n// 2. TTL\uFF1A\u4EC5\u5BF9\u6587\u4EF6\u6307\u7EB9\u751F\u6548\uFF08\u9632 mtime \u7CBE\u5EA6/\u65F6\u949F\u56DE\u62E8\uFF09\uFF1Brevision \u76F8\u7B49\u5373\u6743\u5A01\uFF0C\n// \u4E0D\u53D7 TTL \u5F71\u54CD\uFF08\u5B98\u65B9\u5951\u7EA6\u660E\u6587\u5141\u8BB8 treat equal revisions as unchanged\uFF09\n// 3. \u663E\u5F0F invalidate\uFF1A\u5220\u9664 / \u79FB\u52A8 / \u5F52\u6863\u7B49\u5BBF\u4E3B\u64CD\u4F5C\u540E\u4E3B\u52A8\u4E22\u5F03\u5BF9\u5E94\u6761\u76EE\n//\n// \u7EAF\u903B\u8F91\u4E0E\u526F\u4F5C\u7528\u5206\u79BB\uFF1AisFresh / partitionByCache \u90FD\u662F\u7EAF\u51FD\u6570\uFF0C\u4FBF\u4E8E\u5355\u6D4B\u3002\n\nconst DEFAULT_TTL_MS = 5 * 60 * 1000\nconst DEFAULT_MAX = 4000\n\nconst REVISION_PREFIX = 'rev:'\n\n// \u6587\u4EF6\u6307\u7EB9\uFF1A\u53EA\u6709\u540C\u65F6\u62FF\u5230 mtime \u4E0E size \u624D\u53EF\u4FE1\u3002\n// \u62FF\u4E0D\u5230 stat \u4FE1\u606F\u65F6\u8FD4\u56DE null\u2014\u2014\u8868\u793A\u300C\u65E0\u6CD5\u6821\u9A8C\u300D\uFF0C\u8C03\u7528\u65B9\u5FC5\u987B\u6309\u672A\u547D\u4E2D\u5904\u7406\uFF0C\n// \u7EDD\u4E0D\u80FD\u5728\u6709\u7591\u95EE\u65F6\u8FD4\u56DE\u65E7\u6570\u636E\u3002\nexport function fingerprintOf(stat) {\n if (!stat || typeof stat !== 'object') return null\n // revision \u6307\u7EB9\u4F18\u5148\uFF1ASessionHandle \u4E16\u4EE3\u6CA1\u6709\u53EF\u9760\u7684 locate/stat\uFF0C\n // snapshot.revision \u662F\u5B98\u65B9\u63D0\u4F9B\u7684\u552F\u4E00\u53D8\u66F4\u4EE4\u724C\u3002\n if (typeof stat.revision === 'string' && stat.revision.length > 0) {\n return REVISION_PREFIX + stat.revision\n }\n const mtimeMs = stat.mtimeMs\n const size = stat.size\n if (typeof mtimeMs !== 'number' || !Number.isFinite(mtimeMs) || mtimeMs <= 0) return null\n if (typeof size !== 'number' || !Number.isFinite(size) || size < 0) return null\n return `${Math.floor(mtimeMs)}:${size}`\n}\n\n// revision \u6307\u7EB9\u53EA\u5728\u5F53\u524D service \u5B9E\u4F8B\u5185\u6709\u610F\u4E49\uFF0C\u7EDD\u4E0D\u80FD\u843D\u76D8\u4F5C\u4E3A\u8DE8\u8FDB\u7A0B\u6307\u7EB9\u3002\n// title-persist-index \u7B49\u6301\u4E45\u5316\u5C42\u5FC5\u987B\u5728\u5199\u5165\u524D\u7528\u5B83\u8FC7\u6EE4\u3002\nexport function isPersistableFingerprint(fingerprint) {\n return typeof fingerprint === 'string' && fingerprint !== '' && !fingerprint.startsWith(REVISION_PREFIX)\n}\n\n// \u7F13\u5B58\u6761\u76EE\u662F\u5426\u4ECD\u7136\u65B0\u9C9C\uFF08\u7EAF\u51FD\u6570\uFF09\u3002\n// stat \u4F20 { revision } \u6216 { mtimeMs, size }\uFF1B\u4E24\u7C7B\u6307\u7EB9\u4E0D\u80FD\u4E92\u76F8\u5339\u914D\u3002\nexport function isFresh(entry, stat, now, ttlMs = DEFAULT_TTL_MS) {\n if (!entry) return false\n const fp = fingerprintOf(stat)\n if (!fp) return false\n if (entry.fingerprint !== fp) return false\n if (typeof entry.at !== 'number') return false\n // revision \u6307\u7EB9\u4E0D\u53D7 TTL \u7EA6\u675F\uFF1A\u5951\u7EA6\u5141\u8BB8\u628A\u76F8\u7B49 revision \u89C6\u4E3A\u65E5\u5FD7\u672A\u53D8\u3002\n if (fp.startsWith(REVISION_PREFIX)) return true\n return (now - entry.at) <= ttlMs\n}\n\n// \u628A\u4E00\u6279 id \u5206\u6210\u300C\u547D\u4E2D\u7F13\u5B58\u300D\u4E0E\u300C\u9700\u8981\u89E3\u7801\u300D\u4E24\u7EC4\uFF08\u7EAF\u51FD\u6570\uFF0C\u4FBF\u4E8E\u5355\u6D4B\uFF09\u3002\n// statsById: Map<id, {mtimeMs, size} | {revision}>\uFF1Bcache: \u4E0E SessionMetaCache \u540C\u6784\u7684 Map\u3002\nexport function partitionByCache(ids, statsById, cache, now = Date.now(), ttlMs = DEFAULT_TTL_MS) {\n const cached = new Map()\n const missing = []\n for (const id of ids) {\n const entry = cache && cache.get(String(id))\n const stat = statsById && statsById.get(String(id))\n if (isFresh(entry, stat, now, ttlMs) && entry && entry.meta) {\n cached.set(String(id), entry.meta)\n } else {\n missing.push(String(id))\n }\n }\n return { cached, missing }\n}\n\nexport function createSessionMetaCache(opts = {}) {\n const ttlMs = Number.isFinite(opts.ttlMs) ? opts.ttlMs : DEFAULT_TTL_MS\n const max = Number.isInteger(opts.max) && opts.max > 0 ? opts.max : DEFAULT_MAX\n const map = new Map()\n let hits = 0\n let misses = 0\n\n return {\n // \u547D\u4E2D\u8FD4\u56DE meta\uFF0C\u672A\u547D\u4E2D/\u65E0\u6CD5\u6821\u9A8C\u8FD4\u56DE null\u3002\n get(id, stat) {\n const key = String(id)\n const entry = map.get(key)\n if (isFresh(entry, stat, Date.now(), ttlMs)) {\n hits++\n // LRU\uFF1A\u547D\u4E2D\u540E\u79FB\u5230\u672B\u5C3E\uFF0C\u5BB9\u91CF\u6EE1\u65F6\u4F18\u5148\u6DD8\u6C70\u6700\u4E45\u672A\u7528\u3002\n map.delete(key)\n map.set(key, entry)\n return entry.meta\n }\n misses++\n return null\n },\n set(id, stat, meta) {\n if (!meta) return null\n const fp = fingerprintOf(stat)\n // \u65E0\u6CD5\u7B97\u51FA\u6307\u7EB9\uFF08\u6CA1 stat / revision \u7F3A\u5931 / stat \u5931\u8D25\uFF09\u65F6\u4E0D\u5199\u7F13\u5B58\uFF1A\n // \u5199\u8FDB\u53BB\u5C31\u518D\u4E5F\u65E0\u6CD5\u53EF\u9760\u5931\u6548\u3002\n if (!fp) return null\n const key = String(id)\n map.delete(key)\n map.set(key, { fingerprint: fp, at: Date.now(), meta })\n if (map.size > max) {\n // \u6DD8\u6C70\u6700\u4E45\u672A\u7528\u7684\u4E00\u4E2A\uFF08Map \u4FDD\u6301\u63D2\u5165\u987A\u5E8F\uFF0C\u9996\u4E2A\u5373\u6700\u65E7\uFF09\u3002\n const oldest = map.keys().next().value\n if (oldest !== undefined) map.delete(oldest)\n }\n return meta\n },\n // \u6279\u91CF\u5224\u5B9A\uFF1A\u4E00\u6B21\u7B97\u51FA\u300C\u547D\u4E2D\u7F13\u5B58\u300D\u4E0E\u300C\u9700\u8981\u89E3\u7801\u300D\u4E24\u7EC4\uFF0C\u4F9B\u5217\u8868\u6784\u5EFA\u505A\u6279\u91CF\u6295\u5F71\u3002\n partition(ids, statsById) {\n return partitionByCache(ids, statsById, map, Date.now(), ttlMs)\n },\n invalidate(id) {\n if (id == null) return false\n const key = String(id)\n const had = map.has(key)\n map.delete(key)\n return had\n },\n clear() { map.clear() },\n get size() { return map.size },\n stats() { return { size: map.size, hits, misses, ttlMs } },\n }\n}\n", "// title-persist-index.js \u2014 \u4F1A\u8BDD\u6807\u9898/\u5143\u6570\u636E\u7684**\u78C1\u76D8**\u5C0F\u7D22\u5F15\uFF08P4\uFF0Cissue #1\uFF09\u3002\n//\n// metaCache\uFF08session-meta-cache.js\uFF09\u89E3\u51B3\u7684\u662F\u300C\u8FDB\u7A0B\u5185\u91CD\u590D\u89E3\u7801\u300D\uFF1B\u672C\u6A21\u5757\u89E3\u51B3\n// \u7684\u662F\u51B7\u542F\u52A8\uFF1A\u63D2\u4EF6\u91CD\u542F\u540E\u5185\u5B58\u7F13\u5B58\u4E3A\u7A7A\uFF0C\u7B2C\u4E00\u6B21\u5217\u8868\u6784\u5EFA\u4ECD\u8981\u5168\u5E93\u89E3\u7801\u4E00\u6B21\u3002\n// \u628A\u89E3\u7801\u51FA\u7684\u5143\u6570\u636E\u8FDE\u540C\u6587\u4EF6\u6307\u7EB9\u539F\u5B50\u5199\u8FDB\u4E00\u4E2A JSON \u7D22\u5F15\uFF0C\u91CD\u542F\u540E\u5217\u8868\u53EA\u9700\n// \u4E00\u6B21\u7D22\u5F15\u8BFB + \u6307\u7EB9\u6BD4\u5BF9\uFF0C\u6307\u7EB9\u6CA1\u53D8\u7684\u4F1A\u8BDD\u96F6\u89E3\u7801\u3002\n//\n// \u7ED3\u6784\u4EFF trash \u7684\u539F\u5B50\u5199\u7D22\u5F15\uFF1A{ schemaVersion, entries: { [sessionId]: entry } }\n// entry = { title, cwd, createdAt, fingerprint, updatedAt }\n// fingerprint \u5373 session-meta-cache.js \u7684 fingerprintOf(stat) \u4EA7\u51FA\n// \uFF08\"<mtimeMs>:<size>\"\uFF09\uFF0C\u6BD4\u5BF9\u4E00\u81F4\u5373\u53EF\u4FE1\u4EFB\u6761\u76EE\u5185\u5BB9\u3002\n//\n// \u5199\u5165\u65F6\u673A\u7531\u8C03\u7528\u65B9\u51B3\u5B9A\uFF08\u5217\u8868\u6784\u5EFA\u6536\u5C3E\u6279\u91CF\u56DE\u5199\u3001purge \u65F6\u6E05\u7406\uFF09\uFF0C\u672C\u6A21\u5757\u53EA\n// \u63D0\u4F9B\uFF1A\u8BFB\u53D6\u7F13\u5B58\u3001\u5408\u5E76\u5199\u5165\uFF08\u4E32\u884C\u5316 + \u539F\u5B50\u66FF\u6362\uFF09\u3001\u6309 id \u5220\u9664\u3002\u4EFB\u4F55\u6587\u4EF6\n// \u635F\u574F\u90FD\u6309\u7A7A\u7D22\u5F15\u5904\u7406\uFF0C\u7EDD\u4E0D\u963B\u585E\u5217\u8868\u6784\u5EFA\u3002\n//\n// \u5355\u5B9E\u4F8B\u5047\u8BBE\uFF1A\u4E00\u4E2A\u8FDB\u7A0B\u5185\u53EA apply \u4E00\u4E2A\u63D2\u4EF6\u5B9E\u4F8B\uFF08\u751F\u4EA7\u5373\u5982\u6B64\uFF09\uFF0C\u5B9E\u4F8B\u95F4\u7684\n// \u5185\u5B58\u526F\u672C\u4E0D\u4E92\u76F8\u540C\u6B65\u2014\u2014\u8DE8\u300C\u91CD\u542F\u300D\u4EE5\u843D\u76D8\u5185\u5BB9\u4E3A\u51C6\uFF08\u6D4B\u8BD5\u4EA6\u6309\u6B64\u65AD\u8A00\uFF09\u3002\n\nimport { mkdir, readFile, rename, writeFile } from 'node:fs/promises'\nimport { dirname, join } from 'node:path'\n\nexport const TITLE_INDEX_SCHEMA_VERSION = 1\n\nconst MAX_ENTRIES = 20000\n\n// \u6761\u76EE\u53EA\u4FDD\u7559\u53EF\u5E8F\u5217\u5316\u4E14\u5BF9\u5217\u8868\u6709\u7528\u7684\u5B57\u6BB5\uFF1B\u6307\u7EB9\u7F3A\u5931\u7684\u6761\u76EE\u65E0\u6CD5\u6821\u9A8C\uFF0C\u76F4\u63A5\u4E22\u5F03\u2014\u2014\n// \u5B81\u53EF\u4E0B\u6B21\u91CD\u89E3\u7801\uFF0C\u4E5F\u4E0D\u80FD\u628A\u65E0\u6CD5\u5931\u6548\u7684\u6570\u636E\u5F53\u771F\u3002\n// \u26A0\uFE0F revision \u6307\u7EB9\uFF08\"rev:\u2026\"\uFF09\u53EA\u5728\u5F53\u524D service \u5B9E\u4F8B\u5185\u6709\u610F\u4E49\uFF08\u5B98\u65B9 0.1.3 \u5951\u7EA6\uFF1A\n// opaque token, same instance + same session id\uFF09\uFF0C\u7EDD\u4E0D\u80FD\u843D\u76D8\u4F5C\u4E3A\u8DE8\u8FDB\u7A0B\u6307\u7EB9\u2014\u2014\n// \u8FD9\u91CC\u4F5C\u4E3A\u6700\u540E\u9632\u7EBF\u518D\u6B21\u62E6\u622A\uFF08\u8C03\u7528\u65B9 session-meta-cache.isPersistableFingerprint\n// \u5DF2\u5148\u884C\u8FC7\u6EE4\uFF09\u3002\nexport function normalizeEntry(raw) {\n if (!raw || typeof raw !== 'object') return null\n const title = typeof raw.title === 'string' ? raw.title : null\n const cwd = typeof raw.cwd === 'string' ? raw.cwd : null\n const createdAt = typeof raw.createdAt === 'number' ? raw.createdAt : null\n const fingerprint = typeof raw.fingerprint === 'string' && raw.fingerprint ? raw.fingerprint : null\n const updatedAt = typeof raw.updatedAt === 'number' ? raw.updatedAt : 0\n if (!fingerprint || fingerprint.startsWith('rev:')) return null\n if (!title && !cwd) return null\n return { title, cwd, createdAt, fingerprint, updatedAt }\n}\n\nexport function normalizeTitleIndex(raw) {\n const entries = {}\n if (raw && typeof raw === 'object' && raw.entries && typeof raw.entries === 'object') {\n for (const [id, entry] of Object.entries(raw.entries)) {\n if (typeof id !== 'string' || !id || id.length > 200) continue\n const normalized = normalizeEntry(entry)\n if (normalized) entries[id] = normalized\n }\n }\n return { schemaVersion: TITLE_INDEX_SCHEMA_VERSION, entries }\n}\n\n// \u7EAF\u5408\u5E76\uFF1Aright \u8986\u76D6 left \u540C id \u6761\u76EE\uFF1B\u622A\u65AD\u5230 MAX_ENTRIES\uFF08\u4FDD\u7559 updatedAt \u65B0\u7684\uFF09\u3002\nexport function mergeEntries(left, right) {\n const merged = { ...left }\n for (const [id, entry] of Object.entries(right)) merged[id] = entry\n const ids = Object.keys(merged)\n if (ids.length > MAX_ENTRIES) {\n ids.sort((a, b) => (merged[a].updatedAt || 0) - (merged[b].updatedAt || 0))\n for (const id of ids.slice(0, ids.length - MAX_ENTRIES)) delete merged[id]\n }\n return merged\n}\n\nexport function createTitleIndexStore({ dir, file }) {\n let cache = null\n let chain = Promise.resolve()\n const path = file || join(dir, 'title-index.json')\n\n async function readRaw() {\n try {\n return normalizeTitleIndex(JSON.parse(await readFile(path, 'utf8')))\n } catch (e) {\n return normalizeTitleIndex(null)\n }\n }\n\n // \u6240\u6709\u5199\u64CD\u4F5C\u4E32\u884C\u5316\uFF08\u4EFF trash \u7684 mutate \u961F\u5217\uFF09\uFF0C\u907F\u514D\u5E76\u53D1 merge \u4E92\u76F8\u8986\u76D6\u3002\n function enqueue(mutator) {\n const operation = chain.then(async () => {\n const store = cache || (cache = (await readRaw()).entries)\n await mutator(store)\n return store\n })\n chain = operation.catch(() => {})\n return operation\n }\n\n return {\n // \u53EA\u8BFB\uFF1A\u5185\u5B58\u4F18\u5148\uFF0C\u672A\u52A0\u8F7D\u8FC7\u624D\u843D\u76D8\u4E00\u6B21\u3002\u7EDD\u4E0D\u629B\u9519\u3002\n async entries() {\n if (cache) return cache\n cache = (await readRaw()).entries\n return cache\n },\n // \u6279\u91CF\u5408\u5E76\u5199\u5165\uFF08\u539F\u5B50\u66FF\u6362\uFF09\u3002\u5931\u8D25\u9759\u9ED8\uFF1A\u7D22\u5F15\u53EA\u662F\u52A0\u901F\u5668\uFF0C\u574F\u4E86\u4E0B\u6B21\u91CD\u89E3\u7801\u3002\n async merge(batch) {\n const right = {}\n for (const [id, entry] of Object.entries(batch || {})) {\n const normalized = normalizeEntry(entry)\n if (normalized) right[String(id)] = normalized\n }\n if (!Object.keys(right).length) return false\n await enqueue(async (store) => {\n const next = mergeEntries(store, right)\n await mkdir(dirname(path), { recursive: true })\n const tmp = join(dirname(path), `.title-index-${process.pid}-${Date.now()}.tmp`)\n await writeFile(tmp, JSON.stringify({ schemaVersion: TITLE_INDEX_SCHEMA_VERSION, entries: next }), { encoding: 'utf8', mode: 0o600 })\n await rename(tmp, path)\n cache = next\n })\n return true\n },\n async remove(ids) {\n const wanted = new Set((ids || []).map(String))\n if (!wanted.size) return false\n await enqueue(async (store) => {\n let changed = false\n for (const id of wanted) {\n if (id in store) { delete store[id]; changed = true }\n }\n if (!changed) return\n await mkdir(dirname(path), { recursive: true })\n const tmp = join(dirname(path), `.title-index-${process.pid}-${Date.now()}.tmp`)\n await writeFile(tmp, JSON.stringify({ schemaVersion: TITLE_INDEX_SCHEMA_VERSION, entries: store }), { encoding: 'utf8', mode: 0o600 })\n await rename(tmp, path)\n })\n return true\n },\n }\n}\n\n// \u5224\u5B9A\u6301\u4E45\u6761\u76EE\u80FD\u5426\u5F53\u4F5C\u5F53\u524D\u65E5\u5FD7\u7684\u89E3\u7801\u7ED3\u679C\uFF1A\u6307\u7EB9\u4E00\u81F4\u5373\u53EF\uFF08\u4E0E\u5185\u5B58\u7F13\u5B58\u540C\u4E00\u6807\u51C6\uFF09\u3002\nexport function persistEntryUsable(entry, stat) {\n const normalized = normalizeEntry(entry)\n if (!normalized || !stat) return null\n return normalized.fingerprint === stat.fingerprint ? normalized : null\n}\n", "// Private-path derivation for the SessionHandle era (dsh-v0.1.3-alpha.1).\n//\n// \u8BBE\u8BA1\u88C1\u51B3\uFF082026-09-06\uFF0C\u7528\u6237\u660E\u786E\u51B3\u7B56\uFF09\uFF1A\u5B98\u65B9\u516C\u5171\u5951\u7EA6\u4E0D\u542B delete/move\uFF0C\u800C\u8FD9\u4E24\u7C7B\n// \u80FD\u529B\u5728 legacy \u65F6\u4EE3\u672C\u6765\u5C31\u662F\u300C\u5B98\u65B9 locate \u67E5\u8DEF\u5F84 + \u76F4\u63A5\u6587\u4EF6\u7CFB\u7EDF\u64CD\u4F5C\u300D\u7684\u534A\u5B98\u65B9\n// \u5B9E\u73B0\u3002\u7528\u6237\u636E\u6B64\u653E\u5F03 v3.5.2 \u65E9\u524D\u300C\u53EA\u8D70\u516C\u5171\u5951\u7EA6\u300D\u7684\u81EA\u6211\u9650\u5236\uFF0C\u8981\u6C42\u6CBF\u7528\u540C\u4E00\u601D\u8DEF\n// \u5728 handle \u65F6\u4EE3\u6062\u590D\u300C\u5F7B\u5E95\u5220\u9664\u300D\u4E0E\u300C\u8DE8\u5DE5\u4F5C\u533A\u79FB\u52A8\u300D\u3002\u672C\u6A21\u5757\u628A\u5B98\u65B9\n// session-persistence-jsonl \u540E\u7AEF\u7684\u786E\u5B9A\u6027\u76EE\u5F55\u5E03\u5C40\u79FB\u690D\u4E3A\u53EF\u6821\u9A8C\u7684\u8DEF\u5F84\u63A8\u5BFC\uFF0C\u5E76\u914D\n// \u4E09\u5C42\u5B88\u536B\uFF0C\u4EFB\u4F55\u4E00\u5C42\u4E0D\u6EE1\u8DB3\u90FD\u89C6\u4E3A\u300C\u63A8\u5BFC\u5931\u8D25\u300D\u8FD4\u56DE null\uFF08\u8C03\u7528\u65B9\u5B89\u5168\u964D\u7EA7\u4E3A\u7981\u7528\uFF09\uFF1A\n//\n// 1. root \u5FC5\u987B\u76F4\u63A5\u8BFB\u81EA\u540E\u7AEF\u5B9E\u4F8B\u5B57\u6BB5\uFF08`sp.root`\uFF0C\u6784\u5EFA\u4EA7\u7269\u91CC\u662F\u666E\u901A\u5B9E\u4F8B\u5C5E\u6027\uFF09\uFF0C\n// \u7EDD\u4E0D\u731C\u6D4B\u3001\u7EDD\u4E0D\u626B\u63CF\u78C1\u76D8\u53CD\u63A8\u3002\n// 2. \u4F1A\u8BDD\u76EE\u5F55 basename \u5FC5\u987B\u7B49\u4E8E encodeSegment(id)\uFF0C\u4E14\u76EE\u5F55\u5185\u5FC5\u987B\u5B58\u5728\u81F3\u5C11\u4E00\u4E2A\n// \u89C4\u8303 generation \u6587\u4EF6\uFF08session.vN.jsonl[.zstd]\uFF1B\u4E34\u65F6/\u975E\u89C4\u8303\u540D\u4E0D\u7B97\uFF09\u3002\n// 3. \u6700\u7EC8\u65E5\u5FD7\u8DEF\u5F84\u8FD8\u8981\u8FC7 pathOwnsSession \u7684 id \u5F52\u5C5E\u6821\u9A8C\uFF08\u542B\u5B50\u4E32\u78B0\u649E\u62D2\u7EDD\uFF09\u2014\u2014\n// \u56E0\u6B64\u542B\u5F02\u4F53\u5B57\u7B26\u7684 id\uFF08\u7F16\u7801\u540E\u76EE\u5F55\u540D \u2260 id\uFF09\u4F1A\u5B89\u5168\u964D\u7EA7\u4E3A\u4E0D\u53EF\u7528\u3002\n//\n// \u5E03\u5C40\u89C4\u5219\u79FB\u690D\u81EA\u5B98\u65B9\u6784\u5EFA\u4EA7\u7269\uFF08session-persistence-jsonl/lib/index.js\uFF09\uFF1A\n// projectDir(root, cwd) = root / projectKey(cwd) \uFF08cwd \u7F3A\u7701 \u2192 _no-cwd\uFF09\n// sessionDir(root, cwd, id) = projectDir / encodeSegment(id)\n// generationLogFilename = `session.vN.jsonl` + `.zstd`\uFF08compression=zstd\uFF09\n// projectKey: \u5206\u9694\u7B26\u4E0E `:` \u2192 `-`\uFF1B[A-Za-z0-9._-] \u4FDD\u7559\uFF1B\u5176\u4F59 \u2192 `~XXXX`\n// \uFF08charCode \u7684\u56DB\u4F4D\u5927\u5199\u5341\u516D\u8FDB\u5236\uFF09\uFF1B\u53BB\u524D\u5BFC `-`\uFF1B\u622A\u65AD 251\uFF1B\u7A7A\u4E32\u56DE\u9000 `root`\u3002\n// encodeSegment: \u540C\u6837\u7684 `~XXXX` \u8F6C\u4E49\uFF08`.`/`..` \u4F8B\u5916\uFF09\u3002\n\nimport { readdir, stat } from 'node:fs/promises'\nimport { basename, join } from 'node:path'\nimport { pathOwnsSession } from './path-guard.js'\n\nconst GENERATION_LOG_RE = /^session\\.v\\d+\\.jsonl(\\.zst(d)?)?$/\n\nfunction isSafeChar(ch) {\n return ch !== '~' && /^[A-Za-z0-9._-]$/.test(ch)\n}\n\nexport function projectKeyFor(cwd) {\n const s = String(cwd)\n if (s.length === 0) throw new Error('cannot encode an empty project path')\n let readable = ''\n let separatorRun = false\n for (let i = 0; i < s.length; i++) {\n const ch = s[i]\n if (ch === '/' || ch === '\\\\' || ch === ':') {\n if (!separatorRun) readable += '-'\n separatorRun = true\n } else if (isSafeChar(ch)) {\n readable += ch\n separatorRun = false\n } else {\n readable += '~' + s.charCodeAt(i).toString(16).toUpperCase().padStart(4, '0')\n separatorRun = false\n }\n }\n return '--' + ((readable.replace(/^-+/, '') || 'root').slice(0, 251)) + '--'\n}\n\nexport function encodeSegmentFor(raw) {\n const s = String(raw)\n if (s.length === 0) throw new Error('cannot encode an empty path segment')\n if (s === '.') return '~002E'\n if (s === '..') return '~002E~002E'\n let out = ''\n for (let i = 0; i < s.length; i++) {\n const ch = s[i]\n out += isSafeChar(ch) ? ch : '~' + s.charCodeAt(i).toString(16).toUpperCase().padStart(4, '0')\n }\n return out\n}\n\n// \u540E\u7AEF\u5B9E\u4F8B\u7684 root \u53EA\u5728\u300C\u5B9E\u4F8B\u5B57\u6BB5\u786E\u5B9E\u643A\u5E26\u975E\u7A7A\u5B57\u7B26\u4E32\u300D\u65F6\u53EF\u4FE1\uFF1B\u62FF\u4E0D\u5230\u5C31\u6574\u4F53\u964D\u7EA7\u3002\nexport function resolveSessionRoot(sp) {\n const root = sp && typeof sp === 'object' ? sp.root : undefined\n return typeof root === 'string' && root.length > 0 ? root : null\n}\n\nexport function deriveSessionDir(root, cwd, id) {\n const project = cwd === undefined || cwd === null || cwd === ''\n ? join(root, '_no-cwd')\n : join(root, projectKeyFor(cwd))\n return join(project, encodeSegmentFor(id))\n}\n\n// \u7EAF\u63A8\u5BFC\uFF08\u4E0D\u505A\u78C1\u76D8\u6821\u9A8C\uFF09\u3002\u4F9B\u6D4B\u8BD5\u4E0E\u4E0A\u5C42\u7EC4\u5408\u4F7F\u7528\u3002\nexport function deriveGenerationLogPath(root, cwd, id, { compression = 'zstd' } = {}) {\n return join(deriveSessionDir(root, cwd, id), `session.v2.jsonl${compression === 'zstd' ? '.zstd' : ''}`)\n}\n\n// \u5B9A\u4F4D\u4E00\u4E2A\u5DF2\u843D\u76D8\u4F1A\u8BDD\u7684\u5168\u90E8\u7269\u7406\u5750\u6807\uFF1B\u4E09\u5C42\u5B88\u536B\u5728\u6B64\u6C47\u5408\u3002\u8FD4\u56DE\n// { root, projectDir, sessionDir, logPath, generationFiles }\n// \u6216 null\uFF08root \u4E0D\u53EF\u7528 / \u76EE\u5F55\u4E0D\u5B58\u5728 / \u65E0\u89C4\u8303 generation / id \u5F52\u5C5E\u6821\u9A8C\u62D2\u7EDD\uFF09\u3002\nexport async function locateSessionArtifacts(sp, header) {\n const root = resolveSessionRoot(sp)\n if (!root || !header || header.id == null) return null\n const sid = String(header.id)\n let sessionDir\n try {\n sessionDir = deriveSessionDir(root, header.cwd, sid)\n } catch (e) {\n return null\n }\n if (basename(sessionDir) !== encodeSegmentFor(sid)) return null\n let entries\n try {\n const st = await stat(sessionDir)\n if (!st.isDirectory()) return null\n entries = await readdir(sessionDir)\n } catch (e) {\n return null\n }\n const generationFiles = entries.filter((name) => GENERATION_LOG_RE.test(name))\n if (generationFiles.length === 0) return null\n // \u4F18\u5148 current generation\uFF08v2 \u2192 \u6700\u9AD8\u7248\u672C\u53F7\uFF09\uFF0C\u4FDD\u6301\u786E\u5B9A\u6027\u3002\n generationFiles.sort((a, b) => {\n const va = Number((a.match(/^session\\.v(\\d+)\\./) || [])[1] || 0)\n const vb = Number((b.match(/^session\\.v(\\d+)\\./) || [])[1] || 0)\n return vb - va\n })\n const logPath = join(sessionDir, generationFiles[0])\n if (!pathOwnsSession(logPath, sid)) return null\n return {\n root,\n projectDir: join(root, header.cwd === undefined || header.cwd === null || header.cwd === '' ? '_no-cwd' : projectKeyFor(header.cwd)),\n sessionDir,\n logPath,\n generationFiles,\n }\n}\n", "// path-guard.js \u2014 \u56DE\u6536\u7AD9/\u5F7B\u5E95\u5220\u9664\u524D\u7684\u300C\u65E5\u5FD7\u8DEF\u5F84\u5F52\u5C5E\u300D\u6821\u9A8C\uFF08\u7EAF\u51FD\u6570\uFF09\u3002\n//\n// purgeFromTrash \u5728\u7269\u7406 unlink \u524D\u5FC5\u987B\u786E\u8BA4\u76EE\u6807\u8DEF\u5F84\u771F\u7684\u5C5E\u4E8E\u8BE5\u4F1A\u8BDD\uFF0C\u9632\u6B62\u628A\n// \u65E0\u5173\u6587\u4EF6\u5220\u6389\u3002\u65E7\u5B9E\u73B0\u7528 `basename(dirname(target)) === sid`\uFF0C\u53EA\u5BF9 POSIX\n// \u5206\u9694\u7B26\u6210\u7ACB\uFF1AWindows \u98CE\u683C\u8DEF\u5F84\uFF08`C:\\\\\u2026\\\\<sid>\\\\session.jsonl.zstd`\uFF09\u5728\n// POSIX \u7248 path.basename \u4E0B\u6574\u4E32\u662F\u4E00\u4E2A basename\uFF0C\u6821\u9A8C\u4F1A\u9519\u8BEF\u62D2\u7EDD\uFF1B\u53CD\u8FC7\u6765\uFF0C\n// \u6DF7\u5408\u5206\u9694\u7B26\u6216 URL \u7F16\u7801\u8DEF\u5F84\u4E5F\u53EF\u80FD\u9020\u6210\u8BEF\u653E\u884C\u3002\u8FD9\u91CC\u7EDF\u4E00\u6309\u4E24\u79CD\u5206\u9694\u7B26\u5207\u5206\uFF0C\n// \u5E76\u5904\u7406\u76D8\u7B26\u524D\u7F00\u4E0E\u5C3E\u90E8\u659C\u6760\u3002\n//\n// \u63A5\u53D7\u4E24\u79CD\u5B98\u65B9/\u5386\u53F2\u5E03\u5C40\uFF1A\n// .../<sessionId>/session.jsonl.zstd \uFF08\u76EE\u5F55\u540D = \u4F1A\u8BDD id\uFF09\n// .../<sessionId>.jsonl.zstd \uFF08\u65E7\u540E\u7AEF\uFF1A\u6587\u4EF6\u540D\u542B\u4F1A\u8BDD id\uFF09\n\nfunction splitSegments(target) {\n return String(target)\n .replace(/[\\\\/]+$/, '')\n .split(/[\\\\/]/)\n .filter((seg) => seg.length > 0)\n}\n\n// \u53BB\u6389 Windows \u76D8\u7B26\u6BB5\uFF08\"C:\"\uFF09\uFF0C\u4FDD\u7559\u5176\u4F59\u6BB5\u3002POSIX \u8DEF\u5F84\u4E0D\u542B\u76D8\u7B26\u6BB5\uFF1A\n// \u4E00\u4E2A\u540D\u4E3A \"C:\" \u7684\u76EE\u5F55\u6BB5\u5728 macOS/Linux \u4E0A\u5408\u6CD5\u4F46\u6781\u7F55\u89C1\uFF0C\u628A\u5B83\u5F53\u76D8\u7B26\n// \u5904\u7406\u5BF9\u300C\u4F1A\u8BDD id \u5F52\u5C5E\u300D\u5224\u65AD\u6CA1\u6709\u5F71\u54CD\uFF08id \u4E0D\u4F1A\u662F \"C:\"\uFF09\u3002\nfunction stripDriveLetter(segments) {\n return segments.length > 0 && /^[A-Za-z]:$/.test(segments[0]) ? segments.slice(1) : segments\n}\n\n/**\n * Does `target` plausibly own `sid`'s stored log?\n * @param {string} target - absolute-ish log path reported by the backend or the trash index.\n * @param {string} sid - session id (already validated by isSafeSessionId: no separators).\n * @returns {boolean}\n */\nexport function pathOwnsSession(target, sid) {\n if (typeof target !== 'string' || target.length === 0) return false\n if (typeof sid !== 'string' || sid.length === 0) return false\n const segments = stripDriveLetter(splitSegments(target))\n if (segments.length === 0) return false\n const file = segments[segments.length - 1]\n // Layout 1: the session id owns the parent directory.\n if (segments.length >= 2 && segments[segments.length - 2] === sid) return true\n // Layout 2: legacy flat layout \u2014 the id is part of the file name itself.\n // Only a *standalone token* match counts: `sid` embedded in a longer id\n // (abc \u2194 abcdef) must NOT pass, otherwise a purge of `abc` could delete\n // `abcdef`'s log. Extension punctuation (\".jsonl.zstd\") is not id-glue.\n if (file.includes(sid)) {\n const ID_CHAR = /[A-Za-z0-9_-]/\n let from = 0\n while (true) {\n const at = file.indexOf(sid, from)\n if (at < 0) return false\n const before = at > 0 ? file[at - 1] : ''\n const after = at + sid.length < file.length ? file[at + sid.length] : ''\n if (!(before && ID_CHAR.test(before)) && !(after && ID_CHAR.test(after))) return true\n from = at + 1\n }\n }\n return false\n}\n", "// Compatibility boundary for the two DSH persistence generations supported by\n// dsh-sessions-manager. Business code consumes normalized headers and complete\n// inspections; it never needs to know whether DSH returned a legacy header or\n// a handle-era SessionPersistenceSnapshot.\n//\n// Handle-era notes (official contract, dsh-v0.1.3-alpha.1):\n// - `SessionHandle.read(offset?, length?, options?)` returns a bounded slice\n// of the valid contiguous log; an offset at/past the end returns [].\n// - Every handle is single-owner state: `close()` MUST run exactly once on\n// every path, including throws and aborts (the contract exposes\n// `SessionHandleClosedError` for operations after close).\n// - `stat(id)` \u2192 `SessionPersistenceSnapshot | undefined`; `snapshot.revision`\n// is an opaque change token valid ONLY within one service instance and one\n// session id (see src/session-meta-cache.js).\n\nimport { locateSessionArtifacts } from '../handle-era-paths.js'\n\nconst DEFAULT_CHUNK = 400\n// \u9632\u5FA1\u4E0A\u9650\uFF1A\u4E00\u6B21 inspect \u7684\u5206\u5757\u5FAA\u73AF\u7EDD\u4E0D\u80FD\u65E0\u9650\u81EA\u65CB\uFF08\u540E\u7AEF read \u884C\u4E3A\u5F02\u5E38\u65F6\u5FEB\u901F\u5931\u8D25\uFF09\u3002\nconst MAX_CHUNKS = 20000\n\nfunction normalizeReadResult(events) {\n if (Array.isArray(events)) return events\n if (events && typeof events[Symbol.iterator] === 'function') return [...events]\n return []\n}\n\nasync function closeQuietly(handle) {\n try { if (handle && typeof handle.close === 'function') await handle.close() } catch (e) { /* close \u662F\u5E42\u7B49\u515C\u5E95\uFF0C\u4E8C\u6B21\u5931\u8D25\u5FFD\u7565 */ }\n}\n\nfunction asHeader(value) {\n if (!value || typeof value !== 'object') return null\n const candidate = value.header && typeof value.header === 'object' ? value.header : value\n return candidate.id == null ? null : candidate\n}\n\nexport function normalizePersistenceEntry(value) {\n const header = asHeader(value)\n if (!header) return null\n const snapshot = value && value.header === header ? value : null\n return {\n header,\n snapshot,\n id: String(header.id),\n sizeBytes: snapshot && Number.isFinite(snapshot.sizeBytes) ? Number(snapshot.sizeBytes) : null,\n eventCount: snapshot && Number.isSafeInteger(snapshot.eventCount) ? snapshot.eventCount : null,\n revision: snapshot && typeof snapshot.revision === 'string' && snapshot.revision ? snapshot.revision : null,\n }\n}\n\nexport function normalizePersistenceList(values) {\n if (!Array.isArray(values)) return []\n return values.map(normalizePersistenceEntry).filter(Boolean)\n}\n\nexport function createPersistenceAdapter(service) {\n if (!service || typeof service.list !== 'function') throw new TypeError('sessionPersistence.list is required')\n\n const hasStat = typeof service.stat === 'function'\n const kind = typeof service.open === 'function' ? 'session-handle' : 'legacy'\n\n async function listEntries(options) {\n return normalizePersistenceList(await service.list(options))\n }\n\n // Handle-era only: the official lightweight observation. Returns the\n // normalized snapshot entry, or null when the session does not exist.\n // Never falls back to reading the log \u2014 callers use it for existence\n // checks and revision-based cache validation only.\n async function statSession(id) {\n if (!hasStat) return null\n const snapshot = await service.stat(id)\n return snapshot ? normalizePersistenceEntry(snapshot) : null\n }\n\n // Read one bounded slice through a SessionHandle. The caller owns the\n // handle lifecycle; this helper only guarantees close on read failure \u2014\n // the surrounding try/finally in the chunk drivers below is authoritative.\n async function readChunk(handle, offset, length, signal) {\n if (signal && signal.aborted) {\n const error = new Error('\u4F1A\u8BDD\u8BFB\u53D6\u5DF2\u53D6\u6D88')\n error.code = 'DSM_READ_ABORTED'\n throw error\n }\n const events = await handle.read(offset, length, signal ? { signal } : undefined)\n return normalizeReadResult(events)\n }\n\n // Sequential chunk driver shared by inspectSession / readSession. Opens the\n // handle itself so every code path (success, mid-chunk throw, abort) closes\n // it exactly once in `finally`.\n async function readChunks(id, { offset = 0, chunkSize = DEFAULT_CHUNK, signal, onEvents }) {\n if (typeof service.open !== 'function') throw new Error('\u5F53\u524D DSH \u6301\u4E45\u5316\u670D\u52A1\u4E0D\u652F\u6301\u8BFB\u53D6\u4F1A\u8BDD')\n const handle = await service.open(id, 'read')\n if (!handle || typeof handle.read !== 'function' || typeof handle.close !== 'function') {\n await closeQuietly(handle)\n throw new Error('DSH \u8FD4\u56DE\u4E86\u65E0\u6548\u7684 SessionHandle')\n }\n let cursor = Number.isSafeInteger(offset) && offset >= 0 ? offset : 0\n let total = 0\n try {\n for (let round = 0; round < MAX_CHUNKS; round++) {\n const events = await readChunk(handle, cursor, chunkSize, signal)\n if (events.length === 0) break\n cursor += events.length\n total += events.length\n if (onEvents) await onEvents(events, { offset: cursor - events.length, total })\n if (events.length < chunkSize) break\n }\n } finally {\n await closeQuietly(handle)\n }\n return {\n meta: handle.header || handle.meta || null,\n inheritedEventCount: Number.isSafeInteger(handle.inheritedEventCount) ? handle.inheritedEventCount : 0,\n eventCount: total,\n }\n }\n\n // Streamed full inspection: folds the log chunk-by-chunk through `onEvents`\n // so \u8BE6\u60C5 / \u5BFC\u51FA never materialize a whole large log in memory. `signal`\n // (AbortSignal) cancels before the next chunk; the handle closes on every\n // path. Legacy runtimes have no bounded read \u2014 readFrom already returns the\n // complete log, which becomes a single onEvents batch.\n async function inspectSession(id, opts = {}) {\n const chunkSize = Number.isSafeInteger(opts.chunkSize) && opts.chunkSize > 0 ? opts.chunkSize : DEFAULT_CHUNK\n if (typeof service.open === 'function') {\n // \u53D6\u6D88\u53D1\u751F\u5728 open \u4E4B\u524D\uFF1A\u8FDE handle \u90FD\u4E0D\u53BB\u5F00\u3002\n if (opts.signal && opts.signal.aborted) {\n const error = new Error('\u4F1A\u8BDD\u8BFB\u53D6\u5DF2\u53D6\u6D88')\n error.code = 'DSM_READ_ABORTED'\n throw error\n }\n return readChunks(id, { offset: opts.offset || 0, chunkSize, signal: opts.signal, onEvents: opts.onEvents })\n }\n if (typeof service.readFrom !== 'function') throw new Error('\u5F53\u524D DSH \u6301\u4E45\u5316\u670D\u52A1\u4E0D\u652F\u6301\u8BFB\u53D6\u4F1A\u8BDD')\n if (opts.signal && opts.signal.aborted) {\n const error = new Error('\u4F1A\u8BDD\u8BFB\u53D6\u5DF2\u53D6\u6D88')\n error.code = 'DSM_READ_ABORTED'\n throw error\n }\n const result = await service.readFrom(id, opts.offset || 0)\n const events = normalizeReadResult(result && result.events)\n if (opts.onEvents && events.length) await opts.onEvents(events, { offset: opts.offset || 0, total: events.length })\n return {\n meta: result && result.meta ? result.meta : null,\n inheritedEventCount: result && Number.isSafeInteger(result.inheritedEventCount) ? result.inheritedEventCount : 0,\n eventCount: events.length,\n }\n }\n\n // Complete read (legacy convenience shape). Internally chunked; callers that\n // stream should prefer inspectSession so large logs never buffer whole.\n async function readSession(id, offset = 0) {\n if (typeof service.readFrom === 'function') {\n const result = await service.readFrom(id, offset)\n return {\n meta: result && result.meta ? result.meta : null,\n inheritedEventCount: result && Number.isSafeInteger(result.inheritedEventCount) ? result.inheritedEventCount : 0,\n events: result && Array.isArray(result.events) ? result.events : [],\n }\n }\n const events = []\n const summary = await readChunks(id, { offset, onEvents: (batch) => { events.push(...batch) } })\n return {\n meta: summary.meta,\n inheritedEventCount: summary.inheritedEventCount,\n events,\n }\n }\n\n function locate(header) {\n if (typeof service.locate === 'function') return service.locate(header)\n return null\n }\n\n // \u843D\u76D8\u6821\u9A8C\u7248\u5B9A\u4F4D\uFF1Alegacy \u8D70\u5B98\u65B9 locate\uFF1Bhandle \u65F6\u4EE3\u5B98\u65B9\u6536\u8D70\u4E86 locate\uFF0C\u6539\u7531\n // handle-era-paths \u7684\u4E09\u5C42\u5B88\u536B\u63A8\u5BFC\uFF08root \u5B9E\u4F8B\u5B57\u6BB5 \u2192 \u76EE\u5F55\u7ED3\u6784 \u2192 id \u5F52\u5C5E\uFF09\uFF0C\n // \u4EFB\u4E00\u5C42\u5931\u8D25\u8FD4\u56DE null\uFF0C\u8C03\u7528\u65B9\u5B89\u5168\u964D\u7EA7\u3002\u8FD4\u56DE { path, sessionDir|null }\u3002\n async function locateVerified(header) {\n if (typeof service.locate === 'function') {\n try {\n const loc = service.locate(header)\n if (loc && typeof loc.path === 'string') return { path: loc.path, sessionDir: null }\n } catch (e) { /* \u843D\u5230\u63A8\u5BFC */ }\n }\n const artifacts = await locateSessionArtifacts(service, header)\n return artifacts ? { path: artifacts.logPath, sessionDir: artifacts.sessionDir } : null\n }\n\n return { kind, listEntries, readSession, inspectSession, statSession, locate, locateVerified, hasStat }\n}\n", "// Capability matrix for the two DSH persistence generations. Every user-visible\n// action gets its own availability flag plus a Chinese reason, so the UI can\n// disable buttons honestly and the host routes can refuse with a stable error.\n//\n// Guiding rule (revised 2026-09-06 by explicit user decision): the official\n// SessionHandle-era contract (dsh-v0.1.3-alpha.1) exposes NO delete and NO\n// relocation \u2014 but legacy implementations were never pure-public either (they\n// used the official `locate` to find the path, then acted on the filesystem\n// directly). The user chose to keep that semi-official approach in the handle\n// era: private-path operations ARE allowed, but only through the guarded\n// derivation in src/handle-era-paths.js (backend root instance field \u2192 session\n// directory structure \u2192 id ownership) plus handle-era-ops.js (writer probe,\n// backup + rollback). Any derivation failure degrades to \"unavailable\".\n//\n// Action vocabulary (canonical):\n// readInspection read/list/stat the stored log (read-only)\n// archive archive/unarchive via workspaceRegistry (a marking op)\n// softTrash move a session into the plugin recycle bin (log stays put)\n// restoreIndexedSession restore a trashed session after verifying the\n// underlying stored session still exists\n// physicalPurge irreversibly delete the stored log (guarded fs rm)\n// relocateSession move a session across workspaces (changes header cwd)\n//\n// Legacy aliases (read / trash / restoreTrash / purge / move) are kept so the\n// client and older routes keep working during the transition.\n\nfunction action(available, reason = null) {\n return { available: !!available, reason: available ? null : reason }\n}\n\nexport function detectCapabilities({ persistence, workspaceRegistry }) {\n const handleApi = !!(persistence && typeof persistence.open === 'function')\n const legacyRead = !!(persistence && typeof persistence.readFrom === 'function')\n const legacyLocate = !!(persistence && (typeof persistence.locate === 'function'\n || (persistence.backend && typeof persistence.backend.locate === 'function')))\n // handle \u65F6\u4EE3\uFF1Aroot \u5FC5\u987B\u76F4\u63A5\u8BFB\u81EA\u540E\u7AEF\u5B9E\u4F8B\u5B57\u6BB5\uFF08session-persistence-jsonl \u7684\n // `root`\uFF09\uFF0C\u62FF\u4E0D\u5230\u6574\u4F53\u964D\u7EA7\u2014\u2014\u7EDD\u4E0D\u731C\u8DEF\u5F84\u3002\n const handleEraRoot = !!(handleApi && persistence\n && typeof persistence.root === 'string' && persistence.root.length > 0)\n const canVerifyExistence = !!(handleApi || legacyRead\n || (persistence && typeof persistence.stat === 'function'))\n const readOk = legacyRead || handleApi\n const workspaceInternals = !!(workspaceRegistry\n && workspaceRegistry.headers && workspaceRegistry.sessionPaths\n && typeof workspaceRegistry.replaceHeaderIndex === 'function')\n\n const matrix = {\n readInspection: action(readOk, '\u5F53\u524D DSH \u672A\u63D0\u4F9B\u53EF\u8BC6\u522B\u7684\u4F1A\u8BDD\u8BFB\u53D6\u63A5\u53E3'),\n archive: action(!!(workspaceRegistry && typeof workspaceRegistry.archiveSession === 'function'), '\u5F53\u524D DSH \u672A\u63D0\u4F9B\u5F52\u6863\u63A5\u53E3'),\n softTrash: action(readOk, '\u5F53\u524D DSH \u65E0\u6CD5\u8BFB\u53D6\u4F1A\u8BDD\uFF0C\u4E0D\u80FD\u5B89\u5168\u79FB\u5165\u56DE\u6536\u7AD9'),\n // \u6062\u590D\u4E0D\u518D\u65E0\u6761\u4EF6\u5BA3\u79F0\u53EF\u7528\uFF1A\u5FC5\u987B\u80FD\u6821\u9A8C\u5E95\u5C42\u4F1A\u8BDD\u4ECD\u5B58\u5728\uFF08stat \u6216 list\uFF09\uFF0C\n // \u5426\u5219\u6062\u590D\u53EA\u4F1A\u5236\u9020\u4E00\u6761\u6307\u5411\u5DF2\u6D88\u5931\u65E5\u5FD7\u7684\u50F5\u5C38\u6761\u76EE\u3002\n restoreIndexedSession: action(canVerifyExistence, '\u5F53\u524D DSH \u65E0\u6CD5\u6821\u9A8C\u5E95\u5C42\u4F1A\u8BDD\u662F\u5426\u5B58\u5728\uFF0C\u4E0D\u80FD\u5B89\u5168\u6062\u590D'),\n physicalPurge: action(\n (!handleApi && legacyLocate) || (handleApi && handleEraRoot && canVerifyExistence),\n handleApi && !handleEraRoot\n ? '\u65E0\u6CD5\u4ECE\u5F53\u524D DSH \u540E\u7AEF\u786E\u8BA4\u4F1A\u8BDD\u5B58\u50A8\u6839\u76EE\u5F55\uFF0C\u5DF2\u505C\u6B62\u7269\u7406\u5220\u9664\u4EE5\u4FDD\u62A4\u6570\u636E\u5B89\u5168'\n : '\u5F53\u524D DSH \u7248\u672C\u5C1A\u672A\u63D0\u4F9B\u7ECF\u8FC7\u9A8C\u8BC1\u7684\u5B89\u5168\u6C38\u4E45\u5220\u9664\u80FD\u529B\uFF1B\u79FB\u5165\u56DE\u6536\u7AD9\u4E0D\u4F1A\u91CA\u653E\u78C1\u76D8\u7A7A\u95F4',\n ),\n relocateSession: action(\n (!handleApi && legacyRead && legacyLocate && workspaceInternals)\n || (handleApi && handleEraRoot && readOk && workspaceInternals),\n handleApi && !workspaceInternals\n ? '\u5F53\u524D DSH \u672A\u63D0\u4F9B\u5DE5\u4F5C\u533A\u6CE8\u518C\u8868\u5185\u90E8\u7ED3\u6784\uFF0C\u8DE8\u5DE5\u4F5C\u533A\u79FB\u52A8\u540E\u65E0\u6CD5\u5373\u65F6\u5237\u65B0\u5206\u7EC4'\n : handleApi && !handleEraRoot\n ? '\u65E0\u6CD5\u4ECE\u5F53\u524D DSH \u540E\u7AEF\u786E\u8BA4\u4F1A\u8BDD\u5B58\u50A8\u6839\u76EE\u5F55\uFF0C\u5DF2\u505C\u6B62\u79FB\u52A8\u4EE5\u4FDD\u62A4\u6570\u636E\u5B89\u5168'\n : '\u5F53\u524D DSH \u7248\u672C\u5C1A\u672A\u63D0\u4F9B\u7ECF\u8FC7\u9A8C\u8BC1\u7684\u8DE8\u5DE5\u4F5C\u533A\u8FC1\u79FB\u80FD\u529B',\n ),\n }\n // Legacy aliases for existing client/routes/tests.\n matrix.read = matrix.readInspection\n matrix.trash = matrix.softTrash\n matrix.restoreTrash = matrix.restoreIndexedSession\n matrix.purge = matrix.physicalPurge\n matrix.move = matrix.relocateSession\n\n return {\n persistence: handleApi ? 'session-handle' : 'legacy',\n actions: matrix,\n }\n}\n\nexport function requireCapability(capabilities, name) {\n const value = capabilities && capabilities.actions && capabilities.actions[name]\n if (value && value.available) return\n const error = new Error((value && value.reason) || `\u5F53\u524D\u73AF\u5883\u4E0D\u652F\u6301 ${name}`)\n error.status = 409\n error.code = 'DSM_CAPABILITY_UNAVAILABLE'\n throw error\n}\n", "// Handle-era destructive/moving operations (dsh-v0.1.3-alpha.1).\n//\n// 2026-09-06 \u7528\u6237\u51B3\u7B56\uFF1A\u8FD9\u4E24\u7C7B\u80FD\u529B\u5728 legacy \u65F6\u4EE3\u672C\u5C31\u662F\u300C\u5B98\u65B9 locate \u67E5\u8DEF\u5F84 +\n// \u76F4\u63A5\u6587\u4EF6\u7CFB\u7EDF\u64CD\u4F5C\u300D\u7684\u534A\u5B98\u65B9\u5B9E\u73B0\uFF1Bhandle \u65F6\u4EE3\u5B98\u65B9\u6536\u8D70 locate \u540E\uFF0C\u6539\u4E3A\u7531\n// src/handle-era-paths.js \u7684\u4E09\u5C42\u5B88\u536B\u63A8\u5BFC\u8DEF\u5F84\u3002\u672C\u6A21\u5757\u5B9E\u73B0\u4E24\u4E2A\u64CD\u4F5C\u6838\u5FC3\uFF0C\u4E3B\u8DEF\u5F84\n// \u5C3D\u91CF\u8D70\u5B98\u65B9\u516C\u5171 API\uFF08create/append/flush/close/stat/open\uFF09\uFF0C\u6587\u4EF6\u7CFB\u7EDF\u64CD\u4F5C\u4EC5\u9650\n// \u4E8E\u300C\u628A\u65E7\u65E5\u5FD7\u6539\u540D\u5907\u4EFD / \u5220\u9664\u4F1A\u8BDD\u76EE\u5F55\u300D\u8FD9\u4E24\u6B65\uFF0C\u5E76\u4E14\u5168\u90E8\u6709\u5907\u4EFD\u56DE\u6EDA\u6216\u524D\u7F6E\u63A2\u6D4B\uFF1A\n//\n// - moveSessionToCwd: revision \u524D\u540E\u6821\u9A8C\uFF08\u8C03\u7528\u65B9\uFF09\u2192 \u5B98\u65B9 create+append \u91CD\u653E\n// \u4E3A\u4E3B\u8DEF\u5F84\uFF1B\u540E\u7AEF\u5DF2\u6709\u540C id \u5E7D\u7075\u65F6\u56DE\u9000\u5230 frame0 cwd \u6539\u5199\u642C\u8FD0\uFF08\u590D\u7528\n// zstd-frame.js\uFF0C\u4E0E legacy relocateLog \u540C\u4E00\u5957\u6821\u9A8C\uFF09\u3002\u4EFB\u4F55\u5931\u8D25\u90FD\u4F1A\u628A\u5907\u4EFD\n// \u6539\u540D\u56DE\u539F\u4F4D\u5E76\u6E05\u7406\u76EE\u6807\u76EE\u5F55\uFF0C\u7EDD\u4E0D\u7559\u4E0B\u534A\u79FB\u52A8\u72B6\u6001\u3002\n// - purgeSessionArtifacts: \u5B98\u65B9 open(id,'write') \u63A2\u6D4B\u5E76\u77ED\u6682\u63A5\u7BA1\u5199\u6240\u6709\u6743\n// \uFF08\u6D3B\u8DC3\u5199\u8005 \u2192 409 \u62D2\u7EDD\uFF09\uFF0C\u7136\u540E\u6574\u76EE\u5F55\u5220\u9664\u4F1A\u8BDD\u76EE\u5F55\uFF08basename \u5DF2\u7531\u8DEF\u5F84\n// \u5B88\u536B\u9A8C\u8BC1\uFF09\uFF0C\u6700\u540E\u4EE5\u5B98\u65B9 stat \u590D\u6838\u8BE5 id \u5DF2\u6D88\u5931\u3002\n//\n// \u6D3B\u8DC3\u5199\u8005\u7B56\u7565\uFF1A\u4E24\u4E2A\u64CD\u4F5C\u90FD\u62D2\u7EDD\u300C\u6B63\u5728\u8FDB\u884C\u4E2D\u300D\u7684\u4F1A\u8BDD\uFF0C\u800C\u4E0D\u662F\u7167 legacy \u90A3\u6837\n// \u6539\u5199\u6D3B\u8DC3\u5BF9\u8C61\u2014\u2014handle \u65F6\u4EE3\u7684\u5199\u53E5\u67C4\u6240\u6709\u6743\u5728\u5B98\u65B9 tracker \u5185\u90E8\uFF0C\u4E0E\u5176\u6253\u8865\u4E01\n// \u4E0D\u5982\u5982\u5B9E\u62D2\u7EDD\uFF0C\u98CE\u9669\u9762\u66F4\u5C0F\u3002\n\nimport { mkdir, readFile, rename, rm, unlink, writeFile } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport { rewriteFrame0CwdInMemory, scanZstdFrames } from './zstd-frame.js'\nimport { deriveSessionDir, locateSessionArtifacts } from './handle-era-paths.js'\n\nconst MOVE_BATCH = 400\n\nfunction conflictError(message) {\n const error = new Error(message)\n error.status = 409\n error.code = 'DSM_SESSION_BUSY'\n return error\n}\n\nfunction failureText(e) {\n return `${(e && e.name) || ''} ${(e && e.message) || e}`\n}\n\nfunction isAlreadyOwned(e) {\n return /already owned/i.test(failureText(e))\n}\n\nfunction isAlreadyExists(e) {\n return /already exists/i.test(failureText(e))\n}\n\nasync function closeQuietly(handle) {\n try { if (handle && typeof handle.close === 'function') await handle.close() } catch (e) { /* \u76EE\u5F55\u53EF\u80FD\u5DF2\u88AB\u5220\uFF0Clease \u91CA\u653E\u5931\u8D25\u53EF\u5FFD\u7565 */ }\n}\n\n// \u5B98\u65B9\u5199\u6240\u6709\u6743\u63A2\u6D4B\uFF1A\u80FD open(id,'write') \u5C31\u8BC1\u660E\u5F53\u524D\u6CA1\u6709\u6D3B\u8DC3\u5199\u8005\uFF08\u987A\u5E26\u8BA9\u5B98\u65B9\n// \u8DEF\u5F84 flush \u4E00\u6B21\uFF09\uFF0C\u62FF\u5230\u540E\u7ACB\u5373\u91CA\u653E\u3002\u771F\u6B63\u7684\u5E76\u53D1\u4FDD\u62A4\u6765\u81EA\u968F\u540E\u7684 rename-aside\n// \uFF08\u65E7\u65E5\u5FD7\u6D88\u5931\u540E\uFF0C\u8FDF\u5230\u7684\u5199\u8005\u4F1A\u5728\u5B98\u65B9 open \u5904\u5E72\u51C0\u5730 NotFound\uFF0C\u800C\u4E0D\u662F\u5199\u574F\u6570\u636E\uFF09\u3002\nexport async function ensureNoActiveWriter(sp, sid) {\n let handle = null\n try {\n handle = await sp.open(sid, 'write')\n } catch (e) {\n if (isAlreadyOwned(e)) throw conflictError('\u8BE5\u4F1A\u8BDD\u6B63\u5728\u8FDB\u884C\u4E2D\uFF08\u5B58\u5728\u6D3B\u8DC3\u5199\u5165\uFF09\uFF0C\u8BF7\u5148\u5207\u6362\u5230\u522B\u7684\u4F1A\u8BDD\u518D\u64CD\u4F5C\u3002')\n throw e\n }\n await closeQuietly(handle)\n}\n\n// \u5F7B\u5E95\u5220\u9664\u4E00\u4E2A\u4F1A\u8BDD\u7684\u5168\u90E8\u7269\u7406\u4EA7\u7269\u3002header \u5FC5\u987B\u6765\u81EA\u5B98\u65B9 list/stat\uFF08\u643A\u5E26\u771F\u5B9E cwd\uFF09\u3002\n// \u8FD4\u56DE\u88AB\u5220\u9664\u7684 artifacts\uFF08\u4F9B\u4E0A\u5C42\u8BB0\u5F55 originalPath \u7B49\uFF09\u3002\nexport async function purgeSessionArtifacts(sp, sid, header) {\n const artifacts = await locateSessionArtifacts(sp, header)\n if (!artifacts) {\n const error = new Error('\u65E0\u6CD5\u5B9A\u4F4D\u8BE5\u4F1A\u8BDD\u7684\u7269\u7406\u65E5\u5FD7\u76EE\u5F55\uFF0C\u5DF2\u505C\u6B62\u6C38\u4E45\u5220\u9664')\n error.status = 409\n throw error\n }\n let writer = null\n try {\n writer = await sp.open(sid, 'write')\n } catch (e) {\n if (isAlreadyOwned(e)) throw conflictError('\u8BE5\u4F1A\u8BDD\u6B63\u5728\u8FDB\u884C\u4E2D\uFF08\u5B58\u5728\u6D3B\u8DC3\u5199\u5165\uFF09\uFF0C\u65E0\u6CD5\u5F7B\u5E95\u5220\u9664\u3002')\n throw e\n }\n // \u53E5\u67C4\u4ECE\u672A append \u8FC7\uFF0C\u5148\u91CA\u653E\u518D\u5220\u76EE\u5F55\uFF08Windows \u4E0A\u6253\u5F00\u4E2D\u7684\u6587\u4EF6\u65E0\u6CD5\u5220\u9664\uFF09\u3002\n await closeQuietly(writer)\n writer = null\n try {\n // \u6574\u76EE\u5F55\u79FB\u9664\uFF08\u542B lease \u7B49\u4F1A\u8BDD\u672C\u5730\u6587\u4EF6\uFF09\u3002basename === encodeSegment(id)\n // \u4E0E\u300C\u89C4\u8303 generation \u5728\u4F4D\u300D\u90FD\u5DF2\u5728 locateSessionArtifacts \u9A8C\u8BC1\u8FC7\u3002\n await rm(artifacts.sessionDir, { recursive: true, force: true })\n } catch (e) {\n const error = new Error('\u5220\u9664\u4F1A\u8BDD\u65E5\u5FD7\u5931\u8D25\uFF1A' + String((e && e.message) || e))\n error.status = 500\n throw error\n }\n // \u5B98\u65B9\u89C6\u89D2\u590D\u6838\uFF1A\u8BE5 id \u5FC5\u987B\u5DF2\u4ECE\u540E\u7AEF\u6D88\u5931\u3002\n if (typeof sp.stat === 'function') {\n const after = await sp.stat(sid).catch(() => undefined)\n if (after) {\n const error = new Error('\u5220\u9664\u540E\u5B98\u65B9 stat \u4ECD\u80FD\u770B\u5230\u8BE5\u4F1A\u8BDD\uFF0C\u5DF2\u4E2D\u6B62\uFF08\u76EE\u5F55\u53EF\u80FD\u88AB\u5E76\u53D1\u91CD\u5EFA\uFF09')\n error.status = 500\n throw error\n }\n }\n return artifacts\n}\n\n// frame0 \u6539\u5199\u56DE\u9000\uFF1A\u628A\u5907\u4EFD\u65E5\u5FD7\u7684 frame0 cwd \u6539\u5199\u4E3A\u76EE\u6807\u5DE5\u4F5C\u533A\u540E\u642C\u5165\u76EE\u6807\u4F1A\u8BDD\u76EE\u5F55\u3002\n// \u6821\u9A8C\u4E0E legacy relocateLog \u5B8C\u5168\u4E00\u81F4\uFF1A\u5E27\u6570\u4E0D\u53D8 + frame0 \u4E4B\u5916\u5B57\u8282\u9010\u4F4D\u76F8\u7B49\u3002\nasync function relocateRewrittenBackup({ sid, canonical, backupPath, artifacts }) {\n const original = await readFile(backupPath)\n const frames = scanZstdFrames(original).frames\n if (frames.length === 0) throw new Error('\u79FB\u52A8\u524D\u6821\u9A8C\u5931\u8D25\uFF1A\u4F1A\u8BDD\u65E5\u5FD7\u6CA1\u6709\u5B8C\u6574 zstd \u5E27')\n const rewritten = rewriteFrame0CwdInMemory(original, canonical)\n const rewrittenFrames = scanZstdFrames(rewritten).frames\n if (rewrittenFrames.length !== frames.length) throw new Error('\u79FB\u52A8\u540E\u6821\u9A8C\u5931\u8D25\uFF1A\u4F1A\u8BDD\u65E5\u5FD7\u5E27\u6570\u53D1\u751F\u53D8\u5316')\n if (!original.subarray(frames[0].end).equals(rewritten.subarray(rewrittenFrames[0].end))) {\n throw new Error('\u79FB\u52A8\u540E\u6821\u9A8C\u5931\u8D25\uFF1A\u4F1A\u8BDD\u4E8B\u4EF6\u5185\u5BB9\u53D1\u751F\u53D8\u5316')\n }\n const targetDir = deriveSessionDir(artifacts.root, canonical, sid)\n await mkdir(targetDir, { recursive: true })\n const staged = join(targetDir, `.move-stage-${process.pid}-${Date.now()}`)\n await writeFile(staged, rewritten, { mode: 0o600 })\n await rename(staged, join(targetDir, artifacts.generationFiles[0]))\n return targetDir\n}\n\n// \u8DE8\u5DE5\u4F5C\u533A\u79FB\u52A8\u6838\u5FC3\u3002events \u4E3A\u5B8C\u6574\u4E8B\u4EF6\u6570\u7EC4\uFF08\u5B98\u65B9 read \u8DEF\u5F84\u8BFB\u56DE\uFF0Cseq \u4FDD\u6301\u539F\u503C\uFF09\u3002\n// seeded\uFF08fork \u6EAF\u6E90\uFF09\u65E5\u5FD7\u7684\u7269\u7406\u4E8B\u4EF6 seq \u4E0D\u4ECE 0 \u8D77\u6B65\u65F6\uFF0C\u5B98\u65B9 assertContiguous\n// \u4F1A\u62D2\u7EDD\u76F4\u5F55\u2014\u2014\u6B64\u65F6\u628A\u526F\u672C\u65E5\u5FD7\u7684 seq \u91CD\u6392\u4E3A 0 \u8D77\u6B65\uFF08\u4EC5\u526F\u672C\u7684\u5B58\u50A8\u5E8F\uFF0C\u4E8B\u4EF6\u5185\u5BB9\n// \u4E0D\u53D8\uFF09\uFF0C\u5E76\u5728 create \u65F6\u5982\u5B9E\u643A\u5E26 inheritedEventCount \u6EAF\u6E90\u3002\nexport async function moveSessionToCwd({ sp, sid, header, canonical, events = [], inheritedEventCount = 0 }) {\n const artifacts = await locateSessionArtifacts(sp, header)\n if (!artifacts) {\n const error = new Error('\u65E0\u6CD5\u5B9A\u4F4D\u8BE5\u4F1A\u8BDD\u7684\u7269\u7406\u65E5\u5FD7\uFF0C\u5DF2\u505C\u6B62\u79FB\u52A8')\n error.status = 409\n throw error\n }\n await ensureNoActiveWriter(sp, sid)\n const newHeader = Object.assign({}, header, { cwd: canonical })\n const firstSeq = events.length ? Number(events[0].seq) : 0\n const replay = firstSeq !== 0 ? events.map((event, index) => ({ ...event, seq: index })) : events\n const createOptions = header.isSeeded && Number.isSafeInteger(inheritedEventCount) && inheritedEventCount > 0\n ? { inheritedEventCount }\n : undefined\n const backupPath = `${artifacts.logPath}.move-backup-${process.pid}-${Date.now()}`\n await rename(artifacts.logPath, backupPath)\n let writer = null\n try {\n try {\n writer = await sp.create(newHeader, createOptions)\n for (let i = 0; i < replay.length; i += MOVE_BATCH) {\n await writer.append(replay.slice(i, i + MOVE_BATCH))\n }\n await writer.flush()\n await writer.close()\n writer = null\n } catch (e) {\n if (isAlreadyExists(e)) {\n // \u540E\u7AEF\u5185\u5B58\u91CC\u5DF2\u6709\u540C id \u8BB0\u5F55\uFF08created-but-unmaterialized \u5E7D\u7075\u7B49\uFF09\uFF1A\n // \u56DE\u9000\u5230 frame0 \u6539\u5199\u642C\u8FD0\uFF0C\u4E0D\u518D\u8D70 create\u3002\n await relocateRewrittenBackup({ sid, canonical, backupPath, artifacts })\n } else {\n throw e\n }\n }\n // \u5B98\u65B9\u89C6\u89D2\u6821\u9A8C\uFF1A\u65B0 cwd \u5FC5\u987B\u751F\u6548\uFF1B\u4E8B\u4EF6\u6570\u4E00\u81F4\uFF08snapshot.eventCount \u7F3A\u7701\u65F6\u8DF3\u8FC7\uFF09\u3002\n if (typeof sp.stat !== 'function') throw new Error('\u79FB\u52A8\u540E\u65E0\u6CD5\u6821\u9A8C\uFF1A\u540E\u7AEF\u672A\u63D0\u4F9B stat')\n const after = await sp.stat(sid)\n if (!after || !after.header || after.header.cwd !== canonical) {\n throw new Error('\u79FB\u52A8\u540E\u6821\u9A8C\u5931\u8D25\uFF1A\u4F1A\u8BDD\u5DE5\u4F5C\u76EE\u5F55\u672A\u6B63\u786E\u66F4\u65B0')\n }\n if (Number.isSafeInteger(after.eventCount) && events.length > 0 && after.eventCount !== events.length) {\n throw new Error(`\u79FB\u52A8\u540E\u6821\u9A8C\u5931\u8D25\uFF1A\u4E8B\u4EF6\u6570\u4E0D\u4E00\u81F4\uFF08\u6E90 ${events.length}\uFF0C\u526F\u672C ${after.eventCount}\uFF09`)\n }\n } catch (e) {\n // \u56DE\u6EDA\uFF1A\u6E05\u6389\u76EE\u6807\u76EE\u5F55\u91CC\u7684\u534A\u6210\u54C1\uFF0C\u628A\u5907\u4EFD\u6539\u540D\u56DE\u539F\u4F4D\u3002\n await closeQuietly(writer)\n try { await rm(deriveSessionDir(artifacts.root, canonical, sid), { recursive: true, force: true }) } catch (_) {}\n try { await rename(backupPath, artifacts.logPath) } catch (_) {}\n if (e && e.status) throw e\n const error = new Error('\u79FB\u52A8\u4F1A\u8BDD\u65E5\u5FD7\u5931\u8D25\uFF1A' + String((e && e.message) || e))\n error.status = 500\n throw error\n }\n try { await unlink(backupPath) } catch (e) { /* \u5907\u4EFD\u6E05\u7406\u5931\u8D25\u4E0D\u963B\u585E\u6210\u529F\u7ED3\u679C */ }\n return { sessionDir: deriveSessionDir(artifacts.root, canonical, sid) }\n}\n"],
|
|
5
|
+
"mappings": ";AASA,SAAS,SAAAA,QAAO,YAAAC,WAAU,UAAU,UAAAC,SAAQ,QAAAC,OAAM,UAAAC,SAAQ,aAAAC,kBAAiB;AAC3E,SAAS,YAAAC,WAAU,WAAAC,UAAS,YAAY,QAAAC,aAAY;AACpD,SAAS,gBAAAC,qBAAoB;AAC7B,SAAS,WAAAC,gBAAe;;;ACAxB,OAAO,UAAU;AAKV,IAAM,aAAa;AAE1B,IAAM,gBAAgB,EAAE,QAAQ,EAAE,CAAC,KAAK,UAAU,mBAAmB,GAAG,EAAE,EAAE;AAWrE,SAAS,eAAe,KAAK,YAAY,OAAO,mBAAmB;AACxE,QAAM,SAAS,CAAC;AAChB,MAAI,SAAS;AACb,SAAO,SAAS,IAAI,QAAQ;AAC1B,UAAM,QAAQ;AACd,QAAI,IAAI,SAAS,SAAS,EAAG,QAAO,EAAE,QAAQ,WAAW,MAAM;AAC/D,QAAI,IAAI,aAAa,MAAM,MAAM,YAAY;AAC3C,YAAM,IAAI,MAAM,sEAAe,MAAM,uCAAmB;AAAA,IAC1D;AACA,cAAU;AACV,QAAI,WAAW,IAAI,OAAQ,QAAO,EAAE,QAAQ,WAAW,MAAM;AAE7D,UAAM,aAAa,IAAI,UAAU,QAAQ;AACzC,SAAK,aAAa,QAAU,EAAG,OAAM,IAAI,MAAM,sEAAe,SAAS,CAAC,mDAAW;AACnF,UAAM,kBAAkB,eAAe;AACvC,UAAM,iBAAiB,aAAa,QAAU;AAC9C,UAAM,YAAY,aAAa,OAAU;AACzC,UAAM,iBAAiB,aAAa;AACpC,UAAM,kBAAkB,mBAAmB,IAAI,IAAI;AACnD,UAAM,mBAAmB,oBAAoB,IAAK,gBAAgB,IAAI,IAAK,KAAK;AAChF,UAAM,wBAAwB,gBAAgB,IAAI,KAAK,kBAAkB;AACzE,QAAI,IAAI,SAAS,SAAS,qBAAsB,QAAO,EAAE,QAAQ,WAAW,MAAM;AAClF,cAAU;AAEV,eAAS;AACP,UAAI,IAAI,SAAS,SAAS,EAAG,QAAO,EAAE,QAAQ,WAAW,MAAM;AAC/D,YAAM,cAAc,IAAI,WAAW,QAAQ,CAAC;AAC5C,gBAAU;AACV,YAAM,aAAa,cAAc,OAAO;AACxC,YAAM,YAAa,gBAAgB,IAAK;AACxC,YAAM,YAAY,gBAAgB;AAClC,UAAI,cAAc,EAAM,OAAM,IAAI,MAAM,sEAAe,SAAS,CAAC,mDAAW;AAC5E,YAAM,eAAe,cAAc,IAAO,IAAI;AAC9C,UAAI,IAAI,SAAS,SAAS,aAAc,QAAO,EAAE,QAAQ,WAAW,MAAM;AAC1E,gBAAU;AACV,UAAI,UAAW;AAAA,IACjB;AACA,QAAI,UAAU;AACZ,UAAI,IAAI,SAAS,SAAS,EAAG,QAAO,EAAE,QAAQ,WAAW,MAAM;AAC/D,gBAAU;AAAA,IACZ;AACA,WAAO,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;AAClC,QAAI,OAAO,WAAW,UAAW,QAAO,EAAE,OAAO;AAAA,EACnD;AACA,SAAO,EAAE,OAAO;AAClB;AAOA,SAAS,WAAW,KAAK;AACvB,QAAM,OAAO,eAAe,KAAK,CAAC;AAClC,QAAM,QAAQ,KAAK,OAAO,CAAC;AAC3B,MAAI,CAAC,MAAO,OAAM,IAAI,MAAM,4FAAsB;AAClD,SAAO;AACT;AA0CO,SAAS,yBAAyB,KAAK,QAAQ;AACpD,QAAM,QAAQ,WAAW,GAAG;AAC5B,QAAM,OAAO,MAAM;AACnB,QAAM,SAAS,IAAI,SAAS,MAAM,OAAO,IAAI;AAC7C,QAAM,OAAO,KAAK,mBAAmB,MAAM,EAAE,SAAS,MAAM;AAC5D,QAAM,KAAK,KAAK,QAAQ,IAAI;AAC5B,QAAM,OAAO,MAAM,IAAI,KAAK,MAAM,GAAG,EAAE,IAAI;AAC3C,QAAM,MAAM,KAAK,MAAM,IAAI;AAC3B,MAAI,IAAI,SAAS,WAAW;AAC1B,UAAM,IAAI,MAAM,oHAAyC,IAAI,IAAI,QAAG;AAAA,EACtE;AACA,MAAI,MAAM;AACV,QAAM,YAAY,KAAK,iBAAiB,KAAK,UAAU,GAAG,IAAI,MAAM,aAAa;AACjF,QAAM,OAAO,IAAI,SAAS,IAAI;AAC9B,SAAO,OAAO,OAAO,CAAC,WAAW,IAAI,CAAC;AACxC;;;ACjIA,IAAM,eAAe;AAErB,SAAS,QAAQ,OAAO;AACtB,MAAI,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS,KAAK,KAAK,SAAS,EAAG,QAAO;AAC/E,MAAI;AAAE,WAAO,IAAI,KAAK,KAAK,EAAE,YAAY;AAAA,EAAE,QAAQ;AAAE,WAAO;AAAA,EAAK;AACnE;AAEA,SAAS,WAAW,OAAO;AACzB,SAAO,IAAI,OAAO,KAAK,EAAE,QAAQ,OAAO,MAAM,EAAE,QAAQ,MAAM,KAAK,EAAE,QAAQ,UAAU,KAAK,CAAC;AAC/F;AAEA,SAAS,SAAS,OAAO;AACvB,SAAO,MAAM,QAAQ,KAAK,IAAI,MAAM,OAAO,CAAC,MAAM,KAAK,OAAO,MAAM,QAAQ,IAAI,CAAC;AACnF;AAGA,SAAS,eAAe,QAAQ;AAC9B,QAAM,QAAQ,CAAC;AACf,aAAW,SAAS,QAAQ;AAC1B,QAAI,MAAM,SAAS,UAAU,OAAO,MAAM,SAAS,SAAU,OAAM,KAAK,MAAM,IAAI;AAAA,EACpF;AACA,SAAO,MAAM,KAAK,MAAM,EAAE,KAAK;AACjC;AAEA,SAAS,aAAa,QAAQ;AAC5B,MAAI,QAAQ;AACZ,aAAW,SAAS,OAAQ,KAAI,MAAM,SAAS,QAAS;AACxD,SAAO;AACT;AAEA,SAAS,oBAAoB,QAAQ;AACnC,QAAM,QAAQ,CAAC;AACf,aAAW,SAAS,QAAQ;AAC1B,QAAI,MAAM,SAAS,eAAe,OAAO,MAAM,SAAS,YAAY,MAAM,KAAK,KAAK,EAAG,OAAM,KAAK,MAAM,KAAK,KAAK,CAAC;AAAA,EACrH;AACA,SAAO,MAAM,KAAK,MAAM;AAC1B;AAGO,SAAS,uBAAuBC,OAAM,cAAc;AACzD,MAAI,SAAS;AACb,MAAI,OAAO,iBAAiB,UAAU;AACpC,QAAI;AAAE,eAAS,KAAK,MAAM,YAAY;AAAA,IAAE,QAAQ;AAAE,eAAS;AAAA,IAAK;AAAA,EAClE,WAAW,gBAAgB,OAAO,iBAAiB,UAAU;AAC3D,aAAS;AAAA,EACX;AACA,MAAI,WAAW,KAAM,QAAO,OAAO,iBAAiB,WAAW,aAAa,MAAM,GAAG,YAAY,IAAI;AACrG,MAAI,OAAO,WAAW,SAAU,QAAO,OAAO,MAAM,EAAE,MAAM,GAAG,YAAY;AAC3E,QAAM,YAAY,CAAC,WAAW,aAAa,QAAQ,SAAS,OAAO,SAAS;AAC5E,aAAW,OAAO,WAAW;AAC3B,QAAI,OAAO,OAAO,GAAG,MAAM,YAAY,OAAO,GAAG,EAAE,KAAK,EAAG,QAAO,OAAO,GAAG;AAAA,EAC9E;AACA,QAAM,OAAO,OAAO,KAAK,MAAM;AAC/B,MAAI,KAAK,WAAW,EAAG,QAAO;AAC9B,QAAM,OAAO,CAAC;AACd,aAAW,OAAO,KAAK,MAAM,GAAG,CAAC,GAAG;AAClC,UAAM,QAAQ,OAAO,GAAG;AACxB,SAAK,GAAG,IAAI,OAAO,UAAU,WAAW,QAAQ,KAAK,UAAU,KAAK;AAAA,EACtE;AACA,SAAO,KAAK,UAAU,IAAI,EAAE,MAAM,GAAG,YAAY;AACnD;AAKA,SAAS,mBAAmB,KAAK,QAAQ,SAAS;AAChD,QAAM,mBAAmB,QAAQ,qBAAqB;AACtD,QAAM,qBAAqB,QAAQ,uBAAuB;AAC1D,MAAI,QAAQ,OAAO,OAAO,UAAU,YAAY,OAAO,MAAM,KAAK,IAAI,OAAO,MAAM,KAAK,IAAI;AAC5F,MAAI,OAAO;AACX,SAAO;AAAA,IACL,IAAI,QAAQ;AAAE,aAAO;AAAA,IAAM;AAAA;AAAA,IAE3B,IAAI,QAAQ;AACV,YAAM,OAAO,MAAM,QAAQ,MAAM,IAAI,SAAS,CAAC;AAC/C,iBAAW,MAAM,MAAM;AACrB,YAAI,CAAC,MAAM,OAAO,OAAO,SAAU;AACnC,cAAM,OAAO,GAAG,QAAQ,OAAO,GAAG,SAAS,WAAW,GAAG,OAAO,CAAC;AACjE,cAAM,OAAO,GAAG;AAEhB,YAAI,SAAS,mBAAmB,QAAQ,OAAO,KAAK,UAAU,YAAY,KAAK,MAAM,KAAK,GAAG;AAC3F,kBAAQ,KAAK,MAAM,KAAK;AACxB;AAAA,QACF;AAEA,YAAI,SAAS,cAAc;AACzB,gBAAM,OAAO,OAAO,UAAU,KAAK,IAAI,IAAI,KAAK,OAAO;AACvD,cAAI,SAAS,QAAQ,SAAS,MAAM;AAClC,mBAAO;AACP,gBAAI,KAAK,IAAI,aAAQ,IAAI,SAAI;AAAA,UAC/B;AACA;AAAA,QACF;AAEA,YAAI,SAAS,gBAAgB;AAC3B,gBAAM,SAAS,SAAS,KAAK,OAAO;AACpC,gBAAM,OAAO,eAAe,MAAM;AAClC,gBAAM,SAAS,aAAa,MAAM;AAClC,cAAI,CAAC,QAAQ,WAAW,EAAG;AAC3B,cAAI,KAAK,IAAI,oBAAU,EAAE;AACzB,cAAI,KAAM,KAAI,KAAK,IAAI;AACvB,mBAAS,IAAI,GAAG,IAAI,QAAQ,IAAK,KAAI,KAAK,IAAI,kBAAQ,IAAI,CAAC,eAAe;AAC1E;AAAA,QACF;AAEA,YAAI,SAAS,qBAAqB;AAChC,gBAAM,UAAU,KAAK,WAAW,OAAO,KAAK,YAAY,WAAW,KAAK,UAAU,CAAC;AACnF,gBAAM,SAAS,SAAS,QAAQ,OAAO;AACvC,gBAAM,OAAO,eAAe,MAAM;AAClC,gBAAM,YAAY,mBAAmB,oBAAoB,MAAM,IAAI;AACnE,cAAI,CAAC,QAAQ,CAAC,UAAW;AACzB,cAAI,KAAK,IAAI,oBAAU,EAAE;AACzB,cAAI,UAAW,KAAI,KAAK,yBAAU,UAAU,MAAM,IAAI,EAAE,KAAK,MAAM,GAAG,EAAE;AACxE,cAAI,KAAM,KAAI,KAAK,IAAI;AACvB;AAAA,QACF;AAEA,YAAI,SAAS,aAAa;AACxB,gBAAMA,QAAO,OAAO,KAAK,SAAS,YAAY,KAAK,OAAO,KAAK,OAAO;AACtE,gBAAM,UAAU,uBAAuBA,OAAM,KAAK,SAAS;AAC3D,cAAI,KAAK,IAAI,uCAAcA,KAAI,MAAM,EAAE;AACvC,cAAI,KAAK,UAAU,UAAU,UAAU,UAAU,gCAAO;AACxD;AAAA,QACF;AAEA,YAAI,SAAS,iBAAiB,oBAAoB;AAChD,gBAAM,UAAU,KAAK,WAAW,OAAO,KAAK,YAAY,WAAW,KAAK,UAAU,CAAC;AACnF,gBAAM,SAAS,SAAS,QAAQ,OAAO;AACvC,cAAI,OAAO;AACX,qBAAW,SAAS,QAAQ;AAC1B,gBAAI,MAAM,SAAS,cAAe,QAAO,eAAe,SAAS,MAAM,OAAO,CAAC;AAAA,UACjF;AACA,cAAI,KAAM,KAAI,KAAK,IAAI,wDAAoC,IAAI,UAAU,KAAK,MAAM,GAAG,GAAI,IAAI,SAAS,IAAI,YAAY;AAAA,QAC1H;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAiDO,SAAS,6BAA6B,MAAM,UAAU,CAAC,GAAG;AAC/D,QAAM,SAAS,QAAQ,OAAO,SAAS,WAAW,OAAO,CAAC;AAC1D,QAAM,OAAO,CAAC;AACd,QAAM,OAAO,mBAAmB,MAAM,QAAQ,OAAO;AACrD,SAAO;AAAA,IACL,UAAU,QAAQ;AAAE,WAAK,IAAI,MAAM;AAAA,IAAE;AAAA,IACrC,OAAO,cAAc;AACnB,YAAM,YAAY,gBAAgB,OAAO,iBAAiB,WAAW,eAAe;AACpF,YAAM,QAAQ,KAAK;AACnB,YAAM,QAAQ,CAAC,KAAK;AACpB,UAAI,MAAO,OAAM,KAAK,UAAU,WAAW,KAAK,CAAC,EAAE;AACnD,UAAI,OAAO,UAAU,OAAO,YAAY,UAAU,GAAI,OAAM,KAAK,cAAc,WAAW,UAAU,EAAE,CAAC,EAAE;AACzG,UAAI,OAAO,UAAU,QAAQ,YAAY,UAAU,IAAK,OAAM,KAAK,QAAQ,WAAW,UAAU,GAAG,CAAC,EAAE;AACtG,YAAM,UAAU,QAAQ,UAAU,SAAS;AAC3C,UAAI,QAAS,OAAM,KAAK,cAAc,OAAO,EAAE;AAC/C,YAAM,WAAW,QAAQ,QAAQ,UAAU;AAC3C,UAAI,SAAU,OAAM,KAAK,eAAe,QAAQ,EAAE;AAClD,YAAM,KAAK,KAAK;AAChB,YAAM,MAAM,CAAC,MAAM,KAAK,IAAI,CAAC;AAC7B,UAAI,MAAO,KAAI,KAAK,IAAI,KAAK,KAAK,EAAE;AACpC,UAAI,KAAK,GAAG,MAAM,EAAE;AACpB,aAAO,IAAI,KAAK,IAAI;AAAA,IACtB;AAAA,EACF;AACF;;;AC1NA,SAAS,OAAO,QAAQ,iBAAiB;AACzC,SAAS,oBAAoB;AAC7B,SAAS,eAAe;AACxB,SAAS,YAAY;AAId,IAAM,sBAAsB;AAEnC,IAAM,mBAAmB,KAAK,QAAQ,GAAG,QAAQ,kBAAkB;AAEnE,SAAS,gBAAgB,OAAO;AAC9B,SAAO,OAAO,UAAU,YAAY,MAAM,SAAS,KAAK,MAAM,UAAU,OAAO,CAAC,UAAU,KAAK,KAAK,KAAK,UAAU,OAAO,UAAU;AACtI;AAMO,SAAS,mBAAmB,KAAK;AACtC,QAAM,SAAS,MAAM,QAAQ,GAAG,IAAI,MAAM;AAC1C,QAAM,SAAS,WAAW,OAAO,OAAO,QAAQ,WAAW,MAAM;AACjE,QAAM,MAAM,UAAU,MAAM,QAAQ,OAAO,iBAAiB,IAAI,OAAO,oBAAqB,UAAU,CAAC;AACvG,QAAM,QAAQ,CAAC;AACf,QAAM,OAAO,oBAAI,IAAI;AACrB,aAAW,MAAM,KAAK;AAGpB,QAAI,CAAC,gBAAgB,EAAE,EAAG;AAC1B,QAAI,KAAK,IAAI,EAAE,EAAG;AAClB,SAAK,IAAI,EAAE;AACX,UAAM,KAAK,EAAE;AAAA,EACf;AACA,SAAO,EAAE,eAAe,qBAAqB,mBAAmB,MAAM;AACxE;AAQO,SAAS,gBAAgB,UAAU,CAAC,GAAG;AAC5C,QAAM,MAAM,QAAQ,OAAO,QAAQ,IAAI,iCAAiC;AACxE,QAAM,YAAY,QAAQ,aAAa,KAAK,KAAK,WAAW;AAC5D,MAAI,WAAW,QAAQ,QAAQ;AAE/B,iBAAe,OAAO;AACpB,QAAI;AACF,aAAO,mBAAmB,KAAK,MAAM,aAAa,WAAW,MAAM,CAAC,CAAC;AAAA,IACvE,QAAQ;AACN,aAAO,mBAAmB,IAAI;AAAA,IAChC;AAAA,EACF;AAEA,iBAAe,MAAM,OAAO;AAC1B,UAAM,MAAM,KAAK,EAAE,WAAW,KAAK,CAAC;AACpC,UAAM,MAAM,KAAK,KAAK,SAAS,QAAQ,GAAG,IAAI,KAAK,IAAI,CAAC,MAAM;AAC9D,UAAM,UAAU,KAAK,KAAK,UAAU,mBAAmB,KAAK,GAAG,MAAM,CAAC,GAAG,EAAE,UAAU,QAAQ,MAAM,IAAM,CAAC;AAC1G,UAAM,OAAO,KAAK,SAAS;AAAA,EAC7B;AAIA,WAAS,OAAO,SAAS;AACvB,UAAM,YAAY,SAAS,KAAK,YAAY;AAC1C,YAAM,QAAQ,MAAM,KAAK;AACzB,YAAM,SAAS,MAAM,QAAQ,KAAK;AAClC,YAAM,MAAM,KAAK;AACjB,aAAO;AAAA,IACT,CAAC;AACD,eAAW,UAAU,MAAM,MAAM;AAAA,IAAC,CAAC;AACnC,WAAO;AAAA,EACT;AAQA,WAAS,WAAW,KAAK,SAAS;AAChC,UAAM,UAAU,MAAM,QAAQ,GAAG,IAAI,MAAM,CAAC,GAAG,OAAO,eAAe,EAAE,IAAI,MAAM;AACjF,WAAO,OAAO,CAAC,UAAU;AACvB,YAAM,MAAM,IAAI,IAAI,MAAM,iBAAiB;AAC3C,iBAAW,MAAM,QAAQ;AACvB,YAAI,QAAS,KAAI,IAAI,EAAE;AAAA,YAClB,KAAI,OAAO,EAAE;AAAA,MACpB;AACA,YAAM,oBAAoB,CAAC,GAAG,GAAG;AACjC,aAAO,MAAM;AAAA,IACf,CAAC;AAAA,EACH;AAIA,WAAS,UAAU,KAAK;AACtB,WAAO,WAAW,KAAK,KAAK;AAAA,EAC9B;AAEA,SAAO,EAAE,MAAM,OAAO,QAAQ,YAAY,WAAW,WAAW,IAAI;AACtE;;;ACjGO,IAAM,gBAAgB;AAE7B,SAAS,aAAa,OAAO;AAC3B,SAAO,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,KAAK,SAAS;AACzE;AAoBO,SAAS,iBAAiB,OAAO,UAAU,CAAC,GAAG;AACpD,QAAM,OAAO,OAAO,UAAU,QAAQ,IAAI,KAAK,QAAQ,OAAO,IAAI,QAAQ,OAAO;AACjF,QAAM,OAAO,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC;AAE7C,QAAM,UAAU,oBAAI,IAAI;AACxB,QAAM,QAAQ,CAAC;AACf,MAAI,aAAa;AACjB,MAAI,kBAAkB;AAItB,MAAI,UAAU;AAEd,aAAW,QAAQ,MAAM;AACvB,QAAI,CAAC,QAAQ,KAAK,aAAa,KAAM;AACrC;AACA,UAAM,KAAK,OAAO,KAAK,SAAS;AAChC,UAAM,OAAO,KAAK,gBAAgB,OAAO,KAAK,aAAa,IAAI;AAC/D,UAAM,MAAM,QAAQ;AAEpB,QAAI,SAAS,QAAQ,IAAI,GAAG;AAC5B,QAAI,CAAC,QAAQ;AACX,eAAS,EAAE,KAAK,MAAM,OAAO,KAAK,iBAAiB,OAAO,KAAK,cAAc,IAAI,MAAM,OAAO,GAAG,UAAU,EAAE;AAC7G,cAAQ,IAAI,KAAK,MAAM;AAAA,IACzB;AACA,WAAO;AAEP,QAAI,aAAa,KAAK,SAAS,GAAG;AAChC,aAAO,SAAS,KAAK;AACrB,oBAAc,KAAK;AACnB,YAAM,KAAK;AAAA,QACT,WAAW;AAAA,QACX,OAAO,KAAK,SAAS;AAAA,QACrB,eAAe;AAAA,QACf,gBAAgB,OAAO;AAAA,QACvB,WAAW,KAAK;AAAA,MAClB,CAAC;AAAA,IACH,OAAO;AACL;AAAA,IACF;AAAA,EACF;AAEA,QAAM,aAAa,CAAC,GAAG,QAAQ,OAAO,CAAC,EACpC,KAAK,CAAC,GAAG,MAAO,EAAE,QAAQ,EAAE,SAAW,EAAE,WAAW,EAAE,YAAa,EAAE,IAAI,cAAc,EAAE,GAAG,CAAC,EAC7F,IAAI,CAAC,YAAY,EAAE,GAAG,QAAQ,OAAO,aAAa,IAAI,OAAO,QAAQ,aAAa,EAAE,EAAE;AAEzF,QAAM,MAAM,MACT,KAAK,CAAC,GAAG,MAAO,EAAE,YAAY,EAAE,aAAc,EAAE,UAAU,cAAc,EAAE,SAAS,CAAC,EACpF,MAAM,GAAG,IAAI;AAEhB,SAAO;AAAA,IACL;AAAA,IACA,cAAc;AAAA,IACd,eAAe,MAAM;AAAA,IACrB;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACnFA,SAAS,SAAAC,QAAO,UAAAC,SAAQ,aAAAC,kBAAiB;AACzC,SAAS,gBAAAC,qBAAoB;AAC7B,SAAS,WAAAC,gBAAe;AACxB,SAAS,QAAAC,aAAY;AAId,IAAM,8BAA8B;AAIpC,IAAM,uBAAuB,OAAO,OAAO,CAAC,GAAG,IAAI,IAAI,EAAE,CAAC;AAEjE,IAAM,SAAS;AAGR,IAAM,kBAAkB;AAE/B,IAAM,cAAcA,MAAKD,SAAQ,GAAG,QAAQ,kBAAkB;AAKvD,SAAS,0BAA0B,KAAK;AAC7C,QAAM,SAAS,OAAO,OAAO,QAAQ,YAAY,CAAC,MAAM,QAAQ,GAAG,IAAI,MAAM,CAAC;AAC9E,QAAM,WAAW,OAAO,YAAY,OAAO,OAAO,aAAa,WAAW,OAAO,WAAW,CAAC;AAC7F,QAAM,eAAe,qBAAqB,SAAS,SAAS,YAAY,IAAI,SAAS,eAAe;AACpG,SAAO;AAAA,IACL,eAAe;AAAA,IACf,UAAU;AAAA,MACR;AAAA;AAAA;AAAA,MAGA,aAAa,SAAS,gBAAgB;AAAA,IACxC;AAAA,IACA,WAAW,OAAO,SAAS,OAAO,SAAS,IAAI,OAAO,YAAY;AAAA,IAClE,mBAAmB,OAAO,UAAU,OAAO,iBAAiB,KAAK,OAAO,qBAAqB,IAAI,OAAO,oBAAoB;AAAA,EAC9H;AACF;AAkBO,SAAS,uBAAuB,OAAO,UAAU,CAAC,GAAG;AAC1D,QAAM,OAAO,QAAQ;AACrB,MAAI,CAAC,qBAAqB,SAAS,IAAI,KAAK,SAAS,EAAG,QAAO,CAAC;AAChE,QAAM,MAAM,OAAO,SAAS,QAAQ,GAAG,IAAI,QAAQ,MAAM,KAAK,IAAI;AAClE,QAAM,SAAS,MAAM,OAAO;AAC5B,QAAM,cAAc,QAAQ,gBAAgB;AAC5C,QAAM,WAAW,QAAQ,mBAAmB,OAAO,OAAO,QAAQ,eAAe,IAAI;AACrF,QAAM,OAAO,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC;AAE7C,QAAM,MAAM,CAAC;AACb,QAAM,OAAO,oBAAI,IAAI;AACrB,aAAW,QAAQ,MAAM;AACvB,QAAI,CAAC,QAAQ,KAAK,aAAa,KAAM;AACrC,UAAM,KAAK,OAAO,KAAK,SAAS;AAChC,QAAI,KAAK,IAAI,EAAE,EAAG;AAClB,QAAI,KAAK,SAAU;AACnB,QAAI,eAAe,KAAK,QAAS;AACjC,QAAI,aAAa,QAAQ,OAAO,SAAU;AAC1C,UAAM,YAAY,OAAO,KAAK,SAAS;AAEvC,QAAI,CAAC,OAAO,SAAS,SAAS,KAAK,aAAa,EAAG;AACnD,QAAI,YAAY,QAAQ;AAAE,WAAK,IAAI,EAAE;AAAG,UAAI,KAAK,EAAE;AAAA,IAAE;AAAA,EACvD;AACA,SAAO;AACT;AAQO,SAAS,uBAAuB,UAAU,CAAC,GAAG;AACnD,QAAM,MAAM,QAAQ,OAAO,QAAQ,IAAI,yCAAyC;AAChF,QAAM,YAAY,QAAQ,aAAaC,MAAK,KAAK,mBAAmB;AACpE,MAAI,WAAW,QAAQ,QAAQ;AAE/B,iBAAe,OAAO;AACpB,QAAI;AACF,aAAO,0BAA0B,KAAK,MAAMF,cAAa,WAAW,MAAM,CAAC,CAAC;AAAA,IAC9E,QAAQ;AACN,aAAO,0BAA0B,IAAI;AAAA,IACvC;AAAA,EACF;AAEA,iBAAe,MAAM,OAAO;AAC1B,UAAMH,OAAM,KAAK,EAAE,WAAW,KAAK,CAAC;AACpC,UAAM,MAAMK,MAAK,KAAK,iBAAiB,QAAQ,GAAG,IAAI,KAAK,IAAI,CAAC,MAAM;AACtE,UAAMH,WAAU,KAAK,KAAK,UAAU,0BAA0B,KAAK,GAAG,MAAM,CAAC,GAAG,EAAE,UAAU,QAAQ,MAAM,IAAM,CAAC;AACjH,UAAMD,QAAO,KAAK,SAAS;AAAA,EAC7B;AAEA,WAAS,OAAO,SAAS;AACvB,UAAM,YAAY,SAAS,KAAK,YAAY;AAC1C,YAAM,QAAQ,MAAM,KAAK;AACzB,YAAM,SAAS,MAAM,QAAQ,KAAK;AAClC,YAAM,MAAM,KAAK;AACjB,aAAO;AAAA,IACT,CAAC;AACD,eAAW,UAAU,MAAM,MAAM;AAAA,IAAC,CAAC;AACnC,WAAO;AAAA,EACT;AAOA,WAAS,OAAO,QAAQ,CAAC,GAAG;AAC1B,WAAO,OAAO,CAAC,UAAU;AACvB,UAAI,OAAO,UAAU,eAAe,KAAK,OAAO,cAAc,GAAG;AAC/D,cAAM,OAAO,OAAO,MAAM,YAAY;AACtC,YAAI,CAAC,qBAAqB,SAAS,IAAI,GAAG;AACxC,gBAAM,QAAQ,IAAI,MAAM,mCAAoB,qBAAqB,KAAK,QAAG,CAAC,EAAE;AAC5E,gBAAM,SAAS;AACf,gBAAM;AAAA,QACR;AACA,cAAM,SAAS,eAAe;AAAA,MAChC;AACA,UAAI,OAAO,UAAU,eAAe,KAAK,OAAO,aAAa,GAAG;AAC9D,cAAM,SAAS,cAAc,CAAC,CAAC,MAAM;AAAA,MACvC;AACA,aAAO,MAAM;AAAA,IACf,CAAC;AAAA,EACH;AAGA,WAAS,UAAU,OAAO,KAAK,KAAK,IAAI,GAAG;AACzC,WAAO,OAAO,CAAC,UAAU;AACvB,YAAM,YAAY;AAClB,YAAM,oBAAoB,OAAO,UAAU,KAAK,KAAK,SAAS,IAAI,QAAQ;AAC1E,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAGA,WAASK,SAAQ,OAAO,MAAM,KAAK,IAAI,GAAG;AACxC,WAAO,OAAO,SAAS,SAAS,MAAM,SAAS,KAAM,MAAM,MAAM,YAAa;AAAA,EAChF;AAEA,SAAO,EAAE,MAAM,OAAO,QAAQ,QAAQ,WAAW,SAAAA,UAAS,WAAW,IAAI;AAC3E;;;ACvIA,IAAM,iBAAiB,IAAI,KAAK;AAChC,IAAM,cAAc;AAEpB,IAAM,kBAAkB;AAKjB,SAAS,cAAcC,OAAM;AAClC,MAAI,CAACA,SAAQ,OAAOA,UAAS,SAAU,QAAO;AAG9C,MAAI,OAAOA,MAAK,aAAa,YAAYA,MAAK,SAAS,SAAS,GAAG;AACjE,WAAO,kBAAkBA,MAAK;AAAA,EAChC;AACA,QAAM,UAAUA,MAAK;AACrB,QAAM,OAAOA,MAAK;AAClB,MAAI,OAAO,YAAY,YAAY,CAAC,OAAO,SAAS,OAAO,KAAK,WAAW,EAAG,QAAO;AACrF,MAAI,OAAO,SAAS,YAAY,CAAC,OAAO,SAAS,IAAI,KAAK,OAAO,EAAG,QAAO;AAC3E,SAAO,GAAG,KAAK,MAAM,OAAO,CAAC,IAAI,IAAI;AACvC;AAIO,SAAS,yBAAyB,aAAa;AACpD,SAAO,OAAO,gBAAgB,YAAY,gBAAgB,MAAM,CAAC,YAAY,WAAW,eAAe;AACzG;AAIO,SAAS,QAAQ,OAAOA,OAAM,KAAK,QAAQ,gBAAgB;AAChE,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,KAAK,cAAcA,KAAI;AAC7B,MAAI,CAAC,GAAI,QAAO;AAChB,MAAI,MAAM,gBAAgB,GAAI,QAAO;AACrC,MAAI,OAAO,MAAM,OAAO,SAAU,QAAO;AAEzC,MAAI,GAAG,WAAW,eAAe,EAAG,QAAO;AAC3C,SAAQ,MAAM,MAAM,MAAO;AAC7B;AAIO,SAAS,iBAAiB,KAAK,WAAW,OAAO,MAAM,KAAK,IAAI,GAAG,QAAQ,gBAAgB;AAChG,QAAM,SAAS,oBAAI,IAAI;AACvB,QAAM,UAAU,CAAC;AACjB,aAAW,MAAM,KAAK;AACpB,UAAM,QAAQ,SAAS,MAAM,IAAI,OAAO,EAAE,CAAC;AAC3C,UAAMA,QAAO,aAAa,UAAU,IAAI,OAAO,EAAE,CAAC;AAClD,QAAI,QAAQ,OAAOA,OAAM,KAAK,KAAK,KAAK,SAAS,MAAM,MAAM;AAC3D,aAAO,IAAI,OAAO,EAAE,GAAG,MAAM,IAAI;AAAA,IACnC,OAAO;AACL,cAAQ,KAAK,OAAO,EAAE,CAAC;AAAA,IACzB;AAAA,EACF;AACA,SAAO,EAAE,QAAQ,QAAQ;AAC3B;AAEO,SAAS,uBAAuB,OAAO,CAAC,GAAG;AAChD,QAAM,QAAQ,OAAO,SAAS,KAAK,KAAK,IAAI,KAAK,QAAQ;AACzD,QAAM,MAAM,OAAO,UAAU,KAAK,GAAG,KAAK,KAAK,MAAM,IAAI,KAAK,MAAM;AACpE,QAAM,MAAM,oBAAI,IAAI;AACpB,MAAI,OAAO;AACX,MAAI,SAAS;AAEb,SAAO;AAAA;AAAA,IAEL,IAAI,IAAIA,OAAM;AACZ,YAAM,MAAM,OAAO,EAAE;AACrB,YAAM,QAAQ,IAAI,IAAI,GAAG;AACzB,UAAI,QAAQ,OAAOA,OAAM,KAAK,IAAI,GAAG,KAAK,GAAG;AAC3C;AAEA,YAAI,OAAO,GAAG;AACd,YAAI,IAAI,KAAK,KAAK;AAClB,eAAO,MAAM;AAAA,MACf;AACA;AACA,aAAO;AAAA,IACT;AAAA,IACA,IAAI,IAAIA,OAAM,MAAM;AAClB,UAAI,CAAC,KAAM,QAAO;AAClB,YAAM,KAAK,cAAcA,KAAI;AAG7B,UAAI,CAAC,GAAI,QAAO;AAChB,YAAM,MAAM,OAAO,EAAE;AACrB,UAAI,OAAO,GAAG;AACd,UAAI,IAAI,KAAK,EAAE,aAAa,IAAI,IAAI,KAAK,IAAI,GAAG,KAAK,CAAC;AACtD,UAAI,IAAI,OAAO,KAAK;AAElB,cAAM,SAAS,IAAI,KAAK,EAAE,KAAK,EAAE;AACjC,YAAI,WAAW,OAAW,KAAI,OAAO,MAAM;AAAA,MAC7C;AACA,aAAO;AAAA,IACT;AAAA;AAAA,IAEA,UAAU,KAAK,WAAW;AACxB,aAAO,iBAAiB,KAAK,WAAW,KAAK,KAAK,IAAI,GAAG,KAAK;AAAA,IAChE;AAAA,IACA,WAAW,IAAI;AACb,UAAI,MAAM,KAAM,QAAO;AACvB,YAAM,MAAM,OAAO,EAAE;AACrB,YAAM,MAAM,IAAI,IAAI,GAAG;AACvB,UAAI,OAAO,GAAG;AACd,aAAO;AAAA,IACT;AAAA,IACA,QAAQ;AAAE,UAAI,MAAM;AAAA,IAAE;AAAA,IACtB,IAAI,OAAO;AAAE,aAAO,IAAI;AAAA,IAAK;AAAA,IAC7B,QAAQ;AAAE,aAAO,EAAE,MAAM,IAAI,MAAM,MAAM,QAAQ,MAAM;AAAA,IAAE;AAAA,EAC3D;AACF;;;AC5HA,SAAS,SAAAC,QAAO,UAAU,UAAAC,SAAQ,aAAAC,kBAAiB;AACnD,SAAS,SAAS,QAAAC,aAAY;AAEvB,IAAM,6BAA6B;AAE1C,IAAM,cAAc;AAQb,SAAS,eAAe,KAAK;AAClC,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO;AAC5C,QAAM,QAAQ,OAAO,IAAI,UAAU,WAAW,IAAI,QAAQ;AAC1D,QAAM,MAAM,OAAO,IAAI,QAAQ,WAAW,IAAI,MAAM;AACpD,QAAM,YAAY,OAAO,IAAI,cAAc,WAAW,IAAI,YAAY;AACtE,QAAM,cAAc,OAAO,IAAI,gBAAgB,YAAY,IAAI,cAAc,IAAI,cAAc;AAC/F,QAAM,YAAY,OAAO,IAAI,cAAc,WAAW,IAAI,YAAY;AACtE,MAAI,CAAC,eAAe,YAAY,WAAW,MAAM,EAAG,QAAO;AAC3D,MAAI,CAAC,SAAS,CAAC,IAAK,QAAO;AAC3B,SAAO,EAAE,OAAO,KAAK,WAAW,aAAa,UAAU;AACzD;AAEO,SAAS,oBAAoB,KAAK;AACvC,QAAM,UAAU,CAAC;AACjB,MAAI,OAAO,OAAO,QAAQ,YAAY,IAAI,WAAW,OAAO,IAAI,YAAY,UAAU;AACpF,eAAW,CAAC,IAAI,KAAK,KAAK,OAAO,QAAQ,IAAI,OAAO,GAAG;AACrD,UAAI,OAAO,OAAO,YAAY,CAAC,MAAM,GAAG,SAAS,IAAK;AACtD,YAAM,aAAa,eAAe,KAAK;AACvC,UAAI,WAAY,SAAQ,EAAE,IAAI;AAAA,IAChC;AAAA,EACF;AACA,SAAO,EAAE,eAAe,4BAA4B,QAAQ;AAC9D;AAGO,SAAS,aAAa,MAAM,OAAO;AACxC,QAAM,SAAS,EAAE,GAAG,KAAK;AACzB,aAAW,CAAC,IAAI,KAAK,KAAK,OAAO,QAAQ,KAAK,EAAG,QAAO,EAAE,IAAI;AAC9D,QAAM,MAAM,OAAO,KAAK,MAAM;AAC9B,MAAI,IAAI,SAAS,aAAa;AAC5B,QAAI,KAAK,CAAC,GAAG,OAAO,OAAO,CAAC,EAAE,aAAa,MAAM,OAAO,CAAC,EAAE,aAAa,EAAE;AAC1E,eAAW,MAAM,IAAI,MAAM,GAAG,IAAI,SAAS,WAAW,EAAG,QAAO,OAAO,EAAE;AAAA,EAC3E;AACA,SAAO;AACT;AAEO,SAAS,sBAAsB,EAAE,KAAK,KAAK,GAAG;AACnD,MAAI,QAAQ;AACZ,MAAI,QAAQ,QAAQ,QAAQ;AAC5B,QAAM,OAAO,QAAQA,MAAK,KAAK,kBAAkB;AAEjD,iBAAe,UAAU;AACvB,QAAI;AACF,aAAO,oBAAoB,KAAK,MAAM,MAAM,SAAS,MAAM,MAAM,CAAC,CAAC;AAAA,IACrE,SAAS,GAAG;AACV,aAAO,oBAAoB,IAAI;AAAA,IACjC;AAAA,EACF;AAGA,WAAS,QAAQ,SAAS;AACxB,UAAM,YAAY,MAAM,KAAK,YAAY;AACvC,YAAM,QAAQ,UAAU,SAAS,MAAM,QAAQ,GAAG;AAClD,YAAM,QAAQ,KAAK;AACnB,aAAO;AAAA,IACT,CAAC;AACD,YAAQ,UAAU,MAAM,MAAM;AAAA,IAAC,CAAC;AAChC,WAAO;AAAA,EACT;AAEA,SAAO;AAAA;AAAA,IAEL,MAAM,UAAU;AACd,UAAI,MAAO,QAAO;AAClB,eAAS,MAAM,QAAQ,GAAG;AAC1B,aAAO;AAAA,IACT;AAAA;AAAA,IAEA,MAAM,MAAM,OAAO;AACjB,YAAM,QAAQ,CAAC;AACf,iBAAW,CAAC,IAAI,KAAK,KAAK,OAAO,QAAQ,SAAS,CAAC,CAAC,GAAG;AACrD,cAAM,aAAa,eAAe,KAAK;AACvC,YAAI,WAAY,OAAM,OAAO,EAAE,CAAC,IAAI;AAAA,MACtC;AACA,UAAI,CAAC,OAAO,KAAK,KAAK,EAAE,OAAQ,QAAO;AACvC,YAAM,QAAQ,OAAO,UAAU;AAC7B,cAAM,OAAO,aAAa,OAAO,KAAK;AACtC,cAAMH,OAAM,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAC9C,cAAM,MAAMG,MAAK,QAAQ,IAAI,GAAG,gBAAgB,QAAQ,GAAG,IAAI,KAAK,IAAI,CAAC,MAAM;AAC/E,cAAMD,WAAU,KAAK,KAAK,UAAU,EAAE,eAAe,4BAA4B,SAAS,KAAK,CAAC,GAAG,EAAE,UAAU,QAAQ,MAAM,IAAM,CAAC;AACpI,cAAMD,QAAO,KAAK,IAAI;AACtB,gBAAQ;AAAA,MACV,CAAC;AACD,aAAO;AAAA,IACT;AAAA,IACA,MAAM,OAAO,KAAK;AAChB,YAAM,SAAS,IAAI,KAAK,OAAO,CAAC,GAAG,IAAI,MAAM,CAAC;AAC9C,UAAI,CAAC,OAAO,KAAM,QAAO;AACzB,YAAM,QAAQ,OAAO,UAAU;AAC7B,YAAI,UAAU;AACd,mBAAW,MAAM,QAAQ;AACvB,cAAI,MAAM,OAAO;AAAE,mBAAO,MAAM,EAAE;AAAG,sBAAU;AAAA,UAAK;AAAA,QACtD;AACA,YAAI,CAAC,QAAS;AACd,cAAMD,OAAM,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAC9C,cAAM,MAAMG,MAAK,QAAQ,IAAI,GAAG,gBAAgB,QAAQ,GAAG,IAAI,KAAK,IAAI,CAAC,MAAM;AAC/E,cAAMD,WAAU,KAAK,KAAK,UAAU,EAAE,eAAe,4BAA4B,SAAS,MAAM,CAAC,GAAG,EAAE,UAAU,QAAQ,MAAM,IAAM,CAAC;AACrI,cAAMD,QAAO,KAAK,IAAI;AAAA,MACxB,CAAC;AACD,aAAO;AAAA,IACT;AAAA,EACF;AACF;;;AC9GA,SAAS,SAAS,YAAY;AAC9B,SAAS,UAAU,QAAAG,aAAY;;;ACZ/B,SAAS,cAAc,QAAQ;AAC7B,SAAO,OAAO,MAAM,EACjB,QAAQ,WAAW,EAAE,EACrB,MAAM,OAAO,EACb,OAAO,CAAC,QAAQ,IAAI,SAAS,CAAC;AACnC;AAKA,SAAS,iBAAiB,UAAU;AAClC,SAAO,SAAS,SAAS,KAAK,cAAc,KAAK,SAAS,CAAC,CAAC,IAAI,SAAS,MAAM,CAAC,IAAI;AACtF;AAQO,SAAS,gBAAgB,QAAQ,KAAK;AAC3C,MAAI,OAAO,WAAW,YAAY,OAAO,WAAW,EAAG,QAAO;AAC9D,MAAI,OAAO,QAAQ,YAAY,IAAI,WAAW,EAAG,QAAO;AACxD,QAAM,WAAW,iBAAiB,cAAc,MAAM,CAAC;AACvD,MAAI,SAAS,WAAW,EAAG,QAAO;AAClC,QAAM,OAAO,SAAS,SAAS,SAAS,CAAC;AAEzC,MAAI,SAAS,UAAU,KAAK,SAAS,SAAS,SAAS,CAAC,MAAM,IAAK,QAAO;AAK1E,MAAI,KAAK,SAAS,GAAG,GAAG;AACtB,UAAM,UAAU;AAChB,QAAI,OAAO;AACX,WAAO,MAAM;AACX,YAAM,KAAK,KAAK,QAAQ,KAAK,IAAI;AACjC,UAAI,KAAK,EAAG,QAAO;AACnB,YAAM,SAAS,KAAK,IAAI,KAAK,KAAK,CAAC,IAAI;AACvC,YAAM,QAAQ,KAAK,IAAI,SAAS,KAAK,SAAS,KAAK,KAAK,IAAI,MAAM,IAAI;AACtE,UAAI,EAAE,UAAU,QAAQ,KAAK,MAAM,MAAM,EAAE,SAAS,QAAQ,KAAK,KAAK,GAAI,QAAO;AACjF,aAAO,KAAK;AAAA,IACd;AAAA,EACF;AACA,SAAO;AACT;;;AD9BA,IAAM,oBAAoB;AAE1B,SAAS,WAAW,IAAI;AACtB,SAAO,OAAO,OAAO,mBAAmB,KAAK,EAAE;AACjD;AAEO,SAAS,cAAc,KAAK;AACjC,QAAM,IAAI,OAAO,GAAG;AACpB,MAAI,EAAE,WAAW,EAAG,OAAM,IAAI,MAAM,qCAAqC;AACzE,MAAI,WAAW;AACf,MAAI,eAAe;AACnB,WAAS,IAAI,GAAG,IAAI,EAAE,QAAQ,KAAK;AACjC,UAAM,KAAK,EAAE,CAAC;AACd,QAAI,OAAO,OAAO,OAAO,QAAQ,OAAO,KAAK;AAC3C,UAAI,CAAC,aAAc,aAAY;AAC/B,qBAAe;AAAA,IACjB,WAAW,WAAW,EAAE,GAAG;AACzB,kBAAY;AACZ,qBAAe;AAAA,IACjB,OAAO;AACL,kBAAY,MAAM,EAAE,WAAW,CAAC,EAAE,SAAS,EAAE,EAAE,YAAY,EAAE,SAAS,GAAG,GAAG;AAC5E,qBAAe;AAAA,IACjB;AAAA,EACF;AACA,SAAO,QAAS,SAAS,QAAQ,OAAO,EAAE,KAAK,QAAQ,MAAM,GAAG,GAAG,IAAK;AAC1E;AAEO,SAAS,iBAAiB,KAAK;AACpC,QAAM,IAAI,OAAO,GAAG;AACpB,MAAI,EAAE,WAAW,EAAG,OAAM,IAAI,MAAM,qCAAqC;AACzE,MAAI,MAAM,IAAK,QAAO;AACtB,MAAI,MAAM,KAAM,QAAO;AACvB,MAAI,MAAM;AACV,WAAS,IAAI,GAAG,IAAI,EAAE,QAAQ,KAAK;AACjC,UAAM,KAAK,EAAE,CAAC;AACd,WAAO,WAAW,EAAE,IAAI,KAAK,MAAM,EAAE,WAAW,CAAC,EAAE,SAAS,EAAE,EAAE,YAAY,EAAE,SAAS,GAAG,GAAG;AAAA,EAC/F;AACA,SAAO;AACT;AAGO,SAAS,mBAAmB,IAAI;AACrC,QAAM,OAAO,MAAM,OAAO,OAAO,WAAW,GAAG,OAAO;AACtD,SAAO,OAAO,SAAS,YAAY,KAAK,SAAS,IAAI,OAAO;AAC9D;AAEO,SAAS,iBAAiB,MAAM,KAAK,IAAI;AAC9C,QAAM,UAAU,QAAQ,UAAa,QAAQ,QAAQ,QAAQ,KACzDC,MAAK,MAAM,SAAS,IACpBA,MAAK,MAAM,cAAc,GAAG,CAAC;AACjC,SAAOA,MAAK,SAAS,iBAAiB,EAAE,CAAC;AAC3C;AAUA,eAAsB,uBAAuB,IAAI,QAAQ;AACvD,QAAM,OAAO,mBAAmB,EAAE;AAClC,MAAI,CAAC,QAAQ,CAAC,UAAU,OAAO,MAAM,KAAM,QAAO;AAClD,QAAM,MAAM,OAAO,OAAO,EAAE;AAC5B,MAAI;AACJ,MAAI;AACF,iBAAa,iBAAiB,MAAM,OAAO,KAAK,GAAG;AAAA,EACrD,SAAS,GAAG;AACV,WAAO;AAAA,EACT;AACA,MAAI,SAAS,UAAU,MAAM,iBAAiB,GAAG,EAAG,QAAO;AAC3D,MAAI;AACJ,MAAI;AACF,UAAM,KAAK,MAAM,KAAK,UAAU;AAChC,QAAI,CAAC,GAAG,YAAY,EAAG,QAAO;AAC9B,cAAU,MAAM,QAAQ,UAAU;AAAA,EACpC,SAAS,GAAG;AACV,WAAO;AAAA,EACT;AACA,QAAM,kBAAkB,QAAQ,OAAO,CAACC,UAAS,kBAAkB,KAAKA,KAAI,CAAC;AAC7E,MAAI,gBAAgB,WAAW,EAAG,QAAO;AAEzC,kBAAgB,KAAK,CAAC,GAAG,MAAM;AAC7B,UAAM,KAAK,QAAQ,EAAE,MAAM,oBAAoB,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC;AAC/D,UAAM,KAAK,QAAQ,EAAE,MAAM,oBAAoB,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC;AAC/D,WAAO,KAAK;AAAA,EACd,CAAC;AACD,QAAM,UAAUC,MAAK,YAAY,gBAAgB,CAAC,CAAC;AACnD,MAAI,CAAC,gBAAgB,SAAS,GAAG,EAAG,QAAO;AAC3C,SAAO;AAAA,IACL;AAAA,IACA,YAAYA,MAAK,MAAM,OAAO,QAAQ,UAAa,OAAO,QAAQ,QAAQ,OAAO,QAAQ,KAAK,YAAY,cAAc,OAAO,GAAG,CAAC;AAAA,IACnI;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AE5GA,IAAM,gBAAgB;AAEtB,IAAM,aAAa;AAEnB,SAAS,oBAAoB,QAAQ;AACnC,MAAI,MAAM,QAAQ,MAAM,EAAG,QAAO;AAClC,MAAI,UAAU,OAAO,OAAO,OAAO,QAAQ,MAAM,WAAY,QAAO,CAAC,GAAG,MAAM;AAC9E,SAAO,CAAC;AACV;AAEA,eAAe,aAAa,QAAQ;AAClC,MAAI;AAAE,QAAI,UAAU,OAAO,OAAO,UAAU,WAAY,OAAM,OAAO,MAAM;AAAA,EAAE,SAAS,GAAG;AAAA,EAA2B;AACtH;AAEA,SAAS,SAAS,OAAO;AACvB,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,QAAM,YAAY,MAAM,UAAU,OAAO,MAAM,WAAW,WAAW,MAAM,SAAS;AACpF,SAAO,UAAU,MAAM,OAAO,OAAO;AACvC;AAEO,SAAS,0BAA0B,OAAO;AAC/C,QAAM,SAAS,SAAS,KAAK;AAC7B,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,WAAW,SAAS,MAAM,WAAW,SAAS,QAAQ;AAC5D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,IAAI,OAAO,OAAO,EAAE;AAAA,IACpB,WAAW,YAAY,OAAO,SAAS,SAAS,SAAS,IAAI,OAAO,SAAS,SAAS,IAAI;AAAA,IAC1F,YAAY,YAAY,OAAO,cAAc,SAAS,UAAU,IAAI,SAAS,aAAa;AAAA,IAC1F,UAAU,YAAY,OAAO,SAAS,aAAa,YAAY,SAAS,WAAW,SAAS,WAAW;AAAA,EACzG;AACF;AAEO,SAAS,yBAAyB,QAAQ;AAC/C,MAAI,CAAC,MAAM,QAAQ,MAAM,EAAG,QAAO,CAAC;AACpC,SAAO,OAAO,IAAI,yBAAyB,EAAE,OAAO,OAAO;AAC7D;AAEO,SAAS,yBAAyB,SAAS;AAChD,MAAI,CAAC,WAAW,OAAO,QAAQ,SAAS,WAAY,OAAM,IAAI,UAAU,qCAAqC;AAE7G,QAAM,UAAU,OAAO,QAAQ,SAAS;AACxC,QAAM,OAAO,OAAO,QAAQ,SAAS,aAAa,mBAAmB;AAErE,iBAAe,YAAY,SAAS;AAClC,WAAO,yBAAyB,MAAM,QAAQ,KAAK,OAAO,CAAC;AAAA,EAC7D;AAMA,iBAAe,YAAY,IAAI;AAC7B,QAAI,CAAC,QAAS,QAAO;AACrB,UAAM,WAAW,MAAM,QAAQ,KAAK,EAAE;AACtC,WAAO,WAAW,0BAA0B,QAAQ,IAAI;AAAA,EAC1D;AAKA,iBAAe,UAAU,QAAQ,QAAQ,QAAQ,QAAQ;AACvD,QAAI,UAAU,OAAO,SAAS;AAC5B,YAAM,QAAQ,IAAI,MAAM,4CAAS;AACjC,YAAM,OAAO;AACb,YAAM;AAAA,IACR;AACA,UAAM,SAAS,MAAM,OAAO,KAAK,QAAQ,QAAQ,SAAS,EAAE,OAAO,IAAI,MAAS;AAChF,WAAO,oBAAoB,MAAM;AAAA,EACnC;AAKA,iBAAe,WAAW,IAAI,EAAE,SAAS,GAAG,YAAY,eAAe,QAAQ,SAAS,GAAG;AACzF,QAAI,OAAO,QAAQ,SAAS,WAAY,OAAM,IAAI,MAAM,2FAAqB;AAC7E,UAAM,SAAS,MAAM,QAAQ,KAAK,IAAI,MAAM;AAC5C,QAAI,CAAC,UAAU,OAAO,OAAO,SAAS,cAAc,OAAO,OAAO,UAAU,YAAY;AACtF,YAAM,aAAa,MAAM;AACzB,YAAM,IAAI,MAAM,wDAA0B;AAAA,IAC5C;AACA,QAAI,SAAS,OAAO,cAAc,MAAM,KAAK,UAAU,IAAI,SAAS;AACpE,QAAI,QAAQ;AACZ,QAAI;AACF,eAAS,QAAQ,GAAG,QAAQ,YAAY,SAAS;AAC/C,cAAM,SAAS,MAAM,UAAU,QAAQ,QAAQ,WAAW,MAAM;AAChE,YAAI,OAAO,WAAW,EAAG;AACzB,kBAAU,OAAO;AACjB,iBAAS,OAAO;AAChB,YAAI,SAAU,OAAM,SAAS,QAAQ,EAAE,QAAQ,SAAS,OAAO,QAAQ,MAAM,CAAC;AAC9E,YAAI,OAAO,SAAS,UAAW;AAAA,MACjC;AAAA,IACF,UAAE;AACA,YAAM,aAAa,MAAM;AAAA,IAC3B;AACA,WAAO;AAAA,MACL,MAAM,OAAO,UAAU,OAAO,QAAQ;AAAA,MACtC,qBAAqB,OAAO,cAAc,OAAO,mBAAmB,IAAI,OAAO,sBAAsB;AAAA,MACrG,YAAY;AAAA,IACd;AAAA,EACF;AAOA,iBAAe,eAAe,IAAI,OAAO,CAAC,GAAG;AAC3C,UAAM,YAAY,OAAO,cAAc,KAAK,SAAS,KAAK,KAAK,YAAY,IAAI,KAAK,YAAY;AAChG,QAAI,OAAO,QAAQ,SAAS,YAAY;AAEtC,UAAI,KAAK,UAAU,KAAK,OAAO,SAAS;AACtC,cAAM,QAAQ,IAAI,MAAM,4CAAS;AACjC,cAAM,OAAO;AACb,cAAM;AAAA,MACR;AACA,aAAO,WAAW,IAAI,EAAE,QAAQ,KAAK,UAAU,GAAG,WAAW,QAAQ,KAAK,QAAQ,UAAU,KAAK,SAAS,CAAC;AAAA,IAC7G;AACA,QAAI,OAAO,QAAQ,aAAa,WAAY,OAAM,IAAI,MAAM,2FAAqB;AACjF,QAAI,KAAK,UAAU,KAAK,OAAO,SAAS;AACtC,YAAM,QAAQ,IAAI,MAAM,4CAAS;AACjC,YAAM,OAAO;AACb,YAAM;AAAA,IACR;AACA,UAAM,SAAS,MAAM,QAAQ,SAAS,IAAI,KAAK,UAAU,CAAC;AAC1D,UAAM,SAAS,oBAAoB,UAAU,OAAO,MAAM;AAC1D,QAAI,KAAK,YAAY,OAAO,OAAQ,OAAM,KAAK,SAAS,QAAQ,EAAE,QAAQ,KAAK,UAAU,GAAG,OAAO,OAAO,OAAO,CAAC;AAClH,WAAO;AAAA,MACL,MAAM,UAAU,OAAO,OAAO,OAAO,OAAO;AAAA,MAC5C,qBAAqB,UAAU,OAAO,cAAc,OAAO,mBAAmB,IAAI,OAAO,sBAAsB;AAAA,MAC/G,YAAY,OAAO;AAAA,IACrB;AAAA,EACF;AAIA,iBAAe,YAAY,IAAI,SAAS,GAAG;AACzC,QAAI,OAAO,QAAQ,aAAa,YAAY;AAC1C,YAAM,SAAS,MAAM,QAAQ,SAAS,IAAI,MAAM;AAChD,aAAO;AAAA,QACL,MAAM,UAAU,OAAO,OAAO,OAAO,OAAO;AAAA,QAC5C,qBAAqB,UAAU,OAAO,cAAc,OAAO,mBAAmB,IAAI,OAAO,sBAAsB;AAAA,QAC/G,QAAQ,UAAU,MAAM,QAAQ,OAAO,MAAM,IAAI,OAAO,SAAS,CAAC;AAAA,MACpE;AAAA,IACF;AACA,UAAM,SAAS,CAAC;AAChB,UAAM,UAAU,MAAM,WAAW,IAAI,EAAE,QAAQ,UAAU,CAAC,UAAU;AAAE,aAAO,KAAK,GAAG,KAAK;AAAA,IAAE,EAAE,CAAC;AAC/F,WAAO;AAAA,MACL,MAAM,QAAQ;AAAA,MACd,qBAAqB,QAAQ;AAAA,MAC7B;AAAA,IACF;AAAA,EACF;AAEA,WAAS,OAAO,QAAQ;AACtB,QAAI,OAAO,QAAQ,WAAW,WAAY,QAAO,QAAQ,OAAO,MAAM;AACtE,WAAO;AAAA,EACT;AAKA,iBAAe,eAAe,QAAQ;AACpC,QAAI,OAAO,QAAQ,WAAW,YAAY;AACxC,UAAI;AACF,cAAM,MAAM,QAAQ,OAAO,MAAM;AACjC,YAAI,OAAO,OAAO,IAAI,SAAS,SAAU,QAAO,EAAE,MAAM,IAAI,MAAM,YAAY,KAAK;AAAA,MACrF,SAAS,GAAG;AAAA,MAAa;AAAA,IAC3B;AACA,UAAM,YAAY,MAAM,uBAAuB,SAAS,MAAM;AAC9D,WAAO,YAAY,EAAE,MAAM,UAAU,SAAS,YAAY,UAAU,WAAW,IAAI;AAAA,EACrF;AAEA,SAAO,EAAE,MAAM,aAAa,aAAa,gBAAgB,aAAa,QAAQ,gBAAgB,QAAQ;AACxG;;;ACtKA,SAAS,OAAO,WAAW,SAAS,MAAM;AACxC,SAAO,EAAE,WAAW,CAAC,CAAC,WAAW,QAAQ,YAAY,OAAO,OAAO;AACrE;AAEO,SAAS,mBAAmB,EAAE,aAAa,kBAAkB,GAAG;AACrE,QAAM,YAAY,CAAC,EAAE,eAAe,OAAO,YAAY,SAAS;AAChE,QAAM,aAAa,CAAC,EAAE,eAAe,OAAO,YAAY,aAAa;AACrE,QAAM,eAAe,CAAC,EAAE,gBAAgB,OAAO,YAAY,WAAW,cAChE,YAAY,WAAW,OAAO,YAAY,QAAQ,WAAW;AAGnE,QAAM,gBAAgB,CAAC,EAAE,aAAa,eACjC,OAAO,YAAY,SAAS,YAAY,YAAY,KAAK,SAAS;AACvE,QAAM,qBAAqB,CAAC,EAAE,aAAa,cACrC,eAAe,OAAO,YAAY,SAAS;AACjD,QAAM,SAAS,cAAc;AAC7B,QAAM,qBAAqB,CAAC,EAAE,qBACzB,kBAAkB,WAAW,kBAAkB,gBAC/C,OAAO,kBAAkB,uBAAuB;AAErD,QAAM,SAAS;AAAA,IACb,gBAAgB,OAAO,QAAQ,iGAAsB;AAAA,IACrD,SAAS,OAAO,CAAC,EAAE,qBAAqB,OAAO,kBAAkB,mBAAmB,aAAa,6DAAgB;AAAA,IACjH,WAAW,OAAO,QAAQ,mHAAyB;AAAA;AAAA;AAAA,IAGnD,uBAAuB,OAAO,oBAAoB,qIAA4B;AAAA,IAC9E,eAAe;AAAA,MACZ,CAAC,aAAa,gBAAkB,aAAa,iBAAiB;AAAA,MAC/D,aAAa,CAAC,gBACV,oMACA;AAAA,IACN;AAAA,IACA,iBAAiB;AAAA,MACd,CAAC,aAAa,cAAc,gBAAgB,sBACzC,aAAa,iBAAiB,UAAU;AAAA,MAC5C,aAAa,CAAC,qBACV,oMACA,aAAa,CAAC,gBACZ,wLACA;AAAA,IACR;AAAA,EACF;AAEA,SAAO,OAAO,OAAO;AACrB,SAAO,QAAQ,OAAO;AACtB,SAAO,eAAe,OAAO;AAC7B,SAAO,QAAQ,OAAO;AACtB,SAAO,OAAO,OAAO;AAErB,SAAO;AAAA,IACL,aAAa,YAAY,mBAAmB;AAAA,IAC5C,SAAS;AAAA,EACX;AACF;AAEO,SAAS,kBAAkB,cAAcC,OAAM;AACpD,QAAM,QAAQ,gBAAgB,aAAa,WAAW,aAAa,QAAQA,KAAI;AAC/E,MAAI,SAAS,MAAM,UAAW;AAC9B,QAAM,QAAQ,IAAI,MAAO,SAAS,MAAM,UAAW,8CAAWA,KAAI,EAAE;AACpE,QAAM,SAAS;AACf,QAAM,OAAO;AACb,QAAM;AACR;;;ACrEA,SAAS,SAAAC,QAAO,YAAAC,WAAU,UAAAC,SAAQ,IAAI,QAAQ,aAAAC,kBAAiB;AAC/D,SAAS,QAAAC,aAAY;AAIrB,IAAM,aAAa;AAEnB,SAAS,cAAc,SAAS;AAC9B,QAAM,QAAQ,IAAI,MAAM,OAAO;AAC/B,QAAM,SAAS;AACf,QAAM,OAAO;AACb,SAAO;AACT;AAEA,SAAS,YAAY,GAAG;AACtB,SAAO,GAAI,KAAK,EAAE,QAAS,EAAE,IAAK,KAAK,EAAE,WAAY,CAAC;AACxD;AAEA,SAAS,eAAe,GAAG;AACzB,SAAO,iBAAiB,KAAK,YAAY,CAAC,CAAC;AAC7C;AAEA,SAAS,gBAAgB,GAAG;AAC1B,SAAO,kBAAkB,KAAK,YAAY,CAAC,CAAC;AAC9C;AAEA,eAAeC,cAAa,QAAQ;AAClC,MAAI;AAAE,QAAI,UAAU,OAAO,OAAO,UAAU,WAAY,OAAM,OAAO,MAAM;AAAA,EAAE,SAAS,GAAG;AAAA,EAA8B;AACzH;AAKA,eAAsB,qBAAqB,IAAI,KAAK;AAClD,MAAI,SAAS;AACb,MAAI;AACF,aAAS,MAAM,GAAG,KAAK,KAAK,OAAO;AAAA,EACrC,SAAS,GAAG;AACV,QAAI,eAAe,CAAC,EAAG,OAAM,cAAc,sLAAgC;AAC3E,UAAM;AAAA,EACR;AACA,QAAMA,cAAa,MAAM;AAC3B;AAIA,eAAsB,sBAAsB,IAAI,KAAK,QAAQ;AAC3D,QAAM,YAAY,MAAM,uBAAuB,IAAI,MAAM;AACzD,MAAI,CAAC,WAAW;AACd,UAAM,QAAQ,IAAI,MAAM,sIAAwB;AAChD,UAAM,SAAS;AACf,UAAM;AAAA,EACR;AACA,MAAI,SAAS;AACb,MAAI;AACF,aAAS,MAAM,GAAG,KAAK,KAAK,OAAO;AAAA,EACrC,SAAS,GAAG;AACV,QAAI,eAAe,CAAC,EAAG,OAAM,cAAc,kJAA0B;AACrE,UAAM;AAAA,EACR;AAEA,QAAMA,cAAa,MAAM;AACzB,WAAS;AACT,MAAI;AAGF,UAAM,GAAG,UAAU,YAAY,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,EACjE,SAAS,GAAG;AACV,UAAM,QAAQ,IAAI,MAAM,2DAAc,OAAQ,KAAK,EAAE,WAAY,CAAC,CAAC;AACnE,UAAM,SAAS;AACf,UAAM;AAAA,EACR;AAEA,MAAI,OAAO,GAAG,SAAS,YAAY;AACjC,UAAM,QAAQ,MAAM,GAAG,KAAK,GAAG,EAAE,MAAM,MAAM,MAAS;AACtD,QAAI,OAAO;AACT,YAAM,QAAQ,IAAI,MAAM,0KAAmC;AAC3D,YAAM,SAAS;AACf,YAAM;AAAA,IACR;AAAA,EACF;AACA,SAAO;AACT;AAIA,eAAe,wBAAwB,EAAE,KAAK,WAAW,YAAY,UAAU,GAAG;AAChF,QAAM,WAAW,MAAMC,UAAS,UAAU;AAC1C,QAAM,SAAS,eAAe,QAAQ,EAAE;AACxC,MAAI,OAAO,WAAW,EAAG,OAAM,IAAI,MAAM,8GAAyB;AAClE,QAAM,YAAY,yBAAyB,UAAU,SAAS;AAC9D,QAAM,kBAAkB,eAAe,SAAS,EAAE;AAClD,MAAI,gBAAgB,WAAW,OAAO,OAAQ,OAAM,IAAI,MAAM,8GAAoB;AAClF,MAAI,CAAC,SAAS,SAAS,OAAO,CAAC,EAAE,GAAG,EAAE,OAAO,UAAU,SAAS,gBAAgB,CAAC,EAAE,GAAG,CAAC,GAAG;AACxF,UAAM,IAAI,MAAM,8GAAoB;AAAA,EACtC;AACA,QAAM,YAAY,iBAAiB,UAAU,MAAM,WAAW,GAAG;AACjE,QAAMC,OAAM,WAAW,EAAE,WAAW,KAAK,CAAC;AAC1C,QAAM,SAASC,MAAK,WAAW,eAAe,QAAQ,GAAG,IAAI,KAAK,IAAI,CAAC,EAAE;AACzE,QAAMC,WAAU,QAAQ,WAAW,EAAE,MAAM,IAAM,CAAC;AAClD,QAAMC,QAAO,QAAQF,MAAK,WAAW,UAAU,gBAAgB,CAAC,CAAC,CAAC;AAClE,SAAO;AACT;AAMA,eAAsB,iBAAiB,EAAE,IAAI,KAAK,QAAQ,WAAW,SAAS,CAAC,GAAG,sBAAsB,EAAE,GAAG;AAC3G,QAAM,YAAY,MAAM,uBAAuB,IAAI,MAAM;AACzD,MAAI,CAAC,WAAW;AACd,UAAM,QAAQ,IAAI,MAAM,8GAAoB;AAC5C,UAAM,SAAS;AACf,UAAM;AAAA,EACR;AACA,QAAM,qBAAqB,IAAI,GAAG;AAClC,QAAM,YAAY,OAAO,OAAO,CAAC,GAAG,QAAQ,EAAE,KAAK,UAAU,CAAC;AAC9D,QAAM,WAAW,OAAO,SAAS,OAAO,OAAO,CAAC,EAAE,GAAG,IAAI;AACzD,QAAM,SAAS,aAAa,IAAI,OAAO,IAAI,CAAC,OAAO,WAAW,EAAE,GAAG,OAAO,KAAK,MAAM,EAAE,IAAI;AAC3F,QAAM,gBAAgB,OAAO,YAAY,OAAO,cAAc,mBAAmB,KAAK,sBAAsB,IACxG,EAAE,oBAAoB,IACtB;AACJ,QAAM,aAAa,GAAG,UAAU,OAAO,gBAAgB,QAAQ,GAAG,IAAI,KAAK,IAAI,CAAC;AAChF,QAAME,QAAO,UAAU,SAAS,UAAU;AAC1C,MAAI,SAAS;AACb,MAAI;AACF,QAAI;AACF,eAAS,MAAM,GAAG,OAAO,WAAW,aAAa;AACjD,eAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK,YAAY;AAClD,cAAM,OAAO,OAAO,OAAO,MAAM,GAAG,IAAI,UAAU,CAAC;AAAA,MACrD;AACA,YAAM,OAAO,MAAM;AACnB,YAAM,OAAO,MAAM;AACnB,eAAS;AAAA,IACX,SAAS,GAAG;AACV,UAAI,gBAAgB,CAAC,GAAG;AAGtB,cAAM,wBAAwB,EAAE,KAAK,WAAW,YAAY,UAAU,CAAC;AAAA,MACzE,OAAO;AACL,cAAM;AAAA,MACR;AAAA,IACF;AAEA,QAAI,OAAO,GAAG,SAAS,WAAY,OAAM,IAAI,MAAM,qFAAoB;AACvE,UAAM,QAAQ,MAAM,GAAG,KAAK,GAAG;AAC/B,QAAI,CAAC,SAAS,CAAC,MAAM,UAAU,MAAM,OAAO,QAAQ,WAAW;AAC7D,YAAM,IAAI,MAAM,oHAAqB;AAAA,IACvC;AACA,QAAI,OAAO,cAAc,MAAM,UAAU,KAAK,OAAO,SAAS,KAAK,MAAM,eAAe,OAAO,QAAQ;AACrG,YAAM,IAAI,MAAM,oGAAoB,OAAO,MAAM,sBAAO,MAAM,UAAU,QAAG;AAAA,IAC7E;AAAA,EACF,SAAS,GAAG;AAEV,UAAML,cAAa,MAAM;AACzB,QAAI;AAAE,YAAM,GAAG,iBAAiB,UAAU,MAAM,WAAW,GAAG,GAAG,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,IAAE,SAAS,GAAG;AAAA,IAAC;AAChH,QAAI;AAAE,YAAMK,QAAO,YAAY,UAAU,OAAO;AAAA,IAAE,SAAS,GAAG;AAAA,IAAC;AAC/D,QAAI,KAAK,EAAE,OAAQ,OAAM;AACzB,UAAM,QAAQ,IAAI,MAAM,2DAAc,OAAQ,KAAK,EAAE,WAAY,CAAC,CAAC;AACnE,UAAM,SAAS;AACf,UAAM;AAAA,EACR;AACA,MAAI;AAAE,UAAM,OAAO,UAAU;AAAA,EAAE,SAAS,GAAG;AAAA,EAAsB;AACjE,SAAO,EAAE,YAAY,iBAAiB,UAAU,MAAM,WAAW,GAAG,EAAE;AACxE;;;AZ9JO,IAAM,OAAO;AACb,IAAM,SAAS,CAAC,aAAa,qBAAqB,sBAAsB,gBAAgB,eAAe;AAE9G,IAAM,YAAY;AAElB,IAAM,YAAY,QAAQ,IAAI,kCAAkCC,MAAKC,SAAQ,GAAG,QAAQ,wBAAwB;AAChH,IAAM,cAAcD,MAAK,WAAW,YAAY;AAChD,IAAM,uBAAuB;AAC7B,IAAM,yBAAyB,OAAO,OAAO,EAAE,eAAe,EAAE,CAAC;AAGjE,IAAM,gBAAgB;AACtB,IAAM,cAAc;AACpB,IAAM,YAAY;AAClB,IAAM,kBAAkB;AAExB,SAAS,KAAK,KAAK,OAAO,SAAS,KAAK;AACtC,MAAI,UAAU,QAAQ,EAAE,gBAAgB,mCAAmC,iBAAiB,WAAW,CAAC;AACxG,MAAI,IAAI,KAAK,UAAU,KAAK,CAAC;AAC/B;AAEA,SAAS,YAAY,OAAO;AAC1B,SAAO,SAAS,OAAO,UAAU,MAAM,MAAM,IAAI,MAAM,SAAS;AAClE;AAIA,SAAS,cAAc,KAAK;AAC1B,MAAI,SAAS;AACb,QAAM,QAAQ,CAAC;AACf,SAAO,eAAe,IAAI,IAAI;AAC5B,QAAI,UAAU,IAAK,OAAM,IAAI,QAAQ,CAAC,YAAY,MAAM,KAAK,OAAO,CAAC;AACrE;AACA,QAAI;AAAE,aAAO,MAAM,GAAG;AAAA,IAAE,UAAE;AACxB;AACA,YAAM,OAAO,MAAM,MAAM;AACzB,UAAI,KAAM,MAAK;AAAA,IACjB;AAAA,EACF;AACF;AAEA,eAAe,aAAa,KAAK;AAC/B,QAAM,SAAS,CAAC;AAChB,MAAI,QAAQ;AACZ,mBAAiB,SAAS,KAAK;AAC7B,WAAO,KAAK,KAAK;AACjB,aAAS,MAAM;AACf,QAAI,QAAQ,KAAK,GAAI,QAAO;AAAA,EAC9B;AACA,MAAI;AACF,WAAO,KAAK,MAAM,OAAO,OAAO,MAAM,EAAE,SAAS,MAAM,CAAC;AAAA,EAC1D,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,SAAS,MAAM;AACtB,QAAM,MAAM,QAAQ,KAAK;AACzB,MAAI,CAAC,MAAM,QAAQ,GAAG,EAAG,QAAO;AAChC,QAAM,MAAM,CAAC;AACb,aAAW,KAAK,IAAK,KAAI,OAAO,MAAM,YAAYE,iBAAgB,CAAC,EAAG,KAAI,KAAK,CAAC;AAChF,SAAO;AACT;AAEA,SAASA,iBAAgB,OAAO;AAC9B,SAAO,OAAO,UAAU,YAAY,MAAM,SAAS,KAAK,MAAM,UAAU,OAAO,CAAC,UAAU,KAAK,KAAK,KAAK,UAAU,OAAO,UAAU;AACtI;AAEA,SAAS,iBAAiB,OAAO;AAC/B,MAAI,CAACA,iBAAgB,KAAK,GAAG;AAC3B,UAAM,QAAQ,IAAI,MAAM,8BAAe;AACvC,UAAM,SAAS;AACf,UAAM;AAAA,EACR;AACA,SAAO;AACT;AASA,SAAS,mBAAmB,SAAS;AACnC,MAAI;AACF,UAAM,IAAI,QAAQ,IAAI,eAAe;AACrC,QAAI,KAAK,KAAM,QAAQ,KAAK,EAAE,MAAM,OAAQ,EAAE,KAAM,OAAO,MAAM,WAAW,IAAI;AAAA,EAClF,SAAS,GAAG;AAAA,EAAoB;AAChC,MAAI;AACF,UAAM,IAAI,QAAQ,IAAI,gBAAgB;AACtC,QAAI,KAAK,KAAM,QAAQ,KAAK,EAAE,MAAM,OAAQ,EAAE,KAAM,OAAO,MAAM,WAAW,IAAI;AAAA,EAClF,SAAS,GAAG;AAAA,EAAoB;AAChC,MAAI;AACF,UAAM,QAAQ,QAAQ,IAAI,UAAU;AACpC,QAAI,SAAS,MAAM,UAAU,MAAM,OAAO,MAAM,KAAM,QAAO,MAAM,OAAO;AAAA,EAC5E,SAAS,GAAG;AAAA,EAAoB;AAChC,SAAO;AACT;AAEA,SAAS,UAAU,QAAQ;AACzB,MAAI,QAAQ;AACZ,MAAI,YAAY;AAChB,aAAW,MAAM,QAAQ;AACvB,QAAI,GAAG,SAAS,mBAAmB,GAAG,QAAQ,OAAO,GAAG,KAAK,UAAU,YAAY,GAAG,KAAK,MAAM,QAAQ;AACvG,cAAQ,GAAG,KAAK;AAAA,IAClB;AACA,QAAI,cAAc,QAAQ,GAAG,SAAS,kBAAkB,GAAG,QAAQ,MAAM,QAAQ,GAAG,KAAK,OAAO,GAAG;AACjG,YAAM,MAAM,GAAG,KAAK,QAAQ,OAAO,CAAC,MAAM,KAAK,EAAE,SAAS,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,EAAE,KAAK;AACpH,UAAI,IAAK,aAAY;AAAA,IACvB;AAAA,EACF;AACA,SAAO,SAAS,aAAa;AAC/B;AAEO,SAAS,MAAM,KAAK;AACzB,QAAM,IAAI,IAAI;AACd,QAAM,KAAK,IAAI;AACf,QAAM,cAAc,yBAAyB,EAAE;AAC/C,QAAM,eAAe,mBAAmB,EAAE,aAAa,IAAI,mBAAmB,EAAE,CAAC;AACjF,QAAM,KAAK,IAAI;AACf,QAAM,MAAM,MAAM,IAAI,cAAc,IAAI,WAAW;AACnD,QAAM,sBAAsB,oBAAI,IAAI;AAIpC,QAAM,YAAY,uBAAuB;AAIzC,QAAM,aAAa,sBAAsB,EAAE,KAAK,WAAW,MAAMF,MAAK,WAAW,kBAAkB,EAAE,CAAC;AAKtG,iBAAe,mBAAmB,KAAK,WAAW;AAChD,UAAM,OAAO,oBAAI,IAAI;AACrB,QAAI,CAAC,OAAO,CAAC,IAAI,OAAQ,QAAO;AAChC,QAAI;AACJ,QAAI;AAAE,cAAQ,MAAM,WAAW,QAAQ;AAAA,IAAE,SAAS,GAAG;AAAE,aAAO;AAAA,IAAK;AACnE,eAAW,MAAM,KAAK;AACpB,YAAMG,QAAO,UAAU,IAAI,EAAE;AAC7B,YAAM,QAAQ,SAAS,MAAM,EAAE;AAC/B,UAAI,CAACA,SAAQ,CAAC,MAAO;AACrB,YAAM,KAAK,cAAcA,KAAI;AAC7B,UAAI,CAAC,yBAAyB,EAAE,EAAG;AACnC,UAAI,MAAM,MAAM,gBAAgB,IAAI;AAClC,aAAK,IAAI,IAAI,EAAE,OAAO,MAAM,OAAO,KAAK,MAAM,KAAK,WAAW,MAAM,UAAU,CAAC;AAAA,MACjF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAMA,WAAS,eAAe,SAAS,WAAW;AAC1C,QAAI,CAAC,WAAW,CAAC,QAAQ,KAAM;AAC/B,UAAM,QAAQ,CAAC;AACf,UAAM,MAAM,KAAK,IAAI;AACrB,eAAW,CAAC,IAAI,IAAI,KAAK,SAAS;AAChC,YAAM,KAAK,cAAc,UAAU,IAAI,EAAE,CAAC;AAC1C,UAAI,CAAC,yBAAyB,EAAE,EAAG;AACnC,YAAM,EAAE,IAAI,EAAE,OAAO,KAAK,OAAO,KAAK,KAAK,KAAK,WAAW,KAAK,WAAW,aAAa,IAAI,WAAW,IAAI;AAAA,IAC7G;AACA,QAAI,CAAC,OAAO,KAAK,KAAK,EAAE,OAAQ;AAChC,eAAW,MAAM,KAAK,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAAA,EACxC;AAGA,WAAS,iBAAiB,GAAG;AAC3B,QAAI,QAAQ,MAAM,YAAY,MAAM,MAAM;AAC1C,QAAI,GAAG;AACL,UAAI,EAAE,SAAS,EAAE,MAAM,MAAO,SAAQ,OAAO,EAAE,MAAM,KAAK;AAC1D,UAAI,EAAE,SAAS;AAAE,cAAM,EAAE,QAAQ,OAAO;AAAM,oBAAY,EAAE,QAAQ,aAAa;AAAA,MAAK;AAAA,IACxF;AACA,WAAO,EAAE,OAAO,KAAK,UAAU;AAAA,EACjC;AAIA,WAAS,eAAe,QAAQ;AAC9B,QAAI,CAAC,OAAQ,QAAO;AACpB,QAAI,OAAO,WAAW,YAAa,QAAO,OAAO,SAAS;AAC1D,QAAI,OAAO,WAAW,WAAY,QAAO;AACzC,WAAO;AAAA,EACT;AAEA,iBAAe,gBAAgB;AAC7B,UAAM,IAAI,IAAI;AACd,QAAI,CAAC,EAAG,OAAM,IAAI,MAAM,8BAA8B;AACtD,WAAO,EAAE,OAAO,IAAI;AAAA,EACtB;AAEA,iBAAe,cAAc,SAAS;AACpC,UAAM,IAAI,IAAI;AACd,QAAI,CAAC,EAAG,OAAM,IAAI,MAAM,8BAA8B;AACtD,UAAM,MAAM,EAAE,OAAO,IAAI;AACzB,UAAM,OAAO,OAAO,OAAO,CAAC,GAAG,KAAK,EAAE,oBAAoB,QAAQ,CAAC;AACnE,UAAM,EAAE,OAAO,IAAI,IAAI;AAEvB,QAAI,KAAK,WAAW,GAAG;AAAE,UAAI;AAAE,UAAE,QAAQ;AAAA,MAAK,SAAS,GAAG;AAAA,MAAoB;AAAA,IAAE;AAChF,WAAO;AAAA,EACT;AAEA,MAAI,kBAAkB,QAAQ,QAAQ;AACtC,WAAS,eAAe,SAAS;AAC/B,UAAM,YAAY,gBAAgB,KAAK,YAAY;AACjD,YAAM,QAAQ,MAAM,cAAc;AAClC,YAAM,QAAQ,MAAM,sBAAsB,CAAC,GAAG,IAAI,MAAM;AACxD,YAAM,SAAS,MAAM,QAAQ,IAAI;AACjC,UAAI,OAAO,KAAM,OAAM,cAAc,OAAO,IAAI;AAChD,aAAO,OAAO;AAAA,IAChB,CAAC;AACD,sBAAkB,UAAU,MAAM,MAAM;AAAA,IAAC,CAAC;AAC1C,WAAO;AAAA,EACT;AAEA,MAAI,WAAW,CAAC;AAGhB,WAAS,UAAU,KAAK,MAAM,OAAO,aAAa;AAChD,UAAM,MAAM,KAAK,OAAO;AACxB,UAAM,KAAK,MAAM,SAAS,GAAG,IAAI;AACjC,UAAM,QAAQ,KAAK,SAAS;AAC5B,UAAM,UAAU,QAAS,OAAO,KAAK,EAAE,SAAS,YAAY,OAAO,KAAK,EAAE,MAAM,GAAG,SAAS,IAAI,WAAM,OAAO,KAAK,IAAK;AACvH,UAAM,OAAO;AAAA,MACX,WAAW;AAAA,MACX,OAAO;AAAA,MACP,WAAW,KAAK,aAAa;AAAA,MAC7B,eAAe;AAAA,MACf,gBAAiB,MAAM,GAAG,QAAS,GAAG,QAAQ;AAAA,MAC9C,eAAe,CAAC,EAAE,OAAO,CAAC;AAAA,MAC1B,cAAc,CAAC,CAAC;AAAA,IAClB;AAGA,QAAI,eAAe,OAAO;AACxB,UAAI,MAAM,YAAY,MAAM,SAAS,IAAI,GAAG,EAAG,MAAK,YAAY,MAAM,SAAS,IAAI,GAAG;AACtF,UAAI,MAAM,aAAa,MAAM,UAAU,IAAI,GAAG,EAAG,MAAK,YAAY,MAAM,UAAU,IAAI,GAAG;AAAA,IAC3F;AACA,WAAO;AAAA,EACT;AAeA,iBAAe,WAAW,IAAI,OAAO,OAAO,CAAC,GAAG;AAC9C,UAAM,MAAM,OAAO,EAAE;AACrB,UAAM,WAAW,SAAS,MAAM,YAAY,MAAM,UAAU,IAAI,GAAG,IAAI,SAClE,EAAE,SAAS,MAAM,aAAa,MAAM,UAAU,IAAI,GAAG,GAAG,MAAM,MAAM,YAAY,MAAM,SAAS,IAAI,GAAG,EAAE,IAAI;AACjH,UAAM,SAAS,UAAU,IAAI,KAAK,QAAQ;AAC1C,QAAI,OAAQ,QAAO,UAAU,KAAK,QAAQ,OAAO,KAAK,WAAW;AAEjE,QAAI,OAAO,EAAE,OAAO,MAAM,KAAK,MAAM,WAAW,KAAK;AAGrD,QAAI,KAAK,YAAY;AACnB,UAAI,OAAO,KAAK,WAAW,QAAQ,SAAU,MAAK,MAAM,KAAK,WAAW;AACxE,UAAI,KAAK,WAAW,aAAa,KAAM,MAAK,YAAY,KAAK,WAAW;AAAA,IAC1E;AACA,QAAI,KAAK,cAAc,QAAW;AAChC,YAAM,YAAY,iBAAiB,eAAe,KAAK,SAAS,CAAC;AACjE,UAAI,UAAU,MAAO,MAAK,QAAQ,UAAU;AAC5C,UAAI,CAAC,KAAK,OAAO,UAAU,IAAK,MAAK,MAAM,UAAU;AACrD,UAAI,CAAC,KAAK,aAAa,UAAU,UAAW,MAAK,YAAY,UAAU;AAAA,IACzE,WAAW,OAAO,GAAG,sBAAsB,YAAY;AACrD,UAAI;AACF,cAAM,YAAY,iBAAiB,MAAM,GAAG,kBAAkB,EAAE,CAAC;AACjE,YAAI,UAAU,MAAO,MAAK,QAAQ,UAAU;AAC5C,YAAI,CAAC,KAAK,OAAO,UAAU,IAAK,MAAK,MAAM,UAAU;AACrD,YAAI,CAAC,KAAK,aAAa,UAAU,UAAW,MAAK,YAAY,UAAU;AAAA,MACzE,SAAS,GAAG;AAAA,MAAqB;AAAA,IACnC;AAIA,UAAM,sBAAsB,OAAO,GAAG,sBAAsB,cAAc,OAAO,GAAG,uBAAuB;AAC3G,QAAI,CAAC,KAAK,OAAQ,CAAC,KAAK,SAAS,CAAC,qBAAsB;AACtD,UAAI;AACF,YAAI,cAAc;AAClB,cAAM,UAAU,MAAM,YAAY,eAAe,KAAK;AAAA,UACpD,UAAU,CAAC,WAAW;AAAE,gBAAI,CAAC,YAAa,eAAc,UAAU,MAAM;AAAA,UAAE;AAAA,QAC5E,CAAC;AACD,YAAI,WAAW,QAAQ,MAAM;AAC3B,cAAI,CAAC,KAAK,IAAK,MAAK,MAAM,QAAQ,KAAK,OAAO;AAC9C,cAAI,CAAC,KAAK,UAAW,MAAK,YAAY,QAAQ,KAAK,aAAa;AAAA,QAClE;AACA,YAAI,CAAC,KAAK,SAAS,YAAa,MAAK,QAAQ;AAAA,MAC/C,SAAS,IAAI;AAAA,MAA0B;AAAA,IACzC;AACA,cAAU,IAAI,KAAK,UAAU,IAAI;AAEjC,QAAI,KAAK,kBAAkB,SAAU,MAAK,eAAe,KAAK,IAAI;AAClE,WAAO,UAAU,KAAK,MAAM,OAAO,KAAK,WAAW;AAAA,EACrD;AAeA,iBAAe,aAAa,kBAAkB;AAC5C,UAAM,WAAW,oBAAI,IAAI;AACzB,UAAM,YAAY,oBAAI,IAAI;AAC1B,UAAM,YAAY,oBAAI,IAAI;AAC1B,QAAI,UAAU;AACd,QAAI,MAAM,QAAQ,gBAAgB,EAAG,WAAU;AAAA,SAC1C;AAAE,UAAI;AAAE,kBAAU,MAAM,YAAY,YAAY;AAAA,MAAE,SAAS,GAAG;AAAE,kBAAU,CAAC;AAAA,MAAE;AAAA,IAAE;AACpF,QAAI,CAAC,MAAM,QAAQ,OAAO,EAAG,WAAU,CAAC;AACxC,UAAM,QAAQ;AACd,aAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK,OAAO;AAC9C,YAAM,QAAQ,IAAI,QAAQ,MAAM,GAAG,IAAI,KAAK,EAAE,IAAI,OAAO,UAAU;AACjE,cAAM,SAAS,SAAS,MAAM,SAAS,MAAM,SAAS;AACtD,cAAM,KAAK,SAAS,MAAM,MAAM,OAAO,OAAO,MAAM,EAAE,IAAK,UAAU,OAAO,MAAM,OAAO,OAAO,OAAO,EAAE,IAAI;AAC7G,YAAI,CAAC,GAAI;AAGT,YAAI,SAAS,OAAO,MAAM,aAAa,YAAY,MAAM,UAAU;AACjE,cAAI,OAAO,SAAS,MAAM,SAAS,EAAG,UAAS,IAAI,IAAI,OAAO,MAAM,SAAS,CAAC;AAC9E,oBAAU,IAAI,IAAI,EAAE,UAAU,MAAM,SAAS,CAAC;AAC9C;AAAA,QACF;AACA,YAAI,SAAS,OAAO,SAAS,MAAM,SAAS,EAAG,UAAS,IAAI,IAAI,OAAO,MAAM,SAAS,CAAC;AACvF,YAAI;AACF,gBAAM,MAAM,YAAY,OAAO,MAAM;AACrC,cAAI,CAAC,OAAO,OAAO,IAAI,SAAS,YAAY,CAAC,IAAI,KAAM;AACvD,gBAAM,KAAK,MAAMA,MAAK,IAAI,IAAI;AAC9B,cAAI,CAAC,GAAI;AACT,cAAI,OAAO,GAAG,SAAS,SAAU,UAAS,IAAI,IAAI,GAAG,IAAI;AACzD,cAAI,OAAO,GAAG,YAAY,YAAY,GAAG,UAAU,GAAG;AACpD,sBAAU,IAAI,IAAI,KAAK,MAAM,GAAG,OAAO,CAAC;AACxC,sBAAU,IAAI,IAAI,EAAE,SAAS,KAAK,MAAM,GAAG,OAAO,GAAG,MAAM,OAAO,GAAG,SAAS,WAAW,GAAG,OAAO,OAAU,CAAC;AAAA,UAChH;AAAA,QACF,SAAS,GAAG;AAAA,QAA0D;AAAA,MACxE,CAAC,CAAC;AAAA,IACJ;AACA,WAAO,EAAE,UAAU,WAAW,WAAW,iBAAiB,UAAU,OAAO,EAAE;AAAA,EAC/E;AAGA,iBAAe,WAAW,KAAK;AAC7B,qBAAiB,GAAG;AACpB,WAAO,eAAe,CAAC,SAAS,KAAK,SAAS,GAAG,IAC7C,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,MAAM,GAAG,GAAG,OAAO,EAAE,IAAI,MAAM,UAAU,KAAK,EAAE,IAC3E,EAAE,MAAM,MAAM,OAAO,EAAE,IAAI,MAAM,UAAU,MAAM,EAAE,CAAC;AAAA,EAC1D;AAGA,MAAI,gBAAgB,QAAQ,QAAQ;AACpC,WAAS,oBAAoB,KAAK;AAChC,QAAI,MAAM,QAAQ,GAAG,EAAG,QAAO,EAAE,eAAe,sBAAsB,UAAU,EAAE,GAAG,uBAAuB,GAAG,OAAO,KAAK,kBAAkB,CAAC,EAAE;AAChJ,UAAM,WAAW,OAAO,OAAO,IAAI,aAAa,WAAW,IAAI,WAAW,CAAC;AAC3E,UAAM,gBAAgB,OAAO,UAAU,SAAS,aAAa,KAAK,SAAS,iBAAiB,IAAI,SAAS,gBAAgB;AACzH,WAAO;AAAA,MACL,eAAe;AAAA,MACf,UAAU,EAAE,cAAc;AAAA,MAC1B,OAAO,OAAO,MAAM,QAAQ,IAAI,KAAK,IAAI,IAAI,QAAQ,CAAC;AAAA,MACtD,kBAAkB,OAAO,MAAM,QAAQ,IAAI,gBAAgB,IAAI,CAAC,GAAG,IAAI,IAAI,IAAI,iBAAiB,OAAOD,gBAAe,EAAE,IAAI,MAAM,CAAC,CAAC,IAAI,CAAC;AAAA,IAC3I;AAAA,EACF;AACA,iBAAe,iBAAiB;AAC9B,QAAI;AAAE,aAAO,oBAAoB,KAAK,MAAME,cAAa,aAAa,MAAM,CAAC,CAAC;AAAA,IAAE,SAAS,GAAG;AAAE,aAAO,oBAAoB,IAAI;AAAA,IAAE;AAAA,EACjI;AACA,iBAAe,YAAY;AAAE,YAAQ,MAAM,eAAe,GAAG;AAAA,EAAM;AACnE,iBAAe,gBAAgB,OAAO;AACpC,UAAMC,OAAM,WAAW,EAAE,WAAW,KAAK,CAAC;AAC1C,UAAM,MAAML,MAAK,WAAW,UAAU,QAAQ,GAAG,IAAI,KAAK,IAAI,CAAC,MAAM;AACrE,UAAMM,WAAU,KAAK,KAAK,UAAU,oBAAoB,KAAK,GAAG,MAAM,CAAC,GAAG,EAAE,UAAU,QAAQ,MAAM,IAAM,CAAC;AAC3G,UAAMC,QAAO,KAAK,WAAW;AAAA,EAC/B;AACA,WAAS,YAAY,SAAS;AAC5B,UAAM,YAAY,cAAc,KAAK,YAAY;AAC/C,YAAM,QAAQ,MAAM,eAAe;AACnC,YAAM,SAAS,MAAM,QAAQ,KAAK;AAClC,YAAM,gBAAgB,KAAK;AAC3B,aAAO;AAAA,IACT,CAAC;AACD,oBAAgB,UAAU,MAAM,MAAM;AAAA,IAAC,CAAC;AACxC,WAAO;AAAA,EACT;AAOA,QAAM,QAAQ,gBAAgB;AAE9B,QAAM,cAAc,uBAAuB;AAE3C,iBAAe,QAAQ,UAAU;AAC/B,QAAI;AACF,YAAM,QAAQ,MAAM,MAAM,KAAK;AAC/B,YAAM,QAAQ,IAAI,IAAI,SAAS,IAAI,MAAM,CAAC;AAC1C,YAAM,OAAO,MAAM,kBAAkB,OAAO,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC;AAClE,UAAI,KAAK,OAAQ,OAAM,MAAM,UAAU,IAAI;AAAA,IAC7C,SAAS,GAAG;AAAA,IAAoB;AAAA,EAClC;AAOA,iBAAe,UAAU,KAAK;AAC5B,qBAAiB,GAAG;AAMpB,QAAI,SAAS;AACb,QAAI,MAAM;AACV,QAAI,QAAQ;AACZ,QAAI,cAAc;AAClB,QAAI,mBAAmB;AACvB,QAAI;AACF,YAAM,UAAU,MAAM,YAAY,YAAY;AAC9C,YAAM,QAAQ,QAAQ,KAAK,CAAC,UAAU,MAAM,OAAO,GAAG,KAAK;AAC3D,yBAAmB;AACnB,eAAS,QAAQ,MAAM,SAAS;AAChC,UAAI,QAAQ;AACV,cAAM,MAAM,YAAY,OAAO,MAAM;AACrC,YAAI,OAAO,OAAO,IAAI,SAAS,SAAU,eAAc,IAAI;AAC3D,cAAM,OAAO,OAAO;AACpB,gBAAQ,OAAO,SAAU,OAAO,QAAQ,OAAO,KAAK,SAAU;AAAA,MAChE;AACA,UAAI,CAAC,OAAO;AAGV,YAAI,OAAO,GAAG,sBAAsB,YAAY;AAC9C,cAAI;AACF,kBAAM,OAAO,eAAe,MAAM,GAAG,kBAAkB,GAAG,CAAC;AAC3D,gBAAI,QAAQ,KAAK,SAAS,KAAK,MAAM,MAAO,SAAQ,OAAO,KAAK,MAAM,KAAK;AAC3E,gBAAI,QAAQ,KAAK,SAAS;AAAE,kBAAI,CAAC,IAAK,OAAM,KAAK,QAAQ,OAAO;AAAA,YAAK;AAAA,UACvE,SAAS,GAAG;AAAA,UAAqB;AAAA,QACnC;AAAA,MACF;AACA,UAAI,CAAC,OAAO;AACV,YAAI;AACF,cAAI,SAAS;AACb,gBAAM,UAAU,MAAM,YAAY,eAAe,KAAK;AAAA,YACpD,UAAU,CAAC,WAAW;AAAE,kBAAI,CAAC,OAAQ,UAAS,UAAU,MAAM;AAAA,YAAE;AAAA,UAClE,CAAC;AACD,cAAI,WAAW,QAAQ,QAAQ,CAAC,IAAK,OAAM,QAAQ,KAAK,OAAO;AAC/D,kBAAQ;AAAA,QACV,SAAS,GAAG;AAAA,QAAoB;AAAA,MAClC;AAAA,IACF,SAAS,GAAG;AAAA,IAAoB;AAEhC,QAAI,CAAC,UAAU,CAAC,aAAa;AAC3B,YAAM,QAAQ,IAAI,MAAM,sCAAQ;AAChC,YAAM,SAAS;AACf,YAAM;AAAA,IACR;AACA,UAAM,WAAW,MAAM,eAAe,CAAC,UAAU,EAAE,MAAM,MAAM,OAAO,KAAK,SAAS,GAAG,EAAE,EAAE,EAAE,MAAM,MAAM,KAAK;AAC9G,UAAM,YAAY,CAAC,UAAU;AAC3B,YAAM,QAAQ;AAAA,QACZ,WAAW;AAAA,QAAK,OAAO,SAAS,OAAO;AAAA,QAAK,KAAK,OAAO;AAAA,QACxD,QAAQ,UAAU;AAAA,QAAM,cAAc,eAAe;AAAA,QACrD,WAAW,oBAAoB,OAAO,SAAS,iBAAiB,SAAS,IAAI,iBAAiB,YAAY;AAAA,QAC1G,aAAa;AAAA,QAAU,WAAW,KAAK,IAAI;AAAA,MAC7C;AACA,YAAM,KAAK,MAAM,MAAM,UAAU,CAAC,MAAM,OAAO,EAAE,SAAS,MAAM,GAAG;AACnE,UAAI,MAAM,EAAG,OAAM,MAAM,EAAE,IAAI;AAAA,UAC1B,OAAM,MAAM,KAAK,KAAK;AAC3B,YAAM,mBAAmB,MAAM,iBAAiB,OAAO,CAAC,OAAO,OAAO,GAAG;AAAA,IAC3E,CAAC;AACD,WAAO,EAAE,IAAI,MAAM,SAAS,KAAK;AAAA,EACnC;AASA,iBAAe,mBAAmB,KAAK;AACrC,UAAM,WAAW,IAAI,IAAI,UAAU;AACnC,QAAI,YAAY,SAAS,OAAO,SAAS,IAAI,GAAG,GAAG;AACjD,aAAO,EAAE,IAAI,MAAM,eAAe,OAAO,UAAU,KAAK;AAAA,IAC1D;AACA,QAAI,SAAS;AACb,QAAI,SAAS;AACb,QAAI;AACF,YAAMJ,QAAO,MAAM,YAAY,YAAY,GAAG;AAC9C,UAAIA,OAAM;AAAE,iBAAS;AAAM,iBAASA,MAAK;AAAA,MAAO;AAAA,IAClD,SAAS,GAAG;AAAA,IAAgC;AAC5C,QAAI,CAAC,QAAQ;AACX,UAAI;AACF,cAAM,UAAU,MAAM,YAAY,YAAY;AAC9C,cAAM,QAAQ,QAAQ,KAAK,CAACK,WAAUA,OAAM,OAAO,GAAG;AACtD,YAAI,OAAO;AAAE,mBAAS;AAAM,mBAAS,MAAM;AAAA,QAAO;AAAA,MACpD,SAAS,GAAG;AAAA,MAAwB;AAAA,IACtC;AACA,QAAI,CAAC,QAAQ;AACX,YAAMC,SAAQ,MAAM,eAAe;AACnC,UAAIA,OAAM,iBAAiB,IAAI,MAAM,EAAE,SAAS,GAAG,GAAG;AACpD,eAAO,EAAE,IAAI,OAAO,QAAQ,KAAK,MAAM,sBAAsB,SAAS,yGAAoB;AAAA,MAC5F;AACA,aAAO,EAAE,IAAI,OAAO,QAAQ,KAAK,MAAM,uBAAuB,SAAS,yJAA4B;AAAA,IACrG;AAGA,QAAI,WAAW;AACf,UAAM,QAAQ,MAAM,eAAe;AACnC,UAAM,QAAQ,MAAM,MAAM,KAAK,CAAC,MAAM,OAAO,EAAE,SAAS,MAAM,GAAG;AACjE,QAAI,eAAe,SAAS,OAAO,MAAM,iBAAiB,WAAW,MAAM,eAAe;AAC1F,QAAI,CAAC,gBAAgB,QAAQ;AAG3B,YAAM,MAAM,MAAM,YAAY,eAAe,MAAM,EAAE,MAAM,MAAM,IAAI;AACrE,UAAI,OAAO,OAAO,IAAI,SAAS,SAAU,gBAAe,IAAI;AAAA,IAC9D;AACA,QAAI,cAAc;AAChB,YAAM,eAAe,MAAMN,MAAK,YAAY,EAAE,KAAK,MAAM,IAAI,EAAE,MAAM,MAAM,KAAK;AAChF,UAAI,CAAC,cAAc;AACjB,eAAO,EAAE,IAAI,OAAO,QAAQ,KAAK,MAAM,2BAA2B,SAAS,yMAAoC;AAAA,MACjH;AACA,iBAAW;AAAA,IACb;AACA,QAAI,gBAAgB;AACpB,UAAM,MAAO,UAAU,OAAO,OAAS,SAAS,MAAM,OAAQ;AAC9D,QAAI,KAAK;AACP,UAAI;AAAE,wBAAgB,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,QAAQ,IAAI,SAAS,GAAG;AAAA,MAAE,SAAS,GAAG;AAAE,wBAAgB;AAAA,MAAM;AAAA,IACtG;AACA,WAAO,EAAE,IAAI,MAAM,eAAe,SAAS;AAAA,EAC7C;AAMA,iBAAe,iBAAiB,KAAK;AACnC,qBAAiB,GAAG;AACpB,sBAAkB,cAAc,uBAAuB;AACvD,QAAI,UAAU;AACd,UAAM,YAAY,OAAO,UAAU;AACjC,YAAM,QAAQ,MAAM,MAAM,KAAK,CAAC,MAAM,OAAO,EAAE,SAAS,MAAM,GAAG;AACjE,UAAI,CAAC,OAAO;AACV,YAAI,MAAM,iBAAiB,IAAI,MAAM,EAAE,SAAS,GAAG,GAAG;AACpD,gBAAMO,SAAQ,IAAI,MAAM,wGAAmB;AAC3C,UAAAA,OAAM,SAAS;AACf,UAAAA,OAAM,OAAO;AACb,gBAAMA;AAAA,QACR;AACA,cAAM,QAAQ,IAAI,MAAM,8GAAoB;AAC5C,cAAM,SAAS;AACf,cAAM,OAAO;AACb,cAAM;AAAA,MACR;AAIA,YAAM,eAAe,MAAM,mBAAmB,GAAG;AACjD,UAAI,CAAC,aAAa,IAAI;AACpB,cAAM,QAAQ,IAAI,MAAM,aAAa,OAAO;AAC5C,cAAM,SAAS,aAAa;AAC5B,cAAM,OAAO,aAAa;AAC1B,cAAM;AAAA,MACR;AAIA,UAAI,MAAM,gBAAgB,MAAO,OAAM,WAAW,GAAG;AACrD,YAAM,QAAQ,MAAM,MAAM,OAAO,CAAC,MAAM,OAAO,EAAE,SAAS,MAAM,GAAG;AACnE,YAAM,mBAAmB,MAAM,iBAAiB,OAAO,CAAC,OAAO,OAAO,GAAG;AACzE,gBAAU,EAAE,IAAI,MAAM,UAAU,MAAM,eAAe,aAAa,eAAe,UAAU,aAAa,SAAS;AAAA,IACnH,CAAC;AACD,WAAO,WAAW,EAAE,IAAI,MAAM,UAAU,KAAK;AAAA,EAC/C;AAIA,iBAAe,eAAe,KAAK;AACjC,qBAAiB,GAAG;AACpB,sBAAkB,cAAc,OAAO;AACvC,QAAI,SAAS;AACb,UAAM,YAAY,OAAO,UAAU;AACjC,YAAM,QAAQ,MAAM,MAAM,KAAK,CAAC,MAAM,OAAO,EAAE,SAAS,MAAM,GAAG;AACjE,UAAI,CAAC,OAAO;AAAE,cAAM,QAAQ,IAAI,MAAM,8DAAY;AAAG,cAAM,SAAS;AAAK,cAAM;AAAA,MAAM;AACrF,UAAI,SAAS;AACb,UAAI,gBAAgB;AACpB,UAAI;AACF,cAAM,UAAU,MAAM,YAAY,YAAY;AAC9C,cAAM,UAAU,QAAQ,KAAK,CAACF,WAAUA,OAAM,OAAO,GAAG;AACxD,wBAAgB,UAAU,QAAQ,SAAS;AAK3C,cAAM,UAAU,UAAU,MAAM,YAAY,eAAe,QAAQ,MAAM,IAAI;AAC7E,YAAI,WAAW,OAAO,QAAQ,SAAS,SAAU,UAAS,QAAQ;AAAA,MACpE,SAAS,GAAG;AAAA,MAAC;AAIb,UAAI,CAAC,iBAAiB,OAAO,YAAY,gBAAgB,YAAY;AACnE,YAAI;AACF,gBAAM,OAAO,MAAM,YAAY,YAAY,GAAG;AAC9C,cAAI,QAAQ,KAAK,QAAQ;AACvB,4BAAgB,KAAK;AACrB,kBAAM,UAAU,MAAM,YAAY,eAAe,KAAK,MAAM;AAC5D,gBAAI,WAAW,OAAO,QAAQ,SAAS,SAAU,UAAS,QAAQ;AAAA,UACpE;AAAA,QACF,SAAS,GAAG;AAAA,QAAC;AAAA,MACf;AACA,UAAI,CAAC,UAAU,OAAO,MAAM,iBAAiB,SAAU,UAAS,MAAM;AACtE,UAAI,CAAC,QAAQ;AACX,cAAM,QAAQ,IAAI,MAAM,sIAAwB;AAChD,cAAM,SAAS;AACf,cAAM;AAAA,MACR;AAOA,YAAM,oBAAoB,gBAAgB,QAAQ,GAAG;AACrD,UAAI,UAAU,CAAC,mBAAmB;AAChC,cAAM,QAAQ,IAAI,MAAM,kHAAwB;AAChD,cAAM,SAAS;AACf,cAAM;AAAA,MACR;AAIA,UAAI,CAAC,MAAM,iBAAiB,SAAS,GAAG,EAAG,OAAM,iBAAiB,KAAK,GAAG;AAC1E,YAAM,gBAAgB,KAAK;AAK3B,UAAI;AACF,cAAM,WAAW,IAAI,IAAI,UAAU;AACnC,cAAM,cAAc,YAAY,SAAS,OAAO,SAAS,IAAI,GAAG;AAChE,YAAI,eAAe,OAAO,SAAS,UAAU,WAAY,OAAM,SAAS,MAAM,WAAW;AACzF,cAAM,UAAU,YAAY,SAAS,SAAS,SAAS,MAAM,OAAO,SAAS,MAAM,IAAI,GAAG;AAC1F,YAAI,gBAAgB,CAAC,WAAW,OAAO,QAAQ,WAAW,YAAa,OAAM,IAAI,MAAM,iEAA8B;AACrH,YAAI,WAAW,OAAO,QAAQ,WAAW,WAAY,SAAQ,OAAO;AAKpE,cAAM,aAAa,MAAM,GAAG,eAAe,GAAG,YAAY,OAAO,GAAG,YAAY,IAAI,GAAG;AACvF,YAAI,cAAc,OAAO,WAAW,SAAS,WAAY,OAAM;AAAA,MACjE,SAAS,GAAG;AACV,cAAM,QAAQ,IAAI,MAAM,6HAAyB,OAAQ,KAAK,EAAE,WAAY,CAAC,CAAC;AAC9E,cAAM,SAAS;AACf,cAAM;AAAA,MACR;AACA,UAAI,UAAU,YAAY,SAAS,oBAAoB,eAAe;AAGpE,cAAM,sBAAsB,IAAI,KAAK,aAAa;AAAA,MACpD,WAAW,QAAQ;AACjB,YAAI;AAAE,gBAAMG,QAAO,MAAM;AAAA,QAAE,SAAS,GAAG;AAAE,cAAI,KAAK,EAAE,SAAS,SAAU,OAAM,IAAI,MAAM,+CAAY,OAAQ,KAAK,EAAE,WAAY,CAAC,CAAC;AAAA,QAAE;AAAA,MACpI;AACA,UAAI;AAAE,mBAAW,OAAO,EAAE,KAAK,GAAG;AAAE,cAAI,IAAI,WAAW,SAAS,GAAG,GAAG;AAAE,gBAAI;AAAE,oBAAM,IAAI,cAAc,GAAG;AAAA,YAAE,SAAS,GAAG;AAAA,YAAC;AAAA,UAAE;AAAA,QAAE;AAAA,MAAE,SAAS,GAAG;AAAA,MAAC;AAC3I,UAAI;AAAE,YAAI,EAAE,gBAAgB,EAAE,aAAa,OAAQ,GAAE,aAAa,OAAO,GAAG;AAAA,MAAE,SAAS,GAAG;AAAA,MAAC;AAC3F,UAAI;AAAE,YAAI,EAAE,WAAW,EAAE,QAAQ,OAAQ,GAAE,QAAQ,OAAO,GAAG;AAAA,MAAE,SAAS,GAAG;AAAA,MAAC;AAC5E,YAAM,WAAW,GAAG;AAIpB,UAAI;AAAE,cAAM,gBAAgB;AAAA,MAAE,SAAS,GAAG;AAAA,MAA8C;AACxF,YAAM,QAAQ,MAAM,MAAM,OAAO,CAAC,MAAM,OAAO,EAAE,SAAS,MAAM,GAAG;AACnE,eAAS;AAAA,IACX,CAAC;AACD,QAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,sCAAQ;AACrC,UAAM,UAAU,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AACrC,WAAO,EAAE,IAAI,MAAM,QAAQ,KAAK;AAAA,EAClC;AAEA,iBAAe,cAAc,MAAM;AACjC,QAAI,SAAS,OAAW,SAAQ,MAAM,eAAe,GAAG;AACxD,UAAM,OAAO,OAAO,KAAK,aAAa;AACtC,QAAI,CAAC,OAAO,UAAU,IAAI,KAAK,CAAC,CAAC,GAAG,GAAG,IAAI,EAAE,EAAE,SAAS,IAAI,GAAG;AAC7D,YAAM,QAAQ,IAAI,MAAM,2DAA6B;AACrD,YAAM,SAAS;AACf,YAAM;AAAA,IACR;AACA,UAAM,YAAY,CAAC,UAAU;AAAE,YAAM,WAAW,EAAE,eAAe,KAAK;AAAA,IAAE,CAAC;AACzE,YAAQ,MAAM,eAAe,GAAG;AAAA,EAClC;AAEA,iBAAe,sBAAsB;AACnC,QAAI,CAAC,aAAa,QAAQ,MAAM,UAAW,QAAO;AAClD,UAAM,QAAQ,MAAM,eAAe;AACnC,UAAM,OAAO,MAAM,SAAS;AAC5B,QAAI,CAAC,KAAM,QAAO;AAClB,UAAM,SAAS,KAAK,IAAI,IAAI,OAAO;AACnC,UAAM,MAAM,MAAM,MAAM,OAAO,CAAC,SAAS,OAAO,KAAK,SAAS,IAAI,KAAK,OAAO,KAAK,SAAS,IAAI,MAAM,EAAE,IAAI,CAAC,SAAS,OAAO,KAAK,SAAS,CAAC;AAC5I,QAAI,QAAQ;AACZ,eAAW,OAAO,KAAK;AAAE,UAAI;AAAE,cAAM,eAAe,GAAG;AAAG;AAAA,MAAQ,SAAS,GAAG;AAAA,MAAC;AAAA,IAAE;AACjF,WAAO;AAAA,EACT;AAYA,iBAAe,oBAAoB,SAAS;AAC1C,QAAI,OAAO,YAAY,YAAY,CAAC,QAAQ,KAAK,EAAG,OAAM,IAAI,MAAM,wDAAW;AAC/E,QAAI,IAAI,OAAO,OAAO,EAAE,KAAK;AAC7B,QAAI,EAAE,WAAW,IAAI,EAAG,KAAIX,MAAKC,SAAQ,GAAG,EAAE,MAAM,CAAC,CAAC;AACtD,QAAI,CAAC,WAAW,CAAC,EAAG,KAAID,MAAKC,SAAQ,GAAG,CAAC;AACzC,QAAI,YAAY;AAChB,QAAI;AAAE,kBAAY,MAAM,SAAS,CAAC;AAAA,IAAE,SAAS,GAAG;AAAE,kBAAY;AAAA,IAAK;AACnE,QAAI,cAAc,MAAM;AACtB,YAAMI,OAAM,GAAG,EAAE,WAAW,KAAK,CAAC;AAClC,kBAAY,MAAM,SAAS,CAAC;AAAA,IAC9B;AACA,WAAO,EAAE,WAAW,QAAQ,MAAM,EAAE,OAAO,WAAWO,UAAS,SAAS,KAAK,WAAW,EAAE;AAAA,EAC5F;AAEA,iBAAe,QAAQ,KAAK,YAAY;AACtC,sBAAkB,cAAc,MAAM;AAOtC,UAAM,WAAW,mBAAmB,GAAG;AACvC,QAAI,YAAY,QAAQ,OAAO,QAAQ,MAAM,OAAO,GAAG,GAAG;AACxD,YAAM,IAAI,MAAM,wJAA2B;AAAA,IAC7C;AACA,UAAM,IAAI,MAAM,YAAY,YAAY,KAAK,CAAC;AAC9C,QAAI,CAAC,KAAK,CAAC,EAAE,KAAM,OAAM,IAAI,MAAM,8DAAY;AAC/C,UAAM,OAAO,EAAE;AACf,UAAM,SAAS,EAAE;AACjB,UAAM,SAAS,KAAK,OAAO;AAE3B,UAAM,EAAE,WAAW,QAAQ,OAAO,IAAI,MAAM,oBAAoB,UAAU;AAE1E,QAAI,QAAQ;AACV,UAAI,WAAW;AACf,UAAI;AAAE,mBAAW,MAAM,SAAS,MAAM;AAAA,MAAE,SAAS,GAAG;AAAE,mBAAW;AAAA,MAAK;AACtE,UAAI,aAAa,WAAW;AAC1B,eAAO,EAAE,IAAI,MAAM,SAAS,MAAM,aAAa,OAAO,IAAI,gBAAgB,OAAO,MAAM;AAAA,MACzF;AAAA,IACF;AAEA,UAAM,YAAY,OAAO,OAAO,CAAC,GAAG,MAAM,EAAE,KAAK,UAAU,CAAC;AAa5D,UAAM,OAAO,IAAI,IAAI,UAAU;AAC/B,UAAM,UAAU,QAAQ,KAAK,OAAO,KAAK,IAAI,GAAG;AAChD,UAAM,SAAS,CAAC,CAAC;AAEjB,UAAM,oBAAoB;AAK1B,UAAM,cAAc,OAAO,QAAQ,iBAAiB;AAClD,YAAM,UAAU,WAAW,MAAM;AACjC,YAAM,UAAU,WAAW,YAAY;AACvC,UAAI,CAAC,WAAW,CAAC,WAAW,YAAY,QAAS,QAAO;AACxD,YAAM,aAAa,GAAG,OAAO,gBAAgB,KAAK,IAAI,CAAC;AACvD,YAAM,aAAa,GAAG,OAAO,eAAe,QAAQ,GAAG,IAAI,KAAK,IAAI,CAAC;AACrE,UAAI,uBAAuB;AAC3B,UAAI;AAIF,cAAMP,OAAMQ,SAAQ,OAAO,GAAG,EAAE,WAAW,KAAK,CAAC;AACjD,YAAI;AACF,gBAAMV,MAAK,OAAO;AAClB,gBAAM,IAAI,MAAM,8GAAoB;AAAA,QACtC,SAAS,GAAG;AACV,cAAI,KAAK,EAAE,SAAS,SAAU,OAAM;AAAA,QACtC;AACA,cAAMI,QAAO,SAAS,UAAU;AAChC,cAAM,WAAW,MAAMO,UAAS,UAAU;AAC1C,cAAM,iBAAiB,eAAe,QAAQ,EAAE;AAChD,YAAI,eAAe,WAAW,EAAG,OAAM,IAAI,MAAM,8GAAyB;AAC1E,cAAM,YAAY,yBAAyB,UAAU,SAAS;AAC9D,cAAM,kBAAkB,eAAe,SAAS,EAAE;AAClD,YAAI,gBAAgB,WAAW,eAAe,OAAQ,OAAM,IAAI,MAAM,8GAAoB;AAC1F,cAAM,eAAe,SAAS,SAAS,eAAe,CAAC,EAAE,GAAG;AAC5D,cAAM,gBAAgB,UAAU,SAAS,gBAAgB,CAAC,EAAE,GAAG;AAC/D,YAAI,CAAC,aAAa,OAAO,aAAa,EAAG,OAAM,IAAI,MAAM,8GAAoB;AAC7E,cAAMR,WAAU,YAAY,WAAW,EAAE,MAAM,IAAM,CAAC;AACtD,cAAMC,QAAO,YAAY,OAAO;AAChC,+BAAuB;AACvB,cAAMI,QAAO,UAAU;AAAA,MACzB,SAAS,GAAG;AACV,YAAI;AAAE,gBAAMA,QAAO,UAAU;AAAA,QAAE,SAAS,GAAG;AAAA,QAAC;AAC5C,YAAI,sBAAsB;AAAE,cAAI;AAAE,kBAAMA,QAAO,OAAO;AAAA,UAAE,SAAS,GAAG;AAAA,UAAC;AAAA,QAAE;AACvE,YAAI;AAAE,gBAAMJ,QAAO,YAAY,OAAO;AAAA,QAAE,SAAS,GAAG;AAAA,QAAC;AACrD,YAAI,KAAK,EAAE,SAAS,SAAU,OAAM;AACpC,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT;AAEA,UAAM,aAAa,CAAC,WAAW;AAC7B,UAAI,KAAK;AACT,UAAI;AAAE,YAAI,OAAO,GAAG,WAAW,WAAY,MAAK,GAAG,OAAO,KAAK,EAAE;AAAA,MAAE,SAAS,GAAG;AAAA,MAAC;AAChF,UAAI,CAAC,MAAM,GAAG,WAAW,OAAO,GAAG,QAAQ,WAAW,WAAY,MAAK,GAAG,QAAQ,OAAO,KAAK,GAAG,OAAO;AACxG,UAAI,CAAC,GAAI,QAAO;AAChB,UAAI;AACF,cAAM,MAAM,GAAG,MAAM;AACrB,YAAI,OAAO,OAAO,IAAI,SAAS,SAAU,QAAO,IAAI;AACpD,YAAI,OAAO,QAAQ,SAAU,QAAO;AAAA,MACtC,SAAS,GAAG;AAAA,MAAC;AACb,aAAO;AAAA,IACT;AAOA,QAAI,YAAY,SAAS,kBAAkB;AAIzC,YAAM,QAAQ,MAAM,YAAY,YAAY,GAAG;AAC/C,UAAI,SAAS,MAAM,UAAU;AAC3B,cAAMQ,SAAQ,MAAM,YAAY,YAAY,GAAG;AAC/C,YAAIA,UAASA,OAAM,aAAa,MAAM,UAAU;AAC9C,gBAAM,IAAI,MAAM,sIAAwB;AAAA,QAC1C;AAAA,MACF;AACA,UAAI;AACF,cAAM,iBAAiB,EAAE,IAAI,KAAK,QAAQ,MAAM,WAAW,QAAQ,qBAAqB,EAAE,oBAAoB,CAAC;AAAA,MACjH,SAAS,GAAG;AACV,YAAI,KAAK,EAAE,OAAQ,OAAM;AACzB,cAAM,IAAI,MAAM,2DAAc,OAAQ,KAAK,EAAE,WAAY,CAAC,CAAC;AAAA,MAC7D;AAAA,IACF,WAAW,QAAQ;AAOjB,UAAI,CAAC,MAAM,YAAY,MAAM,SAAS,EAAG,OAAM,IAAI,MAAM,sIAAwB;AAEjF,UAAI;AACF,cAAM,KAAK,GAAG,UAAU,GAAG,OAAO,OAAO,GAAG,OAAO,IAAI,GAAG;AAC1D,YAAI,MAAM,GAAG,KAAM,IAAG,OAAO,OAAO,OAAO,CAAC,GAAG,GAAG,MAAM,EAAE,KAAK,UAAU,CAAC;AAAA,MAC5E,SAAS,GAAG;AAAA,MAAoB;AAAA,IAClC,OAAO;AAOL,UAAI,UAAU;AACd,UAAI;AACF,cAAM,MAAM,WAAW,IAAI;AAC3B,YAAI,OAAO,OAAO,QAAQ,SAAU,WAAU;AAAA,iBACrC,OAAO,IAAI,KAAM,WAAU,IAAI;AAAA,MAC1C,SAAS,GAAG;AAAE,kBAAU;AAAA,MAAK;AAE7B,UAAI,OAAO,GAAG,WAAW,cAAc,OAAO,GAAG,WAAW,YAAY;AAEtE,YAAI,CAAC,MAAM,YAAY,MAAM,SAAS,EAAG,OAAM,IAAI,MAAM,sIAAwB;AAAA,MACnF,OAAO;AACL,cAAM,aAAa,UAAU,GAAG,OAAO,gBAAgB,KAAK,IAAI,CAAC,KAAK;AACtE,YAAI,YAAY;AAAE,cAAI;AAAE,kBAAMR,QAAO,SAAS,UAAU;AAAA,UAAE,SAAS,GAAG;AAAE,gBAAI,KAAK,EAAE,SAAS,SAAU,OAAM,IAAI,MAAM,4FAAiB;AAAA,UAAE;AAAA,QAAE;AAC3I,cAAM,UAAU,YAAY;AAAE,cAAI,YAAY;AAAE,gBAAI;AAAE,oBAAMA,QAAO,YAAY,OAAO;AAAA,YAAE,SAAS,GAAG;AAAA,YAAC;AAAA,UAAE;AAAA,QAAE;AACzG,YAAI;AACF,gBAAM,GAAG,OAAO,SAAS;AACzB,gBAAM,GAAG,OAAO,KAAK,MAAM;AAC3B,gBAAM,QAAQ,MAAM,YAAY,YAAY,KAAK,CAAC;AAClD,cAAI,CAAC,SAAS,CAAC,MAAM,QAAQ,MAAM,KAAK,QAAQ,WAAW;AACzD,kBAAM,IAAI,MAAM,oHAAqB;AAAA,UACvC;AACA,cAAI,YAAY;AAAE,gBAAI;AAAE,oBAAMI,QAAO,UAAU;AAAA,YAAE,SAAS,GAAG;AAAA,YAAC;AAAA,UAAE;AAAA,QAClE,SAAS,GAAG;AACV,cAAI,kBAAkB,KAAK,OAAQ,KAAK,EAAE,WAAY,CAAC,CAAC,GAAG;AAGzD,kBAAM,QAAQ;AACd,gBAAI,CAAC,MAAM,YAAY,MAAM,SAAS,EAAG,OAAM,IAAI,MAAM,sIAAwB;AAAA,UACnF,OAAO;AACL,kBAAM,QAAQ;AACd,kBAAM,IAAI,MAAM,2DAAc,OAAQ,KAAK,EAAE,WAAY,CAAC,CAAC;AAAA,UAC7D;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAOA,QAAI;AACF,UAAI,SAAS;AACX,YAAI,YAAY,QAAS,SAAQ,SAAS;AAC1C,YAAI,SAAS,QAAS,SAAQ,MAAM;AACpC,YAAI,UAAU,QAAS,SAAQ,OAAO;AAAA,MACxC;AAAA,IACF,SAAS,GAAG;AAAA,IAAoB;AAGhC,eAAW,OAAO,EAAE,KAAK,GAAG;AAC1B,UAAI;AAAE,cAAM,IAAI,cAAc,GAAG;AAAA,MAAE,SAAS,GAAG;AAAA,MAAe;AAAA,IAChE;AACA,QAAI,EAAE,WAAW,OAAO,EAAE,QAAQ,QAAQ,WAAY,GAAE,QAAQ,IAAI,KAAK,SAAS;AAClF,QAAI,EAAE,gBAAgB,OAAO,EAAE,aAAa,QAAQ,WAAY,GAAE,aAAa,IAAI,KAAK,SAAS;AACjG,UAAM,OAAO,cAAc,GAAG;AAO9B,UAAM,YAAY,MAAM;AACtB,UAAI;AAAE,eAAO,OAAO,WAAW,SAAS,GAAG;AAAA,MAAE,SAAS,GAAG;AAAE,eAAO;AAAA,MAAM;AAAA,IAC1E,GAAG;AACH,QAAI,CAAC,UAAU;AACb,YAAM,IAAI,MAAM,wKAAiC;AAAA,IACnD;AAEA,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,aAAa,OAAO;AAAA,MACpB,gBAAgB,OAAO;AAAA,MACvB,eAAe;AAAA,IACjB;AAAA,EACF;AAUA,iBAAe,kBAAkB;AAC/B,UAAM,MAAM;AACZ,QAAI,CAAC,OAAO,OAAO,IAAI,uBAAuB,WAAY,QAAO;AACjE,QAAI,UAAU;AACd,QAAI;AAAE,gBAAU,MAAM,YAAY,YAAY;AAAA,IAAE,SAAS,GAAG;AAAE,gBAAU;AAAA,IAAK;AAC7E,QAAI,CAAC,WAAW,CAAC,MAAM,QAAQ,OAAO,EAAG,QAAO;AAChD,UAAM,IAAI,mBAAmB,QAAQ,IAAI,CAAC,UAAU,MAAM,MAAM,CAAC;AACjE,QAAI,OAAO,IAAI,oBAAoB,WAAY,KAAI,gBAAgB;AACnE,WAAO;AAAA,EACT;AAEA,iBAAe,iBAAiB;AAC9B,UAAM,MAAM,CAAC;AACb,QAAI;AACF,iBAAW,OAAO,EAAE,KAAK,EAAG,KAAI,KAAK,EAAE,aAAa,IAAI,IAAI,OAAO,IAAI,OAAO,MAAM,IAAI,KAAK,CAAC;AAAA,IAChG,SAAS,GAAG;AAAA,IAAe;AAC3B,WAAO;AAAA,EACT;AAKA,iBAAe,WAAW,KAAK;AAC7B,qBAAiB,GAAG;AACpB,WAAO,eAAe,OAAO,SAAS;AACpC,UAAI,KAAK,SAAS,GAAG,EAAG,QAAO,EAAE,MAAM,MAAM,OAAO,EAAE,IAAI,MAAM,UAAU,MAAM,EAAE;AAClF,YAAM,EAAE,eAAe,GAAG;AAG1B,aAAO,EAAE,MAAM,MAAM,OAAO,EAAE,IAAI,MAAM,UAAU,KAAK,EAAE;AAAA,IAC3D,CAAC;AAAA,EACH;AAKA,iBAAe,cAAc,KAAK;AAChC,UAAM,MAAM,oBAAI,IAAI;AACpB,QAAI,CAAC,OAAO,CAAC,IAAI,OAAQ,QAAO;AAChC,QAAI,OAAO,GAAG,uBAAuB,WAAY,QAAO;AACxD,QAAI;AACF,YAAM,UAAU,MAAM,GAAG,mBAAmB,GAAG;AAC/C,UAAI,CAAC,MAAM,QAAQ,OAAO,EAAG,QAAO;AACpC,cAAQ,QAAQ,CAAC,QAAQ,UAAU;AACjC,cAAM,KAAK,OAAO,IAAI,KAAK,CAAC;AAC5B,YAAI,IAAI,IAAI,eAAe,MAAM,CAAC;AAAA,MACpC,CAAC;AAAA,IACH,SAAS,GAAG;AAAA,IAAkB;AAC9B,WAAO;AAAA,EACT;AAUA,iBAAe,wBAAwB,OAAO,CAAC,GAAG;AAChD,QAAI,UAAU,CAAC;AACf,QAAI,YAAY;AAChB,QAAI;AACF,gBAAU,MAAM,YAAY,YAAY;AACxC,kBAAY,MAAM,QAAQ,OAAO;AACjC,UAAI,CAAC,UAAW,WAAU,CAAC;AAAA,IAC7B,SAAS,GAAG;AAAE,gBAAU,CAAC;AAAA,IAAE;AAC3B,UAAM,YAAY,IAAI,IAAI,QAAQ,IAAI,CAAC,UAAU,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC;AACnE,QAAI,OAAO,IAAI,IAAI,UAAU;AAC7B,UAAM,MAAM,QAAQ,IAAI,CAAC,UAAU,MAAM,EAAE;AAC3C,QAAI,MAAM;AAAE,UAAI;AAAE,aAAK,KAAK,EAAE,QAAQ,CAAC,MAAM;AAAE,gBAAM,MAAM,OAAO,EAAE,EAAE;AAAG,cAAI,CAAC,IAAI,SAAS,GAAG,EAAG,KAAI,KAAK,GAAG;AAAA,QAAE,CAAC;AAAA,MAAE,SAAS,GAAG;AAAA,MAAe;AAAA,IAAE;AAK/I,QAAI,YAAY,oBAAI,IAAI;AACxB,QAAI;AACF,YAAM,QAAQ,MAAM,eAAe;AACnC,YAAM,UAAU,IAAI,IAAI,GAAG;AAC3B,kBAAY,oBAAI,IAAI;AAAA,QAClB,GAAG,MAAM,MAAM,IAAI,CAAC,MAAM,OAAO,EAAE,SAAS,CAAC;AAAA,QAC7C,GAAG,MAAM,iBAAiB,IAAI,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC;AAAA,MACvE,CAAC;AAAA,IACH,SAAS,GAAG;AAAA,IAAC;AACb,UAAM,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC,UAAU,IAAI,EAAE,CAAC;AACxD,eAAW,CAAC;AACZ,QAAI;AAAE,iBAAW,OAAO,EAAE,KAAK,EAAG,UAAS,IAAI,IAAI,IAAI;AAAA,IAAI,SAAS,GAAG;AAAE,iBAAW,CAAC;AAAA,IAAE;AACvF,UAAM,kBAAkB,IAAI,KAAK,MAAM,cAAc,EAAE,MAAM,OAAO,EAAE,oBAAoB,CAAC,EAAE,EAAE,GAAG,sBAAsB,CAAC,CAAC;AAC1H,UAAM,QAAQ,CAAC;AACf,UAAM,QAAQ,MAAM,aAAa,OAAO;AAExC,UAAM,YAAY,IAAI,IAAI,WAAW,IAAI,CAAC,OAAO;AAAA,MAC/C;AAAA,MACC,MAAM,aAAa,MAAM,UAAU,IAAI,EAAE,KAAM,EAAE,SAAS,MAAM,UAAU,IAAI,EAAE,GAAG,MAAM,MAAM,SAAS,IAAI,EAAE,EAAE;AAAA,IACnH,CAAC,CAAC;AACF,UAAM,EAAE,QAAQ,IAAI,UAAU,UAAU,YAAY,SAAS;AAE7D,UAAM,YAAY,MAAM,mBAAmB,SAAS,SAAS;AAC7D,eAAW,CAAC,IAAI,IAAI,KAAK,UAAW,WAAU,IAAI,IAAI,UAAU,IAAI,EAAE,GAAG,IAAI;AAC7E,UAAM,eAAe,QAAQ,OAAO,CAAC,OAAO,CAAC,UAAU,IAAI,EAAE,CAAC;AAC9D,UAAM,eAAe,MAAM,cAAc,YAAY;AACrD,UAAM,UAAU,oBAAI,IAAI;AACxB,UAAM,iBAAiB,CAAC,IAAI,SAAS;AAAE,cAAQ,IAAI,IAAI,IAAI;AAAA,IAAE;AAC7D,UAAM,QAAQ;AACd,aAAS,IAAI,GAAG,IAAI,WAAW,QAAQ,KAAK,OAAO;AAGjD,YAAM,OAAO,MAAM,QAAQ,IAAI,WAAW,MAAM,GAAG,IAAI,KAAK,EAAE,IAAI,CAAC,OAAO;AACxE,cAAM,QAAQ,UAAU,IAAI,EAAE;AAC9B,eAAO,WAAW,IAAI,OAAO;AAAA,UAC3B,aAAa,CAAC,EAAE,QAAQ,KAAK;AAAA,UAC7B,YAAY,QAAQ,MAAM,SAAS;AAAA,UACnC,WAAW,aAAa,IAAI,EAAE,IAAI,aAAa,IAAI,EAAE,IAAI;AAAA,UACzD;AAAA,QACF,CAAC;AAAA,MACH,CAAC,CAAC;AACF,iBAAW,MAAM,KAAM,OAAM,KAAK,EAAE,GAAG,IAAI,UAAU,gBAAgB,IAAI,GAAG,SAAS,EAAE,CAAC;AAAA,IAC1F;AACA,mBAAe,SAAS,SAAS;AAGjC,QAAI,aAAa,oBAAI,IAAI;AACzB,QAAI;AAAE,mBAAa,IAAI,KAAK,MAAM,MAAM,KAAK,GAAG,iBAAiB;AAAA,IAAE,SAAS,GAAG;AAAA,IAAC;AAChF,eAAW,MAAM,MAAO,IAAG,UAAU,WAAW,IAAI,OAAO,GAAG,SAAS,CAAC;AACxE,QAAI,UAAW,OAAM,QAAQ,GAAG;AAChC,WAAO,EAAE,OAAO,MAAM;AAAA,EACxB;AAEA,iBAAe,gBAAgB,OAAO,CAAC,GAAG;AACxC,YAAQ,MAAM,wBAAwB,IAAI,GAAG;AAAA,EAC/C;AAMA,iBAAe,aAAa,OAAO,CAAC,GAAG;AACrC,UAAM,QAAQ,MAAM,gBAAgB,EAAE,OAAO,KAAK,CAAC;AACnD,UAAM,MAAM,OAAO,QAAQ,KAAK,IAAI;AACpC,UAAM,OAAO,OAAO,UAAU,GAAG,KAAK,MAAM,IAAI,KAAK,IAAI,KAAK,eAAe,IAAI;AACjF,WAAO,iBAAiB,OAAO,EAAE,KAAK,CAAC;AAAA,EACzC;AAQA,iBAAe,iBAAiB,OAAO,CAAC,GAAG;AACzC,UAAM,QAAQ,MAAM,YAAY,KAAK;AACrC,UAAM,OAAO,MAAM,SAAS;AAC5B,QAAI,CAAC,KAAM,QAAO,EAAE,IAAI,MAAM,SAAS,YAAY,UAAU,EAAE;AAC/D,UAAM,MAAM,KAAK,IAAI;AACrB,QAAI,EAAE,QAAQ,KAAK,UAAU,YAAY,QAAQ,OAAO,GAAG,GAAG;AAC5D,aAAO,EAAE,IAAI,MAAM,SAAS,aAAa,UAAU,GAAG,WAAW,MAAM,WAAW,mBAAmB,MAAM,kBAAkB;AAAA,IAC/H;AACA,UAAM,EAAE,OAAO,MAAM,IAAI,MAAM,wBAAwB,EAAE,OAAO,KAAK,CAAC;AAItE,QAAI,CAAC,MAAM,iBAAiB;AAC1B,aAAO;AAAA,QACL,IAAI;AAAA,QAAM,SAAS;AAAA,QAAoB,UAAU;AAAA,QACjD,MAAM;AAAA,MACR;AAAA,IACF;AACA,UAAM,aAAa,uBAAuB,OAAO;AAAA,MAC/C,cAAc;AAAA,MACd,aAAa,MAAM,SAAS;AAAA,MAC5B,iBAAiB,mBAAmB,GAAG;AAAA,MACvC;AAAA,IACF,CAAC;AACD,QAAI,WAAW;AACf,UAAM,SAAS,CAAC;AAChB,eAAW,OAAO,YAAY;AAC5B,UAAI;AACF,cAAM,SAAS,MAAM,WAAW,GAAG;AACnC,YAAI,UAAU,OAAO,SAAU;AAAA,MACjC,SAAS,GAAG;AACV,eAAO,KAAK,EAAE,WAAW,KAAK,OAAO,OAAQ,KAAK,EAAE,WAAY,CAAC,EAAE,CAAC;AAAA,MACtE;AAAA,IACF;AACA,UAAM,YAAY,UAAU,UAAU,GAAG;AACzC,WAAO,EAAE,IAAI,MAAM,UAAU,YAAY,WAAW,QAAQ,QAAQ,WAAW,IAAI;AAAA,EACrF;AAOA,iBAAe,mBAAmB;AAChC,UAAM,MAAM,CAAC;AACb,QAAI,UAAU,CAAC;AACf,QAAI;AAAE,gBAAU,MAAM,YAAY,YAAY;AAAA,IAAE,SAAS,GAAG;AAAE,gBAAU,CAAC;AAAA,IAAE;AAC3E,QAAI,CAAC,MAAM,QAAQ,OAAO,EAAG,WAAU,CAAC;AACxC,eAAW,SAAS,QAAS,KAAI,KAAK,MAAM,EAAE;AAC9C,UAAM,WAAW,IAAI,IAAI,UAAU;AACnC,QAAI;AAAE,UAAI,SAAU,UAAS,KAAK,EAAE,QAAQ,CAAC,YAAY;AAAE,cAAM,MAAM,OAAO,QAAQ,EAAE;AAAG,YAAI,CAAC,IAAI,SAAS,GAAG,EAAG,KAAI,KAAK,GAAG;AAAA,MAAE,CAAC;AAAA,IAAE,SAAS,GAAG;AAAA,IAAC;AACjJ,UAAM,QAAQ,MAAM,eAAe;AAEnC,UAAM,UAAU,IAAI,IAAI,GAAG;AAC3B,UAAM,mBAAmB,MAAM,iBAAiB,IAAI,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC;AAC3F,QAAI,IAAI,QAAQ;AACd,YAAM,QAAQ,MAAM,aAAa,OAAO;AACxC,YAAM,YAAY,IAAI,IAAI,IAAI,IAAI,CAAC,OAAO;AAAA,QACxC;AAAA,QACC,MAAM,aAAa,MAAM,UAAU,IAAI,EAAE,KAAM,EAAE,SAAS,MAAM,UAAU,IAAI,EAAE,GAAG,MAAM,MAAM,SAAS,IAAI,EAAE,EAAE;AAAA,MACnH,CAAC,CAAC;AACF,YAAM,EAAE,QAAQ,QAAQ,IAAI,UAAU,UAAU,KAAK,SAAS;AAE9D,YAAM,YAAY,MAAM,mBAAmB,SAAS,SAAS;AAC7D,iBAAW,CAAC,IAAI,IAAI,KAAK,UAAW,WAAU,IAAI,IAAI,UAAU,IAAI,EAAE,GAAG,IAAI;AAC7E,YAAM,OAAO,QAAQ,OAAO,CAAC,OAAO,CAAC,UAAU,IAAI,EAAE,CAAC;AACtD,YAAM,eAAe,MAAM,cAAc,IAAI;AAC7C,YAAM,UAAU,oBAAI,IAAI;AACxB,YAAM,iBAAiB,CAAC,IAAI,SAAS;AAAE,gBAAQ,IAAI,IAAI,IAAI;AAAA,MAAE;AAC7D,iBAAW,MAAM,KAAK;AACpB,YAAI,OAAO,OAAO,IAAI,EAAE,KAAK,UAAU,IAAI,EAAE,KAAK;AAClD,YAAI,CAAC,MAAM;AACT,gBAAM,QAAQ,QAAQ,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AAC7C,gBAAM,WAAW,aAAa,IAAI,EAAE,IAChC,aAAa,IAAI,EAAE,IAClB,OAAO,GAAG,sBAAsB,aAAa,MAAM,GAAG,kBAAkB,EAAE,EAAE,MAAM,MAAM,IAAI,IAAI;AACrG,gBAAM,OAAO,iBAAiB,QAAQ;AACtC,cAAI,SAAS,MAAM,QAAQ;AACzB,gBAAI,CAAC,KAAK,OAAO,OAAO,MAAM,OAAO,QAAQ,SAAU,MAAK,MAAM,MAAM,OAAO;AAC/E,gBAAI,CAAC,KAAK,aAAa,MAAM,OAAO,aAAa,KAAM,MAAK,YAAY,MAAM,OAAO;AAAA,UACvF;AACA,oBAAU,IAAI,IAAI,UAAU,IAAI,EAAE,GAAG,IAAI;AACzC,cAAI,UAAU,IAAI,EAAE,EAAG,gBAAe,IAAI,IAAI;AAC9C,iBAAO;AAAA,QACT;AACA,YAAI,QAAQ,KAAK,MAAO,qBAAoB,IAAI,IAAI,OAAO,KAAK,KAAK,CAAC;AAAA,MACxE;AACA,qBAAe,SAAS,SAAS;AAAA,IACnC;AACA,WAAO;AAAA,MACL,QAAQ,OAAO,YAAY,mBAAmB;AAAA,MAC9C,mBAAmB,MAAM,MAAM,IAAI,CAAC,SAAS,OAAO,KAAK,SAAS,CAAC;AAAA,MACnE,kBAAkB;AAAA,IACpB;AAAA,EACF;AAQA,iBAAe,aAAa,KAAK,QAAQ;AACvC,UAAM,WAAW,IAAI,IAAI,UAAU;AACnC,UAAM,OAAO,YAAY,SAAS,IAAI,GAAG;AACzC,QAAI,OAAO;AACX,QAAI,WAAW;AACf,UAAM,UAAU,oBAAI,IAAI;AACxB,UAAM,QAAQ;AAAA,MACZ,OAAO;AAAA,MAAG,OAAO;AAAA,MAAG,cAAc;AAAA,MAAG,mBAAmB;AAAA,MACxD,WAAW;AAAA,MAAG,aAAa;AAAA,MAAG,YAAY,CAAC;AAAA,MAAG,SAAS,CAAC;AAAA,IAC1D;AACA,UAAM,WAAW,oBAAI,IAAI;AACzB,UAAM,WAAW,oBAAI,IAAI;AAEzB,UAAM,SAAS,CAAC,OAAO;AACrB,UAAI,MAAM,OAAO,GAAG,SAAS,YAAY,GAAG,OAAO,SAAU,YAAW,GAAG;AAC3E,YAAM,IAAK,MAAM,GAAG,QAAQ,OAAO,GAAG,SAAS,WAAY,GAAG,OAAO,CAAC;AACtE,YAAM,OAAO,MAAM,GAAG;AACtB,cAAQ,MAAM;AAAA,QACZ,KAAK;AACH,cAAI,OAAO,EAAE,SAAS,SAAU,UAAS,IAAI,EAAE,IAAI;AACnD;AAAA,QACF,KAAK;AACH,cAAI,OAAO,EAAE,SAAS,SAAU,UAAS,IAAI,EAAE,IAAI;AACnD;AAAA,QACF,KAAK;AACH,gBAAM;AACN,cAAI,MAAM,QAAQ,EAAE,OAAO;AAAG,uBAAW,KAAK,EAAE,QAAS,KAAI,KAAK,EAAE,SAAS,QAAS,OAAM;AAAA;AAC5F;AAAA,QACF,KAAK;AACH,gBAAM;AACN;AAAA,QACF,KAAK,aAAa;AAChB,gBAAM;AACN,gBAAM,KAAK,OAAO,EAAE,SAAS,YAAY,EAAE,OAAO,EAAE,OAAO;AAC3D,gBAAM,WAAW,EAAE,KAAK,MAAM,WAAW,EAAE,KAAK,KAAK;AACrD,cAAI,cAAc,KAAK,EAAE,GAAG;AAC1B,gBAAI;AACJ,gBAAI;AACF,oBAAM,IAAI,OAAO,EAAE,cAAc,WAAW,KAAK,MAAM,EAAE,SAAS,IAAI,EAAE;AACxE,sBAAQ,OAAO,GAAG,UAAU,WAAW,EAAE,QAAQ,OAAO,GAAG,QAAQ,WAAW,EAAE,MAAM,OAAO,GAAG,MAAM,WAAW,EAAE,IAAI;AAAA,YACzH,SAAS,GAAG;AAAE,sBAAQ;AAAA,YAAU;AAChC,kBAAM,QAAQ,KAAK,EAAE,MAAM,IAAI,GAAI,SAAS,UAAU,KAAK,EAAE,MAAM,IAAI,CAAC,EAAG,CAAC;AAAA,UAC9E;AACA,cAAI,OAAO,WAAW,OAAO,QAAQ;AACnC,gBAAI;AACJ,gBAAI;AAAE,sBAAQ,OAAO,EAAE,cAAc,WAAW,KAAK,MAAM,EAAE,SAAS,IAAI,EAAE;AAAA,YAAU,SAAS,GAAG;AAAE;AAAA,YAAM;AAC1G,kBAAM,KAAK,SAAS,OAAO,MAAM,cAAc,YAAY,MAAM,YAAY,MAAM,YAAY;AAC/F,gBAAI,OAAO,UAAa,CAAC,QAAQ,IAAI,EAAE,EAAG,SAAQ,IAAI,IAAI,EAAE;AAAA,UAC9D;AACA;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,QAAI,SAAS,QAAQ;AACnB,aAAQ,QAAQ,KAAK,UAAW;AAChC,UAAI;AAAE,SAAC,MAAM,QAAQ,KAAK,MAAM,IAAI,CAAC,GAAG,KAAK,MAAM,IAAI,CAAC,GAAG,QAAQ,MAAM;AAAA,MAAE,SAAS,GAAG;AAAA,MAAc;AAAA,IACvG,OAAO;AACL,YAAM,UAAU,MAAM,YAAY,eAAe,KAAK,EAAE,QAAQ,UAAU,CAAC,UAAU;AAAE,mBAAW,MAAM,MAAO,QAAO,EAAE;AAAA,MAAE,EAAE,CAAC;AAC7H,UAAI,CAAC,WAAW,CAAC,QAAQ,KAAM,OAAM,IAAI,MAAM,kGAAkB;AACjE,aAAO,QAAQ;AAAA,IACjB;AACA,UAAM,QAAQ,SAAS;AACvB,UAAM,QAAQ,SAAS;AACvB,QAAI,YAAY;AAChB,QAAI,SAAS,QAAQ;AAGnB,UAAI;AACF,cAAMR,QAAO,MAAM,YAAY,YAAY,GAAG;AAC9C,YAAIA,SAAQ,OAAO,SAASA,MAAK,SAAS,EAAG,aAAYA,MAAK;AAAA,MAChE,SAAS,GAAG;AAAA,MAAqB;AAAA,IACnC;AACA,QAAI,cAAc,MAAM;AACtB,UAAI;AAGF,cAAM,MAAM,YAAY,OAAO,IAAI;AACnC,YAAI,OAAO,OAAO,IAAI,SAAS,YAAY,IAAI,MAAM;AACnD,gBAAM,KAAK,MAAMA,MAAK,IAAI,IAAI;AAC9B,cAAI,MAAM,OAAO,GAAG,SAAS,SAAU,aAAY,GAAG;AAAA,QACxD;AAAA,MACF,SAAS,GAAG;AAAE,oBAAY;AAAA,MAAK;AAAA,IACjC;AACA,QAAI,MAAM,QAAQ,SAAS,YAAa,OAAM,UAAU,MAAM,QAAQ,MAAM,GAAG,WAAW;AAC1F,UAAM,cAAc,CAAC,GAAG,QAAQ,QAAQ,CAAC,EAAE,MAAM,GAAG,YAAY,CAAC;AACjE,UAAM,SAAS,MAAM,QAAQ,IAAI,YAAY,IAAI,CAAC,CAAC,CAAC,MAAMA,MAAK,CAAC,EAAE,KAAK,MAAM,IAAI,EAAE,MAAM,MAAM,KAAK,CAAC,CAAC;AACtG,UAAM,QAAQ,YACX,OAAO,CAAC,GAAG,MAAM,OAAO,CAAC,CAAC,EAC1B,IAAI,CAAC,CAAC,MAAM,IAAI,OAAO,EAAE,MAAM,KAAK,EAAE,EACtC,MAAM,GAAG,SAAS;AAErB,UAAM,UAAU;AAAA,MACd,iBAAkB,QAAQ,OAAO,KAAK,kBAAkB,WAAY,KAAK,gBAAgB;AAAA,MACzF,UAAU,CAAC;AAAA,MACX,WAAW,CAAC;AAAA,IACd;AACA,UAAM,cAAc,oBAAI,IAAI;AAC5B,UAAM,cAAc,oBAAI,IAAI;AAC5B,QAAI;AACF,UAAI,OAAO,GAAG,SAAS,YAAY;AACjC,mBAAW,SAAS,MAAM,YAAY,YAAY,GAAG;AACnD,gBAAM,IAAI,MAAM;AAChB,cAAI,OAAO,EAAE,aAAa,MAAM,OAAO,GAAG,EAAG;AAC7C,cAAI,EAAE,WAAW,WAAY,aAAY,IAAI,EAAE,EAAE;AAAA,cAAQ,aAAY,IAAI,EAAE,EAAE;AAAA,QAC/E;AAAA,MACF;AAAA,IACF,SAAS,GAAG;AAAA,IAAoB;AAChC,QAAI,UAAU;AACZ,UAAI;AACF,iBAAS,KAAK,EAAE,QAAQ,CAAC,MAAM;AAC7B,cAAI,OAAO,EAAE,OAAO,aAAa,MAAM,OAAO,GAAG,EAAG;AACpD,cAAI,EAAE,OAAO,WAAW,WAAY,aAAY,IAAI,EAAE,EAAE;AAAA,cAAQ,aAAY,IAAI,EAAE,EAAE;AAAA,QACtF,CAAC;AAAA,MACH,SAAS,GAAG;AAAA,MAAoB;AAAA,IAClC;AACA,YAAQ,WAAW,CAAC,GAAG,WAAW;AAClC,YAAQ,YAAY,CAAC,GAAG,WAAW;AACnC,WAAO;AAAA,MACL,WAAW;AAAA,MACX;AAAA,MACA,WAAY,QAAQ,OAAO,KAAK,cAAc,WAAY,KAAK,YAAY;AAAA,MAC3E,WAAW,KAAK,IAAI,YAAY,GAAI,QAAQ,OAAO,KAAK,cAAc,WAAW,KAAK,YAAY,CAAE,KAAK;AAAA,MACzG;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,MAAI,OAAO,MAAM;AACf,UAAM,YAAY,CAAC;AAEnB,QAAI,OAAO,IAAI,OAAO,WAAY,WAAU,KAAK,IAAI,GAAG,iBAAiB,CAAC,SAAS,UAAU;AAC3F,UAAI,SAAS,MAAM,SAAS,mBAAmB,MAAM,QAAQ,OAAO,MAAM,KAAK,UAAU,UAAU;AACjG,4BAAoB,IAAI,OAAO,QAAQ,EAAE,GAAG,MAAM,KAAK,KAAK;AAAA,MAC9D;AAAA,IACF,CAAC,CAAC;AAEF,cAAU,KAAK,IAAI,UAAU,SAAS;AAAA,MACpC,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,OAAO,KAAK,QAAQ,KAAK,KAAK,YAAY;AAAA,IACrD,CAAC,CAAC;AAEF,cAAU,KAAK,IAAI,UAAU,SAAS;AAAA,MACpC,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,OAAO,KAAK,QAAQ;AAC3B,YAAI;AACF,gBAAM,QAAQ,MAAM,cAAc;AAClC,gBAAM,MAAM,MAAM,sBAAsB,CAAC;AAGzC,cAAI,eAAe,oBAAI,IAAI;AAC3B,cAAI,OAAO,IAAI,IAAI,UAAU;AAC7B,cAAI;AACF,kBAAM,UAAU,MAAM,YAAY,YAAY;AAC9C,2BAAe,IAAI,IAAI,QAAQ,IAAI,CAAC,UAAU,MAAM,EAAE,CAAC;AAAA,UACzD,SAAS,GAAG;AAAA,UAAoB;AAChC,gBAAM,aAAa,MAAM,eAAe;AAExC,gBAAM,UAAU,oBAAI,IAAI;AAAA,YACtB,GAAG;AAAA,YACH,GAAG,IAAI,IAAI,MAAM;AAAA,YACjB,GAAI,QAAQ,OAAO,KAAK,SAAS,aAAa,KAAK,KAAK,EAAE,IAAI,CAAC,MAAM,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC;AAAA,UACxF,CAAC;AACD,gBAAM,aAAa,WAAW,iBAAiB,IAAI,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC;AAC1F,gBAAM,SAAS,oBAAI,IAAI,CAAC,GAAG,WAAW,MAAM,IAAI,CAAC,SAAS,OAAO,KAAK,SAAS,CAAC,GAAG,GAAG,UAAU,CAAC;AACjG,gBAAM,SAAS,IAAI,IAAI,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,MAAM,aAAa,IAAI,EAAE,KAAM,QAAQ,KAAK,IAAI,EAAE,EAAG;AACjH,qBAAW,CAAC;AACZ,cAAI;AAAE,uBAAW,OAAO,EAAE,KAAK,EAAG,UAAS,IAAI,IAAI,IAAI;AAAA,UAAI,SAAS,GAAG;AAAE,uBAAW,CAAC;AAAA,UAAE;AACvF,gBAAM,QAAQ,CAAC;AACf,gBAAM,QAAQ;AACd,mBAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK,OAAO;AAC7C,kBAAM,OAAO,MAAM,QAAQ,IAAI,OAAO,MAAM,GAAG,IAAI,KAAK,EAAE,IAAI,CAAC,OAAO,WAAW,EAAE,CAAC,CAAC;AACrF,kBAAM,KAAK,MAAM,OAAO,IAAI;AAAA,UAC9B;AACA,eAAK,KAAK,EAAE,MAAM,CAAC;AAAA,QACrB,SAAS,GAAG;AACV,eAAK,KAAK,EAAE,OAAO,OAAQ,KAAK,EAAE,WAAY,CAAC,EAAE,GAAG,GAAG;AAAA,QACzD;AAAA,MACF;AAAA,IACF,CAAC,CAAC;AAEF,cAAU,KAAK,IAAI,UAAU,SAAS;AAAA,MACpC,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,OAAO,KAAK,QAAQ;AAC3B,YAAI;AACF,gBAAM,OAAO,MAAM,aAAa,GAAG;AACnC,gBAAM,MAAM,QAAQ,OAAO,KAAK,cAAc,WAAW,KAAK,YAAY;AAC1E,cAAI,CAAC,IAAK,QAAO,KAAK,KAAK,EAAE,IAAI,OAAO,OAAO,oBAAoB,GAAG,GAAG;AACzE,eAAK,KAAK,MAAM,WAAW,GAAG,CAAC;AAAA,QACjC,SAAS,GAAG;AACV,eAAK,KAAK,EAAE,IAAI,OAAO,OAAO,OAAQ,KAAK,EAAE,WAAY,CAAC,EAAE,GAAG,YAAY,CAAC,CAAC;AAAA,QAC/E;AAAA,MACF;AAAA,IACF,CAAC,CAAC;AAEF,cAAU,KAAK,IAAI,UAAU,SAAS;AAAA,MACpC,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,OAAO,KAAK,QAAQ;AAC3B,YAAI;AACF,gBAAM,OAAO,MAAM,aAAa,GAAG;AACnC,gBAAM,MAAM,SAAS,IAAI;AACzB,cAAI,CAAC,OAAO,IAAI,WAAW,EAAG,QAAO,KAAK,KAAK,EAAE,IAAI,OAAO,OAAO,qBAAqB,GAAG,GAAG;AAC9F,gBAAM,UAAU,CAAC;AACjB,qBAAW,OAAO,KAAK;AACrB,gBAAI;AAAE,sBAAQ,KAAK,EAAE,WAAW,KAAK,IAAI,MAAM,GAAI,MAAM,WAAW,GAAG,EAAG,CAAC;AAAA,YAAE,SACtE,GAAG;AAAE,sBAAQ,KAAK,EAAE,WAAW,KAAK,IAAI,OAAO,MAAM,KAAK,EAAE,MAAM,OAAO,OAAQ,KAAK,EAAE,WAAY,CAAC,EAAE,CAAC;AAAA,YAAE;AAAA,UACnH;AACA,eAAK,KAAK,EAAE,IAAI,MAAM,UAAU,QAAQ,OAAO,CAAC,MAAM,EAAE,EAAE,EAAE,QAAQ,QAAQ,CAAC;AAAA,QAC/E,SAAS,GAAG;AACV,eAAK,KAAK,EAAE,IAAI,OAAO,MAAM,KAAK,EAAE,MAAM,OAAO,OAAQ,KAAK,EAAE,WAAY,CAAC,EAAE,GAAG,YAAY,CAAC,CAAC;AAAA,QAClG;AAAA,MACF;AAAA,IACF,CAAC,CAAC;AAEF,cAAU,KAAK,IAAI,UAAU,SAAS;AAAA,MACpC,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,OAAO,KAAK,QAAQ;AAC3B,YAAI;AACF,gBAAM,OAAO,MAAM,aAAa,GAAG;AACnC,gBAAM,MAAM,QAAQ,OAAO,KAAK,cAAc,WAAW,KAAK,YAAY;AAC1E,cAAI,CAAC,IAAK,QAAO,KAAK,KAAK,EAAE,IAAI,OAAO,OAAO,oBAAoB,GAAG,GAAG;AACzE,gBAAM,MAAM,MAAM,UAAU,GAAG;AAG/B,oBAAU,WAAW,GAAG;AACxB,eAAK,KAAK,GAAG;AAAA,QACf,SAAS,GAAG;AACV,eAAK,KAAK,EAAE,IAAI,OAAO,OAAO,OAAQ,KAAK,EAAE,WAAY,CAAC,EAAE,GAAG,YAAY,CAAC,CAAC;AAAA,QAC/E;AAAA,MACF;AAAA,IACF,CAAC,CAAC;AAEF,cAAU,KAAK,IAAI,UAAU,SAAS;AAAA,MACpC,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,OAAO,KAAK,QAAQ;AAC3B,YAAI;AACF,gBAAM,OAAO,MAAM,aAAa,GAAG;AACnC,gBAAM,MAAM,SAAS,IAAI;AACzB,cAAI,CAAC,OAAO,IAAI,WAAW,EAAG,QAAO,KAAK,KAAK,EAAE,IAAI,OAAO,OAAO,qBAAqB,GAAG,GAAG;AAC9F,gBAAM,UAAU,CAAC;AACjB,qBAAW,OAAO,KAAK;AACrB,gBAAI;AAAE,sBAAQ,KAAK,EAAE,WAAW,KAAK,IAAI,MAAM,GAAI,MAAM,UAAU,GAAG,EAAG,CAAC;AAAG,wBAAU,WAAW,GAAG;AAAA,YAAE,SAChG,GAAG;AAAE,sBAAQ,KAAK,EAAE,WAAW,KAAK,IAAI,OAAO,OAAO,OAAQ,KAAK,EAAE,WAAY,CAAC,EAAE,CAAC;AAAA,YAAE;AAAA,UAChG;AACA,eAAK,KAAK,EAAE,IAAI,MAAM,SAAS,QAAQ,OAAO,CAAC,MAAM,EAAE,EAAE,EAAE,QAAQ,QAAQ,CAAC;AAAA,QAC9E,SAAS,GAAG;AACV,eAAK,KAAK,EAAE,IAAI,OAAO,MAAM,KAAK,EAAE,MAAM,OAAO,OAAQ,KAAK,EAAE,WAAY,CAAC,EAAE,GAAG,YAAY,CAAC,CAAC;AAAA,QAClG;AAAA,MACF;AAAA,IACF,CAAC,CAAC;AAGF,cAAU,KAAK,IAAI,UAAU,SAAS;AAAA,MACpC,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,OAAO,KAAK,QAAQ;AAC3B,YAAI;AACF,gBAAM,oBAAoB;AAC1B,gBAAM,OAAO,MAAM,UAAU;AAC7B,eAAK,KAAK,CAAC,GAAG,OAAO,EAAE,aAAa,MAAM,EAAE,aAAa,EAAE;AAC3D,gBAAM,QAAQ,MAAM,eAAe;AACnC,eAAK,KAAK,EAAE,eAAe,MAAM,eAAe,UAAU,MAAM,UAAU,kBAAkB,MAAM,kBAAkB,OAAO,KAAK,CAAC;AAAA,QACnI,SAAS,GAAG;AACV,eAAK,KAAK,EAAE,IAAI,OAAO,OAAO,OAAQ,KAAK,EAAE,WAAY,CAAC,EAAE,GAAG,YAAY,CAAC,CAAC;AAAA,QAC/E;AAAA,MACF;AAAA,IACF,CAAC,CAAC;AAEF,cAAU,KAAK,IAAI,UAAU,SAAS;AAAA,MACpC,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,OAAO,KAAK,QAAQ;AAC3B,YAAI;AACF,gBAAM,OAAO,MAAM,aAAa,GAAG;AACnC,gBAAM,WAAW,QAAQ,OAAO,UAAU,eAAe,KAAK,MAAM,eAAe,IAC/E,MAAM,cAAc,EAAE,eAAe,KAAK,cAAc,CAAC,IACzD,MAAM,cAAc;AACxB,eAAK,KAAK,EAAE,IAAI,MAAM,SAAS,CAAC;AAAA,QAClC,SAAS,GAAG;AACV,eAAK,KAAK,EAAE,IAAI,OAAO,OAAO,OAAQ,KAAK,EAAE,WAAY,CAAC,EAAE,GAAG,YAAY,CAAC,CAAC;AAAA,QAC/E;AAAA,MACF;AAAA,IACF,CAAC,CAAC;AAEF,cAAU,KAAK,IAAI,UAAU,SAAS;AAAA,MACpC,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,OAAO,KAAK,QAAQ;AAC3B,YAAI;AACF,gBAAM,QAAQ,MAAM,UAAU;AAC9B,gBAAM,UAAU,MAAM,QAAQ,IAAI,MAAM,IAAI,OAAO,SAAS;AAC1D,gBAAI,OAAO,KAAK,iBAAiB,YAAY,CAAC,KAAK,cAAc;AAC/D,qBAAO,EAAE,WAAW,KAAK,WAAW,QAAQ,cAAc,cAAc,KAAK;AAAA,YAC/E;AACA,kBAAM,SAAS,MAAMA,MAAK,KAAK,YAAY,EAAE,KAAK,MAAM,IAAI,EAAE,MAAM,MAAM,KAAK;AAC/E,mBAAO,EAAE,WAAW,KAAK,WAAW,QAAQ,SAAS,OAAO,WAAW,cAAc,KAAK,aAAa;AAAA,UACzG,CAAC,CAAC;AACF,eAAK,KAAK;AAAA,YACR,IAAI;AAAA,YACJ,SAAS,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,IAAI,EAAE;AAAA,YAClD,SAAS,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,SAAS,EAAE;AAAA,YACvD,YAAY,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,YAAY,EAAE;AAAA,YAC7D;AAAA,UACF,CAAC;AAAA,QACH,SAAS,GAAG;AACV,eAAK,KAAK,EAAE,IAAI,OAAO,OAAO,OAAQ,KAAK,EAAE,WAAY,CAAC,EAAE,GAAG,YAAY,CAAC,CAAC;AAAA,QAC/E;AAAA,MACF;AAAA,IACF,CAAC,CAAC;AAEF,cAAU,KAAK,IAAI,UAAU,SAAS;AAAA,MACpC,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,OAAO,KAAK,QAAQ;AAC3B,YAAI;AACF,gBAAM,OAAO,MAAM,aAAa,GAAG;AACnC,gBAAM,MAAM,QAAQ,OAAO,KAAK,cAAc,WAAW,KAAK,YAAY;AAC1E,cAAI,CAAC,IAAK,QAAO,KAAK,KAAK,EAAE,IAAI,OAAO,OAAO,oBAAoB,GAAG,GAAG;AACzE,gBAAM,MAAM,MAAM,iBAAiB,GAAG;AACtC,oBAAU,WAAW,GAAG;AACxB,eAAK,KAAK,GAAG;AAAA,QACf,SAAS,GAAG;AACV,eAAK,KAAK,EAAE,IAAI,OAAO,MAAM,KAAK,EAAE,MAAM,OAAO,OAAQ,KAAK,EAAE,WAAY,CAAC,EAAE,GAAG,YAAY,CAAC,CAAC;AAAA,QAClG;AAAA,MACF;AAAA,IACF,CAAC,CAAC;AAEF,cAAU,KAAK,IAAI,UAAU,SAAS;AAAA,MACpC,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,OAAO,KAAK,QAAQ;AAC3B,YAAI;AACF,gBAAM,OAAO,MAAM,aAAa,GAAG;AACnC,gBAAM,MAAM,QAAQ,OAAO,KAAK,cAAc,WAAW,KAAK,YAAY;AAC1E,cAAI,CAAC,IAAK,QAAO,KAAK,KAAK,EAAE,IAAI,OAAO,OAAO,oBAAoB,GAAG,GAAG;AACzE,gBAAM,MAAM,MAAM,eAAe,GAAG;AACpC,oBAAU,WAAW,GAAG;AAExB,qBAAW,OAAO,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM;AAAA,UAAC,CAAC;AACvC,eAAK,KAAK,GAAG;AAAA,QACf,SAAS,GAAG;AACV,eAAK,KAAK,EAAE,IAAI,OAAO,MAAM,KAAK,EAAE,MAAM,OAAO,OAAQ,KAAK,EAAE,WAAY,CAAC,EAAE,GAAG,YAAY,CAAC,CAAC;AAAA,QAClG;AAAA,MACF;AAAA,IACF,CAAC,CAAC;AAEF,cAAU,KAAK,IAAI,UAAU,SAAS;AAAA,MACpC,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,OAAO,KAAK,QAAQ;AAC3B,YAAI;AACF,gBAAM,OAAO,MAAM,aAAa,GAAG;AACnC,gBAAM,MAAM,SAAS,IAAI;AACzB,cAAI,CAAC,OAAO,IAAI,WAAW,EAAG,QAAO,KAAK,KAAK,EAAE,IAAI,OAAO,OAAO,qBAAqB,GAAG,GAAG;AAC9F,gBAAM,UAAU,CAAC;AACjB,qBAAW,OAAO,KAAK;AACrB,gBAAI;AAAE,sBAAQ,KAAK,EAAE,WAAW,KAAK,IAAI,MAAM,GAAI,MAAM,eAAe,GAAG,EAAG,CAAC;AAAG,wBAAU,WAAW,GAAG;AAAG,yBAAW,OAAO,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM;AAAA,cAAC,CAAC;AAAA,YAAE,SAC/I,GAAG;AAAE,sBAAQ,KAAK,EAAE,WAAW,KAAK,IAAI,OAAO,OAAO,OAAQ,KAAK,EAAE,WAAY,CAAC,EAAE,CAAC;AAAA,YAAE;AAAA,UAChG;AACA,eAAK,KAAK,EAAE,IAAI,MAAM,QAAQ,QAAQ,OAAO,CAAC,MAAM,EAAE,EAAE,EAAE,QAAQ,QAAQ,CAAC;AAAA,QAC7E,SAAS,GAAG;AACV,eAAK,KAAK,EAAE,IAAI,OAAO,MAAM,KAAK,EAAE,MAAM,OAAO,OAAQ,KAAK,EAAE,WAAY,CAAC,EAAE,GAAG,YAAY,CAAC,CAAC;AAAA,QAClG;AAAA,MACF;AAAA,IACF,CAAC,CAAC;AAGF,cAAU,KAAK,IAAI,UAAU,SAAS;AAAA,MACpC,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,OAAO,KAAK,QAAQ;AAC3B,YAAI;AACF,eAAK,KAAK,EAAE,OAAO,MAAM,gBAAgB,EAAE,CAAC;AAAA,QAC9C,SAAS,GAAG;AACV,eAAK,KAAK,EAAE,OAAO,OAAQ,KAAK,EAAE,WAAY,CAAC,EAAE,GAAG,GAAG;AAAA,QACzD;AAAA,MACF;AAAA,IACF,CAAC,CAAC;AAGF,cAAU,KAAK,IAAI,UAAU,SAAS;AAAA,MACpC,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,OAAO,KAAK,QAAQ;AAC3B,YAAI;AACF,gBAAM,OAAO,MAAM,aAAa,GAAG;AACnC,gBAAM,UAAU,CAAC,EAAE,QAAQ,KAAK;AAChC,cAAI,MAAM,SAAS,IAAI;AACvB,eAAK,CAAC,OAAO,IAAI,WAAW,MAAM,QAAQ,OAAO,KAAK,cAAc,UAAU;AAC5E,kBAAMD,iBAAgB,KAAK,SAAS,IAAI,CAAC,KAAK,SAAS,IAAI;AAAA,UAC7D;AACA,cAAI,CAAC,OAAO,IAAI,WAAW,EAAG,QAAO,KAAK,KAAK,EAAE,IAAI,OAAO,OAAO,oBAAoB,GAAG,GAAG;AAC7F,gBAAM,oBAAoB,MAAM,MAAM,WAAW,KAAK,OAAO;AAC7D,eAAK,KAAK,EAAE,IAAI,MAAM,kBAAkB,CAAC;AAAA,QAC3C,SAAS,GAAG;AACV,eAAK,KAAK,EAAE,IAAI,OAAO,OAAO,OAAQ,KAAK,EAAE,WAAY,CAAC,EAAE,GAAG,YAAY,CAAC,CAAC;AAAA,QAC/E;AAAA,MACF;AAAA,IACF,CAAC,CAAC;AASF,UAAM,gBAAgB,cAAc,CAAC;AACrC,cAAU,KAAK,IAAI,UAAU,SAAS;AAAA,MACpC,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,OAAO,KAAK,QAAQ;AAC3B,YAAI;AACF,gBAAM,MAAM,IAAI,IAAI,IAAI,KAAK,kBAAkB;AAC/C,gBAAM,MAAM,IAAI,aAAa,IAAI,WAAW;AAC5C,2BAAiB,GAAG;AACpB,gBAAM,KAAK,IAAI,gBAAgB;AAC/B,cAAI,GAAG,SAAS,MAAM;AAAE,gBAAI,CAAC,IAAI,cAAe,IAAG,MAAM;AAAA,UAAE,CAAC;AAC5D,gBAAM,KAAK,MAAM,cAAc,YAAY;AACzC,kBAAM,UAAU,6BAA6B,EAAE,IAAI,IAAI,CAAC;AACxD,kBAAM,UAAU,MAAM,YAAY,eAAe,KAAK;AAAA,cACpD,QAAQ,GAAG;AAAA,cACX,UAAU,CAAC,UAAU,QAAQ,UAAU,KAAK;AAAA,YAC9C,CAAC;AACD,gBAAI,CAAC,WAAW,CAAC,QAAQ,MAAM;AAC7B,oBAAM,QAAQ,IAAI,MAAM,8DAAY;AACpC,oBAAM,SAAS;AACf,oBAAM;AAAA,YACR;AAEA,mBAAO,QAAQ,OAAO,EAAE,GAAG,QAAQ,MAAM,IAAI,IAAI,CAAC;AAAA,UACpD,CAAC;AACD,cAAI,UAAU,KAAK;AAAA,YACjB,gBAAgB;AAAA,YAChB,uBAAuB,qCAAqC,GAAG;AAAA,YAC/D,iBAAiB;AAAA,UACnB,CAAC;AACD,cAAI,IAAI,EAAE;AAAA,QACZ,SAAS,GAAG;AACV,eAAK,KAAK,EAAE,OAAO,OAAQ,KAAK,EAAE,WAAY,CAAC,EAAE,GAAG,YAAY,CAAC,CAAC;AAAA,QACpE;AAAA,MACF;AAAA,IACF,CAAC,CAAC;AAEF,cAAU,KAAK,IAAI,UAAU,SAAS;AAAA,MACpC,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,OAAO,KAAK,QAAQ;AAC3B,YAAI;AACF,eAAK,KAAK,MAAM,iBAAiB,CAAC;AAAA,QACpC,SAAS,GAAG;AACV,eAAK,KAAK,EAAE,OAAO,OAAQ,KAAK,EAAE,WAAY,CAAC,EAAE,GAAG,YAAY,CAAC,CAAC;AAAA,QACpE;AAAA,MACF;AAAA,IACF,CAAC,CAAC;AAGF,cAAU,KAAK,IAAI,UAAU,SAAS;AAAA,MACpC,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,OAAO,KAAK,QAAQ;AAC3B,YAAI;AACF,eAAK,KAAK,EAAE,OAAO,MAAM,eAAe,EAAE,CAAC;AAAA,QAC7C,SAAS,GAAG;AACV,eAAK,KAAK,EAAE,OAAO,OAAQ,KAAK,EAAE,WAAY,CAAC,EAAE,GAAG,GAAG;AAAA,QACzD;AAAA,MACF;AAAA,IACF,CAAC,CAAC;AAGF,cAAU,KAAK,IAAI,UAAU,SAAS;AAAA,MACpC,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,OAAO,KAAK,QAAQ;AAC3B,YAAI;AACF,gBAAM,OAAO,MAAM,aAAa,GAAG;AACnC,gBAAM,MAAM,QAAQ,OAAO,KAAK,cAAc,WAAW,KAAK,YAAY;AAC1E,gBAAM,SAAS,QAAQ,OAAO,KAAK,eAAe,WAAW,KAAK,aAAa;AAC/E,cAAI,CAAC,IAAK,QAAO,KAAK,KAAK,EAAE,IAAI,OAAO,OAAO,oBAAoB,GAAG,GAAG;AACzE,cAAI,CAAC,OAAQ,QAAO,KAAK,KAAK,EAAE,IAAI,OAAO,OAAO,qBAAqB,GAAG,GAAG;AAC7E,gBAAM,QAAQ,MAAM,QAAQ,KAAK,MAAM;AAGvC,oBAAU,WAAW,GAAG;AAMxB,cAAI;AAAE,kBAAM,gBAAgB;AAAA,UAAE,SAAS,GAAG;AAAA,UAAoB;AAC9D,eAAK,KAAK,EAAE,WAAW,KAAK,GAAG,MAAM,CAAC;AAAA,QACxC,SAAS,GAAG;AACV,eAAK,KAAK,EAAE,IAAI,OAAO,MAAM,KAAK,EAAE,MAAM,OAAO,OAAQ,KAAK,EAAE,WAAY,CAAC,EAAE,GAAG,YAAY,CAAC,CAAC;AAAA,QAClG;AAAA,MACF;AAAA,IACF,CAAC,CAAC;AAGF,cAAU,KAAK,IAAI,UAAU,SAAS;AAAA,MACpC,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,OAAO,KAAK,QAAQ;AAC3B,YAAI;AACF,gBAAM,OAAO,MAAM,aAAa,GAAG;AACnC,gBAAM,MAAM,QAAQ,OAAO,KAAK,cAAc,WAAW,KAAK,YAAY;AAC1E,cAAI,CAAC,IAAK,QAAO,KAAK,KAAK,EAAE,IAAI,OAAO,OAAO,oBAAoB,GAAG,GAAG;AACzE,eAAK,KAAK,EAAE,WAAW,KAAK,GAAI,MAAM,WAAW,GAAG,EAAG,CAAC;AAAA,QAC1D,SAAS,GAAG;AACV,eAAK,KAAK,EAAE,IAAI,OAAO,OAAO,OAAQ,KAAK,EAAE,WAAY,CAAC,EAAE,GAAG,GAAG;AAAA,QACpE;AAAA,MACF;AAAA,IACF,CAAC,CAAC;AAGF,cAAU,KAAK,IAAI,UAAU,SAAS;AAAA,MACpC,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,OAAO,KAAK,QAAQ;AAC3B,YAAI;AACF,gBAAM,OAAO,MAAM,aAAa,GAAG;AACnC,gBAAM,MAAM,SAAS,IAAI;AACzB,cAAI,CAAC,OAAO,IAAI,WAAW,EAAG,QAAO,KAAK,KAAK,EAAE,IAAI,OAAO,OAAO,qBAAqB,GAAG,GAAG;AAC9F,gBAAM,UAAU,CAAC;AACjB,qBAAW,OAAO,KAAK;AACrB,gBAAI;AAAE,sBAAQ,KAAK,EAAE,WAAW,KAAK,IAAI,MAAM,GAAI,MAAM,WAAW,GAAG,EAAG,CAAC;AAAA,YAAE,SACtE,GAAG;AAAE,sBAAQ,KAAK,EAAE,WAAW,KAAK,IAAI,OAAO,OAAO,OAAQ,KAAK,EAAE,WAAY,CAAC,EAAE,CAAC;AAAA,YAAE;AAAA,UAChG;AACA,eAAK,KAAK,EAAE,IAAI,MAAM,UAAU,QAAQ,OAAO,CAAC,MAAM,EAAE,EAAE,EAAE,QAAQ,QAAQ,CAAC;AAAA,QAC/E,SAAS,GAAG;AACV,eAAK,KAAK,EAAE,IAAI,OAAO,OAAO,OAAQ,KAAK,EAAE,WAAY,CAAC,EAAE,GAAG,GAAG;AAAA,QACpE;AAAA,MACF;AAAA,IACF,CAAC,CAAC;AAIF,cAAU,KAAK,IAAI,UAAU,SAAS;AAAA,MACpC,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,OAAO,KAAK,QAAQ;AAC3B,YAAI;AACF,gBAAM,OAAO,MAAM,aAAa,GAAG;AACnC,gBAAM,MAAM,QAAQ,OAAO,KAAK,cAAc,WAAW,KAAK,YAAY;AAC1E,cAAI,CAAC,IAAK,QAAO,KAAK,KAAK,EAAE,IAAI,OAAO,OAAO,oBAAoB,GAAG,GAAG;AAEzE,gBAAM,KAAK,IAAI,gBAAgB;AAC/B,cAAI,GAAG,SAAS,MAAM;AAAE,gBAAI,CAAC,IAAI,cAAe,IAAG,MAAM;AAAA,UAAE,CAAC;AAC5D,eAAK,KAAK,MAAM,aAAa,KAAK,GAAG,MAAM,CAAC;AAAA,QAC9C,SAAS,GAAG;AACV,eAAK,KAAK,EAAE,OAAO,OAAQ,KAAK,EAAE,WAAY,CAAC,EAAE,GAAI,KAAK,EAAE,SAAU,EAAE,SAAS,GAAG;AAAA,QACtF;AAAA,MACF;AAAA,IACF,CAAC,CAAC;AAGF,cAAU,KAAK,IAAI,UAAU,SAAS;AAAA,MACpC,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,OAAO,KAAK,QAAQ;AAC3B,YAAI;AACF,gBAAM,OAAO,MAAM,aAAa,GAAG;AACnC,eAAK,KAAK,MAAM,aAAa,EAAE,MAAM,QAAQ,KAAK,KAAK,CAAC,CAAC;AAAA,QAC3D,SAAS,GAAG;AACV,eAAK,KAAK,EAAE,OAAO,OAAQ,KAAK,EAAE,WAAY,CAAC,EAAE,GAAG,GAAG;AAAA,QACzD;AAAA,MACF;AAAA,IACF,CAAC,CAAC;AAQF,cAAU,KAAK,IAAI,UAAU,SAAS;AAAA,MACpC,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,OAAO,KAAK,QAAQ;AAC3B,YAAI;AACF,gBAAM,OAAO,MAAM,aAAa,GAAG;AACnC,gBAAM,QAAQ,CAAC;AACf,cAAI,QAAQ,OAAO,UAAU,eAAe,KAAK,MAAM,cAAc,EAAG,OAAM,eAAe,KAAK;AAClG,cAAI,QAAQ,OAAO,UAAU,eAAe,KAAK,MAAM,aAAa,EAAG,OAAM,cAAc,KAAK;AAChG,gBAAM,UAAU,OAAO,KAAK,KAAK,EAAE,SAAS;AAC5C,gBAAM,WAAW,UACb,MAAM,YAAY,OAAO,KAAK,KAC7B,MAAM,YAAY,KAAK,GAAG;AAC/B,cAAI;AACJ,cAAI,SAAS;AAEX,oBAAQ,MAAM,iBAAiB;AAAA,UACjC,OAAO;AAGL,iBAAK,iBAAiB,EAAE,MAAM,MAAM;AAAA,YAAC,CAAC;AACtC,oBAAQ,EAAE,WAAW,KAAK;AAAA,UAC5B;AACA,gBAAM,QAAQ,MAAM,YAAY,KAAK;AACrC,eAAK,KAAK;AAAA,YACR,IAAI;AAAA,YACJ;AAAA,YACA,WAAW,MAAM;AAAA,YACjB,mBAAmB,MAAM;AAAA,YACzB;AAAA,UACF,CAAC;AAAA,QACH,SAAS,GAAG;AACV,eAAK,KAAK,EAAE,IAAI,OAAO,OAAO,OAAQ,KAAK,EAAE,WAAY,CAAC,EAAE,GAAG,YAAY,CAAC,CAAC;AAAA,QAC/E;AAAA,MACF;AAAA,IACF,CAAC,CAAC;AAGF,cAAU,KAAK,IAAI,UAAU,SAAS;AAAA,MACpC,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS,OAAO,KAAK,QAAQ;AAC3B,YAAI;AACF,gBAAM,QAAQ,MAAM,iBAAiB,EAAE,OAAO,KAAK,CAAC;AACpD,gBAAM,QAAQ,MAAM,YAAY,KAAK;AACrC,eAAK,KAAK,EAAE,IAAI,MAAM,GAAG,OAAO,UAAU,MAAM,UAAU,WAAW,MAAM,WAAW,mBAAmB,MAAM,kBAAkB,CAAC;AAAA,QACpI,SAAS,GAAG;AACV,eAAK,KAAK,EAAE,IAAI,OAAO,OAAO,OAAQ,KAAK,EAAE,WAAY,CAAC,EAAE,GAAG,GAAG;AAAA,QACpE;AAAA,MACF;AAAA,IACF,CAAC,CAAC;AAEF,WAAO,MAAM;AAAE,iBAAW,KAAK,UAAW,GAAE;AAAA,IAAE;AAAA,EAChD,GAAG,8BAA8B;AACnC;",
|
|
6
|
+
"names": ["mkdir", "readFile", "rename", "stat", "unlink", "writeFile", "basename", "dirname", "join", "readFileSync", "homedir", "name", "mkdir", "rename", "writeFile", "readFileSync", "homedir", "join", "isFresh", "stat", "mkdir", "rename", "writeFile", "join", "join", "join", "name", "join", "name", "mkdir", "readFile", "rename", "writeFile", "join", "closeQuietly", "readFile", "mkdir", "join", "writeFile", "rename", "join", "homedir", "isSafeSessionId", "stat", "readFileSync", "mkdir", "writeFile", "rename", "entry", "store", "error", "unlink", "basename", "dirname", "readFile", "stat2"]
|
|
7
7
|
}
|