dsh-sessions-manager 3.6.2 → 3.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +21 -10
- package/README.md +23 -12
- package/lib/client.js +990 -32
- package/lib/client.js.map +2 -2
- package/lib/index.js +921 -151
- package/lib/index.js.map +4 -4
- package/package.json +1 -1
- package/src/client/index.jsx +816 -33
- package/src/client/logic.js +285 -0
- package/src/empty-scan-index.js +118 -0
- package/src/index.js +340 -79
- package/src/lineage.js +18 -14
- package/src/move-notices.js +129 -0
- package/src/saved-filters.js +208 -0
- package/src/tag-index.js +308 -0
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/pending-moves.js", "../src/state-temp-sweep.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", "../src/lineage.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, readdir, realpath, rename, rm, 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 { createPendingMoveStore } from './pending-moves.js'\nimport { sweepStaleStateTemps } from './state-temp-sweep.js'\nimport { aggregateStorage } from './storage-stats.js'\nimport { createAutoArchiveStore, pickInactiveCandidates } from './auto-archive.js'\nimport { createSessionMetaCache, fingerprintOf, persistFingerprintOf } 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'\nimport { classifyLineage, isEmptyEventTypes, EMPTY_DECODE_LIMIT } from './lineage.js'\n\n// \u6784\u5EFA\u6307\u7EB9\uFF1Abuild.mjs \u4EE5 define \u5728\u7F16\u8BD1\u671F\u6CE8\u5165\uFF1B\u76F4\u63A5\u4EE5\u6E90\u7801\u8FD0\u884C\uFF08\u6D4B\u8BD5\uFF09\u65F6\u4E3A 'dev'\u3002\n// \u7528\u9014\uFF1Acapabilities \u5E26\u51FA buildStamp\uFF0C\u4E00\u773C\u5224\u65AD\u300C\u8FD0\u884C\u4E2D\u7684 host \u662F\u4E0D\u662F\u8FD9\u4EFD\u6784\u5EFA\u300D\u2014\u2014\n// \u63D2\u4EF6 host \u7AEF\u53EA\u5728\u5BBF\u4E3B\u542F\u52A8\u65F6\u52A0\u8F7D\u4E00\u6B21\uFF0C\u6539\u5B8C lib \u4E0D\u91CD\u542F\u5BBF\u4E3B\u7B49\u4E8E\u767D\u6539\u3002\nconst BUILD_STAMP = typeof __BUILD_STAMP__ !== 'undefined' ? __BUILD_STAMP__ : 'dev'\n\n\nexport const name = 'dsh-sessions-manager'\nexport const inject = ['webServer', 'workspaceRegistry', 'sessionPersistence', 'sessionQuery', 'storageDomain']\n\nconst MAX_TITLE = 80\n// \u63D2\u4EF6\u81EA\u6709\u72B6\u6001\u76EE\u5F55\uFF08\u661F\u6807 / \u81EA\u52A8\u5F52\u6863 / \u6807\u9898\u7D22\u5F15\u5171\u7528\uFF09\u3002\u4E0E star-index.js\u3001auto-archive.js\n// \u7684\u9ED8\u8BA4\u76EE\u5F55\u4FDD\u6301\u4E00\u81F4\uFF0C\u73AF\u5883\u53D8\u91CF\u540C\u540D\uFF0C\u4FBF\u4E8E\u6D4B\u8BD5\u6CE8\u5165\u3002\nconst STATE_DIR = process.env.DSH_SESSIONS_MANAGER_STAR_DIR || join(homedir(), '.dsh', 'sessions-manager')\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\n// foldTitle\uFF08v3.6.1 \u5220\u9664\u8DEF\u5F84\u7684\u515C\u5E95\u6298\u53E0\uFF09\u968F v3.6.2 #7 \u7684\u300C\u5220\u9664\u8DEF\u5F84\u96F6\u89E3\u7801\u300D\u4E00\u5E76\n// \u79FB\u9664\uFF1B\u6807\u9898\u6298\u53E0\u903B\u8F91\u7684\u6743\u5A01\u5B9E\u73B0\u73B0\u5728\u662F runtime \u6295\u5F71\uFF08src/index.js projectTitlesStatus\uFF09\u3002\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 // \u6301\u4E45\u7D22\u5F15\u53EA\u8BA4\u53EF\u8DE8\u91CD\u542F\u7684\u6307\u7EB9\uFF08legacy \u7684\u6587\u4EF6\u6307\u7EB9 / handle \u4E16\u4EE3\u7684 sz \u6307\u7EB9\uFF0C\n // \u89C1 session-meta-cache.persistFingerprintOf\u2014\u2014issue #8 \u4E4B\u524D handle \u4E16\u4EE3\n // \u4ECE\u4E0D\u843D\u76D8\uFF0C\u5BFC\u81F4\u6BCF\u6B21\u91CD\u542F\u90FD\u5168\u91CF\u91CD\u65B0\u89E3\u7801\uFF09\u3002\n const fp = persistFingerprintOf(stat)\n if (!fp) continue\n // v3.6.2 #1\uFF1Atitle \u4E3A null \u7684\u6761\u76EE\u5FC5\u987B\u662F\u300C\u6295\u5F71\u786E\u5B9E\u6210\u529F\u8FC7\u300D\uFF08resolved\uFF09\u624D\u53EF\u4FE1\u3002\n // v3.6.1 \u628A\u6295\u5F71\u5931\u8D25\u5F53\u7ED3\u679C\u843D\u76D8\u7684\u6C61\u67D3\u6761\u76EE\uFF08null \u6807\u9898\u3001\u65E0\u6807\u8BB0\uFF09\u5728\u8FD9\u91CC\u88AB\u4E22\u5F03\uFF0C\n // \u8C03\u7528\u65B9\u6309\u672A\u547D\u4E2D\u5904\u7406 \u2192 \u91CD\u65B0\u5165\u961F\u9884\u70ED\uFF0C\u7D22\u5F15\u81EA\u6108\u3002\n if (entry.fingerprint === fp && (entry.title || entry.resolved)) {\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\u56DE\u5199\u6301\u4E45\u7D22\u5F15\uFF08\u7D22\u5F15\u53EA\u662F\u52A0\u901F\u5668\uFF1A\u5199\u5931\u8D25\u4E0D\u5F71\u54CD\u54CD\u5E94\uFF0C\n // \u961F\u5217\u5185\u90E8\u5DF2\u4E32\u884C\u5316 + \u539F\u5B50\u66FF\u6362\uFF09\u3002**\u5FC5\u987B await** \u2014\u2014 \u5B83\u662F\u6301\u4E45\u5199\u5165\uFF0C\u6D6E\u52A8\u5199\u5165\u4F1A\u5728\n // \u8C03\u7528\u65B9/\u6D4B\u8BD5 teardown \u5DF2\u5F00\u59CB\u6E05\u7406\u72B6\u6001\u76EE\u5F55\u65F6\u843D\u5730\uFF08`ENOTEMPTY: rmdir .../state`\uFF09\uFF0C\n // \u4E14\"\u54CD\u5E94\u5DF2\u8FD4\u56DE\u4F46\u7D22\u5F15\u6CA1\u843D\u76D8\"\u65F6\u8FDB\u7A0B\u82E5\u6070\u597D\u9000\u51FA\u5C31\u4F1A\u4E22\u6761\u76EE\u3002\n // \u6307\u7EB9\u7528 persistFingerprintOf\uFF1Alegacy \u6587\u4EF6\u6307\u7EB9 + handle \u4E16\u4EE3 sz(sizeBytes) \u6307\u7EB9\n // \u90FD\u53EF\u8DE8\u91CD\u542F\uFF1Brev: \u6307\u7EB9\u4ECD\u88AB\u6392\u9664\uFF08\u5B9E\u4F8B\u5185 opaque token\uFF0Cissue #8\uFF09\u3002\n // v3.6.2 #1\uFF1Adecoded \u7684\u503C\u662F { meta, resolved } \u2014\u2014 resolved=false\uFF08\u6295\u5F71\u5931\u8D25\uFF09\n // \u7684\u6761\u76EE\u7EDD\u4E0D\u843D\u76D8\uFF1Bnull \u6807\u9898\u53EA\u6709 resolved=true \u624D\u5141\u8BB8\uFF08\u5426\u5219\u8BFB\u53D6\u7AEF\u4F1A\u5F53\u6C61\u67D3\u4E22\u5F03\uFF09\u3002\n async function persistDecoded(decoded, statsById) {\n if (!decoded || !decoded.size) return\n const batch = {}\n const now = Date.now()\n for (const [id, pack] of decoded) {\n if (!pack || !pack.resolved) continue\n const meta = pack.meta\n const fp = persistFingerprintOf(statsById.get(id))\n if (!fp) continue\n batch[id] = { title: meta.title, cwd: meta.cwd, createdAt: meta.createdAt, fingerprint: fp, updatedAt: now, resolved: 1 }\n }\n if (!Object.keys(batch).length) return\n try { await titleIndex.merge(batch) } catch (e) { /* \u7D22\u5F15\u5199\u5931\u8D25\u4E0D\u5F71\u54CD\u672C\u6B21\u54CD\u5E94 */ }\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 \u2192 issue #8\uFF09\uFF1Aruntime \u7684\u6807\u9898\u6295\u5F71\uFF08readTitleSnapshots\uFF09\n // \u5728 0.1.x \u4E0A\u5BF9\u6BCF\u6761\u975E live \u4F1A\u8BDD\u90FD\u662F**\u6574\u672C\u65E5\u5FD7\u89E3\u7801**\uFF08SessionCorpus.projectMany\n // \u2192 inspectPersisted\uFF09\u3002\u5217\u8868\u6784\u5EFA\u7EDD\u4E0D\u80FD\u5728\u8BF7\u6C42\u8DEF\u5F84\u4E0A\u540C\u6B65\u89E6\u53D1\u5B83\u2014\u2014issue #8 \u5B9E\u6D4B\uFF1A\n // 87 \u672C\u65E5\u5FD7 / 249MB \u7684\u5E93\uFF0C\u4E00\u6B21\u51B7\u542F\u52A8\u5168\u91CF\u6295\u5F71\u628A\u5BBF\u4E3B\u6253\u6EE1 ~90s CPU\u3002\n //\n // \u56E0\u6B64\u8BF7\u6C42\u8DEF\u5F84\u53EA\u6D88\u8D39\u4E24\u7EA7\u7F13\u5B58\uFF08metaCache \u5185\u5B58\u7F13\u5B58 \u2192 titleIndex \u6301\u4E45\u7D22\u5F15\uFF09\uFF0C\n // \u7F3A\u5931\u7684\u4F1A\u8BDD\u4EA4\u7ED9\u540E\u53F0\u9884\u70ED\u961F\u5217\u5206\u6279\u8865\u9F50\uFF08\u89C1 enqueueWarm/runWarm\uFF09\uFF1B\u4FA7\u680F\u9AD8\u9891\n // \u8F6E\u8BE2 + \u7BA1\u7406\u9762\u677F\u5237\u65B0\u4F1A\u8BA9\u8865\u9F50\u7ED3\u679C\u81EA\u7136\u6D6E\u73B0\u3002\n const EMPTY_META = { title: null, cwd: null, createdAt: null }\n\n // \u2014\u2014 \u51B7\u542F\u52A8\u540E\u53F0\u9884\u70ED\uFF08issue #8\uFF09\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\n // \u5355\u98DE\u961F\u5217\uFF1A\u8BF7\u6C42\u8DEF\u5F84\u53D1\u73B0\u7F13\u5B58\u672A\u547D\u4E2D\u7684\u4F1A\u8BDD\uFF0C\u628A { stat, header } \u5FEB\u7167\u4E22\u8FDB\n // warmQueue\uFF0C\u7531 runWarm \u4EE5\u5C0F\u6279\u6B21\u6D88\u8D39\u3002\u6BCF\u6279\u4E4B\u95F4 setImmediate \u8BA9\u6B65\u4E8B\u4EF6\u5FAA\u73AF\uFF0C\n // \u7EDD\u4E0D\u72EC\u5360\u5BBF\u4E3B\u4E3B\u7EBF\u7A0B\uFF1B\u7ED3\u679C\u5199 metaCache + \u6301\u4E45\u6807\u9898\u7D22\u5F15\u3002stat \u662F\u5165\u961F\u65F6\u523B\u7684\n // \u5FEB\u7167\u2014\u2014\u82E5\u65E5\u5FD7\u5728\u9884\u70ED\u671F\u95F4\u53C8\u53D8\u4E86\uFF0C\u4E0B\u6B21\u8BF7\u6C42\u7684\u6307\u7EB9\u6BD4\u5BF9\u4F1A\u518D\u6B21\u5224\u672A\u547D\u4E2D\u5E76\u91CD\u65B0\n // \u5165\u961F\uFF0C\u5929\u7136\u81EA\u6108\u3002\n const WARM_CHUNK = 4\n const warmQueue = new Map()\n let warmRunning = false\n let warmKickTimer = null\n\n // v3.6.2 #1\uFF1A\u6295\u5F71\u5931\u8D25\u7684\u4E09\u6001\u5904\u7406\uFF08issue #8 \u5BA1\u8BA1\uFF09\u3002\u65E7\u5B9E\u73B0\u628A\u300C\u6295\u5F71\u5931\u8D25\u300D\u548C\n // \u300C\u4F1A\u8BDD\u771F\u6CA1\u6807\u9898\u300D\u6DF7\u4E3A\u540C\u4E00\u4E2A null \u2192 \u5931\u8D25\u88AB\u5199\u8FDB\u7F13\u5B58/\u6301\u4E45\u7D22\u5F15\uFF0C\u8DE8\u91CD\u542F\u56FA\u5316\u6210\n // \u6C38\u4E45\u5360\u4F4D\u4E14\u6C38\u4E0D\u91CD\u8BD5\u3002\u73B0\u5728\uFF1A\n // - resolved\uFF08fulfilled\uFF0Ctitle \u53EF\u4EE5\u662F null = \u4E8B\u5B9E\u65E0\u6807\u9898\uFF09\u2192 \u6B63\u5E38\u5165\u7F13\u5B58+\u843D\u76D8\uFF1B\n // - failed\uFF08rejected / \u6279\u91CF\u5F02\u5E38 / \u7ED3\u679C\u7F3A\u6761\uFF09\u2192 \u4E0D\u7F13\u5B58\u3001\u4E0D\u843D\u76D8\uFF0C\u6309 id \u8BA1\u6570\u9000\u907F\u3002\n // \u9000\u907F\uFF1A15s\u00D72^n \u9012\u589E\uFF0C\u6700\u591A WARM_MAX_ATTEMPTS \u6B21\uFF1B\u6B64\u540E parked \u4E00\u5C0F\u65F6\u540E\u518D\u63A2\u4E00\u6B21\n // \uFF08\u574F\u65E5\u5FD7\u957F\u671F\u505C\u6446\u65F6\u4E0D\u81F3\u4E8E\u6C38\u4E45\u9759\u9ED8\uFF09\u3002\u65E5\u5FD7\u6307\u7EB9\u4EFB\u4F55\u53D8\u5316\u90FD\u6E05\u96F6\u8BA1\u6570\u91CD\u65B0\u6B66\u88C5\u3002\n const WARM_MAX_ATTEMPTS = 5\n const warmFail = new Map() // id \u2192 { count, fp, nextAt }\n\n function warmFpOf(stat) {\n return fingerprintOf(stat) || persistFingerprintOf(stat)\n }\n\n function warmBlocked(id, fp) {\n const rec = warmFail.get(id)\n if (!rec) return 0\n if (fp && rec.fp && rec.fp !== fp) { warmFail.delete(id); return 0 } // \u5185\u5BB9\u53D8\u4E86 \u2192 \u91CD\u65B0\u6B66\u88C5\n const now = Date.now()\n return rec.nextAt > now ? rec.nextAt - now : 0\n }\n\n function warmMarkFailure(id, stat, header) {\n const rec = warmFail.get(id) || { count: 0, fp: null, nextAt: 0 }\n rec.count += 1\n rec.fp = warmFpOf(stat) || rec.fp\n // \u9000\u907F\u5230\u70B9\u540E\u7531 scheduleWarmRetry \u539F\u6837\u91CD\u65B0\u5165\u961F\uFF08\u542B\u672C\u8F6E\u7684 stat/header \u5FEB\u7167\uFF09\u3002\n if (stat) rec.stat = stat\n if (header) rec.header = header\n const backoff = rec.count >= WARM_MAX_ATTEMPTS\n ? 60 * 60 * 1000\n : Math.min(5 * 60 * 1000, 15 * 1000 * Math.pow(2, rec.count))\n rec.nextAt = Date.now() + backoff\n warmFail.set(id, rec)\n }\n\n // \u961F\u5217\u91CC\u8FD8\u6709\u300C\u672A\u653E\u5F03\u300D\u7684\u6D3B \u2192 \u4FA7\u680F/\u9762\u677F\u5E94\u7F29\u77ED\u8F6E\u8BE2\u8282\u62CD\uFF08client \u6D88\u8D39\uFF09\u3002\n function warmPendingNow() {\n if (!warmHasApi) return false\n if (warmRunning || warmQueue.size) return true\n for (const rec of warmFail.values()) if (rec.nextAt > Date.now()) return true\n return false\n }\n\n // \u9000\u907F\u5230\u70B9\u7684\u6761\u76EE\u7531\u4E00\u4E2A unref \u5B9A\u65F6\u5668\u91CD\u65B0\u5165\u961F\uFF08\u6BCF\u8F6E\u53EA\u6302\u6700\u8FD1\u7684\u4E00\u4E2A\uFF09\u3002\n let warmRetryTimer = null\n function scheduleWarmRetry() {\n if (warmRetryTimer) return\n let soonest = 0\n for (const rec of warmFail.values()) {\n const wait = rec.nextAt - Date.now()\n if (wait <= 0) { soonest = 1; break }\n if (!soonest || wait < soonest) soonest = wait\n }\n if (!soonest) return\n warmRetryTimer = setTimeout(() => {\n warmRetryTimer = null\n // \u5230\u70B9\u7684\u6761\u76EE\u91CD\u65B0\u5165\u961F\uFF08enqueue \u65F6\u4F1A\u91CD\u65B0\u6821\u9A8C blocked/fp\uFF09\u3002\n const now = Date.now()\n for (const [id, rec] of warmFail) {\n if (rec.nextAt <= now && !warmQueue.has(id)) warmQueue.set(id, { stat: rec.stat || null, header: rec.header || null })\n }\n if (warmQueue.size) scheduleWarm()\n }, soonest)\n if (typeof warmRetryTimer.unref === 'function') warmRetryTimer.unref()\n }\n\n function scheduleWarm() {\n if (warmKickTimer || warmRunning) return\n warmKickTimer = setTimeout(() => { warmKickTimer = null; runWarm() }, 25)\n // unref\uFF1A\u9884\u70ED\u7EDD\u4E0D\u53CD\u8FC7\u6765\u628A\u5BBF\u4E3B\u8FDB\u7A0B\u9489\u4F4F\uFF08\u4E0E autoArchive\u300C\u65E0\u5B9A\u65F6\u5668\u300D\u540C\u4E00\u539F\u5219\uFF09\u3002\n if (typeof warmKickTimer.unref === 'function') warmKickTimer.unref()\n }\n\n function enqueueWarm(ids, statsById, entryById) {\n if (!ids || !ids.length) return\n // \u65E0\u6295\u5F71 API \u7684 runtime\uFF1A\u9884\u70ED\u6CE8\u5B9A\u65E0\u679C\uFF0C\u4E0D\u5165\u961F\uFF08\u5360\u4F4D\u884C\u4E3A\u9000\u56DE\u300C\u5217\u8868\u4E0D\u5E26\u6807\u9898\u300D\n // \u7684\u8BDA\u5B9E\u5F62\u6001\uFF0C\u800C\u4E0D\u662F\u8BA9\u9000\u907F\u5B9A\u65F6\u5668\u6C38\u8FDC\u8F6C\u4E0B\u53BB\uFF09\u3002\n if (!warmHasApi) return\n for (const id of ids) {\n const key = String(id)\n const stat = statsById ? (statsById.get(key) || null) : null\n // #9\uFF1A\u4EFB\u4F55\u6307\u7EB9\u90FD\u7B97\u4E0D\u51FA\u6765\u7684\u4F1A\u8BDD\uFF08live \u672A\u843D\u76D8\u7B49\uFF09\u65E2\u8FDB\u4E0D\u4E86\u5185\u5B58\u7F13\u5B58\u4E5F\u8FDB\u4E0D\u4E86\n // \u6301\u4E45\u7D22\u5F15\u2014\u2014\u6295\u5F71\u7ED3\u679C\u6CE8\u5B9A\u65E0\u5904\u5B89\u653E\uFF0C\u6BCF\u8F6E\u8F6E\u8BE2\u91CD\u590D\u5165\u961F\u53EA\u662F\u767D\u70E7 CPU\uFF08churn\uFF09\u3002\n // \u8DF3\u8FC7\uFF1B\u8FD9\u7C7B\u884C\u7684\u6807\u9898\u7531 DSH \u81EA\u5DF1\u7684 live \u6E32\u67D3\u4FDD\u8BC1\u3002\n const fp = warmFpOf(stat)\n if (!fp) continue\n // #1\uFF1A\u4ECD\u5728\u5931\u8D25\u9000\u907F\u7A97\u53E3\u5185\u7684\u6761\u76EE\u4E0D\u91CD\u590D\u5165\u961F\uFF08runWarm \u4F1A\u6309 blocked \u8DF3\u8FC7\uFF09\u3002\n const blockedMs = warmBlocked(key, fp)\n const entry = entryById ? entryById.get(key) : null\n const rec = warmFail.get(key)\n if (rec) { rec.stat = stat || rec.stat; if (entry) rec.header = entry.header || rec.header }\n if (blockedMs > 0) continue\n warmQueue.set(key, {\n stat,\n header: (entry && entry.header) || null,\n })\n }\n if (warmQueue.size) scheduleWarm()\n scheduleWarmRetry()\n }\n\n // #7\uFF1A\u8F6F\u5220\u9664\u65F6\u6807\u9898\u53EF\u80FD\u8FD8\u6CA1\u9884\u70ED\u51FA\u6765\uFF08\u56DE\u6536\u7AD9\u6761\u76EE\u843D\u4E00\u6761 title:null \u7684\u8BDA\u5B9E\u8BB0\u5F55\uFF09\uFF0C\n // \u4E4B\u540E\u4EFB\u4F55\u4E00\u8F6E warm \u89E3\u51FA\u8BE5\u4F1A\u8BDD\u6807\u9898\u5C31\u8865\u5199\u8FDB\u56DE\u6536\u7AD9\u7D22\u5F15\u2014\u2014\u53EA\u8865\u7A7A\u6807\u9898\uFF0C\n // \u7EDD\u4E0D\u8986\u76D6\u5DF2\u6709\u503C\u3002\u56DE\u6536\u7AD9\u6E32\u67D3\u7AEF\uFF08t.title || t.sessionId\uFF09\u968F\u4E0B\u6B21\u62C9\u53D6\u81EA\u7136\u66F4\u65B0\u3002\n async function backfillTrashTitles(decoded) {\n if (!decoded || !decoded.size) return\n try {\n const items = await readTrash()\n const worth = items.some((t) => !t.title && decoded.get(String(t.sessionId)) && decoded.get(String(t.sessionId)).meta && decoded.get(String(t.sessionId)).meta.title)\n if (!worth) return\n await mutateTrash((store) => {\n for (const item of store.items) {\n if (item.title) continue\n const pack = decoded.get(String(item.sessionId))\n const t = pack && pack.meta && pack.meta.title\n if (t) item.title = String(t)\n }\n })\n } catch (e) { /* \u8865\u5199\u5931\u8D25\u65E0\u5BB3\uFF1A\u7D22\u5F15\u53EA\u662F\u52A0\u901F\u5668 */ }\n }\n\n async function runWarm() {\n if (warmRunning) return\n warmRunning = true\n try {\n while (warmQueue.size) {\n const batch = [...warmQueue.entries()].slice(0, WARM_CHUNK)\n for (const [id] of batch) warmQueue.delete(id)\n try {\n const ids = batch.map(([id]) => id)\n const resultById = await projectTitlesStatus(ids)\n const decoded = new Map()\n const statsById = new Map()\n for (const [id, desc] of batch) {\n const r = resultById.get(id)\n if (!r || !r.resolved) {\n // \u6295\u5F71\u5931\u8D25\uFF1A\u7EDD\u4E0D\u5199\u7F13\u5B58/\u6301\u4E45\u7D22\u5F15\uFF08\u5426\u5219\u5931\u8D25\u88AB\u56FA\u5316\u4E3A\u6C38\u4E45\u5360\u4F4D\uFF09\u3002\n warmMarkFailure(id, desc.stat, desc.header)\n continue\n }\n warmFail.delete(id)\n const meta = metaFromSnapshot(r.snapshot || null)\n // cwd/createdAt \u6C38\u8FDC\u4EE5\u6700\u65B0 list header \u4E3A\u6743\u5A01\uFF08\u6295\u5F71\u7684 session \u5934\u53EF\u80FD\n // \u9648\u65E7\uFF1B\u79FB\u52A8\u4F1A\u8BDD\u540E\u5C24\u5176\u5982\u6B64\uFF09\uFF0C\u6295\u5F71\u53EA\u8D1F\u8D23\u6807\u9898\u3002\n if (desc.header) {\n if (typeof desc.header.cwd === 'string') meta.cwd = desc.header.cwd\n if (desc.header.createdAt != null) meta.createdAt = desc.header.createdAt\n }\n metaCache.set(id, desc.stat, meta)\n statsById.set(id, desc.stat)\n decoded.set(id, { meta, resolved: true })\n }\n await persistDecoded(decoded, statsById)\n // #7\uFF1A\u56DE\u6536\u7AD9\u6761\u76EE\u5220\u9664\u65F6\u53EF\u80FD\u6CA1\u6709\u6807\u9898\uFF08\u8F6F\u5220\u9664\u53EA\u8BB0\u5F55\uFF09\uFF1B\u9884\u70ED\u89E3\u51FA\u6765\u540E\u8865\u5199\u3002\n await backfillTrashTitles(decoded)\n } catch (e) { /* \u5355\u6279\u5931\u8D25\u4E0D\u5F71\u54CD\u540E\u7EED\u6279\u6B21\uFF1A\u7D22\u5F15/\u7F13\u5B58\u53EA\u662F\u52A0\u901F\u5668 */ }\n // \u6279\u95F4\u8BA9\u6B65\uFF1A\u4FDD\u8BC1\u5BBF\u4E3B\u4E8B\u4EF6\u5FAA\u73AF\uFF08RPC/\u5FC3\u8DF3/\u5176\u4ED6\u63D2\u4EF6\uFF09\u59CB\u7EC8\u53EF\u8C03\u5EA6\u3002\n await new Promise((resolve) => setImmediate(resolve))\n }\n } finally {\n warmRunning = false\n // \u9884\u70ED\u671F\u95F4\u53C8\u6709\u65B0\u8BF7\u6C42\u5165\u961F \u2192 \u518D\u6392\u4E00\u8F6E\u3002\n if (warmQueue.size) scheduleWarm()\n scheduleWarmRetry()\n }\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\u3002revision \u8FDB\u5185\u5B58\u7F13\u5B58\u6307\u7EB9\uFF1B\n // sizeBytes \u4F9B persistFingerprintOf \u6D3E\u751F\u8DE8\u91CD\u542F\u7684 sz \u6301\u4E45\u6307\u7EB9\uFF08issue #8\uFF09\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, Number.isFinite(entry.sizeBytes)\n ? { revision: entry.revision, sizeBytes: Number(entry.sizeBytes) }\n : { 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 // \u5F85\u79FB\u52A8\u961F\u5217\uFF1A\u4F1A\u8BDD\u88AB\u5360\u7528\uFF08DSH \u6253\u5F00\u4E2D\uFF09\u65F6\u767B\u8BB0\uFF0C\u7B49\u5B83\u91CA\u653E\u540E\u81EA\u52A8\u5B8C\u6210\u79FB\u52A8\u3002\n // \u89C1 src/pending-moves.js \u7684\u6A21\u5757\u6CE8\u91CA\uFF080.1.5 \u5355\u5199\u8005\u9501\u6CA1\u6709\u516C\u5171\u91CA\u653E API\uFF09\u3002\n const pendingMoves = createPendingMoveStore()\n // Auto-archive settings live in their own schema-v4 store, off by default.\n const autoArchive = createAutoArchiveStore()\n // \u542F\u52A8\u6E05\u626B\uFF1A\u8FDB\u7A0B\u5728\u300C\u5199\u4E34\u65F6\u6587\u4EF6 \u2192 rename\u300D\u4E4B\u95F4\u88AB\u6740\u4F1A\u7559\u4E0B .<name>-<pid>-<ts>.tmp\n // \u5B64\u513F\uFF08\u5B9E\u6D4B\u4E00\u6B21\u7D2F\u79EF 153 \u4E2A\uFF09\u3002\u8FD9\u91CC\u628A 1 \u5C0F\u65F6\u524D\u7684\u65E7\u4E34\u65F6\u6587\u4EF6\u6536\u6389\uFF0C\u4E0D\u78B0\u6B63\u5728\u5199\u7684\u3002\n sweepStaleStateTemps([STATE_DIR, TRASH_DIR], {}).catch(() => {})\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 // v3.6.2 #7\uFF1A\u5220\u9664\u8DEF\u5F84**\u7EDD\u4E0D**\u505A\u6807\u9898\u6295\u5F71/\u5206\u5757\u89E3\u7801\u2014\u2014issue #8 \u7684\u6559\u8BAD\uFF1A\n // \u5927\u65E5\u5FD7\u4E0A\u5355\u6761\u515C\u5E95\u6295\u5F71\u4E5F\u662F\u6574\u672C\u89E3\u538B\uFF0C\u5220\u9664 = \u79D2\u7EA7\u5361\u5BBF\u4E3B\u3002\u53EA\u6D88\u8D39\u73B0\u6210\u7F13\u5B58\uFF1A\n // metaCache\uFF08\u7528 list \u5FEB\u7167\u7B97\u6307\u7EB9\uFF09\u2192 \u6301\u4E45\u7D22\u5F15 \u2192 \u4FA7\u680F\u6743\u5A01\u7F13\u5B58\u3002\u90FD\u6CA1\u6709\u5C31\u5B58\n // null\uFF08\u8BDA\u5B9E\u5360\u4F4D\uFF0C\u4E0D\u518D\u628A cwd/\u88F8 id \u5192\u5145\u6807\u9898\u6C38\u4E45\u5199\u8FDB\u56DE\u6536\u7AD9\uFF09\uFF0C\n // \u540E\u53F0\u9884\u70ED\u89E3\u51FA\u6807\u9898\u540E\u7531 backfillTrashTitles \u8865\u5199\u3002\n try {\n const delStat = persistenceEntry && typeof persistenceEntry.revision === 'string' && persistenceEntry.revision\n ? { revision: persistenceEntry.revision, sizeBytes: Number.isFinite(persistenceEntry.sizeBytes) ? Number(persistenceEntry.sizeBytes) : undefined }\n : (removedPath ? await stat(removedPath).then((st) => ({ mtimeMs: st.mtimeMs, size: st.size })) : null)\n if (delStat) {\n const m = metaCache.get(sid, delStat) || (await hydrateFromPersist([sid], new Map([[sid, delStat]]))).get(sid)\n if (m && m.title) title = String(m.title)\n }\n } catch (e) { /* best-effort */ }\n if (!title) { const at = authorityTitleCache.get(sid); if (at) title = String(at) }\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 // v3.6.2 #7\uFF1A\u4E0D\u518D\u628A cwd/\u88F8 id \u5192\u5145\u6807\u9898\u6C38\u4E45\u5B9A\u683C\u2014\u2014\u5B58 null\uFF0C\u9884\u70ED\u89E3\u51FA\u540E\n // backfillTrashTitles \u8865\u5199\uFF1B\u6E32\u67D3\u7AEF\uFF08t.title || t.sessionId\uFF09\u81EA\u7136\u964D\u7EA7\u3002\n sessionId: sid, title: title || null, 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 // \u661F\u6807\u6E05\u7406\u5FC5\u987B await\u3002\u539F\u5148\u8FD9\u91CC\u662F\u6D6E\u52A8\u5199\u5165\uFF08`stars.removeIds([sid]).catch(...)`\uFF09\uFF1A\n // \u5220\u9664\u7ED3\u679C\u5148\u8FD4\u56DE\u3001\u661F\u6807\u6587\u4EF6\u968F\u540E\u624D\u843D\u5730\uFF0C\u6B63\u597D\u4F1A\u649E\u4E0A\u8C03\u7528\u65B9\uFF08\u6216\u6D4B\u8BD5 teardown\uFF09\u5DF2\u5F00\u59CB\u7684\n // \u72B6\u6001\u76EE\u5F55\u6E05\u7406 \u2192 `ENOTEMPTY: rmdir .../state`\uFF08\u5168\u91CF\u6D4B\u8BD5\u91CC\u7EA6 1/4 \u6982\u7387\u5076\u53D1\u5931\u8D25\uFF09\u3002\n // \u800C\u4E14\"\u5220\u9664\u6210\u529F\"\u4E0D\u8BE5\u65E9\u4E8E\u72B6\u6001\u843D\u76D8\uFF1A\u8FDB\u7A0B\u6070\u597D\u5728\u6B64\u523B\u9000\u51FA\u5C31\u4F1A\u7559\u4E0B\u6307\u5411\u5DF2\u5220\u4F1A\u8BDD\u7684\u661F\u6807\u3002\n try { await stars.removeIds([sid]) } catch (e) { /* \u661F\u6807\u6E05\u7406\u5931\u8D25\u4E0D\u963B\u585E\u5220\u9664\u7ED3\u679C */ }\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 const error = new Error('\u4F1A\u8BDD\u6B63\u88AB DSH \u6253\u5F00\uFF0C\u6682\u65F6\u65E0\u6CD5\u79FB\u52A8\uFF1B\u8BF7\u91CD\u542F DSH \u540E\u518D\u8BD5\u3002')\n error.status = 409\n error.code = 'DSM_SESSION_BUSY'\n throw error\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 // \u79FB\u52A8\u8FC7\u7A0B\u7684\u975E\u81F4\u547D\u63D0\u793A\uFF08\u5982\u6E90\u76EE\u5F55\u4ECD\u6709\u65E7\u4EE3\u65E5\u5FD7\u672A\u80FD\u6E05\u7406\uFF09\uFF0C\u968F\u6210\u529F\u7ED3\u679C\u4E00\u5E76\n // \u56DE\u62A5\u7ED9\u5BA2\u6237\u7AEF\u5C55\u793A\u3002\n const moveNotes = []\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 const keptInSource = await cleanupMovedSourceDir(dirname(oldPath))\n if (keptInSource.length > 0) moveNotes.push(`\u6E90\u76EE\u5F55\u672A\u80FD\u6E05\u7406\u5E72\u51C0\uFF08\u6B8B\u7559 ${keptInSource.join('\u3001')}\uFF09\uFF0C\u82E5\u540E\u7EED\u79FB\u52A8\u62A5\u201Cduplicate\u201D\u8BF7\u624B\u52A8\u6E05\u7A7A\u8BE5\u76EE\u5F55\u3002`)\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 // \u79FB\u52A8\u6210\u529F\u540E\u7684\u6E90\u76EE\u5F55\u6536\u5C3E\uFF08legacy \u8DEF\u5F84\uFF09\uFF1A**\u6574\u4F53\u79FB\u9664**\u3002\u76EE\u6807\u4FA7\u5DF2\u5199\u5165\u6821\u9A8C\u901A\u8FC7\u7684\n // \u6743\u5A01\u65E5\u5FD7\uFF0C\u6E90\u76EE\u5F55\u53EA\u8981\u8FD8\u7559\u7740\u4EFB\u4F55\u4E00\u4EE3\u65E5\u5FD7\uFF08legacy \u65E7\u4EE3 session.jsonl.zstd \u6216\n // session.vN.jsonl.zstd\uFF09\uFF0C\u5C31\u4F1A\u8BA9\u540C id \u51FA\u73B0\u5728\u4E24\u4E2A\u9879\u76EE\u76EE\u5F55\uFF0C\u540E\u7AEF list/create\n // \u7ACB\u523B\u62A5 duplicate\u3002\u8FD4\u56DE\u672A\u80FD\u6E05\u7406\u65F6\u7684\u6B8B\u7559\u6587\u4EF6\u540D\uFF08\u4F9B\u5982\u5B9E\u56DE\u62A5\uFF09\u3002\n const cleanupMovedSourceDir = async (dir) => {\n let entries = null\n try { entries = await readdir(dir) } catch (e) { return [] }\n try { await rm(dir, { recursive: true, force: true }) } catch (e) { return entries }\n return []\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 const movedHandle = await moveSessionToCwd({ sp, sid, header: meta, canonical, events, inheritedEventCount: r.inheritedEventCount })\n if (movedHandle && Array.isArray(movedHandle.reclaimedSiblings) && movedHandle.reclaimedSiblings.length > 0) {\n moveNotes.push(`\u5DF2\u987A\u5E26\u56DE\u6536 ${movedHandle.reclaimedSiblings.length} \u5904\u88AB\u53D6\u4EE3\u7684\u65E7\u4EE3\u65E5\u5FD7\u526F\u672C\uFF08\u5386\u53F2\u79FB\u52A8\u6B8B\u7559\uFF09\uFF0C\u907F\u514D\u540C\u4E00\u4F1A\u8BDD\u5728\u591A\u76EE\u5F55\u91CD\u590D\u3002`)\n }\n if (movedHandle && movedHandle.sourceCleanup && movedHandle.sourceCleanup.cleaned === false) {\n moveNotes.push(`\u6E90\u76EE\u5F55\u672A\u80FD\u6E05\u7406\u5E72\u51C0\uFF08\u6B8B\u7559 ${movedHandle.sourceCleanup.leftover.join('\u3001')}\uFF09\uFF0C\u82E5\u540E\u7EED\u79FB\u52A8\u62A5\u201Cduplicate\u201D\u8BF7\u624B\u52A8\u6E05\u7A7A\u8BE5\u76EE\u5F55\u3002`)\n }\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 if (oldPath) {\n const keptInSource = await cleanupMovedSourceDir(dirname(oldPath))\n if (keptInSource.length > 0) moveNotes.push(`\u6E90\u76EE\u5F55\u672A\u80FD\u6E05\u7406\u5E72\u51C0\uFF08\u6B8B\u7559 ${keptInSource.join('\u3001')}\uFF09\uFF0C\u82E5\u540E\u7EED\u79FB\u52A8\u62A5\u201Cduplicate\u201D\u8BF7\u624B\u52A8\u6E05\u7A7A\u8BE5\u76EE\u5F55\u3002`)\n }\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 ...(moveNotes.length > 0 ? { notes: moveNotes } : {}),\n }\n }\n\n // ---- \u5F85\u79FB\u52A8\u961F\u5217\uFF08\u6D3B\u8DC3 / \u88AB\u5360\u7528\u7684\u4F1A\u8BDD\uFF09-----------------------------------\n // 0.1.5 \u7684\u5355\u5199\u8005\u9501\u7531\u6301\u6709\u5199\u53E5\u67C4\u7684\u8FDB\u7A0B\u638C\u63A7\uFF0C\u63D2\u4EF6\u65E2\u62FF\u4E0D\u5230\u53E5\u67C4\u4E5F\u6CA1\u6709\u91CA\u653E\u5B83\u7684\u516C\u5171\n // API\uFF1B\u5728\u5360\u7528\u671F\u786C\u642C\u76EE\u5F55\u4F1A\u8BA9\u5728\u5199\u8005\u7EE7\u7EED\u5199\u65E7 inode \u5E76\u5728\u65E7\u8DEF\u5F84\u91CD\u5EFA\u7A7A\u58F3\u3002\u56E0\u6B64\u5360\u7528\u65F6\n // \u53EA\u767B\u8BB0\u6392\u961F\uFF0C\u7B49\u5BBF\u4E3B\u91CA\u653E\uFF08session/disposed\uFF09\u6216\u4E0B\u6B21\u63D2\u4EF6\n // \u542F\u52A8\u65F6\uFF08\u4F1A\u8BDD\u5C1A\u672A\u88AB\u6253\u5F00\uFF09\u81EA\u52A8\u5B8C\u6210\u3002\n const QUEUE_NOTE = '\u5DF2\u6392\u961F\uFF1A\u8BE5\u4F1A\u8BDD\u6B63\u88AB DSH \u6253\u5F00\uFF08\u5199\u6240\u6709\u6743\u53EA\u5728 DSH \u9000\u51FA\u65F6\u91CA\u653E\uFF09\u3002\u91CD\u542F DSH \u65F6\u4F1A\u81EA\u52A8\u5B8C\u6210\uFF0C\u8BF7\u5148\u522B\u6253\u5F00\u5B83\u3002'\n\n function isBusyError(e) {\n if (!e) return false\n if (e.code === 'DSM_SESSION_BUSY') return true\n const text = String((e && e.message) || e)\n return /\u6B63\u88AB DSH \u6253\u5F00|already owned/i.test(text)\n }\n\n // \u79FB\u52A8\u5165\u53E3\uFF1A\u5360\u7528 \u2192 \u6392\u961F\uFF1B\u5176\u5B83\u9519\u8BEF\u7167\u65E7\u629B\u51FA\u3002\u8FD4\u56DE\u6210\u529F\u7ED3\u679C\u6216\u6392\u961F\u7ED3\u679C\u3002\n async function moveOrQueue(sid, targetPath) {\n try {\n return await moveOne(sid, targetPath)\n } catch (e) {\n if (!isBusyError(e)) throw e\n await pendingMoves.queue(sid, targetPath)\n return { ok: true, moved: false, queued: true, notes: [QUEUE_NOTE] }\n }\n }\n\n // \u542F\u52A8\u540E\u7684\u300C\u5B66\u6B65\u671F\u300D\uFF1A\u8FD9\u6BB5\u65F6\u95F4\u5185 moveOne \u7684\u975E\u5360\u7528\u7C7B\u5931\u8D25\u53EA\u5F53\u73AF\u5883\u672A\u5C31\u7EEA\uFF0C\u4E0D\u8BA1\u5165\n // \u300C\u591A\u6B21\u5931\u8D25\u5373\u653E\u5F03\u300D\u7684\u8BA1\u6570\uFF08\u5426\u5219 boot \u7ADE\u6001\u4F1A\u628A\u7528\u6237\u7684\u6392\u961F\u9879\u767D\u767D\u4E22\u6389\uFF09\u3002\n const BOOT_WARMUP_MS = 30000\n const bootedAt = Date.now()\n\n let queueRunning = false\n async function runPendingMoves(reason) {\n if (queueRunning) return { ran: false, moved: 0, kept: 0 }\n queueRunning = true\n let moved = 0\n const notes = []\n try {\n const items = await pendingMoves.list()\n for (const item of items) {\n try {\n await moveOne(item.sessionId, item.targetPath)\n await pendingMoves.remove([item.sessionId])\n metaCache.invalidate(item.sessionId)\n moved++\n notes.push(`\u6392\u961F\u4E2D\u7684\u79FB\u52A8\u5DF2\u5B8C\u6210\uFF1A${String(item.sessionId).slice(0, 18)}\u2026`)\n } catch (e) {\n if (isBusyError(e)) continue // \u4ECD\u88AB\u5360\u7528\uFF1A\u7559\u5728\u961F\u5217\u91CC\uFF0C\u7B49\u4E0B\u4E00\u6B21\u89E6\u53D1\n if (Date.now() - bootedAt < BOOT_WARMUP_MS) continue // boot \u671F\u672A\u5C31\u7EEA\uFF1A\u4E0D\u8BB0\u5931\u8D25\n const bumped = await pendingMoves.bumpAttempts(item.sessionId)\n if (bumped && bumped.dropped) notes.push(`\u6392\u961F\u4E2D\u7684\u79FB\u52A8\u591A\u6B21\u5931\u8D25\u5DF2\u653E\u5F03\uFF1A${String(item.sessionId).slice(0, 18)}\u2026\uFF08${String((e && e.message) || e)}\uFF09`)\n }\n }\n if (moved > 0) { try { await reindexRegistry() } catch (e) { /* best-effort */ } }\n } finally {\n queueRunning = false\n }\n if (notes.length > 0) {\n try { for (const n of notes) console.warn('[dsh-sessions-manager] ' + n) } catch (e) { /* ignore */ }\n }\n void reason\n return { ran: true, moved, kept: (await pendingMoves.list()).length }\n }\n\n // \u6392\u961F\u9879\u7684\u8865\u8DD1\u65F6\u673A\u3002**\u5173\u952E\u524D\u63D0**\uFF1A0.1.5 \u7684\u5355\u5199\u8005\u6240\u6709\u6743\u4E00\u7ECF open \u5C31\u6301\u6709\u5230**\u8FDB\u7A0B\u9000\u51FA**\n // \u4E3A\u6B62\u2014\u2014\u5B98\u65B9\u6CA1\u6709\u4EFB\u4F55\u300C\u5173\u95ED\u4F1A\u8BDD / \u91CA\u653E\u6240\u6709\u6743\u300D\u7684\u516C\u5F00\u5165\u53E3\uFF08`dsh-commands` \u53EA\u6709\n // compact/feedback/goal\uFF1B\u5BBF\u4E3B\u65E0 unloadSession/closeSession/evict\uFF09\uFF0C\u800C\u6D4F\u89C8\u5668\u4E00\u8FDE\u4E0A\u5C31\u4F1A\n // \u81EA\u52A8\u6253\u5F00/\u65B0\u5EFA\u4F1A\u8BDD\uFF0C\u4E00\u65E6\u88AB\u6253\u5F00\u5C31\u518D\u4E5F\u642C\u4E0D\u52A8\u3002\u6240\u4EE5\u552F\u4E00\u53EF\u9760\u7A97\u53E3\u662F**\u5BBF\u4E3B\u521A\u8D77\u6765\u3001\u6D4F\u89C8\u5668\n // \u8FD8\u6CA1\u8FDE\u4E0A**\u7684\u90A3\u4E00\u4E24\u79D2 \u21D2 \u542F\u52A8\u540E\u7ACB\u523B\u8BD5\uFF0C\u5E76\u5728\u524D 30s \u5185\u5BC6\u96C6\u91CD\u8BD5\uFF1B\u4E4B\u540E\u6BCF 120s \u515C\u5E95\uFF1B\n // \u4F1A\u8BDD\u771F\u88AB\u91CA\u653E\uFF08session/disposed\uFF09\u65F6 500ms \u540E\u518D\u8BD5\u4E00\u6B21\u3002\n const queueEffect = typeof ctx.effect === 'function' ? ctx.effect.bind(ctx) : ((fn) => { fn() })\n if (typeof ctx.on === 'function') {\n queueEffect(() => ctx.on('session/disposed', (session) => {\n const id = session && session.id != null ? String(session.id) : null\n if (!id) return\n pendingMoves.has(id).then((queued) => {\n if (!queued) return\n const t = setTimeout(() => { runPendingMoves('session-disposed').catch(() => {}) }, 500)\n if (t && typeof t.unref === 'function') t.unref()\n }).catch(() => {})\n }))\n }\n queueEffect(() => {\n // \u6BCF\u4E2A\u542F\u52A8\u8865\u8DD1\u5B9A\u65F6\u5668\u90FD\u8981 unref\uFF1A\u5BBF\u4E3B\u81EA\u5DF1\u4E0D\u4F1A\u95F2\u4E0B\u6765\u65E0\u6240\u8C13\uFF0C\u4F46\u6D4B\u8BD5\u91CC\u672A unref \u7684\n // 30s \u5B9A\u65F6\u5668\u4F1A\u8BA9 node:test \u591A\u7B49 30s \u624D\u9000\u51FA\uFF08\u6574\u5957\u6D4B\u8BD5\u88AB\u65E0\u8C13\u62D6\u957F\uFF0C\u5B9E\u6D4B\u89C1\u62A5\u544A\uFF09\u3002\n const timers = [0, 1000, 3000, 6000, 12000, 30000].map((ms) => {\n const t = setTimeout(() => {\n runPendingMoves(ms === 0 ? 'startup' : `startup+${ms}`).catch(() => {})\n }, ms)\n if (t && typeof t.unref === 'function') t.unref()\n return t\n })\n // \u8F7B\u91CF\u5468\u671F\u91CD\u8BD5\uFF1A\u53EA\u5728\u961F\u5217\u975E\u7A7A\u65F6\u5E72\u6D3B\uFF08\u961F\u5217\u7A7A = \u4E00\u6B21\u672C\u5730 JSON \u8BFB\u53D6\uFF09\u3002\n const tickTimer = setInterval(() => {\n pendingMoves.list().then((items) => { if (items.length > 0) return runPendingMoves('tick') }).catch(() => {})\n }, 120000)\n if (tickTimer && typeof tickTimer.unref === 'function') tickTimer.unref()\n return () => { for (const t of timers) clearTimeout(t); clearInterval(tickTimer) }\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\uFF08v3.6.2 #1 \u4E09\u6001\u7248\uFF09\u3002\u8FD4\u56DE Map<id, { resolved, snapshot|null }>\uFF1A\n // resolved=true \u2014\u2014 fulfilled \u5FEB\u7167\uFF08title \u53EF\u80FD\u4E3A null\uFF1A\u4F1A\u8BDD\u771F\u7684\u6CA1\u6807\u9898\uFF0C\n // \u8FD9\u662F\u4E8B\u5B9E\uFF0C\u53EF\u4EE5\u7F13\u5B58/\u843D\u76D8\uFF09\uFF1B\n // resolved=false \u2014\u2014 rejected / \u6279\u91CF\u5F02\u5E38 / \u7ED3\u679C\u7F3A\u6761 / \u65E0\u6295\u5F71 API\u3002\n // \u8C03\u7528\u65B9\uFF08runWarm\uFF09\u53EA\u7F13\u5B58 resolved \u7684\u6761\u76EE\uFF1B\u5931\u8D25\u7684\u8FDB\u9000\u907F\u91CD\u8BD5\uFF0C\u7EDD\u4E0D\u843D\u76D8\u2014\u2014\n // \u5426\u5219\u300C\u4E00\u6B21\u5931\u8D25\u300D\u88AB\u56FA\u5316\u4E3A\u8DE8\u91CD\u542F\u7684\u6C38\u4E45\u5360\u4F4D\uFF08v3.6.1 \u5BA1\u8BA1 #1\uFF09\u3002\n const warmHasApi = typeof sq.readTitleSnapshots === 'function' || typeof sq.readTitleSnapshot === 'function'\n\n async function projectTitlesStatus(ids) {\n const out = new Map()\n const markAll = (resolved) => { for (const id of ids) out.set(String(id), { resolved, snapshot: null }) }\n if (!ids || !ids.length) return out\n if (!warmHasApi) { markAll(false); return out }\n if (typeof sq.readTitleSnapshots === 'function') {\n let results = null\n try { results = await sq.readTitleSnapshots(ids) } catch (e) { results = null }\n if (Array.isArray(results)) {\n results.forEach((result, index) => {\n const id = String(ids[index])\n if (result && result.status === 'fulfilled') out.set(id, { resolved: true, snapshot: unwrapSnapshot(result) })\n else if (result && result.status === 'rejected') out.set(id, { resolved: false, snapshot: null })\n else if (result) out.set(id, { resolved: true, snapshot: unwrapSnapshot(result) }) // \u6700\u8001\u5F62\u6001\uFF1A\u76F4\u63A5\u662F\u5FEB\u7167\n else out.set(id, { resolved: false, snapshot: null })\n })\n // \u7ED3\u679C\u6570\u7EC4\u77ED\u4E8E\u8BF7\u6C42\uFF08runtime \u884C\u4E3A\u5F02\u5E38\uFF09\u2192 \u7F3A\u7684\u6761\u76EE\u6309\u5931\u8D25\u5904\u7406\u3002\n for (const id of ids) if (!out.has(String(id))) out.set(String(id), { resolved: false, snapshot: null })\n return out\n }\n // \u6279\u91CF\u5F62\u6001\u4E0D\u8BA4\u8BC6\uFF1A\u9000\u56DE\u9010\u6761\u3002\n }\n if (typeof sq.readTitleSnapshot === 'function') {\n for (const raw of ids) {\n const id = String(raw)\n try {\n const r = await sq.readTitleSnapshot(id)\n if (r && r.status === 'rejected') out.set(id, { resolved: false, snapshot: null })\n else out.set(id, { resolved: true, snapshot: unwrapSnapshot(r) })\n } catch (e) { out.set(id, { resolved: false, snapshot: null }) }\n }\n return out\n }\n markAll(false)\n return out\n }\n\n // \u517C\u5BB9\u65E7\u8C03\u7528\u70B9\uFF08\u6682\u65E0\uFF09\uFF1A\u4FDD\u7559\u540D\u5B57\u4E0D\u5BFC\u51FA\uFF0C\u907F\u514D\u8BEF\u7528\u56DE\u300C\u5931\u8D25\u5373 null\u300D\u7684\u65E7\u8BED\u4E49\u3002\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. \u7F13\u5B58\u672A\u547D\u4E2D\u7684\u4F1A\u8BDD**\u7EDD\u4E0D\u5728\u8BF7\u6C42\u8DEF\u5F84\u4E0A\u540C\u6B65\u6295\u5F71**\uFF08issue #8\uFF1Aruntime \u7684\n // readTitleSnapshots \u6BCF\u6761\u90FD\u662F\u6574\u672C\u89E3\u7801\uFF09\u2014\u2014\u5165\u961F\u540E\u53F0\u9884\u70ED\uFF0C\u5148\u4EE5\u5360\u4F4D\u5143\u6570\u636E\u8FD4\u56DE\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 usage = await collectUsage(entries)\n // \u5148\u6309\u6307\u7EB9\u628A\u300C\u7F13\u5B58\u547D\u4E2D\u300D\u4E0E\u300C\u9700\u8981\u8865\u9F50\u300D\u5206\u5F00\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 { cached, 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 // cwd/createdAt \u56DE\u586B\u65F6\u4EE5\u6700\u65B0 list header \u4E3A\u6743\u5A01\u2014\u2014\u6301\u4E45\u6761\u76EE\u91CC\u7684 cwd \u53EF\u80FD\u56E0\n // \u79FB\u52A8\u4F1A\u8BDD\u800C\u9648\u65E7\uFF08sz \u6307\u7EB9\u5BF9 cwd \u65E0\u611F\u77E5\uFF09\uFF0C\u6807\u9898\u624D\u662F\u7D22\u5F15\u7684\u4EA7\u51FA\u7269\u3002\n const persisted = await hydrateFromPersist(missing, statsById)\n for (const [id, meta] of persisted) {\n const entry = entryById.get(id)\n const header = entry && entry.header ? entry.header : null\n metaCache.set(id, statsById.get(id), {\n title: meta.title,\n cwd: (header && typeof header.cwd === 'string' && header.cwd) ? header.cwd : meta.cwd,\n createdAt: (header && header.createdAt != null) ? header.createdAt : meta.createdAt,\n })\n }\n const stillMissing = missing.filter((id) => !persisted.has(id))\n // issue #8\uFF1A\u7F3A\u5931\u90E8\u5206\u4EA4\u540E\u53F0\u9884\u70ED\uFF08\u5206\u6279 + \u8BA9\u6B65\uFF09\uFF0C\u8BF7\u6C42\u8DEF\u5F84\u96F6\u6295\u5F71\u3001\u96F6\u65E5\u5FD7\u89E3\u7801\u3002\n if (stillMissing.length) enqueueWarm(stillMissing, statsById, entryById)\n const items = []\n for (const id of visibleIds) {\n // metaCache \u4F18\u5148\uFF1Apersisted \u547D\u4E2D\u5DF2\u5E26 header \u6743\u5A01 cwd/createdAt \u56DE\u586B\u8FDB\n // metaCache\uFF08persisted.get \u91CC\u7684 cwd \u53EF\u80FD\u56E0\u79FB\u52A8\u4F1A\u8BDD\u800C\u9648\u65E7\uFF09\u3002\n // \u5B8C\u5168\u672A\u547D\u4E2D\u7684\u4F1A\u8BDD\u4E5F\u4E0D\u80FD\u4E22 cwd/createdAt\u2014\u2014\u5B83\u4EEC\u6765\u81EA list header\uFF0C\u96F6\u6210\u672C\n // \u4E14\u662F\u5DE5\u4F5C\u533A\u5F52\u5C5E/\u521B\u5EFA\u65F6\u95F4\u7684\u6743\u5A01\u6765\u6E90\uFF1B\u53EA\u6709\u6807\u9898\u5141\u8BB8\u5360\u4F4D\u7B49\u540E\u53F0\u9884\u70ED\uFF08issue #8\uFF09\u3002\n let meta = metaCache.get(id, statsById.get(id)) || persisted.get(id) || null\n if (!meta) {\n meta = { title: null, cwd: null, createdAt: null }\n const entry = entryById.get(id)\n const header = entry && entry.header ? entry.header : null\n if (header) {\n if (typeof header.cwd === 'string') meta.cwd = header.cwd\n if (header.createdAt != null) meta.createdAt = header.createdAt\n }\n }\n const it = buildItem(id, meta, usage, !!(opts && opts.usage))\n items.push({ ...it, archived: currentArchived.has(it.sessionId) })\n }\n if (opts && opts.onlyArchived) {\n // /archived-sessions/list \u7684\u8BED\u4E49\uFF1A\u53EA\u8FD4\u56DE\u5F52\u6863\u96C6\u91CC\u4ECD\u7136\u5B58\u5728\u7684\u4F1A\u8BDD\uFF0C\n // \u4E14\u4E0D\u5E26 archived \u5E03\u5C14\u6CE8\u8BB0\uFF08\u65E7\u8DEF\u7531\u7684\u8F93\u51FA\u5F62\u72B6\uFF09\u3002\n const archivedItems = []\n for (const it of items) {\n if (!it.archived) continue\n const { archived: _drop, ...rest } = it\n archivedItems.push(rest)\n }\n return { items: archivedItems, usage }\n }\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 entryById = new Map(entries.map((entry) => [entry.id, entry]))\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) {\n const entry = entryById.get(id)\n const header = entry && entry.header ? entry.header : null\n metaCache.set(id, statsById.get(id), {\n title: meta.title,\n cwd: (header && typeof header.cwd === 'string' && header.cwd) ? header.cwd : meta.cwd,\n createdAt: (header && header.createdAt != null) ? header.createdAt : meta.createdAt,\n })\n }\n const rest = missing.filter((id) => !persisted.has(id))\n // issue #8\uFF1A\u7F3A\u5931\u6807\u9898\u4E0D\u5728\u8BF7\u6C42\u8DEF\u5F84\u4E0A\u540C\u6B65\u6295\u5F71\uFF08runtime \u6295\u5F71 = \u9010\u6761\u6574\u672C\u89E3\u7801\uFF09\uFF0C\n // \u4EA4\u540E\u53F0\u9884\u70ED\u8865\u9F50\uFF1B\u4FA7\u680F\u9AD8\u9891\u8F6E\u8BE2\u4F1A\u8BA9\u8865\u9F50\u7ED3\u679C\u81EA\u7136\u6D6E\u73B0\u3002\n if (rest.length) enqueueWarm(rest, statsById, entryById)\n for (const id of ids) {\n const meta = metaCache.get(id, statsById.get(id)) || persisted.get(id) || null\n if (meta && meta.title) authorityTitleCache.set(id, String(meta.title))\n }\n }\n // \u8840\u7F18\u5206\u7C7B\uFF08issue #6\uFF09\uFF1A\u7ED3\u6784\u5206\u7C7B\uFF08\u5B50\u4EE3\u7406 / fork \u5206\u652F\uFF09\u6765\u81EA list snapshot\n // \u7684 header\uFF0C\u96F6\u89E3\u7801\uFF1B\u7A7A\u767D\u5224\u5B9A\u89C1\u4E0B\u65B9 refineEmptyLineage\uFF080.1.3 \u8D77\u4F53\u79EF\u6CD5\n // \u5931\u6548\uFF0C\u6539\u4E3A\u4E8B\u4EF6\u7C7B\u578B\u7CBE\u5224\uFF09\u3002\u666E\u901A\u9876\u5C42\u975E\u7A7A\u4F1A\u8BDD\u4E0D\u4EA7\u751F\u6761\u76EE\uFF0Cpayload \u6700\u5C0F\u3002\n const lineage = {}\n for (const entry of entries) {\n const info = classifyLineage(entry.header, entry.sizeBytes)\n if (info) lineage[entry.id] = info\n }\n await refineEmptyLineage(lineage, entries)\n return {\n titles: Object.fromEntries(authorityTitleCache),\n trashedSessionIds: store.items.map((item) => String(item.sessionId)),\n purgedSessionIds: activeTombstones,\n lineage,\n // v3.6.2\uFF1A\u8FD8\u6709\u9884\u70ED/\u9000\u907F\u91CD\u8BD5\u5728\u9014 \u2192 client \u7F29\u77ED\u8F6E\u8BE2\u8282\u62CD\uFF0C\u9884\u70ED\u4E00\u5B8C\u6210\u5C31\u628A\n // \u8865\u9F50\u7684\u6807\u9898\u9001\u56DE\uFF08\u542B\u9762\u677F\u81EA\u52A8\u5237\u65B0\uFF09\u3002\u65E0\u9884\u70ED API \u65F6\u6052 false\uFF0C\u7EDD\u4E0D\u5047\u5FD9\u3002\n warmPending: warmPendingNow(),\n }\n }\n\n // \u7A7A\u4F1A\u8BDD\u5224\u5B9A\u7F13\u5B58\uFF1Aid \u2192 { sizeBytes, empty }\u3002\u65E5\u5FD7\u6CA1\u53D8\uFF08sizeBytes \u76F8\u540C\uFF09\n // \u5C31\u4E0D\u91CD\u590D\u89E3\u7801\u2014\u2014authority \u4F1A\u88AB\u4FA7\u680F\u9AD8\u9891\u8F6E\u8BE2\uFF0C\u7F13\u5B58\u8BA9\u5B83\u4FDD\u6301\u5728\u8FD1\u96F6\u6210\u672C\u3002\n const emptyScanCache = new Map()\n\n // 0.1.3 \u7A7A\u4F1A\u8BDD\u7CBE\u5224\uFF08\u4E8B\u4EF6\u7C7B\u578B\u6CD5\uFF0C\u89C1 lineage.js\uFF09\uFF1A\u4F53\u79EF\u9608\u503C\u5BF9\u65B0\u683C\u5F0F\u5931\u6548\n // \uFF08\u5934\u90E8\u6269\u5BB9 + \u6052\u5B58\u751F\u547D\u5468\u671F\u5E27\uFF09\uFF0C\u6539\u4E3A\u5BF9\u300C\u538B\u7F29\u4F53\u79EF \u2264 EMPTY_DECODE_LIMIT\u300D\n // \u7684\u5019\u9009\u8D70\u5B98\u65B9 inspectSession \u89E3\u7801\uFF0C\u6309\u4E8B\u4EF6\u7C7B\u578B\u5224\u5B9A\u3002\u8D85\u8FC7\u4E0A\u9650\u7684\u65E5\u5FD7\u5FC5\u6709\n // \u5185\u5BB9\uFF0C\u76F4\u63A5\u8DF3\u8FC7\uFF08\u7EF4\u6301\u4F53\u79EF\u6CD5/\u7ED3\u6784\u5206\u7C7B\u7684\u7ED3\u679C\uFF09\u3002\u89E3\u7801\u5931\u8D25\u6309\u300C\u975E\u7A7A\u300D\u5904\u7406\uFF1A\n // \u5B81\u53EF\u6F0F\u5224\u4E00\u4E2A\u7A7A\u4F1A\u8BDD\uFF0C\u4E0D\u80FD\u628A\u6709\u5185\u5BB9\u7684\u4F1A\u8BDD\u9519\u6807\u6210\u7A7A\u3002\n // v3.6.2\uFF08\u5206\u652F\u6807\u7B7E\u5EF6\u8FDF\u5BA1\u8BA1 #1 \u7684\u901F\u6548\u534A\u8FB9\uFF09\uFF1A\u65E7\u5B9E\u73B0\u628A\u5168\u90E8 \u22648KB \u5019\u9009**\u4E32\u884C**\n // \u89E3\u7801\u5728 sidebar-state \u7684\u8BF7\u6C42\u8DEF\u5F84\u91CC\u2014\u2014\u51B7\u542F\u52A8\uFF08\u8FDB\u7A0B\u5185\u7F13\u5B58\u5168\u7A7A\uFF09\u65F6\u96F6\u89E3\u7801\u6210\u672C\n // \u7684\u8840\u7F18\u6570\u636E\u88AB\u8FD9\u4E32\u6162\u89E3\u7801\u6321\u5728 return \u4E4B\u524D\uFF0C\u8FD9\u6B63\u662F\u300C\u2442 \u5206\u652F\u300Dchip \u665A\u51FA/32s \u53F0\u9636\n // \u7684\u76F4\u63A5\u95E8\u63A7\u3002\u73B0\u5728\uFF1A\u5E76\u884C\u9650\u6D41 4 \u8DEF + \u6BCF\u8BF7\u6C42\u9884\u7B97 REFINE_BUDGET \u6761\uFF08\u8D85\u9884\u7B97\u7684\n // \u5C0F\u65E5\u5FD7\u4E0B\u4E00\u62CD\u7EE7\u7EED\uFF0C\u9010\u62CD\u6536\u655B\uFF1B\u5DF2\u7F13\u5B58\u7684\u6761\u76EE\u96F6\u6210\u672C\u7167\u5E38\u5E94\u7528\uFF0C\u4E0D\u5F71\u54CD\u6B63\u786E\u6027\uFF09\u3002\n // \u5F7B\u5E95\u89E3\u7ED1\uFF08\u7CBE\u5224\u632A\u8FDB\u540E\u53F0\u961F\u5217\uFF09\u662F 3.7.0 \u7684\u54CD\u5E94\u5951\u7EA6\u6539\u9020\uFF0C\u4E0D\u5728\u70ED\u4FEE\u8303\u56F4\u3002\n const REFINE_BUDGET = 40\n function applyEmptyScan(lineage, id, empty) {\n if (empty) {\n // \u7ED3\u6784\u5206\u7C7B\u6CA1\u5EFA\u6761\u76EE\u7684\u666E\u901A\u4F1A\u8BDD\u4E5F\u8981\u8865\u4E0A\uFF080.1.3 \u7A7A\u4F1A\u8BDD header \u65E0\u8840\u7F18\u5B57\u6BB5\uFF0C\n // classifyLineage \u5BF9\u5B83\u4EEC\u8FD4\u56DE null\uFF09\u3002\n const info = lineage[id] || (lineage[id] = { origin: null, parentSession: null, delegationDepth: 0, empty: false })\n info.empty = true\n } else if (lineage[id]) {\n // \u65E7\u4F53\u79EF\u6CD5\u5728\u5C0F\u65E5\u5FD7\u4E0A\u7684\u5047\u9633\u6027\uFF08\u5982 alpha.2 \u5355\u4E8B\u4EF6\u65E5\u5FD7\uFF09\u5728\u8FD9\u91CC\u7EA0\u6B63\uFF1B\n // \u7EA0\u6B63\u540E\u82E5\u65E0\u4EFB\u4F55\u8840\u7F18\u7ED3\u6784\uFF0C\u6761\u76EE\u6574\u4E2A\u64A4\u6389\uFF0C\u7EF4\u6301\u300C\u666E\u901A\u4F1A\u8BDD\u4E0D\u4EA7\u751F\u6761\u76EE\u300D\u3002\n const info = lineage[id]\n info.empty = false\n if (!info.origin && !info.parentSession) delete lineage[id]\n }\n }\n async function refineEmptyLineage(lineage, entries) {\n if (!persistence || typeof persistence.inspectSession !== 'function') return\n const limiter = createLimiter(4)\n const todo = []\n for (const entry of entries) {\n const size = entry && Number.isFinite(entry.sizeBytes) ? entry.sizeBytes : null\n if (size === null || size > EMPTY_DECODE_LIMIT) continue\n const id = String(entry.id)\n const scanned = emptyScanCache.get(id)\n if (scanned && scanned.sizeBytes === size) { applyEmptyScan(lineage, id, scanned.empty); continue }\n if (todo.length < REFINE_BUDGET) todo.push({ id, size })\n }\n await Promise.all(todo.map(({ id, size }) => limiter(async () => {\n let isEmpty = false\n try {\n const types = []\n await persistence.inspectSession(id, { onEvents: (batch) => {\n for (const ev of batch || []) if (types.length < 64) types.push(ev && ev.type)\n } })\n isEmpty = isEmptyEventTypes(types)\n } catch (e) { isEmpty = false }\n emptyScanCache.set(id, { sizeBytes: size, empty: isEmpty })\n applyEmptyScan(lineage, id, isEmpty)\n })))\n // \u7F13\u5B58\u53EA\u4FDD\u7559\u300C\u672C\u8F6E\u4ECD\u53C2\u4E0E\u5224\u5B9A\u300D\u7684\u4F1A\u8BDD\uFF1A\u5DF2\u5F7B\u5E95\u5220\u9664\u6216\u65E5\u5FD7\u81A8\u80C0\u8D85\u8FC7\u89E3\u7801\n // \u4E0A\u9650\u7684\u6761\u76EE\u4E0D\u518D\u6709\u7528\uFF0C\u6DD8\u6C70\u6389\u9632\u6B62 Map \u968F\u5386\u53F2\u4F1A\u8BDD\u65E0\u9650\u589E\u957F\u3002\n const live = new Set()\n for (const entry of entries) {\n const size = entry && Number.isFinite(entry.sizeBytes) ? entry.sizeBytes : null\n if (size !== null && size <= EMPTY_DECODE_LIMIT) live.add(String(entry.id))\n }\n for (const key of emptyScanCache.keys()) {\n if (!live.has(key)) emptyScanCache.delete(key)\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, buildStamp: BUILD_STAMP }),\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 // issue #8\uFF1A\u5F52\u6863\u5217\u8868\u4E5F\u590D\u7528\u300C\u7F13\u5B58\u76F4\u8BFB + \u540E\u53F0\u9884\u70ED\u300D\u7684\u7EDF\u4E00\u7BA1\u7EBF\u3002\n // \u65E7\u5B9E\u73B0\u9010\u6761 resolveOne(id)\uFF08\u65E0 header\u3001\u65E0\u6307\u7EB9\uFF09\u2014\u2014\u51B7\u542F\u52A8\u5BF9\u6BCF\u6761\u5F52\u6863\n // \u4F1A\u8BDD\u6574\u672C\u89E3\u7801\uFF0C\u4E14\u8FDE\u8FDB\u7A0B\u5185\u7F13\u5B58\u90FD\u6C38\u8FDC\u547D\u4E2D\u4E0D\u4E86\u3002\n const wanted = new Set(idStrs)\n const detailed = await allSessionItemsDetailed()\n const items = detailed.items.filter((it) => wanted.has(String(it.sessionId)) && it.archived)\n for (const it of items) delete it.archived\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 try { await titleIndex.remove([sid]) } catch (e) { /* \u7D22\u5F15\u6E05\u7406\u5931\u8D25\u4E0D\u963B\u585E\u5220\u9664\u7ED3\u679C */ }\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); await 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(), warmPending: warmPendingNow() })\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 // \u5B50\u4EE3\u7406\u8840\u7F18\u6811\uFF08\u7BA1\u7406\u89C6\u56FE\u6570\u636E\u9762\uFF09\uFF1A\u7ED9\u5B9A\u7236\u4F1A\u8BDD\uFF0C\u8FD4\u56DE origin==='subagent'\n // \u7684\u9012\u5F52\u5B50\u6811\u3002DSH \u539F\u751F\u76EE\u5F55\uFF08ui-subagent\uFF09\u53EA\u8BFB\uFF0C\u8FD9\u91CC\u8865\u7BA1\u7406\u80FD\u529B\u7684\u6570\u636E\u6765\u6E90\u3002\n // \u53EA\u8BFB\u5B98\u65B9 header \u8840\u7F18\u5B57\u6BB5\uFF08parentSession/origin/delegationDepth/createdAt\uFF09\uFF0C\n // \u6807\u9898\u8D70 v3.6.2 \u7684\u7EAF\u7F13\u5B58\u8BFB\u53D6\uFF08metaCache/\u6301\u4E45\u7D22\u5F15/\u6743\u5A01\u7F13\u5B58\uFF09\uFF0C\u672A\u547D\u4E2D\u5165\u540E\u53F0\n // \u9884\u70ED\u3001\u672C\u8F6E\u8FD4\u56DE null\uFF1B\u8BF7\u6C42\u8DEF\u5F84\u96F6\u89E3\u7801\u3002\n // live \u6807\u8BB0 = \u4F1A\u8BDD\u5728\u5185\u5B58\u91CC\u6D3B\u7740\uFF08\u6B63\u5728\u8FD0\u884C\u6216\u5DF2\u6253\u5F00\uFF09\uFF1A\u6279\u91CF\u6E05\u7406\u5FC5\u987B\u8DF3\u8FC7\u3002\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/lineage-tree',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const rootId = body && typeof body.sessionId === 'string' ? body.sessionId : ''\n if (!rootId || !isSafeSessionId(rootId)) return json(res, { error: 'missing sessionId' }, 400)\n const headerById = new Map()\n const sizeById = new Map()\n // \u4E0E\u4F1A\u8BDD\u5217\u8868\u540C\u6E90\u7684\u53EF\u89C1\u6027\u5224\u5B9A\uFF1A\u56DE\u6536\u7AD9\u9879\u76EE\u4E00\u5F8B\u4E0D\u53C2\u4E0E\u8840\u7F18\u6811\u3002\n const trashedIds = new Set()\n let purgedIds = []\n const persistedIds = new Set()\n try {\n const store = await readTrashStore()\n for (const item of store.items) trashedIds.add(String(item.sessionId))\n purgedIds = store.purgedSessionIds.map(String)\n } catch (e) { /* best-effort */ }\n const addHeader = (h, sizeBytes) => {\n if (!h || h.id == null) return\n const id = String(h.id)\n // \u56DE\u6536\u7AD9\u91CC\u7684\u4F1A\u8BDD\uFF08\u8F6F\u5220\u9664\u540E\u65E5\u5FD7\u5DF2\u642C\u8D70\uFF09\u4E0D\u80FD\u51FA\u73B0\u5728\u8840\u7F18\u6811\u91CC\uFF0C\u5426\u5219\n // \u4F1A\u51FA\u73B0\u300C\u5220\u6389\u4E86\u4FA7\u680F\u8FD8\u5728\u300D\u3002\u5F7B\u5E95\u5220\u9664\u7684\u5893\u7891\u5728\u4E0B\u9762\u6309\u300C\u5F53\u524D\u5DF2\u4E0D\u5B58\u5728\u300D\n // \u7EDF\u4E00\u5254\u9664\uFF0C\u907F\u514D\u538B\u4F4F\u540E\u6765\u540C id \u91CD\u5EFA\u7684\u4F1A\u8BDD\u3002\n if (headerById.has(id) || trashedIds.has(id)) return\n headerById.set(id, {\n parentSession: h.parentSession != null ? String(h.parentSession) : null,\n subagent: h.origin === 'subagent',\n delegationDepth: Number.isFinite(h.delegationDepth) ? h.delegationDepth : null,\n createdAt: typeof h.createdAt === 'number' ? h.createdAt : null,\n })\n if (Number.isFinite(sizeBytes)) sizeById.set(id, sizeBytes)\n }\n // v3.6.2 #4\uFF1A\u6807\u9898\u53EA\u8BFB\u7F13\u5B58\uFF08metaCache \u2192 \u6301\u4E45\u7D22\u5F15 \u2192 \u6743\u5A01\u7F13\u5B58\uFF09\uFF0C\u672A\u547D\u4E2D\n // \u5165\u540E\u53F0\u9884\u70ED\u3001\u672C\u8F6E\u8FD4\u56DE null\u3002\u65E7\u5B9E\u73B0\u5728\u8BF7\u6C42\u8DEF\u5F84\u76F4\u8C03 projectTitles\u2014\u2014\n // \u5C55\u5F00\u4E00\u4E2A N \u5B50\u6811\u7684\u7236\u4F1A\u8BDD = N \u6B21\u6574\u672C\u89E3\u7801\u540C\u6B65\u5728\u8BF7\u6C42\u8DEF\u5F84\u4E0A\uFF08issue #8\n // \u8981\u6D88\u706D\u7684\u5F62\u6001\u5728\u672C\u8DEF\u7531\u7684\u6B8B\u7559\uFF09\u3002\u8FD9\u91CC\u987A\u624B\u8BB0\u4E0B\u6307\u7EB9\u4E0E\u539F\u59CB header\uFF0C\u4F9B\n // \u7F13\u5B58\u8BFB\u53D6\u4E0E enqueueWarm \u4F7F\u7528\u3002\n const lineageStats = new Map()\n const lineageHeaders = new Map()\n try {\n for (const entry of await persistence.listEntries()) {\n addHeader(entry.header, entry.sizeBytes)\n const eid = entry && entry.id != null ? String(entry.id) : null\n if (eid) {\n lineageHeaders.set(eid, { header: (entry && entry.header) || null })\n // \u53EA\u6709 handle \u4E16\u4EE3\uFF08snapshot \u5E26 revision\uFF09\u624D\u5EFA stats\uFF1Blegacy \u7684\u5217\u8868\u5FEB\u7167\n // \u672C\u5C31\u6CA1\u6709\u8FD9\u4E9B\u89C2\u6D4B\uFF0C\u5176\u6807\u9898\u7ECF sidebarAuthority \u7684 authorityTitleCache\n // \u515C\u4F4F\u3002\u523B\u610F\u4E0D\u5728\u8FD9\u91CC\u5408\u6210 sz-only stat\u2014\u2014\u4F1A\u548C\u5217\u8868\u6784\u5EFA\u7684 mtime:size\n // \u6307\u7EB9\u5728\u540C\u4E00\u7D22\u5F15\u91CC\u4E52\u4E53\u8986\u76D6\uFF0C\u5F15\u53D1\u4EA4\u66FF\u91CD\u590D\u89E3\u7801\u3002\n if (entry && typeof entry.revision === 'string' && entry.revision) {\n lineageStats.set(eid, Number.isFinite(entry.sizeBytes)\n ? { revision: entry.revision, sizeBytes: Number(entry.sizeBytes) }\n : { revision: entry.revision })\n }\n }\n if (entry && entry.id != null) persistedIds.add(String(entry.id))\n }\n } catch (e) { /* best-effort */ }\n const liveIds = new Set()\n const live = ctx.get('sessions')\n try {\n if (live && typeof live.list === 'function') {\n live.list().forEach((s) => { liveIds.add(String(s.id)); addHeader(s.header, undefined) })\n }\n } catch (e) { /* best-effort */ }\n // \u5893\u7891\u53EA\u5BF9\u300C\u6301\u4E45\u5C42\u91CC\u786E\u5B9E\u6CA1\u4E86\u300D\u7684 id \u751F\u6548\uFF1A\u540C id \u4F1A\u8BDD\u540E\u6765\u91CD\u65B0\u51FA\u73B0\u65F6\n // \u5FC5\u987B\u8BA9\u4F4D\uFF0C\u4E0D\u80FD\u6C38\u4E45\u538B\u4F4F\u65B0\u4F1A\u8BDD\uFF08\u4E0E\u4F1A\u8BDD\u5217\u8868\u540C\u4E00\u5957\u89C4\u5219\uFF09\u3002\n for (const id of purgedIds) {\n if (!persistedIds.has(id)) headerById.delete(id)\n }\n // \u5B50\u4EE3\u7406\u7D22\u5F15\uFF1AparentSession \u2192 \u76F4\u63A5\u5B50\u4EE3\u7406 id \u5217\u8868\uFF08\u53EA\u6536 origin==='subagent'\uFF09\u3002\n const kidsOf = new Map()\n for (const [id, h] of headerById) {\n if (!h.subagent || !h.parentSession) continue\n if (!kidsOf.has(h.parentSession)) kidsOf.set(h.parentSession, [])\n kidsOf.get(h.parentSession).push(id)\n }\n // \u9012\u5F52\u5C55\u5F00\uFF1Avisited \u9632\u73AF\uFF0C\u8282\u70B9\u603B\u6570\u5C01\u9876\u9632\u75C5\u6001\u6570\u636E\u3002\n const MAX_NODES = 500\n let nodeCount = 0\n const build = (id, depth, visited) => {\n nodeCount++\n const h = headerById.get(id) || {}\n const childVisited = new Set(visited)\n childVisited.add(id)\n const kidIds = nodeCount >= MAX_NODES ? [] : (kidsOf.get(id) || []).filter((k) => !childVisited.has(k))\n return {\n sessionId: id,\n parentSession: h.parentSession || null,\n delegationDepth: h.delegationDepth,\n depth,\n createdAt: h.createdAt || null,\n sizeBytes: sizeById.has(id) ? sizeById.get(id) : null,\n live: liveIds.has(id),\n title: null,\n children: kidIds.map((k) => build(k, depth + 1, childVisited)),\n }\n }\n const nodes = (kidsOf.get(rootId) || []).map((k) => build(k, 1, new Set([rootId])))\n const allIds = [rootId]\n const walk = (n) => { allIds.push(n.sessionId); n.children.forEach(walk) }\n nodes.forEach(walk)\n // v3.6.2 #4\uFF1A\u7F13\u5B58\u8BFB\u53D6 + \u9884\u70ED\u5165\u961F\uFF0C\u8BF7\u6C42\u8DEF\u5F84\u96F6\u89E3\u7801\u3002#12\uFF1A\u6807\u9898\u6309\n // MAX_TITLE \u622A\u65AD\uFF0C\u4E0E\u5217\u8868\u8F93\u51FA\u53E3\u5F84\u4E00\u81F4\u3002\n const lineageIds = allIds.map(String)\n const { cached: lineageCached, missing: lineageMissing } = metaCache.partition(lineageIds, lineageStats)\n const lineagePersisted = await hydrateFromPersist(lineageMissing, lineageStats)\n for (const [id, meta] of lineagePersisted) metaCache.set(id, lineageStats.get(id), meta)\n const lineageRest = lineageMissing.filter((id) => !lineagePersisted.has(id))\n if (lineageRest.length) enqueueWarm(lineageRest, lineageStats, lineageHeaders)\n const truncateTitle = (t) => (t ? (t.length > MAX_TITLE ? t.slice(0, MAX_TITLE) + '\u2026' : t) : null)\n const titleOf = (id) => {\n const key = String(id)\n const m = lineageCached.get(key) || lineagePersisted.get(key)\n return truncateTitle((m && m.title) || authorityTitleCache.get(key) || null)\n }\n const fill = (n) => { n.title = titleOf(n.sessionId); n.children.forEach(fill) }\n nodes.forEach(fill)\n json(res, { parent: { sessionId: rootId, title: titleOf(rootId) }, nodes })\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 moveOrQueue(sid, target)\n if (moved.queued) return json(res, { sessionId: sid, ...moved })\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 // Move many conversations to one target workspace (issue #7). Sequential\n // on purpose: each move rewrites frame0 (file IO), and one bad session\n // must not block the rest. Single reindex at the end covers all moves.\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/move-many',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const ids = Array.isArray(body && body.sessionIds)\n ? [...new Set(body.sessionIds.filter((x) => typeof x === 'string' && x))]\n : []\n const target = body && typeof body.targetPath === 'string' ? body.targetPath : null\n if (!ids.length) return json(res, { ok: false, error: 'missing sessionIds' }, 400)\n if (!target) return json(res, { ok: false, error: 'missing targetPath' }, 400)\n let moved = 0\n const failed = []\n const queued = []\n for (const sid of ids) {\n try {\n const r = await moveOrQueue(sid, target)\n if (r && r.queued) { queued.push(sid); continue }\n // frame0 \u7684 cwd \u88AB\u6539\u5199\uFF1A\u4E0E\u5355\u79FB\u52A8\u540C\u7406\u7531\uFF0C\u4E3B\u52A8\u4E22\u7F13\u5B58\u4E0D\u7B49\u6307\u7EB9\u5931\u6548\u3002\n metaCache.invalidate(sid)\n moved++\n } catch (e) {\n const err = e && e.code ? { sessionId: sid, error: String((e && e.message) || e), code: e.code } : { sessionId: sid, error: String((e && e.message) || e) }\n failed.push(err)\n }\n }\n try { await reindexRegistry() } catch (e) { /* best-effort */ }\n json(res, {\n moved,\n failed,\n ...(queued.length > 0 ? { queued, notes: [`${queued.length} \u4E2A\u4F1A\u8BDD\u5DF2\u6392\u961F\uFF08\u6B63\u88AB DSH \u6253\u5F00\uFF09\uFF0C\u91CD\u542F DSH \u540E\u4F1A\u81EA\u52A8\u5B8C\u6210\uFF1B\u91CD\u542F\u540E\u8BF7\u5148\u522B\u6253\u5F00\u5B83\u4EEC\u3002`] } : {}),\n })\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 // \u5F85\u79FB\u52A8\u961F\u5217\uFF1A\u67E5\u770B / \u53D6\u6D88\uFF08\u4F1A\u8BDD\u88AB\u5360\u7528\u65F6\u6392\u961F\uFF0C\u91CA\u653E\u540E\u81EA\u52A8\u5B8C\u6210\uFF09\u3002\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/pending-moves',\n handler: async (req, res) => {\n try {\n const items = await pendingMoves.list()\n json(res, { items: items.map((i) => ({ sessionId: i.sessionId, targetPath: i.targetPath, queuedAt: i.queuedAt, attempts: i.attempts })) })\n } catch (e) {\n json(res, { error: String((e && e.message) || e) }, 500)\n }\n },\n }))\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/pending-moves/cancel',\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 removed = await pendingMoves.remove(ids)\n json(res, { ok: true, removed })\n } catch (e) {\n json(res, { ok: false, 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", "// Deferred cross-workspace moves (\"\u6392\u961F\u79FB\u52A8\").\n//\n// \u80CC\u666F\uFF1A0.1.5 \u8D77\u4F1A\u8BDD\u65E5\u5FD7\u662F**\u5355\u5199\u8005**\u2014\u2014agent-loop \u5728 resume \u65F6\u4F1A\u8BDD\u65F6\u53D6\u5199\u6240\u6709\u6743\n// \uFF08\u65E5\u5FD7\u65C1\u7684 session.lock \u4E0A\u4E00\u4E2A flock(2)\uFF09\uFF0C\u6301\u6709\u5230 agent \u5378\u8F7D\uFF1B\u63D2\u4EF6\u65E2\u62FF\u4E0D\u5230\u8BE5\n// \u53E5\u67C4\uFF0C\u4E5F\u6CA1\u6709\u4EFB\u4F55\u516C\u5171 API \u80FD\u91CA\u653E\u522B\u4EBA\u7684\u6240\u6709\u6743\uFF08dsh-session \u670D\u52A1\u53EA\u66B4\u9732\n// list/get/prepare/enter/fork/flush\uFF1B`session/disposed` \u53EA\u5728\u6301\u6709\u5B83\u7684 fiber \u88AB\n// dispose \u65F6\u53D1\u51FA\uFF09\u3002\u5728\u5360\u7528\u671F\u786C\u642C\u76EE\u5F55\u4F1A\u8BA9\u5728\u5199\u8005\u7EE7\u7EED\u5F80\u65E7 inode \u5199\u3001\u5E76\u5728\u65E7\u8DEF\u5F84\n// \u91CD\u5EFA\u7A7A\u58F3\uFF082026-09-10 \u5B9E\u6D4B\u8FC7\uFF09\uFF0C\u6240\u4EE5\u552F\u4E00\u5B89\u5168\u7684\u505A\u6CD5\u662F**\u6392\u961F\u7B49\u5B83\u88AB\u91CA\u653E**\u3002\n//\n// \u672C\u6A21\u5757\u53EA\u8D1F\u8D23\u6301\u4E45\u5316\u961F\u5217\u672C\u8EAB\uFF08\u8BFB\u5199/\u53BB\u91CD/\u6E05\u7406\uFF09\uFF0C\u6267\u884C\u65F6\u673A\u7531 index.js \u51B3\u5B9A\uFF1A\n// - \u5BBF\u4E3B\u91CA\u653E\u8BE5\u4F1A\u8BDD\uFF08session/disposed\uFF1B0.1.5 \u65E0\u7528\u6237\u53EF\u89C1\u7684\u5173\u95ED\u5165\u53E3\uFF0C\u7EDD\u5927\u591A\u6570\u60C5\u51B5\n// \u5C31\u662F\u8FDB\u7A0B\u9000\u51FA\uFF09\u2192 \u7ACB\u523B\u5C1D\u8BD5\n// - \u63D2\u4EF6\u542F\u52A8\u540E\uFF08\u4F1A\u8BDD\u5C1A\u672A\u88AB\u6253\u5F00\uFF09\u2192 \u515C\u5E95\u5C1D\u8BD5\n// - \u5468\u671F\u6027\u8F7B\u91CF\u91CD\u8BD5\uFF08\u961F\u5217\u4E3A\u7A7A\u65F6\u4E0D\u542F\u52A8\u5B9A\u65F6\u5668\uFF09\n// \u5199\u5165\u6CBF\u7528\u672C\u4ED3\u5E93\u5176\u4ED6\u7D22\u5F15\u7684\u6A21\u5F0F\uFF1AschemaVersion + \u539F\u5B50\u5199\uFF08tmp \u2192 rename\uFF09\u3002\n\nimport { readFileSync } from 'node:fs'\nimport { mkdir, rename, writeFile } from 'node:fs/promises'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\n\nconst SCHEMA_VERSION = 1\nconst DEFAULT_DIR = process.env.DSH_SESSIONS_MANAGER_PENDING_DIR\n || process.env.DSH_SESSIONS_MANAGER_STAR_DIR\n || join(homedir(), '.dsh', 'sessions-manager')\nconst MAX_ITEMS = 50\n// \u975E\"\u5360\u7528\u4E2D\"\u7684\u5931\u8D25\uFF08\u76EE\u6807\u5DE5\u4F5C\u533A\u6D88\u5931\u3001\u65E5\u5FD7\u635F\u574F\u2026\uFF09\u7559\u5728\u961F\u5217\u91CC\u4F46\u8BA1\u6570\uFF1B\u8D85\u8FC7\u9608\u503C\u5C31\u4E22\u5F03\uFF0C\n// \u907F\u514D\u4E00\u4E2A\u6C38\u8FDC\u5931\u8D25\u7684\u6761\u76EE\u8BA9\u6BCF\u6B21\u91CD\u8BD5\u90FD\u767D\u8DD1\u3002\nconst MAX_ATTEMPTS = 5\n\nfunction isSafeId(value) {\n return typeof value === 'string' && value.length > 0 && value.length <= 200\n}\n\nfunction normalizeStore(raw) {\n const items = []\n const seen = new Set()\n const source = raw && Array.isArray(raw.items) ? raw.items : []\n for (const item of source) {\n if (!item || !isSafeId(item.sessionId) || typeof item.targetPath !== 'string' || item.targetPath.length === 0) continue\n if (seen.has(item.sessionId)) continue\n seen.add(item.sessionId)\n items.push({\n sessionId: String(item.sessionId),\n targetPath: String(item.targetPath),\n queuedAt: Number.isFinite(item.queuedAt) ? Number(item.queuedAt) : Date.now(),\n attempts: Number.isSafeInteger(item.attempts) && item.attempts >= 0 ? Number(item.attempts) : 0,\n })\n if (items.length >= MAX_ITEMS) break\n }\n return { schemaVersion: SCHEMA_VERSION, items }\n}\n\n/**\n * @param {object} [options]\n * @param {string} [options.dir] \u961F\u5217\u6240\u5728\u76EE\u5F55\uFF08\u6D4B\u8BD5\u6CE8\u5165\u4E34\u65F6\u76EE\u5F55\uFF09\n */\nexport function createPendingMoveStore(options = {}) {\n const dir = options.dir || DEFAULT_DIR\n const indexPath = options.indexPath || join(dir, 'pending-moves.json')\n let mutation = Promise.resolve()\n\n async function read() {\n try {\n return normalizeStore(JSON.parse(readFileSync(indexPath, 'utf8')))\n } catch (e) {\n return normalizeStore(null)\n }\n }\n\n async function write(store) {\n await mkdir(dir, { recursive: true })\n const tmp = join(dir, `.pending-moves-${process.pid}-${Date.now()}.tmp`)\n await writeFile(tmp, JSON.stringify(normalizeStore(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 return {\n indexPath,\n dir,\n list: async () => (await read()).items,\n has: async (sessionId) => (await read()).items.some((item) => item.sessionId === String(sessionId)),\n queue: (sessionId, targetPath) => mutate((store) => {\n if (!isSafeId(sessionId) || typeof targetPath !== 'string' || targetPath.length === 0) return null\n const existing = store.items.find((item) => item.sessionId === String(sessionId))\n if (existing) {\n existing.targetPath = String(targetPath)\n existing.attempts = 0\n return existing\n }\n const item = { sessionId: String(sessionId), targetPath: String(targetPath), queuedAt: Date.now(), attempts: 0 }\n store.items.push(item)\n if (store.items.length > MAX_ITEMS) store.items.splice(0, store.items.length - MAX_ITEMS)\n return item\n }),\n remove: (sessionIds) => mutate((store) => {\n const drop = new Set((Array.isArray(sessionIds) ? sessionIds : [sessionIds]).filter(isSafeId).map(String))\n const before = store.items.length\n store.items = store.items.filter((item) => !drop.has(item.sessionId))\n return before - store.items.length\n }),\n bumpAttempts: (sessionId) => mutate((store) => {\n const item = store.items.find((entry) => entry.sessionId === String(sessionId))\n if (!item) return null\n item.attempts += 1\n if (item.attempts >= MAX_ATTEMPTS) {\n store.items = store.items.filter((entry) => entry.sessionId !== item.sessionId)\n return { dropped: true, attempts: item.attempts }\n }\n return { dropped: false, attempts: item.attempts }\n }),\n }\n}\n\nexport { MAX_ITEMS, MAX_ATTEMPTS, SCHEMA_VERSION, normalizeStore }\n", "// Stale atomic-write temp sweeper.\n//\n// \u56DB\u4E2A\u72B6\u6001\u6587\u4EF6\u5199\u5165\u5668\u90FD\u7528\u300C\u540C\u76EE\u5F55 .<name>-<pid>-<ts>.tmp \u2192 rename \u5230\u6B63\u5F0F\u6587\u4EF6\u300D\u7684\n// \u539F\u5B50\u5199\u6A21\u5F0F\uFF08star-index / auto-archive / title-persist-index / index.js \u7684\u56DE\u6536\u7AD9\u7D22\u5F15\uFF09\u3002\n// \u82E5\u8FDB\u7A0B\u5728 writeFile \u4E0E rename \u4E4B\u95F4\u88AB\u6740\uFF08\u53CD\u590D\u91CD\u542F dsm web \u65F6\u5F88\u5E38\u89C1\uFF09\uFF0C\u4E34\u65F6\u6587\u4EF6\u5C31\u7559\u5728\n// \u76EE\u5F55\u91CC\uFF1A\u5B9E\u6D4B ~/.dsh/sessions-manager \u7D2F\u79EF\u4E86 153 \u4E2A\u5B64\u513F .star-*.tmp\uFF082026-09-10\uFF09\u3002\n//\n// \u542F\u52A8\u65F6\u626B\u4E00\u904D\u8FD9\u4E9B\u76EE\u5F55\uFF0C\u628A\u300C\u8D85\u8FC7 maxAgeMs \u6CA1\u88AB\u52A8\u8FC7\u300D\u7684\u4E34\u65F6\u6587\u4EF6\u6E05\u6389\u3002\u7528\u5E74\u9F84\u800C\u975E pid\n// \u5224\u5B9A\uFF1Apid \u4F1A\u56DE\u7ED5\uFF0C\u800C 1 \u5C0F\u65F6\u7684\u5BBD\u9650\u671F\u8FDC\u5927\u4E8E\u4EFB\u4F55\u6B63\u5E38\u5199\u5165\u7A97\u53E3\uFF0C\u4E0D\u4F1A\u78B0\u5230\u5E76\u53D1\u4E2D\u7684\u5199\u5165\u3002\n\nimport { readdir, rm, stat } from 'node:fs/promises'\nimport { join } from 'node:path'\n\nconst TEMP_NAME_RE = /^\\..+-\\d+-\\d+\\.tmp$/\n\n/**\n * @param {string[]} dirs \u9700\u8981\u6E05\u626B\u7684\u76EE\u5F55\uFF08\u4E0D\u5B58\u5728\u65F6\u9759\u9ED8\u8DF3\u8FC7\uFF09\n * @param {object} [options]\n * @param {number} [options.maxAgeMs] \u53EA\u6E05\u7406\u6BD4\u8FD9\u66F4\u65E7\u7684\u4E34\u65F6\u6587\u4EF6\uFF08\u9ED8\u8BA4 1 \u5C0F\u65F6\uFF09\n * @param {number} [options.now] \u6CE8\u5165\u65F6\u949F\uFF0C\u4FBF\u4E8E\u6D4B\u8BD5\n * @returns {Promise<number>} \u6E05\u7406\u6389\u7684\u4E34\u65F6\u6587\u4EF6\u6570\n */\nexport async function sweepStaleStateTemps(dirs, options = {}) {\n const maxAgeMs = Number.isSafeInteger(options.maxAgeMs) && options.maxAgeMs >= 0 ? options.maxAgeMs : 3600_000\n const now = Number.isFinite(options.now) ? options.now : Date.now()\n let removed = 0\n for (const dir of Array.isArray(dirs) ? dirs : []) {\n if (typeof dir !== 'string' || dir.length === 0) continue\n let entries\n try { entries = await readdir(dir) } catch (e) { continue }\n for (const name of entries) {\n if (!TEMP_NAME_RE.test(name)) continue\n const path = join(dir, name)\n let info\n try { info = await stat(path) } catch (e) { continue }\n if (!info.isFile()) continue\n if (now - info.mtimeMs < maxAgeMs) continue\n try { await rm(path, { force: true }); removed++ } catch (e) { /* \u6E05\u4E0D\u6389\u7684\u4E0B\u6B21\u518D\u8BF4 */ }\n }\n }\n return removed\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// \u8DE8\u8FDB\u7A0B\uFF08\u91CD\u542F\u540E\uFF09\u4ECD\u53EF\u7528\u7684\u6301\u4E45\u6307\u7EB9\uFF0C\u4F9B title-persist-index \u4F7F\u7528\uFF08issue #8\uFF09\u3002\n//\n// - legacy \u4E16\u4EE3\uFF1AfingerprintOf \u4EA7\u51FA (mtimeMs:size) \u6587\u4EF6\u6307\u7EB9\uFF0C\u672C\u8EAB\u53EF\u6301\u4E45\u5316\uFF1B\n// - handle \u4E16\u4EE3\uFF080.1.3+\uFF09\uFF1AfingerprintOf \u4EA7\u51FA rev: \u6307\u7EB9\uFF0C\u88AB isPersistableFingerprint\n// \u6B63\u786E\u62D2\u7EDD\uFF08revision \u662F\u5B9E\u4F8B\u5185 opaque token\uFF09\u3002\u4F46\u8FD9\u6837\u6301\u4E45\u7D22\u5F15\u5728\u8BE5\u4E16\u4EE3**\u4ECE\u4E0D\n// \u5199\u5165**\u2014\u2014issue #8 \u5B9E\u6D4B\uFF1A249MB / 87 \u65E5\u5FD7\u7684\u5E93\u6BCF\u6B21\u91CD\u542F\u90FD\u91CD\u65B0\u5168\u91CF\u89E3\u7801\u7EA6 90s\u3002\n// \u9000\u800C\u6C42\u5176\u6B21\u7528\u5B98\u65B9 list()/stat() \u6BCF\u6B21\u5E26\u56DE\u7684 sizeBytes\uFF08\"sz:<n>\"\uFF09\uFF1A\n// \u65E5\u5FD7\u4EFB\u4F55\u8FFD\u52A0/\u622A\u65AD\u90FD\u4F1A\u6539\u53D8 size\uFF0Csize \u4E0D\u53D8\u800C\u6807\u9898\u53D8\u5316\u5728\u771F\u5B9E\u573A\u666F\u91CC\u57FA\u672C\n// \u4E0D\u5B58\u5728\uFF1B\u6700\u574F\u4EE3\u4EF7\u662F\u663E\u793A\u4E00\u6761\u9648\u65E7\u6807\u9898\uFF0C\u7EDD\u4E0D\u4EA7\u751F\u9519\u8BEF\u6570\u636E\u3002\n// cwd/createdAt \u4E0D\u53D7\u6B64\u5F71\u54CD\uFF1A\u56DE\u586B\u65F6\u59CB\u7EC8\u4EE5\u6700\u65B0 list header \u4E3A\u6743\u5A01\uFF08\u89C1 index.js\uFF09\u3002\n// - \u62FF\u4E0D\u5230\u4EFB\u4F55\u53EF\u7528\u89C2\u6D4B\u91CF\u65F6\u8FD4\u56DE null\uFF08\u8C03\u7528\u65B9\u6309\u672A\u547D\u4E2D/\u4E0D\u843D\u76D8\u5904\u7406\uFF09\u3002\nexport function persistFingerprintOf(stat) {\n const fp = fingerprintOf(stat)\n if (fp && isPersistableFingerprint(fp)) return fp\n if (stat && Number.isFinite(stat.sizeBytes) && stat.sizeBytes >= 0) return `sz:${stat.sizeBytes}`\n return null\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, resolved? }\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// resolved\uFF08schema v2\uFF0Cv3.6.2 #1\uFF09\uFF1A\u6807\u8BB0\u300C\u6295\u5F71\u786E\u5B9E\u6210\u529F\u8FC7\u300D\u3002title \u4E3A null \u7684\n// \u6761\u76EE\u53EA\u6709\u5E26\u8FD9\u4E2A\u6807\u8BB0\u624D\u53EF\u4FE1\u2014\u2014\u6CA1\u6807\u8BB0\u7684 null \u6807\u9898\u6761\u76EE\u662F v3.6.1 \u4E4B\u524D\u300C\u6295\u5F71\u5931\u8D25\n// \u88AB\u5F53\u7ED3\u679C\u7F13\u5B58\u300D\u7684\u6C61\u67D3\u6E90\uFF0C\u8BFB\u53D6\u65F6\u5FC5\u987B\u4E22\u5F03\u5E76\u91CD\u65B0\u9884\u70ED\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 = 2\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 const resolved = raw.resolved === true || raw.resolved === 1\n if (!fingerprint || fingerprint.startsWith('rev:')) return null\n if (!title && !cwd) return null\n // v3.6.2 #1\uFF1Anull \u6807\u9898\u53EA\u6709\u300C\u6295\u5F71\u786E\u5B9E\u6210\u529F\u8FC7\u300D\uFF08\u4F1A\u8BDD\u771F\u7684\u6CA1\u6709\u6807\u9898\u4E8B\u4EF6\uFF09\u624D\u53EF\u4FE1\u3002\n // \u65E0 resolved \u6807\u8BB0\u7684 null \u6807\u9898\u6761\u76EE = v3.6.1 \u7684\u5931\u8D25\u6C61\u67D3\u6E90\uFF08\u6216 v1 \u65E7\u6570\u636E\uFF09\uFF0C\n // \u4E00\u5F8B\u4E22\u5F03 \u2192 \u4E0B\u6B21\u6309\u672A\u547D\u4E2D\u91CD\u65B0\u9884\u70ED\uFF0C\u7D22\u5F15\u81EA\u6108\u3002\n if (!title && !resolved) return null\n const entry = { title, cwd, createdAt, fingerprint, updatedAt }\n if (resolved) entry.resolved = 1\n return entry\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\n// \u89C4\u8303 generation \u6587\u4EF6\uFF1A\u5B98\u65B9 `session.vN.jsonl[.zstd]`\uFF0C**v0 \u4EE3\u65E0 `.vN.` \u5206\u91CF**\n// \uFF08\u5373 `session.jsonl[.zstd]`\uFF0Clegacy \u65F6\u4EE3\u4EA7\u7269\uFF09\u3002\u5B98\u65B9\n// `parseSessionFormatLogFilename` \u628A v0 \u5F53 version 0 \u53C2\u4E0E\u300C\u6700\u9AD8\u4EE3\u4F18\u5148\u300D\uFF0C\n// \u6240\u4EE5\u8FD9\u91CC\u4E5F\u5FC5\u987B\u6536 v0\uFF0C\u5426\u5219\u300C\u53EA\u6709 v0 \u4EE3\u300D\u7684\u4F1A\u8BDD\u4F1A\u88AB\u8BEF\u5224\u4E3A\u4E0D\u53EF\u5B9A\u4F4D\n// \uFF08\u79FB\u52A8/\u5F7B\u5E95\u5220\u9664\u9759\u9ED8\u7981\u7528\uFF09\u3002\u4E34\u65F6\u5907\u4EFD\u540D\uFF08`.move-backup-\u2026`\uFF09\u4E0D\u4EE5\n// `.jsonl`/`.zstd` \u7ED3\u5C3E\uFF0C\u5929\u7136\u4E0D\u5339\u914D\u3002\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\n// `generation` \u53EA\u662F\u540D\u5B57\u91CC\u7684 `.vN` \u5206\u91CF\uFF1A0 = legacy \u7684 `session.jsonl`\uFF0C2 = `session.v2.jsonl`\u3002\n// \u5B9E\u9645\u843D\u76D8\u7248\u672C\u7531 runtime \u7684\u683C\u5F0F\u76EE\u5F55\u51B3\u5B9A\uFF0C\u6B64\u5904\u4E0D\u5047\u8BBE\u201C\u5F53\u524D\u7248\u672C\u662F\u51E0\u201D\u3002\nexport function deriveGenerationLogPath(root, cwd, id, { compression = 'zstd', generation = 2 } = {}) {\n const base = generation === 0 ? 'session.jsonl' : `session.v${generation}.jsonl`\n return join(deriveSessionDir(root, cwd, id), `${base}${compression === 'zstd' ? '.zstd' : ''}`)\n}\n\n// \u540D\u5B57\u91CC\u7684\u4EE3\u7248\u672C\u53F7\uFF08`session.v3.jsonl.zstd` \u2192 3\uFF1B`session.jsonl.zstd` \u2192 0\uFF09\u3002\nexport function generationVersionOf(name) {\n return Number((String(name).match(/^session\\.v(\\d+)\\./) || [])[1] || 0)\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\uFF08v0/legacy \u4E5F\u662F\u5019\u9009\uFF0C\u7248\u672C\u53F7\u6700\u5C0F\uFF09\uFF0C\u4FDD\u6301\u786E\u5B9A\u6027\u3002\n generationFiles.sort((a, b) => generationVersionOf(b) - generationVersionOf(a))\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 // \u6700\u9AD8\u4EE3\u7248\u672C\u53F7\uFF1A0 = legacy `session.jsonl[.zstd]`\uFF0C\u22651 = `session.vN.jsonl[.zstd]`\u3002\n // \u4E0A\u5C42\u7528\u5B83\u5224\u65AD\u300C\u53E6\u4E00\u4E2A\u76EE\u5F55\u91CC\u7684\u540C id \u526F\u672C\u662F\u4E0D\u662F\u88AB\u53D6\u4EE3\u7684\u65E7\u4EE3\u300D\u3002\n generationVersion: generationVersionOf(generationFiles[0]),\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\n// SessionHandle.read() \u7684\u8FD4\u56DE\u503C\u5728 0.1.3 / 0.1.5 \u4E4B\u95F4\u6362\u8FC7\u5F62\u6001\uFF0C\u8FD9\u91CC\u7EDF\u4E00\u6210\u4E8B\u4EF6\u6570\u7EC4\uFF1A\n// - 0.1.3\uFF1A\u76F4\u63A5\u662F\u4E8B\u4EF6\u6570\u7EC4\uFF08\u6216\u53EF\u8FED\u4EE3\u5BF9\u8C61\uFF09\n// - 0.1.5\uFF1A**{ eventState: 'shared-frozen' | \u2026, events: [...] }**\uFF08\u4E0D\u518D\u662F\u6570\u7EC4\uFF01\n// \u672B\u5C3E\u8BFB\u53D6\u540C\u6837\u662F\u8FD9\u4E2A\u5F62\u72B6\uFF0C\u53EA\u662F events: []\uFF09\n// - \u672A\u77E5\u5F62\u6001**\u629B\u9519\u800C\u4E0D\u662F\u5F53\u7A7A\u6570\u7EC4**\uFF1A\u9759\u9ED8\u8FD4\u56DE [] \u7684\u4EE3\u4EF7\u662F\u707E\u96BE\u6027\u7684\u2014\u2014\n// 2026-09-10 \u5B9E\u6D4B\uFF0C0.1.5 \u5347\u7EA7\u540E\u8BFB\u53D6\u6052\u4E3A\u7A7A\uFF0C\u79FB\u52A8\"\u7528\u7A7A\u4E8B\u4EF6\u91CD\u5EFA\u65E5\u5FD7\"\u628A\u4E24\u4E2A\u4F1A\u8BDD\n// \u524A\u6210\u53EA\u5269\u5934\u90E8\u7684\u7A7A\u58F3\u3002\u4EFB\u4F55\u65E0\u6CD5\u8BC6\u522B\u7684\u8FD4\u56DE\u503C\u90FD\u5FC5\u987B\u8BA9\u8C03\u7528\u65B9\u770B\u5230\u9519\u8BEF\u3002\nfunction normalizeReadResult(events) {\n if (events === undefined || events === null) return []\n if (Array.isArray(events)) return events\n if (typeof events === 'object' && Array.isArray(events.events)) return events.events\n if (typeof events[Symbol.iterator] === 'function') return [...events]\n const error = new Error(\n 'DSH \u4F1A\u8BDD\u8BFB\u53D6\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u7ED3\u6784\uFF08runtime \u63A5\u53E3\u53EF\u80FD\u5DF2\u53D8\u66F4\uFF09\uFF0C\u5DF2\u505C\u6B62\u89E3\u6790\u4EE5\u514D\u8BEF\u5224\u4E3A\u7A7A\uFF1A' +\n Object.prototype.toString.call(events),\n )\n error.code = 'DSM_READ_SHAPE_UNKNOWN'\n throw error\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\u88AB DSH \u6253\u5F00\u3001\u5199\u6743\u9650\u5DF2\u88AB\u5360\u7528\u300D\u7684\u4F1A\u8BDD\uFF0C\u800C\u4E0D\u662F\u7167\n// legacy \u90A3\u6837\u6539\u5199\u6D3B\u8DC3\u5BF9\u8C61\u2014\u2014handle \u65F6\u4EE3\u7684\u5199\u53E5\u67C4\u6240\u6709\u6743\u5728\u5B98\u65B9 tracker \u5185\u90E8\uFF0C\n// \u4E0E\u5176\u6253\u8865\u4E01\u4E0D\u5982\u5982\u5B9E\u62D2\u7EDD\uFF0C\u98CE\u9669\u9762\u66F4\u5C0F\u3002\n//\n// \u6CE8\u610F\u8FD9\u4E0E legacy \u65F6\u4EE3\u7684\u53EF\u7528\u8303\u56F4\u4E0D\u540C\uFF1Alegacy \u65F6\u4EE3\u6CA1\u6709\u5355\u5199\u8005\u6240\u6709\u6743\uFF0C\u63D2\u4EF6\u76F4\u63A5\u6539\n// \u6587\u4EF6 + \u540C\u6B65 live \u5BF9\u8C61\u5C31\u80FD\u79FB\u52A8\u4EFB\u610F\u4F1A\u8BDD\uFF1B0.1.3 \u5F15\u5165 handle \u540E\uFF0Cagent-loop \u5728\n// resume \u4F1A\u8BDD\u65F6\u5148\u53D6\u5199\u6240\u6709\u6743\uFF08core/agent-loop resumeWith: \"Taking write ownership\n// FIRST\"\uFF09\u5E76\u6301\u6709\u5230 agent \u5378\u8F7D\uFF0C\u4E8E\u662F\u300C\u5728 DSH \u91CC\u70B9\u5F00\u8FC7\u7684\u4F1A\u8BDD\u300D\u4E00\u5F8B\u5904\u4E8E\u5360\u7528\u6001\u3002\n// \u8FD9\u662F\u5BBF\u4E3B\u673A\u5236\u51B3\u5B9A\u7684\u786C\u7EA6\u675F\uFF0C\u4E0D\u662F\u63D2\u4EF6\u80FD\u7ED5\u5F00\u7684\u5224\u5B9A\uFF0C\u63D0\u793A\u5FC5\u987B\u5982\u5B9E\u8BF4\u660E\u3002\n\nimport { mkdir, readFile, readdir, rename, rm, stat, writeFile } from 'node:fs/promises'\nimport { basename, dirname, join } from 'node:path'\nimport { rewriteFrame0CwdInMemory, scanZstdFrames } from './zstd-frame.js'\nimport { deriveSessionDir, encodeSegmentFor, generationVersionOf, locateSessionArtifacts } from './handle-era-paths.js'\n\nconst MOVE_BATCH = 400\n\n// \u771F\u5B9E\u65E5\u5FD7\u5224\u5B9A\uFF1A\u5B98\u65B9\u547D\u540D\u662F session.vN.jsonl[.zstd]\uFF0Clegacy \u65F6\u4EE3\u662F\n// session.jsonl[.zstd]\u2014\u2014\u951A\u5B9A\u7ED3\u5C3E\uFF0C\u5176\u4ED6\u540E\u7F00\uFF08\u5982\u6D4B\u8BD5\u6B8B\u6E23 *.jsonl.zstd.test\uFF09\n// \u4E0D\u7B97\u771F\u65E5\u5FD7\uFF1B\u53EA\u6709\u672C\u63D2\u4EF6\u79FB\u52A8\u8FC7\u7A0B\u7684\u4E34\u65F6\u540D\uFF08.move-backup- / .move-stage-\uFF09\n// \u4E5F\u4E0D\u7B97\u3002\nconst REAL_LOG_RE = /^session.*\\.jsonl(\\.zst(d)?)?$/\nconst MOVE_TEMP_RE = /\\.move-(backup|stage)-/\n// \u4F1A\u8BDD\u76EE\u5F55\u91CC\"\u672C\u4F1A\u8BDD\u81EA\u5DF1\u7684\"\u975E\u65E5\u5FD7\u6587\u4EF6\uFF08lease / flock / \u5B98\u65B9\u4E34\u65F6\u4EA7\u7269\uFF09\u3002\u7528\u4E8E\u5224\u5B9A\n// \u4E00\u4E2A\u4EC5\u5269\u65E7\u4EE3\u7684\u76EE\u5F55\u662F\u4E0D\u662F\u53EF\u4EE5\u5B89\u5168\u56DE\u6536\u2014\u2014\u5939\u5E26\u522B\u7684\u6587\u4EF6\u5C31\u4EA4\u4EBA\u5DE5\u88C1\u51B3\u3002\nconst SESSION_LOCAL_JUNK_RE = /^(\\.?session\\.lock.*|\\.lock.*|.*\\.lock|.*\\.tmp|.*\\.stage|.*\\.bak|\\.DS_Store)$/\n\n// \u540C id \u8DE8\u76EE\u5F55\u6B8B\u7559\u5904\u7406\u3002\u540E\u7AEF\u5728 create/list \u65F6\u626B\u5168\u76D8\uFF1A\u540C\u4E00\u4F1A\u8BDD id \u51FA\u73B0\u5728\u591A\u4E2A\n// \u9879\u76EE\u76EE\u5F55\u5373\u62A5 \u201Cduplicate JSONL session id ... appears in multiple project\n// directories\u201D\u3002\u4E09\u7C7B\u6B8B\u7559\u533A\u522B\u5BF9\u5F85\uFF08\u5224\u5B9A\u987A\u5E8F\u5373\u98CE\u9669\u4ECE\u4F4E\u5230\u9AD8\uFF09\uFF1A\n//\n// 1) \u7A7A\u58F3\uFF1A\u76EE\u5F55\u91CC\u6CA1\u6709\u4EFB\u4F55\u771F\u5B9E\u65E5\u5FD7 \u2192 \u7EAF\u5783\u573E\uFF0C\u76F4\u63A5\u5220\u3002\n// 2) \u53EA\u542B**\u88AB\u53D6\u4EE3\u7684\u65E7\u4EE3**\u65E5\u5FD7\uFF08\u6700\u9AD8\u4EE3\u7248\u672C\u53F7\u4E25\u683C\u4F4E\u4E8E\u5F53\u524D\u76EE\u5F55\u7684\u6700\u9AD8\u4EE3\uFF09\u2192 \u4E5F\u5220\u3002\n// 0.1.5 \u8D77\u5B98\u65B9\u300C\u53D1\u5E03\u65B0\u4EE3\u4F46\u4E0D\u5220\u65E7\u4EE3\u300D\uFF08\u5B9E\u6D4B\u540C\u4E00\u76EE\u5F55\u91CC session.v2 \u4E0E\n// session.v3 \u5E76\u5B58\uFF09\uFF0C\u800C\u5386\u53F2\u7248\u672C\u7684\u63D2\u4EF6\u79FB\u52A8\u65F6\u53EA\u642C\u8D70\u5F53\u524D\u4EE3\uFF0C\u7559\u4E0B\u7684\u65E7\u4EE3\u4F1A\u8BA9\u8BE5\n// id \u6C38\u8FDC\u5904\u4E8E\"\u8DE8\u76EE\u5F55\u91CD\u590D\"\u72B6\u6001\uFF0C\u4E4B\u540E\u6240\u6709\u79FB\u52A8/\u5F7B\u5E95\u5220\u9664\u90FD\u88AB\u62D2\u3002\u65E7\u4EE3\u5185\u5BB9\u5DF2\u88AB\n// \u65B0\u4EE3\u53D6\u4EE3\uFF08\u5B98\u65B9\u8BFB\u53D6\u6052\u5B9A\u53D6\u6700\u9AD8\u4EE3\uFF09\uFF0C\u5220\u9664\u4E0D\u4E22\u6570\u636E\uFF0C\u4E14\u4F1A\u4EE5 note \u5982\u5B9E\u56DE\u62A5\u3002\n// \u4E3A\u7A33\u59A5\u53EA\u5220\"\u7EAF\u65E5\u5FD7\u76EE\u5F55\"\uFF08\u9664\u65E5\u5FD7\u5916\u53EA\u5141\u8BB8 lock/\u4E34\u65F6\u6587\u4EF6\uFF09\uFF0C\u5939\u5E26\u672A\u77E5\u6587\u4EF6\u65F6\n// \u964D\u7EA7\u4E3A\u7B2C 3 \u7C7B\u4EBA\u5DE5\u88C1\u51B3\u3002\n// 3) \u7248\u672C\u76F8\u540C\u6216\u66F4\u9AD8 \u2192 \u771F\u91CD\u590D\uFF0C\u65E0\u6CD5\u5224\u65AD\u54EA\u4EFD\u6743\u5A01 \u2192 \u62D2\u7EDD\u79FB\u52A8\u5E76\u7ED9\u51FA\u6E05\u5355\u3002\nasync function cleanSiblingCopies(root, sid, keepDir, keepVersion) {\n let projects\n try { projects = await readdir(root, { withFileTypes: true }) } catch (e) { return { removed: 0, superseded: [], real: [] } }\n let segment\n try { segment = encodeSegmentFor(sid) } catch (e) { return { removed: 0, superseded: [], real: [] } }\n let removed = 0\n const superseded = []\n const real = []\n for (const ent of projects) {\n if (!ent.isDirectory()) continue\n const candidate = join(root, ent.name, segment)\n if (keepDir && candidate === keepDir) continue\n let entries\n try {\n const st = await stat(candidate)\n if (!st.isDirectory()) continue\n entries = await readdir(candidate)\n } catch (e) { continue }\n const logs = entries.filter((name) => REAL_LOG_RE.test(name) && !MOVE_TEMP_RE.test(name))\n if (logs.length === 0) {\n try { await rm(candidate, { recursive: true, force: true }); removed++ } catch (e) { /* \u6E05\u4E0D\u6389\u7684\u58F3\u7531\u771F\u91CD\u590D\u68C0\u67E5\u515C\u5E95 */ }\n continue\n }\n const highest = Math.max(...logs.map(generationVersionOf))\n const onlyLogsAndLocalJunk = entries.every((name) =>\n (REAL_LOG_RE.test(name) && !MOVE_TEMP_RE.test(name)) || SESSION_LOCAL_JUNK_RE.test(name))\n if (Number.isSafeInteger(keepVersion) && highest < keepVersion && onlyLogsAndLocalJunk) {\n try {\n await rm(candidate, { recursive: true, force: true })\n superseded.push(candidate)\n } catch (e) { real.push(candidate) }\n continue\n }\n real.push(candidate)\n }\n return { removed, superseded, real }\n}\n\n// \u79FB\u52A8\u6210\u529F\u540E\u7684\u6E90\u76EE\u5F55\u6536\u5C3E\u3002\u76EE\u6807\u4FA7\u5DF2\u7ECF create + append + \u6821\u9A8C\u51FA\u4E00\u4EFD\u5B8C\u6574\u6743\u5A01\u65E5\u5FD7\uFF0C\n// \u6E90\u76EE\u5F55\u5FC5\u987B**\u6574\u4F53\u79FB\u9664**\uFF1A\n// - 0.1.5 \u8D77\u5B98\u65B9\u53D1\u5E03\u65B0\u4EE3\u4E0D\u5220\u65E7\u4EE3\uFF0C\u82E5\u53EA\u642C\u8D70\u5F53\u524D\u4EE3\uFF0C\u6E90\u76EE\u5F55\u91CC\u7684\u65E7\u4EE3\u4F1A\u8BA9\u540C id \u51FA\u73B0\n// \u5728\u4E24\u4E2A\u9879\u76EE\u76EE\u5F55 \u2192 \u5B98\u65B9 listArtifacts/stat \u7ACB\u523B\u62A5 duplicate\uFF08\u5B9E\u6D4B\u6839\u56E0\uFF09\uFF1B\n// - \u76EE\u5F55\u672C\u8EAB\u5DF2\u7531 locateSessionArtifacts \u6821\u9A8C\u8FC7 basename === encodeSegment(id)\n// \u4E14 id \u5F52\u5C5E\u6B63\u786E\uFF0C\u5220\u7684\u662F\u8BE5\u4F1A\u8BDD\u81EA\u5DF1\u7684\u76EE\u5F55\uFF0C\u4E0D\u662F\"\u7591\u4F3C\u522B\u4EBA\u7684\u6570\u636E\"\u3002\n// \u8FD4\u56DE { cleaned, leftover }\uFF1Acleaned=false + leftover \u540D\u5355\u7528\u4E8E\u5982\u5B9E\u56DE\u62A5\u6E05\u7406\u5931\u8D25\u3002\nasync function removeSourceDir(sessionDir) {\n let entries\n try { entries = await readdir(sessionDir) } catch (e) { return { cleaned: true, leftover: [] } }\n try {\n await rm(sessionDir, { recursive: true, force: true })\n } catch (e) {\n return { cleaned: false, leftover: entries }\n }\n return { cleaned: true, leftover: [] }\n}\n\n// \u6D3B\u8DC3\u5199\u8005\uFF08409\uFF09\u63D0\u793A\u30020.1.3 \u8D77\u5B98\u65B9 session handle \u662F\u300C\u5355\u5199\u8005\u300D\uFF1Aagent-loop\n// \u5728 resume \u4E00\u4E2A\u4F1A\u8BDD\u65F6\u5148 open(id,'write') \u53D6\u5199\u6240\u6709\u6743\u5E76\u6301\u6709\u5230 agent \u5378\u8F7D\uFF0C\u6240\u4EE5\n// \u5728 DSH \u91CC\u70B9\u5F00\u8FC7\u7684\u4F1A\u8BDD\u90FD\u5904\u4E8E\u88AB\u5360\u7528\u72B6\u6001\u3002runtime \u672A\u63D0\u4F9B\u4EFB\u4F55\u80FD\u8FDC\u7A0B\u91CA\u653E\u8BE5\u6240\u6709\u6743\n// \u7684\u516C\u5171 API\uFF08\u65E0 unloadSession / closeSession / evict\uFF09\uFF0C\u56E0\u6B64\u63D2\u4EF6\u4E0D\u80FD\u66FF\u7528\u6237\u89E3\u9501\uFF0C\n// \u53EA\u80FD\u5982\u5B9E\u8BF4\u660E\u53EF\u64CD\u4F5C\u7684\u81EA\u6551\u8DEF\u5F84\uFF0C\u5E76\u9760\u300C\u91CD\u8BD5\u300D\u8BA9\u7528\u6237\u5207\u8D70\u4F1A\u8BDD\u540E\u539F\u5730\u518D\u8BD5\u4E00\u6B21\u3002\nconst BUSY_MOVE_MESSAGE = '\u4F1A\u8BDD\u6B63\u88AB DSH \u6253\u5F00\uFF0C\u6682\u65F6\u65E0\u6CD5\u79FB\u52A8\uFF1B\u8BF7\u91CD\u542F DSH \u540E\u518D\u8BD5\u3002'\nconst BUSY_PURGE_MESSAGE = '\u4F1A\u8BDD\u6B63\u88AB DSH \u6253\u5F00\uFF0C\u6682\u65F6\u65E0\u6CD5\u5F7B\u5E95\u5220\u9664\uFF1B\u8BF7\u91CD\u542F DSH \u540E\u518D\u8BD5\u3002'\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(BUSY_MOVE_MESSAGE)\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(BUSY_PURGE_MESSAGE)\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, backupLogPath, artifacts }) {\n const original = await readFile(backupLogPath)\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\n//\n// 0.1.5 \u5173\u952E\u7EA6\u675F\uFF08\u5B9E\u6D4B\uFF09\uFF1A\u5B98\u65B9\u5728 open(id,'write') \u65F6\u4F1A\u4E3A\u5386\u53F2\u4EE3**\u53D1\u5E03\u5F53\u524D\u4EE3**\n// \uFF08v0/v2 \u2192 v3\uFF09\u4E14**\u4E0D\u5220\u65E7\u4EE3**\uFF0C\u4E00\u4E2A\u4F1A\u8BDD\u76EE\u5F55\u91CC\u53EF\u540C\u65F6\u6709 v0/v2/v3\uFF1B\u800C\u5B98\u65B9\n// listArtifacts/findLog \u4F1A\u8DE8\u9879\u76EE\u76EE\u5F55\u89E3\u6790\u540C\u4E00\u4E2A id\uFF0C**\u4EFB\u610F\u4E24\u4E2A\u76EE\u5F55\u540C\u65F6\u6301\u6709\u8BE5 id\n// \u7684\u65E5\u5FD7\uFF08\u65E0\u8BBA\u54EA\u4E00\u4EE3\uFF09\u90FD\u4F1A\u629B duplicate**\u3002\u6240\u4EE5\u642C\u8FD0\u5FC5\u987B\u662F\uFF1A\n// \u63A2\u6D4B\uFF08\u4F1A\u53D1\u5E03\u65B0\u4EE3\uFF0C\u5FC5\u987B\u5148\u505A\uFF09\u2192 \u5B9A\u4F4D \u2192 \u540C id \u6B8B\u7559\u6E05\u7406\n// \u2192 **\u628A\u6574\u4E2A\u6E90\u4F1A\u8BDD\u76EE\u5F55\u6539\u540D\u79FB\u5F00**\uFF08\u5BF9\u5B98\u65B9\u5F7B\u5E95\u4E0D\u53EF\u89C1\uFF0C\u800C\u4E0D\u662F\u53EA\u642C\u5355\u4E2A\u6587\u4EF6\uFF09\n// \u2192 \u76EE\u6807\u4FA7 create+append+\u6821\u9A8C \u2192 \u6210\u529F\u5219\u5220\u9664\u79FB\u5F00\u7684\u6E90\u76EE\u5F55\uFF0C\u5931\u8D25\u5219\u6574\u4F53\u6539\u56DE\u3002\nexport async function moveSessionToCwd({ sp, sid, header, canonical, events = [], inheritedEventCount = 0 }) {\n // 1) \u5199\u6240\u6709\u6743\u63A2\u6D4B\u653E\u6700\u524D\uFF1A\u5B83\u53EF\u80FD\u53D1\u5E03\u65B0\u4EE3\uFF0C\u4E4B\u540E\u5B9A\u4F4D\u5230\u7684\u624D\u662F\u6743\u5A01\u8DEF\u5F84\u3002\n // \u975E\u300C\u5DF2\u88AB\u5360\u7528\u300D\u7684\u63A2\u6D4B\u5931\u8D25\uFF08\u540E\u7AEF\u5F02\u5E38\u7B49\uFF09\u4E0D\u5728\u6B64\u5904\u7ACB\u5373\u4E0A\u629B\u2014\u2014\u5148\u770B\u80FD\u5426\u5B9A\u4F4D\uFF0C\n // \u5B9A\u4F4D\u4E5F\u5931\u8D25\u65F6\u5982\u5B9E\u56DE\u62A5\u5B9A\u4F4D\u9519\u8BEF\uFF08\u63D0\u793A\u66F4\u53EF\u64CD\u4F5C\uFF09\uFF0C\u80FD\u5B9A\u4F4D\u65F6\u624D\u62A5\u544A\u5199\u72B6\u6001\u672A\u77E5\u3002\n let probeError = null\n try {\n await ensureNoActiveWriter(sp, sid)\n } catch (e) {\n if (e && e.status === 409) throw e\n probeError = e\n }\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 if (probeError) {\n const error = new Error('\u65E0\u6CD5\u786E\u8BA4\u8BE5\u4F1A\u8BDD\u662F\u5426\u6B63\u88AB\u5199\u5165\uFF0C\u5DF2\u505C\u6B62\u79FB\u52A8\uFF1A' + String((probeError && probeError.message) || probeError))\n error.status = 409\n throw error\n }\n // \u6570\u636E\u5B89\u5168\u5B88\u536B\uFF08\u6700\u540E\u4E00\u5C42\u4FDD\u9669\uFF09\uFF1A\u6E90\u65E5\u5FD7\u660E\u663E\u4E0D\u53EA\u662F\u5934\u90E8\uFF08> 4KB\uFF09\uFF0C\u4F46\u6211\u4EEC\u62FF\u5230\u7684\u4E8B\u4EF6\n // \u662F\u7A7A\u7684 \u2014\u2014 \u8BF4\u660E\u8BFB\u53D6\u94FE\u8DEF\u51FA\u4E86\u95EE\u9898\u3002\u6B64\u65F6\u82E5\u7EE7\u7EED\uFF0C\u5C31\u662F\"\u7528\u7A7A\u4E8B\u4EF6\u91CD\u5EFA\u65E5\u5FD7\"\u518D\u5220\u6389\u6E90\u76EE\u5F55\uFF0C\n // \u7B49\u4E8E\u6E05\u7A7A\u4F1A\u8BDD\u30022026-09-10 \u5B9E\u6D4B\u8FC7\u4E00\u6B21\uFF080.1.5 \u8BFB\u53D6\u8FD4\u56DE\u7ED3\u6784\u53D8\u66F4\uFF09\uFF0C\u7EDD\u4E0D\u80FD\u518D\u53D1\u751F\u3002\n const HEADER_ONLY_MAX = 4096\n if (events.length === 0) {\n let sourceBytes = null\n try { sourceBytes = (await stat(artifacts.logPath)).size } catch (e) { sourceBytes = null }\n if (sourceBytes !== null && sourceBytes > HEADER_ONLY_MAX) {\n const error = new Error(\n `\u79FB\u52A8\u524D\u6821\u9A8C\u5931\u8D25\uFF1A\u6E90\u65E5\u5FD7\u6709 ${sourceBytes} \u5B57\u8282\u4F46\u8BFB\u5230 0 \u6761\u4E8B\u4EF6\uFF08\u8BFB\u53D6\u94FE\u8DEF\u5F02\u5E38\uFF09\uFF0C\u5DF2\u505C\u6B62\u79FB\u52A8\u4EE5\u514D\u4E22\u5931\u4F1A\u8BDD\u5185\u5BB9\u3002`,\n )\n error.status = 409\n error.code = 'DSM_MOVE_EMPTY_READ'\n throw error\n }\n }\n // 2) \u540C id \u8DE8\u76EE\u5F55\u6B8B\u7559\uFF1A\u7A7A\u58F3\u4E0E\u88AB\u53D6\u4EE3\u7684\u65E7\u4EE3\u76F4\u63A5\u56DE\u6536\uFF08\u4F1A\u4EE5 note \u56DE\u62A5\uFF09\uFF0C\n // \u7248\u672C\u76F8\u540C/\u66F4\u9AD8\u7684\u771F\u91CD\u590D\u62D2\u7EDD\u79FB\u52A8\u5E76\u7ED9\u51FA\u6E05\u5355\u3002\u5FC5\u987B\u5728 rename \u5907\u4EFD\u4E4B\u524D\u505A\u2014\u2014\n // rename \u540E\u6E90\u76EE\u5F55\u6682\u65F6\u53D8\u6210\u58F3\uFF0C\u4F1A\u5E72\u6270\u5224\u5B9A\u3002\n const siblings = await cleanSiblingCopies(artifacts.root, sid, artifacts.sessionDir, artifacts.generationVersion)\n if (siblings.real.length > 0) {\n const error = new Error(\n '\u65E0\u6CD5\u79FB\u52A8\uFF1A\u5728\u5176\u4ED6\u5DE5\u4F5C\u533A\u76EE\u5F55\u53D1\u73B0\u540C\u4E00\u4F1A\u8BDD\u7684\u65E5\u5FD7\u526F\u672C\uFF0C\u8BF7\u5148\u786E\u8BA4\u4FDD\u7559\u54EA\u4E00\u4EFD\uFF1A\\n' +\n siblings.real.map((p) => '\u00B7 ' + p).join('\\n')\n )\n error.status = 409\n error.code = 'DSM_SESSION_DUP_LOG'\n throw error\n }\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 // 3) \u628A**\u6574\u4E2A\u6E90\u4F1A\u8BDD\u76EE\u5F55**\u79FB\u51FA sessions \u6839\uFF0C\u800C\u4E0D\u662F\u53EA rename \u5F53\u524D\u4EE3\u90A3\u4E00\u4E2A\u6587\u4EF6\uFF1A\n // - \u53EA\u642C\u5355\u4E2A\u6587\u4EF6\u4F1A\u7559\u4E0B\u5E76\u5B58\u7684\u5176\u4ED6\u4EE3\uFF080.1.5 \u7684 v0/v2/v3 \u591A\u4EE3\u5171\u5B58\uFF09\uFF0C\n // - \u5728\u672C\u9879\u76EE\u76EE\u5F55\u91CC\u6539\u540D\u4E5F\u4E0D\u591F\uFF1A\u5B98\u65B9 listSessionDirs \u679A\u4E3E\u9879\u76EE\u76EE\u5F55\u4E0B\u7684**\u6240\u6709**\n // \u5B50\u76EE\u5F55\uFF08\u4E0D\u6309\u540D\u5B57\u8FC7\u6EE4\uFF09\uFF0ClistArtifacts \u4F1A\u8BFB\u6BCF\u4E2A\u76EE\u5F55\u91CC\u7684\u65E5\u5FD7\u5934\uFF0C\u4ECD\u4F1A\u770B\u5230\n // \u540C\u4E00\u4E2A id \u2192 duplicate\u3002\u5FC5\u987B\u79FB\u5230 root \u4E4B\u5916\uFF08\u4E0E\u56DE\u6536\u7AD9\u540C\u7EA7\uFF09\u624D\u5BF9\u5B98\u65B9\u626B\u63CF\n // \u5F7B\u5E95\u4E0D\u53EF\u89C1\u3002\n const backupRoot = join(dirname(artifacts.root), 'sessions-manager-move-backup')\n const backupDir = join(backupRoot, `${encodeSegmentFor(sid)}-${process.pid}-${Date.now()}`)\n await mkdir(backupRoot, { recursive: true })\n const backupLogPath = join(backupDir, basename(artifacts.logPath))\n await rename(artifacts.sessionDir, backupDir)\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, backupLogPath, 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\u6574\u4E2A\u6E90\u76EE\u5F55\u79FB\u56DE\u539F\u4F4D\uFF08\u591A\u4EE3\u65E5\u5FD7\u4E00\u8D77\u590D\u539F\uFF09\u3002\n await closeQuietly(writer)\n try { await rm(deriveSessionDir(artifacts.root, canonical, sid), { recursive: true, force: true }) } catch (_) {}\n try { await mkdir(dirname(artifacts.sessionDir), { recursive: true }) } catch (_) {}\n try { await rename(backupDir, artifacts.sessionDir) } 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 // 4) \u6210\u529F\uFF1A\u5220\u6389\u79FB\u5F00\u7684\u6E90\u76EE\u5F55\uFF08\u542B\u5168\u90E8\u65E7\u4EE3\u65E5\u5FD7\uFF09\u3002\u7559\u7740\u5B83\u7B49\u4E8E\u8BA9\u540C\u4E00\u4E2A id \u51FA\u73B0\u5728\n // \u4E24\u4E2A\u9879\u76EE\u76EE\u5F55\uFF0C\u4E0B\u4E00\u6B21 create/list \u7ACB\u523B\u88AB\u540E\u7AEF duplicate \u68C0\u67E5\u62D2\u7EDD\u3002\n const sourceCleanup = await removeSourceDir(backupDir)\n return {\n sessionDir: deriveSessionDir(artifacts.root, canonical, sid),\n sourceCleanup,\n reclaimedSiblings: siblings.superseded,\n }\n}\n", "// Lineage classification for sidebar grouping (issue #6).\n//\n// All inputs come from the public list() snapshot \u2014 header + sizeBytes \u2014 so\n// classification costs zero log decoding, keeping the zero-decode listing\n// design intact. Three kinds:\n// - subagent: official header.origin === 'subagent' (with parentSession and\n// a delegationDepth recursion budget, both persisted by the backend)\n// - fork branch: header.parentSession set without the subagent origin\n// - empty: the log holds only the generation header\n//\n// The backend list snapshot carries NO eventCount, so the size test below is\n// only a cheap PRE-FILTER: since 0.1.3 it can no longer decide emptiness by\n// itself (bigger headers + a constant lifecycle-metadata frame push every\n// new log past the old baseline). The authoritative verdict comes from\n// refineEmptyLineage in index.js \u2014 an event-type scan (see below). Keep the\n// size test: it flags candidates cheaply and its false positives get\n// corrected by the precise pass.\n\nconst EMPTY_BASE = 190\n\nexport function isEmptyLogSize(sizeBytes, cwd) {\n if (!Number.isFinite(sizeBytes) || sizeBytes < 0) return false\n const cwdLen = typeof cwd === 'string' ? cwd.length : 0\n return sizeBytes <= EMPTY_BASE + cwdLen\n}\n\n// ---- 0.1.3 \u7A7A\u4F1A\u8BDD\u5224\u5B9A\uFF08\u4E8B\u4EF6\u7C7B\u578B\u6CD5\uFF09---------------------------------------\n// 0.1.3 \u8D77\u65E5\u5FD7\u7ED3\u6784\u53D8\u4E86\uFF1A\u5934\u90E8\u5E27\u4E4B\u540E\u6052\u5B9A\u8DDF\u4E00\u5E27\u300C\u751F\u547D\u5468\u671F\u5143\u6570\u636E\u300D\n// \uFF08permission/preset / sandbox/mode / approval/policy\uFF0C\u5B9E\u6D4B\u7EA6 150B \u538B\u7F29\uFF09\uFF0C\n// \u4E14\u5934\u90E8\u65B0\u589E isSeeded / delegationDepth / agentPreset \u7B49\u5B57\u6BB5\uFF0C\u538B\u7F29\u540E\u6574\u672C\n// \u7EA6 300 + cwd.length \u5B57\u8282\u2014\u2014\u4E0A\u9762\u7684\u4F53\u79EF\u9608\u503C\uFF08190 + cwd\uFF0Calpha.2 \u57FA\u7EBF\uFF09\u5BF9\n// \u65B0\u683C\u5F0F\u6C38\u8FDC\u5224\u4E0D\u4E2D\uFF0C\u7A7A\u767D\u4F1A\u8BDD\u5168\u90E8\u6F0F\u5224\u3002\u538B\u7F29\u4F53\u79EF\u5BF9\u5934\u90E8\u6269\u5BB9/\u538B\u7F29\u5668\u53C2\u6570\u5929\u751F\n// \u654F\u611F\uFF0C\u4E0D\u518D\u6269\u9608\u503C\uFF0C\u6539\u4E3A\u6309\u4E8B\u4EF6\u7C7B\u578B\u5224\u5B9A\uFF1A\n// \u7A7A\u4F1A\u8BDD = \u5934\u90E8\u4E4B\u5916\u53EA\u51FA\u73B0\u751F\u547D\u5468\u671F\u5143\u6570\u636E\u4E8B\u4EF6\uFF0C\u6CA1\u6709\u4EFB\u4F55\u5185\u5BB9\u4E8B\u4EF6\u3002\n// \u89E3\u7801\u5728\u5BBF\u4E3B\u4FA7\u8FDB\u884C\uFF08index.js \u7684 refineEmptyLineage\uFF1A\u53EA\u5BF9\u538B\u7F29\u4F53\u79EF \u2264\n// EMPTY_DECODE_LIMIT \u7684\u5019\u9009\u8C03\u5B98\u65B9 inspectSession\uFF09\uFF0C\u8FD9\u91CC\u53EA\u653E\u7EAF\u51FD\u6570\u4E0E\u5E38\u91CF\u3002\n//\n// \u5DF2\u77E5\u7684\u751F\u547D\u5468\u671F\u4E8B\u4EF6\uFF080.1.3-alpha.1 \u5B9E\u6D4B\uFF0C\u4F1A\u8BDD\u521B\u5EFA\u65F6\u4E00\u6B21\u6027\u5199\u5165\uFF09\u3002'session'\n// \u662F\u5934\u90E8\u884C\u81EA\u8EAB\u2014\u2014inspectSession \u82E5\u628A\u5934\u90E8\u5F53\u4E8B\u4EF6\u56DE\u4F20\uFF0C\u5B83\u6052\u5B58\u5728\u4E8E\u6BCF\u672C\u65E5\u5FD7\uFF0C\n// \u653E\u884C\u4E0D\u524A\u5F31\u5224\u5B9A\uFF1B\u4EFB\u4F55\u672A\u77E5\u7C7B\u578B\u90FD\u6309\u5185\u5BB9\u5904\u7406\uFF08\u5B81\u53EF\u6F0F\u5224\uFF0C\u4E0D\u53EF\u9519\u6740\uFF09\u3002\nexport const EMPTY_DECODE_LIMIT = 8192\n\nconst LIFECYCLE_EVENT_TYPES = new Set([\n 'session',\n 'permission/preset',\n 'sandbox/mode',\n 'approval/policy',\n])\n\n/**\n * @param {Array<string|undefined>} types \u4E8B\u4EF6\u7C7B\u578B\u5E8F\u5217\uFF08\u4E0D\u542B\u5934\u90E8\u4E5F\u53EF\uFF0C\u542B\u5934\u90E8\n * \u4E5F\u53EF\u2014\u2014'session' \u5728\u653E\u884C\u6E05\u5355\u91CC\uFF09\u30020 \u6761 = \u5934\u90E8\u4E4B\u5916\u65E0\u4EFB\u4F55\u4E8B\u4EF6\uFF0C\u89C6\u4E3A\u7A7A\u3002\n * @returns {boolean}\n */\nexport function isEmptyEventTypes(types) {\n if (!Array.isArray(types)) return false\n for (const t of types) {\n if (typeof t !== 'string' || !LIFECYCLE_EVENT_TYPES.has(t)) return false\n }\n return true\n}\n\n// Returns a lineage record, or null when the session is an ordinary\n// top-level, non-empty session (the overwhelmingly common case \u2014 keeps the\n// sidebar-state payload small).\nexport function classifyLineage(header, sizeBytes) {\n if (!header || typeof header !== 'object') return null\n const origin = header.origin === 'subagent' ? 'subagent' : null\n const parentSession = typeof header.parentSession === 'string' && header.parentSession\n ? header.parentSession\n : null\n const delegationDepth = Number.isSafeInteger(header.delegationDepth) && header.delegationDepth > 0\n ? header.delegationDepth\n : 0\n const empty = isEmptyLogSize(sizeBytes, header.cwd)\n if (!origin && !parentSession && !empty) return null\n return { origin, parentSession, delegationDepth, empty }\n}\n"],
|
|
5
|
-
"mappings": ";AASA,SAAS,SAAAA,QAAO,YAAAC,WAAU,WAAAC,UAAS,UAAU,UAAAC,SAAQ,MAAAC,KAAI,QAAAC,OAAM,QAAQ,aAAAC,kBAAiB;AACxF,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;;;AC5FA,SAAS,gBAAAC,qBAAoB;AAC7B,SAAS,SAAAC,QAAO,UAAAC,SAAQ,aAAAC,kBAAiB;AACzC,SAAS,WAAAC,gBAAe;AACxB,SAAS,QAAAC,aAAY;AAErB,IAAM,iBAAiB;AACvB,IAAM,cAAc,QAAQ,IAAI,oCAC3B,QAAQ,IAAI,iCACZA,MAAKD,SAAQ,GAAG,QAAQ,kBAAkB;AAC/C,IAAM,YAAY;AAGlB,IAAM,eAAe;AAErB,SAAS,SAAS,OAAO;AACvB,SAAO,OAAO,UAAU,YAAY,MAAM,SAAS,KAAK,MAAM,UAAU;AAC1E;AAEA,SAAS,eAAe,KAAK;AAC3B,QAAM,QAAQ,CAAC;AACf,QAAM,OAAO,oBAAI,IAAI;AACrB,QAAM,SAAS,OAAO,MAAM,QAAQ,IAAI,KAAK,IAAI,IAAI,QAAQ,CAAC;AAC9D,aAAW,QAAQ,QAAQ;AACzB,QAAI,CAAC,QAAQ,CAAC,SAAS,KAAK,SAAS,KAAK,OAAO,KAAK,eAAe,YAAY,KAAK,WAAW,WAAW,EAAG;AAC/G,QAAI,KAAK,IAAI,KAAK,SAAS,EAAG;AAC9B,SAAK,IAAI,KAAK,SAAS;AACvB,UAAM,KAAK;AAAA,MACT,WAAW,OAAO,KAAK,SAAS;AAAA,MAChC,YAAY,OAAO,KAAK,UAAU;AAAA,MAClC,UAAU,OAAO,SAAS,KAAK,QAAQ,IAAI,OAAO,KAAK,QAAQ,IAAI,KAAK,IAAI;AAAA,MAC5E,UAAU,OAAO,cAAc,KAAK,QAAQ,KAAK,KAAK,YAAY,IAAI,OAAO,KAAK,QAAQ,IAAI;AAAA,IAChG,CAAC;AACD,QAAI,MAAM,UAAU,UAAW;AAAA,EACjC;AACA,SAAO,EAAE,eAAe,gBAAgB,MAAM;AAChD;AAMO,SAAS,uBAAuB,UAAU,CAAC,GAAG;AACnD,QAAM,MAAM,QAAQ,OAAO;AAC3B,QAAM,YAAY,QAAQ,aAAaC,MAAK,KAAK,oBAAoB;AACrE,MAAI,WAAW,QAAQ,QAAQ;AAE/B,iBAAe,OAAO;AACpB,QAAI;AACF,aAAO,eAAe,KAAK,MAAML,cAAa,WAAW,MAAM,CAAC,CAAC;AAAA,IACnE,SAAS,GAAG;AACV,aAAO,eAAe,IAAI;AAAA,IAC5B;AAAA,EACF;AAEA,iBAAe,MAAM,OAAO;AAC1B,UAAMC,OAAM,KAAK,EAAE,WAAW,KAAK,CAAC;AACpC,UAAM,MAAMI,MAAK,KAAK,kBAAkB,QAAQ,GAAG,IAAI,KAAK,IAAI,CAAC,MAAM;AACvE,UAAMF,WAAU,KAAK,KAAK,UAAU,eAAe,KAAK,GAAG,MAAM,CAAC,GAAG,EAAE,UAAU,QAAQ,MAAM,IAAM,CAAC;AACtG,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;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,MAAM,aAAa,MAAM,KAAK,GAAG;AAAA,IACjC,KAAK,OAAO,eAAe,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,SAAS,KAAK,cAAc,OAAO,SAAS,CAAC;AAAA,IAClG,OAAO,CAAC,WAAW,eAAe,OAAO,CAAC,UAAU;AAClD,UAAI,CAAC,SAAS,SAAS,KAAK,OAAO,eAAe,YAAY,WAAW,WAAW,EAAG,QAAO;AAC9F,YAAM,WAAW,MAAM,MAAM,KAAK,CAACI,UAASA,MAAK,cAAc,OAAO,SAAS,CAAC;AAChF,UAAI,UAAU;AACZ,iBAAS,aAAa,OAAO,UAAU;AACvC,iBAAS,WAAW;AACpB,eAAO;AAAA,MACT;AACA,YAAM,OAAO,EAAE,WAAW,OAAO,SAAS,GAAG,YAAY,OAAO,UAAU,GAAG,UAAU,KAAK,IAAI,GAAG,UAAU,EAAE;AAC/G,YAAM,MAAM,KAAK,IAAI;AACrB,UAAI,MAAM,MAAM,SAAS,UAAW,OAAM,MAAM,OAAO,GAAG,MAAM,MAAM,SAAS,SAAS;AACxF,aAAO;AAAA,IACT,CAAC;AAAA,IACD,QAAQ,CAAC,eAAe,OAAO,CAAC,UAAU;AACxC,YAAM,OAAO,IAAI,KAAK,MAAM,QAAQ,UAAU,IAAI,aAAa,CAAC,UAAU,GAAG,OAAO,QAAQ,EAAE,IAAI,MAAM,CAAC;AACzG,YAAM,SAAS,MAAM,MAAM;AAC3B,YAAM,QAAQ,MAAM,MAAM,OAAO,CAAC,SAAS,CAAC,KAAK,IAAI,KAAK,SAAS,CAAC;AACpE,aAAO,SAAS,MAAM,MAAM;AAAA,IAC9B,CAAC;AAAA,IACD,cAAc,CAAC,cAAc,OAAO,CAAC,UAAU;AAC7C,YAAM,OAAO,MAAM,MAAM,KAAK,CAAC,UAAU,MAAM,cAAc,OAAO,SAAS,CAAC;AAC9E,UAAI,CAAC,KAAM,QAAO;AAClB,WAAK,YAAY;AACjB,UAAI,KAAK,YAAY,cAAc;AACjC,cAAM,QAAQ,MAAM,MAAM,OAAO,CAAC,UAAU,MAAM,cAAc,KAAK,SAAS;AAC9E,eAAO,EAAE,SAAS,MAAM,UAAU,KAAK,SAAS;AAAA,MAClD;AACA,aAAO,EAAE,SAAS,OAAO,UAAU,KAAK,SAAS;AAAA,IACnD,CAAC;AAAA,EACH;AACF;;;ACjHA,SAAS,SAAS,IAAI,YAAY;AAClC,SAAS,QAAAC,aAAY;AAErB,IAAM,eAAe;AASrB,eAAsB,qBAAqB,MAAM,UAAU,CAAC,GAAG;AAC7D,QAAM,WAAW,OAAO,cAAc,QAAQ,QAAQ,KAAK,QAAQ,YAAY,IAAI,QAAQ,WAAW;AACtG,QAAM,MAAM,OAAO,SAAS,QAAQ,GAAG,IAAI,QAAQ,MAAM,KAAK,IAAI;AAClE,MAAI,UAAU;AACd,aAAW,OAAO,MAAM,QAAQ,IAAI,IAAI,OAAO,CAAC,GAAG;AACjD,QAAI,OAAO,QAAQ,YAAY,IAAI,WAAW,EAAG;AACjD,QAAI;AACJ,QAAI;AAAE,gBAAU,MAAM,QAAQ,GAAG;AAAA,IAAE,SAAS,GAAG;AAAE;AAAA,IAAS;AAC1D,eAAWC,SAAQ,SAAS;AAC1B,UAAI,CAAC,aAAa,KAAKA,KAAI,EAAG;AAC9B,YAAM,OAAOD,MAAK,KAAKC,KAAI;AAC3B,UAAI;AACJ,UAAI;AAAE,eAAO,MAAM,KAAK,IAAI;AAAA,MAAE,SAAS,GAAG;AAAE;AAAA,MAAS;AACrD,UAAI,CAAC,KAAK,OAAO,EAAG;AACpB,UAAI,MAAM,KAAK,UAAU,SAAU;AACnC,UAAI;AAAE,cAAM,GAAG,MAAM,EAAE,OAAO,KAAK,CAAC;AAAG;AAAA,MAAU,SAAS,GAAG;AAAA,MAAiB;AAAA,IAChF;AAAA,EACF;AACA,SAAO;AACT;;;AC9BO,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,IAAMC,eAAcD,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,yCAAyCE;AAChF,QAAM,YAAY,QAAQ,aAAaD,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,WAASM,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;AAaO,SAAS,qBAAqBA,OAAM;AACzC,QAAM,KAAK,cAAcA,KAAI;AAC7B,MAAI,MAAM,yBAAyB,EAAE,EAAG,QAAO;AAC/C,MAAIA,SAAQ,OAAO,SAASA,MAAK,SAAS,KAAKA,MAAK,aAAa,EAAG,QAAO,MAAMA,MAAK,SAAS;AAC/F,SAAO;AACT;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;;;AC3IA,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,QAAM,WAAW,IAAI,aAAa,QAAQ,IAAI,aAAa;AAC3D,MAAI,CAAC,eAAe,YAAY,WAAW,MAAM,EAAG,QAAO;AAC3D,MAAI,CAAC,SAAS,CAAC,IAAK,QAAO;AAI3B,MAAI,CAAC,SAAS,CAAC,SAAU,QAAO;AAChC,QAAM,QAAQ,EAAE,OAAO,KAAK,WAAW,aAAa,UAAU;AAC9D,MAAI,SAAU,OAAM,WAAW;AAC/B,SAAO;AACT;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;;;ACxHA,SAAS,WAAAG,UAAS,QAAAC,aAAY;AAC9B,SAAS,UAAU,QAAAC,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;;;ADxBA,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;AAWO,SAAS,oBAAoBC,OAAM;AACxC,SAAO,QAAQ,OAAOA,KAAI,EAAE,MAAM,oBAAoB,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC;AACxE;AAKA,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,MAAMC,MAAK,UAAU;AAChC,QAAI,CAAC,GAAG,YAAY,EAAG,QAAO;AAC9B,cAAU,MAAMC,SAAQ,UAAU;AAAA,EACpC,SAAS,GAAG;AACV,WAAO;AAAA,EACT;AACA,QAAM,kBAAkB,QAAQ,OAAO,CAACF,UAAS,kBAAkB,KAAKA,KAAI,CAAC;AAC7E,MAAI,gBAAgB,WAAW,EAAG,QAAO;AAEzC,kBAAgB,KAAK,CAAC,GAAG,MAAM,oBAAoB,CAAC,IAAI,oBAAoB,CAAC,CAAC;AAC9E,QAAM,UAAUG,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;AAAA;AAAA,IAGA,mBAAmB,oBAAoB,gBAAgB,CAAC,CAAC;AAAA,EAC3D;AACF;;;AEzHA,IAAM,gBAAgB;AAEtB,IAAM,aAAa;AASnB,SAAS,oBAAoB,QAAQ;AACnC,MAAI,WAAW,UAAa,WAAW,KAAM,QAAO,CAAC;AACrD,MAAI,MAAM,QAAQ,MAAM,EAAG,QAAO;AAClC,MAAI,OAAO,WAAW,YAAY,MAAM,QAAQ,OAAO,MAAM,EAAG,QAAO,OAAO;AAC9E,MAAI,OAAO,OAAO,OAAO,QAAQ,MAAM,WAAY,QAAO,CAAC,GAAG,MAAM;AACpE,QAAM,QAAQ,IAAI;AAAA,IAChB,yOACA,OAAO,UAAU,SAAS,KAAK,MAAM;AAAA,EACvC;AACA,QAAM,OAAO;AACb,QAAM;AACR;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;;;ACpLA,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;;;AC/DA,SAAS,SAAAC,QAAO,YAAAC,WAAU,WAAAC,UAAS,UAAAC,SAAQ,MAAAC,KAAI,QAAAC,OAAM,aAAAC,kBAAiB;AACtE,SAAS,YAAAC,WAAU,WAAAC,UAAS,QAAAC,aAAY;AAIxC,IAAM,aAAa;AAMnB,IAAM,cAAc;AACpB,IAAM,eAAe;AAGrB,IAAM,wBAAwB;AAe9B,eAAe,mBAAmB,MAAM,KAAK,SAAS,aAAa;AACjE,MAAI;AACJ,MAAI;AAAE,eAAW,MAAMC,SAAQ,MAAM,EAAE,eAAe,KAAK,CAAC;AAAA,EAAE,SAAS,GAAG;AAAE,WAAO,EAAE,SAAS,GAAG,YAAY,CAAC,GAAG,MAAM,CAAC,EAAE;AAAA,EAAE;AAC5H,MAAI;AACJ,MAAI;AAAE,cAAU,iBAAiB,GAAG;AAAA,EAAE,SAAS,GAAG;AAAE,WAAO,EAAE,SAAS,GAAG,YAAY,CAAC,GAAG,MAAM,CAAC,EAAE;AAAA,EAAE;AACpG,MAAI,UAAU;AACd,QAAM,aAAa,CAAC;AACpB,QAAM,OAAO,CAAC;AACd,aAAW,OAAO,UAAU;AAC1B,QAAI,CAAC,IAAI,YAAY,EAAG;AACxB,UAAM,YAAYC,MAAK,MAAM,IAAI,MAAM,OAAO;AAC9C,QAAI,WAAW,cAAc,QAAS;AACtC,QAAI;AACJ,QAAI;AACF,YAAM,KAAK,MAAMC,MAAK,SAAS;AAC/B,UAAI,CAAC,GAAG,YAAY,EAAG;AACvB,gBAAU,MAAMF,SAAQ,SAAS;AAAA,IACnC,SAAS,GAAG;AAAE;AAAA,IAAS;AACvB,UAAM,OAAO,QAAQ,OAAO,CAACG,UAAS,YAAY,KAAKA,KAAI,KAAK,CAAC,aAAa,KAAKA,KAAI,CAAC;AACxF,QAAI,KAAK,WAAW,GAAG;AACrB,UAAI;AAAE,cAAMC,IAAG,WAAW,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAG;AAAA,MAAU,SAAS,GAAG;AAAA,MAAsB;AACzG;AAAA,IACF;AACA,UAAM,UAAU,KAAK,IAAI,GAAG,KAAK,IAAI,mBAAmB,CAAC;AACzD,UAAM,uBAAuB,QAAQ,MAAM,CAACD,UACzC,YAAY,KAAKA,KAAI,KAAK,CAAC,aAAa,KAAKA,KAAI,KAAM,sBAAsB,KAAKA,KAAI,CAAC;AAC1F,QAAI,OAAO,cAAc,WAAW,KAAK,UAAU,eAAe,sBAAsB;AACtF,UAAI;AACF,cAAMC,IAAG,WAAW,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AACpD,mBAAW,KAAK,SAAS;AAAA,MAC3B,SAAS,GAAG;AAAE,aAAK,KAAK,SAAS;AAAA,MAAE;AACnC;AAAA,IACF;AACA,SAAK,KAAK,SAAS;AAAA,EACrB;AACA,SAAO,EAAE,SAAS,YAAY,KAAK;AACrC;AASA,eAAe,gBAAgB,YAAY;AACzC,MAAI;AACJ,MAAI;AAAE,cAAU,MAAMJ,SAAQ,UAAU;AAAA,EAAE,SAAS,GAAG;AAAE,WAAO,EAAE,SAAS,MAAM,UAAU,CAAC,EAAE;AAAA,EAAE;AAC/F,MAAI;AACF,UAAMI,IAAG,YAAY,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,EACvD,SAAS,GAAG;AACV,WAAO,EAAE,SAAS,OAAO,UAAU,QAAQ;AAAA,EAC7C;AACA,SAAO,EAAE,SAAS,MAAM,UAAU,CAAC,EAAE;AACvC;AAOA,IAAM,oBAAoB;AAC1B,IAAM,qBAAqB;AAE3B,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,iBAAiB;AAC5D,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,kBAAkB;AAC7D,UAAM;AAAA,EACR;AAEA,QAAMA,cAAa,MAAM;AACzB,WAAS;AACT,MAAI;AAGF,UAAMD,IAAG,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,eAAe,UAAU,GAAG;AACnF,QAAM,WAAW,MAAME,UAAS,aAAa;AAC7C,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,SAASN,MAAK,WAAW,eAAe,QAAQ,GAAG,IAAI,KAAK,IAAI,CAAC,EAAE;AACzE,QAAMO,WAAU,QAAQ,WAAW,EAAE,MAAM,IAAM,CAAC;AAClD,QAAMC,QAAO,QAAQR,MAAK,WAAW,UAAU,gBAAgB,CAAC,CAAC,CAAC;AAClE,SAAO;AACT;AAcA,eAAsB,iBAAiB,EAAE,IAAI,KAAK,QAAQ,WAAW,SAAS,CAAC,GAAG,sBAAsB,EAAE,GAAG;AAI3G,MAAI,aAAa;AACjB,MAAI;AACF,UAAM,qBAAqB,IAAI,GAAG;AAAA,EACpC,SAAS,GAAG;AACV,QAAI,KAAK,EAAE,WAAW,IAAK,OAAM;AACjC,iBAAa;AAAA,EACf;AACA,QAAM,YAAY,MAAM,uBAAuB,IAAI,MAAM;AACzD,MAAI,CAAC,WAAW;AACd,UAAM,QAAQ,IAAI,MAAM,8GAAoB;AAC5C,UAAM,SAAS;AACf,UAAM;AAAA,EACR;AACA,MAAI,YAAY;AACd,UAAM,QAAQ,IAAI,MAAM,6HAAyB,OAAQ,cAAc,WAAW,WAAY,UAAU,CAAC;AACzG,UAAM,SAAS;AACf,UAAM;AAAA,EACR;AAIA,QAAM,kBAAkB;AACxB,MAAI,OAAO,WAAW,GAAG;AACvB,QAAI,cAAc;AAClB,QAAI;AAAE,qBAAe,MAAMC,MAAK,UAAU,OAAO,GAAG;AAAA,IAAK,SAAS,GAAG;AAAE,oBAAc;AAAA,IAAK;AAC1F,QAAI,gBAAgB,QAAQ,cAAc,iBAAiB;AACzD,YAAM,QAAQ,IAAI;AAAA,QAChB,4EAAgB,WAAW;AAAA,MAC7B;AACA,YAAM,SAAS;AACf,YAAM,OAAO;AACb,YAAM;AAAA,IACR;AAAA,EACF;AAIA,QAAM,WAAW,MAAM,mBAAmB,UAAU,MAAM,KAAK,UAAU,YAAY,UAAU,iBAAiB;AAChH,MAAI,SAAS,KAAK,SAAS,GAAG;AAC5B,UAAM,QAAQ,IAAI;AAAA,MAChB,yNACA,SAAS,KAAK,IAAI,CAAC,MAAM,UAAO,CAAC,EAAE,KAAK,IAAI;AAAA,IAC9C;AACA,UAAM,SAAS;AACf,UAAM,OAAO;AACb,UAAM;AAAA,EACR;AACA,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;AAOJ,QAAM,aAAaD,MAAKS,SAAQ,UAAU,IAAI,GAAG,8BAA8B;AAC/E,QAAM,YAAYT,MAAK,YAAY,GAAG,iBAAiB,GAAG,CAAC,IAAI,QAAQ,GAAG,IAAI,KAAK,IAAI,CAAC,EAAE;AAC1F,QAAMM,OAAM,YAAY,EAAE,WAAW,KAAK,CAAC;AAC3C,QAAM,gBAAgBN,MAAK,WAAWU,UAAS,UAAU,OAAO,CAAC;AACjE,QAAMF,QAAO,UAAU,YAAY,SAAS;AAC5C,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,eAAe,UAAU,CAAC;AAAA,MAC5E,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,UAAMJ,cAAa,MAAM;AACzB,QAAI;AAAE,YAAMD,IAAG,iBAAiB,UAAU,MAAM,WAAW,GAAG,GAAG,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,IAAE,SAAS,GAAG;AAAA,IAAC;AAChH,QAAI;AAAE,YAAMG,OAAMG,SAAQ,UAAU,UAAU,GAAG,EAAE,WAAW,KAAK,CAAC;AAAA,IAAE,SAAS,GAAG;AAAA,IAAC;AACnF,QAAI;AAAE,YAAMD,QAAO,WAAW,UAAU,UAAU;AAAA,IAAE,SAAS,GAAG;AAAA,IAAC;AACjE,QAAI,KAAK,EAAE,OAAQ,OAAM;AACzB,UAAM,QAAQ,IAAI,MAAM,2DAAc,OAAQ,KAAK,EAAE,WAAY,CAAC,CAAC;AACnE,UAAM,SAAS;AACf,UAAM;AAAA,EACR;AAGA,QAAM,gBAAgB,MAAM,gBAAgB,SAAS;AACrD,SAAO;AAAA,IACL,YAAY,iBAAiB,UAAU,MAAM,WAAW,GAAG;AAAA,IAC3D;AAAA,IACA,mBAAmB,SAAS;AAAA,EAC9B;AACF;;;ACtUA,IAAM,aAAa;AAEZ,SAAS,eAAe,WAAW,KAAK;AAC7C,MAAI,CAAC,OAAO,SAAS,SAAS,KAAK,YAAY,EAAG,QAAO;AACzD,QAAM,SAAS,OAAO,QAAQ,WAAW,IAAI,SAAS;AACtD,SAAO,aAAa,aAAa;AACnC;AAgBO,IAAM,qBAAqB;AAElC,IAAM,wBAAwB,oBAAI,IAAI;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAOM,SAAS,kBAAkB,OAAO;AACvC,MAAI,CAAC,MAAM,QAAQ,KAAK,EAAG,QAAO;AAClC,aAAW,KAAK,OAAO;AACrB,QAAI,OAAO,MAAM,YAAY,CAAC,sBAAsB,IAAI,CAAC,EAAG,QAAO;AAAA,EACrE;AACA,SAAO;AACT;AAKO,SAAS,gBAAgB,QAAQ,WAAW;AACjD,MAAI,CAAC,UAAU,OAAO,WAAW,SAAU,QAAO;AAClD,QAAM,SAAS,OAAO,WAAW,aAAa,aAAa;AAC3D,QAAM,gBAAgB,OAAO,OAAO,kBAAkB,YAAY,OAAO,gBACrE,OAAO,gBACP;AACJ,QAAM,kBAAkB,OAAO,cAAc,OAAO,eAAe,KAAK,OAAO,kBAAkB,IAC7F,OAAO,kBACP;AACJ,QAAM,QAAQ,eAAe,WAAW,OAAO,GAAG;AAClD,MAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC,MAAO,QAAO;AAChD,SAAO,EAAE,QAAQ,eAAe,iBAAiB,MAAM;AACzD;;;Af9CA,IAAM,cAAc,OAAyC,mBAAkB;AAGxE,IAAM,OAAO;AACb,IAAM,SAAS,CAAC,aAAa,qBAAqB,sBAAsB,gBAAgB,eAAe;AAE9G,IAAM,YAAY;AAGlB,IAAM,YAAY,QAAQ,IAAI,iCAAiCG,MAAKC,SAAQ,GAAG,QAAQ,kBAAkB;AAEzG,IAAM,YAAY,QAAQ,IAAI,kCAAkCD,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;AAKO,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;AAIrB,YAAM,KAAK,qBAAqBA,KAAI;AACpC,UAAI,CAAC,GAAI;AAIT,UAAI,MAAM,gBAAgB,OAAO,MAAM,SAAS,MAAM,WAAW;AAC/D,aAAK,IAAI,IAAI,EAAE,OAAO,MAAM,OAAO,KAAK,MAAM,KAAK,WAAW,MAAM,UAAU,CAAC;AAAA,MACjF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAUA,iBAAe,eAAe,SAAS,WAAW;AAChD,QAAI,CAAC,WAAW,CAAC,QAAQ,KAAM;AAC/B,UAAM,QAAQ,CAAC;AACf,UAAM,MAAM,KAAK,IAAI;AACrB,eAAW,CAAC,IAAI,IAAI,KAAK,SAAS;AAChC,UAAI,CAAC,QAAQ,CAAC,KAAK,SAAU;AAC7B,YAAM,OAAO,KAAK;AAClB,YAAM,KAAK,qBAAqB,UAAU,IAAI,EAAE,CAAC;AACjD,UAAI,CAAC,GAAI;AACT,YAAM,EAAE,IAAI,EAAE,OAAO,KAAK,OAAO,KAAK,KAAK,KAAK,WAAW,KAAK,WAAW,aAAa,IAAI,WAAW,KAAK,UAAU,EAAE;AAAA,IAC1H;AACA,QAAI,CAAC,OAAO,KAAK,KAAK,EAAE,OAAQ;AAChC,QAAI;AAAE,YAAM,WAAW,MAAM,KAAK;AAAA,IAAE,SAAS,GAAG;AAAA,IAAqB;AAAA,EACvE;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;AAYA,QAAM,aAAa,EAAE,OAAO,MAAM,KAAK,MAAM,WAAW,KAAK;AAQ7D,QAAM,aAAa;AACnB,QAAM,YAAY,oBAAI,IAAI;AAC1B,MAAI,cAAc;AAClB,MAAI,gBAAgB;AASpB,QAAM,oBAAoB;AAC1B,QAAM,WAAW,oBAAI,IAAI;AAEzB,WAAS,SAASA,OAAM;AACtB,WAAO,cAAcA,KAAI,KAAK,qBAAqBA,KAAI;AAAA,EACzD;AAEA,WAAS,YAAY,IAAI,IAAI;AAC3B,UAAM,MAAM,SAAS,IAAI,EAAE;AAC3B,QAAI,CAAC,IAAK,QAAO;AACjB,QAAI,MAAM,IAAI,MAAM,IAAI,OAAO,IAAI;AAAE,eAAS,OAAO,EAAE;AAAG,aAAO;AAAA,IAAE;AACnE,UAAM,MAAM,KAAK,IAAI;AACrB,WAAO,IAAI,SAAS,MAAM,IAAI,SAAS,MAAM;AAAA,EAC/C;AAEA,WAAS,gBAAgB,IAAIA,OAAM,QAAQ;AACzC,UAAM,MAAM,SAAS,IAAI,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,MAAM,QAAQ,EAAE;AAChE,QAAI,SAAS;AACb,QAAI,KAAK,SAASA,KAAI,KAAK,IAAI;AAE/B,QAAIA,MAAM,KAAI,OAAOA;AACrB,QAAI,OAAQ,KAAI,SAAS;AACzB,UAAM,UAAU,IAAI,SAAS,oBACzB,KAAK,KAAK,MACV,KAAK,IAAI,IAAI,KAAK,KAAM,KAAK,MAAO,KAAK,IAAI,GAAG,IAAI,KAAK,CAAC;AAC9D,QAAI,SAAS,KAAK,IAAI,IAAI;AAC1B,aAAS,IAAI,IAAI,GAAG;AAAA,EACtB;AAGA,WAAS,iBAAiB;AACxB,QAAI,CAAC,WAAY,QAAO;AACxB,QAAI,eAAe,UAAU,KAAM,QAAO;AAC1C,eAAW,OAAO,SAAS,OAAO,EAAG,KAAI,IAAI,SAAS,KAAK,IAAI,EAAG,QAAO;AACzE,WAAO;AAAA,EACT;AAGA,MAAI,iBAAiB;AACrB,WAAS,oBAAoB;AAC3B,QAAI,eAAgB;AACpB,QAAI,UAAU;AACd,eAAW,OAAO,SAAS,OAAO,GAAG;AACnC,YAAM,OAAO,IAAI,SAAS,KAAK,IAAI;AACnC,UAAI,QAAQ,GAAG;AAAE,kBAAU;AAAG;AAAA,MAAM;AACpC,UAAI,CAAC,WAAW,OAAO,QAAS,WAAU;AAAA,IAC5C;AACA,QAAI,CAAC,QAAS;AACd,qBAAiB,WAAW,MAAM;AAChC,uBAAiB;AAEjB,YAAM,MAAM,KAAK,IAAI;AACrB,iBAAW,CAAC,IAAI,GAAG,KAAK,UAAU;AAChC,YAAI,IAAI,UAAU,OAAO,CAAC,UAAU,IAAI,EAAE,EAAG,WAAU,IAAI,IAAI,EAAE,MAAM,IAAI,QAAQ,MAAM,QAAQ,IAAI,UAAU,KAAK,CAAC;AAAA,MACvH;AACA,UAAI,UAAU,KAAM,cAAa;AAAA,IACnC,GAAG,OAAO;AACV,QAAI,OAAO,eAAe,UAAU,WAAY,gBAAe,MAAM;AAAA,EACvE;AAEA,WAAS,eAAe;AACtB,QAAI,iBAAiB,YAAa;AAClC,oBAAgB,WAAW,MAAM;AAAE,sBAAgB;AAAM,cAAQ;AAAA,IAAE,GAAG,EAAE;AAExE,QAAI,OAAO,cAAc,UAAU,WAAY,eAAc,MAAM;AAAA,EACrE;AAEA,WAAS,YAAY,KAAK,WAAW,WAAW;AAC9C,QAAI,CAAC,OAAO,CAAC,IAAI,OAAQ;AAGzB,QAAI,CAAC,WAAY;AACjB,eAAW,MAAM,KAAK;AACpB,YAAM,MAAM,OAAO,EAAE;AACrB,YAAMA,QAAO,YAAa,UAAU,IAAI,GAAG,KAAK,OAAQ;AAIxD,YAAM,KAAK,SAASA,KAAI;AACxB,UAAI,CAAC,GAAI;AAET,YAAM,YAAY,YAAY,KAAK,EAAE;AACrC,YAAM,QAAQ,YAAY,UAAU,IAAI,GAAG,IAAI;AAC/C,YAAM,MAAM,SAAS,IAAI,GAAG;AAC5B,UAAI,KAAK;AAAE,YAAI,OAAOA,SAAQ,IAAI;AAAM,YAAI,MAAO,KAAI,SAAS,MAAM,UAAU,IAAI;AAAA,MAAO;AAC3F,UAAI,YAAY,EAAG;AACnB,gBAAU,IAAI,KAAK;AAAA,QACjB,MAAAA;AAAA,QACA,QAAS,SAAS,MAAM,UAAW;AAAA,MACrC,CAAC;AAAA,IACH;AACA,QAAI,UAAU,KAAM,cAAa;AACjC,sBAAkB;AAAA,EACpB;AAKA,iBAAe,oBAAoB,SAAS;AAC1C,QAAI,CAAC,WAAW,CAAC,QAAQ,KAAM;AAC/B,QAAI;AACF,YAAM,QAAQ,MAAM,UAAU;AAC9B,YAAM,QAAQ,MAAM,KAAK,CAAC,MAAM,CAAC,EAAE,SAAS,QAAQ,IAAI,OAAO,EAAE,SAAS,CAAC,KAAK,QAAQ,IAAI,OAAO,EAAE,SAAS,CAAC,EAAE,QAAQ,QAAQ,IAAI,OAAO,EAAE,SAAS,CAAC,EAAE,KAAK,KAAK;AACpK,UAAI,CAAC,MAAO;AACZ,YAAM,YAAY,CAAC,UAAU;AAC3B,mBAAW,QAAQ,MAAM,OAAO;AAC9B,cAAI,KAAK,MAAO;AAChB,gBAAM,OAAO,QAAQ,IAAI,OAAO,KAAK,SAAS,CAAC;AAC/C,gBAAM,IAAI,QAAQ,KAAK,QAAQ,KAAK,KAAK;AACzC,cAAI,EAAG,MAAK,QAAQ,OAAO,CAAC;AAAA,QAC9B;AAAA,MACF,CAAC;AAAA,IACH,SAAS,GAAG;AAAA,IAAuB;AAAA,EACrC;AAEA,iBAAe,UAAU;AACvB,QAAI,YAAa;AACjB,kBAAc;AACd,QAAI;AACF,aAAO,UAAU,MAAM;AACrB,cAAM,QAAQ,CAAC,GAAG,UAAU,QAAQ,CAAC,EAAE,MAAM,GAAG,UAAU;AAC1D,mBAAW,CAAC,EAAE,KAAK,MAAO,WAAU,OAAO,EAAE;AAC7C,YAAI;AACF,gBAAM,MAAM,MAAM,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE;AAClC,gBAAM,aAAa,MAAM,oBAAoB,GAAG;AAChD,gBAAM,UAAU,oBAAI,IAAI;AACxB,gBAAM,YAAY,oBAAI,IAAI;AAC1B,qBAAW,CAAC,IAAI,IAAI,KAAK,OAAO;AAC9B,kBAAM,IAAI,WAAW,IAAI,EAAE;AAC3B,gBAAI,CAAC,KAAK,CAAC,EAAE,UAAU;AAErB,8BAAgB,IAAI,KAAK,MAAM,KAAK,MAAM;AAC1C;AAAA,YACF;AACA,qBAAS,OAAO,EAAE;AAClB,kBAAM,OAAO,iBAAiB,EAAE,YAAY,IAAI;AAGhD,gBAAI,KAAK,QAAQ;AACf,kBAAI,OAAO,KAAK,OAAO,QAAQ,SAAU,MAAK,MAAM,KAAK,OAAO;AAChE,kBAAI,KAAK,OAAO,aAAa,KAAM,MAAK,YAAY,KAAK,OAAO;AAAA,YAClE;AACA,sBAAU,IAAI,IAAI,KAAK,MAAM,IAAI;AACjC,sBAAU,IAAI,IAAI,KAAK,IAAI;AAC3B,oBAAQ,IAAI,IAAI,EAAE,MAAM,UAAU,KAAK,CAAC;AAAA,UAC1C;AACA,gBAAM,eAAe,SAAS,SAAS;AAEvC,gBAAM,oBAAoB,OAAO;AAAA,QACnC,SAAS,GAAG;AAAA,QAA+B;AAE3C,cAAM,IAAI,QAAQ,CAAC,YAAY,aAAa,OAAO,CAAC;AAAA,MACtD;AAAA,IACF,UAAE;AACA,oBAAc;AAEd,UAAI,UAAU,KAAM,cAAa;AACjC,wBAAkB;AAAA,IACpB;AAAA,EACF;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;AAIT,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,OAAO,SAAS,MAAM,SAAS,IAC7C,EAAE,UAAU,MAAM,UAAU,WAAW,OAAO,MAAM,SAAS,EAAE,IAC/D,EAAE,UAAU,MAAM,SAAS,CAAC;AAChC;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;AAG9B,QAAM,eAAe,uBAAuB;AAE5C,QAAM,cAAc,uBAAuB;AAG3C,uBAAqB,CAAC,WAAW,SAAS,GAAG,CAAC,CAAC,EAAE,MAAM,MAAM;AAAA,EAAC,CAAC;AAE/D,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;AAMV,YAAI;AACF,gBAAM,UAAU,oBAAoB,OAAO,iBAAiB,aAAa,YAAY,iBAAiB,WAClG,EAAE,UAAU,iBAAiB,UAAU,WAAW,OAAO,SAAS,iBAAiB,SAAS,IAAI,OAAO,iBAAiB,SAAS,IAAI,OAAU,IAC9I,cAAc,MAAMJ,MAAK,WAAW,EAAE,KAAK,CAAC,QAAQ,EAAE,SAAS,GAAG,SAAS,MAAM,GAAG,KAAK,EAAE,IAAI;AACpG,cAAI,SAAS;AACX,kBAAM,IAAI,UAAU,IAAI,KAAK,OAAO,MAAM,MAAM,mBAAmB,CAAC,GAAG,GAAG,oBAAI,IAAI,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG;AAC7G,gBAAI,KAAK,EAAE,MAAO,SAAQ,OAAO,EAAE,KAAK;AAAA,UAC1C;AAAA,QACF,SAAS,GAAG;AAAA,QAAoB;AAChC,YAAI,CAAC,OAAO;AAAE,gBAAM,KAAK,oBAAoB,IAAI,GAAG;AAAG,cAAI,GAAI,SAAQ,OAAO,EAAE;AAAA,QAAE;AAAA,MACpF;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;AAAA;AAAA,QAGZ,WAAW;AAAA,QAAK,OAAO,SAAS;AAAA,QAAM,KAAK,OAAO;AAAA,QAClD,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,YAAMA,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,gBAAM,OAAO,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;AAKrC,QAAI;AAAE,YAAM,MAAM,UAAU,CAAC,GAAG,CAAC;AAAA,IAAE,SAAS,GAAG;AAAA,IAAsB;AACrE,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,KAAIR,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,WAAWM,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,QAAQ,IAAI,MAAM,0IAAiC;AACzD,YAAM,SAAS;AACf,YAAM,OAAO;AACb,YAAM;AAAA,IACR;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;AAI9D,UAAM,YAAY,CAAC;AAajB,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,cAAMN,OAAMO,SAAQ,OAAO,GAAG,EAAE,WAAW,KAAK,CAAC;AACjD,YAAI;AACF,gBAAMT,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,MAAMM,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,cAAMP,WAAU,YAAY,WAAW,EAAE,MAAM,IAAM,CAAC;AACtD,cAAMC,QAAO,YAAY,OAAO;AAChC,+BAAuB;AACvB,cAAM,OAAO,UAAU;AACvB,cAAM,eAAe,MAAM,sBAAsBK,SAAQ,OAAO,CAAC;AACjE,YAAI,aAAa,SAAS,EAAG,WAAU,KAAK,4EAAgB,aAAa,KAAK,QAAG,CAAC,6HAA8B;AAAA,MAClH,SAAS,GAAG;AACV,YAAI;AAAE,gBAAM,OAAO,UAAU;AAAA,QAAE,SAAS,GAAG;AAAA,QAAC;AAC5C,YAAI,sBAAsB;AAAE,cAAI;AAAE,kBAAM,OAAO,OAAO;AAAA,UAAE,SAAS,GAAG;AAAA,UAAC;AAAA,QAAE;AACvE,YAAI;AAAE,gBAAML,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;AAMA,UAAM,wBAAwB,OAAO,QAAQ;AAC3C,UAAI,UAAU;AACd,UAAI;AAAE,kBAAU,MAAMO,SAAQ,GAAG;AAAA,MAAE,SAAS,GAAG;AAAE,eAAO,CAAC;AAAA,MAAE;AAC3D,UAAI;AAAE,cAAMC,IAAG,KAAK,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,MAAE,SAAS,GAAG;AAAE,eAAO;AAAA,MAAQ;AACnF,aAAO,CAAC;AAAA,IACV;AAOA,QAAI,YAAY,SAAS,kBAAkB;AAIzC,YAAM,QAAQ,MAAM,YAAY,YAAY,GAAG;AAC/C,UAAI,SAAS,MAAM,UAAU;AAC3B,cAAMC,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,cAAc,MAAM,iBAAiB,EAAE,IAAI,KAAK,QAAQ,MAAM,WAAW,QAAQ,qBAAqB,EAAE,oBAAoB,CAAC;AACnI,YAAI,eAAe,MAAM,QAAQ,YAAY,iBAAiB,KAAK,YAAY,kBAAkB,SAAS,GAAG;AAC3G,oBAAU,KAAK,kCAAS,YAAY,kBAAkB,MAAM,yMAAoC;AAAA,QAClG;AACA,YAAI,eAAe,YAAY,iBAAiB,YAAY,cAAc,YAAY,OAAO;AAC3F,oBAAU,KAAK,4EAAgB,YAAY,cAAc,SAAS,KAAK,QAAG,CAAC,6HAA8B;AAAA,QAC3G;AAAA,MACF,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,kBAAMT,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,oBAAM,OAAO,UAAU;AAAA,YAAE,SAAS,GAAG;AAAA,YAAC;AAAA,UAAE;AAChE,cAAI,SAAS;AACX,kBAAM,eAAe,MAAM,sBAAsBK,SAAQ,OAAO,CAAC;AACjE,gBAAI,aAAa,SAAS,EAAG,WAAU,KAAK,4EAAgB,aAAa,KAAK,QAAG,CAAC,6HAA8B;AAAA,UAClH;AAAA,QACF,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,MACf,GAAI,UAAU,SAAS,IAAI,EAAE,OAAO,UAAU,IAAI,CAAC;AAAA,IACrD;AAAA,EACF;AAOA,QAAM,aAAa;AAEnB,WAAS,YAAY,GAAG;AACtB,QAAI,CAAC,EAAG,QAAO;AACf,QAAI,EAAE,SAAS,mBAAoB,QAAO;AAC1C,UAAM,OAAO,OAAQ,KAAK,EAAE,WAAY,CAAC;AACzC,WAAO,2BAA2B,KAAK,IAAI;AAAA,EAC7C;AAGA,iBAAe,YAAY,KAAK,YAAY;AAC1C,QAAI;AACF,aAAO,MAAM,QAAQ,KAAK,UAAU;AAAA,IACtC,SAAS,GAAG;AACV,UAAI,CAAC,YAAY,CAAC,EAAG,OAAM;AAC3B,YAAM,aAAa,MAAM,KAAK,UAAU;AACxC,aAAO,EAAE,IAAI,MAAM,OAAO,OAAO,QAAQ,MAAM,OAAO,CAAC,UAAU,EAAE;AAAA,IACrE;AAAA,EACF;AAIA,QAAM,iBAAiB;AACvB,QAAM,WAAW,KAAK,IAAI;AAE1B,MAAI,eAAe;AACnB,iBAAe,gBAAgB,QAAQ;AACrC,QAAI,aAAc,QAAO,EAAE,KAAK,OAAO,OAAO,GAAG,MAAM,EAAE;AACzD,mBAAe;AACf,QAAI,QAAQ;AACZ,UAAM,QAAQ,CAAC;AACf,QAAI;AACF,YAAM,QAAQ,MAAM,aAAa,KAAK;AACtC,iBAAW,QAAQ,OAAO;AACxB,YAAI;AACF,gBAAM,QAAQ,KAAK,WAAW,KAAK,UAAU;AAC7C,gBAAM,aAAa,OAAO,CAAC,KAAK,SAAS,CAAC;AAC1C,oBAAU,WAAW,KAAK,SAAS;AACnC;AACA,gBAAM,KAAK,+DAAa,OAAO,KAAK,SAAS,EAAE,MAAM,GAAG,EAAE,CAAC,QAAG;AAAA,QAChE,SAAS,GAAG;AACV,cAAI,YAAY,CAAC,EAAG;AACpB,cAAI,KAAK,IAAI,IAAI,WAAW,eAAgB;AAC5C,gBAAM,SAAS,MAAM,aAAa,aAAa,KAAK,SAAS;AAC7D,cAAI,UAAU,OAAO,QAAS,OAAM,KAAK,uFAAiB,OAAO,KAAK,SAAS,EAAE,MAAM,GAAG,EAAE,CAAC,eAAK,OAAQ,KAAK,EAAE,WAAY,CAAC,CAAC,QAAG;AAAA,QACpI;AAAA,MACF;AACA,UAAI,QAAQ,GAAG;AAAE,YAAI;AAAE,gBAAM,gBAAgB;AAAA,QAAE,SAAS,GAAG;AAAA,QAAoB;AAAA,MAAE;AAAA,IACnF,UAAE;AACA,qBAAe;AAAA,IACjB;AACA,QAAI,MAAM,SAAS,GAAG;AACpB,UAAI;AAAE,mBAAW,KAAK,MAAO,SAAQ,KAAK,4BAA4B,CAAC;AAAA,MAAE,SAAS,GAAG;AAAA,MAAe;AAAA,IACtG;AACA,SAAK;AACL,WAAO,EAAE,KAAK,MAAM,OAAO,OAAO,MAAM,aAAa,KAAK,GAAG,OAAO;AAAA,EACtE;AAQA,QAAM,cAAc,OAAO,IAAI,WAAW,aAAa,IAAI,OAAO,KAAK,GAAG,KAAK,CAAC,OAAO;AAAE,OAAG;AAAA,EAAE;AAC9F,MAAI,OAAO,IAAI,OAAO,YAAY;AAChC,gBAAY,MAAM,IAAI,GAAG,oBAAoB,CAAC,YAAY;AACxD,YAAM,KAAK,WAAW,QAAQ,MAAM,OAAO,OAAO,QAAQ,EAAE,IAAI;AAChE,UAAI,CAAC,GAAI;AACT,mBAAa,IAAI,EAAE,EAAE,KAAK,CAAC,WAAW;AACpC,YAAI,CAAC,OAAQ;AACb,cAAM,IAAI,WAAW,MAAM;AAAE,0BAAgB,kBAAkB,EAAE,MAAM,MAAM;AAAA,UAAC,CAAC;AAAA,QAAE,GAAG,GAAG;AACvF,YAAI,KAAK,OAAO,EAAE,UAAU,WAAY,GAAE,MAAM;AAAA,MAClD,CAAC,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC;AAAA,IACnB,CAAC,CAAC;AAAA,EACJ;AACA,cAAY,MAAM;AAGhB,UAAM,SAAS,CAAC,GAAG,KAAM,KAAM,KAAM,MAAO,GAAK,EAAE,IAAI,CAAC,OAAO;AAC7D,YAAM,IAAI,WAAW,MAAM;AACzB,wBAAgB,OAAO,IAAI,YAAY,WAAW,EAAE,EAAE,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AAAA,MACxE,GAAG,EAAE;AACL,UAAI,KAAK,OAAO,EAAE,UAAU,WAAY,GAAE,MAAM;AAChD,aAAO;AAAA,IACT,CAAC;AAED,UAAM,YAAY,YAAY,MAAM;AAClC,mBAAa,KAAK,EAAE,KAAK,CAAC,UAAU;AAAE,YAAI,MAAM,SAAS,EAAG,QAAO,gBAAgB,MAAM;AAAA,MAAE,CAAC,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC;AAAA,IAC9G,GAAG,IAAM;AACT,QAAI,aAAa,OAAO,UAAU,UAAU,WAAY,WAAU,MAAM;AACxE,WAAO,MAAM;AAAE,iBAAW,KAAK,OAAQ,cAAa,CAAC;AAAG,oBAAc,SAAS;AAAA,IAAE;AAAA,EACnF,CAAC;AAUD,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;AAQA,QAAM,aAAa,OAAO,GAAG,uBAAuB,cAAc,OAAO,GAAG,sBAAsB;AAElG,iBAAe,oBAAoB,KAAK;AACtC,UAAM,MAAM,oBAAI,IAAI;AACpB,UAAM,UAAU,CAAC,aAAa;AAAE,iBAAW,MAAM,IAAK,KAAI,IAAI,OAAO,EAAE,GAAG,EAAE,UAAU,UAAU,KAAK,CAAC;AAAA,IAAE;AACxG,QAAI,CAAC,OAAO,CAAC,IAAI,OAAQ,QAAO;AAChC,QAAI,CAAC,YAAY;AAAE,cAAQ,KAAK;AAAG,aAAO;AAAA,IAAI;AAC9C,QAAI,OAAO,GAAG,uBAAuB,YAAY;AAC/C,UAAI,UAAU;AACd,UAAI;AAAE,kBAAU,MAAM,GAAG,mBAAmB,GAAG;AAAA,MAAE,SAAS,GAAG;AAAE,kBAAU;AAAA,MAAK;AAC9E,UAAI,MAAM,QAAQ,OAAO,GAAG;AAC1B,gBAAQ,QAAQ,CAAC,QAAQ,UAAU;AACjC,gBAAM,KAAK,OAAO,IAAI,KAAK,CAAC;AAC5B,cAAI,UAAU,OAAO,WAAW,YAAa,KAAI,IAAI,IAAI,EAAE,UAAU,MAAM,UAAU,eAAe,MAAM,EAAE,CAAC;AAAA,mBACpG,UAAU,OAAO,WAAW,WAAY,KAAI,IAAI,IAAI,EAAE,UAAU,OAAO,UAAU,KAAK,CAAC;AAAA,mBACvF,OAAQ,KAAI,IAAI,IAAI,EAAE,UAAU,MAAM,UAAU,eAAe,MAAM,EAAE,CAAC;AAAA,cAC5E,KAAI,IAAI,IAAI,EAAE,UAAU,OAAO,UAAU,KAAK,CAAC;AAAA,QACtD,CAAC;AAED,mBAAW,MAAM,IAAK,KAAI,CAAC,IAAI,IAAI,OAAO,EAAE,CAAC,EAAG,KAAI,IAAI,OAAO,EAAE,GAAG,EAAE,UAAU,OAAO,UAAU,KAAK,CAAC;AACvG,eAAO;AAAA,MACT;AAAA,IAEF;AACA,QAAI,OAAO,GAAG,sBAAsB,YAAY;AAC9C,iBAAW,OAAO,KAAK;AACrB,cAAM,KAAK,OAAO,GAAG;AACrB,YAAI;AACF,gBAAM,IAAI,MAAM,GAAG,kBAAkB,EAAE;AACvC,cAAI,KAAK,EAAE,WAAW,WAAY,KAAI,IAAI,IAAI,EAAE,UAAU,OAAO,UAAU,KAAK,CAAC;AAAA,cAC5E,KAAI,IAAI,IAAI,EAAE,UAAU,MAAM,UAAU,eAAe,CAAC,EAAE,CAAC;AAAA,QAClE,SAAS,GAAG;AAAE,cAAI,IAAI,IAAI,EAAE,UAAU,OAAO,UAAU,KAAK,CAAC;AAAA,QAAE;AAAA,MACjE;AACA,aAAO;AAAA,IACT;AACA,YAAQ,KAAK;AACb,WAAO;AAAA,EACT;AAaA,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,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,QAAQ,IAAI,UAAU,UAAU,YAAY,SAAS;AAIrE,UAAM,YAAY,MAAM,mBAAmB,SAAS,SAAS;AAC7D,eAAW,CAAC,IAAI,IAAI,KAAK,WAAW;AAClC,YAAM,QAAQ,UAAU,IAAI,EAAE;AAC9B,YAAM,SAAS,SAAS,MAAM,SAAS,MAAM,SAAS;AACtD,gBAAU,IAAI,IAAI,UAAU,IAAI,EAAE,GAAG;AAAA,QACnC,OAAO,KAAK;AAAA,QACZ,KAAM,UAAU,OAAO,OAAO,QAAQ,YAAY,OAAO,MAAO,OAAO,MAAM,KAAK;AAAA,QAClF,WAAY,UAAU,OAAO,aAAa,OAAQ,OAAO,YAAY,KAAK;AAAA,MAC5E,CAAC;AAAA,IACH;AACA,UAAM,eAAe,QAAQ,OAAO,CAAC,OAAO,CAAC,UAAU,IAAI,EAAE,CAAC;AAE9D,QAAI,aAAa,OAAQ,aAAY,cAAc,WAAW,SAAS;AACvE,UAAM,QAAQ,CAAC;AACf,eAAW,MAAM,YAAY;AAK3B,UAAI,OAAO,UAAU,IAAI,IAAI,UAAU,IAAI,EAAE,CAAC,KAAK,UAAU,IAAI,EAAE,KAAK;AACxE,UAAI,CAAC,MAAM;AACT,eAAO,EAAE,OAAO,MAAM,KAAK,MAAM,WAAW,KAAK;AACjD,cAAM,QAAQ,UAAU,IAAI,EAAE;AAC9B,cAAM,SAAS,SAAS,MAAM,SAAS,MAAM,SAAS;AACtD,YAAI,QAAQ;AACV,cAAI,OAAO,OAAO,QAAQ,SAAU,MAAK,MAAM,OAAO;AACtD,cAAI,OAAO,aAAa,KAAM,MAAK,YAAY,OAAO;AAAA,QACxD;AAAA,MACF;AACA,YAAM,KAAK,UAAU,IAAI,MAAM,OAAO,CAAC,EAAE,QAAQ,KAAK,MAAM;AAC5D,YAAM,KAAK,EAAE,GAAG,IAAI,UAAU,gBAAgB,IAAI,GAAG,SAAS,EAAE,CAAC;AAAA,IACnE;AACA,QAAI,QAAQ,KAAK,cAAc;AAG7B,YAAM,gBAAgB,CAAC;AACvB,iBAAW,MAAM,OAAO;AACtB,YAAI,CAAC,GAAG,SAAU;AAClB,cAAM,EAAE,UAAU,OAAO,GAAG,KAAK,IAAI;AACrC,sBAAc,KAAK,IAAI;AAAA,MACzB;AACA,aAAO,EAAE,OAAO,eAAe,MAAM;AAAA,IACvC;AAGA,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,QAAQ,IAAI,CAAC,UAAU,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC;AACnE,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,WAAW;AAClC,cAAM,QAAQ,UAAU,IAAI,EAAE;AAC9B,cAAM,SAAS,SAAS,MAAM,SAAS,MAAM,SAAS;AACtD,kBAAU,IAAI,IAAI,UAAU,IAAI,EAAE,GAAG;AAAA,UACnC,OAAO,KAAK;AAAA,UACZ,KAAM,UAAU,OAAO,OAAO,QAAQ,YAAY,OAAO,MAAO,OAAO,MAAM,KAAK;AAAA,UAClF,WAAY,UAAU,OAAO,aAAa,OAAQ,OAAO,YAAY,KAAK;AAAA,QAC5E,CAAC;AAAA,MACH;AACA,YAAM,OAAO,QAAQ,OAAO,CAAC,OAAO,CAAC,UAAU,IAAI,EAAE,CAAC;AAGtD,UAAI,KAAK,OAAQ,aAAY,MAAM,WAAW,SAAS;AACvD,iBAAW,MAAM,KAAK;AACpB,cAAM,OAAO,UAAU,IAAI,IAAI,UAAU,IAAI,EAAE,CAAC,KAAK,UAAU,IAAI,EAAE,KAAK;AAC1E,YAAI,QAAQ,KAAK,MAAO,qBAAoB,IAAI,IAAI,OAAO,KAAK,KAAK,CAAC;AAAA,MACxE;AAAA,IACF;AAIA,UAAM,UAAU,CAAC;AACjB,eAAW,SAAS,SAAS;AAC3B,YAAM,OAAO,gBAAgB,MAAM,QAAQ,MAAM,SAAS;AAC1D,UAAI,KAAM,SAAQ,MAAM,EAAE,IAAI;AAAA,IAChC;AACA,UAAM,mBAAmB,SAAS,OAAO;AACzC,WAAO;AAAA,MACL,QAAQ,OAAO,YAAY,mBAAmB;AAAA,MAC9C,mBAAmB,MAAM,MAAM,IAAI,CAAC,SAAS,OAAO,KAAK,SAAS,CAAC;AAAA,MACnE,kBAAkB;AAAA,MAClB;AAAA;AAAA;AAAA,MAGA,aAAa,eAAe;AAAA,IAC9B;AAAA,EACF;AAIA,QAAM,iBAAiB,oBAAI,IAAI;AAa/B,QAAM,gBAAgB;AACtB,WAAS,eAAe,SAAS,IAAI,OAAO;AAC1C,QAAI,OAAO;AAGT,YAAM,OAAO,QAAQ,EAAE,MAAM,QAAQ,EAAE,IAAI,EAAE,QAAQ,MAAM,eAAe,MAAM,iBAAiB,GAAG,OAAO,MAAM;AACjH,WAAK,QAAQ;AAAA,IACf,WAAW,QAAQ,EAAE,GAAG;AAGtB,YAAM,OAAO,QAAQ,EAAE;AACvB,WAAK,QAAQ;AACb,UAAI,CAAC,KAAK,UAAU,CAAC,KAAK,cAAe,QAAO,QAAQ,EAAE;AAAA,IAC5D;AAAA,EACF;AACA,iBAAe,mBAAmB,SAAS,SAAS;AAClD,QAAI,CAAC,eAAe,OAAO,YAAY,mBAAmB,WAAY;AACtE,UAAM,UAAU,cAAc,CAAC;AAC/B,UAAM,OAAO,CAAC;AACd,eAAW,SAAS,SAAS;AAC3B,YAAM,OAAO,SAAS,OAAO,SAAS,MAAM,SAAS,IAAI,MAAM,YAAY;AAC3E,UAAI,SAAS,QAAQ,OAAO,mBAAoB;AAChD,YAAM,KAAK,OAAO,MAAM,EAAE;AAC1B,YAAM,UAAU,eAAe,IAAI,EAAE;AACrC,UAAI,WAAW,QAAQ,cAAc,MAAM;AAAE,uBAAe,SAAS,IAAI,QAAQ,KAAK;AAAG;AAAA,MAAS;AAClG,UAAI,KAAK,SAAS,cAAe,MAAK,KAAK,EAAE,IAAI,KAAK,CAAC;AAAA,IACzD;AACA,UAAM,QAAQ,IAAI,KAAK,IAAI,CAAC,EAAE,IAAI,KAAK,MAAM,QAAQ,YAAY;AAC/D,UAAI,UAAU;AACd,UAAI;AACF,cAAM,QAAQ,CAAC;AACf,cAAM,YAAY,eAAe,IAAI,EAAE,UAAU,CAAC,UAAU;AAC1D,qBAAW,MAAM,SAAS,CAAC,EAAG,KAAI,MAAM,SAAS,GAAI,OAAM,KAAK,MAAM,GAAG,IAAI;AAAA,QAC/E,EAAE,CAAC;AACH,kBAAU,kBAAkB,KAAK;AAAA,MACnC,SAAS,GAAG;AAAE,kBAAU;AAAA,MAAM;AAC9B,qBAAe,IAAI,IAAI,EAAE,WAAW,MAAM,OAAO,QAAQ,CAAC;AAC1D,qBAAe,SAAS,IAAI,OAAO;AAAA,IACrC,CAAC,CAAC,CAAC;AAGH,UAAM,OAAO,oBAAI,IAAI;AACrB,eAAW,SAAS,SAAS;AAC3B,YAAM,OAAO,SAAS,OAAO,SAAS,MAAM,SAAS,IAAI,MAAM,YAAY;AAC3E,UAAI,SAAS,QAAQ,QAAQ,mBAAoB,MAAK,IAAI,OAAO,MAAM,EAAE,CAAC;AAAA,IAC5E;AACA,eAAW,OAAO,eAAe,KAAK,GAAG;AACvC,UAAI,CAAC,KAAK,IAAI,GAAG,EAAG,gBAAe,OAAO,GAAG;AAAA,IAC/C;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,cAAMT,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,EAAE,GAAG,cAAc,YAAY,YAAY,CAAC;AAAA,IACrF,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;AAIvF,gBAAM,SAAS,IAAI,IAAI,MAAM;AAC7B,gBAAM,WAAW,MAAM,wBAAwB;AAC/C,gBAAM,QAAQ,SAAS,MAAM,OAAO,CAAC,OAAO,OAAO,IAAI,OAAO,GAAG,SAAS,CAAC,KAAK,GAAG,QAAQ;AAC3F,qBAAW,MAAM,MAAO,QAAO,GAAG;AAClC,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,cAAI;AAAE,kBAAM,WAAW,OAAO,CAAC,GAAG,CAAC;AAAA,UAAE,SAAS,GAAG;AAAA,UAAsB;AACvE,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,oBAAM,WAAW,OAAO,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM;AAAA,cAAC,CAAC;AAAA,YAAE,SACrJ,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,GAAG,aAAa,eAAe,EAAE,CAAC;AAAA,QAC7E,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;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,SAAS,QAAQ,OAAO,KAAK,cAAc,WAAW,KAAK,YAAY;AAC7E,cAAI,CAAC,UAAU,CAACA,iBAAgB,MAAM,EAAG,QAAO,KAAK,KAAK,EAAE,OAAO,oBAAoB,GAAG,GAAG;AAC7F,gBAAM,aAAa,oBAAI,IAAI;AAC3B,gBAAM,WAAW,oBAAI,IAAI;AAEzB,gBAAM,aAAa,oBAAI,IAAI;AAC3B,cAAI,YAAY,CAAC;AACjB,gBAAM,eAAe,oBAAI,IAAI;AAC7B,cAAI;AACF,kBAAM,QAAQ,MAAM,eAAe;AACnC,uBAAW,QAAQ,MAAM,MAAO,YAAW,IAAI,OAAO,KAAK,SAAS,CAAC;AACrE,wBAAY,MAAM,iBAAiB,IAAI,MAAM;AAAA,UAC/C,SAAS,GAAG;AAAA,UAAoB;AAChC,gBAAM,YAAY,CAAC,GAAG,cAAc;AAClC,gBAAI,CAAC,KAAK,EAAE,MAAM,KAAM;AACxB,kBAAM,KAAK,OAAO,EAAE,EAAE;AAItB,gBAAI,WAAW,IAAI,EAAE,KAAK,WAAW,IAAI,EAAE,EAAG;AAC9C,uBAAW,IAAI,IAAI;AAAA,cACjB,eAAe,EAAE,iBAAiB,OAAO,OAAO,EAAE,aAAa,IAAI;AAAA,cACnE,UAAU,EAAE,WAAW;AAAA,cACvB,iBAAiB,OAAO,SAAS,EAAE,eAAe,IAAI,EAAE,kBAAkB;AAAA,cAC1E,WAAW,OAAO,EAAE,cAAc,WAAW,EAAE,YAAY;AAAA,YAC7D,CAAC;AACD,gBAAI,OAAO,SAAS,SAAS,EAAG,UAAS,IAAI,IAAI,SAAS;AAAA,UAC5D;AAMA,gBAAM,eAAe,oBAAI,IAAI;AAC7B,gBAAM,iBAAiB,oBAAI,IAAI;AAC/B,cAAI;AACF,uBAAW,SAAS,MAAM,YAAY,YAAY,GAAG;AACnD,wBAAU,MAAM,QAAQ,MAAM,SAAS;AACvC,oBAAM,MAAM,SAAS,MAAM,MAAM,OAAO,OAAO,MAAM,EAAE,IAAI;AAC3D,kBAAI,KAAK;AACP,+BAAe,IAAI,KAAK,EAAE,QAAS,SAAS,MAAM,UAAW,KAAK,CAAC;AAKnE,oBAAI,SAAS,OAAO,MAAM,aAAa,YAAY,MAAM,UAAU;AACjE,+BAAa,IAAI,KAAK,OAAO,SAAS,MAAM,SAAS,IACjD,EAAE,UAAU,MAAM,UAAU,WAAW,OAAO,MAAM,SAAS,EAAE,IAC/D,EAAE,UAAU,MAAM,SAAS,CAAC;AAAA,gBAClC;AAAA,cACF;AACA,kBAAI,SAAS,MAAM,MAAM,KAAM,cAAa,IAAI,OAAO,MAAM,EAAE,CAAC;AAAA,YAClE;AAAA,UACF,SAAS,GAAG;AAAA,UAAoB;AAChC,gBAAM,UAAU,oBAAI,IAAI;AACxB,gBAAM,OAAO,IAAI,IAAI,UAAU;AAC/B,cAAI;AACF,gBAAI,QAAQ,OAAO,KAAK,SAAS,YAAY;AAC3C,mBAAK,KAAK,EAAE,QAAQ,CAAC,MAAM;AAAE,wBAAQ,IAAI,OAAO,EAAE,EAAE,CAAC;AAAG,0BAAU,EAAE,QAAQ,MAAS;AAAA,cAAE,CAAC;AAAA,YAC1F;AAAA,UACF,SAAS,GAAG;AAAA,UAAoB;AAGhC,qBAAW,MAAM,WAAW;AAC1B,gBAAI,CAAC,aAAa,IAAI,EAAE,EAAG,YAAW,OAAO,EAAE;AAAA,UACjD;AAEA,gBAAM,SAAS,oBAAI,IAAI;AACvB,qBAAW,CAAC,IAAI,CAAC,KAAK,YAAY;AAChC,gBAAI,CAAC,EAAE,YAAY,CAAC,EAAE,cAAe;AACrC,gBAAI,CAAC,OAAO,IAAI,EAAE,aAAa,EAAG,QAAO,IAAI,EAAE,eAAe,CAAC,CAAC;AAChE,mBAAO,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE;AAAA,UACrC;AAEA,gBAAM,YAAY;AAClB,cAAI,YAAY;AAChB,gBAAM,QAAQ,CAAC,IAAI,OAAO,YAAY;AACpC;AACA,kBAAM,IAAI,WAAW,IAAI,EAAE,KAAK,CAAC;AACjC,kBAAM,eAAe,IAAI,IAAI,OAAO;AACpC,yBAAa,IAAI,EAAE;AACnB,kBAAM,SAAS,aAAa,YAAY,CAAC,KAAK,OAAO,IAAI,EAAE,KAAK,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,aAAa,IAAI,CAAC,CAAC;AACtG,mBAAO;AAAA,cACL,WAAW;AAAA,cACX,eAAe,EAAE,iBAAiB;AAAA,cAClC,iBAAiB,EAAE;AAAA,cACnB;AAAA,cACA,WAAW,EAAE,aAAa;AAAA,cAC1B,WAAW,SAAS,IAAI,EAAE,IAAI,SAAS,IAAI,EAAE,IAAI;AAAA,cACjD,MAAM,QAAQ,IAAI,EAAE;AAAA,cACpB,OAAO;AAAA,cACP,UAAU,OAAO,IAAI,CAAC,MAAM,MAAM,GAAG,QAAQ,GAAG,YAAY,CAAC;AAAA,YAC/D;AAAA,UACF;AACA,gBAAM,SAAS,OAAO,IAAI,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,MAAM,MAAM,GAAG,GAAG,oBAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;AAClF,gBAAM,SAAS,CAAC,MAAM;AACtB,gBAAM,OAAO,CAAC,MAAM;AAAE,mBAAO,KAAK,EAAE,SAAS;AAAG,cAAE,SAAS,QAAQ,IAAI;AAAA,UAAE;AACzE,gBAAM,QAAQ,IAAI;AAGlB,gBAAM,aAAa,OAAO,IAAI,MAAM;AACpC,gBAAM,EAAE,QAAQ,eAAe,SAAS,eAAe,IAAI,UAAU,UAAU,YAAY,YAAY;AACvG,gBAAM,mBAAmB,MAAM,mBAAmB,gBAAgB,YAAY;AAC9E,qBAAW,CAAC,IAAI,IAAI,KAAK,iBAAkB,WAAU,IAAI,IAAI,aAAa,IAAI,EAAE,GAAG,IAAI;AACvF,gBAAM,cAAc,eAAe,OAAO,CAAC,OAAO,CAAC,iBAAiB,IAAI,EAAE,CAAC;AAC3E,cAAI,YAAY,OAAQ,aAAY,aAAa,cAAc,cAAc;AAC7E,gBAAM,gBAAgB,CAAC,MAAO,IAAK,EAAE,SAAS,YAAY,EAAE,MAAM,GAAG,SAAS,IAAI,WAAM,IAAK;AAC7F,gBAAM,UAAU,CAAC,OAAO;AACtB,kBAAM,MAAM,OAAO,EAAE;AACrB,kBAAM,IAAI,cAAc,IAAI,GAAG,KAAK,iBAAiB,IAAI,GAAG;AAC5D,mBAAO,cAAe,KAAK,EAAE,SAAU,oBAAoB,IAAI,GAAG,KAAK,IAAI;AAAA,UAC7E;AACA,gBAAM,OAAO,CAAC,MAAM;AAAE,cAAE,QAAQ,QAAQ,EAAE,SAAS;AAAG,cAAE,SAAS,QAAQ,IAAI;AAAA,UAAE;AAC/E,gBAAM,QAAQ,IAAI;AAClB,eAAK,KAAK,EAAE,QAAQ,EAAE,WAAW,QAAQ,OAAO,QAAQ,MAAM,EAAE,GAAG,MAAM,CAAC;AAAA,QAC5E,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,YAAY,KAAK,MAAM;AAC3C,cAAI,MAAM,OAAQ,QAAO,KAAK,KAAK,EAAE,WAAW,KAAK,GAAG,MAAM,CAAC;AAG/D,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;AAKF,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,MAAM,QAAQ,QAAQ,KAAK,UAAU,IAC7C,CAAC,GAAG,IAAI,IAAI,KAAK,WAAW,OAAO,CAAC,MAAM,OAAO,MAAM,YAAY,CAAC,CAAC,CAAC,IACtE,CAAC;AACL,gBAAM,SAAS,QAAQ,OAAO,KAAK,eAAe,WAAW,KAAK,aAAa;AAC/E,cAAI,CAAC,IAAI,OAAQ,QAAO,KAAK,KAAK,EAAE,IAAI,OAAO,OAAO,qBAAqB,GAAG,GAAG;AACjF,cAAI,CAAC,OAAQ,QAAO,KAAK,KAAK,EAAE,IAAI,OAAO,OAAO,qBAAqB,GAAG,GAAG;AAC7E,cAAI,QAAQ;AACZ,gBAAM,SAAS,CAAC;AAChB,gBAAM,SAAS,CAAC;AAChB,qBAAW,OAAO,KAAK;AACrB,gBAAI;AACF,oBAAM,IAAI,MAAM,YAAY,KAAK,MAAM;AACvC,kBAAI,KAAK,EAAE,QAAQ;AAAE,uBAAO,KAAK,GAAG;AAAG;AAAA,cAAS;AAEhD,wBAAU,WAAW,GAAG;AACxB;AAAA,YACF,SAAS,GAAG;AACV,oBAAM,MAAM,KAAK,EAAE,OAAO,EAAE,WAAW,KAAK,OAAO,OAAQ,KAAK,EAAE,WAAY,CAAC,GAAG,MAAM,EAAE,KAAK,IAAI,EAAE,WAAW,KAAK,OAAO,OAAQ,KAAK,EAAE,WAAY,CAAC,EAAE;AAC1J,qBAAO,KAAK,GAAG;AAAA,YACjB;AAAA,UACF;AACA,cAAI;AAAE,kBAAM,gBAAgB;AAAA,UAAE,SAAS,GAAG;AAAA,UAAoB;AAC9D,eAAK,KAAK;AAAA,YACR;AAAA,YACA;AAAA,YACA,GAAI,OAAO,SAAS,IAAI,EAAE,QAAQ,OAAO,CAAC,GAAG,OAAO,MAAM,mNAA8C,EAAE,IAAI,CAAC;AAAA,UACjH,CAAC;AAAA,QACH,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,QAAQ,MAAM,aAAa,KAAK;AACtC,eAAK,KAAK,EAAE,OAAO,MAAM,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,WAAW,YAAY,EAAE,YAAY,UAAU,EAAE,UAAU,UAAU,EAAE,SAAS,EAAE,EAAE,CAAC;AAAA,QAC3I,SAAS,GAAG;AACV,eAAK,KAAK,EAAE,OAAO,OAAQ,KAAK,EAAE,WAAY,CAAC,EAAE,GAAG,GAAG;AAAA,QACzD;AAAA,MACF;AAAA,IACF,CAAC,CAAC;AACF,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,MAAM,aAAa,OAAO,GAAG;AAC7C,eAAK,KAAK,EAAE,IAAI,MAAM,QAAQ,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;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", "readdir", "rename", "rm", "stat", "writeFile", "basename", "dirname", "join", "readFileSync", "homedir", "name", "readFileSync", "mkdir", "rename", "writeFile", "homedir", "join", "item", "join", "name", "mkdir", "rename", "writeFile", "readFileSync", "homedir", "join", "DEFAULT_DIR", "isFresh", "stat", "mkdir", "rename", "writeFile", "join", "readdir", "stat", "join", "join", "name", "stat", "readdir", "join", "name", "mkdir", "readFile", "readdir", "rename", "rm", "stat", "writeFile", "basename", "dirname", "join", "readdir", "join", "stat", "name", "rm", "closeQuietly", "readFile", "mkdir", "writeFile", "rename", "dirname", "basename", "join", "homedir", "isSafeSessionId", "stat", "readFileSync", "mkdir", "writeFile", "rename", "entry", "store", "error", "basename", "dirname", "readFile", "readdir", "rm", "stat2"]
|
|
3
|
+
"sources": ["../src/index.js", "../src/zstd-frame.js", "../src/markdown.js", "../src/star-index.js", "../src/tag-index.js", "../src/saved-filters.js", "../src/pending-moves.js", "../src/move-notices.js", "../src/state-temp-sweep.js", "../src/storage-stats.js", "../src/auto-archive.js", "../src/session-meta-cache.js", "../src/title-persist-index.js", "../src/empty-scan-index.js", "../src/handle-era-paths.js", "../src/path-guard.js", "../src/compat/persistence.js", "../src/compat/capabilities.js", "../src/handle-era-ops.js", "../src/lineage.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, readdir, realpath, rename, rm, 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 { createTagIndex } from './tag-index.js'\nimport { createSavedFilters } from './saved-filters.js'\nimport { createPendingMoveStore } from './pending-moves.js'\nimport { createMoveNoticeStore } from './move-notices.js'\nimport { sweepStaleStateTemps } from './state-temp-sweep.js'\nimport { aggregateStorage } from './storage-stats.js'\nimport { createAutoArchiveStore, pickInactiveCandidates } from './auto-archive.js'\nimport { createSessionMetaCache, fingerprintOf, persistFingerprintOf } from './session-meta-cache.js'\nimport { createTitleIndexStore } from './title-persist-index.js'\nimport { createEmptyScanStore } from './empty-scan-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'\nimport { classifyLineage, emptyScanCandidate, isEmptyEventTypes, EMPTY_DECODE_LIMIT } from './lineage.js'\n\n// \u6784\u5EFA\u6307\u7EB9\uFF1Abuild.mjs \u4EE5 define \u5728\u7F16\u8BD1\u671F\u6CE8\u5165\uFF1B\u76F4\u63A5\u4EE5\u6E90\u7801\u8FD0\u884C\uFF08\u6D4B\u8BD5\uFF09\u65F6\u4E3A 'dev'\u3002\n// \u7528\u9014\uFF1Acapabilities \u5E26\u51FA buildStamp\uFF0C\u4E00\u773C\u5224\u65AD\u300C\u8FD0\u884C\u4E2D\u7684 host \u662F\u4E0D\u662F\u8FD9\u4EFD\u6784\u5EFA\u300D\u2014\u2014\n// \u63D2\u4EF6 host \u7AEF\u53EA\u5728\u5BBF\u4E3B\u542F\u52A8\u65F6\u52A0\u8F7D\u4E00\u6B21\uFF0C\u6539\u5B8C lib \u4E0D\u91CD\u542F\u5BBF\u4E3B\u7B49\u4E8E\u767D\u6539\u3002\nconst BUILD_STAMP = typeof __BUILD_STAMP__ !== 'undefined' ? __BUILD_STAMP__ : 'dev'\n\n\nexport const name = 'dsh-sessions-manager'\nexport const inject = ['webServer', 'workspaceRegistry', 'sessionPersistence', 'sessionQuery', 'storageDomain']\n\nconst MAX_TITLE = 80\n// \u63D2\u4EF6\u81EA\u6709\u72B6\u6001\u76EE\u5F55\uFF08\u661F\u6807 / \u6807\u7B7E / \u4FDD\u5B58\u7B5B\u9009 / \u81EA\u52A8\u5F52\u6863 / \u6807\u9898\u7D22\u5F15\u5171\u7528\uFF09\u3002\u4E0E star-index.js\u3001\n// tag-index.js\u3001auto-archive.js\n// \u7684\u9ED8\u8BA4\u76EE\u5F55\u4FDD\u6301\u4E00\u81F4\uFF0C\u73AF\u5883\u53D8\u91CF\u540C\u540D\uFF0C\u4FBF\u4E8E\u6D4B\u8BD5\u6CE8\u5165\u3002\nconst STATE_DIR = process.env.DSH_SESSIONS_MANAGER_STAR_DIR || join(homedir(), '.dsh', 'sessions-manager')\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\n// foldTitle\uFF08v3.6.1 \u5220\u9664\u8DEF\u5F84\u7684\u515C\u5E95\u6298\u53E0\uFF09\u968F v3.6.2 #7 \u7684\u300C\u5220\u9664\u8DEF\u5F84\u96F6\u89E3\u7801\u300D\u4E00\u5E76\n// \u79FB\u9664\uFF1B\u6807\u9898\u6298\u53E0\u903B\u8F91\u7684\u6743\u5A01\u5B9E\u73B0\u73B0\u5728\u662F runtime \u6295\u5F71\uFF08src/index.js projectTitlesStatus\uFF09\u3002\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 // T1\uFF083.7.0\uFF09\uFF1A\u7A7A\u767D\u7CBE\u5224\u7ED3\u8BBA\u7684\u6301\u4E45\u5C42\u3002\u53EA\u6709**\u771F\u89E3\u7801\u6210\u529F**\u7684\u5224\u5B9A\u843D\u76D8\uFF08unknown\n // \u4E0E\u5931\u8D25\u515C\u5E95\u90FD\u4E0D\u662F\u7ED3\u8BBA\uFF09\uFF0Csz \u6307\u7EB9 + 14 \u5929 TTL \u53CC\u95F8\u95E8\u9632\u300C\u540C\u5C3A\u5BF8\u539F\u5730\u6539\u5199\u300D\u3002\n const emptyIndex = createEmptyScanStore({ dir: TRASH_DIR })\n const EMPTY_VERDICT_TTL_MS = 14 * 24 * 3600 * 1000\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 // \u6301\u4E45\u7D22\u5F15\u53EA\u8BA4\u53EF\u8DE8\u91CD\u542F\u7684\u6307\u7EB9\uFF08legacy \u7684\u6587\u4EF6\u6307\u7EB9 / handle \u4E16\u4EE3\u7684 sz \u6307\u7EB9\uFF0C\n // \u89C1 session-meta-cache.persistFingerprintOf\u2014\u2014issue #8 \u4E4B\u524D handle \u4E16\u4EE3\n // \u4ECE\u4E0D\u843D\u76D8\uFF0C\u5BFC\u81F4\u6BCF\u6B21\u91CD\u542F\u90FD\u5168\u91CF\u91CD\u65B0\u89E3\u7801\uFF09\u3002\n const fp = persistFingerprintOf(stat)\n if (!fp) continue\n // v3.6.2 #1\uFF1Atitle \u4E3A null \u7684\u6761\u76EE\u5FC5\u987B\u662F\u300C\u6295\u5F71\u786E\u5B9E\u6210\u529F\u8FC7\u300D\uFF08resolved\uFF09\u624D\u53EF\u4FE1\u3002\n // v3.6.1 \u628A\u6295\u5F71\u5931\u8D25\u5F53\u7ED3\u679C\u843D\u76D8\u7684\u6C61\u67D3\u6761\u76EE\uFF08null \u6807\u9898\u3001\u65E0\u6807\u8BB0\uFF09\u5728\u8FD9\u91CC\u88AB\u4E22\u5F03\uFF0C\n // \u8C03\u7528\u65B9\u6309\u672A\u547D\u4E2D\u5904\u7406 \u2192 \u91CD\u65B0\u5165\u961F\u9884\u70ED\uFF0C\u7D22\u5F15\u81EA\u6108\u3002\n if (entry.fingerprint === fp && (entry.title || entry.resolved)) {\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\u56DE\u5199\u6301\u4E45\u7D22\u5F15\uFF08\u7D22\u5F15\u53EA\u662F\u52A0\u901F\u5668\uFF1A\u5199\u5931\u8D25\u4E0D\u5F71\u54CD\u54CD\u5E94\uFF0C\n // \u961F\u5217\u5185\u90E8\u5DF2\u4E32\u884C\u5316 + \u539F\u5B50\u66FF\u6362\uFF09\u3002**\u5FC5\u987B await** \u2014\u2014 \u5B83\u662F\u6301\u4E45\u5199\u5165\uFF0C\u6D6E\u52A8\u5199\u5165\u4F1A\u5728\n // \u8C03\u7528\u65B9/\u6D4B\u8BD5 teardown \u5DF2\u5F00\u59CB\u6E05\u7406\u72B6\u6001\u76EE\u5F55\u65F6\u843D\u5730\uFF08`ENOTEMPTY: rmdir .../state`\uFF09\uFF0C\n // \u4E14\"\u54CD\u5E94\u5DF2\u8FD4\u56DE\u4F46\u7D22\u5F15\u6CA1\u843D\u76D8\"\u65F6\u8FDB\u7A0B\u82E5\u6070\u597D\u9000\u51FA\u5C31\u4F1A\u4E22\u6761\u76EE\u3002\n // \u6307\u7EB9\u7528 persistFingerprintOf\uFF1Alegacy \u6587\u4EF6\u6307\u7EB9 + handle \u4E16\u4EE3 sz(sizeBytes) \u6307\u7EB9\n // \u90FD\u53EF\u8DE8\u91CD\u542F\uFF1Brev: \u6307\u7EB9\u4ECD\u88AB\u6392\u9664\uFF08\u5B9E\u4F8B\u5185 opaque token\uFF0Cissue #8\uFF09\u3002\n // v3.6.2 #1\uFF1Adecoded \u7684\u503C\u662F { meta, resolved } \u2014\u2014 resolved=false\uFF08\u6295\u5F71\u5931\u8D25\uFF09\n // \u7684\u6761\u76EE\u7EDD\u4E0D\u843D\u76D8\uFF1Bnull \u6807\u9898\u53EA\u6709 resolved=true \u624D\u5141\u8BB8\uFF08\u5426\u5219\u8BFB\u53D6\u7AEF\u4F1A\u5F53\u6C61\u67D3\u4E22\u5F03\uFF09\u3002\n async function persistDecoded(decoded, statsById) {\n if (!decoded || !decoded.size) return\n const batch = {}\n const now = Date.now()\n for (const [id, pack] of decoded) {\n if (!pack || !pack.resolved) continue\n const meta = pack.meta\n const fp = persistFingerprintOf(statsById.get(id))\n if (!fp) continue\n batch[id] = { title: meta.title, cwd: meta.cwd, createdAt: meta.createdAt, fingerprint: fp, updatedAt: now, resolved: 1 }\n }\n if (!Object.keys(batch).length) return\n try { await titleIndex.merge(batch) } catch (e) { /* \u7D22\u5F15\u5199\u5931\u8D25\u4E0D\u5F71\u54CD\u672C\u6B21\u54CD\u5E94 */ }\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\u91CC\u5E26\u51FA\uFF08\u5B58\u50A8\u5206\u6790 / \u81EA\u52A8\u5F52\u6863 / \u4F1A\u8BDD\n // \u5217\u8868\u2014\u20143.7.0 \u8D77\u5217\u8868\u4E5F\u8981\uFF1A\u5206\u652F\u7EC4\u65F6\u95F4\u56DE\u9000\u952E\u8BFB updatedAt\uFF09\u3002\u5B83\u4EEC\u672C\u5C31\u6765\u81EA\n // usage\uFF0C\u53EA\u662F payload \u4F53\u79EF\uFF0C\u4E0D\u5F15\u5165\u4EFB\u4F55\u89E3\u7801\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 \u2192 issue #8\uFF09\uFF1Aruntime \u7684\u6807\u9898\u6295\u5F71\uFF08readTitleSnapshots\uFF09\n // \u5728 0.1.x \u4E0A\u5BF9\u6BCF\u6761\u975E live \u4F1A\u8BDD\u90FD\u662F**\u6574\u672C\u65E5\u5FD7\u89E3\u7801**\uFF08SessionCorpus.projectMany\n // \u2192 inspectPersisted\uFF09\u3002\u5217\u8868\u6784\u5EFA\u7EDD\u4E0D\u80FD\u5728\u8BF7\u6C42\u8DEF\u5F84\u4E0A\u540C\u6B65\u89E6\u53D1\u5B83\u2014\u2014issue #8 \u5B9E\u6D4B\uFF1A\n // 87 \u672C\u65E5\u5FD7 / 249MB \u7684\u5E93\uFF0C\u4E00\u6B21\u51B7\u542F\u52A8\u5168\u91CF\u6295\u5F71\u628A\u5BBF\u4E3B\u6253\u6EE1 ~90s CPU\u3002\n //\n // \u56E0\u6B64\u8BF7\u6C42\u8DEF\u5F84\u53EA\u6D88\u8D39\u4E24\u7EA7\u7F13\u5B58\uFF08metaCache \u5185\u5B58\u7F13\u5B58 \u2192 titleIndex \u6301\u4E45\u7D22\u5F15\uFF09\uFF0C\n // \u7F3A\u5931\u7684\u4F1A\u8BDD\u4EA4\u7ED9\u540E\u53F0\u9884\u70ED\u961F\u5217\u5206\u6279\u8865\u9F50\uFF08\u89C1 enqueueWarm/runWarm\uFF09\uFF1B\u4FA7\u680F\u9AD8\u9891\n // \u8F6E\u8BE2 + \u7BA1\u7406\u9762\u677F\u5237\u65B0\u4F1A\u8BA9\u8865\u9F50\u7ED3\u679C\u81EA\u7136\u6D6E\u73B0\u3002\n const EMPTY_META = { title: null, cwd: null, createdAt: null }\n\n // \u2014\u2014 \u51B7\u542F\u52A8\u540E\u53F0\u9884\u70ED\uFF08issue #8\uFF09\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\n // \u5355\u98DE\u961F\u5217\uFF1A\u8BF7\u6C42\u8DEF\u5F84\u53D1\u73B0\u7F13\u5B58\u672A\u547D\u4E2D\u7684\u4F1A\u8BDD\uFF0C\u628A { stat, header } \u5FEB\u7167\u4E22\u8FDB\n // warmQueue\uFF0C\u7531 runWarm \u4EE5\u5C0F\u6279\u6B21\u6D88\u8D39\u3002\u6BCF\u6279\u4E4B\u95F4 setImmediate \u8BA9\u6B65\u4E8B\u4EF6\u5FAA\u73AF\uFF0C\n // \u7EDD\u4E0D\u72EC\u5360\u5BBF\u4E3B\u4E3B\u7EBF\u7A0B\uFF1B\u7ED3\u679C\u5199 metaCache + \u6301\u4E45\u6807\u9898\u7D22\u5F15\u3002stat \u662F\u5165\u961F\u65F6\u523B\u7684\n // \u5FEB\u7167\u2014\u2014\u82E5\u65E5\u5FD7\u5728\u9884\u70ED\u671F\u95F4\u53C8\u53D8\u4E86\uFF0C\u4E0B\u6B21\u8BF7\u6C42\u7684\u6307\u7EB9\u6BD4\u5BF9\u4F1A\u518D\u6B21\u5224\u672A\u547D\u4E2D\u5E76\u91CD\u65B0\n // \u5165\u961F\uFF0C\u5929\u7136\u81EA\u6108\u3002\n const WARM_CHUNK = 4\n const warmQueue = new Map()\n let warmRunning = false\n let warmKickTimer = null\n\n // v3.6.2 #1\uFF1A\u6295\u5F71\u5931\u8D25\u7684\u4E09\u6001\u5904\u7406\uFF08issue #8 \u5BA1\u8BA1\uFF09\u3002\u65E7\u5B9E\u73B0\u628A\u300C\u6295\u5F71\u5931\u8D25\u300D\u548C\n // \u300C\u4F1A\u8BDD\u771F\u6CA1\u6807\u9898\u300D\u6DF7\u4E3A\u540C\u4E00\u4E2A null \u2192 \u5931\u8D25\u88AB\u5199\u8FDB\u7F13\u5B58/\u6301\u4E45\u7D22\u5F15\uFF0C\u8DE8\u91CD\u542F\u56FA\u5316\u6210\n // \u6C38\u4E45\u5360\u4F4D\u4E14\u6C38\u4E0D\u91CD\u8BD5\u3002\u73B0\u5728\uFF1A\n // - resolved\uFF08fulfilled\uFF0Ctitle \u53EF\u4EE5\u662F null = \u4E8B\u5B9E\u65E0\u6807\u9898\uFF09\u2192 \u6B63\u5E38\u5165\u7F13\u5B58+\u843D\u76D8\uFF1B\n // - failed\uFF08rejected / \u6279\u91CF\u5F02\u5E38 / \u7ED3\u679C\u7F3A\u6761\uFF09\u2192 \u4E0D\u7F13\u5B58\u3001\u4E0D\u843D\u76D8\uFF0C\u6309 id \u8BA1\u6570\u9000\u907F\u3002\n // \u9000\u907F\uFF1A15s\u00D72^n \u9012\u589E\uFF0C\u6700\u591A WARM_MAX_ATTEMPTS \u6B21\uFF1B\u6B64\u540E parked \u4E00\u5C0F\u65F6\u540E\u518D\u63A2\u4E00\u6B21\n // \uFF08\u574F\u65E5\u5FD7\u957F\u671F\u505C\u6446\u65F6\u4E0D\u81F3\u4E8E\u6C38\u4E45\u9759\u9ED8\uFF09\u3002\u65E5\u5FD7\u6307\u7EB9\u4EFB\u4F55\u53D8\u5316\u90FD\u6E05\u96F6\u8BA1\u6570\u91CD\u65B0\u6B66\u88C5\u3002\n const WARM_MAX_ATTEMPTS = 5\n const warmFail = new Map() // id \u2192 { count, fp, nextAt }\n\n function warmFpOf(stat) {\n return fingerprintOf(stat) || persistFingerprintOf(stat)\n }\n\n function warmBlocked(id, fp) {\n const rec = warmFail.get(id)\n if (!rec) return 0\n if (fp && rec.fp && rec.fp !== fp) { warmFail.delete(id); return 0 } // \u5185\u5BB9\u53D8\u4E86 \u2192 \u91CD\u65B0\u6B66\u88C5\n const now = Date.now()\n return rec.nextAt > now ? rec.nextAt - now : 0\n }\n\n function warmMarkFailure(id, stat, header) {\n const rec = warmFail.get(id) || { count: 0, fp: null, nextAt: 0 }\n rec.count += 1\n rec.fp = warmFpOf(stat) || rec.fp\n // \u9000\u907F\u5230\u70B9\u540E\u7531 scheduleWarmRetry \u539F\u6837\u91CD\u65B0\u5165\u961F\uFF08\u542B\u672C\u8F6E\u7684 stat/header \u5FEB\u7167\uFF09\u3002\n if (stat) rec.stat = stat\n if (header) rec.header = header\n const backoff = rec.count >= WARM_MAX_ATTEMPTS\n ? 60 * 60 * 1000\n : Math.min(5 * 60 * 1000, 15 * 1000 * Math.pow(2, rec.count))\n rec.nextAt = Date.now() + backoff\n warmFail.set(id, rec)\n }\n\n // \u961F\u5217\u91CC\u8FD8\u6709\u300C\u672A\u653E\u5F03\u300D\u7684\u6D3B \u2192 \u4FA7\u680F/\u9762\u677F\u5E94\u7F29\u77ED\u8F6E\u8BE2\u8282\u62CD\uFF08client \u6D88\u8D39\uFF09\u3002\n function warmPendingNow() {\n if (!warmHasApi) return false\n if (warmRunning || warmQueue.size) return true\n for (const rec of warmFail.values()) if (rec.nextAt > Date.now()) return true\n return false\n }\n\n // \u9000\u907F\u5230\u70B9\u7684\u6761\u76EE\u7531\u4E00\u4E2A unref \u5B9A\u65F6\u5668\u91CD\u65B0\u5165\u961F\uFF08\u6BCF\u8F6E\u53EA\u6302\u6700\u8FD1\u7684\u4E00\u4E2A\uFF09\u3002\n let warmRetryTimer = null\n function scheduleWarmRetry() {\n if (warmRetryTimer) return\n let soonest = 0\n for (const rec of warmFail.values()) {\n const wait = rec.nextAt - Date.now()\n if (wait <= 0) { soonest = 1; break }\n if (!soonest || wait < soonest) soonest = wait\n }\n if (!soonest) return\n warmRetryTimer = setTimeout(() => {\n warmRetryTimer = null\n // \u5230\u70B9\u7684\u6761\u76EE\u91CD\u65B0\u5165\u961F\uFF08enqueue \u65F6\u4F1A\u91CD\u65B0\u6821\u9A8C blocked/fp\uFF09\u3002\n const now = Date.now()\n for (const [id, rec] of warmFail) {\n if (rec.nextAt <= now && !warmQueue.has(id)) warmQueue.set(id, { stat: rec.stat || null, header: rec.header || null })\n }\n if (warmQueue.size) scheduleWarm()\n }, soonest)\n if (typeof warmRetryTimer.unref === 'function') warmRetryTimer.unref()\n }\n\n function scheduleWarm() {\n if (warmKickTimer || warmRunning) return\n warmKickTimer = setTimeout(() => { warmKickTimer = null; runWarm() }, 25)\n // unref\uFF1A\u9884\u70ED\u7EDD\u4E0D\u53CD\u8FC7\u6765\u628A\u5BBF\u4E3B\u8FDB\u7A0B\u9489\u4F4F\uFF08\u4E0E autoArchive\u300C\u65E0\u5B9A\u65F6\u5668\u300D\u540C\u4E00\u539F\u5219\uFF09\u3002\n if (typeof warmKickTimer.unref === 'function') warmKickTimer.unref()\n }\n\n function enqueueWarm(ids, statsById, entryById) {\n if (!ids || !ids.length) return\n // \u65E0\u6295\u5F71 API \u7684 runtime\uFF1A\u9884\u70ED\u6CE8\u5B9A\u65E0\u679C\uFF0C\u4E0D\u5165\u961F\uFF08\u5360\u4F4D\u884C\u4E3A\u9000\u56DE\u300C\u5217\u8868\u4E0D\u5E26\u6807\u9898\u300D\n // \u7684\u8BDA\u5B9E\u5F62\u6001\uFF0C\u800C\u4E0D\u662F\u8BA9\u9000\u907F\u5B9A\u65F6\u5668\u6C38\u8FDC\u8F6C\u4E0B\u53BB\uFF09\u3002\n if (!warmHasApi) return\n for (const id of ids) {\n const key = String(id)\n const stat = statsById ? (statsById.get(key) || null) : null\n // #9\uFF1A\u4EFB\u4F55\u6307\u7EB9\u90FD\u7B97\u4E0D\u51FA\u6765\u7684\u4F1A\u8BDD\uFF08live \u672A\u843D\u76D8\u7B49\uFF09\u65E2\u8FDB\u4E0D\u4E86\u5185\u5B58\u7F13\u5B58\u4E5F\u8FDB\u4E0D\u4E86\n // \u6301\u4E45\u7D22\u5F15\u2014\u2014\u6295\u5F71\u7ED3\u679C\u6CE8\u5B9A\u65E0\u5904\u5B89\u653E\uFF0C\u6BCF\u8F6E\u8F6E\u8BE2\u91CD\u590D\u5165\u961F\u53EA\u662F\u767D\u70E7 CPU\uFF08churn\uFF09\u3002\n // \u8DF3\u8FC7\uFF1B\u8FD9\u7C7B\u884C\u7684\u6807\u9898\u7531 DSH \u81EA\u5DF1\u7684 live \u6E32\u67D3\u4FDD\u8BC1\u3002\n const fp = warmFpOf(stat)\n if (!fp) continue\n // #1\uFF1A\u4ECD\u5728\u5931\u8D25\u9000\u907F\u7A97\u53E3\u5185\u7684\u6761\u76EE\u4E0D\u91CD\u590D\u5165\u961F\uFF08runWarm \u4F1A\u6309 blocked \u8DF3\u8FC7\uFF09\u3002\n const blockedMs = warmBlocked(key, fp)\n const entry = entryById ? entryById.get(key) : null\n const rec = warmFail.get(key)\n if (rec) { rec.stat = stat || rec.stat; if (entry) rec.header = entry.header || rec.header }\n if (blockedMs > 0) continue\n warmQueue.set(key, {\n stat,\n header: (entry && entry.header) || null,\n })\n }\n if (warmQueue.size) scheduleWarm()\n scheduleWarmRetry()\n }\n\n // #7\uFF1A\u8F6F\u5220\u9664\u65F6\u6807\u9898\u53EF\u80FD\u8FD8\u6CA1\u9884\u70ED\u51FA\u6765\uFF08\u56DE\u6536\u7AD9\u6761\u76EE\u843D\u4E00\u6761 title:null \u7684\u8BDA\u5B9E\u8BB0\u5F55\uFF09\uFF0C\n // \u4E4B\u540E\u4EFB\u4F55\u4E00\u8F6E warm \u89E3\u51FA\u8BE5\u4F1A\u8BDD\u6807\u9898\u5C31\u8865\u5199\u8FDB\u56DE\u6536\u7AD9\u7D22\u5F15\u2014\u2014\u53EA\u8865\u7A7A\u6807\u9898\uFF0C\n // \u7EDD\u4E0D\u8986\u76D6\u5DF2\u6709\u503C\u3002\u56DE\u6536\u7AD9\u6E32\u67D3\u7AEF\uFF08t.title || t.sessionId\uFF09\u968F\u4E0B\u6B21\u62C9\u53D6\u81EA\u7136\u66F4\u65B0\u3002\n async function backfillTrashTitles(decoded) {\n if (!decoded || !decoded.size) return\n try {\n const items = await readTrash()\n const worth = items.some((t) => !t.title && decoded.get(String(t.sessionId)) && decoded.get(String(t.sessionId)).meta && decoded.get(String(t.sessionId)).meta.title)\n if (!worth) return\n await mutateTrash((store) => {\n for (const item of store.items) {\n if (item.title) continue\n const pack = decoded.get(String(item.sessionId))\n const t = pack && pack.meta && pack.meta.title\n if (t) item.title = String(t)\n }\n })\n } catch (e) { /* \u8865\u5199\u5931\u8D25\u65E0\u5BB3\uFF1A\u7D22\u5F15\u53EA\u662F\u52A0\u901F\u5668 */ }\n }\n\n async function runWarm() {\n if (warmRunning) return\n warmRunning = true\n try {\n while (warmQueue.size) {\n const batch = [...warmQueue.entries()].slice(0, WARM_CHUNK)\n for (const [id] of batch) warmQueue.delete(id)\n try {\n const ids = batch.map(([id]) => id)\n const resultById = await projectTitlesStatus(ids)\n const decoded = new Map()\n const statsById = new Map()\n for (const [id, desc] of batch) {\n const r = resultById.get(id)\n if (!r || !r.resolved) {\n // \u6295\u5F71\u5931\u8D25\uFF1A\u7EDD\u4E0D\u5199\u7F13\u5B58/\u6301\u4E45\u7D22\u5F15\uFF08\u5426\u5219\u5931\u8D25\u88AB\u56FA\u5316\u4E3A\u6C38\u4E45\u5360\u4F4D\uFF09\u3002\n warmMarkFailure(id, desc.stat, desc.header)\n continue\n }\n warmFail.delete(id)\n const meta = metaFromSnapshot(r.snapshot || null)\n // cwd/createdAt \u6C38\u8FDC\u4EE5\u6700\u65B0 list header \u4E3A\u6743\u5A01\uFF08\u6295\u5F71\u7684 session \u5934\u53EF\u80FD\n // \u9648\u65E7\uFF1B\u79FB\u52A8\u4F1A\u8BDD\u540E\u5C24\u5176\u5982\u6B64\uFF09\uFF0C\u6295\u5F71\u53EA\u8D1F\u8D23\u6807\u9898\u3002\n if (desc.header) {\n if (typeof desc.header.cwd === 'string') meta.cwd = desc.header.cwd\n if (desc.header.createdAt != null) meta.createdAt = desc.header.createdAt\n }\n metaCache.set(id, desc.stat, meta)\n statsById.set(id, desc.stat)\n decoded.set(id, { meta, resolved: true })\n }\n await persistDecoded(decoded, statsById)\n // #7\uFF1A\u56DE\u6536\u7AD9\u6761\u76EE\u5220\u9664\u65F6\u53EF\u80FD\u6CA1\u6709\u6807\u9898\uFF08\u8F6F\u5220\u9664\u53EA\u8BB0\u5F55\uFF09\uFF1B\u9884\u70ED\u89E3\u51FA\u6765\u540E\u8865\u5199\u3002\n await backfillTrashTitles(decoded)\n } catch (e) { /* \u5355\u6279\u5931\u8D25\u4E0D\u5F71\u54CD\u540E\u7EED\u6279\u6B21\uFF1A\u7D22\u5F15/\u7F13\u5B58\u53EA\u662F\u52A0\u901F\u5668 */ }\n // \u6279\u95F4\u8BA9\u6B65\uFF1A\u4FDD\u8BC1\u5BBF\u4E3B\u4E8B\u4EF6\u5FAA\u73AF\uFF08RPC/\u5FC3\u8DF3/\u5176\u4ED6\u63D2\u4EF6\uFF09\u59CB\u7EC8\u53EF\u8C03\u5EA6\u3002\n await new Promise((resolve) => setImmediate(resolve))\n }\n } finally {\n warmRunning = false\n // \u9884\u70ED\u671F\u95F4\u53C8\u6709\u65B0\u8BF7\u6C42\u5165\u961F \u2192 \u518D\u6392\u4E00\u8F6E\u3002\n if (warmQueue.size) scheduleWarm()\n scheduleWarmRetry()\n }\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\u3002revision \u8FDB\u5185\u5B58\u7F13\u5B58\u6307\u7EB9\uFF1B\n // sizeBytes \u4F9B persistFingerprintOf \u6D3E\u751F\u8DE8\u91CD\u542F\u7684 sz \u6301\u4E45\u6307\u7EB9\uFF08issue #8\uFF09\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, Number.isFinite(entry.sizeBytes)\n ? { revision: entry.revision, sizeBytes: Number(entry.sizeBytes) }\n : { 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 // \u6807\u7B7E\uFF083.7.0\uFF0Cschema v4\uFF09\uFF1A\u4E0E\u661F\u6807\u540C\u578B\u3001\u540C\u72B6\u6001\u76EE\u5F55\uFF08tags.json\uFF09\u3002\u7EAF\u7528\u6237\u5143\u6570\u636E\uFF0C\n // rename/merge/delete \u53EA\u91CD\u5199\u6807\u7B7E\u6587\u6863\uFF0C\u6C38\u4E0D\u89E6\u78B0\u4F1A\u8BDD\u672C\u4F53\uFF08\u65B9\u6848 \u00A71.3 \u7EA2\u7EBF\uFF09\u3002\n const tags = createTagIndex()\n // \u4FDD\u5B58\u7684\u7B5B\u9009\uFF08schema v1\uFF0Csaved-filters.json\uFF09\uFF1Afilters \u4E3A\u4E0D\u900F\u660E JSON\uFF0Chost\n // \u53EA\u9650\u6761\u6570/\u540D\u79F0/\u5E8F\u5217\u5316\u4F53\u79EF\uFF0C\u7EDD\u4E0D\u89E3\u6790\u5176\u5185\u5BB9\u3002\n const savedFilters = createSavedFilters()\n // \u5F85\u79FB\u52A8\u961F\u5217\uFF1A\u4F1A\u8BDD\u88AB\u5360\u7528\uFF08DSH \u6253\u5F00\u4E2D\uFF09\u65F6\u767B\u8BB0\uFF0C\u7B49\u5B83\u91CA\u653E\u540E\u81EA\u52A8\u5B8C\u6210\u79FB\u52A8\u3002\n // \u89C1 src/pending-moves.js \u7684\u6A21\u5757\u6CE8\u91CA\uFF080.1.5 \u5355\u5199\u8005\u9501\u6CA1\u6709\u516C\u5171\u91CA\u653E API\uFF09\u3002\n const pendingMoves = createPendingMoveStore()\n // T2\uFF1A\u6392\u961F\u79FB\u52A8\u7684\u540E\u53F0\u7EC8\u5C40\uFF08\u5B8C\u6210/\u653E\u5F03\uFF09\u843D\u6210\u6301\u4E45\u901A\u77E5\uFF0Csidebar-state \u5E26\u51FA\u3001\n // client \u5F39\u51FA\u540E ack \u6E05\u9664\u3002\u72EC\u7ACB\u4E8E\u961F\u5217\u6587\u4EF6\uFF08\u7EC8\u5C40\u4E0E\u961F\u5217\u9879\u540C\u751F\u6B7B\uFF0C\u6302\u6761\u76EE\u4E0A\u89C2\u5BDF\u4E0D\u5230\uFF09\u3002\n const moveNotices = createMoveNoticeStore()\n // Auto-archive settings live in their own schema-v4 store, off by default.\n const autoArchive = createAutoArchiveStore()\n // \u542F\u52A8\u6E05\u626B\uFF1A\u8FDB\u7A0B\u5728\u300C\u5199\u4E34\u65F6\u6587\u4EF6 \u2192 rename\u300D\u4E4B\u95F4\u88AB\u6740\u4F1A\u7559\u4E0B .<name>-<pid>-<ts>.tmp\n // \u5B64\u513F\uFF08\u5B9E\u6D4B\u4E00\u6B21\u7D2F\u79EF 153 \u4E2A\uFF09\u3002\u8FD9\u91CC\u628A 1 \u5C0F\u65F6\u524D\u7684\u65E7\u4E34\u65F6\u6587\u4EF6\u6536\u6389\uFF0C\u4E0D\u78B0\u6B63\u5728\u5199\u7684\u3002\n sweepStaleStateTemps([STATE_DIR, TRASH_DIR], {}).catch(() => {})\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 // \u6807\u7B7E\u7684\u4F1A\u8BDD\u4FA7\u5F15\u7528\u540C\u6837\u8981 GC\uFF1A\u4F1A\u8BDD\u88AB\u5916\u90E8\u79FB\u9664\uFF08\u4E0D\u5728 list \u57FA\u7EBF\u91CC\uFF09\u65F6\uFF0C\n // assignments \u91CC\u7684\u952E\u4F1A\u53D8\u6210\u6C38\u8FDC\u5217\u4E0D\u51FA\u6765\u7684\u5E7D\u7075\u3002\u4E0E gcStars \u540C\u6302\u70B9\u3001\u540C\u4FE1\u4EFB\u6761\u4EF6\u3002\n async function gcTags(validIds) {\n try {\n const store = await tags.read()\n const valid = new Set(validIds.map(String))\n const gone = Object.keys(store.assignments).filter((id) => !valid.has(id))\n if (gone.length) await tags.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 // v3.6.2 #7\uFF1A\u5220\u9664\u8DEF\u5F84**\u7EDD\u4E0D**\u505A\u6807\u9898\u6295\u5F71/\u5206\u5757\u89E3\u7801\u2014\u2014issue #8 \u7684\u6559\u8BAD\uFF1A\n // \u5927\u65E5\u5FD7\u4E0A\u5355\u6761\u515C\u5E95\u6295\u5F71\u4E5F\u662F\u6574\u672C\u89E3\u538B\uFF0C\u5220\u9664 = \u79D2\u7EA7\u5361\u5BBF\u4E3B\u3002\u53EA\u6D88\u8D39\u73B0\u6210\u7F13\u5B58\uFF1A\n // metaCache\uFF08\u7528 list \u5FEB\u7167\u7B97\u6307\u7EB9\uFF09\u2192 \u6301\u4E45\u7D22\u5F15 \u2192 \u4FA7\u680F\u6743\u5A01\u7F13\u5B58\u3002\u90FD\u6CA1\u6709\u5C31\u5B58\n // null\uFF08\u8BDA\u5B9E\u5360\u4F4D\uFF0C\u4E0D\u518D\u628A cwd/\u88F8 id \u5192\u5145\u6807\u9898\u6C38\u4E45\u5199\u8FDB\u56DE\u6536\u7AD9\uFF09\uFF0C\n // \u540E\u53F0\u9884\u70ED\u89E3\u51FA\u6807\u9898\u540E\u7531 backfillTrashTitles \u8865\u5199\u3002\n try {\n const delStat = persistenceEntry && typeof persistenceEntry.revision === 'string' && persistenceEntry.revision\n ? { revision: persistenceEntry.revision, sizeBytes: Number.isFinite(persistenceEntry.sizeBytes) ? Number(persistenceEntry.sizeBytes) : undefined }\n : (removedPath ? await stat(removedPath).then((st) => ({ mtimeMs: st.mtimeMs, size: st.size })) : null)\n if (delStat) {\n const m = metaCache.get(sid, delStat) || (await hydrateFromPersist([sid], new Map([[sid, delStat]]))).get(sid)\n if (m && m.title) title = String(m.title)\n }\n } catch (e) { /* best-effort */ }\n if (!title) { const at = authorityTitleCache.get(sid); if (at) title = String(at) }\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 // v3.6.2 #7\uFF1A\u4E0D\u518D\u628A cwd/\u88F8 id \u5192\u5145\u6807\u9898\u6C38\u4E45\u5B9A\u683C\u2014\u2014\u5B58 null\uFF0C\u9884\u70ED\u89E3\u51FA\u540E\n // backfillTrashTitles \u8865\u5199\uFF1B\u6E32\u67D3\u7AEF\uFF08t.title || t.sessionId\uFF09\u81EA\u7136\u964D\u7EA7\u3002\n sessionId: sid, title: title || null, 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 // \u661F\u6807\u6E05\u7406\u5FC5\u987B await\u3002\u539F\u5148\u8FD9\u91CC\u662F\u6D6E\u52A8\u5199\u5165\uFF08`stars.removeIds([sid]).catch(...)`\uFF09\uFF1A\n // \u5220\u9664\u7ED3\u679C\u5148\u8FD4\u56DE\u3001\u661F\u6807\u6587\u4EF6\u968F\u540E\u624D\u843D\u5730\uFF0C\u6B63\u597D\u4F1A\u649E\u4E0A\u8C03\u7528\u65B9\uFF08\u6216\u6D4B\u8BD5 teardown\uFF09\u5DF2\u5F00\u59CB\u7684\n // \u72B6\u6001\u76EE\u5F55\u6E05\u7406 \u2192 `ENOTEMPTY: rmdir .../state`\uFF08\u5168\u91CF\u6D4B\u8BD5\u91CC\u7EA6 1/4 \u6982\u7387\u5076\u53D1\u5931\u8D25\uFF09\u3002\n // \u800C\u4E14\"\u5220\u9664\u6210\u529F\"\u4E0D\u8BE5\u65E9\u4E8E\u72B6\u6001\u843D\u76D8\uFF1A\u8FDB\u7A0B\u6070\u597D\u5728\u6B64\u523B\u9000\u51FA\u5C31\u4F1A\u7559\u4E0B\u6307\u5411\u5DF2\u5220\u4F1A\u8BDD\u7684\u661F\u6807\u3002\n try { await stars.removeIds([sid]) } catch (e) { /* \u661F\u6807\u6E05\u7406\u5931\u8D25\u4E0D\u963B\u585E\u5220\u9664\u7ED3\u679C */ }\n // \u6807\u7B7E assignments \u540C\u7406\uFF08S4 \u6559\u8BAD\u4F4D\uFF09\uFF1A\u6E05\u7406\u5FC5\u987B await\u3001\u4E0D\u5F97\u6D6E\u52A8\u5199\u2014\u2014purgeFromTrash\n // \u662F\u552F\u4E00\u7684\u5F7B\u5E95\u5220\u9664\u6536\u53E3\uFF08trash/purge\u3001trash/purge-many\u3001\u5230\u671F\u6E05\u7406\u90FD\u7ECF\u8FC7\u5B83\uFF09\uFF0C\n // \u5728\u8FD9\u91CC\u843D\u76D8\u5373\u8986\u76D6\u6240\u6709\u8DEF\u5F84\uFF0C\u4E14\"\u5220\u9664\u6210\u529F\"\u4E0D\u65E9\u4E8E\u72B6\u6001\u843D\u76D8\u3002\n try { await tags.removeIds([sid]) } catch (e) { /* \u6807\u7B7E\u6E05\u7406\u5931\u8D25\u4E0D\u963B\u585E\u5220\u9664\u7ED3\u679C */ }\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 const error = new Error('\u4F1A\u8BDD\u6B63\u88AB DSH \u6253\u5F00\uFF0C\u6682\u65F6\u65E0\u6CD5\u79FB\u52A8\uFF1B\u8BF7\u91CD\u542F DSH \u540E\u518D\u8BD5\u3002')\n error.status = 409\n error.code = 'DSM_SESSION_BUSY'\n throw error\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 // \u79FB\u52A8\u8FC7\u7A0B\u7684\u975E\u81F4\u547D\u63D0\u793A\uFF08\u5982\u6E90\u76EE\u5F55\u4ECD\u6709\u65E7\u4EE3\u65E5\u5FD7\u672A\u80FD\u6E05\u7406\uFF09\uFF0C\u968F\u6210\u529F\u7ED3\u679C\u4E00\u5E76\n // \u56DE\u62A5\u7ED9\u5BA2\u6237\u7AEF\u5C55\u793A\u3002\n const moveNotes = []\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 const keptInSource = await cleanupMovedSourceDir(dirname(oldPath))\n if (keptInSource.length > 0) moveNotes.push(`\u6E90\u76EE\u5F55\u672A\u80FD\u6E05\u7406\u5E72\u51C0\uFF08\u6B8B\u7559 ${keptInSource.join('\u3001')}\uFF09\uFF0C\u82E5\u540E\u7EED\u79FB\u52A8\u62A5\u201Cduplicate\u201D\u8BF7\u624B\u52A8\u6E05\u7A7A\u8BE5\u76EE\u5F55\u3002`)\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 // \u79FB\u52A8\u6210\u529F\u540E\u7684\u6E90\u76EE\u5F55\u6536\u5C3E\uFF08legacy \u8DEF\u5F84\uFF09\uFF1A**\u6574\u4F53\u79FB\u9664**\u3002\u76EE\u6807\u4FA7\u5DF2\u5199\u5165\u6821\u9A8C\u901A\u8FC7\u7684\n // \u6743\u5A01\u65E5\u5FD7\uFF0C\u6E90\u76EE\u5F55\u53EA\u8981\u8FD8\u7559\u7740\u4EFB\u4F55\u4E00\u4EE3\u65E5\u5FD7\uFF08legacy \u65E7\u4EE3 session.jsonl.zstd \u6216\n // session.vN.jsonl.zstd\uFF09\uFF0C\u5C31\u4F1A\u8BA9\u540C id \u51FA\u73B0\u5728\u4E24\u4E2A\u9879\u76EE\u76EE\u5F55\uFF0C\u540E\u7AEF list/create\n // \u7ACB\u523B\u62A5 duplicate\u3002\u8FD4\u56DE\u672A\u80FD\u6E05\u7406\u65F6\u7684\u6B8B\u7559\u6587\u4EF6\u540D\uFF08\u4F9B\u5982\u5B9E\u56DE\u62A5\uFF09\u3002\n const cleanupMovedSourceDir = async (dir) => {\n let entries = null\n try { entries = await readdir(dir) } catch (e) { return [] }\n try { await rm(dir, { recursive: true, force: true }) } catch (e) { return entries }\n return []\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 const movedHandle = await moveSessionToCwd({ sp, sid, header: meta, canonical, events, inheritedEventCount: r.inheritedEventCount })\n if (movedHandle && Array.isArray(movedHandle.reclaimedSiblings) && movedHandle.reclaimedSiblings.length > 0) {\n moveNotes.push(`\u5DF2\u987A\u5E26\u56DE\u6536 ${movedHandle.reclaimedSiblings.length} \u5904\u88AB\u53D6\u4EE3\u7684\u65E7\u4EE3\u65E5\u5FD7\u526F\u672C\uFF08\u5386\u53F2\u79FB\u52A8\u6B8B\u7559\uFF09\uFF0C\u907F\u514D\u540C\u4E00\u4F1A\u8BDD\u5728\u591A\u76EE\u5F55\u91CD\u590D\u3002`)\n }\n if (movedHandle && movedHandle.sourceCleanup && movedHandle.sourceCleanup.cleaned === false) {\n moveNotes.push(`\u6E90\u76EE\u5F55\u672A\u80FD\u6E05\u7406\u5E72\u51C0\uFF08\u6B8B\u7559 ${movedHandle.sourceCleanup.leftover.join('\u3001')}\uFF09\uFF0C\u82E5\u540E\u7EED\u79FB\u52A8\u62A5\u201Cduplicate\u201D\u8BF7\u624B\u52A8\u6E05\u7A7A\u8BE5\u76EE\u5F55\u3002`)\n }\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 if (oldPath) {\n const keptInSource = await cleanupMovedSourceDir(dirname(oldPath))\n if (keptInSource.length > 0) moveNotes.push(`\u6E90\u76EE\u5F55\u672A\u80FD\u6E05\u7406\u5E72\u51C0\uFF08\u6B8B\u7559 ${keptInSource.join('\u3001')}\uFF09\uFF0C\u82E5\u540E\u7EED\u79FB\u52A8\u62A5\u201Cduplicate\u201D\u8BF7\u624B\u52A8\u6E05\u7A7A\u8BE5\u76EE\u5F55\u3002`)\n }\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 ...(moveNotes.length > 0 ? { notes: moveNotes } : {}),\n }\n }\n\n // ---- \u5F85\u79FB\u52A8\u961F\u5217\uFF08\u6D3B\u8DC3 / \u88AB\u5360\u7528\u7684\u4F1A\u8BDD\uFF09-----------------------------------\n // 0.1.5 \u7684\u5355\u5199\u8005\u9501\u7531\u6301\u6709\u5199\u53E5\u67C4\u7684\u8FDB\u7A0B\u638C\u63A7\uFF0C\u63D2\u4EF6\u65E2\u62FF\u4E0D\u5230\u53E5\u67C4\u4E5F\u6CA1\u6709\u91CA\u653E\u5B83\u7684\u516C\u5171\n // API\uFF1B\u5728\u5360\u7528\u671F\u786C\u642C\u76EE\u5F55\u4F1A\u8BA9\u5728\u5199\u8005\u7EE7\u7EED\u5199\u65E7 inode \u5E76\u5728\u65E7\u8DEF\u5F84\u91CD\u5EFA\u7A7A\u58F3\u3002\u56E0\u6B64\u5360\u7528\u65F6\n // \u53EA\u767B\u8BB0\u6392\u961F\uFF0C\u7B49\u5BBF\u4E3B\u91CA\u653E\uFF08session/disposed\uFF09\u6216\u4E0B\u6B21\u63D2\u4EF6\n // \u542F\u52A8\u65F6\uFF08\u4F1A\u8BDD\u5C1A\u672A\u88AB\u6253\u5F00\uFF09\u81EA\u52A8\u5B8C\u6210\u3002\n const QUEUE_NOTE = '\u5DF2\u6392\u961F\uFF1A\u8BE5\u4F1A\u8BDD\u6B63\u88AB DSH \u6253\u5F00\uFF08\u5199\u6240\u6709\u6743\u53EA\u5728 DSH \u9000\u51FA\u65F6\u91CA\u653E\uFF09\u3002\u91CD\u542F DSH \u65F6\u4F1A\u81EA\u52A8\u5B8C\u6210\uFF0C\u8BF7\u5148\u522B\u6253\u5F00\u5B83\u3002'\n\n function isBusyError(e) {\n if (!e) return false\n if (e.code === 'DSM_SESSION_BUSY') return true\n const text = String((e && e.message) || e)\n return /\u6B63\u88AB DSH \u6253\u5F00|already owned/i.test(text)\n }\n\n // \u79FB\u52A8\u5165\u53E3\uFF1A\u5360\u7528 \u2192 \u6392\u961F\uFF1B\u5176\u5B83\u9519\u8BEF\u7167\u65E7\u629B\u51FA\u3002\u8FD4\u56DE\u6210\u529F\u7ED3\u679C\u6216\u6392\u961F\u7ED3\u679C\u3002\n async function moveOrQueue(sid, targetPath) {\n try {\n return await moveOne(sid, targetPath)\n } catch (e) {\n if (!isBusyError(e)) throw e\n await pendingMoves.queue(sid, targetPath)\n return { ok: true, moved: false, queued: true, notes: [QUEUE_NOTE] }\n }\n }\n\n // \u542F\u52A8\u540E\u7684\u300C\u5B66\u6B65\u671F\u300D\uFF1A\u8FD9\u6BB5\u65F6\u95F4\u5185 moveOne \u7684\u975E\u5360\u7528\u7C7B\u5931\u8D25\u53EA\u5F53\u73AF\u5883\u672A\u5C31\u7EEA\uFF0C\u4E0D\u8BA1\u5165\n // \u300C\u591A\u6B21\u5931\u8D25\u5373\u653E\u5F03\u300D\u7684\u8BA1\u6570\uFF08\u5426\u5219 boot \u7ADE\u6001\u4F1A\u628A\u7528\u6237\u7684\u6392\u961F\u9879\u767D\u767D\u4E22\u6389\uFF09\u3002\n const BOOT_WARMUP_MS = 30000\n const bootedAt = Date.now()\n\n let queueRunning = false\n async function runPendingMoves(reason) {\n if (queueRunning) return { ran: false, moved: 0, kept: 0 }\n queueRunning = true\n let moved = 0\n const notes = []\n try {\n const items = await pendingMoves.list()\n for (const item of items) {\n try {\n await moveOne(item.sessionId, item.targetPath)\n await pendingMoves.remove([item.sessionId])\n metaCache.invalidate(item.sessionId)\n moved++\n notes.push(`\u6392\u961F\u4E2D\u7684\u79FB\u52A8\u5DF2\u5B8C\u6210\uFF1A${String(item.sessionId).slice(0, 18)}\u2026`)\n // T2\uFF1A\u901A\u77E5\u843D\u76D8\u5931\u8D25\u4E0D\u541E\u6389\u79FB\u52A8\u7ED3\u679C\u672C\u8EAB\uFF08\u961F\u5217\u9879\u5DF2\u5220\uFF0C\u56DE\u6EDA\u4EE3\u4EF7\u4E0D\u503C\u2014\u2014\n // \u4FDD\u7559 console.warn \u4F5C\u6700\u540E\u515C\u5E95\uFF0C\u8FD9\u662F\u523B\u610F\u63A5\u53D7\u7684\u9759\u9ED8\u7F3A\u53E3\uFF09\u3002\n try { await moveNotices.append({ kind: 'moved', sessionId: item.sessionId, targetPath: item.targetPath, at: Date.now() }) } catch (e) { /* best-effort */ }\n } catch (e) {\n if (isBusyError(e)) continue // \u4ECD\u88AB\u5360\u7528\uFF1A\u7559\u5728\u961F\u5217\u91CC\uFF0C\u7B49\u4E0B\u4E00\u6B21\u89E6\u53D1\n if (Date.now() - bootedAt < BOOT_WARMUP_MS) continue // boot \u671F\u672A\u5C31\u7EEA\uFF1A\u4E0D\u8BB0\u5931\u8D25\n const bumped = await pendingMoves.bumpAttempts(item.sessionId)\n if (bumped && bumped.dropped) {\n notes.push(`\u6392\u961F\u4E2D\u7684\u79FB\u52A8\u591A\u6B21\u5931\u8D25\u5DF2\u653E\u5F03\uFF1A${String(item.sessionId).slice(0, 18)}\u2026\uFF08${String((e && e.message) || e)}\uFF09`)\n try { await moveNotices.append({ kind: 'abandoned', sessionId: item.sessionId, targetPath: item.targetPath, at: Date.now(), attempts: bumped.attempts, reason: String((e && e.message) || e).split('\\n')[0] }) } catch (err) { /* best-effort */ }\n }\n }\n }\n if (moved > 0) { try { await reindexRegistry() } catch (e) { /* best-effort */ } }\n } finally {\n queueRunning = false\n }\n if (notes.length > 0) {\n try { for (const n of notes) console.warn('[dsh-sessions-manager] ' + n) } catch (e) { /* ignore */ }\n }\n void reason\n return { ran: true, moved, kept: (await pendingMoves.list()).length }\n }\n\n // \u6392\u961F\u9879\u7684\u8865\u8DD1\u65F6\u673A\u3002**\u5173\u952E\u524D\u63D0**\uFF1A0.1.5 \u7684\u5355\u5199\u8005\u6240\u6709\u6743\u4E00\u7ECF open \u5C31\u6301\u6709\u5230**\u8FDB\u7A0B\u9000\u51FA**\n // \u4E3A\u6B62\u2014\u2014\u5B98\u65B9\u6CA1\u6709\u4EFB\u4F55\u300C\u5173\u95ED\u4F1A\u8BDD / \u91CA\u653E\u6240\u6709\u6743\u300D\u7684\u516C\u5F00\u5165\u53E3\uFF08`dsh-commands` \u53EA\u6709\n // compact/feedback/goal\uFF1B\u5BBF\u4E3B\u65E0 unloadSession/closeSession/evict\uFF09\uFF0C\u800C\u6D4F\u89C8\u5668\u4E00\u8FDE\u4E0A\u5C31\u4F1A\n // \u81EA\u52A8\u6253\u5F00/\u65B0\u5EFA\u4F1A\u8BDD\uFF0C\u4E00\u65E6\u88AB\u6253\u5F00\u5C31\u518D\u4E5F\u642C\u4E0D\u52A8\u3002\u6240\u4EE5\u552F\u4E00\u53EF\u9760\u7A97\u53E3\u662F**\u5BBF\u4E3B\u521A\u8D77\u6765\u3001\u6D4F\u89C8\u5668\n // \u8FD8\u6CA1\u8FDE\u4E0A**\u7684\u90A3\u4E00\u4E24\u79D2 \u21D2 \u542F\u52A8\u540E\u7ACB\u523B\u8BD5\uFF0C\u5E76\u5728\u524D 30s \u5185\u5BC6\u96C6\u91CD\u8BD5\uFF1B\u4E4B\u540E\u6BCF 120s \u515C\u5E95\uFF1B\n // \u4F1A\u8BDD\u771F\u88AB\u91CA\u653E\uFF08session/disposed\uFF09\u65F6 500ms \u540E\u518D\u8BD5\u4E00\u6B21\u3002\n const queueEffect = typeof ctx.effect === 'function' ? ctx.effect.bind(ctx) : ((fn) => { fn() })\n if (typeof ctx.on === 'function') {\n queueEffect(() => ctx.on('session/disposed', (session) => {\n const id = session && session.id != null ? String(session.id) : null\n if (!id) return\n pendingMoves.has(id).then((queued) => {\n if (!queued) return\n const t = setTimeout(() => { runPendingMoves('session-disposed').catch(() => {}) }, 500)\n if (t && typeof t.unref === 'function') t.unref()\n }).catch(() => {})\n }))\n }\n queueEffect(() => {\n // \u6BCF\u4E2A\u542F\u52A8\u8865\u8DD1\u5B9A\u65F6\u5668\u90FD\u8981 unref\uFF1A\u5BBF\u4E3B\u81EA\u5DF1\u4E0D\u4F1A\u95F2\u4E0B\u6765\u65E0\u6240\u8C13\uFF0C\u4F46\u6D4B\u8BD5\u91CC\u672A unref \u7684\n // 30s \u5B9A\u65F6\u5668\u4F1A\u8BA9 node:test \u591A\u7B49 30s \u624D\u9000\u51FA\uFF08\u6574\u5957\u6D4B\u8BD5\u88AB\u65E0\u8C13\u62D6\u957F\uFF0C\u5B9E\u6D4B\u89C1\u62A5\u544A\uFF09\u3002\n const timers = [0, 1000, 3000, 6000, 12000, 30000].map((ms) => {\n const t = setTimeout(() => {\n runPendingMoves(ms === 0 ? 'startup' : `startup+${ms}`).catch(() => {})\n }, ms)\n if (t && typeof t.unref === 'function') t.unref()\n return t\n })\n // \u8F7B\u91CF\u5468\u671F\u91CD\u8BD5\uFF1A\u53EA\u5728\u961F\u5217\u975E\u7A7A\u65F6\u5E72\u6D3B\uFF08\u961F\u5217\u7A7A = \u4E00\u6B21\u672C\u5730 JSON \u8BFB\u53D6\uFF09\u3002\n const tickTimer = setInterval(() => {\n pendingMoves.list().then((items) => { if (items.length > 0) return runPendingMoves('tick') }).catch(() => {})\n }, 120000)\n if (tickTimer && typeof tickTimer.unref === 'function') tickTimer.unref()\n return () => { for (const t of timers) clearTimeout(t); clearInterval(tickTimer) }\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\uFF08v3.6.2 #1 \u4E09\u6001\u7248\uFF09\u3002\u8FD4\u56DE Map<id, { resolved, snapshot|null }>\uFF1A\n // resolved=true \u2014\u2014 fulfilled \u5FEB\u7167\uFF08title \u53EF\u80FD\u4E3A null\uFF1A\u4F1A\u8BDD\u771F\u7684\u6CA1\u6807\u9898\uFF0C\n // \u8FD9\u662F\u4E8B\u5B9E\uFF0C\u53EF\u4EE5\u7F13\u5B58/\u843D\u76D8\uFF09\uFF1B\n // resolved=false \u2014\u2014 rejected / \u6279\u91CF\u5F02\u5E38 / \u7ED3\u679C\u7F3A\u6761 / \u65E0\u6295\u5F71 API\u3002\n // \u8C03\u7528\u65B9\uFF08runWarm\uFF09\u53EA\u7F13\u5B58 resolved \u7684\u6761\u76EE\uFF1B\u5931\u8D25\u7684\u8FDB\u9000\u907F\u91CD\u8BD5\uFF0C\u7EDD\u4E0D\u843D\u76D8\u2014\u2014\n // \u5426\u5219\u300C\u4E00\u6B21\u5931\u8D25\u300D\u88AB\u56FA\u5316\u4E3A\u8DE8\u91CD\u542F\u7684\u6C38\u4E45\u5360\u4F4D\uFF08v3.6.1 \u5BA1\u8BA1 #1\uFF09\u3002\n const warmHasApi = typeof sq.readTitleSnapshots === 'function' || typeof sq.readTitleSnapshot === 'function'\n\n async function projectTitlesStatus(ids) {\n const out = new Map()\n const markAll = (resolved) => { for (const id of ids) out.set(String(id), { resolved, snapshot: null }) }\n if (!ids || !ids.length) return out\n if (!warmHasApi) { markAll(false); return out }\n if (typeof sq.readTitleSnapshots === 'function') {\n let results = null\n try { results = await sq.readTitleSnapshots(ids) } catch (e) { results = null }\n if (Array.isArray(results)) {\n results.forEach((result, index) => {\n const id = String(ids[index])\n if (result && result.status === 'fulfilled') out.set(id, { resolved: true, snapshot: unwrapSnapshot(result) })\n else if (result && result.status === 'rejected') out.set(id, { resolved: false, snapshot: null })\n else if (result) out.set(id, { resolved: true, snapshot: unwrapSnapshot(result) }) // \u6700\u8001\u5F62\u6001\uFF1A\u76F4\u63A5\u662F\u5FEB\u7167\n else out.set(id, { resolved: false, snapshot: null })\n })\n // \u7ED3\u679C\u6570\u7EC4\u77ED\u4E8E\u8BF7\u6C42\uFF08runtime \u884C\u4E3A\u5F02\u5E38\uFF09\u2192 \u7F3A\u7684\u6761\u76EE\u6309\u5931\u8D25\u5904\u7406\u3002\n for (const id of ids) if (!out.has(String(id))) out.set(String(id), { resolved: false, snapshot: null })\n return out\n }\n // \u6279\u91CF\u5F62\u6001\u4E0D\u8BA4\u8BC6\uFF1A\u9000\u56DE\u9010\u6761\u3002\n }\n if (typeof sq.readTitleSnapshot === 'function') {\n for (const raw of ids) {\n const id = String(raw)\n try {\n const r = await sq.readTitleSnapshot(id)\n if (r && r.status === 'rejected') out.set(id, { resolved: false, snapshot: null })\n else out.set(id, { resolved: true, snapshot: unwrapSnapshot(r) })\n } catch (e) { out.set(id, { resolved: false, snapshot: null }) }\n }\n return out\n }\n markAll(false)\n return out\n }\n\n // \u517C\u5BB9\u65E7\u8C03\u7528\u70B9\uFF08\u6682\u65E0\uFF09\uFF1A\u4FDD\u7559\u540D\u5B57\u4E0D\u5BFC\u51FA\uFF0C\u907F\u514D\u8BEF\u7528\u56DE\u300C\u5931\u8D25\u5373 null\u300D\u7684\u65E7\u8BED\u4E49\u3002\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. \u7F13\u5B58\u672A\u547D\u4E2D\u7684\u4F1A\u8BDD**\u7EDD\u4E0D\u5728\u8BF7\u6C42\u8DEF\u5F84\u4E0A\u540C\u6B65\u6295\u5F71**\uFF08issue #8\uFF1Aruntime \u7684\n // readTitleSnapshots \u6BCF\u6761\u90FD\u662F\u6574\u672C\u89E3\u7801\uFF09\u2014\u2014\u5165\u961F\u540E\u53F0\u9884\u70ED\uFF0C\u5148\u4EE5\u5360\u4F4D\u5143\u6570\u636E\u8FD4\u56DE\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 usage = await collectUsage(entries)\n // \u5148\u6309\u6307\u7EB9\u628A\u300C\u7F13\u5B58\u547D\u4E2D\u300D\u4E0E\u300C\u9700\u8981\u8865\u9F50\u300D\u5206\u5F00\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 { cached, 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 // cwd/createdAt \u56DE\u586B\u65F6\u4EE5\u6700\u65B0 list header \u4E3A\u6743\u5A01\u2014\u2014\u6301\u4E45\u6761\u76EE\u91CC\u7684 cwd \u53EF\u80FD\u56E0\n // \u79FB\u52A8\u4F1A\u8BDD\u800C\u9648\u65E7\uFF08sz \u6307\u7EB9\u5BF9 cwd \u65E0\u611F\u77E5\uFF09\uFF0C\u6807\u9898\u624D\u662F\u7D22\u5F15\u7684\u4EA7\u51FA\u7269\u3002\n const persisted = await hydrateFromPersist(missing, statsById)\n for (const [id, meta] of persisted) {\n const entry = entryById.get(id)\n const header = entry && entry.header ? entry.header : null\n metaCache.set(id, statsById.get(id), {\n title: meta.title,\n cwd: (header && typeof header.cwd === 'string' && header.cwd) ? header.cwd : meta.cwd,\n createdAt: (header && header.createdAt != null) ? header.createdAt : meta.createdAt,\n })\n }\n const stillMissing = missing.filter((id) => !persisted.has(id))\n // issue #8\uFF1A\u7F3A\u5931\u90E8\u5206\u4EA4\u540E\u53F0\u9884\u70ED\uFF08\u5206\u6279 + \u8BA9\u6B65\uFF09\uFF0C\u8BF7\u6C42\u8DEF\u5F84\u96F6\u6295\u5F71\u3001\u96F6\u65E5\u5FD7\u89E3\u7801\u3002\n if (stillMissing.length) enqueueWarm(stillMissing, statsById, entryById)\n const items = []\n for (const id of visibleIds) {\n // metaCache \u4F18\u5148\uFF1Apersisted \u547D\u4E2D\u5DF2\u5E26 header \u6743\u5A01 cwd/createdAt \u56DE\u586B\u8FDB\n // metaCache\uFF08persisted.get \u91CC\u7684 cwd \u53EF\u80FD\u56E0\u79FB\u52A8\u4F1A\u8BDD\u800C\u9648\u65E7\uFF09\u3002\n // \u5B8C\u5168\u672A\u547D\u4E2D\u7684\u4F1A\u8BDD\u4E5F\u4E0D\u80FD\u4E22 cwd/createdAt\u2014\u2014\u5B83\u4EEC\u6765\u81EA list header\uFF0C\u96F6\u6210\u672C\n // \u4E14\u662F\u5DE5\u4F5C\u533A\u5F52\u5C5E/\u521B\u5EFA\u65F6\u95F4\u7684\u6743\u5A01\u6765\u6E90\uFF1B\u53EA\u6709\u6807\u9898\u5141\u8BB8\u5360\u4F4D\u7B49\u540E\u53F0\u9884\u70ED\uFF08issue #8\uFF09\u3002\n let meta = metaCache.get(id, statsById.get(id)) || persisted.get(id) || null\n if (!meta) {\n meta = { title: null, cwd: null, createdAt: null }\n const entry = entryById.get(id)\n const header = entry && entry.header ? entry.header : null\n if (header) {\n if (typeof header.cwd === 'string') meta.cwd = header.cwd\n if (header.createdAt != null) meta.createdAt = header.createdAt\n }\n }\n const it = buildItem(id, meta, usage, !!(opts && opts.usage))\n items.push({ ...it, archived: currentArchived.has(it.sessionId) })\n }\n if (opts && opts.onlyArchived) {\n // /archived-sessions/list \u7684\u8BED\u4E49\uFF1A\u53EA\u8FD4\u56DE\u5F52\u6863\u96C6\u91CC\u4ECD\u7136\u5B58\u5728\u7684\u4F1A\u8BDD\uFF0C\n // \u4E14\u4E0D\u5E26 archived \u5E03\u5C14\u6CE8\u8BB0\uFF08\u65E7\u8DEF\u7531\u7684\u8F93\u51FA\u5F62\u72B6\uFF09\u3002\n const archivedItems = []\n for (const it of items) {\n if (!it.archived) continue\n const { archived: _drop, ...rest } = it\n archivedItems.push(rest)\n }\n return { items: archivedItems, usage }\n }\n // Annotate stars & tags; 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 let tagIdsBySession = new Map()\n try {\n starredSet = new Set((await stars.read()).starredSessionIds)\n // Same one-shot read as stars: tag ids are plain metadata, no decoding.\n // Filter dangling tagIds against the live definitions so a half-deleted\n // tag can never leak into a rendered row.\n const tagStore = await tags.read()\n const knownTagIds = new Set(tagStore.tags.map((t) => t.id))\n for (const [sid, list] of Object.entries(tagStore.assignments)) {\n const kept = list.filter((id) => knownTagIds.has(id))\n if (kept.length) tagIdsBySession.set(sid, kept)\n }\n } catch (e) {}\n for (const it of items) {\n it.starred = starredSet.has(String(it.sessionId))\n it.tags = tagIdsBySession.get(String(it.sessionId)) || []\n }\n if (headersOk) await gcStars(ids)\n if (headersOk) await gcTags(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 entryById = new Map(entries.map((entry) => [entry.id, entry]))\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) {\n const entry = entryById.get(id)\n const header = entry && entry.header ? entry.header : null\n metaCache.set(id, statsById.get(id), {\n title: meta.title,\n cwd: (header && typeof header.cwd === 'string' && header.cwd) ? header.cwd : meta.cwd,\n createdAt: (header && header.createdAt != null) ? header.createdAt : meta.createdAt,\n })\n }\n const rest = missing.filter((id) => !persisted.has(id))\n // issue #8\uFF1A\u7F3A\u5931\u6807\u9898\u4E0D\u5728\u8BF7\u6C42\u8DEF\u5F84\u4E0A\u540C\u6B65\u6295\u5F71\uFF08runtime \u6295\u5F71 = \u9010\u6761\u6574\u672C\u89E3\u7801\uFF09\uFF0C\n // \u4EA4\u540E\u53F0\u9884\u70ED\u8865\u9F50\uFF1B\u4FA7\u680F\u9AD8\u9891\u8F6E\u8BE2\u4F1A\u8BA9\u8865\u9F50\u7ED3\u679C\u81EA\u7136\u6D6E\u73B0\u3002\n if (rest.length) enqueueWarm(rest, statsById, entryById)\n for (const id of ids) {\n const meta = metaCache.get(id, statsById.get(id)) || persisted.get(id) || null\n if (meta && meta.title) authorityTitleCache.set(id, String(meta.title))\n }\n }\n // \u8840\u7F18\u5206\u7C7B\uFF08issue #6 + T1/3.7.0\uFF09\uFF1A\u7ED3\u6784\u5206\u7C7B\uFF08\u5B50\u4EE3\u7406 / fork \u5206\u652F\uFF09\u6765\u81EA list\n // snapshot \u7684 header\uFF0C\u96F6\u89E3\u7801\u3002\u7A7A\u767D\uFF08empty\uFF09\u662F**\u4E09\u6001**\uFF1Anull=\u672A\u77E5\uFF08\u7B49\u540E\u53F0\n // refine \u961F\u5217\u7CBE\u5224\uFF09\u3001true/false=\u5DF2\u5224\u5B9A\uFF08\u6765\u81EA\u8FDB\u7A0B\u5185\u7F13\u5B58\u6216 empty-scan \u6301\u4E45\u5C42\uFF0C\n // sz \u6307\u7EB9\u4E00\u81F4 + 14 \u5929 TTL \u5185\u624D\u53EF\u4FE1\uFF09\u3002\u8BF7\u6C42\u8DEF\u5F84\u96F6\u89E3\u7801\u627F\u8BFA\u7531\u6B64\u5B8C\u6574\u6210\u7ACB\uFF1A\n // \u8D85\u8FC7\u89E3\u7801\u4E0A\u9650\u7684\u65E5\u5FD7\u300C\u5FC5\u6709\u5185\u5BB9\u300D\u6309\u4E8B\u5B9E\u76F4\u63A5\u7ED9 false\uFF1Blegacy \u65E0 sizeBytes\n // \u89C2\u6D4B \u2192 \u6C38\u4E0D\u5019\u9009\u3001\u6052\u672A\u77E5\uFF08\u4E0E\u65E7\u884C\u4E3A\u4E00\u81F4\uFF09\u3002\u666E\u901A\u4F1A\u8BDD\u53EA\u5728\u771F\u5224\u7A7A\u65F6\u5EFA\u6761\u76EE\uFF0C\n // \u300C\u8BEF\u9690\u85CF\u300D\u5728\u7ED3\u6784\u4E0A\u4E0D\u53EF\u80FD\u6765\u81EA\u4F53\u79EF\u6CD5\uFF08\u8BE5\u8DEF\u5F84\u5DF2\u6574\u4F53\u9000\u5F79\uFF09\u3002\n const lineage = {}\n const refineWanted = []\n let emptyStore = null\n try { emptyStore = await emptyIndex.entries() } catch (e) { emptyStore = null }\n const nowTs = Date.now()\n for (const entry of entries) {\n const id = String(entry.id)\n const size = entry && Number.isFinite(entry.sizeBytes) ? entry.sizeBytes : null\n const candidate = emptyScanCandidate(size)\n let verdict = null\n if (!candidate) {\n if (size !== null) verdict = false // \u8D85\u51FA\u89E3\u7801\u4E0A\u9650 = \u5FC5\u6709\u5185\u5BB9\uFF08\u4E8B\u5B9E\uFF0C\u4E0D\u662F\u731C\u6D4B\uFF09\n } else {\n const mem = emptyScanCache.get(id)\n if (mem && mem.sizeBytes === size) {\n verdict = !!mem.empty\n } else {\n const rec = emptyStore && emptyStore[id]\n if (rec && rec.fingerprint === `sz:${size}` && nowTs - (rec.updatedAt || 0) <= EMPTY_VERDICT_TTL_MS) {\n verdict = rec.empty === 1\n emptyScanCache.set(id, { sizeBytes: size, empty: verdict })\n }\n }\n if (verdict === null && refineCapable() && !refineQueue.has(id)) refineWanted.push({ id, sizeBytes: size })\n }\n const info = classifyLineage(entry.header)\n if (info) lineage[id] = { origin: info.origin, parentSession: info.parentSession, delegationDepth: info.delegationDepth, empty: verdict }\n else if (verdict === true) lineage[id] = { origin: null, parentSession: null, delegationDepth: 0, empty: true }\n }\n enqueueRefine(refineWanted)\n // \u7F13\u5B58\u53EA\u4FDD\u7559\u300C\u672C\u8F6E\u4ECD\u662F\u5019\u9009\u300D\u7684\u4F1A\u8BDD\uFF0C\u9632\u6B62 Map \u968F\u5386\u53F2\u4F1A\u8BDD\u65E0\u9650\u589E\u957F\u3002\n for (const key of emptyScanCache.keys()) {\n const rec = emptyScanCache.get(key)\n if (!rec || !emptyScanCandidate(rec.sizeBytes)) emptyScanCache.delete(key)\n }\n const payload = {\n titles: Object.fromEntries(authorityTitleCache),\n trashedSessionIds: store.items.map((item) => String(item.sessionId)),\n purgedSessionIds: activeTombstones,\n lineage,\n // v3.6.2\uFF1A\u8FD8\u6709\u9884\u70ED/\u9000\u907F\u91CD\u8BD5\u5728\u9014 \u2192 client \u7F29\u77ED\u8F6E\u8BE2\u8282\u62CD\uFF0C\u9884\u70ED\u4E00\u5B8C\u6210\u5C31\u628A\n // \u8865\u9F50\u7684\u6807\u9898\u9001\u56DE\uFF08\u542B\u9762\u677F\u81EA\u52A8\u5237\u65B0\uFF09\u3002\u65E0\u9884\u70ED API \u65F6\u6052 false\uFF0C\u7EDD\u4E0D\u5047\u5FD9\u3002\n warmPending: warmPendingNow(),\n // T1\uFF1A\u7A7A\u767D\u7CBE\u5224\u540E\u53F0\u961F\u5217\u662F\u5426\u8FD8\u6709\u6D3B\u3002\u65E0\u7CBE\u5224\u80FD\u529B\uFF08\u65E7 runtime \u65E0 inspect \u901A\u9053\uFF09\n // \u65F6\u6052 false\u2014\u2014\u6C38\u4E45 busy \u4F1A\u8BA9 client \u75AF\u8F6E\u8BE2\uFF0C\u8FD9\u662F\u552F\u4E00\u73B0\u5B9E\u7684\u5047\u5FD9\u9677\u9631\u3002\n refinePending: refinePendingNow(),\n }\n // T2\uFF1A\u6709\u672A\u786E\u8BA4\u7684\u6392\u961F\u79FB\u52A8\u7EC8\u5C40\u624D\u5E26\u51FA\uFF08\u7A7A\u5219\u7701\u7565\u5B57\u6BB5\u2014\u2014\u4E0E\u300C\u666E\u901A\u4F1A\u8BDD\u4E0D\u4EA7\u751F\u6761\u76EE\u300D\n // \u540C\u98CE\u683C\u7684\u8F7D\u8377\u6700\u5C0F\u5316\uFF1B\u65E7 client \u5BF9\u672A\u77E5\u5B57\u6BB5\u5929\u7136\u5FFD\u7565\uFF09\u3002\n try {\n const noticeRows = await moveNotices.list()\n if (noticeRows.length) payload.moveNotices = noticeRows\n } catch (e) { /* \u901A\u77E5\u901A\u9053\u574F\u4E86\u4E0D\u5F71\u54CD\u4FA7\u680F\u4E3B\u6570\u636E */ }\n return payload\n }\n\n // \u7A7A\u4F1A\u8BDD\u5224\u5B9A\u7F13\u5B58\uFF08\u8FDB\u7A0B\u5185\uFF09\uFF1Aid \u2192 { sizeBytes, empty }\u3002\u65E5\u5FD7\u6CA1\u53D8\uFF08sizeBytes\n // \u76F8\u540C\uFF09\u5C31\u4E0D\u91CD\u590D\u89E3\u7801\uFF1BT1 \u4E4B\u540E\u5B83\u53EA\u662F emptyIndex \u6301\u4E45\u5C42\u4E4B\u4E0A\u7684\u70ED\u7F13\u5B58\u3002\n const emptyScanCache = new Map()\n\n // T1\uFF083.7.0\uFF09\uFF1A\u7A7A\u767D\u7CBE\u5224\u5F7B\u5E95\u79FB\u51FA\u8BF7\u6C42\u8DEF\u5F84\u3002v3.6.2 \u7684\u300C\u9884\u7B97+\u9650\u6D41\u300D\u53EA\u662F\u8FC7\u6E21\u2014\u2014\n // \u51B7\u542F\u52A8\uFF08\u7F13\u5B58\u5168\u7A7A\uFF09\u65F6\u9996\u62CD\u4ECD\u8981\u4E3A\u7CBE\u5224\u89E3\u7801\uFF0C\u8FD9\u6B63\u662F\u300C\u2442 \u5206\u652F\u300D\u7B49\u96F6\u89E3\u7801\u8840\u7F18\u88AB\n // \u6321\u5728 return \u4E4B\u524D\u7684\u6700\u540E\u4E00\u5757\u6346\u7ED1\u3002\u73B0\u5728\uFF1Asidebar-state \u5148\u56DE\u4E09\u6001\u6570\u636E\uFF0C\u672A\u5224\u5B9A\n // \u7684\u5019\u9009\u8FDB\u8FD9\u6761\u4E0E runWarm \u540C\u578B\u7684\u540E\u53F0\u961F\u5217\uFF08REFINE_CHUNK=2\u3001\u6279\u95F4 setImmediate\n // \u8BA9\u6B65\u3001\u6210\u529F\u7ED3\u8BBA\u843D\u76D8\u3001\u5931\u8D25\u53EA\u5728\u8FDB\u7A0B\u5185\u6309\u300C\u975E\u7A7A\u300D\u515C\u5E95\u4E14**\u4E0D\u843D\u76D8**\u2014\u2014\u5B81\u53EF\u6F0F\u5224\n // \u4E00\u4E2A\u7A7A\u767D\uFF0C\u4E0D\u80FD\u628A\u6709\u5185\u5BB9\u7684\u4F1A\u8BDD\u9519\u6807\u6210\u7A7A\uFF0C\u4E5F\u4E0D\u80FD\u628A\u5931\u8D25\u56FA\u5316\u6210\u8DE8\u91CD\u542F\u7684\u7ED3\u8BBA\uFF09\u3002\n const REFINE_CHUNK = 2\n const refineQueue = new Map()\n let refineRunning = false\n let refineKickTimer = null\n\n function refineCapable() {\n return !!persistence && typeof persistence.inspectSession === 'function'\n }\n\n function refinePendingNow() {\n return !!(refineRunning || refineQueue.size)\n }\n\n function scheduleRefine() {\n if (refineKickTimer || refineRunning || !refineQueue.size) return\n refineKickTimer = setTimeout(() => { refineKickTimer = null; runRefine() }, 25)\n if (typeof refineKickTimer.unref === 'function') refineKickTimer.unref()\n }\n\n function enqueueRefine(items) {\n if (!items || !items.length || !refineCapable()) return\n for (const { id, sizeBytes } of items) {\n if (emptyScanCache.has(id) && emptyScanCache.get(id).sizeBytes === sizeBytes) continue\n refineQueue.set(id, { sizeBytes })\n }\n scheduleRefine()\n }\n\n async function runRefine() {\n if (refineRunning) return\n refineRunning = true\n try {\n while (refineQueue.size) {\n const batch = [...refineQueue.entries()].slice(0, REFINE_CHUNK)\n for (const [id] of batch) refineQueue.delete(id)\n const persistBatch = {}\n for (const [id, desc] of batch) {\n try {\n const types = []\n await persistence.inspectSession(id, { onEvents: (b) => {\n for (const ev of b || []) if (types.length < 64) types.push(ev && ev.type)\n } })\n const isEmpty = isEmptyEventTypes(types)\n emptyScanCache.set(id, { sizeBytes: desc.sizeBytes, empty: isEmpty })\n persistBatch[id] = { empty: isEmpty ? 1 : 0, fingerprint: `sz:${desc.sizeBytes}`, updatedAt: Date.now() }\n } catch (e) {\n // \u5931\u8D25\u515C\u5E95\uFF1A\u975E\u7A7A\uFF08\u6B62 churn\uFF09\uFF0C\u4F46\u53EA\u8FDB\u5185\u5B58\uFF0C\u4E0D\u843D\u76D8\u3002\n emptyScanCache.set(id, { sizeBytes: desc.sizeBytes, empty: false })\n }\n }\n if (Object.keys(persistBatch).length) {\n try { await emptyIndex.merge(persistBatch) } catch (e) { /* \u6301\u4E45\u5C42\u53EA\u662F\u52A0\u901F\u5668 */ }\n }\n // \u6279\u95F4\u8BA9\u6B65\uFF1A\u4E0E runWarm \u540C\u4E00\u7EAA\u5F8B\uFF0C\u7EDD\u4E0D\u8BA9\u540E\u53F0\u7CBE\u5224\u72EC\u5360\u5BBF\u4E3B\u4E8B\u4EF6\u5FAA\u73AF\u3002\n await new Promise((resolve) => setImmediate(resolve))\n }\n } finally {\n refineRunning = false\n if (refineQueue.size) scheduleRefine()\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\u7F18 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, buildStamp: BUILD_STAMP }),\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 // issue #8\uFF1A\u5F52\u6863\u5217\u8868\u4E5F\u590D\u7528\u300C\u7F13\u5B58\u76F4\u8BFB + \u540E\u53F0\u9884\u70ED\u300D\u7684\u7EDF\u4E00\u7BA1\u7EBF\u3002\n // \u65E7\u5B9E\u73B0\u9010\u6761 resolveOne(id)\uFF08\u65E0 header\u3001\u65E0\u6307\u7EB9\uFF09\u2014\u2014\u51B7\u542F\u52A8\u5BF9\u6BCF\u6761\u5F52\u6863\n // \u4F1A\u8BDD\u6574\u672C\u89E3\u7801\uFF0C\u4E14\u8FDE\u8FDB\u7A0B\u5185\u7F13\u5B58\u90FD\u6C38\u8FDC\u547D\u4E2D\u4E0D\u4E86\u3002\n const wanted = new Set(idStrs)\n const detailed = await allSessionItemsDetailed()\n const items = detailed.items.filter((it) => wanted.has(String(it.sessionId)) && it.archived)\n for (const it of items) delete it.archived\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 try { await titleIndex.remove([sid]) } catch (e) { /* \u7D22\u5F15\u6E05\u7406\u5931\u8D25\u4E0D\u963B\u585E\u5220\u9664\u7ED3\u679C */ }\n try { await emptyIndex.remove([sid]) } catch (e) { /* \u540C\u4E0A */ }\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); await titleIndex.remove([sid]).catch(() => {}); await emptyIndex.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 // usage:true\uFF1AupdatedAt(=\u65E5\u5FD7\u6587\u4EF6 mtime) \u968F\u884C\u5E26\u51FA\u2014\u20143.7.0 \u5206\u652F\u805A\u62E2\u7684\n // createdAt \u7F3A\u5931\u56DE\u9000\u952E\uFF08logic.branchTimeKey\uFF09\u3002collectUsage \u672C\u5C31\u5728\n // allSessionItemsDetailed \u5185\u65E0\u6761\u4EF6\u6267\u884C\uFF0C\u6210\u672C\u2248\u7EAF payload \u589E\u52A0\u3002\n json(res, { items: await allSessionItems({ usage: true }), warmPending: warmPendingNow() })\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, code: 'DSM_STAR_SESSION_INVALID', error: 'missing sessionId' }, 400)\n const starredSessionIds = await stars.setStarred(ids, starred)\n json(res, { ok: true, starredSessionIds })\n } catch (e) {\n // 3.7.0\uFF1A\u8865 code \u5B57\u6BB5\uFF08\u54CD\u5E94\u5F62\u72B6\u5411\u540E\u517C\u5BB9\uFF0C\u53EA\u589E\u5B57\u6BB5\uFF09\u2014\u2014\u65B0\u8DEF\u7531\u5168\u90E8\u5E26 code\uFF0C\n // \u661F\u6807\u4E0D\u5E94\u662F\u4F8B\u5916\u3002\n json(res, { ok: false, code: e && e.code, error: String((e && e.message) || e) }, errorStatus(e))\n }\n },\n }))\n\n // ---- Tags (\u6807\u7B7E, schema v4) \u2014 one route one action, same shape as star/set.\n // Pure user metadata: these routes never create/modify/delete a session.\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/tags/list',\n handler: async (req, res) => {\n try {\n const { tags: tagList, assignments } = await tags.list()\n json(res, { ok: true, tags: tagList, assignments })\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/tags/create',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const tag = await tags.create(body && body.name)\n json(res, { ok: true, tag })\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/tags/rename',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n await tags.rename(body && body.id, body && body.name)\n json(res, { ok: true })\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/tags/merge',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n await tags.merge(body && body.fromId, body && body.toId)\n json(res, { ok: true })\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/tags/delete',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n await tags.removeTag(body && body.id)\n json(res, { ok: true })\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/tags/set',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const sid = body && body.sessionId\n if (!isSafeSessionId(sid)) {\n return json(res, { ok: false, code: 'DSM_TAG_SESSION_INVALID', error: 'missing/invalid sessionId' }, 400)\n }\n const assignments = await tags.setTags(sid, body && body.tagIds)\n json(res, { ok: true, assignments })\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 // ---- Saved filters (\u4FDD\u5B58\u7B5B\u9009, schema v1) --------------------------------\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/filters/list',\n handler: async (req, res) => {\n try {\n json(res, { ok: true, items: await savedFilters.list() })\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/filters/save',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const item = await savedFilters.save(body && body.name, body && body.filters)\n json(res, { ok: true, item })\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/filters/delete',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const ids = body && Array.isArray(body.ids) ? body.ids : null\n if (!ids || ids.length === 0) return json(res, { ok: false, code: 'DSM_FILTER_IDS_INVALID', error: 'missing ids' }, 400)\n const removed = await savedFilters.remove(ids)\n json(res, { ok: true, removed })\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 // 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 // \u5B50\u4EE3\u7406\u8840\u7F18\u6811\uFF08\u7BA1\u7406\u89C6\u56FE\u6570\u636E\u9762\uFF09\uFF1A\u7ED9\u5B9A\u7236\u4F1A\u8BDD\uFF0C\u8FD4\u56DE origin==='subagent'\n // \u7684\u9012\u5F52\u5B50\u6811\u3002DSH \u539F\u751F\u76EE\u5F55\uFF08ui-subagent\uFF09\u53EA\u8BFB\uFF0C\u8FD9\u91CC\u8865\u7BA1\u7406\u80FD\u529B\u7684\u6570\u636E\u6765\u6E90\u3002\n // \u53EA\u8BFB\u5B98\u65B9 header \u8840\u7F18\u5B57\u6BB5\uFF08parentSession/origin/delegationDepth/createdAt\uFF09\uFF0C\n // \u6807\u9898\u8D70 v3.6.2 \u7684\u7EAF\u7F13\u5B58\u8BFB\u53D6\uFF08metaCache/\u6301\u4E45\u7D22\u5F15/\u6743\u5A01\u7F13\u5B58\uFF09\uFF0C\u672A\u547D\u4E2D\u5165\u540E\u53F0\n // \u9884\u70ED\u3001\u672C\u8F6E\u8FD4\u56DE null\uFF1B\u8BF7\u6C42\u8DEF\u5F84\u96F6\u89E3\u7801\u3002\n // live \u6807\u8BB0 = \u4F1A\u8BDD\u5728\u5185\u5B58\u91CC\u6D3B\u7740\uFF08\u6B63\u5728\u8FD0\u884C\u6216\u5DF2\u6253\u5F00\uFF09\uFF1A\u6279\u91CF\u6E05\u7406\u5FC5\u987B\u8DF3\u8FC7\u3002\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/lineage-tree',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const rootId = body && typeof body.sessionId === 'string' ? body.sessionId : ''\n if (!rootId || !isSafeSessionId(rootId)) return json(res, { error: 'missing sessionId' }, 400)\n const headerById = new Map()\n const sizeById = new Map()\n // \u4E0E\u4F1A\u8BDD\u5217\u8868\u540C\u6E90\u7684\u53EF\u89C1\u6027\u5224\u5B9A\uFF1A\u56DE\u6536\u7AD9\u9879\u76EE\u4E00\u5F8B\u4E0D\u53C2\u4E0E\u8840\u7F18\u6811\u3002\n const trashedIds = new Set()\n let purgedIds = []\n const persistedIds = new Set()\n try {\n const store = await readTrashStore()\n for (const item of store.items) trashedIds.add(String(item.sessionId))\n purgedIds = store.purgedSessionIds.map(String)\n } catch (e) { /* best-effort */ }\n const addHeader = (h, sizeBytes) => {\n if (!h || h.id == null) return\n const id = String(h.id)\n // \u56DE\u6536\u7AD9\u91CC\u7684\u4F1A\u8BDD\uFF08\u8F6F\u5220\u9664\u540E\u65E5\u5FD7\u5DF2\u642C\u8D70\uFF09\u4E0D\u80FD\u51FA\u73B0\u5728\u8840\u7F18\u6811\u91CC\uFF0C\u5426\u5219\n // \u4F1A\u51FA\u73B0\u300C\u5220\u6389\u4E86\u4FA7\u680F\u8FD8\u5728\u300D\u3002\u5F7B\u5E95\u5220\u9664\u7684\u5893\u7891\u5728\u4E0B\u9762\u6309\u300C\u5F53\u524D\u5DF2\u4E0D\u5B58\u5728\u300D\n // \u7EDF\u4E00\u5254\u9664\uFF0C\u907F\u514D\u538B\u4F4F\u540E\u6765\u540C id \u91CD\u5EFA\u7684\u4F1A\u8BDD\u3002\n if (headerById.has(id) || trashedIds.has(id)) return\n headerById.set(id, {\n parentSession: h.parentSession != null ? String(h.parentSession) : null,\n subagent: h.origin === 'subagent',\n delegationDepth: Number.isFinite(h.delegationDepth) ? h.delegationDepth : null,\n createdAt: typeof h.createdAt === 'number' ? h.createdAt : null,\n })\n if (Number.isFinite(sizeBytes)) sizeById.set(id, sizeBytes)\n }\n // v3.6.2 #4\uFF1A\u6807\u9898\u53EA\u8BFB\u7F13\u5B58\uFF08metaCache \u2192 \u6301\u4E45\u7D22\u5F15 \u2192 \u6743\u5A01\u7F13\u5B58\uFF09\uFF0C\u672A\u547D\u4E2D\n // \u5165\u540E\u53F0\u9884\u70ED\u3001\u672C\u8F6E\u8FD4\u56DE null\u3002\u65E7\u5B9E\u73B0\u5728\u8BF7\u6C42\u8DEF\u5F84\u76F4\u8C03 projectTitles\u2014\u2014\n // \u5C55\u5F00\u4E00\u4E2A N \u5B50\u6811\u7684\u7236\u4F1A\u8BDD = N \u6B21\u6574\u672C\u89E3\u7801\u540C\u6B65\u5728\u8BF7\u6C42\u8DEF\u5F84\u4E0A\uFF08issue #8\n // \u8981\u6D88\u706D\u7684\u5F62\u6001\u5728\u672C\u8DEF\u7531\u7684\u6B8B\u7559\uFF09\u3002\u8FD9\u91CC\u987A\u624B\u8BB0\u4E0B\u6307\u7EB9\u4E0E\u539F\u59CB header\uFF0C\u4F9B\n // \u7F13\u5B58\u8BFB\u53D6\u4E0E enqueueWarm \u4F7F\u7528\u3002\n const lineageStats = new Map()\n const lineageHeaders = new Map()\n try {\n for (const entry of await persistence.listEntries()) {\n addHeader(entry.header, entry.sizeBytes)\n const eid = entry && entry.id != null ? String(entry.id) : null\n if (eid) {\n lineageHeaders.set(eid, { header: (entry && entry.header) || null })\n // \u53EA\u6709 handle \u4E16\u4EE3\uFF08snapshot \u5E26 revision\uFF09\u624D\u5EFA stats\uFF1Blegacy \u7684\u5217\u8868\u5FEB\u7167\n // \u672C\u5C31\u6CA1\u6709\u8FD9\u4E9B\u89C2\u6D4B\uFF0C\u5176\u6807\u9898\u7ECF sidebarAuthority \u7684 authorityTitleCache\n // \u515C\u4F4F\u3002\u523B\u610F\u4E0D\u5728\u8FD9\u91CC\u5408\u6210 sz-only stat\u2014\u2014\u4F1A\u548C\u5217\u8868\u6784\u5EFA\u7684 mtime:size\n // \u6307\u7EB9\u5728\u540C\u4E00\u7D22\u5F15\u91CC\u4E52\u4E53\u8986\u76D6\uFF0C\u5F15\u53D1\u4EA4\u66FF\u91CD\u590D\u89E3\u7801\u3002\n if (entry && typeof entry.revision === 'string' && entry.revision) {\n lineageStats.set(eid, Number.isFinite(entry.sizeBytes)\n ? { revision: entry.revision, sizeBytes: Number(entry.sizeBytes) }\n : { revision: entry.revision })\n }\n }\n if (entry && entry.id != null) persistedIds.add(String(entry.id))\n }\n } catch (e) { /* best-effort */ }\n const liveIds = new Set()\n const live = ctx.get('sessions')\n try {\n if (live && typeof live.list === 'function') {\n live.list().forEach((s) => { liveIds.add(String(s.id)); addHeader(s.header, undefined) })\n }\n } catch (e) { /* best-effort */ }\n // \u5893\u7891\u53EA\u5BF9\u300C\u6301\u4E45\u5C42\u91CC\u786E\u5B9E\u6CA1\u4E86\u300D\u7684 id \u751F\u6548\uFF1A\u540C id \u4F1A\u8BDD\u540E\u6765\u91CD\u65B0\u51FA\u73B0\u65F6\n // \u5FC5\u987B\u8BA9\u4F4D\uFF0C\u4E0D\u80FD\u6C38\u4E45\u538B\u4F4F\u65B0\u4F1A\u8BDD\uFF08\u4E0E\u4F1A\u8BDD\u5217\u8868\u540C\u4E00\u5957\u89C4\u5219\uFF09\u3002\n for (const id of purgedIds) {\n if (!persistedIds.has(id)) headerById.delete(id)\n }\n // \u5B50\u4EE3\u7406\u7D22\u5F15\uFF1AparentSession \u2192 \u76F4\u63A5\u5B50\u4EE3\u7406 id \u5217\u8868\uFF08\u53EA\u6536 origin==='subagent'\uFF09\u3002\n const kidsOf = new Map()\n for (const [id, h] of headerById) {\n if (!h.subagent || !h.parentSession) continue\n if (!kidsOf.has(h.parentSession)) kidsOf.set(h.parentSession, [])\n kidsOf.get(h.parentSession).push(id)\n }\n // \u9012\u5F52\u5C55\u5F00\uFF1Avisited \u9632\u73AF\uFF0C\u8282\u70B9\u603B\u6570\u5C01\u9876\u9632\u75C5\u6001\u6570\u636E\u3002\n const MAX_NODES = 500\n let nodeCount = 0\n const build = (id, depth, visited) => {\n nodeCount++\n const h = headerById.get(id) || {}\n const childVisited = new Set(visited)\n childVisited.add(id)\n const kidIds = nodeCount >= MAX_NODES ? [] : (kidsOf.get(id) || []).filter((k) => !childVisited.has(k))\n return {\n sessionId: id,\n parentSession: h.parentSession || null,\n delegationDepth: h.delegationDepth,\n depth,\n createdAt: h.createdAt || null,\n sizeBytes: sizeById.has(id) ? sizeById.get(id) : null,\n live: liveIds.has(id),\n title: null,\n children: kidIds.map((k) => build(k, depth + 1, childVisited)),\n }\n }\n const nodes = (kidsOf.get(rootId) || []).map((k) => build(k, 1, new Set([rootId])))\n const allIds = [rootId]\n const walk = (n) => { allIds.push(n.sessionId); n.children.forEach(walk) }\n nodes.forEach(walk)\n // v3.6.2 #4\uFF1A\u7F13\u5B58\u8BFB\u53D6 + \u9884\u70ED\u5165\u961F\uFF0C\u8BF7\u6C42\u8DEF\u5F84\u96F6\u89E3\u7801\u3002#12\uFF1A\u6807\u9898\u6309\n // MAX_TITLE \u622A\u65AD\uFF0C\u4E0E\u5217\u8868\u8F93\u51FA\u53E3\u5F84\u4E00\u81F4\u3002\n const lineageIds = allIds.map(String)\n const { cached: lineageCached, missing: lineageMissing } = metaCache.partition(lineageIds, lineageStats)\n const lineagePersisted = await hydrateFromPersist(lineageMissing, lineageStats)\n for (const [id, meta] of lineagePersisted) metaCache.set(id, lineageStats.get(id), meta)\n const lineageRest = lineageMissing.filter((id) => !lineagePersisted.has(id))\n if (lineageRest.length) enqueueWarm(lineageRest, lineageStats, lineageHeaders)\n const truncateTitle = (t) => (t ? (t.length > MAX_TITLE ? t.slice(0, MAX_TITLE) + '\u2026' : t) : null)\n const titleOf = (id) => {\n const key = String(id)\n const m = lineageCached.get(key) || lineagePersisted.get(key)\n return truncateTitle((m && m.title) || authorityTitleCache.get(key) || null)\n }\n const fill = (n) => { n.title = titleOf(n.sessionId); n.children.forEach(fill) }\n nodes.forEach(fill)\n json(res, { parent: { sessionId: rootId, title: titleOf(rootId) }, nodes })\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 moveOrQueue(sid, target)\n if (moved.queued) return json(res, { sessionId: sid, ...moved })\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 // Move many conversations to one target workspace (issue #7). Sequential\n // on purpose: each move rewrites frame0 (file IO), and one bad session\n // must not block the rest. Single reindex at the end covers all moves.\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/move-many',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const ids = Array.isArray(body && body.sessionIds)\n ? [...new Set(body.sessionIds.filter((x) => typeof x === 'string' && x))]\n : []\n const target = body && typeof body.targetPath === 'string' ? body.targetPath : null\n if (!ids.length) return json(res, { ok: false, error: 'missing sessionIds' }, 400)\n if (!target) return json(res, { ok: false, error: 'missing targetPath' }, 400)\n let moved = 0\n const failed = []\n const queued = []\n for (const sid of ids) {\n try {\n const r = await moveOrQueue(sid, target)\n if (r && r.queued) { queued.push(sid); continue }\n // frame0 \u7684 cwd \u88AB\u6539\u5199\uFF1A\u4E0E\u5355\u79FB\u52A8\u540C\u7406\u7531\uFF0C\u4E3B\u52A8\u4E22\u7F13\u5B58\u4E0D\u7B49\u6307\u7EB9\u5931\u6548\u3002\n metaCache.invalidate(sid)\n moved++\n } catch (e) {\n const err = e && e.code ? { sessionId: sid, error: String((e && e.message) || e), code: e.code } : { sessionId: sid, error: String((e && e.message) || e) }\n failed.push(err)\n }\n }\n try { await reindexRegistry() } catch (e) { /* best-effort */ }\n json(res, {\n moved,\n failed,\n ...(queued.length > 0 ? { queued, notes: [`${queued.length} \u4E2A\u4F1A\u8BDD\u5DF2\u6392\u961F\uFF08\u6B63\u88AB DSH \u6253\u5F00\uFF09\uFF0C\u91CD\u542F DSH \u540E\u4F1A\u81EA\u52A8\u5B8C\u6210\uFF1B\u91CD\u542F\u540E\u8BF7\u5148\u522B\u6253\u5F00\u5B83\u4EEC\u3002`] } : {}),\n })\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 // \u5F85\u79FB\u52A8\u961F\u5217\uFF1A\u67E5\u770B / \u53D6\u6D88\uFF08\u4F1A\u8BDD\u88AB\u5360\u7528\u65F6\u6392\u961F\uFF0C\u91CA\u653E\u540E\u81EA\u52A8\u5B8C\u6210\uFF09\u3002\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/pending-moves',\n handler: async (req, res) => {\n try {\n const items = await pendingMoves.list()\n json(res, { items: items.map((i) => ({ sessionId: i.sessionId, targetPath: i.targetPath, queuedAt: i.queuedAt, attempts: i.attempts })) })\n } catch (e) {\n json(res, { error: String((e && e.message) || e) }, 500)\n }\n },\n }))\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/pending-moves/cancel',\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 removed = await pendingMoves.remove(ids)\n json(res, { ok: true, removed })\n } catch (e) {\n json(res, { ok: false, error: String((e && e.message) || e) }, errorStatus(e))\n }\n },\n }))\n\n // T2\uFF1Aack \u5DF2\u5C55\u793A\u7684\u6392\u961F\u79FB\u52A8\u901A\u77E5\uFF08\u5C3D\u529B\u6E05\u7406\uFF1B\u5931\u8D25\u65E0\u5BB3\uFF0Cclient \u7AEF localStorage\n // \u5DF2\u89C1\u96C6\u5408\u8D1F\u8D23\u591A tab \u53BB\u91CD\uFF0C7 \u5929 TTL \u515C\u5E95\uFF09\u3002\n disposers.push(ctx.webServer.register({\n kind: 'exact',\n path: '/archived-sessions/pending-moves/notices/ack',\n handler: async (req, res) => {\n try {\n const body = await readJsonBody(req)\n const ids = body && Array.isArray(body.ids) ? body.ids : null\n if (!ids || !ids.length) return json(res, { ok: false, error: 'missing ids' }, 400)\n const removed = await moveNotices.ack(ids)\n json(res, { ok: true, removed })\n } catch (e) {\n json(res, { ok: false, 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", "// Durable \"session tags\" index (schema v4).\n//\n// Deliberately mirrors the star index in src/star-index.js: version field,\n// per-entry defensive normalize (dirty data is dropped, never repaired by\n// guessing), atomic write (tmp + rename at 0o600) and a single chained\n// mutation queue so two concurrent requests can never clobber each other.\n// Tags are pure user metadata: create/rename/merge/remove rewrite THIS\n// document only and never touch a session (the 3.7.0 red line, plan \u00A71.3).\n// Extracted from the host bundle so it can be unit-tested directly \u2014 pass\n// `dir` to point the index at a temp directory.\nimport { mkdir, rename as fsRename, writeFile } from 'node:fs/promises'\nimport { readFileSync } from 'node:fs'\nimport { randomBytes } from 'node:crypto'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\n\n// v4 is the first tag schema; it starts at 4 so it can never be confused with\n// the recycle bin's v1/v2 or the star index's v3 documents even if a file is\n// copied between them.\nexport const TAG_SCHEMA_VERSION = 4\n\n// Caps (plan \u00A71.3): \u2264200 tag definitions globally, \u226410 tags per session,\n// \u226424 code points per name. Array.from counting means one Chinese character\n// (or one surrogate pair) counts as exactly 1, so the limit is honest for CJK.\nexport const MAX_TAGS = 200\nexport const MAX_TAGS_PER_SESSION = 10\nexport const MAX_TAG_NAME = 24\n\n// Same state directory (and same env override) as the star index: all\n// plugin-owned user marks live together in ~/.dsh/sessions-manager.\nconst DEFAULT_TAG_DIR = join(homedir(), '.dsh', 'sessions-manager')\n\n// Random short ids: 't_' + 8 lowercase alphanumeric chars. Ids are minted\n// once and never reused (rename only rewrites the name), so assignments can\n// reference them safely. A collision (36^-8) is simply re-rolled.\nconst TAG_ID_ALPHABET = 'abcdefghijklmnopqrstuvwxyz0123456789'\n\nfunction randomSuffix() {\n const bytes = randomBytes(8)\n let out = ''\n for (const b of bytes) out += TAG_ID_ALPHABET[b % TAG_ID_ALPHABET.length]\n return out\n}\n\nfunction isSafeSessionId(value) {\n return typeof value === 'string' && value.length > 0 && value.length <= 200 && !/[\\\\/\\0]/.test(value) && value !== '.' && value !== '..'\n}\n\nfunction isSafeTagId(value) {\n return typeof value === 'string' && value.length > 0 && value.length <= 64 && !/[\\\\/\\0]/.test(value)\n}\n\nfunction tagError(message, status, code) {\n const error = new Error(message)\n error.status = status\n if (code) error.code = code\n throw error\n}\n\n// Trim + shape-check a user-supplied tag name. Returns the cleaned name or\n// null; the caller turns null into a 400. Slashes and NUL are rejected in\n// line with this plugin's path-safety discipline for anything persisted.\nexport function normalizeTagName(value) {\n if (typeof value !== 'string') return null\n const name = value.trim()\n if (!name || /[\\\\/\\0]/.test(name)) return null\n if (Array.from(name).length > MAX_TAG_NAME) return null\n return name\n}\n\n// Casefold key used for the global name-uniqueness rule.\nfunction nameKey(name) {\n return name.toLocaleLowerCase()\n}\n\n/**\n * Coerce anything on disk (or nothing at all) into a valid v4 store.\n * Every entry is defended individually: a bad tag entry or a dangling\n * assignment (a tagId no longer defined) is dropped silently.\n */\nexport function normalizeTagStore(raw) {\n const source = raw && typeof raw === 'object' && !Array.isArray(raw) ? raw : null\n const tags = []\n const ids = new Set()\n const names = new Set()\n for (const item of (source && Array.isArray(source.tags) ? source.tags : [])) {\n if (!item || typeof item !== 'object') continue\n // Strings only: coercing a number into an id would let junk into the\n // index and mask a caller bug (same reasoning as normalizeStarStore).\n if (!isSafeTagId(item.id) || ids.has(item.id)) continue\n const name = normalizeTagName(item.name)\n if (name === null) continue\n const key = nameKey(name)\n if (names.has(key)) continue\n ids.add(item.id)\n names.add(key)\n const createdAt = Number.isFinite(Number(item.createdAt)) ? Number(item.createdAt) : 0\n tags.push({ id: item.id, name, createdAt })\n if (tags.length >= MAX_TAGS) break\n }\n const assignments = {}\n const rawAssignments = source && source.assignments && typeof source.assignments === 'object' && !Array.isArray(source.assignments)\n ? source.assignments\n : null\n if (rawAssignments) {\n for (const [sid, value] of Object.entries(rawAssignments)) {\n if (!isSafeSessionId(sid) || !Array.isArray(value)) continue\n const kept = []\n const seen = new Set()\n for (const tagId of value) {\n // Unknown ids are dangling (tag deleted meanwhile, or a foreign file\n // was copied in): drop, never keep a ghost the UI could not render.\n if (!ids.has(tagId) || seen.has(tagId)) continue\n seen.add(tagId)\n kept.push(tagId)\n if (kept.length >= MAX_TAGS_PER_SESSION) break\n }\n if (kept.length) assignments[sid] = kept\n }\n }\n return { schemaVersion: TAG_SCHEMA_VERSION, tags, assignments }\n}\n\n/**\n * Open the tag 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 createTagIndex(options = {}) {\n const dir = options.dir || process.env.DSH_SESSIONS_MANAGER_STAR_DIR || DEFAULT_TAG_DIR\n const indexPath = options.indexPath || join(dir, 'tags.json')\n let mutation = Promise.resolve()\n\n async function read() {\n try {\n return normalizeTagStore(JSON.parse(readFileSync(indexPath, 'utf8')))\n } catch {\n return normalizeTagStore(null)\n }\n }\n\n async function write(store) {\n await mkdir(dir, { recursive: true })\n const tmp = join(dir, `.tags-${process.pid}-${Date.now()}.tmp`)\n await writeFile(tmp, JSON.stringify(normalizeTagStore(store), null, 2), { encoding: 'utf8', mode: 0o600 })\n await fsRename(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 (and\n // writes nothing \u2014 the checks throw before `write` is reached).\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 function newTagId(store) {\n for (let i = 0; i < 16; i++) {\n const id = `t_${randomSuffix()}`\n if (!store.tags.some((t) => t.id === id)) return id\n }\n // Astronomically unreachable; honest failure beats a duplicate id.\n return tagError('\u65E0\u6CD5\u751F\u6210\u6807\u7B7E id\uFF08\u968F\u673A\u78B0\u649E\u5F02\u5E38\uFF09', 500, 'DSM_TAG_ID_COLLISION')\n }\n\n /**\n * Define a new tag.\n * @param {string} rawName\n * @returns {Promise<{id: string, name: string, createdAt: number}>}\n * @throws 400 DSM_TAG_NAME_INVALID | 409 DSM_TAG_EXISTS | 409 DSM_TAG_LIMIT\n */\n async function create(rawName) {\n const name = normalizeTagName(rawName)\n if (name === null) tagError(`\u6807\u7B7E\u540D\u65E0\u6548\uFF08\u975E\u7A7A\u3001\u4E0D\u542B\u659C\u6760\u3001\u4E0D\u8D85\u8FC7 ${MAX_TAG_NAME} \u4E2A\u5B57\u7B26\uFF09`, 400, 'DSM_TAG_NAME_INVALID')\n const key = nameKey(name)\n return mutate((store) => {\n if (store.tags.some((t) => nameKey(t.name) === key)) tagError('\u540C\u540D\u6807\u7B7E\u5DF2\u5B58\u5728', 409, 'DSM_TAG_EXISTS')\n if (store.tags.length >= MAX_TAGS) tagError(`\u6807\u7B7E\u603B\u6570\u5DF2\u8FBE\u4E0A\u9650\uFF08${MAX_TAGS}\uFF09`, 409, 'DSM_TAG_LIMIT')\n const tag = { id: newTagId(store), name, createdAt: Date.now() }\n store.tags.push(tag)\n return tag\n })\n }\n\n /**\n * Rename a tag. Ids never change, so assignments survive a rename untouched.\n * A rename that only differs in case is legal (it's not a \"duplicate\" of\n * another tag); a collision with a DIFFERENT tag is rejected.\n * (Note: this method name is why the atomic rename above is `fsRename`.)\n * @throws 400 | 404 DSM_TAG_NOT_FOUND | 409 DSM_TAG_EXISTS\n */\n async function rename(id, rawName) {\n const name = normalizeTagName(rawName)\n if (name === null) tagError(`\u6807\u7B7E\u540D\u65E0\u6548\uFF08\u975E\u7A7A\u3001\u4E0D\u542B\u659C\u6760\u3001\u4E0D\u8D85\u8FC7 ${MAX_TAG_NAME} \u4E2A\u5B57\u7B26\uFF09`, 400, 'DSM_TAG_NAME_INVALID')\n const key = nameKey(name)\n return mutate((store) => {\n const tag = store.tags.find((t) => t.id === id)\n if (!tag) tagError('\u6807\u7B7E\u4E0D\u5B58\u5728', 404, 'DSM_TAG_NOT_FOUND')\n if (store.tags.some((t) => t.id !== tag.id && nameKey(t.name) === key)) tagError('\u540C\u540D\u6807\u7B7E\u5DF2\u5B58\u5728', 409, 'DSM_TAG_EXISTS')\n tag.name = name\n return tag\n })\n }\n\n /**\n * Fold the source tag into the target tag: every session carrying the\n * source also carries the target (deduped; the per-session cap truncates an\n * overflow rather than failing a half-applied merge \u2014 the UI must never be\n * stuck with a source it cannot remove). The source definition and all of\n * its assignments are then dropped. Sessions themselves are never touched.\n * @throws 400 DSM_TAG_INVALID | 404 DSM_TAG_NOT_FOUND\n */\n async function merge(fromId, toId) {\n if (!isSafeTagId(fromId) || !isSafeTagId(toId) || fromId === toId) {\n tagError('\u5408\u5E76\u7684\u6E90/\u76EE\u6807\u6807\u7B7E\u65E0\u6548\u6216\u76F8\u540C', 400, 'DSM_TAG_INVALID')\n }\n return mutate((store) => {\n if (!store.tags.some((t) => t.id === fromId) || !store.tags.some((t) => t.id === toId)) {\n tagError('\u6807\u7B7E\u4E0D\u5B58\u5728', 404, 'DSM_TAG_NOT_FOUND')\n }\n for (const [sid, list] of Object.entries(store.assignments)) {\n if (!list.includes(fromId)) continue\n const merged = [...new Set(list.filter((x) => x !== fromId).concat(toId))]\n store.assignments[sid] = merged.slice(0, MAX_TAGS_PER_SESSION)\n }\n store.tags = store.tags.filter((t) => t.id !== fromId)\n return { merged: true }\n })\n }\n\n /**\n * Drop a tag definition and every assignment to it. Idempotent: an unknown\n * id is a no-op success (the UI may race itself). NEVER touches a session.\n */\n function removeTag(id) {\n return mutate((store) => {\n if (isSafeTagId(id)) {\n store.tags = store.tags.filter((t) => t.id !== id)\n for (const [sid, list] of Object.entries(store.assignments)) {\n const kept = list.filter((x) => x !== id)\n if (kept.length) store.assignments[sid] = kept\n else delete store.assignments[sid]\n }\n }\n return { removed: true }\n })\n }\n\n /**\n * Replace the full tag set of one session (the UI always sends the complete\n * list; \"assign\" and \"unassign\" are just set-with-one-more / set-minus-one).\n * @param {string} sessionId\n * @param {string[]} tagIds\n * @returns {Promise<object>} the full assignments map after the change.\n * @throws 400 DSM_TAG_SESSION_INVALID | 400 DSM_TAG_IDS_INVALID\n * | 400 DSM_TAG_UNKNOWN | 409 DSM_TAG_LIMIT\n */\n async function setTags(sessionId, tagIds) {\n if (!isSafeSessionId(sessionId)) tagError('\u65E0\u6548\u7684 sessionId', 400, 'DSM_TAG_SESSION_INVALID')\n if (!Array.isArray(tagIds)) tagError('tagIds \u5FC5\u987B\u662F\u6570\u7EC4', 400, 'DSM_TAG_IDS_INVALID')\n const seen = new Set()\n const wanted = []\n for (const v of tagIds) {\n // Strings only (same reasoning as the star index): a number in the list\n // is a caller bug, not data to coerce.\n if (!isSafeTagId(v)) tagError('\u65E0\u6548\u7684\u6807\u7B7E id', 400, 'DSM_TAG_UNKNOWN')\n if (seen.has(v)) continue\n seen.add(v)\n wanted.push(v)\n }\n if (wanted.length > MAX_TAGS_PER_SESSION) tagError(`\u5355\u4E2A\u4F1A\u8BDD\u6700\u591A ${MAX_TAGS_PER_SESSION} \u4E2A\u6807\u7B7E`, 409, 'DSM_TAG_LIMIT')\n return mutate((store) => {\n const known = new Set(store.tags.map((t) => t.id))\n const unknown = wanted.filter((id) => !known.has(id))\n if (unknown.length) tagError(`\u672A\u77E5\u7684\u6807\u7B7E id\uFF1A${unknown.join('\u3001')}`, 400, 'DSM_TAG_UNKNOWN')\n if (wanted.length) store.assignments[sessionId] = [...wanted]\n else delete store.assignments[sessionId]\n return store.assignments\n })\n }\n\n // Drop assignments once their session is gone (purged / deleted), otherwise\n // the index would grow forever with ids that can never be listed again.\n function removeIds(ids) {\n const wanted = (Array.isArray(ids) ? ids : []).filter(isSafeSessionId)\n return mutate((store) => {\n for (const sid of wanted) delete store.assignments[sid]\n return store.assignments\n })\n }\n\n /**\n * @returns {Promise<{tags: Array<{id,name,createdAt}>, assignments: object}>}\n */\n async function list() {\n const store = await read()\n return { tags: store.tags, assignments: store.assignments }\n }\n\n return { read, write, mutate, list, create, rename, merge, removeTag, setTags, removeIds, indexPath, dir }\n}\n", "// Durable \"saved filters\" store (schema v1).\n//\n// Same discipline as src/star-index.js / src/tag-index.js: version field,\n// per-entry defensive normalize, atomic write (tmp + rename at 0o600) and a\n// single chained mutation queue. Filter payloads are OPAQUE JSON: the host\n// never interprets them (the UI round-trips its own chip state); we only\n// bound the serialized size so a corrupt entry can never bloat the state\n// file. Lives in the plugin state directory next to tags.json.\nimport { mkdir, rename, writeFile } from 'node:fs/promises'\nimport { readFileSync } from 'node:fs'\nimport { randomBytes } from 'node:crypto'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\n\n// v1 is the first saved-filters schema. Unlike tags.json (which starts at v4\n// to dodge star's v3) this document lives in its own file and can begin\n// counting from 1.\nexport const FILTER_SCHEMA_VERSION = 1\n\n// Caps: \u226420 saved filters, \u226440 code points per name (Array.from counting),\n// \u22642048 characters of serialized JSON per payload.\nexport const MAX_FILTERS = 20\nexport const MAX_FILTER_NAME = 40\nexport const MAX_FILTER_JSON = 2048\n\n// Same state directory (and same env override) as the star / tag indexes.\nconst DEFAULT_FILTER_DIR = join(homedir(), '.dsh', 'sessions-manager')\n\nconst FILTER_ID_ALPHABET = 'abcdefghijklmnopqrstuvwxyz0123456789'\n\nfunction randomSuffix() {\n const bytes = randomBytes(8)\n let out = ''\n for (const b of bytes) out += FILTER_ID_ALPHABET[b % FILTER_ID_ALPHABET.length]\n return out\n}\n\nfunction isSafeFilterId(value) {\n return typeof value === 'string' && value.length > 0 && value.length <= 64 && !/[\\\\/\\0]/.test(value)\n}\n\nfunction filterError(message, status, code) {\n const error = new Error(message)\n error.status = status\n if (code) error.code = code\n throw error\n}\n\nfunction normalizeFilterName(value) {\n if (typeof value !== 'string') return null\n const name = value.trim()\n if (!name || /[\\\\/\\0]/.test(name)) return null\n if (Array.from(name).length > MAX_FILTER_NAME) return null\n return name\n}\n\nfunction nameKey(name) {\n return name.toLocaleLowerCase()\n}\n\n// Serialize an opaque payload, or null when it cannot be stored (not JSON at\n// all \u2014 e.g. undefined/functions \u2014 or beyond the size cap).\nfunction normalizeFiltersPayload(value) {\n let serialized\n try {\n serialized = JSON.stringify(value)\n } catch {\n return null\n }\n if (typeof serialized !== 'string' || serialized.length > MAX_FILTER_JSON) return null\n try {\n return JSON.parse(serialized)\n } catch {\n return null\n }\n}\n\n/**\n * Coerce anything on disk (or nothing at all) into a valid v1 store.\n * A dirty entry (bad id/name, unserializable or oversize payload, duplicate\n * id / casefold-duplicate name) is dropped whole, never partially repaired.\n */\nexport function normalizeFilterStore(raw) {\n const source = raw && typeof raw === 'object' && !Array.isArray(raw) ? raw : null\n const items = []\n const ids = new Set()\n const names = new Set()\n for (const item of (source && Array.isArray(source.items) ? source.items : [])) {\n if (!item || typeof item !== 'object') continue\n if (!isSafeFilterId(item.id) || ids.has(item.id)) continue\n const name = normalizeFilterName(item.name)\n if (name === null) continue\n const key = nameKey(name)\n if (names.has(key)) continue\n const filters = normalizeFiltersPayload(item.filters)\n if (filters === null) continue\n ids.add(item.id)\n names.add(key)\n const createdAt = Number.isFinite(Number(item.createdAt)) ? Number(item.createdAt) : 0\n items.push({ id: item.id, name, filters, createdAt })\n if (items.length >= MAX_FILTERS) break\n }\n return { schemaVersion: FILTER_SCHEMA_VERSION, items }\n}\n\n/**\n * Open the saved-filters store.\n * @param {object} [options]\n * @param {string} [options.dir] - Directory holding the store (tests inject a temp dir).\n * @param {string} [options.indexPath] - Full store path, overriding `dir`.\n */\nexport function createSavedFilters(options = {}) {\n const dir = options.dir || process.env.DSH_SESSIONS_MANAGER_STAR_DIR || DEFAULT_FILTER_DIR\n const indexPath = options.indexPath || join(dir, 'saved-filters.json')\n let mutation = Promise.resolve()\n\n async function read() {\n try {\n return normalizeFilterStore(JSON.parse(readFileSync(indexPath, 'utf8')))\n } catch {\n return normalizeFilterStore(null)\n }\n }\n\n async function write(store) {\n await mkdir(dir, { recursive: true })\n const tmp = join(dir, `.saved-filters-${process.pid}-${Date.now()}.tmp`)\n await writeFile(tmp, JSON.stringify(normalizeFilterStore(store), null, 2), { encoding: 'utf8', mode: 0o600 })\n await rename(tmp, indexPath)\n }\n\n // Serialize read-modify-write cycles (same chain semantics as the star index).\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 function newFilterId(store) {\n for (let i = 0; i < 16; i++) {\n const id = `f_${randomSuffix()}`\n if (!store.items.some((t) => t.id === id)) return id\n }\n return filterError('\u65E0\u6CD5\u751F\u6210\u7B5B\u9009 id\uFF08\u968F\u673A\u78B0\u649E\u5F02\u5E38\uFF09', 500, 'DSM_FILTER_ID_COLLISION')\n }\n\n /**\n * Save a named filter. `filters` is stored verbatim (opaque to the host).\n * @param {string} rawName\n * @param {*} filters\n * @returns {Promise<{id, name, filters, createdAt}>}\n * @throws 400 DSM_FILTER_NAME_INVALID | 400 DSM_FILTER_INVALID\n * | 400 DSM_FILTER_TOO_LARGE | 409 DSM_FILTER_EXISTS | 409 DSM_FILTER_LIMIT\n */\n async function save(rawName, filters) {\n const name = normalizeFilterName(rawName)\n if (name === null) filterError(`\u7B5B\u9009\u540D\u65E0\u6548\uFF08\u975E\u7A7A\u3001\u4E0D\u542B\u659C\u6760\u3001\u4E0D\u8D85\u8FC7 ${MAX_FILTER_NAME} \u4E2A\u5B57\u7B26\uFF09`, 400, 'DSM_FILTER_NAME_INVALID')\n // Bound the opaque payload before it can ever reach disk, with honest\n // codes for \"not JSON at all\" vs. \"oversize\".\n let serialized\n try {\n serialized = JSON.stringify(filters)\n } catch {\n serialized = undefined\n }\n if (typeof serialized !== 'string') filterError('\u7B5B\u9009\u6761\u4EF6\u5FC5\u987B\u662F\u53EF JSON \u5E8F\u5217\u5316\u7684\u6570\u636E', 400, 'DSM_FILTER_INVALID')\n if (serialized === 'null') filterError('\u7B5B\u9009\u6761\u4EF6\u4E0D\u80FD\u4E3A null', 400, 'DSM_FILTER_INVALID')\n if (serialized.length > MAX_FILTER_JSON) filterError(`\u7B5B\u9009\u6761\u4EF6\u8FC7\u5927\uFF08\u5E8F\u5217\u5316\u540E\u6700\u591A ${MAX_FILTER_JSON} \u5B57\u7B26\uFF09`, 400, 'DSM_FILTER_TOO_LARGE')\n const payload = JSON.parse(serialized)\n const key = nameKey(name)\n return mutate((store) => {\n if (store.items.some((t) => nameKey(t.name) === key)) filterError('\u540C\u540D\u7B5B\u9009\u5DF2\u5B58\u5728', 409, 'DSM_FILTER_EXISTS')\n if (store.items.length >= MAX_FILTERS) filterError(`\u4FDD\u5B58\u7684\u7B5B\u9009\u5DF2\u8FBE\u4E0A\u9650\uFF08${MAX_FILTERS}\uFF09`, 409, 'DSM_FILTER_LIMIT')\n const item = { id: newFilterId(store), name, filters: payload, createdAt: Date.now() }\n store.items.push(item)\n return item\n })\n }\n\n /**\n * Delete saved filters by id (unknown ids are ignored).\n * @param {string[]} ids\n * @returns {Promise<number>} how many items were actually removed.\n */\n function remove(ids) {\n const wanted = new Set((Array.isArray(ids) ? ids : []).filter(isSafeFilterId).map(String))\n return mutate((store) => {\n const before = store.items.length\n store.items = store.items.filter((t) => !wanted.has(t.id))\n return before - store.items.length\n })\n }\n\n /**\n * @returns {Promise<Array<{id, name, filters, createdAt}>>}\n */\n async function list() {\n const store = await read()\n return store.items\n }\n\n return { read, write, mutate, list, save, remove, indexPath, dir }\n}\n", "// Deferred cross-workspace moves (\"\u6392\u961F\u79FB\u52A8\").\n//\n// \u80CC\u666F\uFF1A0.1.5 \u8D77\u4F1A\u8BDD\u65E5\u5FD7\u662F**\u5355\u5199\u8005**\u2014\u2014agent-loop \u5728 resume \u65F6\u4F1A\u8BDD\u65F6\u53D6\u5199\u6240\u6709\u6743\n// \uFF08\u65E5\u5FD7\u65C1\u7684 session.lock \u4E0A\u4E00\u4E2A flock(2)\uFF09\uFF0C\u6301\u6709\u5230 agent \u5378\u8F7D\uFF1B\u63D2\u4EF6\u65E2\u62FF\u4E0D\u5230\u8BE5\n// \u53E5\u67C4\uFF0C\u4E5F\u6CA1\u6709\u4EFB\u4F55\u516C\u5171 API \u80FD\u91CA\u653E\u522B\u4EBA\u7684\u6240\u6709\u6743\uFF08dsh-session \u670D\u52A1\u53EA\u66B4\u9732\n// list/get/prepare/enter/fork/flush\uFF1B`session/disposed` \u53EA\u5728\u6301\u6709\u5B83\u7684 fiber \u88AB\n// dispose \u65F6\u53D1\u51FA\uFF09\u3002\u5728\u5360\u7528\u671F\u786C\u642C\u76EE\u5F55\u4F1A\u8BA9\u5728\u5199\u8005\u7EE7\u7EED\u5F80\u65E7 inode \u5199\u3001\u5E76\u5728\u65E7\u8DEF\u5F84\n// \u91CD\u5EFA\u7A7A\u58F3\uFF082026-09-10 \u5B9E\u6D4B\u8FC7\uFF09\uFF0C\u6240\u4EE5\u552F\u4E00\u5B89\u5168\u7684\u505A\u6CD5\u662F**\u6392\u961F\u7B49\u5B83\u88AB\u91CA\u653E**\u3002\n//\n// \u672C\u6A21\u5757\u53EA\u8D1F\u8D23\u6301\u4E45\u5316\u961F\u5217\u672C\u8EAB\uFF08\u8BFB\u5199/\u53BB\u91CD/\u6E05\u7406\uFF09\uFF0C\u6267\u884C\u65F6\u673A\u7531 index.js \u51B3\u5B9A\uFF1A\n// - \u5BBF\u4E3B\u91CA\u653E\u8BE5\u4F1A\u8BDD\uFF08session/disposed\uFF1B0.1.5 \u65E0\u7528\u6237\u53EF\u89C1\u7684\u5173\u95ED\u5165\u53E3\uFF0C\u7EDD\u5927\u591A\u6570\u60C5\u51B5\n// \u5C31\u662F\u8FDB\u7A0B\u9000\u51FA\uFF09\u2192 \u7ACB\u523B\u5C1D\u8BD5\n// - \u63D2\u4EF6\u542F\u52A8\u540E\uFF08\u4F1A\u8BDD\u5C1A\u672A\u88AB\u6253\u5F00\uFF09\u2192 \u515C\u5E95\u5C1D\u8BD5\n// - \u5468\u671F\u6027\u8F7B\u91CF\u91CD\u8BD5\uFF08\u961F\u5217\u4E3A\u7A7A\u65F6\u4E0D\u542F\u52A8\u5B9A\u65F6\u5668\uFF09\n// \u5199\u5165\u6CBF\u7528\u672C\u4ED3\u5E93\u5176\u4ED6\u7D22\u5F15\u7684\u6A21\u5F0F\uFF1AschemaVersion + \u539F\u5B50\u5199\uFF08tmp \u2192 rename\uFF09\u3002\n\nimport { readFileSync } from 'node:fs'\nimport { mkdir, rename, writeFile } from 'node:fs/promises'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\n\nconst SCHEMA_VERSION = 1\nconst DEFAULT_DIR = process.env.DSH_SESSIONS_MANAGER_PENDING_DIR\n || process.env.DSH_SESSIONS_MANAGER_STAR_DIR\n || join(homedir(), '.dsh', 'sessions-manager')\nconst MAX_ITEMS = 50\n// \u975E\"\u5360\u7528\u4E2D\"\u7684\u5931\u8D25\uFF08\u76EE\u6807\u5DE5\u4F5C\u533A\u6D88\u5931\u3001\u65E5\u5FD7\u635F\u574F\u2026\uFF09\u7559\u5728\u961F\u5217\u91CC\u4F46\u8BA1\u6570\uFF1B\u8D85\u8FC7\u9608\u503C\u5C31\u4E22\u5F03\uFF0C\n// \u907F\u514D\u4E00\u4E2A\u6C38\u8FDC\u5931\u8D25\u7684\u6761\u76EE\u8BA9\u6BCF\u6B21\u91CD\u8BD5\u90FD\u767D\u8DD1\u3002\nconst MAX_ATTEMPTS = 5\n\nfunction isSafeId(value) {\n return typeof value === 'string' && value.length > 0 && value.length <= 200\n}\n\nfunction normalizeStore(raw) {\n const items = []\n const seen = new Set()\n const source = raw && Array.isArray(raw.items) ? raw.items : []\n for (const item of source) {\n if (!item || !isSafeId(item.sessionId) || typeof item.targetPath !== 'string' || item.targetPath.length === 0) continue\n if (seen.has(item.sessionId)) continue\n seen.add(item.sessionId)\n items.push({\n sessionId: String(item.sessionId),\n targetPath: String(item.targetPath),\n queuedAt: Number.isFinite(item.queuedAt) ? Number(item.queuedAt) : Date.now(),\n attempts: Number.isSafeInteger(item.attempts) && item.attempts >= 0 ? Number(item.attempts) : 0,\n })\n if (items.length >= MAX_ITEMS) break\n }\n return { schemaVersion: SCHEMA_VERSION, items }\n}\n\n/**\n * @param {object} [options]\n * @param {string} [options.dir] \u961F\u5217\u6240\u5728\u76EE\u5F55\uFF08\u6D4B\u8BD5\u6CE8\u5165\u4E34\u65F6\u76EE\u5F55\uFF09\n */\nexport function createPendingMoveStore(options = {}) {\n const dir = options.dir || DEFAULT_DIR\n const indexPath = options.indexPath || join(dir, 'pending-moves.json')\n let mutation = Promise.resolve()\n\n async function read() {\n try {\n return normalizeStore(JSON.parse(readFileSync(indexPath, 'utf8')))\n } catch (e) {\n return normalizeStore(null)\n }\n }\n\n async function write(store) {\n await mkdir(dir, { recursive: true })\n const tmp = join(dir, `.pending-moves-${process.pid}-${Date.now()}.tmp`)\n await writeFile(tmp, JSON.stringify(normalizeStore(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 return {\n indexPath,\n dir,\n list: async () => (await read()).items,\n has: async (sessionId) => (await read()).items.some((item) => item.sessionId === String(sessionId)),\n queue: (sessionId, targetPath) => mutate((store) => {\n if (!isSafeId(sessionId) || typeof targetPath !== 'string' || targetPath.length === 0) return null\n const existing = store.items.find((item) => item.sessionId === String(sessionId))\n if (existing) {\n existing.targetPath = String(targetPath)\n existing.attempts = 0\n return existing\n }\n const item = { sessionId: String(sessionId), targetPath: String(targetPath), queuedAt: Date.now(), attempts: 0 }\n store.items.push(item)\n if (store.items.length > MAX_ITEMS) store.items.splice(0, store.items.length - MAX_ITEMS)\n return item\n }),\n remove: (sessionIds) => mutate((store) => {\n const drop = new Set((Array.isArray(sessionIds) ? sessionIds : [sessionIds]).filter(isSafeId).map(String))\n const before = store.items.length\n store.items = store.items.filter((item) => !drop.has(item.sessionId))\n return before - store.items.length\n }),\n bumpAttempts: (sessionId) => mutate((store) => {\n const item = store.items.find((entry) => entry.sessionId === String(sessionId))\n if (!item) return null\n item.attempts += 1\n if (item.attempts >= MAX_ATTEMPTS) {\n store.items = store.items.filter((entry) => entry.sessionId !== item.sessionId)\n return { dropped: true, attempts: item.attempts }\n }\n return { dropped: false, attempts: item.attempts }\n }),\n }\n}\n\nexport { MAX_ITEMS, MAX_ATTEMPTS, SCHEMA_VERSION, normalizeStore }\n", "// move-notices.js \u2014 \u6392\u961F\u79FB\u52A8\u300C\u540E\u53F0\u7EC8\u5C40\u300D\u7684\u6301\u4E45\u901A\u77E5\uFF083.7.0 T2\uFF09\u3002\n//\n// \u80CC\u666F\uFF08UX \u9ED1\u6D1E\uFF09\uFF1A\u6392\u961F\u79FB\u52A8\u53D1\u8D77\u65F6\u6709\u8BDA\u5B9E\u7684\u300C\u5DF2\u6392\u961F\u300D\u63D0\u793A\uFF0C\u4F46**\u540E\u53F0\u5B8C\u6210/\u6700\u7EC8\u653E\u5F03**\n// \u539F\u5148\u53EA console.warn\u2014\u2014\u7528\u6237\u5408\u4E0A\u9875\u9762\u5C31\u6C38\u8FDC\u4E0D\u77E5\u9053\u7ED3\u679C\u3002\u672C\u6A21\u5757\u628A\u6BCF\u6B21\u7EC8\u5C40\u843D\u6210\u4E00\u6761\n// \u72EC\u7ACB\u901A\u77E5\uFF0C\u7ECF sidebar-state \u5E26\u51FA\u3001client \u5F39\u51FA\u3001ack \u540E\u6E05\u9664\u3002\n//\n// \u4E3A\u4EC0\u4E48\u662F\u72EC\u7ACB\u6587\u4EF6\u800C\u4E0D\u662F pending-moves.json \u52A0\u5B57\u6BB5\uFF1A\u6392\u961F\u7684\u4E24\u4E2A\u7EC8\u5C40\uFF08\u6210\u529F remove\u3001\n// \u653E\u5F03 bumpAttempts\u2192dropped\uFF09\u90FD\u4F1A\u628A\u6761\u76EE\u4ECE items \u91CC\u5220\u6389\u2014\u2014\u6302\u5728\u6761\u76EE\u4E0A\u7684\u5B57\u6BB5\u4E0E\u8F7D\u4F53\n// \u540C\u751F\u5171\u6B7B\uFF0C\u6070\u6070\u5728\u4E24\u4E2A\u76EE\u6807\u573A\u666F\u91CC\u90FD\u89C2\u5BDF\u4E0D\u5230\u3002\u72EC\u7ACB\u6587\u4EF6\u53E6\u5916\u4E24\u70B9\u597D\u5904\uFF1Apending-moves\n// \u7684 items \u5F62\u72B6\u4E0E schemaVersion \u4FDD\u6301 1 \u4E0D\u52A8\uFF08\u65E7 host \u8BFB\u65B0\u6587\u4EF6\u4E0D\u53EF\u89C1\uFF0C\u56DE\u6EDA\u96F6\u5F71\u54CD\uFF09\uFF1B\n// \u901A\u77E5\u7684\u751F\u547D\u5468\u671F\uFF08\u670D\u52A1\u7AEF\u4FDD\u7559\u5230 ack + 7 \u5929 TTL + 20 \u6761\u622A\u65AD\uFF09\u4E0E\u961F\u5217\u4E92\u4E0D\u5E72\u6270\u3002\n//\n// \u6295\u9012\u8BED\u4E49\uFF1A**\u7559\u5728\u670D\u52A1\u7AEF\u76F4\u5230 client ack**\u2014\u2014pop \u5F0F\u6295\u9012\u4F1A\u88AB\u300Ctoast \u6CA1\u5F39\u7528\u6237\u5C31\u5173\u4E86\n// \u9875\u9762\u300D\u76F4\u63A5\u4E22\u901A\u77E5\u3002\u540C\u6D4F\u89C8\u5668\u591A tab \u7684\u5373\u65F6\u53BB\u91CD\u9760 client \u7684 localStorage \u5DF2\u89C1\u96C6\u5408\uFF0C\n// ack \u53EA\u662F\u5C3D\u529B\u6E05\u7406\uFF08ack \u5931\u8D25\u65E0\u5BB3\uFF0CTTL \u515C\u5E95\uFF09\u3002\n//\n// \u5199\u5165\u6CBF\u7528\u672C\u4ED3\u5E93\u7D22\u5F15\u7684\u65E2\u5B9A\u7EAA\u5F8B\uFF1AschemaVersion + \u4E32\u884C mutation + \u539F\u5B50\u5199\uFF08tmp \u2192\n// rename\uFF09+ 0600 + \u9632\u5FA1\u5F0F\u5F52\u4E00\u5316\uFF08\u574F\u6570\u636E\u9010\u6761\u4E22\u5F03\uFF0C\u574F\u6587\u4EF6\u5F53\u7A7A\u96C6\u5408\uFF09\u3002\nimport { readFileSync } from 'node:fs'\nimport { mkdir, rename, writeFile } from 'node:fs/promises'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\n\nconst SCHEMA_VERSION = 1\n// env \u5728 create \u65F6\u8BFB\u53D6\u800C\u975E\u6A21\u5757\u52A0\u8F7D\u65F6\u51BB\u7ED3\uFF08\u6D4B\u8BD5\u52A8\u6001\u5BFC\u5165\u7684\u65E2\u5B9A\u6A21\u5F0F\uFF1B\u751F\u4EA7\u5355\u5B9E\u4F8B\u4E24\u53EF\uFF09\u3002\nexport const MAX_NOTICES = 20\nexport const NOTICE_MAX_AGE_MS = 7 * 24 * 3600 * 1000\nconst KINDS = new Set(['moved', 'abandoned'])\n\nfunction isSafeId(value) {\n return typeof value === 'string' && value.length > 0 && value.length <= 200\n}\nfunction str(v, max) {\n return typeof v === 'string' && v ? v.slice(0, max) : null\n}\n\nexport function normalizeNotice(raw) {\n if (!raw || typeof raw !== 'object') return null\n if (!KINDS.has(raw.kind) || !isSafeId(raw.sessionId)) return null\n const at = Number.isFinite(raw.at) && raw.at > 0 ? Math.floor(raw.at) : 0\n if (!at) return null\n const sessionId = String(raw.sessionId)\n return {\n id: str(raw.id, 400) || `${sessionId}:${raw.kind}:${at}`,\n kind: raw.kind,\n sessionId,\n targetPath: str(raw.targetPath, 500),\n attempts: Number.isSafeInteger(raw.attempts) && raw.attempts >= 0 ? raw.attempts : null,\n reason: str(raw.reason, 300),\n at,\n }\n}\n\nfunction normalizeStore(raw) {\n const source = raw && Array.isArray(raw.items) ? raw.items : []\n const seen = new Set()\n const items = []\n for (const entry of source) {\n const n = normalizeNotice(entry)\n if (!n || seen.has(n.id)) continue\n seen.add(n.id)\n items.push(n)\n }\n items.sort((a, b) => a.at - b.at)\n const trimmed = items.length > MAX_NOTICES ? items.slice(items.length - MAX_NOTICES) : items\n return { schemaVersion: SCHEMA_VERSION, items: trimmed }\n}\n\n/**\n * @param {object} [options]\n * @param {string} [options.dir] \u901A\u77E5\u6587\u4EF6\u6240\u5728\u76EE\u5F55\uFF08\u6D4B\u8BD5\u6CE8\u5165\u4E34\u65F6\u76EE\u5F55\uFF09\n */\nexport function createMoveNoticeStore(options = {}) {\n const dir = options.dir\n || process.env.DSH_SESSIONS_MANAGER_PENDING_DIR\n || process.env.DSH_SESSIONS_MANAGER_STAR_DIR\n || join(homedir(), '.dsh', 'sessions-manager')\n const indexPath = options.indexPath || join(dir, 'move-notices.json')\n let mutation = Promise.resolve()\n\n function read() {\n try {\n return normalizeStore(JSON.parse(readFileSync(indexPath, 'utf8')))\n } catch (e) {\n return normalizeStore(null)\n }\n }\n\n async function write(store) {\n await mkdir(dir, { recursive: true })\n const tmp = join(dir, `.move-notices-${process.pid}-${Date.now()}.tmp`)\n await writeFile(tmp, JSON.stringify(normalizeStore(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 = 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 return {\n indexPath,\n // \u7EC8\u5C40\u843D\u4E00\u6761\u901A\u77E5\uFF1B\u540C id\uFF08\u4F1A\u8BDD+\u7C7B\u578B+\u65F6\u523B\uFF09\u5E42\u7B49\u53BB\u91CD\u3002\n append: (notice) => mutate((store) => {\n const n = normalizeNotice(notice)\n if (!n) return null\n if (store.items.some((x) => x.id === n.id)) return n\n store.items.push(n)\n return n\n }),\n // \u53EA\u8BFB\u5217\u51FA\u672A\u8FC7\u671F\u3001\u672A ack \u7684\u901A\u77E5\uFF08\u6309\u65F6\u95F4\u5347\u5E8F\uFF09\u3002\u8FC7\u671F\u9879\u5728\u4E0B\u6B21\u5199\u5165\u65F6\u968F\u5F52\u4E00\u5316\u6E05\u6389\u3002\n async list() {\n const now = Date.now()\n return read().items.filter((n) => now - n.at <= NOTICE_MAX_AGE_MS)\n },\n ack: (ids) => mutate((store) => {\n const drop = new Set((Array.isArray(ids) ? ids : []).filter((v) => typeof v === 'string' && v.length <= 400).map(String))\n const before = store.items.length\n store.items = store.items.filter((n) => !drop.has(n.id))\n return before - store.items.length\n }),\n }\n}\n", "// Stale atomic-write temp sweeper.\n//\n// \u56DB\u4E2A\u72B6\u6001\u6587\u4EF6\u5199\u5165\u5668\u90FD\u7528\u300C\u540C\u76EE\u5F55 .<name>-<pid>-<ts>.tmp \u2192 rename \u5230\u6B63\u5F0F\u6587\u4EF6\u300D\u7684\n// \u539F\u5B50\u5199\u6A21\u5F0F\uFF08star-index / auto-archive / title-persist-index / index.js \u7684\u56DE\u6536\u7AD9\u7D22\u5F15\uFF09\u3002\n// \u82E5\u8FDB\u7A0B\u5728 writeFile \u4E0E rename \u4E4B\u95F4\u88AB\u6740\uFF08\u53CD\u590D\u91CD\u542F dsm web \u65F6\u5F88\u5E38\u89C1\uFF09\uFF0C\u4E34\u65F6\u6587\u4EF6\u5C31\u7559\u5728\n// \u76EE\u5F55\u91CC\uFF1A\u5B9E\u6D4B ~/.dsh/sessions-manager \u7D2F\u79EF\u4E86 153 \u4E2A\u5B64\u513F .star-*.tmp\uFF082026-09-10\uFF09\u3002\n//\n// \u542F\u52A8\u65F6\u626B\u4E00\u904D\u8FD9\u4E9B\u76EE\u5F55\uFF0C\u628A\u300C\u8D85\u8FC7 maxAgeMs \u6CA1\u88AB\u52A8\u8FC7\u300D\u7684\u4E34\u65F6\u6587\u4EF6\u6E05\u6389\u3002\u7528\u5E74\u9F84\u800C\u975E pid\n// \u5224\u5B9A\uFF1Apid \u4F1A\u56DE\u7ED5\uFF0C\u800C 1 \u5C0F\u65F6\u7684\u5BBD\u9650\u671F\u8FDC\u5927\u4E8E\u4EFB\u4F55\u6B63\u5E38\u5199\u5165\u7A97\u53E3\uFF0C\u4E0D\u4F1A\u78B0\u5230\u5E76\u53D1\u4E2D\u7684\u5199\u5165\u3002\n\nimport { readdir, rm, stat } from 'node:fs/promises'\nimport { join } from 'node:path'\n\nconst TEMP_NAME_RE = /^\\..+-\\d+-\\d+\\.tmp$/\n\n/**\n * @param {string[]} dirs \u9700\u8981\u6E05\u626B\u7684\u76EE\u5F55\uFF08\u4E0D\u5B58\u5728\u65F6\u9759\u9ED8\u8DF3\u8FC7\uFF09\n * @param {object} [options]\n * @param {number} [options.maxAgeMs] \u53EA\u6E05\u7406\u6BD4\u8FD9\u66F4\u65E7\u7684\u4E34\u65F6\u6587\u4EF6\uFF08\u9ED8\u8BA4 1 \u5C0F\u65F6\uFF09\n * @param {number} [options.now] \u6CE8\u5165\u65F6\u949F\uFF0C\u4FBF\u4E8E\u6D4B\u8BD5\n * @returns {Promise<number>} \u6E05\u7406\u6389\u7684\u4E34\u65F6\u6587\u4EF6\u6570\n */\nexport async function sweepStaleStateTemps(dirs, options = {}) {\n const maxAgeMs = Number.isSafeInteger(options.maxAgeMs) && options.maxAgeMs >= 0 ? options.maxAgeMs : 3600_000\n const now = Number.isFinite(options.now) ? options.now : Date.now()\n let removed = 0\n for (const dir of Array.isArray(dirs) ? dirs : []) {\n if (typeof dir !== 'string' || dir.length === 0) continue\n let entries\n try { entries = await readdir(dir) } catch (e) { continue }\n for (const name of entries) {\n if (!TEMP_NAME_RE.test(name)) continue\n const path = join(dir, name)\n let info\n try { info = await stat(path) } catch (e) { continue }\n if (!info.isFile()) continue\n if (now - info.mtimeMs < maxAgeMs) continue\n try { await rm(path, { force: true }); removed++ } catch (e) { /* \u6E05\u4E0D\u6389\u7684\u4E0B\u6B21\u518D\u8BF4 */ }\n }\n }\n return removed\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// \u8DE8\u8FDB\u7A0B\uFF08\u91CD\u542F\u540E\uFF09\u4ECD\u53EF\u7528\u7684\u6301\u4E45\u6307\u7EB9\uFF0C\u4F9B title-persist-index \u4F7F\u7528\uFF08issue #8\uFF09\u3002\n//\n// - legacy \u4E16\u4EE3\uFF1AfingerprintOf \u4EA7\u51FA (mtimeMs:size) \u6587\u4EF6\u6307\u7EB9\uFF0C\u672C\u8EAB\u53EF\u6301\u4E45\u5316\uFF1B\n// - handle \u4E16\u4EE3\uFF080.1.3+\uFF09\uFF1AfingerprintOf \u4EA7\u51FA rev: \u6307\u7EB9\uFF0C\u88AB isPersistableFingerprint\n// \u6B63\u786E\u62D2\u7EDD\uFF08revision \u662F\u5B9E\u4F8B\u5185 opaque token\uFF09\u3002\u4F46\u8FD9\u6837\u6301\u4E45\u7D22\u5F15\u5728\u8BE5\u4E16\u4EE3**\u4ECE\u4E0D\n// \u5199\u5165**\u2014\u2014issue #8 \u5B9E\u6D4B\uFF1A249MB / 87 \u65E5\u5FD7\u7684\u5E93\u6BCF\u6B21\u91CD\u542F\u90FD\u91CD\u65B0\u5168\u91CF\u89E3\u7801\u7EA6 90s\u3002\n// \u9000\u800C\u6C42\u5176\u6B21\u7528\u5B98\u65B9 list()/stat() \u6BCF\u6B21\u5E26\u56DE\u7684 sizeBytes\uFF08\"sz:<n>\"\uFF09\uFF1A\n// \u65E5\u5FD7\u4EFB\u4F55\u8FFD\u52A0/\u622A\u65AD\u90FD\u4F1A\u6539\u53D8 size\uFF0Csize \u4E0D\u53D8\u800C\u6807\u9898\u53D8\u5316\u5728\u771F\u5B9E\u573A\u666F\u91CC\u57FA\u672C\n// \u4E0D\u5B58\u5728\uFF1B\u6700\u574F\u4EE3\u4EF7\u662F\u663E\u793A\u4E00\u6761\u9648\u65E7\u6807\u9898\uFF0C\u7EDD\u4E0D\u4EA7\u751F\u9519\u8BEF\u6570\u636E\u3002\n// cwd/createdAt \u4E0D\u53D7\u6B64\u5F71\u54CD\uFF1A\u56DE\u586B\u65F6\u59CB\u7EC8\u4EE5\u6700\u65B0 list header \u4E3A\u6743\u5A01\uFF08\u89C1 index.js\uFF09\u3002\n// - \u62FF\u4E0D\u5230\u4EFB\u4F55\u53EF\u7528\u89C2\u6D4B\u91CF\u65F6\u8FD4\u56DE null\uFF08\u8C03\u7528\u65B9\u6309\u672A\u547D\u4E2D/\u4E0D\u843D\u76D8\u5904\u7406\uFF09\u3002\nexport function persistFingerprintOf(stat) {\n const fp = fingerprintOf(stat)\n if (fp && isPersistableFingerprint(fp)) return fp\n if (stat && Number.isFinite(stat.sizeBytes) && stat.sizeBytes >= 0) return `sz:${stat.sizeBytes}`\n return null\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, resolved? }\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// resolved\uFF08schema v2\uFF0Cv3.6.2 #1\uFF09\uFF1A\u6807\u8BB0\u300C\u6295\u5F71\u786E\u5B9E\u6210\u529F\u8FC7\u300D\u3002title \u4E3A null \u7684\n// \u6761\u76EE\u53EA\u6709\u5E26\u8FD9\u4E2A\u6807\u8BB0\u624D\u53EF\u4FE1\u2014\u2014\u6CA1\u6807\u8BB0\u7684 null \u6807\u9898\u6761\u76EE\u662F v3.6.1 \u4E4B\u524D\u300C\u6295\u5F71\u5931\u8D25\n// \u88AB\u5F53\u7ED3\u679C\u7F13\u5B58\u300D\u7684\u6C61\u67D3\u6E90\uFF0C\u8BFB\u53D6\u65F6\u5FC5\u987B\u4E22\u5F03\u5E76\u91CD\u65B0\u9884\u70ED\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 = 2\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 const resolved = raw.resolved === true || raw.resolved === 1\n if (!fingerprint || fingerprint.startsWith('rev:')) return null\n if (!title && !cwd) return null\n // v3.6.2 #1\uFF1Anull \u6807\u9898\u53EA\u6709\u300C\u6295\u5F71\u786E\u5B9E\u6210\u529F\u8FC7\u300D\uFF08\u4F1A\u8BDD\u771F\u7684\u6CA1\u6709\u6807\u9898\u4E8B\u4EF6\uFF09\u624D\u53EF\u4FE1\u3002\n // \u65E0 resolved \u6807\u8BB0\u7684 null \u6807\u9898\u6761\u76EE = v3.6.1 \u7684\u5931\u8D25\u6C61\u67D3\u6E90\uFF08\u6216 v1 \u65E7\u6570\u636E\uFF09\uFF0C\n // \u4E00\u5F8B\u4E22\u5F03 \u2192 \u4E0B\u6B21\u6309\u672A\u547D\u4E2D\u91CD\u65B0\u9884\u70ED\uFF0C\u7D22\u5F15\u81EA\u6108\u3002\n if (!title && !resolved) return null\n const entry = { title, cwd, createdAt, fingerprint, updatedAt }\n if (resolved) entry.resolved = 1\n return entry\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", "// empty-scan-index.js \u2014 \u7A7A\u767D\u4F1A\u8BDD\u7CBE\u5224\u7ED3\u8BBA\u7684**\u78C1\u76D8**\u7F13\u5B58\uFF083.7.0 / T1 refine \u89E3\u7ED1\uFF09\u3002\n//\n// \u80CC\u666F\uFF1A\u7CBE\u5224\uFF08\u5BF9 \u22648KB \u5C0F\u65E5\u5FD7\u6309\u4E8B\u4EF6\u7C7B\u578B\u5224\u7A7A\u767D\uFF09\u539F\u5148\u53EA\u5728 sidebar-state \u7684\u8BF7\u6C42\u8DEF\u5F84\u91CC\n// \u540C\u6B65\u8DD1\uFF0C\u8FDB\u7A0B\u5185 Map \u7F13\u5B58\u91CD\u542F\u5373\u5168\u51B7\u2014\u2014\u5206\u652F\u6807\u7B7E\u5EF6\u8FDF\u5BA1\u8BA1\u7684\u6839\u56E0\u4E4B\u4E00\u3002T1 \u628A\u7CBE\u5224\u632A\u8FDB\n// \u540E\u53F0\u961F\u5217\u540E\uFF0C\u672C\u6A21\u5757\u8BA9\u300C\u5DF2\u5224\u5B9A\u300D\u8DE8\u91CD\u542F\u590D\u7528\uFF1A\u6307\u7EB9\u672A\u53D8\u7684\u4F1A\u8BDD\u76F4\u63A5\u6CBF\u7528\u7ED3\u8BBA\uFF0C\u96F6\u89E3\u7801\u3002\n//\n// \u7EAA\u5F8B\uFF08\u5168\u90E8\u6CBF\u7528 title-persist-index / session-meta-cache \u7684\u65E2\u5B9A\u7EA2\u7EBF\uFF09\uFF1A\n// 1. \u53EA\u6709**\u771F\u6B63\u89E3\u7801\u6210\u529F**\u7684\u7ED3\u8BBA\u624D\u5141\u8BB8\u843D\u76D8\uFF1B\u89E3\u7801\u5931\u8D25\u6309\u300C\u975E\u7A7A\u300D\u515C\u5E95\u53EA\u8FDB\u8FDB\u7A0B\u5185\uFF0C\n// \u7EDD\u4E0D\u56FA\u5316\u6210\u8DE8\u91CD\u542F\u7684\u5224\u5B9A\uFF08v3.6.1 #1 \u7684\u6559\u8BAD\uFF1A\u4E00\u6B21\u5931\u8D25\u88AB\u6C38\u4E45\u8BB0\u4E0B\uFF09\u3002\n// 2. rev: \u6307\u7EB9\uFF08\u5B9E\u4F8B\u5185 opaque token\uFF09\u5728 normalizeEntry \u5904\u786C\u6027\u62E6\u622A\uFF0C\u4E0E\n// title-persist-index.js \u540C\u4E00\u9053\u9632\u7EBF\u3002\n// 3. \u4EFB\u4F55\u6587\u4EF6\u635F\u574F \u2192 \u5F53\u7A7A\u7D22\u5F15\uFF0C\u7EDD\u4E0D\u963B\u585E\u4FA7\u680F\u6570\u636E\uFF1B\u574F db \u7684\u4EE3\u4EF7\u662F\u91CD\u5224\uFF0C\u4E0D\u662F\u9519\u6570\u636E\u3002\n//\n// \u6761\u76EE\u5F62\u72B6 { empty: 0|1, fingerprint: \"<mtime:size>\" | \"sz:<n>\", updatedAt }\n\nimport { mkdir, readFile, rename, writeFile } from 'node:fs/promises'\nimport { dirname, join } from 'node:path'\n\nexport const EMPTY_SCAN_SCHEMA_VERSION = 1\n\nconst MAX_ENTRIES = 20000\n\nexport function normalizeEntry(raw) {\n if (!raw || typeof raw !== 'object') return null\n const empty = raw.empty === 1 || raw.empty === true ? 1 : raw.empty === 0 || raw.empty === false ? 0 : 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 (empty === null || !fingerprint || fingerprint.startsWith('rev:')) return null\n return { empty, fingerprint, updatedAt }\n}\n\nexport function normalizeEmptyScanIndex(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: EMPTY_SCAN_SCHEMA_VERSION, entries }\n}\n\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 createEmptyScanStore({ dir, file }) {\n let cache = null\n let chain = Promise.resolve()\n const path = file || join(dir, 'empty-scan.json')\n\n async function readRaw() {\n try {\n return normalizeEmptyScanIndex(JSON.parse(await readFile(path, 'utf8')))\n } catch (e) {\n return normalizeEmptyScanIndex(null)\n }\n }\n\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 async entries() {\n if (cache) return cache\n cache = (await readRaw()).entries\n return cache\n },\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), `.empty-scan-${process.pid}-${Date.now()}.tmp`)\n await writeFile(tmp, JSON.stringify({ schemaVersion: EMPTY_SCAN_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), `.empty-scan-${process.pid}-${Date.now()}.tmp`)\n await writeFile(tmp, JSON.stringify({ schemaVersion: EMPTY_SCAN_SCHEMA_VERSION, entries: store }), { encoding: 'utf8', mode: 0o600 })\n await rename(tmp, path)\n })\n return true\n },\n }\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\n// \u89C4\u8303 generation \u6587\u4EF6\uFF1A\u5B98\u65B9 `session.vN.jsonl[.zstd]`\uFF0C**v0 \u4EE3\u65E0 `.vN.` \u5206\u91CF**\n// \uFF08\u5373 `session.jsonl[.zstd]`\uFF0Clegacy \u65F6\u4EE3\u4EA7\u7269\uFF09\u3002\u5B98\u65B9\n// `parseSessionFormatLogFilename` \u628A v0 \u5F53 version 0 \u53C2\u4E0E\u300C\u6700\u9AD8\u4EE3\u4F18\u5148\u300D\uFF0C\n// \u6240\u4EE5\u8FD9\u91CC\u4E5F\u5FC5\u987B\u6536 v0\uFF0C\u5426\u5219\u300C\u53EA\u6709 v0 \u4EE3\u300D\u7684\u4F1A\u8BDD\u4F1A\u88AB\u8BEF\u5224\u4E3A\u4E0D\u53EF\u5B9A\u4F4D\n// \uFF08\u79FB\u52A8/\u5F7B\u5E95\u5220\u9664\u9759\u9ED8\u7981\u7528\uFF09\u3002\u4E34\u65F6\u5907\u4EFD\u540D\uFF08`.move-backup-\u2026`\uFF09\u4E0D\u4EE5\n// `.jsonl`/`.zstd` \u7ED3\u5C3E\uFF0C\u5929\u7136\u4E0D\u5339\u914D\u3002\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\n// `generation` \u53EA\u662F\u540D\u5B57\u91CC\u7684 `.vN` \u5206\u91CF\uFF1A0 = legacy \u7684 `session.jsonl`\uFF0C2 = `session.v2.jsonl`\u3002\n// \u5B9E\u9645\u843D\u76D8\u7248\u672C\u7531 runtime \u7684\u683C\u5F0F\u76EE\u5F55\u51B3\u5B9A\uFF0C\u6B64\u5904\u4E0D\u5047\u8BBE\u201C\u5F53\u524D\u7248\u672C\u662F\u51E0\u201D\u3002\nexport function deriveGenerationLogPath(root, cwd, id, { compression = 'zstd', generation = 2 } = {}) {\n const base = generation === 0 ? 'session.jsonl' : `session.v${generation}.jsonl`\n return join(deriveSessionDir(root, cwd, id), `${base}${compression === 'zstd' ? '.zstd' : ''}`)\n}\n\n// \u540D\u5B57\u91CC\u7684\u4EE3\u7248\u672C\u53F7\uFF08`session.v3.jsonl.zstd` \u2192 3\uFF1B`session.jsonl.zstd` \u2192 0\uFF09\u3002\nexport function generationVersionOf(name) {\n return Number((String(name).match(/^session\\.v(\\d+)\\./) || [])[1] || 0)\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\uFF08v0/legacy \u4E5F\u662F\u5019\u9009\uFF0C\u7248\u672C\u53F7\u6700\u5C0F\uFF09\uFF0C\u4FDD\u6301\u786E\u5B9A\u6027\u3002\n generationFiles.sort((a, b) => generationVersionOf(b) - generationVersionOf(a))\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 // \u6700\u9AD8\u4EE3\u7248\u672C\u53F7\uFF1A0 = legacy `session.jsonl[.zstd]`\uFF0C\u22651 = `session.vN.jsonl[.zstd]`\u3002\n // \u4E0A\u5C42\u7528\u5B83\u5224\u65AD\u300C\u53E6\u4E00\u4E2A\u76EE\u5F55\u91CC\u7684\u540C id \u526F\u672C\u662F\u4E0D\u662F\u88AB\u53D6\u4EE3\u7684\u65E7\u4EE3\u300D\u3002\n generationVersion: generationVersionOf(generationFiles[0]),\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\n// SessionHandle.read() \u7684\u8FD4\u56DE\u503C\u5728 0.1.3 / 0.1.5 \u4E4B\u95F4\u6362\u8FC7\u5F62\u6001\uFF0C\u8FD9\u91CC\u7EDF\u4E00\u6210\u4E8B\u4EF6\u6570\u7EC4\uFF1A\n// - 0.1.3\uFF1A\u76F4\u63A5\u662F\u4E8B\u4EF6\u6570\u7EC4\uFF08\u6216\u53EF\u8FED\u4EE3\u5BF9\u8C61\uFF09\n// - 0.1.5\uFF1A**{ eventState: 'shared-frozen' | \u2026, events: [...] }**\uFF08\u4E0D\u518D\u662F\u6570\u7EC4\uFF01\n// \u672B\u5C3E\u8BFB\u53D6\u540C\u6837\u662F\u8FD9\u4E2A\u5F62\u72B6\uFF0C\u53EA\u662F events: []\uFF09\n// - \u672A\u77E5\u5F62\u6001**\u629B\u9519\u800C\u4E0D\u662F\u5F53\u7A7A\u6570\u7EC4**\uFF1A\u9759\u9ED8\u8FD4\u56DE [] \u7684\u4EE3\u4EF7\u662F\u707E\u96BE\u6027\u7684\u2014\u2014\n// 2026-09-10 \u5B9E\u6D4B\uFF0C0.1.5 \u5347\u7EA7\u540E\u8BFB\u53D6\u6052\u4E3A\u7A7A\uFF0C\u79FB\u52A8\"\u7528\u7A7A\u4E8B\u4EF6\u91CD\u5EFA\u65E5\u5FD7\"\u628A\u4E24\u4E2A\u4F1A\u8BDD\n// \u524A\u6210\u53EA\u5269\u5934\u90E8\u7684\u7A7A\u58F3\u3002\u4EFB\u4F55\u65E0\u6CD5\u8BC6\u522B\u7684\u8FD4\u56DE\u503C\u90FD\u5FC5\u987B\u8BA9\u8C03\u7528\u65B9\u770B\u5230\u9519\u8BEF\u3002\nfunction normalizeReadResult(events) {\n if (events === undefined || events === null) return []\n if (Array.isArray(events)) return events\n if (typeof events === 'object' && Array.isArray(events.events)) return events.events\n if (typeof events[Symbol.iterator] === 'function') return [...events]\n const error = new Error(\n 'DSH \u4F1A\u8BDD\u8BFB\u53D6\u8FD4\u56DE\u4E86\u65E0\u6CD5\u8BC6\u522B\u7684\u7ED3\u6784\uFF08runtime \u63A5\u53E3\u53EF\u80FD\u5DF2\u53D8\u66F4\uFF09\uFF0C\u5DF2\u505C\u6B62\u89E3\u6790\u4EE5\u514D\u8BEF\u5224\u4E3A\u7A7A\uFF1A' +\n Object.prototype.toString.call(events),\n )\n error.code = 'DSM_READ_SHAPE_UNKNOWN'\n throw error\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\u88AB DSH \u6253\u5F00\u3001\u5199\u6743\u9650\u5DF2\u88AB\u5360\u7528\u300D\u7684\u4F1A\u8BDD\uFF0C\u800C\u4E0D\u662F\u7167\n// legacy \u90A3\u6837\u6539\u5199\u6D3B\u8DC3\u5BF9\u8C61\u2014\u2014handle \u65F6\u4EE3\u7684\u5199\u53E5\u67C4\u6240\u6709\u6743\u5728\u5B98\u65B9 tracker \u5185\u90E8\uFF0C\n// \u4E0E\u5176\u6253\u8865\u4E01\u4E0D\u5982\u5982\u5B9E\u62D2\u7EDD\uFF0C\u98CE\u9669\u9762\u66F4\u5C0F\u3002\n//\n// \u6CE8\u610F\u8FD9\u4E0E legacy \u65F6\u4EE3\u7684\u53EF\u7528\u8303\u56F4\u4E0D\u540C\uFF1Alegacy \u65F6\u4EE3\u6CA1\u6709\u5355\u5199\u8005\u6240\u6709\u6743\uFF0C\u63D2\u4EF6\u76F4\u63A5\u6539\n// \u6587\u4EF6 + \u540C\u6B65 live \u5BF9\u8C61\u5C31\u80FD\u79FB\u52A8\u4EFB\u610F\u4F1A\u8BDD\uFF1B0.1.3 \u5F15\u5165 handle \u540E\uFF0Cagent-loop \u5728\n// resume \u4F1A\u8BDD\u65F6\u5148\u53D6\u5199\u6240\u6709\u6743\uFF08core/agent-loop resumeWith: \"Taking write ownership\n// FIRST\"\uFF09\u5E76\u6301\u6709\u5230 agent \u5378\u8F7D\uFF0C\u4E8E\u662F\u300C\u5728 DSH \u91CC\u70B9\u5F00\u8FC7\u7684\u4F1A\u8BDD\u300D\u4E00\u5F8B\u5904\u4E8E\u5360\u7528\u6001\u3002\n// \u8FD9\u662F\u5BBF\u4E3B\u673A\u5236\u51B3\u5B9A\u7684\u786C\u7EA6\u675F\uFF0C\u4E0D\u662F\u63D2\u4EF6\u80FD\u7ED5\u5F00\u7684\u5224\u5B9A\uFF0C\u63D0\u793A\u5FC5\u987B\u5982\u5B9E\u8BF4\u660E\u3002\n\nimport { mkdir, readFile, readdir, rename, rm, stat, writeFile } from 'node:fs/promises'\nimport { basename, dirname, join } from 'node:path'\nimport { rewriteFrame0CwdInMemory, scanZstdFrames } from './zstd-frame.js'\nimport { deriveSessionDir, encodeSegmentFor, generationVersionOf, locateSessionArtifacts } from './handle-era-paths.js'\n\nconst MOVE_BATCH = 400\n\n// \u771F\u5B9E\u65E5\u5FD7\u5224\u5B9A\uFF1A\u5B98\u65B9\u547D\u540D\u662F session.vN.jsonl[.zstd]\uFF0Clegacy \u65F6\u4EE3\u662F\n// session.jsonl[.zstd]\u2014\u2014\u951A\u5B9A\u7ED3\u5C3E\uFF0C\u5176\u4ED6\u540E\u7F00\uFF08\u5982\u6D4B\u8BD5\u6B8B\u6E23 *.jsonl.zstd.test\uFF09\n// \u4E0D\u7B97\u771F\u65E5\u5FD7\uFF1B\u53EA\u6709\u672C\u63D2\u4EF6\u79FB\u52A8\u8FC7\u7A0B\u7684\u4E34\u65F6\u540D\uFF08.move-backup- / .move-stage-\uFF09\n// \u4E5F\u4E0D\u7B97\u3002\nconst REAL_LOG_RE = /^session.*\\.jsonl(\\.zst(d)?)?$/\nconst MOVE_TEMP_RE = /\\.move-(backup|stage)-/\n// \u4F1A\u8BDD\u76EE\u5F55\u91CC\"\u672C\u4F1A\u8BDD\u81EA\u5DF1\u7684\"\u975E\u65E5\u5FD7\u6587\u4EF6\uFF08lease / flock / \u5B98\u65B9\u4E34\u65F6\u4EA7\u7269\uFF09\u3002\u7528\u4E8E\u5224\u5B9A\n// \u4E00\u4E2A\u4EC5\u5269\u65E7\u4EE3\u7684\u76EE\u5F55\u662F\u4E0D\u662F\u53EF\u4EE5\u5B89\u5168\u56DE\u6536\u2014\u2014\u5939\u5E26\u522B\u7684\u6587\u4EF6\u5C31\u4EA4\u4EBA\u5DE5\u88C1\u51B3\u3002\nconst SESSION_LOCAL_JUNK_RE = /^(\\.?session\\.lock.*|\\.lock.*|.*\\.lock|.*\\.tmp|.*\\.stage|.*\\.bak|\\.DS_Store)$/\n\n// \u540C id \u8DE8\u76EE\u5F55\u6B8B\u7559\u5904\u7406\u3002\u540E\u7AEF\u5728 create/list \u65F6\u626B\u5168\u76D8\uFF1A\u540C\u4E00\u4F1A\u8BDD id \u51FA\u73B0\u5728\u591A\u4E2A\n// \u9879\u76EE\u76EE\u5F55\u5373\u62A5 \u201Cduplicate JSONL session id ... appears in multiple project\n// directories\u201D\u3002\u4E09\u7C7B\u6B8B\u7559\u533A\u522B\u5BF9\u5F85\uFF08\u5224\u5B9A\u987A\u5E8F\u5373\u98CE\u9669\u4ECE\u4F4E\u5230\u9AD8\uFF09\uFF1A\n//\n// 1) \u7A7A\u58F3\uFF1A\u76EE\u5F55\u91CC\u6CA1\u6709\u4EFB\u4F55\u771F\u5B9E\u65E5\u5FD7 \u2192 \u7EAF\u5783\u573E\uFF0C\u76F4\u63A5\u5220\u3002\n// 2) \u53EA\u542B**\u88AB\u53D6\u4EE3\u7684\u65E7\u4EE3**\u65E5\u5FD7\uFF08\u6700\u9AD8\u4EE3\u7248\u672C\u53F7\u4E25\u683C\u4F4E\u4E8E\u5F53\u524D\u76EE\u5F55\u7684\u6700\u9AD8\u4EE3\uFF09\u2192 \u4E5F\u5220\u3002\n// 0.1.5 \u8D77\u5B98\u65B9\u300C\u53D1\u5E03\u65B0\u4EE3\u4F46\u4E0D\u5220\u65E7\u4EE3\u300D\uFF08\u5B9E\u6D4B\u540C\u4E00\u76EE\u5F55\u91CC session.v2 \u4E0E\n// session.v3 \u5E76\u5B58\uFF09\uFF0C\u800C\u5386\u53F2\u7248\u672C\u7684\u63D2\u4EF6\u79FB\u52A8\u65F6\u53EA\u642C\u8D70\u5F53\u524D\u4EE3\uFF0C\u7559\u4E0B\u7684\u65E7\u4EE3\u4F1A\u8BA9\u8BE5\n// id \u6C38\u8FDC\u5904\u4E8E\"\u8DE8\u76EE\u5F55\u91CD\u590D\"\u72B6\u6001\uFF0C\u4E4B\u540E\u6240\u6709\u79FB\u52A8/\u5F7B\u5E95\u5220\u9664\u90FD\u88AB\u62D2\u3002\u65E7\u4EE3\u5185\u5BB9\u5DF2\u88AB\n// \u65B0\u4EE3\u53D6\u4EE3\uFF08\u5B98\u65B9\u8BFB\u53D6\u6052\u5B9A\u53D6\u6700\u9AD8\u4EE3\uFF09\uFF0C\u5220\u9664\u4E0D\u4E22\u6570\u636E\uFF0C\u4E14\u4F1A\u4EE5 note \u5982\u5B9E\u56DE\u62A5\u3002\n// \u4E3A\u7A33\u59A5\u53EA\u5220\"\u7EAF\u65E5\u5FD7\u76EE\u5F55\"\uFF08\u9664\u65E5\u5FD7\u5916\u53EA\u5141\u8BB8 lock/\u4E34\u65F6\u6587\u4EF6\uFF09\uFF0C\u5939\u5E26\u672A\u77E5\u6587\u4EF6\u65F6\n// \u964D\u7EA7\u4E3A\u7B2C 3 \u7C7B\u4EBA\u5DE5\u88C1\u51B3\u3002\n// 3) \u7248\u672C\u76F8\u540C\u6216\u66F4\u9AD8 \u2192 \u771F\u91CD\u590D\uFF0C\u65E0\u6CD5\u5224\u65AD\u54EA\u4EFD\u6743\u5A01 \u2192 \u62D2\u7EDD\u79FB\u52A8\u5E76\u7ED9\u51FA\u6E05\u5355\u3002\nasync function cleanSiblingCopies(root, sid, keepDir, keepVersion) {\n let projects\n try { projects = await readdir(root, { withFileTypes: true }) } catch (e) { return { removed: 0, superseded: [], real: [] } }\n let segment\n try { segment = encodeSegmentFor(sid) } catch (e) { return { removed: 0, superseded: [], real: [] } }\n let removed = 0\n const superseded = []\n const real = []\n for (const ent of projects) {\n if (!ent.isDirectory()) continue\n const candidate = join(root, ent.name, segment)\n if (keepDir && candidate === keepDir) continue\n let entries\n try {\n const st = await stat(candidate)\n if (!st.isDirectory()) continue\n entries = await readdir(candidate)\n } catch (e) { continue }\n const logs = entries.filter((name) => REAL_LOG_RE.test(name) && !MOVE_TEMP_RE.test(name))\n if (logs.length === 0) {\n try { await rm(candidate, { recursive: true, force: true }); removed++ } catch (e) { /* \u6E05\u4E0D\u6389\u7684\u58F3\u7531\u771F\u91CD\u590D\u68C0\u67E5\u515C\u5E95 */ }\n continue\n }\n const highest = Math.max(...logs.map(generationVersionOf))\n const onlyLogsAndLocalJunk = entries.every((name) =>\n (REAL_LOG_RE.test(name) && !MOVE_TEMP_RE.test(name)) || SESSION_LOCAL_JUNK_RE.test(name))\n if (Number.isSafeInteger(keepVersion) && highest < keepVersion && onlyLogsAndLocalJunk) {\n try {\n await rm(candidate, { recursive: true, force: true })\n superseded.push(candidate)\n } catch (e) { real.push(candidate) }\n continue\n }\n real.push(candidate)\n }\n return { removed, superseded, real }\n}\n\n// \u79FB\u52A8\u6210\u529F\u540E\u7684\u6E90\u76EE\u5F55\u6536\u5C3E\u3002\u76EE\u6807\u4FA7\u5DF2\u7ECF create + append + \u6821\u9A8C\u51FA\u4E00\u4EFD\u5B8C\u6574\u6743\u5A01\u65E5\u5FD7\uFF0C\n// \u6E90\u76EE\u5F55\u5FC5\u987B**\u6574\u4F53\u79FB\u9664**\uFF1A\n// - 0.1.5 \u8D77\u5B98\u65B9\u53D1\u5E03\u65B0\u4EE3\u4E0D\u5220\u65E7\u4EE3\uFF0C\u82E5\u53EA\u642C\u8D70\u5F53\u524D\u4EE3\uFF0C\u6E90\u76EE\u5F55\u91CC\u7684\u65E7\u4EE3\u4F1A\u8BA9\u540C id \u51FA\u73B0\n// \u5728\u4E24\u4E2A\u9879\u76EE\u76EE\u5F55 \u2192 \u5B98\u65B9 listArtifacts/stat \u7ACB\u523B\u62A5 duplicate\uFF08\u5B9E\u6D4B\u6839\u56E0\uFF09\uFF1B\n// - \u76EE\u5F55\u672C\u8EAB\u5DF2\u7531 locateSessionArtifacts \u6821\u9A8C\u8FC7 basename === encodeSegment(id)\n// \u4E14 id \u5F52\u5C5E\u6B63\u786E\uFF0C\u5220\u7684\u662F\u8BE5\u4F1A\u8BDD\u81EA\u5DF1\u7684\u76EE\u5F55\uFF0C\u4E0D\u662F\"\u7591\u4F3C\u522B\u4EBA\u7684\u6570\u636E\"\u3002\n// \u8FD4\u56DE { cleaned, leftover }\uFF1Acleaned=false + leftover \u540D\u5355\u7528\u4E8E\u5982\u5B9E\u56DE\u62A5\u6E05\u7406\u5931\u8D25\u3002\nasync function removeSourceDir(sessionDir) {\n let entries\n try { entries = await readdir(sessionDir) } catch (e) { return { cleaned: true, leftover: [] } }\n try {\n await rm(sessionDir, { recursive: true, force: true })\n } catch (e) {\n return { cleaned: false, leftover: entries }\n }\n return { cleaned: true, leftover: [] }\n}\n\n// \u6D3B\u8DC3\u5199\u8005\uFF08409\uFF09\u63D0\u793A\u30020.1.3 \u8D77\u5B98\u65B9 session handle \u662F\u300C\u5355\u5199\u8005\u300D\uFF1Aagent-loop\n// \u5728 resume \u4E00\u4E2A\u4F1A\u8BDD\u65F6\u5148 open(id,'write') \u53D6\u5199\u6240\u6709\u6743\u5E76\u6301\u6709\u5230 agent \u5378\u8F7D\uFF0C\u6240\u4EE5\n// \u5728 DSH \u91CC\u70B9\u5F00\u8FC7\u7684\u4F1A\u8BDD\u90FD\u5904\u4E8E\u88AB\u5360\u7528\u72B6\u6001\u3002runtime \u672A\u63D0\u4F9B\u4EFB\u4F55\u80FD\u8FDC\u7A0B\u91CA\u653E\u8BE5\u6240\u6709\u6743\n// \u7684\u516C\u5171 API\uFF08\u65E0 unloadSession / closeSession / evict\uFF09\uFF0C\u56E0\u6B64\u63D2\u4EF6\u4E0D\u80FD\u66FF\u7528\u6237\u89E3\u9501\uFF0C\n// \u53EA\u80FD\u5982\u5B9E\u8BF4\u660E\u53EF\u64CD\u4F5C\u7684\u81EA\u6551\u8DEF\u5F84\uFF0C\u5E76\u9760\u300C\u91CD\u8BD5\u300D\u8BA9\u7528\u6237\u5207\u8D70\u4F1A\u8BDD\u540E\u539F\u5730\u518D\u8BD5\u4E00\u6B21\u3002\nconst BUSY_MOVE_MESSAGE = '\u4F1A\u8BDD\u6B63\u88AB DSH \u6253\u5F00\uFF0C\u6682\u65F6\u65E0\u6CD5\u79FB\u52A8\uFF1B\u8BF7\u91CD\u542F DSH \u540E\u518D\u8BD5\u3002'\nconst BUSY_PURGE_MESSAGE = '\u4F1A\u8BDD\u6B63\u88AB DSH \u6253\u5F00\uFF0C\u6682\u65F6\u65E0\u6CD5\u5F7B\u5E95\u5220\u9664\uFF1B\u8BF7\u91CD\u542F DSH \u540E\u518D\u8BD5\u3002'\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(BUSY_MOVE_MESSAGE)\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(BUSY_PURGE_MESSAGE)\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, backupLogPath, artifacts }) {\n const original = await readFile(backupLogPath)\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\n//\n// 0.1.5 \u5173\u952E\u7EA6\u675F\uFF08\u5B9E\u6D4B\uFF09\uFF1A\u5B98\u65B9\u5728 open(id,'write') \u65F6\u4F1A\u4E3A\u5386\u53F2\u4EE3**\u53D1\u5E03\u5F53\u524D\u4EE3**\n// \uFF08v0/v2 \u2192 v3\uFF09\u4E14**\u4E0D\u5220\u65E7\u4EE3**\uFF0C\u4E00\u4E2A\u4F1A\u8BDD\u76EE\u5F55\u91CC\u53EF\u540C\u65F6\u6709 v0/v2/v3\uFF1B\u800C\u5B98\u65B9\n// listArtifacts/findLog \u4F1A\u8DE8\u9879\u76EE\u76EE\u5F55\u89E3\u6790\u540C\u4E00\u4E2A id\uFF0C**\u4EFB\u610F\u4E24\u4E2A\u76EE\u5F55\u540C\u65F6\u6301\u6709\u8BE5 id\n// \u7684\u65E5\u5FD7\uFF08\u65E0\u8BBA\u54EA\u4E00\u4EE3\uFF09\u90FD\u4F1A\u629B duplicate**\u3002\u6240\u4EE5\u642C\u8FD0\u5FC5\u987B\u662F\uFF1A\n// \u63A2\u6D4B\uFF08\u4F1A\u53D1\u5E03\u65B0\u4EE3\uFF0C\u5FC5\u987B\u5148\u505A\uFF09\u2192 \u5B9A\u4F4D \u2192 \u540C id \u6B8B\u7559\u6E05\u7406\n// \u2192 **\u628A\u6574\u4E2A\u6E90\u4F1A\u8BDD\u76EE\u5F55\u6539\u540D\u79FB\u5F00**\uFF08\u5BF9\u5B98\u65B9\u5F7B\u5E95\u4E0D\u53EF\u89C1\uFF0C\u800C\u4E0D\u662F\u53EA\u642C\u5355\u4E2A\u6587\u4EF6\uFF09\n// \u2192 \u76EE\u6807\u4FA7 create+append+\u6821\u9A8C \u2192 \u6210\u529F\u5219\u5220\u9664\u79FB\u5F00\u7684\u6E90\u76EE\u5F55\uFF0C\u5931\u8D25\u5219\u6574\u4F53\u6539\u56DE\u3002\nexport async function moveSessionToCwd({ sp, sid, header, canonical, events = [], inheritedEventCount = 0 }) {\n // 1) \u5199\u6240\u6709\u6743\u63A2\u6D4B\u653E\u6700\u524D\uFF1A\u5B83\u53EF\u80FD\u53D1\u5E03\u65B0\u4EE3\uFF0C\u4E4B\u540E\u5B9A\u4F4D\u5230\u7684\u624D\u662F\u6743\u5A01\u8DEF\u5F84\u3002\n // \u975E\u300C\u5DF2\u88AB\u5360\u7528\u300D\u7684\u63A2\u6D4B\u5931\u8D25\uFF08\u540E\u7AEF\u5F02\u5E38\u7B49\uFF09\u4E0D\u5728\u6B64\u5904\u7ACB\u5373\u4E0A\u629B\u2014\u2014\u5148\u770B\u80FD\u5426\u5B9A\u4F4D\uFF0C\n // \u5B9A\u4F4D\u4E5F\u5931\u8D25\u65F6\u5982\u5B9E\u56DE\u62A5\u5B9A\u4F4D\u9519\u8BEF\uFF08\u63D0\u793A\u66F4\u53EF\u64CD\u4F5C\uFF09\uFF0C\u80FD\u5B9A\u4F4D\u65F6\u624D\u62A5\u544A\u5199\u72B6\u6001\u672A\u77E5\u3002\n let probeError = null\n try {\n await ensureNoActiveWriter(sp, sid)\n } catch (e) {\n if (e && e.status === 409) throw e\n probeError = e\n }\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 if (probeError) {\n const error = new Error('\u65E0\u6CD5\u786E\u8BA4\u8BE5\u4F1A\u8BDD\u662F\u5426\u6B63\u88AB\u5199\u5165\uFF0C\u5DF2\u505C\u6B62\u79FB\u52A8\uFF1A' + String((probeError && probeError.message) || probeError))\n error.status = 409\n throw error\n }\n // \u6570\u636E\u5B89\u5168\u5B88\u536B\uFF08\u6700\u540E\u4E00\u5C42\u4FDD\u9669\uFF09\uFF1A\u6E90\u65E5\u5FD7\u660E\u663E\u4E0D\u53EA\u662F\u5934\u90E8\uFF08> 4KB\uFF09\uFF0C\u4F46\u6211\u4EEC\u62FF\u5230\u7684\u4E8B\u4EF6\n // \u662F\u7A7A\u7684 \u2014\u2014 \u8BF4\u660E\u8BFB\u53D6\u94FE\u8DEF\u51FA\u4E86\u95EE\u9898\u3002\u6B64\u65F6\u82E5\u7EE7\u7EED\uFF0C\u5C31\u662F\"\u7528\u7A7A\u4E8B\u4EF6\u91CD\u5EFA\u65E5\u5FD7\"\u518D\u5220\u6389\u6E90\u76EE\u5F55\uFF0C\n // \u7B49\u4E8E\u6E05\u7A7A\u4F1A\u8BDD\u30022026-09-10 \u5B9E\u6D4B\u8FC7\u4E00\u6B21\uFF080.1.5 \u8BFB\u53D6\u8FD4\u56DE\u7ED3\u6784\u53D8\u66F4\uFF09\uFF0C\u7EDD\u4E0D\u80FD\u518D\u53D1\u751F\u3002\n const HEADER_ONLY_MAX = 4096\n if (events.length === 0) {\n let sourceBytes = null\n try { sourceBytes = (await stat(artifacts.logPath)).size } catch (e) { sourceBytes = null }\n if (sourceBytes !== null && sourceBytes > HEADER_ONLY_MAX) {\n const error = new Error(\n `\u79FB\u52A8\u524D\u6821\u9A8C\u5931\u8D25\uFF1A\u6E90\u65E5\u5FD7\u6709 ${sourceBytes} \u5B57\u8282\u4F46\u8BFB\u5230 0 \u6761\u4E8B\u4EF6\uFF08\u8BFB\u53D6\u94FE\u8DEF\u5F02\u5E38\uFF09\uFF0C\u5DF2\u505C\u6B62\u79FB\u52A8\u4EE5\u514D\u4E22\u5931\u4F1A\u8BDD\u5185\u5BB9\u3002`,\n )\n error.status = 409\n error.code = 'DSM_MOVE_EMPTY_READ'\n throw error\n }\n }\n // 2) \u540C id \u8DE8\u76EE\u5F55\u6B8B\u7559\uFF1A\u7A7A\u58F3\u4E0E\u88AB\u53D6\u4EE3\u7684\u65E7\u4EE3\u76F4\u63A5\u56DE\u6536\uFF08\u4F1A\u4EE5 note \u56DE\u62A5\uFF09\uFF0C\n // \u7248\u672C\u76F8\u540C/\u66F4\u9AD8\u7684\u771F\u91CD\u590D\u62D2\u7EDD\u79FB\u52A8\u5E76\u7ED9\u51FA\u6E05\u5355\u3002\u5FC5\u987B\u5728 rename \u5907\u4EFD\u4E4B\u524D\u505A\u2014\u2014\n // rename \u540E\u6E90\u76EE\u5F55\u6682\u65F6\u53D8\u6210\u58F3\uFF0C\u4F1A\u5E72\u6270\u5224\u5B9A\u3002\n const siblings = await cleanSiblingCopies(artifacts.root, sid, artifacts.sessionDir, artifacts.generationVersion)\n if (siblings.real.length > 0) {\n const error = new Error(\n '\u65E0\u6CD5\u79FB\u52A8\uFF1A\u5728\u5176\u4ED6\u5DE5\u4F5C\u533A\u76EE\u5F55\u53D1\u73B0\u540C\u4E00\u4F1A\u8BDD\u7684\u65E5\u5FD7\u526F\u672C\uFF0C\u8BF7\u5148\u786E\u8BA4\u4FDD\u7559\u54EA\u4E00\u4EFD\uFF1A\\n' +\n siblings.real.map((p) => '\u00B7 ' + p).join('\\n')\n )\n error.status = 409\n error.code = 'DSM_SESSION_DUP_LOG'\n throw error\n }\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 // 3) \u628A**\u6574\u4E2A\u6E90\u4F1A\u8BDD\u76EE\u5F55**\u79FB\u51FA sessions \u6839\uFF0C\u800C\u4E0D\u662F\u53EA rename \u5F53\u524D\u4EE3\u90A3\u4E00\u4E2A\u6587\u4EF6\uFF1A\n // - \u53EA\u642C\u5355\u4E2A\u6587\u4EF6\u4F1A\u7559\u4E0B\u5E76\u5B58\u7684\u5176\u4ED6\u4EE3\uFF080.1.5 \u7684 v0/v2/v3 \u591A\u4EE3\u5171\u5B58\uFF09\uFF0C\n // - \u5728\u672C\u9879\u76EE\u76EE\u5F55\u91CC\u6539\u540D\u4E5F\u4E0D\u591F\uFF1A\u5B98\u65B9 listSessionDirs \u679A\u4E3E\u9879\u76EE\u76EE\u5F55\u4E0B\u7684**\u6240\u6709**\n // \u5B50\u76EE\u5F55\uFF08\u4E0D\u6309\u540D\u5B57\u8FC7\u6EE4\uFF09\uFF0ClistArtifacts \u4F1A\u8BFB\u6BCF\u4E2A\u76EE\u5F55\u91CC\u7684\u65E5\u5FD7\u5934\uFF0C\u4ECD\u4F1A\u770B\u5230\n // \u540C\u4E00\u4E2A id \u2192 duplicate\u3002\u5FC5\u987B\u79FB\u5230 root \u4E4B\u5916\uFF08\u4E0E\u56DE\u6536\u7AD9\u540C\u7EA7\uFF09\u624D\u5BF9\u5B98\u65B9\u626B\u63CF\n // \u5F7B\u5E95\u4E0D\u53EF\u89C1\u3002\n const backupRoot = join(dirname(artifacts.root), 'sessions-manager-move-backup')\n const backupDir = join(backupRoot, `${encodeSegmentFor(sid)}-${process.pid}-${Date.now()}`)\n await mkdir(backupRoot, { recursive: true })\n const backupLogPath = join(backupDir, basename(artifacts.logPath))\n await rename(artifacts.sessionDir, backupDir)\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, backupLogPath, 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\u6574\u4E2A\u6E90\u76EE\u5F55\u79FB\u56DE\u539F\u4F4D\uFF08\u591A\u4EE3\u65E5\u5FD7\u4E00\u8D77\u590D\u539F\uFF09\u3002\n await closeQuietly(writer)\n try { await rm(deriveSessionDir(artifacts.root, canonical, sid), { recursive: true, force: true }) } catch (_) {}\n try { await mkdir(dirname(artifacts.sessionDir), { recursive: true }) } catch (_) {}\n try { await rename(backupDir, artifacts.sessionDir) } 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 // 4) \u6210\u529F\uFF1A\u5220\u6389\u79FB\u5F00\u7684\u6E90\u76EE\u5F55\uFF08\u542B\u5168\u90E8\u65E7\u4EE3\u65E5\u5FD7\uFF09\u3002\u7559\u7740\u5B83\u7B49\u4E8E\u8BA9\u540C\u4E00\u4E2A id \u51FA\u73B0\u5728\n // \u4E24\u4E2A\u9879\u76EE\u76EE\u5F55\uFF0C\u4E0B\u4E00\u6B21 create/list \u7ACB\u523B\u88AB\u540E\u7AEF duplicate \u68C0\u67E5\u62D2\u7EDD\u3002\n const sourceCleanup = await removeSourceDir(backupDir)\n return {\n sessionDir: deriveSessionDir(artifacts.root, canonical, sid),\n sourceCleanup,\n reclaimedSiblings: siblings.superseded,\n }\n}\n", "// Lineage classification for sidebar grouping (issue #6).\n//\n// All inputs come from the public list() snapshot \u2014 header + sizeBytes \u2014 so\n// classification costs zero log decoding, keeping the zero-decode listing\n// design intact. Three kinds:\n// - subagent: official header.origin === 'subagent' (with parentSession and\n// a delegationDepth recursion budget, both persisted by the backend)\n// - fork branch: header.parentSession set without the subagent origin\n// - empty: the log holds only the generation header\n//\n// v3.7.0 (T1)\uFF1A\u4F53\u79EF\u6CD5**\u4E0D\u518D\u5BF9\u5916\u53D1\u5E03\u4EFB\u4F55\u7A7A\u767D\u7ED3\u8BBA**\u2014\u2014\u5B83\u5386\u53F2\u4E0A\u5C31\u6709\u5047\u9633\u6027\n// \uFF08\u957F cwd \u62AC\u9AD8\u9608\u503C\u628A\u6709\u5185\u5BB9\u7684\u5C0F\u65E5\u5FD7\u6807\u7A7A \u2192 \u4FA7\u680F\u8BEF\u9690\u85CF\uFF0C\u8BEF\u9690\u85CF\u4E25\u683C\u91CD\u4E8E\u8BEF\u95EA\u73B0\uFF09\u3002\n// isEmptyLogSize \u964D\u7EA7\u4E3A\u7EAF\u53C2\u8003\u5B9E\u73B0\uFF08\u9608\u503C\u5355\u6D4B\u4ECD\u9501\u7740\uFF09\uFF1B\u7A7A\u767D\u4E0E\u5426\u73B0\u5728\u53EA\u6709\u4E09\u4E2A\u6765\u6E90\uFF1A\n// \u89E3\u7801\u7CBE\u5224\u7684\u6210\u529F\u7ED3\u8BBA\uFF08true/false\uFF09\u3001\u7CBE\u5224\u89E3\u7801\u4E0A\u9650\u4E4B\u5916\u7684\u65E5\u5FD7\uFF08false = \u5FC5\u6709\u5185\u5BB9\uFF09\u3001\n// \u4EE5\u53CA\u672A\u77E5\uFF08null\uFF0C\u4EA4\u540E\u53F0 refine \u961F\u5217\u5224\u5B9A\uFF09\u3002\u89C1 index.js refineEmpty.\n\nconst EMPTY_BASE = 190\n\nexport function isEmptyLogSize(sizeBytes, cwd) {\n if (!Number.isFinite(sizeBytes) || sizeBytes < 0) return false\n const cwdLen = typeof cwd === 'string' ? cwd.length : 0\n return sizeBytes <= EMPTY_BASE + cwdLen\n}\n\n// ---- 0.1.3 \u7A7A\u4F1A\u8BDD\u5224\u5B9A\uFF08\u4E8B\u4EF6\u7C7B\u578B\u6CD5\uFF09---------------------------------------\n// 0.1.3 \u8D77\u65E5\u5FD7\u7ED3\u6784\u53D8\u4E86\uFF1A\u5934\u90E8\u5E27\u4E4B\u540E\u6052\u5B9A\u8DDF\u4E00\u5E27\u300C\u751F\u547D\u5468\u671F\u5143\u6570\u636E\u300D\n// \uFF08permission/preset / sandbox/mode / approval/policy\uFF0C\u5B9E\u6D4B\u7EA6 150B \u538B\u7F29\uFF09\uFF0C\n// \u4E14\u5934\u90E8\u65B0\u589E isSeeded / delegationDepth / agentPreset \u7B49\u5B57\u6BB5\uFF0C\u538B\u7F29\u540E\u6574\u672C\n// \u7EA6 300 + cwd.length \u5B57\u8282\u2014\u2014\u4E0A\u9762\u7684\u4F53\u79EF\u9608\u503C\uFF08190 + cwd\uFF0Calpha.2 \u57FA\u7EBF\uFF09\u5BF9\n// \u65B0\u683C\u5F0F\u6C38\u8FDC\u5224\u4E0D\u4E2D\uFF0C\u7A7A\u767D\u4F1A\u8BDD\u5168\u90E8\u6F0F\u5224\u3002\u538B\u7F29\u4F53\u79EF\u5BF9\u5934\u90E8\u6269\u5BB9/\u538B\u7F29\u5668\u53C2\u6570\u5929\u751F\n// \u654F\u611F\uFF0C\u4E0D\u518D\u6269\u9608\u503C\uFF0C\u6539\u4E3A\u6309\u4E8B\u4EF6\u7C7B\u578B\u5224\u5B9A\uFF1A\n// \u7A7A\u4F1A\u8BDD = \u5934\u90E8\u4E4B\u5916\u53EA\u51FA\u73B0\u751F\u547D\u5468\u671F\u5143\u6570\u636E\u4E8B\u4EF6\uFF0C\u6CA1\u6709\u4EFB\u4F55\u5185\u5BB9\u4E8B\u4EF6\u3002\n// \u89E3\u7801\u5728\u5BBF\u4E3B\u4FA7\u8FDB\u884C\uFF08index.js \u7684 refineEmptyLineage\uFF1A\u53EA\u5BF9\u538B\u7F29\u4F53\u79EF \u2264\n// EMPTY_DECODE_LIMIT \u7684\u5019\u9009\u8C03\u5B98\u65B9 inspectSession\uFF09\uFF0C\u8FD9\u91CC\u53EA\u653E\u7EAF\u51FD\u6570\u4E0E\u5E38\u91CF\u3002\n//\n// \u5DF2\u77E5\u7684\u751F\u547D\u5468\u671F\u4E8B\u4EF6\uFF080.1.3-alpha.1 \u5B9E\u6D4B\uFF0C\u4F1A\u8BDD\u521B\u5EFA\u65F6\u4E00\u6B21\u6027\u5199\u5165\uFF09\u3002'session'\n// \u662F\u5934\u90E8\u884C\u81EA\u8EAB\u2014\u2014inspectSession \u82E5\u628A\u5934\u90E8\u5F53\u4E8B\u4EF6\u56DE\u4F20\uFF0C\u5B83\u6052\u5B58\u5728\u4E8E\u6BCF\u672C\u65E5\u5FD7\uFF0C\n// \u653E\u884C\u4E0D\u524A\u5F31\u5224\u5B9A\uFF1B\u4EFB\u4F55\u672A\u77E5\u7C7B\u578B\u90FD\u6309\u5185\u5BB9\u5904\u7406\uFF08\u5B81\u53EF\u6F0F\u5224\uFF0C\u4E0D\u53EF\u9519\u6740\uFF09\u3002\nexport const EMPTY_DECODE_LIMIT = 8192\n\nconst LIFECYCLE_EVENT_TYPES = new Set([\n 'session',\n 'permission/preset',\n 'sandbox/mode',\n 'approval/policy',\n])\n\n/**\n * @param {Array<string|undefined>} types \u4E8B\u4EF6\u7C7B\u578B\u5E8F\u5217\uFF08\u4E0D\u542B\u5934\u90E8\u4E5F\u53EF\uFF0C\u542B\u5934\u90E8\n * \u4E5F\u53EF\u2014\u2014'session' \u5728\u653E\u884C\u6E05\u5355\u91CC\uFF09\u30020 \u6761 = \u5934\u90E8\u4E4B\u5916\u65E0\u4EFB\u4F55\u4E8B\u4EF6\uFF0C\u89C6\u4E3A\u7A7A\u3002\n * @returns {boolean}\n */\nexport function isEmptyEventTypes(types) {\n if (!Array.isArray(types)) return false\n for (const t of types) {\n if (typeof t !== 'string' || !LIFECYCLE_EVENT_TYPES.has(t)) return false\n }\n return true\n}\n\n// Structural lineage only (T1): a record is produced when the session is a\n// subagent or a fork branch; `empty` is published as null (= not yet judged)\n// and refined in the background. Ordinary top-level sessions return null \u2014\n// they only ever gain an entry once a real decode says empty:true.\nexport function classifyLineage(header) {\n if (!header || typeof header !== 'object') return null\n const origin = header.origin === 'subagent' ? 'subagent' : null\n const parentSession = typeof header.parentSession === 'string' && header.parentSession\n ? header.parentSession\n : null\n const delegationDepth = Number.isSafeInteger(header.delegationDepth) && header.delegationDepth > 0\n ? header.delegationDepth\n : 0\n if (!origin && !parentSession) return null\n return { origin, parentSession, delegationDepth, empty: null }\n}\n\n// \u7A7A\u767D\u7CBE\u5224\u5019\u9009\uFF1A\u538B\u7F29\u4F53\u79EF\u5728\u89E3\u7801\u4E0A\u9650\u5185\u7684\u5C0F\u65E5\u5FD7\u3002sizeBytes \u7F3A\u5931\uFF08legacy \u5217\u8868\n// \u5FEB\u7167\u6CA1\u6709\u8BE5\u89C2\u6D4B\uFF09\u65F6\u8FD4\u56DE false \u2014\u2014 \u4E0E\u5386\u53F2\u884C\u4E3A\u4E00\u81F4\uFF1Alegacy \u4E16\u4EE3\u7A7A\u767D\u5224\u5B9A\u4E0D\u751F\u6548\u3002\nexport function emptyScanCandidate(sizeBytes) {\n return Number.isFinite(sizeBytes) && sizeBytes <= EMPTY_DECODE_LIMIT\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["mkdir", "readFile", "readdir", "rename", "rm", "stat", "writeFile", "basename", "dirname", "join", "readFileSync", "homedir", "name", "mkdir", "writeFile", "readFileSync", "homedir", "join", "isSafeSessionId", "name", "rename", "list", "mkdir", "rename", "writeFile", "readFileSync", "randomBytes", "homedir", "join", "randomSuffix", "name", "nameKey", "readFileSync", "mkdir", "rename", "writeFile", "homedir", "join", "item", "readFileSync", "mkdir", "rename", "writeFile", "homedir", "join", "SCHEMA_VERSION", "isSafeId", "normalizeStore", "join", "name", "mkdir", "rename", "writeFile", "readFileSync", "homedir", "join", "DEFAULT_DIR", "isFresh", "stat", "mkdir", "rename", "writeFile", "join", "mkdir", "readFile", "rename", "writeFile", "dirname", "join", "MAX_ENTRIES", "normalizeEntry", "mergeEntries", "readdir", "stat", "join", "join", "name", "stat", "readdir", "join", "name", "mkdir", "readFile", "readdir", "rename", "rm", "stat", "writeFile", "basename", "dirname", "join", "readdir", "join", "stat", "name", "rm", "closeQuietly", "readFile", "mkdir", "writeFile", "rename", "dirname", "basename", "join", "homedir", "isSafeSessionId", "stat", "readFileSync", "mkdir", "writeFile", "rename", "entry", "store", "error", "basename", "dirname", "readFile", "readdir", "rm", "stat2"]
|
|
7
7
|
}
|