dsh-memoir 0.9.2 → 0.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +26 -15
- package/README.md +26 -15
- package/SESSION_RECOVERY.md +11 -8
- package/lib/client.js +6 -6
- package/lib/client.js.map +1 -1
- package/lib/index.js +3 -0
- package/lib/selector.d.ts +15 -10
- package/lib/selector.js +62 -30
- package/lib/store.d.ts +4 -1
- package/lib/store.js +115 -58
- package/lib/tools.d.ts +1 -1
- package/lib/tools.js +1 -1
- package/package.json +23 -23
- package/scripts/repair-session-receipts.mjs +80 -10
package/lib/client.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/client/index.tsx", "<define:__MEMOIR_PACKAGE_INFO__>", "../src/client/api.ts", "../src/client/i18n.ts", "../src/client/panel.tsx", "../src/client/about.tsx", "../src/client/announcement.ts", "../src/host/languages.ts", "../src/client/view-model.ts", "../src/client/styles.ts", "../src/client/native-navigation.ts", "../src/client/sidebar.tsx", "../src/client/plugin-settings.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * Browser-half entry for the DSH 0.2.0 client architecture.\n *\n * The alpha shell removed dsh-client-runtime and exposes additive UI through\n * domain-owned slots. Memoir therefore registers as a native Conversation\n * view and a native Settings section. No CSS-module selector or DOM takeover\n * is used for mounting; the host remains the sole owner of layout and view\n * navigation.\n */\n\nimport type { Context } from '@deepseek-ai/cordis'\nimport type { SessionListState } from '@deepseek-ai/dsh-api-session-controller/client'\nimport type { ConvViewProps } from '@deepseek-ai/dsh-client-ui-conversation/client'\nimport type { UseSessions } from '@deepseek-ai/dsh-client-ui-session/client'\nimport type { PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { SessionId } from '@deepseek-ai/dsh-session/types'\nimport type {} from '@deepseek-ai/dsh-api-session-controller/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-renderer/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-session/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-workspace/client'\nimport { useEffect } from 'react'\nimport { MemoirApi } from './api.js'\nimport { makeT } from './i18n.js'\nimport { MemoirPanel } from './panel.jsx'\nimport { mountPanelStyles } from './styles.js'\nimport { mainWorkspaceCwd } from './native-navigation.js'\nimport { watchSidebar } from './sidebar.js'\nimport { watchPluginSettings } from './plugin-settings.js'\n\ntype NativeGlobalProps = { useSessions: UseSessions }\ntype NativeSettingsSectionProps = PropsRuntime<'settings.section'> & NativeGlobalProps\n\n/** Required alpha services; package.json injects the packages that provide them. */\nexport const inject = ['uiWorkspace', 'slots']\n\n/** Native per-session Conversation view. */\nfunction ConversationMemoirView({\n api,\n ctx,\n t,\n sessionId,\n useSessions,\n viewRequest,\n completeViewRequest,\n openView,\n}: ConvViewProps & NativeGlobalProps & {\n api: MemoirApi\n ctx: Context\n t: (key: string) => string\n}) {\n const cwd = useSessions((snapshot: SessionListState) => snapshot.byId[sessionId]?.cwd ?? '')\n\n // A future native deep-link may select Memoir with an opaque focus token.\n // The current panel has no focus-addressed rows, so acknowledge it once to\n // avoid retaining a stale one-shot request in the Conversation store.\n useEffect(() => {\n if (viewRequest?.view === 'memoir') completeViewRequest()\n }, [viewRequest, completeViewRequest])\n\n return (\n <div\n className=\"memoir-native-view\"\n data-dsh-plugin=\"memoir\"\n data-dsh-part=\"conversation-view\"\n data-conversation-composer-overlay=\"\"\n >\n <MemoirPanel\n api={api}\n cwd={cwd}\n t={t}\n announceOnOpen\n openSource={(sourceSessionId) => {\n if (sourceSessionId === sessionId) openView('chat', '')\n ctx.uiWorkspace.openSession(sourceSessionId as SessionId)\n }}\n />\n </div>\n )\n}\n\n/** Root-scoped Settings page; it also preserves global-memory access with no session selected. */\nfunction SettingsMemoirSection({\n api,\n ctx,\n t,\n close,\n useSessions,\n}: NativeSettingsSectionProps & {\n api: MemoirApi\n ctx: Context\n t: (key: string) => string\n}) {\n const cwd = useSessions(mainWorkspaceCwd)\n return (\n <div className=\"memoir-settings-section\" data-dsh-plugin=\"memoir\" data-dsh-part=\"settings-section\">\n <MemoirPanel\n api={api}\n cwd={cwd}\n t={t}\n onClose={close}\n openSource={(sourceSessionId) => {\n close()\n ctx.uiWorkspace.openSession(sourceSessionId as SessionId)\n }}\n />\n </div>\n )\n}\n\n/**\n * Register the native alpha surfaces.\n * @param rawCtx - DSH alpha client root context.\n */\nexport function apply(rawCtx: Context): void {\n const ctx = rawCtx\n const api = new MemoirApi()\n const t = makeT(document)\n\n ctx.effect(() => mountPanelStyles(), 'dsh-memoir: native alpha styles')\n ctx.effect(() => watchSidebar(ctx, api, t), 'dsh-memoir: optional sidebar')\n ctx.effect(() => watchPluginSettings(ctx, api, t), 'dsh-memoir: optional plugin settings')\n ctx.effect(() => {\n let disposers: Array<() => void> = []\n const register = (): void => {\n for (const dispose of disposers.splice(0)) dispose()\n disposers = [\n ctx.slots.inject('conversation.view', () => ctx.slots.register({\n name: 'conversation.view',\n id: 'memoir',\n order: 20,\n label: () => t('entry.label'),\n }, props => <ConversationMemoirView {...props} api={api} ctx={ctx} t={t} />)),\n ctx.slots.inject('settings.section', () => ctx.slots.register({\n name: 'settings.section',\n id: 'memoir',\n order: 25,\n label: () => t('entry.label'),\n }, props => <SettingsMemoirSection {...props} api={api} ctx={ctx} t={t} />)),\n ]\n }\n\n register()\n // Memoir owns a tiny bilingual dictionary rather than importing the\n // unpublished alpha locale package. Re-registering bumps both native\n // rosters so their labels switch with the shell language immediately.\n const observer = new MutationObserver(register)\n observer.observe(document.documentElement, { attributes: true, attributeFilter: ['lang'] })\n return () => {\n observer.disconnect()\n for (const dispose of disposers.splice(0)) dispose()\n }\n }, 'dsh-memoir: native alpha slots')\n}\n", "{\"version\":\"0.9.2\",\"hostRange\":\">=0.2.0-rc.1 <0.3.0-0 || >=0.2.1-alpha.1 <0.2.1\",\"sdkBaseline\":\"0.2.0-rc.1\"}", "/**\n * Browser API client for the host /api/dsh-memoir routes. The only data path\n * the panel uses \u2014 same-origin fetch, JSON envelope { ok, value | error }.\n * The fetch implementation is injectable for tests.\n */\n\nimport type { MemoirStatus, SectionKey } from './types.ts'\nimport type { MemoirLanguage } from '../host/languages.js'\n\n/** Error carrying the route's JSON error message. */\nexport class MemoirApiError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'MemoirApiError'\n }\n}\n\ninterface EnvelopeResponse {\n status: number\n ok: boolean\n json(): Promise<unknown>\n}\n\n/** Parse the envelope or throw a MemoirApiError (transport or route error). */\nexport async function readEnvelope(response: EnvelopeResponse): Promise<unknown> {\n let body: unknown\n try {\n body = await response.json()\n } catch {\n throw new MemoirApiError(`HTTP ${response.status}: invalid JSON response`)\n }\n if (typeof body !== 'object' || body === null || (body as { ok?: boolean }).ok !== true) {\n const record = body as { error?: { message?: string } } | null\n const message = record && typeof record.error === 'object' && record.error !== null && typeof record.error.message === 'string'\n ? record.error.message\n : `HTTP ${response.status}`\n throw new MemoirApiError(message)\n }\n return (body as { value: unknown }).value\n}\n\n/** Query-string helper (omits undefined/empty values). */\nexport function query(params: Record<string, string | undefined>): string {\n const search = new URLSearchParams()\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== '') search.set(key, String(value))\n }\n const text = search.toString()\n return text === '' ? '' : '?' + text\n}\n\n/** One memory entry as the panel sees it over the wire. */\nexport interface WireEntry {\n id: string\n section: SectionKey\n title?: string\n content: string\n time: number\n source?: { sessionId?: string; turnId?: number }\n /** Legacy v3 wire alias; prefer source.sessionId. */\n sessionId?: string\n importance?: number\n pinned?: boolean\n status?: MemoirStatus\n supersedes?: string[]\n tags?: string[]\n}\n\nexport interface WireProject {\n key: string\n path: string\n title: string\n updatedAt: number\n entries: WireEntry[]\n /** Lifecycle totals before any route-level status/section filter. */\n stats?: { total: number; active: number; superseded: number; archived: number }\n}\n\n/** The host /diagnostics payload (v0.4 observability, v0.4.2 extended). */\nexport interface WireDiagnostics {\n snapshotPersistence?: {\n restored: number; created: number; failures: number\n lastStatus: 'idle' | 'restored' | 'created' | 'volatile'\n lastError: 'invalid-record' | 'record-too-large' | 'unavailable' | null\n }\n autoDistill?: {\n counts: Partial<Record<string, number>>\n writes?: Record<'persisted' | 'afterReminder' | 'failed' | 'canceled' | 'needsResolution' | 'receiptFailed', number>\n workedTurns: number\n agents: number\n last: { outcome: string; at: number; turn: number; toolCalls: number } | null\n }\n storeRevision: number\n snapshotEpoch: number\n cache: {\n revision: number\n epoch: number\n loads: number\n hits: number\n misses: number\n hitRate: number\n fileReads: number\n statProbes: number\n corruptBackups: number\n renders: number\n renderComputes: number\n renderHitRate: number\n lastLoadMs?: number\n }\n snapshotCount: number\n snapshotMax: number\n hotMemory: { selected: number; total: number; estimatedTokens: number } | null\n /** v0.4.2: retrieval index / query cache / last query. */\n retrieval: {\n index: { docs: number; terms: number; epoch: number } | null\n cache: { hits: number; misses: number; evictions: number; hitRate: number; size: number; capacity: number }\n lastQuery: { query: string; latencyMs: number; candidates: number; returned: number; at: number } | null\n }\n /** v0.4.2: the most recently frozen session snapshot. */\n snapshot: { hash: string; createdAt: number; storeRevision: number } | null\n config: {\n language: MemoirLanguage\n announceToAgent: boolean\n autoDistill: boolean\n autoDistillEvery: number\n autoDistillCooldownMin: number\n autoDistillMinTools: number\n hotMemoryTokens: number\n hotMemoryMaxTokens: number\n readDefaultLimit: number\n readMaxLimit: number\n sessionSnapshotMax: number\n queryCacheSize: number\n }\n}\n\n/** Full live runtime settings managed by both GUI settings surfaces. */\nexport interface WireMemoirSettings {\n language: MemoirLanguage\n announceToAgent: boolean\n autoDistill: boolean\n autoDistillEvery: number\n autoDistillCooldownMin: number\n autoDistillMinTools: number\n hotMemoryTokens: number\n hotMemoryMaxTokens: number\n readDefaultLimit: number\n readMaxLimit: number\n sessionSnapshotMax: number\n queryCacheSize: number\n}\n\nexport interface WireMemoirSettingsSnapshot {\n settings: WireMemoirSettings\n source: 'profile' | 'web'\n}\n\n/** v0.5.3 source compatibility aliases. */\nexport type WireAutoDistillSettings = WireMemoirSettings\nexport type WireAutoDistillSettingsSnapshot = WireMemoirSettingsSnapshot\n\n/** One ranked /search hit (v0.4.2: shared RetrievalEngine order). */\nexport interface WireSearchResult {\n projectPath: string\n entry: WireEntry\n score: number\n}\n\nexport type WireRecordResolution = 'update' | 'supersede' | 'force-record'\nexport type WireRecordAction = 'recorded' | 'needs-resolution' | 'updated' | 'superseded' | 'force-recorded'\n\nexport interface WireSimilarityCandidate {\n kind: 'duplicate' | 'conflict'\n score: number\n components: { bm25: number; title: number; tokenJaccard: number }\n reasons: string[]\n entry: WireEntry\n projectPath: string\n}\n\nexport interface WireRecordResult {\n action: WireRecordAction\n recorded: boolean\n entry?: WireEntry\n candidates: WireSimilarityCandidate[]\n}\n\n/** The /hot-memory inspector payload (v0.4.2). */\nexport interface WireHotMemory {\n text: string\n selected: WireEntry[]\n total: number\n estimatedTokens: number\n}\n\nexport interface RecordPayload {\n path: string\n section: SectionKey\n title?: string\n content: string\n importance?: number\n pinned?: boolean\n supersedes?: string[]\n tags?: string[]\n resolution?: WireRecordResolution\n targetId?: string\n}\n\ntype FetchLike = (input: string, init?: RequestInit) => Promise<EnvelopeResponse>\n\n/** The browser half's only data entry point. */\nexport class MemoirApi {\n private readonly fetchImpl: FetchLike\n\n /**\n * @param fetchImpl - injectable fetch (defaults to globalThis.fetch).\n */\n constructor(fetchImpl?: FetchLike) {\n this.fetchImpl = fetchImpl ?? ((...args) => globalThis.fetch(...args) as Promise<EnvelopeResponse>)\n }\n\n /** Read one project's memory (empty project shape when unknown). */\n async project(path: string, options: { section?: SectionKey; query?: string; status?: MemoirStatus | 'all' } = {}): Promise<{ project: WireProject }> {\n const response = await this.fetchImpl('/api/dsh-memoir/project' + query({ path, ...options }))\n return readEnvelope(response) as Promise<{ project: WireProject }>\n }\n\n /** Read the cross-project global index. */\n async global(options: { section?: SectionKey; query?: string; status?: MemoirStatus | 'all' } = {}): Promise<{ projects: WireProject[] }> {\n const response = await this.fetchImpl('/api/dsh-memoir/global' + query({ ...options }))\n return readEnvelope(response) as Promise<{ projects: WireProject[] }>\n }\n\n /** Read runtime diagnostics (cache hit rates, snapshot/hot-memory stats). */\n async diagnostics(path?: string): Promise<WireDiagnostics> {\n const response = await this.fetchImpl('/api/dsh-memoir/diagnostics' + query({ path }))\n return readEnvelope(response) as Promise<WireDiagnostics>\n }\n\n /** Read all live settings and whether they come from Web overrides. */\n async settings(): Promise<WireMemoirSettingsSnapshot> {\n const response = await this.fetchImpl('/api/dsh-memoir/settings')\n return readEnvelope(response) as Promise<WireMemoirSettingsSnapshot>\n }\n\n /** Persist and immediately apply the complete runtime policy. */\n async updateSettings(settings: WireMemoirSettings): Promise<WireMemoirSettingsSnapshot> {\n const response = await this.fetchImpl('/api/dsh-memoir/settings', {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(settings),\n })\n return readEnvelope(response) as Promise<WireMemoirSettingsSnapshot>\n }\n\n /** Remove the Web override and restore the profile defaults captured at boot. */\n async resetSettings(): Promise<WireMemoirSettingsSnapshot> {\n const response = await this.fetchImpl('/api/dsh-memoir/settings', {\n method: 'DELETE',\n headers: { 'content-type': 'application/json' },\n body: '{}',\n })\n return readEnvelope(response) as Promise<WireMemoirSettingsSnapshot>\n }\n\n /**\n * Ranked search over the host RetrievalEngine (v0.4.2) \u2014 the same ranking\n * memoir_read uses, so the GUI search and the agent recall never diverge.\n */\n async search(options: { scope: 'project' | 'global' | 'all'; path?: string; section?: SectionKey; query: string; limit?: number; status?: MemoirStatus | 'all' }): Promise<{ results: WireSearchResult[] }> {\n const response = await this.fetchImpl('/api/dsh-memoir/search' + query({\n scope: options.scope,\n path: options.path,\n section: options.section,\n query: options.query,\n limit: options.limit === undefined ? undefined : String(options.limit),\n status: options.status,\n }))\n return readEnvelope(response) as Promise<{ results: WireSearchResult[] }>\n }\n\n /** Hot-memory preview for one workspace (the inspector). */\n async hotMemory(path: string): Promise<{ hotMemory: WireHotMemory | null }> {\n const response = await this.fetchImpl('/api/dsh-memoir/hot-memory' + query({ path }))\n return readEnvelope(response) as Promise<{ hotMemory: WireHotMemory | null }>\n }\n\n /** Record one entry (host regenerates PROJECT_MEMORY.md). */\n async record(payload: RecordPayload): Promise<WireRecordResult> {\n const response = await this.fetchImpl('/api/dsh-memoir/entries', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n })\n return readEnvelope(response) as Promise<WireRecordResult>\n }\n\n /** Delete one entry by id. */\n async remove(payload: { path: string; id: string }): Promise<{ removed: boolean }> {\n const response = await this.fetchImpl('/api/dsh-memoir/entries', {\n method: 'DELETE',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n })\n return readEnvelope(response) as Promise<{ removed: boolean }>\n }\n\n /** Update entry content or lifecycle metadata without deleting. */\n async update(payload: { path: string; id: string; section?: SectionKey; title?: string | null; content?: string; importance?: number; pinned?: boolean; status?: MemoirStatus; supersedes?: string[]; tags?: string[] }): Promise<{ entry: WireEntry | null; updated: boolean }> {\n const response = await this.fetchImpl('/api/dsh-memoir/entries', {\n method: 'PATCH',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n })\n return readEnvelope(response) as Promise<{ entry: WireEntry | null; updated: boolean }>\n }\n}\n", "/**\n * Bilingual surface copy (zh-first). Pure \u2014 no DOM, unit-testable.\n * The shell owns <html lang>; the panel reads it at render time.\n */\n\nexport type Lang = 'zh' | 'en'\n\nexport const dictionaries: Record<Lang, Record<string, string>> = {\n zh: {\n 'guide.label': '\u8BB0\u5FC6\u63D2\u4EF6\u4FE1\u606F\u4E0E\u5FEB\u6377\u5165\u53E3',\n 'guide.repository': 'GitHub \u9879\u76EE',\n 'guide.settings': '\u6253\u5F00\u8BB0\u5FC6\u8BBE\u7F6E',\n 'sidebar.description': '\u8FB9\u5BF9\u8BDD\u8FB9\u67E5\u770B\u9879\u76EE\u8BB0\u5FC6\u3001Hot Memory \u4E0E\u6765\u6E90\u3002',\n 'about.title': '\u5173\u4E8E\u4E0E\u5E2E\u52A9',\n 'notice.title': '\u672C\u7248\u66F4\u65B0',\n 'notice.dismiss': '\u77E5\u9053\u4E86',\n 'notice.reopen': '\u67E5\u770B\u672C\u7248\u66F4\u65B0',\n 'notice.compat': '0.9.2 \u9884\u9002\u914D DSH 0.2.1-alpha.1\uFF0C\u4FDD\u7559 0.2.0-rc.1 / rc.2 \u652F\u6301\uFF1B\u4FEE\u590D\u8DE8\u9879\u76EE\u53EC\u56DE\u4E2D\u5DF2\u5C55\u793A\u8BB0\u5FC6\u88AB\u8BEF\u62A5\u4E3A\u622A\u65AD\u7684\u95EE\u9898\u3002',\n 'notice.features': '\u5347\u7EA7\u963B\u6B62\u65B0\u589E\u5F02\u5E38\uFF0C\u4F46\u4E0D\u4F1A\u81EA\u52A8\u6539\u5199\u65E7\u65E5\u5FD7\u3002\u65E7\u4F1A\u8BDD\u4ECD\u6253\u4E0D\u5F00\u65F6\uFF0C\u8BF7\u6309 README \u7684\u5386\u53F2\u6062\u590D\u8BF4\u660E\uFF1A\u5148\u53EA\u8BFB\u68C0\u67E5\uFF0C\u5168\u90E8\u5BBF\u4E3B\u9000\u51FA\u5E76\u5907\u4EFD\u540E\uFF0C\u518D\u663E\u5F0F\u6267\u884C\u6062\u590D\u3002',\n 'notice.privacy': '\u516C\u544A\u968F\u5305\u5185\u7F6E\uFF0C\u4E0D\u8054\u7F51\u3001\u4E0D\u6539\u8BB0\u5FC6\u3002\u786E\u8BA4\u540E\u672C\u7248\u672C\u4E0D\u518D\u81EA\u52A8\u663E\u793A\uFF1B\u53EF\u5728\u201C\u5173\u4E8E\u4E0E\u5E2E\u52A9\u201D\u91CD\u770B\u3002',\n 'about.host': '\u652F\u6301\u7684 DSH \u8303\u56F4',\n 'about.baseline': '\u5F00\u53D1 SDK \u57FA\u7EBF',\n 'about.maintainer': '\u7EF4\u62A4\u8005',\n 'about.repositoryNote': '\u4EE5\u4E0B\u662F\u8BB0\u5FC6\u63D2\u4EF6\u7684\u9879\u76EE\u4ED3\u5E93\uFF0C\u4E0D\u662F\u5F53\u524D\u4F1A\u8BDD\u5DE5\u4F5C\u533A\u7684 Git \u4ED3\u5E93\u3002',\n 'about.links': '\u63D2\u4EF6\u9879\u76EE\u4E0E\u5E2E\u52A9\u94FE\u63A5',\n 'about.readmeFile': 'README.md',\n 'about.docs': '\u4F7F\u7528\u6587\u6863',\n 'about.releases': '\u7248\u672C\u4E0E\u66F4\u65B0\u65E5\u5FD7',\n 'about.issues': '\u95EE\u9898\u53CD\u9988',\n 'about.updates': '\u66F4\u65B0\u8BF7\u4F7F\u7528\u5BBF\u4E3B\u63D2\u4EF6\u7BA1\u7406\u5668\uFF1B\u5B89\u88C5\u524D\u6838\u5BF9\u76EE\u6807\u7248\u672C\u7684 DSH \u8981\u6C42\uFF0C\u9884\u53D1\u5E03\u901A\u9053\u4E5F\u9700\u5339\u914D\u3002\u672C\u9762\u677F\u4E0D\u81EA\u52A8\u8054\u7F51\u68C0\u67E5\u6216\u5347\u7EA7\uFF0C\u4E0D\u4E0A\u4F20\u5DE5\u4F5C\u533A\u8DEF\u5F84\u6216\u8BB0\u5FC6\u5185\u5BB9\u3002',\n 'snapshot.disk': '\u4F1A\u8BDD\u5FEB\u7167\u6301\u4E45\u5316',\n 'snapshot.restored': '\u4ECE\u78C1\u76D8\u6062\u590D',\n 'snapshot.created': '\u5EFA\u7ACB\u65B0\u57FA\u7EBF',\n 'snapshot.failures': '\u6301\u4E45\u5316\u5931\u8D25',\n 'snapshot.last': '\u6700\u8FD1\u78C1\u76D8\u64CD\u4F5C',\n 'snapshot.idle': '\u5C1A\u672A\u8BFB\u53D6',\n 'snapshot.volatile': '\u964D\u7EA7\u4E3A\u8FDB\u7A0B\u5185\u5FEB\u7167',\n 'snapshot.degraded': '\u65E0\u6CD5\u4FDD\u8BC1\u91CD\u542F\u540E\u524D\u7F00\u4E00\u81F4\uFF1B\u8BF7\u68C0\u67E5\u5FEB\u7167\u5B58\u50A8',\n 'snapshot.invalid-record': '\u683C\u5F0F\u6216\u6821\u9A8C\u4E0D\u7B26\uFF0C\u539F\u6587\u4EF6\u5DF2\u4FDD\u7559',\n 'snapshot.record-too-large': '\u8D85\u51FA\u5FEB\u7167\u5927\u5C0F\u4E0A\u9650',\n 'snapshot.unavailable': '\u8BFB\u5199\u4E0D\u53EF\u7528\u6216\u9501\u8D85\u65F6',\n 'snapshot.retention': 'LRU \u4EC5\u9650\u5236\u5185\u5B58\uFF1B\u78C1\u76D8\u5FEB\u7167\u65E0\u81EA\u52A8\u8FC7\u671F\u3002\u65E7\u4F1A\u8BDD\u9996\u6B21\u5347\u7EA7\u53EF\u80FD\u5EFA\u7ACB\u4E00\u6B21\u65B0\u57FA\u7EBF\uFF1B\u4E0D\u4FDD\u8BC1\u670D\u52A1\u7AEF\u7F13\u5B58\u547D\u4E2D\u3002',\n 'distill.title': '\u81EA\u52A8\u84B8\u998F\u751F\u547D\u5468\u671F',\n 'distill.worked': '\u7D2F\u8BA1\u6709\u6548\u5DE5\u4F5C\u56DE\u5408',\n 'distill.agents': '\u8DDF\u8E2A Agent',\n 'distill.note': '\u672C\u6B21\u8FDB\u7A0B\u5185\u7EDF\u8BA1\uFF1B\u63D0\u9192\u6210\u529F\u4E0D\u4EE3\u8868\u8BB0\u5FC6\u5DF2\u5199\u5165\u3002\u505C\u7528\u81EA\u52A8\u84B8\u998F\u540E\u4ECD\u53EF\u624B\u52A8\u8BB0\u5F55\u3002',\n 'distill.last': '\u6700\u8FD1\u51B3\u7B56',\n 'distill.disabled': '\u81EA\u52A8\u84B8\u998F\u5DF2\u5173\u95ED',\n 'distill.subagent': '\u5B50\u4EE3\u7406\u8DF3\u8FC7',\n 'distill.aborted': '\u4E2D\u6B62\u8DF3\u8FC7',\n 'distill.idle': '\u65E0\u5DE5\u5177\u6D3B\u52A8',\n 'distill.recorded': '\u672C\u56DE\u5408\u5DF2\u4FDD\u5B58\u8BB0\u5FC6\u6216\u66F4\u65B0',\n 'distill.unavailable': '\u4F1A\u8BDD\u6D3B\u52A8\u6295\u5F71\u4E0D\u53EF\u7528\uFF0C\u5DF2\u5B89\u5168\u8DF3\u8FC7',\n 'writes.title': '\u5B9E\u9645\u5199\u5165\u7ED3\u679C',\n 'writes.persisted': '\u5DF2\u4FDD\u5B58\u5199\u5165 / \u66F4\u65B0',\n 'writes.afterReminder': '\u5176\u4E2D\uFF1A\u63D0\u9192\u6240\u5728\u56DE\u5408\u540E\u7EED\u4FDD\u5B58',\n 'writes.failed': '\u5DE5\u5177\u7ED3\u679C\u5931\u8D25',\n 'writes.canceled': '\u5DE5\u5177\u7ED3\u679C\u53D6\u6D88',\n 'writes.needsResolution': '\u76F8\u4F3C\u8BB0\u5FC6\u5F85\u786E\u8BA4\uFF08\u672A\u5199\u5165\uFF09',\n 'writes.receiptFailed': '\u5DF2\u4FDD\u5B58\u4F46\u56DE\u5408\u56DE\u6267\u4E0D\u53EF\u7528',\n 'writes.note': '\u4EC5\u7EDF\u8BA1\u672C\u8FDB\u7A0B\u5185 Agent \u5DE5\u5177\uFF1B\u4FDD\u5B58\u540E\u4ECD\u53EF\u80FD\u88AB\u5BBF\u4E3B\u5224\u5B9A\u53D6\u6D88\uFF0C\u56E0\u6B64\u8BA1\u6570\u53EF\u91CD\u53E0\u3002\u4FDD\u5B58\u4E0E\u63D0\u9192\u7684\u5173\u8054\u4E0D\u8BC1\u660E\u56E0\u679C\u6216\u8BB0\u5FC6\u5185\u5BB9\u6B63\u786E\u3002',\n 'distill.duplicate': '\u91CD\u590D\u6216\u8FC7\u671F\u56DE\u5408',\n 'distill.interval': '\u672A\u8FBE\u56DE\u5408\u95F4\u9694',\n 'distill.tools': '\u672A\u8FBE\u5DE5\u5177\u8C03\u7528\u9608\u503C',\n 'distill.cooldown': '\u51B7\u5374\u4E2D',\n 'distill.queued': '\u5DF2\u6392\u5165\u72EC\u7ACB\u6536\u5C3E\u56DE\u5408',\n 'distill.distillation': '\u8BB0\u5FC6\u6536\u5C3E\u56DE\u5408\uFF0C\u4E0D\u518D\u89E6\u53D1\u84B8\u998F',\n 'distill.failed': '\u63D0\u9192\u63D0\u4EA4\u5931\u8D25',\n 'entry.label': '\u8BB0\u5FC6',\n 'entry.tooltip': '\u6253\u5F00\u8BB0\u5FC6\u9762\u677F\uFF08\u9879\u76EE\u8BB0\u5FC6 / \u5168\u5C40\u8BB0\u5FC6\uFF09',\n 'panel.title': '\u8BB0\u5FC6 Memoir',\n 'panel.close': '\u5173\u95ED',\n 'panel.refresh': '\u5237\u65B0',\n 'surface.navigation': '\u8BB0\u5FC6\u529F\u80FD\u533A',\n 'surface.browse': '\u8BB0\u5FC6\u6D4F\u89C8',\n 'surface.settings': '\u8BB0\u5FC6\u8BBE\u7F6E',\n 'surface.hotMemory': 'Hot Memory',\n 'surface.diagnostics': '\u8BCA\u65AD',\n 'browse.scope': '\u8BB0\u5FC6\u8303\u56F4',\n 'tab.project': '\u9879\u76EE\u8BB0\u5FC6',\n 'tab.global': '\u5168\u5C40\u8BB0\u5FC6',\n 'entry.expand': '\u5C55\u5F00\u6B63\u6587',\n 'entry.collapse': '\u6536\u8D77\u6B63\u6587',\n 'toolbar.search': '\u641C\u7D22\u6807\u9898\u4E0E\u6B63\u6587\u2026',\n 'toolbar.add': '\u6DFB\u52A0\u8BB0\u5FC6',\n 'toolbar.cancel': '\u53D6\u6D88',\n 'form.section': '\u5206\u7C7B',\n 'form.title': '\u6807\u9898\uFF08\u53EF\u9009\uFF09',\n 'form.content': '\u5185\u5BB9',\n 'form.importance': '\u91CD\u8981\u5EA6',\n 'form.importanceHint': '1 \u6700\u4F4E\uFF0C5 \u6700\u9AD8\uFF1B\u4F1A\u5F71\u54CD Hot Memory \u6392\u5E8F\u3002',\n 'form.tags': '\u6807\u7B7E',\n 'form.supersedes': '\u66FF\u4EE3\u7684\u8BB0\u5FC6 ID',\n 'form.pinned': '\u7F6E\u9876\u8FD9\u6761\u8BB0\u5FC6',\n 'form.pinnedHint': '\u7F6E\u9876\u6761\u76EE\u5728 Hot Memory \u9009\u62E9\u4E2D\u4F18\u5148\u3002',\n 'form.submit': '\u8BB0\u5F55',\n 'form.placeholder.title': '\u4E00\u53E5\u8BDD\u6807\u9898\uFF0C\u5982\u300C\u4FEE\u590D pet \u60AC\u505C\u95EA\u9000\u300D',\n 'form.placeholder.content': '\u5177\u4F53\u505A\u4E86\u4EC0\u4E48\u3001\u7ED3\u8BBA\u3001\u6559\u8BAD\u6216\u4E0B\u4E00\u6B65\u600E\u4E48\u505A\u3002\u5EFA\u8BAE\u7CBE\u70BC\u3001\u53EF\u6267\u884C\u3002',\n 'form.placeholder.tags': '\u9017\u53F7\u5206\u9694\uFF0C\u4F8B\u5982 release, windows',\n 'form.placeholder.supersedes': '\u9017\u53F7\u5206\u9694\u7684\u65E7\u8BB0\u5FC6 ID\uFF08\u53EF\u9009\uFF09',\n 'empty.project': '\u672C\u9879\u76EE\u6682\u65E0\u6301\u4E45\u8BB0\u5FC6',\n 'empty.projectHint': '\u8BA9 agent \u7528 memoir_record \u6C89\u6DC0\u7ECF\u9A8C\uFF0C\u6216\u70B9\u300C\u6DFB\u52A0\u8BB0\u5FC6\u300D\u624B\u52A8\u8BB0\u5F55\u3002',\n 'empty.workspace': '\u672A\u6253\u5F00\u9879\u76EE\u4F1A\u8BDD',\n 'empty.workspaceHint': '\u6253\u5F00\u4E00\u4E2A\u9879\u76EE\u4F1A\u8BDD\u540E\uFF0C\u8FD9\u91CC\u663E\u793A\u8BE5\u9879\u76EE\u7684\u6301\u4E45\u8BB0\u5FC6\u3002',\n 'empty.global': '\u5168\u5C40\u7D22\u5F15\u4E3A\u7A7A',\n 'empty.globalHint': '\u5728\u4EFB\u4F55\u9879\u76EE\u91CC\u7528 memoir_record \u8BB0\u5F55\u540E\uFF0C\u4F1A\u51FA\u73B0\u5728\u8FD9\u91CC\u4F9B\u8DE8\u9879\u76EE\u68C0\u7D22\u3002',\n 'empty.search': '\u6CA1\u6709\u5339\u914D\u7684\u6761\u76EE',\n 'load.failed': '\u52A0\u8F7D\u5931\u8D25',\n 'record.failed': '\u8BB0\u5F55\u5931\u8D25',\n 'update.failed': '\u66F4\u65B0\u5931\u8D25',\n 'delete.failed': '\u5220\u9664\u5931\u8D25',\n 'delete.confirm': '\u5220\u9664\u8FD9\u6761\u8BB0\u5FC6\uFF1F',\n 'updated': '\u66F4\u65B0\u4E8E',\n 'entries': '\u6761',\n 'pagination.showing': '\u5DF2\u663E\u793A',\n 'pagination.projects': '\u5DF2\u663E\u793A\u9879\u76EE',\n 'pagination.more': '\u52A0\u8F7D\u66F4\u591A',\n 'project.expandAll': '\u5168\u90E8\u5C55\u5F00',\n 'project.collapseAll': '\u5168\u90E8\u6298\u53E0',\n 'project.unscoped': '\u672A\u5F52\u5C5E',\n 'project.unscopedHint': '\u6CA1\u6709\u9879\u76EE\u6765\u6E90\u7684\u5386\u53F2\u8BB0\u5FC6',\n 'session': '\u4F1A\u8BDD',\n 'source.label': '\u6765\u6E90',\n 'source.turn': '\u56DE\u5408',\n 'source.open': '\u6253\u5F00\u6765\u6E90\u4F1A\u8BDD\uFF08\u56DE\u5408\u7F16\u53F7\u53EF\u590D\u5236\uFF09',\n 'source.copy': '\u590D\u5236\u4F1A\u8BDD\u4E0E\u56DE\u5408\u6807\u8BC6',\n 'source.copied': '\u5DF2\u590D\u5236',\n 'sections.work': '\u5DE5\u4F5C\u8BB0\u5F55',\n 'sections.lessons': '\u7ECF\u9A8C\u6559\u8BAD',\n 'sections.actions': '\u884C\u52A8\u6307\u5357',\n 'sections.note': '\u5907\u6CE8',\n 'diag.title': 'Memory Diagnostics',\n 'diag.revision': 'Store revision',\n 'diag.snapshot': 'Session snapshots',\n 'diag.cache': 'Store cache',\n 'diag.render': 'Render cache',\n 'diag.hot': 'Hot memory',\n 'diag.retrieval': 'Retrieval \u7D22\u5F15',\n 'diag.qcache': 'Query cache',\n 'diag.lastQuery': '\u6700\u8FD1\u67E5\u8BE2',\n 'diag.snapshotInfo': '\u4F1A\u8BDD\u5FEB\u7167',\n 'diag.unavailable': '\u8BCA\u65AD\u4FE1\u606F\u6682\u4E0D\u53EF\u7528',\n 'diag.hits': '\u547D\u4E2D',\n 'diag.misses': '\u672A\u547D\u4E2D',\n 'diag.items': '\u6761',\n 'diag.budget': '\u9884\u7B97',\n 'diag.documents': '\u6587\u6863',\n 'diag.terms': '\u8BCD\u9879',\n 'diag.epoch': '\u4EE3\u6B21',\n 'diag.evicted': '\u5DF2\u6DD8\u6C70',\n 'diag.returned': '\u8FD4\u56DE/\u5019\u9009',\n 'inspector.title': 'Hot Memory \u9884\u89C8',\n 'inspector.empty': '\u672C\u5DE5\u4F5C\u533A\u6682\u65E0 Hot Memory',\n 'inspector.selected': '\u5DF2\u9009\u8BB0\u5FC6',\n 'search.ranked': '\u6309\u76F8\u5173\u6027\u6392\u5E8F',\n 'filter.status': '\u72B6\u6001',\n 'filter.section': '\u5206\u7C7B',\n 'filter.all': '\u5168\u90E8',\n 'status.active': '\u6D3B\u8DC3',\n 'status.superseded': '\u5DF2\u88AB\u66FF\u4EE3',\n 'status.archived': '\u5DF2\u5F52\u6863',\n 'lifecycle.pin': '\u7F6E\u9876',\n 'lifecycle.unpin': '\u53D6\u6D88\u7F6E\u9876',\n 'lifecycle.edit': '\u7F16\u8F91',\n 'lifecycle.save': '\u4FDD\u5B58\u66F4\u65B0',\n 'lifecycle.supersede': '\u6807\u8BB0\u5DF2\u66FF\u4EE3',\n 'lifecycle.unsupersede': '\u6062\u590D\u6D3B\u8DC3',\n 'lifecycle.archive': '\u5F52\u6863',\n 'lifecycle.restore': '\u6062\u590D',\n 'similarity.title': '\u53D1\u73B0\u76F8\u4F3C\u8BB0\u5FC6\uFF0C\u672C\u6B21\u5C1A\u672A\u5199\u5165',\n 'similarity.description': '\u8BF7\u9009\u62E9\u66F4\u65B0\u5DF2\u6709\u8BB0\u5FC6\u3001\u7528\u65B0\u7ED3\u8BBA\u66FF\u4EE3\u5B83\uFF0C\u6216\u660E\u786E\u4FDD\u7559\u4E24\u6761\uFF1B\u63D2\u4EF6\u4E0D\u4F1A\u81EA\u52A8\u5220\u9664\u6216\u5408\u5E76\u3002',\n 'similarity.kind.duplicate': '\u7591\u4F3C\u91CD\u590D',\n 'similarity.kind.conflict': '\u53EF\u80FD\u51B2\u7A81',\n 'similarity.titleScore': '\u6807\u9898',\n 'similarity.update': '\u66F4\u65B0\u8FD9\u4E00\u6761',\n 'similarity.supersede': '\u7528\u65B0\u7ED3\u8BBA\u66FF\u4EE3',\n 'similarity.force': '\u4ECD\u7136\u4FDD\u7559\u4E24\u6761',\n 'similarity.back': '\u8FD4\u56DE\u4FEE\u6539',\n 'similarity.reason.exact-content': '\u6B63\u6587\u4E00\u81F4',\n 'similarity.reason.exact-title': '\u6807\u9898\u4E00\u81F4',\n 'similarity.reason.high-title-overlap': '\u6807\u9898\u9AD8\u5EA6\u76F8\u4F3C',\n 'similarity.reason.high-token-overlap': 'Token \u9AD8\u91CD\u5408',\n 'similarity.reason.bm25-candidate': 'BM25 \u9AD8\u76F8\u5173',\n 'similarity.reason.same-topic-different-content': '\u540C\u4E3B\u9898\u4F46\u5185\u5BB9\u4E0D\u540C',\n 'settings.title': '\u8BB0\u5FC6\u8BBE\u7F6E',\n 'settings.description': '\u5B8C\u6574\u8FD0\u884C\u65F6\u8BBE\u7F6E\uFF1B\u4FDD\u5B58\u540E\u7ACB\u5373\u5E94\u7528\uFF0C\u5E76\u6301\u4E45\u5316\u5230\u672C\u673A DSH \u7528\u6237\u76EE\u5F55\u3002',\n 'settings.language': 'Agent \u4F7F\u7528\u8BED\u8A00',\n 'settings.languageHint': '\u63A7\u5236\u5DE5\u5177\u8BF4\u660E\u3001\u81EA\u52A8\u84B8\u998F\u3001Hot Memory \u6807\u9898\u3001\u5DE5\u5177\u7ED3\u679C\u548C\u9519\u8BEF\uFF1B\u4E0D\u6539\u53D8 Web \u754C\u9762\u8BED\u8A00\u3002',\n 'settings.language.zh': '\u4E2D\u6587',\n 'settings.language.en': 'English',\n 'settings.language.de': 'Deutsch\uFF08\u5FB7\u8BED\uFF09',\n 'settings.language.ru': '\u0420\u0443\u0441\u0441\u043A\u0438\u0439\uFF08\u4FC4\u8BED\uFF09',\n 'settings.expand': '\u5C55\u5F00',\n 'settings.collapse': '\u6298\u53E0',\n 'settings.announce': '\u5411 Agent \u6CE8\u5165\u8BB0\u5FC6',\n 'settings.announceHint': '\u5173\u95ED\u540E\u4E0D\u518D\u5411\u7CFB\u7EDF\u63D0\u793A\u6CE8\u5165\u63D2\u4EF6\u8BF4\u660E\u4E0E Hot Memory\uFF0C\u4F46\u5DE5\u5177\u548C GUI \u4FDD\u6301\u53EF\u7528\u3002',\n 'settings.group.distill': '\u81EA\u52A8\u84B8\u998F',\n 'settings.group.memory': 'Hot Memory\u3001\u53EC\u56DE\u4E0E\u7F13\u5B58',\n 'settings.enabled': '\u542F\u7528\u81EA\u52A8\u84B8\u998F',\n 'settings.enabledHint': '\u5728\u9876\u5C42 agent \u7684\u6709\u6548\u5DE5\u4F5C\u56DE\u5408\u7ED3\u675F\u65F6\u63D0\u9192\u5F52\u7EB3\u8BB0\u5FC6\u3002',\n 'settings.autoDistillEvery': '\u5DE5\u4F5C\u56DE\u5408\u95F4\u9694',\n 'settings.autoDistillEveryHint': '\u6BCF\u7D2F\u8BA1 N \u4E2A worked turn \u6700\u591A\u63D0\u9192\u4E00\u6B21\uFF08\u6700\u5C0F 1\uFF09\u3002',\n 'settings.autoDistillCooldownMin': '\u51B7\u5374\u65F6\u95F4\uFF08\u5206\u949F\uFF09',\n 'settings.autoDistillCooldownMinHint': '\u4E24\u6B21\u6210\u529F\u63D0\u9192\u81F3\u5C11\u95F4\u9694 M \u5206\u949F\uFF08\u6700\u5C0F 0\uFF09\u3002',\n 'settings.autoDistillMinTools': '\u6700\u4F4E\u5DE5\u5177\u8C03\u7528\u6570',\n 'settings.autoDistillMinToolsHint': '\u89E6\u53D1\u56DE\u5408\u81F3\u5C11\u5305\u542B K \u6B21\u5DE5\u5177\u8C03\u7528\uFF08\u6700\u5C0F 1\uFF09\u3002',\n 'settings.hotMemoryTokens': 'Hot Memory \u76EE\u6807 tokens',\n 'settings.hotMemoryTokensHint': '\u5E38\u89C4\u9009\u62E9\u9884\u7B97\uFF0C\u5FC5\u987B\u4E0D\u5927\u4E8E\u786C\u4E0A\u9650\u3002',\n 'settings.hotMemoryMaxTokens': 'Hot Memory \u786C\u4E0A\u9650',\n 'settings.hotMemoryMaxTokensHint': '\u4EFB\u4F55\u65B0\u4F1A\u8BDD\u5FEB\u7167\u90FD\u4E0D\u4F1A\u8D85\u8FC7\u6B64\u9884\u7B97\u3002',\n 'settings.readDefaultLimit': '\u9ED8\u8BA4\u53EC\u56DE\u6761\u6570',\n 'settings.readDefaultLimitHint': 'memoir_read \u672A\u4F20 limit \u65F6\u4F7F\u7528\u3002',\n 'settings.readMaxLimit': '\u6700\u5927\u53EC\u56DE\u6761\u6570',\n 'settings.readMaxLimitHint': 'memoir_read \u7684\u5B9E\u65F6\u4E0A\u9650\uFF0C\u4E0D\u5C0F\u4E8E\u9ED8\u8BA4\u503C\u3002',\n 'settings.sessionSnapshotMax': '\u4F1A\u8BDD\u5FEB\u7167\u5BB9\u91CF',\n 'settings.sessionSnapshotMaxHint': '\u51BB\u7ED3\u63D0\u793A\u524D\u7F00\u7684 LRU \u5BB9\u91CF\uFF1B\u7F29\u5C0F\u65F6\u7ACB\u5373\u6DD8\u6C70\u6700\u65E7\u9879\u3002',\n 'settings.queryCacheSize': '\u67E5\u8BE2\u7F13\u5B58\u5BB9\u91CF',\n 'settings.queryCacheSizeHint': 'BM25 \u67E5\u8BE2 LRU \u5BB9\u91CF\uFF1B\u7F29\u5C0F\u65F6\u7ACB\u5373\u6DD8\u6C70\u6700\u65E7\u9879\u3002',\n 'settings.andHint': '\u4E09\u4E2A\u9891\u7387\u6761\u4EF6\u6309 AND \u5224\u5B9A\uFF1Bidle\u3001aborted\u3001subagent \u548C\u5DF2\u8BB0\u5F55\u8BB0\u5FC6\u7684\u56DE\u5408\u4E0D\u4F1A\u89E6\u53D1\u3002',\n 'settings.liveHint': '\u9884\u7B97\u548C\u53EC\u56DE\u9650\u5236\u7ACB\u5373\u5F71\u54CD\u65B0\u8BF7\u6C42\uFF1B\u5DF2\u51BB\u7ED3\u7684\u4F1A\u8BDD\u5FEB\u7167\u4E0D\u4F1A\u91CD\u5199\uFF0C\u4EE5\u4FDD\u6301\u63D0\u793A\u524D\u7F00\u7F13\u5B58\u7A33\u5B9A\u3002',\n 'settings.source': '\u5F53\u524D\u6765\u6E90',\n 'settings.source.profile': '\u542F\u52A8\u914D\u7F6E',\n 'settings.source.web': 'Web \u6301\u4E45\u5316\u8986\u76D6',\n 'settings.save': '\u4FDD\u5B58\u5E76\u7ACB\u5373\u5E94\u7528',\n 'settings.reset': '\u6062\u590D\u542F\u52A8\u914D\u7F6E',\n 'settings.saved': '\u5DF2\u4FDD\u5B58\uFF0C\u540E\u7EED\u56DE\u5408\u7ACB\u5373\u751F\u6548\u3002',\n 'settings.resetDone': '\u5DF2\u6062\u590D\u672C\u6B21\u542F\u52A8\u65F6\u7684\u914D\u7F6E\u3002',\n 'settings.invalid': '\u8BF7\u8F93\u5165\u6709\u6548\u6570\u503C\uFF1A\u6574\u6570\u9879\u4E0D\u5C0F\u4E8E 1\u3001\u51B7\u5374\u4E0D\u5C0F\u4E8E 0\uFF1B\u786C\u4E0A\u9650\u4E0D\u5F97\u5C0F\u4E8E\u76EE\u6807\u6216\u9ED8\u8BA4\u503C\u3002',\n 'settings.loadFailed': '\u8BBE\u7F6E\u52A0\u8F7D\u5931\u8D25',\n 'settings.saveFailed': '\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25',\n },\n en: {\n 'guide.label': 'Memoir identity and shortcuts',\n 'guide.repository': 'GitHub project',\n 'guide.settings': 'Open memory settings',\n 'sidebar.description': 'Browse project memory, Hot Memory and sources alongside your chat.',\n 'about.title': 'About & help',\n 'notice.title': 'What\u2019s new',\n 'notice.dismiss': 'Got it',\n 'notice.reopen': 'View release highlights',\n 'notice.compat': '0.9.2 prepares support for DSH 0.2.1-alpha.1 while retaining 0.2.0-rc.1 / rc.2. Fixes misleading truncation counts for memories already displayed during cross-project recall.',\n 'notice.features': 'Upgrading prevents new invalid receipts; it does not rewrite old logs. If an old session still fails to open, follow the recovery guide linked in README: audit first, stop every host and back up, then explicitly apply the repair.',\n 'notice.privacy': 'Bundled offline; no memory changes. Acknowledge once per version, or reopen from About & help.',\n 'about.host': 'Supported DSH range',\n 'about.baseline': 'Development SDK baseline',\n 'about.maintainer': 'Maintainer',\n 'about.repositoryNote': 'These links belong to the memory plugin, not the current workspace Git repository.',\n 'about.links': 'Plugin project and help links',\n 'about.readmeFile': 'README.en.md',\n 'about.docs': 'Documentation',\n 'about.releases': 'Releases & changelog',\n 'about.issues': 'Report an issue',\n 'about.updates': 'Use the host plugin manager to update. Check the target package\u2019s DSH requirements, including its prerelease channel, before installing. This panel does not automatically check or upgrade online, or upload workspace paths or memory content.',\n 'snapshot.disk': 'Durable session snapshots',\n 'snapshot.restored': 'Restored from disk',\n 'snapshot.created': 'New baselines',\n 'snapshot.failures': 'Persistence failures',\n 'snapshot.last': 'Last disk operation',\n 'snapshot.idle': 'Not read yet',\n 'snapshot.volatile': 'Process-local fallback',\n 'snapshot.degraded': 'Prefix stability across restart is not guaranteed; check snapshot storage',\n 'snapshot.invalid-record': 'Invalid format or hash; original file preserved',\n 'snapshot.record-too-large': 'Snapshot size limit exceeded',\n 'snapshot.unavailable': 'Storage unavailable or lock timeout',\n 'snapshot.retention': 'LRU bounds RAM only; disk snapshots do not auto-expire. Older sessions may establish a new baseline once after upgrade. Server-side cache hits are not guaranteed.',\n 'distill.title': 'Automatic distillation lifecycle',\n 'distill.worked': 'Eligible worked turns',\n 'distill.agents': 'Tracked agents',\n 'distill.note': 'Process-local counters; a submitted reminder does not confirm a memory write. Manual recording remains available when disabled.',\n 'distill.last': 'Latest decision',\n 'distill.disabled': 'Automatic distillation disabled',\n 'distill.subagent': 'Subagent skipped',\n 'distill.aborted': 'Aborted turn skipped',\n 'distill.idle': 'No tool activity',\n 'distill.recorded': 'Memory write or update persisted in this turn',\n 'distill.unavailable': 'Activity projection unavailable; skipped safely',\n 'writes.title': 'Actual write outcomes',\n 'writes.persisted': 'Persisted writes / updates',\n 'writes.afterReminder': 'Of these: later saves in a reminded turn',\n 'writes.failed': 'Failed tool results',\n 'writes.canceled': 'Canceled tool results',\n 'writes.needsResolution': 'Similarity needs resolution (no write)',\n 'writes.receiptFailed': 'Saved but turn receipt unavailable',\n 'writes.note': 'Process-local Agent tools only. Host cancellation may follow a save, so counts may overlap. Correlation with a reminder proves neither causation nor semantic correctness.',\n 'distill.duplicate': 'Duplicate or stale turn',\n 'distill.interval': 'Turn interval not reached',\n 'distill.tools': 'Tool threshold not reached',\n 'distill.cooldown': 'Cooldown active',\n 'distill.queued': 'Separate wrap-up turn queued',\n 'distill.distillation': 'Memory wrap-up turn; no recursive reminder',\n 'distill.failed': 'Reminder submission failed',\n 'entry.label': 'Memory',\n 'entry.tooltip': 'Open the memory panel (project / global)',\n 'panel.title': 'Memory Memoir',\n 'panel.close': 'Close',\n 'panel.refresh': 'Refresh',\n 'surface.navigation': 'Memory sections',\n 'surface.browse': 'Browse',\n 'surface.settings': 'Settings',\n 'surface.hotMemory': 'Hot Memory',\n 'surface.diagnostics': 'Diagnostics',\n 'browse.scope': 'Memory scope',\n 'tab.project': 'Project',\n 'tab.global': 'Global',\n 'entry.expand': 'Expand content',\n 'entry.collapse': 'Collapse content',\n 'toolbar.search': 'Search titles and content\u2026',\n 'toolbar.add': 'Add entry',\n 'toolbar.cancel': 'Cancel',\n 'form.section': 'Section',\n 'form.title': 'Title (optional)',\n 'form.content': 'Content',\n 'form.importance': 'Importance',\n 'form.importanceHint': '1 is lowest and 5 is highest; this affects Hot Memory ranking.',\n 'form.tags': 'Tags',\n 'form.supersedes': 'Superseded entry IDs',\n 'form.pinned': 'Pin this entry',\n 'form.pinnedHint': 'Pinned entries receive priority during Hot Memory selection.',\n 'form.submit': 'Record',\n 'form.placeholder.title': 'A one-line title, e.g. \"Fix pet hover crash\"',\n 'form.placeholder.content': 'What was done, the conclusion, the lesson, or the next step. Concise and actionable.',\n 'form.placeholder.tags': 'Comma-separated, for example release, windows',\n 'form.placeholder.supersedes': 'Comma-separated old entry IDs (optional)',\n 'empty.project': 'No persistent memory in this project yet',\n 'empty.projectHint': 'Ask the agent to distill via memoir_record, or add an entry manually.',\n 'empty.workspace': 'No project session open',\n 'empty.workspaceHint': 'Open a project session to see its persistent memory here.',\n 'empty.global': 'The global index is empty',\n 'empty.globalHint': 'Entries recorded via memoir_record in any project appear here for cross-project search.',\n 'empty.search': 'No matching entries',\n 'load.failed': 'Failed to load',\n 'record.failed': 'Failed to record',\n 'update.failed': 'Failed to update',\n 'delete.failed': 'Failed to delete',\n 'delete.confirm': 'Delete this entry?',\n 'updated': 'Updated',\n 'entries': 'entries',\n 'pagination.showing': 'Showing',\n 'pagination.projects': 'Projects shown',\n 'pagination.more': 'Load more',\n 'project.expandAll': 'Expand all',\n 'project.collapseAll': 'Collapse all',\n 'project.unscoped': 'Unscoped',\n 'project.unscopedHint': 'Legacy memories without a project source',\n 'session': 'session',\n 'source.label': 'Source',\n 'source.turn': 'turn',\n 'source.open': 'Open the source session (turn ID can be copied)',\n 'source.copy': 'Copy session and turn identifiers',\n 'source.copied': 'Copied',\n 'sections.work': 'Work Log',\n 'sections.lessons': 'Lessons Learned',\n 'sections.actions': 'Action Guide',\n 'sections.note': 'Notes',\n 'diag.title': 'Memory Diagnostics',\n 'diag.revision': 'Store revision',\n 'diag.snapshot': 'Session snapshots',\n 'diag.cache': 'Store cache',\n 'diag.render': 'Render cache',\n 'diag.hot': 'Hot memory',\n 'diag.retrieval': 'Retrieval index',\n 'diag.qcache': 'Query cache',\n 'diag.lastQuery': 'Last query',\n 'diag.snapshotInfo': 'Session snapshot',\n 'diag.unavailable': 'Diagnostics are temporarily unavailable',\n 'diag.hits': 'hits',\n 'diag.misses': 'misses',\n 'diag.items': 'entries',\n 'diag.budget': 'budget',\n 'diag.documents': 'docs',\n 'diag.terms': 'terms',\n 'diag.epoch': 'epoch',\n 'diag.evicted': 'evicted',\n 'diag.returned': 'returned/candidates',\n 'inspector.title': 'Hot Memory Inspector',\n 'inspector.empty': 'No hot memory in this workspace yet',\n 'inspector.selected': 'Selected memories',\n 'search.ranked': 'Ranked by relevance',\n 'filter.status': 'Status',\n 'filter.section': 'Section',\n 'filter.all': 'All',\n 'status.active': 'Active',\n 'status.superseded': 'Superseded',\n 'status.archived': 'Archived',\n 'lifecycle.pin': 'Pin',\n 'lifecycle.unpin': 'Unpin',\n 'lifecycle.edit': 'Edit',\n 'lifecycle.save': 'Save update',\n 'lifecycle.supersede': 'Mark superseded',\n 'lifecycle.unsupersede': 'Restore active',\n 'lifecycle.archive': 'Archive',\n 'lifecycle.restore': 'Restore',\n 'similarity.title': 'Similar memory found; nothing has been written yet',\n 'similarity.description': 'Update the existing memory, supersede it with the new conclusion, or explicitly keep both. The plugin never deletes or merges automatically.',\n 'similarity.kind.duplicate': 'Likely duplicate',\n 'similarity.kind.conflict': 'Possible conflict',\n 'similarity.titleScore': 'title',\n 'similarity.update': 'Update this entry',\n 'similarity.supersede': 'Supersede with new',\n 'similarity.force': 'Keep both anyway',\n 'similarity.back': 'Back to edit',\n 'similarity.reason.exact-content': 'Exact content',\n 'similarity.reason.exact-title': 'Exact title',\n 'similarity.reason.high-title-overlap': 'High title overlap',\n 'similarity.reason.high-token-overlap': 'High token overlap',\n 'similarity.reason.bm25-candidate': 'High BM25 relevance',\n 'similarity.reason.same-topic-different-content': 'Same topic, different content',\n 'settings.title': 'Memory settings',\n 'settings.description': 'Complete runtime settings; saves apply immediately and persist in the local DSH user directory.',\n 'settings.language': 'Agent-facing language',\n 'settings.languageHint': 'Controls tool schemas, automatic distillation, Hot Memory headings, tool results, and errors; it does not change the Web UI language.',\n 'settings.language.zh': 'Chinese',\n 'settings.language.en': 'English',\n 'settings.language.de': 'Deutsch (German)',\n 'settings.language.ru': '\u0420\u0443\u0441\u0441\u043A\u0438\u0439 (Russian)',\n 'settings.expand': 'Expand',\n 'settings.collapse': 'Collapse',\n 'settings.announce': 'Inject memory for agents',\n 'settings.announceHint': 'When off, plugin guidance and Hot Memory leave the system prompt while tools and the GUI remain available.',\n 'settings.group.distill': 'Auto-distill',\n 'settings.group.memory': 'Hot Memory, recall, and cache',\n 'settings.enabled': 'Enable auto-distill',\n 'settings.enabledHint': 'Prompt top-level agents to distill memory after eligible worked turns.',\n 'settings.autoDistillEvery': 'Worked-turn interval',\n 'settings.autoDistillEveryHint': 'Remind at most once per N accumulated worked turns (minimum 1).',\n 'settings.autoDistillCooldownMin': 'Cooldown (minutes)',\n 'settings.autoDistillCooldownMinHint': 'Require at least M minutes between successful reminders (minimum 0).',\n 'settings.autoDistillMinTools': 'Minimum tool calls',\n 'settings.autoDistillMinToolsHint': 'The triggering turn must contain at least K tool calls (minimum 1).',\n 'settings.hotMemoryTokens': 'Hot Memory target tokens',\n 'settings.hotMemoryTokensHint': 'Normal selection budget; it cannot exceed the hard limit.',\n 'settings.hotMemoryMaxTokens': 'Hot Memory hard limit',\n 'settings.hotMemoryMaxTokensHint': 'No newly frozen session snapshot exceeds this budget.',\n 'settings.readDefaultLimit': 'Default recall count',\n 'settings.readDefaultLimitHint': 'Used when memoir_read omits limit.',\n 'settings.readMaxLimit': 'Maximum recall count',\n 'settings.readMaxLimitHint': 'Live memoir_read ceiling; it cannot be below the default.',\n 'settings.sessionSnapshotMax': 'Session snapshot capacity',\n 'settings.sessionSnapshotMaxHint': 'LRU capacity for frozen prompt prefixes; shrinking evicts the oldest immediately.',\n 'settings.queryCacheSize': 'Query cache capacity',\n 'settings.queryCacheSizeHint': 'BM25 query LRU capacity; shrinking evicts the oldest immediately.',\n 'settings.andHint': 'All three frequency conditions use AND semantics; idle, aborted, subagent, and already-recorded turns do not trigger.',\n 'settings.liveHint': 'Budgets and recall limits affect new requests immediately; frozen session snapshots remain unchanged for prompt-prefix cache stability.',\n 'settings.source': 'Current source',\n 'settings.source.profile': 'startup profile config',\n 'settings.source.web': 'persistent Web override',\n 'settings.save': 'Save and apply now',\n 'settings.reset': 'Restore startup config',\n 'settings.saved': 'Saved; subsequent turns use the new policy immediately.',\n 'settings.resetDone': 'Restored the configuration captured at startup.',\n 'settings.invalid': 'Enter valid values: integer fields are at least 1 and cooldown is at least 0; a hard/maximum value cannot be below its target/default.',\n 'settings.loadFailed': 'Failed to load settings',\n 'settings.saveFailed': 'Failed to save settings',\n },\n}\n\n/** Section keys in canonical display order. */\nexport const SECTION_KEYS: string[] = ['work', 'lessons', 'actions', 'note']\n\n/** Minimal document surface for language detection. */\nexport interface DocumentLike {\n documentElement?: { lang?: string }\n}\n\n/** Current UI language: zh when the shell's <html lang> starts with zh. */\nexport function detectLanguage(documentLike: DocumentLike | undefined): Lang {\n const lang = documentLike?.documentElement?.lang\n return typeof lang === 'string' && lang.startsWith('zh') ? 'zh' : 'en'\n}\n\n/** Pure translation lookup: `translate(lang, key)` with en fallback. */\nexport function translate(lang: string, key: string): string {\n const dict = dictionaries[lang as Lang] ?? dictionaries.en\n return Object.prototype.hasOwnProperty.call(dict, key) ? dict[key] : (dictionaries.en[key] ?? key)\n}\n\n/** Bound translator reading the live <html lang> at each call. */\nexport function makeT(documentLike: DocumentLike): (key: string) => string {\n return (key) => translate(detectLanguage(documentLike), key)\n}\n", "/**\n * The memoir panel: project / global memory tabs, client-side search,\n * manual record form, per-entry delete. Shared by native Conversation,\n * Settings and optional right-sidebar slots; each owns its view state.\n */\n\nimport { Fragment, useEffect, useId, useMemo, useState, useSyncExternalStore, type KeyboardEvent as ReactKeyboardEvent, type ReactNode } from 'react'\nimport { SECTION_KEYS } from './i18n.js'\nimport type { MemoirApi, WireDiagnostics, WireEntry, WireHotMemory, WireMemoirSettings, WireProject, WireRecordResolution, WireRecordResult, WireSearchResult, WireSimilarityCandidate } from './api.js'\nimport type { CwdTracker } from './cwd.js'\nimport type { PanelController } from './controller.js'\nimport type { MemoirStatus, SectionKey } from './types.ts'\nimport { MemoirAbout } from './about.js'\nimport { MEMOIR_LANGUAGES, resolveMemoirLanguage } from '../host/languages.js'\nimport {\n ENTRY_PAGE_SIZE,\n PROJECT_PAGE_SIZE,\n buildProjectGroups,\n filterEntries,\n groupRankedResults,\n nextPageSize,\n shouldCollapseEntry,\n type EntryStats,\n} from './view-model.js'\n\ninterface PanelProps {\n controller?: PanelController\n api: MemoirApi\n cwdTracker?: CwdTracker\n /** Native alpha slots provide a session-bound cwd directly. */\n cwd?: string\n t: (key: string) => string\n openSource?: (sessionId: string, turnId?: number) => void\n /** Native settings may close their owning shell without a legacy controller. */\n onClose?: () => void\n announceOnOpen?: boolean\n}\n\nconst EMPTY_CWD_TRACKER: CwdTracker = {\n getSnapshot: () => '',\n subscribe: () => () => {},\n}\n\ntype EntryPatch = {\n section?: SectionKey\n title?: string | null\n content?: string\n importance?: number\n pinned?: boolean\n status?: MemoirStatus\n supersedes?: string[]\n tags?: string[]\n}\n\nconst parseList = (value: string): string[] =>\n [...new Set(value.split(/[,\uFF0C\\n]/).map((item) => item.trim()).filter((item) => item !== ''))]\n\nasync function copyText(value: string): Promise<boolean> {\n try {\n if (navigator.clipboard !== undefined) {\n await navigator.clipboard.writeText(value)\n return true\n }\n const textarea = document.createElement('textarea')\n textarea.value = value\n textarea.style.position = 'fixed'\n textarea.style.opacity = '0'\n document.body.appendChild(textarea)\n textarea.select()\n const copied = document.execCommand('copy')\n textarea.remove()\n return copied\n } catch {\n return false\n }\n}\n\n/** One entry's meta line: lifecycle, importance, tags and provenance. */\nfunction EntryMeta({ entry, t, openSource }: {\n entry: WireEntry\n t: (key: string) => string\n openSource?: (sessionId: string, turnId?: number) => void\n}) {\n const [copied, setCopied] = useState(false)\n const when = new Date(entry.time)\n const pad = (n: number) => String(n).padStart(2, '0')\n const timeText = `${when.getFullYear()}-${pad(when.getMonth() + 1)}-${pad(when.getDate())} ${pad(when.getHours())}:${pad(when.getMinutes())}`\n const source = entry.source ?? (entry.sessionId === undefined ? undefined : { sessionId: entry.sessionId })\n const sourceText = source === undefined\n ? ''\n : [\n source.sessionId === undefined ? undefined : `sessionId=${source.sessionId}`,\n source.turnId === undefined ? undefined : `turnId=${source.turnId}`,\n ].filter(Boolean).join('\\n')\n const copySource = () => {\n void copyText(sourceText).then((ok) => {\n if (!ok) return\n setCopied(true)\n setTimeout(() => setCopied(false), 1_500)\n })\n }\n return (\n <div className=\"memoir-entry-meta\">\n <span>{timeText}</span>\n <span className=\"memoir-chip\">{t('sections.' + entry.section)}</span>\n {entry.status !== undefined && entry.status !== 'active'\n ? <span className=\"memoir-chip\">{t('status.' + entry.status)}</span>\n : null}\n {entry.pinned === true ? <span className=\"memoir-chip\">{t('lifecycle.pin')}</span> : null}\n <span className=\"memoir-chip\" title={t('form.importanceHint')}>{t('form.importance')}: {entry.importance ?? 3}</span>\n {(entry.tags ?? []).map((tag) => <span className=\"memoir-chip memoir-tag\" key={tag}>#{tag}</span>)}\n {(entry.supersedes?.length ?? 0) > 0\n ? <span className=\"memoir-chip\" title={entry.supersedes?.join('\\n')}>{t('form.supersedes')}: {entry.supersedes?.length}</span>\n : null}\n {source !== undefined\n ? <span className=\"memoir-source\">\n {source.sessionId !== undefined\n ? <button type=\"button\" className=\"memoir-source-link\" title={t('source.open')} onClick={() => openSource?.(source.sessionId!, source.turnId)}>\n {t('source.label')}: {source.sessionId.slice(0, 10)}{source.turnId === undefined ? '' : ` \u00B7 ${t('source.turn')} ${source.turnId}`}\n </button>\n : <span>{t('source.turn')} {source.turnId}</span>}\n <button type=\"button\" className=\"memoir-source-copy\" title={t('source.copy')} onClick={copySource}>{copied ? t('source.copied') : '\u29C9'}</button>\n </span>\n : null}\n </div>\n )\n}\n\nfunction EntryCard({ entry, t, onDelete, onUpdate, openSource, score }: { entry: WireEntry; t: (key: string) => string; onDelete: (entry: WireEntry) => void; onUpdate?: (entry: WireEntry, patch: EntryPatch) => void; openSource?: (sessionId: string, turnId?: number) => void; score?: number }) {\n const [editing, setEditing] = useState(false)\n const [contentExpanded, setContentExpanded] = useState(false)\n const [section, setSection] = useState<SectionKey>(entry.section)\n const [title, setTitle] = useState(entry.title ?? '')\n const [content, setContent] = useState(entry.content)\n const [importance, setImportance] = useState(String(entry.importance ?? 3))\n const [tags, setTags] = useState((entry.tags ?? []).join(', '))\n const [supersedes, setSupersedes] = useState((entry.supersedes ?? []).join(', '))\n const save = () => {\n if (content.trim() === '' || onUpdate === undefined) return\n onUpdate(entry, {\n section,\n title: title.trim() === '' ? null : title.trim(),\n content: content.trim(),\n importance: Number(importance),\n tags: parseList(tags),\n supersedes: parseList(supersedes),\n })\n setEditing(false)\n }\n return (\n <div className=\"memoir-entry\" data-dsh-part=\"entry\">\n <button type=\"button\" className=\"memoir-delete\" title={t('delete.confirm')} onClick={() => onDelete(entry)}>\u00D7</button>\n {onUpdate !== undefined\n ? <div className=\"memoir-entry-actions\">\n <button type=\"button\" className=\"memoir-iconbtn\" onClick={() => setEditing((value) => !value)}>{editing ? t('toolbar.cancel') : t('lifecycle.edit')}</button>\n <button type=\"button\" className=\"memoir-iconbtn\" onClick={() => onUpdate(entry, { pinned: entry.pinned !== true })}>{entry.pinned === true ? t('lifecycle.unpin') : t('lifecycle.pin')}</button>\n {(entry.status ?? 'active') === 'active'\n ? <button type=\"button\" className=\"memoir-iconbtn\" onClick={() => onUpdate(entry, { status: 'superseded' })}>{t('lifecycle.supersede')}</button>\n : <button type=\"button\" className=\"memoir-iconbtn\" onClick={() => onUpdate(entry, { status: 'active' })}>{t('lifecycle.unsupersede')}</button>}\n <button type=\"button\" className=\"memoir-iconbtn\" onClick={() => onUpdate(entry, { status: entry.status === 'archived' ? 'active' : 'archived' })}>{entry.status === 'archived' ? t('lifecycle.restore') : t('lifecycle.archive')}</button>\n </div>\n : null}\n <EntryMeta entry={entry} t={t} openSource={openSource} />\n {score !== undefined\n ? <span className=\"memoir-score\" title={t('search.ranked')}>{score.toFixed(3)}</span>\n : null}\n {editing\n ? <div className=\"memoir-form memoir-entry-editor\">\n <div className=\"memoir-field\">\n <label>{t('form.section')}</label>\n <select value={section} onChange={(e) => setSection(e.target.value as SectionKey)}>\n {SECTION_KEYS.map((key) => <option key={key} value={key}>{t('sections.' + key)}</option>)}\n </select>\n </div>\n <div className=\"memoir-field\">\n <label>{t('form.title')}</label>\n <input value={title} onChange={(e) => setTitle(e.target.value)} />\n </div>\n <div className=\"memoir-field\">\n <label>{t('form.content')}</label>\n <textarea value={content} onChange={(e) => setContent(e.target.value)} />\n </div>\n <div className=\"memoir-form-row\">\n <div className=\"memoir-field\">\n <label>{t('form.importance')}</label>\n <select value={importance} onChange={(e) => setImportance(e.target.value)}>\n {[1, 2, 3, 4, 5].map((value) => <option key={value} value={value}>{value}</option>)}\n </select>\n </div>\n <div className=\"memoir-field\">\n <label>{t('form.tags')}</label>\n <input value={tags} placeholder={t('form.placeholder.tags')} onChange={(e) => setTags(e.target.value)} />\n </div>\n </div>\n <div className=\"memoir-field\">\n <label>{t('form.supersedes')}</label>\n <input value={supersedes} placeholder={t('form.placeholder.supersedes')} onChange={(e) => setSupersedes(e.target.value)} />\n </div>\n <div className=\"memoir-form-actions\">\n <button type=\"button\" className=\"memoir-iconbtn\" onClick={() => setEditing(false)}>{t('toolbar.cancel')}</button>\n <button type=\"button\" className=\"memoir-primary\" onClick={save}>{t('lifecycle.save')}</button>\n </div>\n </div>\n : <>\n {entry.title !== undefined ? <div className=\"memoir-entry-title\">{entry.title}</div> : null}\n <div className=\"memoir-entry-content\" data-expanded={contentExpanded ? 'true' : undefined} data-collapsible={shouldCollapseEntry(entry.content) ? 'true' : undefined}>{entry.content}</div>\n {shouldCollapseEntry(entry.content)\n ? <button\n type=\"button\"\n className=\"memoir-content-toggle\"\n aria-expanded={contentExpanded}\n onClick={() => setContentExpanded((value) => !value)}\n >{contentExpanded ? t('entry.collapse') : t('entry.expand')}</button>\n : null}\n </>}\n </div>\n )\n}\n\n/** Sectioned list with a per-section progressive rendering cap. */\nfunction SectionedEntries({ entries, t, onDelete, onUpdate, openSource, resetKey }: { entries: WireEntry[]; t: (key: string) => string; onDelete: (entry: WireEntry) => void; onUpdate?: (entry: WireEntry, patch: EntryPatch) => void; openSource?: (sessionId: string, turnId?: number) => void; resetKey: string }) {\n const [limit, setLimit] = useState(ENTRY_PAGE_SIZE)\n useEffect(() => setLimit(ENTRY_PAGE_SIZE), [resetKey])\n const groups = useMemo(\n () => SECTION_KEYS.map((key) => ({ key, entries: entries.filter((e) => e.section === key) })).filter((g) => g.entries.length > 0),\n [entries],\n )\n if (groups.length === 0) {\n return (\n <div className=\"memoir-empty\">\n <div className=\"memoir-empty-title\">{t('empty.search')}</div>\n </div>\n )\n }\n const visibleCount = groups.reduce((count, group) => count + Math.min(group.entries.length, limit), 0)\n const maxGroupSize = Math.max(...groups.map((group) => group.entries.length))\n const hasMore = visibleCount < entries.length\n return (\n <Fragment>\n {groups.map((group) => (\n <Fragment key={group.key}>\n <div className=\"memoir-section-title\">\n {t('sections.' + group.key)}\n <span className=\"memoir-count\">({group.entries.length})</span>\n </div>\n {group.entries.slice(0, limit).map((entry) => (\n <EntryCard key={entry.id} entry={entry} t={t} onDelete={onDelete} onUpdate={onUpdate} openSource={openSource} />\n ))}\n </Fragment>\n ))}\n {hasMore\n ? <div className=\"memoir-load-more\">\n <span>{t('pagination.showing')} {visibleCount}/{entries.length}</span>\n <button type=\"button\" className=\"memoir-iconbtn\" onClick={() => setLimit((value) => nextPageSize(value, maxGroupSize, ENTRY_PAGE_SIZE))}>{t('pagination.more')}</button>\n </div>\n : null}\n </Fragment>\n )\n}\n\n/**\n * Ranked project search results (v0.4.2): the host RetrievalEngine order.\n * Global ranked results use the same collapsible project shell as browsing.\n */\nfunction RankedResults({ results, pending, t, onDelete, onUpdate, openSource }: {\n results: WireSearchResult[]\n pending: boolean\n t: (key: string) => string\n onDelete: (entry: WireEntry, path: string) => void\n onUpdate?: (entry: WireEntry, path: string, patch: EntryPatch) => void\n openSource?: (sessionId: string, turnId?: number) => void\n}) {\n if (pending) return <div className=\"memoir-empty\">\u2026</div>\n if (results.length === 0) {\n return (\n <div className=\"memoir-empty\">\n <div className=\"memoir-empty-title\">{t('empty.search')}</div>\n <div className=\"memoir-empty-hint\">{t('search.ranked')}</div>\n </div>\n )\n }\n return (\n <Fragment>\n <div className=\"memoir-ranked-note\">{t('search.ranked')}</div>\n {results.map((r) => (\n <EntryCard key={r.entry.id} entry={r.entry} score={r.score} t={t} onDelete={(entry) => onDelete(entry, r.projectPath)} onUpdate={(entry, patch) => onUpdate?.(entry, r.projectPath, patch)} openSource={openSource} />\n ))}\n </Fragment>\n )\n}\n\nfunction ProjectDisclosure({ project, open, t, onToggle, children }: {\n project: { path: string; title: string; updatedAt: number; stats: EntryStats }\n open: boolean\n t: (key: string) => string\n onToggle: () => void\n children: ReactNode\n}) {\n const when = new Date(project.updatedAt)\n const title = project.title || t('project.unscoped')\n const path = project.path || t('project.unscopedHint')\n return (\n <section className=\"memoir-project-card\" data-expanded={open ? 'true' : undefined}>\n <button type=\"button\" className=\"memoir-project-toggle\" aria-expanded={open} onClick={onToggle}>\n <span className=\"memoir-project-chevron\" aria-hidden=\"true\">\u203A</span>\n <span className=\"memoir-project-heading\">\n <span className=\"memoir-project-head\">\n <span className=\"memoir-project-title\">{title}</span>\n <span className=\"memoir-project-path\" title={project.path}>{path}</span>\n </span>\n <span className=\"memoir-project-meta\">\n <span>{t('status.active')}: {project.stats.active}</span>\n <span>{t('status.archived')}: {project.stats.archived}</span>\n <span>{t('status.superseded')}: {project.stats.superseded}</span>\n <span>{t('updated')} {when.toISOString().slice(0, 16).replace('T', ' ')}</span>\n </span>\n </span>\n </button>\n {open ? <div className=\"memoir-project-body\">{children}</div> : null}\n </section>\n )\n}\n\ntype AddPayload = {\n section: SectionKey\n title?: string\n content: string\n importance: number\n pinned: boolean\n tags: string[]\n supersedes: string[]\n}\n\nfunction AddForm({ t, onSubmit, onCancel }: { t: (key: string) => string; onSubmit: (payload: AddPayload) => void; onCancel: () => void }) {\n const [section, setSection] = useState<SectionKey>('lessons')\n const [title, setTitle] = useState('')\n const [content, setContent] = useState('')\n const [importance, setImportance] = useState('3')\n const [pinned, setPinned] = useState(false)\n const [tags, setTags] = useState('')\n const [supersedes, setSupersedes] = useState('')\n const submit = () => {\n if (content.trim() === '') return\n onSubmit({\n section,\n title: title.trim() === '' ? undefined : title.trim(),\n content: content.trim(),\n importance: Number(importance),\n pinned,\n tags: parseList(tags),\n supersedes: parseList(supersedes),\n })\n }\n return (\n <div className=\"memoir-form\" data-dsh-part=\"entry-form\">\n <div className=\"memoir-form-row\">\n <div className=\"memoir-field\">\n <label>{t('form.section')}</label>\n <select value={section} onChange={(e) => setSection(e.target.value as SectionKey)}>\n {SECTION_KEYS.map((key) => (\n <option key={key} value={key}>{t('sections.' + key)}</option>\n ))}\n </select>\n </div>\n <div className=\"memoir-field\">\n <label>{t('form.title')}</label>\n <input value={title} placeholder={t('form.placeholder.title')} onChange={(e) => setTitle(e.target.value)} />\n </div>\n </div>\n <div className=\"memoir-field\">\n <label>{t('form.content')}</label>\n <textarea value={content} placeholder={t('form.placeholder.content')} onChange={(e) => setContent(e.target.value)} />\n </div>\n <div className=\"memoir-form-row\">\n <div className=\"memoir-field\">\n <label>{t('form.importance')}</label>\n <select value={importance} onChange={(e) => setImportance(e.target.value)}>\n {[1, 2, 3, 4, 5].map((value) => <option key={value} value={value}>{value}</option>)}\n </select>\n <small>{t('form.importanceHint')}</small>\n </div>\n <div className=\"memoir-field\">\n <label>{t('form.tags')}</label>\n <input value={tags} placeholder={t('form.placeholder.tags')} onChange={(e) => setTags(e.target.value)} />\n </div>\n </div>\n <div className=\"memoir-field\">\n <label>{t('form.supersedes')}</label>\n <input value={supersedes} placeholder={t('form.placeholder.supersedes')} onChange={(e) => setSupersedes(e.target.value)} />\n </div>\n <label className=\"memoir-settings-switch\">\n <input type=\"checkbox\" checked={pinned} onChange={(e) => setPinned(e.target.checked)} />\n <span><strong>{t('form.pinned')}</strong><small>{t('form.pinnedHint')}</small></span>\n </label>\n <div className=\"memoir-form-actions\">\n <button type=\"button\" className=\"memoir-iconbtn\" onClick={onCancel}>{t('toolbar.cancel')}</button>\n <button type=\"button\" className=\"memoir-primary\" onClick={submit}>{t('form.submit')}</button>\n </div>\n </div>\n )\n}\n\nfunction SimilarityCandidateCard({ candidate, t, busy, onResolve }: {\n candidate: WireSimilarityCandidate\n t: (key: string) => string\n busy: boolean\n onResolve: (resolution: WireRecordResolution, targetId: string) => void\n}) {\n return (\n <div className=\"memoir-similarity-candidate\">\n <div className=\"memoir-similarity-head\">\n <span className={`memoir-chip memoir-similarity-${candidate.kind}`}>{t(`similarity.kind.${candidate.kind}`)}</span>\n <strong>{candidate.entry.title ?? candidate.entry.content.slice(0, 100)}</strong>\n <span className=\"memoir-score-static\">{Math.round(candidate.score * 100)}%</span>\n </div>\n {candidate.entry.title !== undefined ? <div className=\"memoir-similarity-content\">{candidate.entry.content}</div> : null}\n <div className=\"memoir-similarity-components\">\n BM25 {Math.round(candidate.components.bm25 * 100)}% \u00B7 {t('similarity.titleScore')} {Math.round(candidate.components.title * 100)}% \u00B7 Jaccard {Math.round(candidate.components.tokenJaccard * 100)}%\n </div>\n <div className=\"memoir-similarity-reasons\">\n {candidate.reasons.map((reason) => <span className=\"memoir-chip\" key={reason}>{t(`similarity.reason.${reason}`)}</span>)}\n </div>\n <div className=\"memoir-form-actions\">\n <button type=\"button\" className=\"memoir-iconbtn\" disabled={busy} onClick={() => onResolve('update', candidate.entry.id)}>{t('similarity.update')}</button>\n <button type=\"button\" className=\"memoir-primary\" disabled={busy} onClick={() => onResolve('supersede', candidate.entry.id)}>{t('similarity.supersede')}</button>\n </div>\n </div>\n )\n}\n\nfunction SimilarityResolution({ result, t, busy, onResolve, onBack }: {\n result: WireRecordResult\n t: (key: string) => string\n busy: boolean\n onResolve: (resolution: WireRecordResolution, targetId?: string) => void\n onBack: () => void\n}) {\n return (\n <div className=\"memoir-similarity\" data-dsh-part=\"similarity-resolution\">\n <div className=\"memoir-similarity-title\">{t('similarity.title')}</div>\n <div className=\"memoir-settings-description\">{t('similarity.description')}</div>\n {result.candidates.map((candidate) => (\n <SimilarityCandidateCard key={candidate.entry.id} candidate={candidate} t={t} busy={busy} onResolve={onResolve} />\n ))}\n <div className=\"memoir-similarity-footer\">\n <button type=\"button\" className=\"memoir-iconbtn\" disabled={busy} onClick={onBack}>{t('similarity.back')}</button>\n <button type=\"button\" className=\"memoir-iconbtn\" disabled={busy} onClick={() => onResolve('force-record')}>{t('similarity.force')}</button>\n </div>\n </div>\n )\n}\n\ntype NumericSettingsKey =\n | 'autoDistillEvery'\n | 'autoDistillCooldownMin'\n | 'autoDistillMinTools'\n | 'hotMemoryTokens'\n | 'hotMemoryMaxTokens'\n | 'readDefaultLimit'\n | 'readMaxLimit'\n | 'sessionSnapshotMax'\n | 'queryCacheSize'\n\nconst NUMERIC_SETTINGS: NumericSettingsKey[] = [\n 'autoDistillEvery',\n 'autoDistillCooldownMin',\n 'autoDistillMinTools',\n 'hotMemoryTokens',\n 'hotMemoryMaxTokens',\n 'readDefaultLimit',\n 'readMaxLimit',\n 'sessionSnapshotMax',\n 'queryCacheSize',\n]\n\n/** Persistent, live complete settings shared by the panel and Settings page. */\nexport function MemoirSettingsPanel({ api, t, refreshKey, onChanged, defaultOpen = false, alwaysOpen = false, showDescription = true }: {\n api: MemoirApi\n t: (key: string) => string\n refreshKey: number\n onChanged: () => void\n defaultOpen?: boolean\n alwaysOpen?: boolean\n showDescription?: boolean\n}) {\n const [open, setOpen] = useState(defaultOpen)\n const [settings, setSettings] = useState<WireMemoirSettings | null>(null)\n const [source, setSource] = useState<'profile' | 'web'>('profile')\n const [draft, setDraft] = useState<Record<NumericSettingsKey, string>>({\n autoDistillEvery: '1',\n autoDistillCooldownMin: '0',\n autoDistillMinTools: '1',\n hotMemoryTokens: '900',\n hotMemoryMaxTokens: '1200',\n readDefaultLimit: '8',\n readMaxLimit: '30',\n sessionSnapshotMax: '128',\n queryCacheSize: '128',\n })\n const [busy, setBusy] = useState(false)\n const [message, setMessage] = useState<string | null>(null)\n const [error, setError] = useState<string | null>(null)\n\n const applySnapshot = (snapshot: { settings: WireMemoirSettings; source: 'profile' | 'web' }) => {\n setError(null)\n setSettings(snapshot.settings)\n setSource(snapshot.source)\n setDraft(Object.fromEntries(NUMERIC_SETTINGS.map((key) => [key, String(snapshot.settings[key])])) as Record<NumericSettingsKey, string>)\n }\n\n useEffect(() => {\n let cancelled = false\n api.settings()\n .then((value) => { if (!cancelled) applySnapshot(value) })\n .catch((e: Error) => { if (!cancelled) setError(`${t('settings.loadFailed')}: ${e.message}`) })\n return () => { cancelled = true }\n }, [api, refreshKey])\n\n const save = () => {\n if (settings === null) return\n const parsed = Object.fromEntries(NUMERIC_SETTINGS.map((key) => [key, Number(draft[key])])) as Record<NumericSettingsKey, number>\n const integerKeys = NUMERIC_SETTINGS.filter((key) => key !== 'autoDistillCooldownMin')\n const invalidInteger = integerKeys.some((key) => !Number.isSafeInteger(parsed[key]) || parsed[key] < 1)\n if (\n invalidInteger\n || !Number.isFinite(parsed.autoDistillCooldownMin)\n || parsed.autoDistillCooldownMin < 0\n || parsed.hotMemoryMaxTokens < parsed.hotMemoryTokens\n || parsed.readMaxLimit < parsed.readDefaultLimit\n ) {\n setMessage(null)\n setError(t('settings.invalid'))\n return\n }\n setBusy(true)\n setError(null)\n setMessage(null)\n api.updateSettings({\n language: settings.language,\n announceToAgent: settings.announceToAgent,\n autoDistill: settings.autoDistill,\n ...parsed,\n })\n .then((value) => {\n applySnapshot(value)\n setMessage(t('settings.saved'))\n onChanged()\n })\n .catch((e: Error) => setError(`${t('settings.saveFailed')}: ${e.message}`))\n .finally(() => setBusy(false))\n }\n\n const reset = () => {\n setBusy(true)\n setError(null)\n setMessage(null)\n api.resetSettings()\n .then((value) => {\n applySnapshot(value)\n setMessage(t('settings.resetDone'))\n onChanged()\n })\n .catch((e: Error) => setError(`${t('settings.saveFailed')}: ${e.message}`))\n .finally(() => setBusy(false))\n }\n\n return (\n <div className=\"memoir-settings\" data-dsh-part=\"settings\">\n {!alwaysOpen\n ? <button type=\"button\" className=\"memoir-diagnostics-toggle\" aria-expanded={open} onClick={() => setOpen((value) => !value)}>\n {t('settings.title')} {open ? '\u25BE' : '\u25B8'}\n </button>\n : null}\n {alwaysOpen || open\n ? settings === null\n ? <div className=\"memoir-settings-body\">{error ?? '\u2026'}</div>\n : (\n <div className=\"memoir-settings-body\">\n {showDescription ? <div className=\"memoir-settings-description\">{t('settings.description')}</div> : null}\n <div className=\"memoir-settings-grid\">\n <label className=\"memoir-field\">\n <span>{t('settings.language')}</span>\n <select\n value={settings.language}\n onChange={(event) => setSettings({ ...settings, language: resolveMemoirLanguage(event.target.value) })}\n >\n {MEMOIR_LANGUAGES.map(language => <option key={language} value={language}>{t(`settings.language.${language}`)}</option>)}\n </select>\n <small>{t('settings.languageHint')}</small>\n </label>\n </div>\n <label className=\"memoir-settings-switch\">\n <input\n type=\"checkbox\"\n checked={settings.announceToAgent}\n onChange={(event) => setSettings({ ...settings, announceToAgent: event.target.checked })}\n />\n <span><strong>{t('settings.announce')}</strong><small>{t('settings.announceHint')}</small></span>\n </label>\n <div className=\"memoir-settings-group-title\">{t('settings.group.distill')}</div>\n <label className=\"memoir-settings-switch\">\n <input\n type=\"checkbox\"\n checked={settings.autoDistill}\n onChange={(event) => setSettings({ ...settings, autoDistill: event.target.checked })}\n />\n <span><strong>{t('settings.enabled')}</strong><small>{t('settings.enabledHint')}</small></span>\n </label>\n <div className=\"memoir-settings-grid\">\n {(['autoDistillEvery', 'autoDistillCooldownMin', 'autoDistillMinTools'] as NumericSettingsKey[]).map((key) => (\n <label className=\"memoir-field\" key={key}>\n <span>{t(`settings.${key}`)}</span>\n <input\n type=\"number\"\n min={key === 'autoDistillCooldownMin' ? '0' : '1'}\n step={key === 'autoDistillCooldownMin' ? '0.1' : '1'}\n value={draft[key]}\n onChange={(event) => setDraft({ ...draft, [key]: event.target.value })}\n />\n <small>{t(`settings.${key}Hint`)}</small>\n </label>\n ))}\n </div>\n <div className=\"memoir-settings-note\">{t('settings.andHint')}</div>\n <div className=\"memoir-settings-group-title\">{t('settings.group.memory')}</div>\n <div className=\"memoir-settings-grid\">\n {(['hotMemoryTokens', 'hotMemoryMaxTokens', 'readDefaultLimit', 'readMaxLimit', 'sessionSnapshotMax', 'queryCacheSize'] as NumericSettingsKey[]).map((key) => (\n <label className=\"memoir-field\" key={key}>\n <span>{t(`settings.${key}`)}</span>\n <input\n type=\"number\"\n min=\"1\"\n step=\"1\"\n value={draft[key]}\n onChange={(event) => setDraft({ ...draft, [key]: event.target.value })}\n />\n <small>{t(`settings.${key}Hint`)}</small>\n </label>\n ))}\n </div>\n <div className=\"memoir-settings-note\">{t('settings.liveHint')}</div>\n <div className=\"memoir-settings-source\">{t('settings.source')}: {t(`settings.source.${source}`)}</div>\n {error !== null ? <div className=\"memoir-error memoir-settings-feedback\">{error}</div> : null}\n {message !== null ? <div className=\"memoir-settings-success\">{message}</div> : null}\n <div className=\"memoir-form-actions\">\n <button type=\"button\" className=\"memoir-iconbtn\" disabled={busy || source === 'profile'} onClick={reset}>{t('settings.reset')}</button>\n <button type=\"button\" className=\"memoir-primary\" disabled={busy} onClick={save}>{t('settings.save')}</button>\n </div>\n </div>\n )\n : null}\n </div>\n )\n}\n\ntype PanelSurface = 'browse' | 'settings' | 'hot-memory' | 'diagnostics'\n\nconst PANEL_SURFACES: Array<{ id: PanelSurface; label: string }> = [\n { id: 'browse', label: 'surface.browse' },\n { id: 'settings', label: 'surface.settings' },\n { id: 'hot-memory', label: 'surface.hotMemory' },\n { id: 'diagnostics', label: 'surface.diagnostics' },\n]\n\nexport function MemoirPanel({ controller, api, cwdTracker = EMPTY_CWD_TRACKER, cwd: fixedCwd, t, openSource, onClose, announceOnOpen = false }: PanelProps) {\n const [, setLanguage] = useState(document.documentElement.lang)\n useEffect(() => {\n const observer = new MutationObserver(() => setLanguage(document.documentElement.lang))\n observer.observe(document.documentElement, { attributes: true, attributeFilter: ['lang'] })\n return () => observer.disconnect()\n }, [])\n const trackedCwd = useSyncExternalStore(cwdTracker.subscribe, cwdTracker.getSnapshot)\n const cwd = fixedCwd ?? trackedCwd\n const close = onClose ?? (controller === undefined ? undefined : () => controller.close())\n const panelId = useId().replace(/:/g, '')\n const [surface, setSurface] = useState<PanelSurface>('browse')\n const [tab, setTab] = useState<'project' | 'global'>('project')\n const [query, setQuery] = useState('')\n const [statusFilter, setStatusFilter] = useState<MemoirStatus | 'all'>('active')\n const [sectionFilter, setSectionFilter] = useState<SectionKey | 'all'>('all')\n const [formOpen, setFormOpen] = useState(false)\n const [pendingRecord, setPendingRecord] = useState<{ payload: AddPayload; result: WireRecordResult } | null>(null)\n const [refreshKey, setRefreshKey] = useState(0)\n const [project, setProject] = useState<WireProject | null>(null)\n const [projects, setProjects] = useState<WireProject[]>([])\n const [loading, setLoading] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const [busy, setBusy] = useState(false)\n const [diag, setDiag] = useState<WireDiagnostics | null>(null)\n const [searchResults, setSearchResults] = useState<WireSearchResult[] | null>(null)\n const [hotMemory, setHotMemory] = useState<WireHotMemory | null>(null)\n const [expandedProjects, setExpandedProjects] = useState<Record<string, boolean>>({})\n const [projectLimit, setProjectLimit] = useState(PROJECT_PAGE_SIZE)\n\n const q = query.trim().toLowerCase()\n\n useEffect(() => {\n let cancelled = false\n setError(null)\n if (tab === 'project') {\n if (cwd === '') {\n setProject(null)\n return undefined\n }\n setLoading(true)\n api.project(cwd, { status: 'all' })\n .then((value) => { if (!cancelled) setProject(value.project) })\n .catch((e: Error) => { if (!cancelled) setError(e.message) })\n .finally(() => { if (!cancelled) setLoading(false) })\n } else {\n setLoading(true)\n api.global({ status: 'all' })\n .then((value) => { if (!cancelled) setProjects(value.projects) })\n .catch((e: Error) => { if (!cancelled) setError(e.message) })\n .finally(() => { if (!cancelled) setLoading(false) })\n }\n return () => { cancelled = true }\n }, [tab, cwd, refreshKey])\n\n useEffect(() => {\n let cancelled = false\n // Diagnostics and Hot Memory follow the active workspace independently\n // from browse filters so surface switches never trigger redundant reads.\n api.diagnostics(cwd === '' ? undefined : cwd)\n .then((value) => { if (!cancelled) setDiag(value) })\n .catch(() => { if (!cancelled) setDiag(null) })\n // Hot-memory inspector preview (what the next session inherits).\n if (cwd === '') {\n setHotMemory(null)\n } else {\n api.hotMemory(cwd)\n .then((value) => { if (!cancelled) setHotMemory(value.hotMemory) })\n .catch(() => { if (!cancelled) setHotMemory(null) })\n }\n return () => { cancelled = true }\n }, [cwd, refreshKey])\n\n // v0.4.2: a non-empty query searches through the host RetrievalEngine \u2014\n // the same BM25 ranking memoir_read uses. Debounced; empty query resets.\n useEffect(() => {\n if (q === '') {\n setSearchResults(null)\n return undefined\n }\n if (tab === 'project' && cwd === '') {\n setSearchResults([])\n return undefined\n }\n let cancelled = false\n setSearchResults(null)\n const timer = setTimeout(() => {\n const scope = tab === 'project' ? 'project' : 'global'\n api.search({\n scope,\n path: tab === 'project' && cwd !== '' ? cwd : undefined,\n query: q,\n status: statusFilter,\n section: sectionFilter === 'all' ? undefined : sectionFilter,\n })\n .then((value) => { if (!cancelled) setSearchResults(value.results) })\n .catch((e: Error) => {\n if (!cancelled) {\n setSearchResults([])\n setError(e.message)\n }\n })\n }, 200)\n return () => { cancelled = true; clearTimeout(timer) }\n }, [q, tab, cwd, statusFilter, sectionFilter, refreshKey])\n\n const reload = () => setRefreshKey((k) => k + 1)\n\n const onDelete = (entry: WireEntry, entryPath: string) => {\n if (!window.confirm(t('delete.confirm'))) return\n setBusy(true)\n api.remove({ path: entryPath, id: entry.id })\n .then(() => reload())\n .catch((e: Error) => setError(`${t('delete.failed')}: ${e.message}`))\n .finally(() => setBusy(false))\n }\n\n const onRecord = (payload: AddPayload, resolution?: WireRecordResolution, targetId?: string) => {\n setBusy(true)\n api.record({ path: cwd, ...payload, ...(resolution !== undefined ? { resolution } : {}), ...(targetId !== undefined ? { targetId } : {}) })\n .then((result) => {\n if (result.action === 'needs-resolution') {\n setPendingRecord({ payload, result })\n return\n }\n setPendingRecord(null)\n setFormOpen(false)\n reload()\n })\n .catch((e: Error) => setError(`${t('record.failed')}: ${e.message}`))\n .finally(() => setBusy(false))\n }\n\n const onUpdate = (entry: WireEntry, entryPath: string, patch: EntryPatch) => {\n setBusy(true)\n api.update({ path: entryPath, id: entry.id, ...patch })\n .then(() => reload())\n .catch((e: Error) => setError(`${t('update.failed')}: ${e.message}`))\n .finally(() => setBusy(false))\n }\n\n const projectEntries = useMemo(\n () => project === null ? [] : filterEntries(project.entries, statusFilter, sectionFilter),\n [project, statusFilter, sectionFilter],\n )\n const globalGroups = useMemo(\n () => buildProjectGroups(projects, statusFilter, sectionFilter),\n [projects, statusFilter, sectionFilter],\n )\n const rankedGlobalGroups = useMemo(\n () => groupRankedResults(searchResults ?? [], projects),\n [searchResults, projects],\n )\n const displayedGlobalGroups = q === '' ? globalGroups : rankedGlobalGroups\n const projectSignature = displayedGlobalGroups.map((group) => group.key).join('\\n')\n const narrowingSignature = q === '' && statusFilter === 'active' && sectionFilter === 'all'\n ? ''\n : `${q}\\n${statusFilter}\\n${sectionFilter}\\n${projectSignature}`\n\n useEffect(() => {\n setProjectLimit(PROJECT_PAGE_SIZE)\n }, [tab, q, statusFilter, sectionFilter, refreshKey])\n\n useEffect(() => {\n if (tab !== 'global' || narrowingSignature === '') return\n setExpandedProjects((current) => {\n const next = { ...current }\n for (const group of displayedGlobalGroups) next[group.key] = true\n return next\n })\n }, [tab, narrowingSignature])\n\n const setAllProjects = (open: boolean) => {\n setExpandedProjects((current) => {\n const next = { ...current }\n for (const group of displayedGlobalGroups) next[group.key] = open\n return next\n })\n }\n\n const onSurfaceKeyDown = (event: ReactKeyboardEvent<HTMLButtonElement>, index: number) => {\n let nextIndex: number | undefined\n if (event.key === 'ArrowRight') nextIndex = (index + 1) % PANEL_SURFACES.length\n if (event.key === 'ArrowLeft') nextIndex = (index - 1 + PANEL_SURFACES.length) % PANEL_SURFACES.length\n if (event.key === 'Home') nextIndex = 0\n if (event.key === 'End') nextIndex = PANEL_SURFACES.length - 1\n if (nextIndex === undefined) return\n event.preventDefault()\n const next = PANEL_SURFACES[nextIndex]\n setSurface(next.id)\n document.getElementById(`${panelId}-${next.id}-tab`)?.focus()\n }\n\n const headerSubtitle = surface === 'browse'\n ? (tab === 'project' ? (cwd === '' ? t('empty.workspace') : cwd) : t('tab.global'))\n : t(PANEL_SURFACES.find((item) => item.id === surface)?.label ?? 'surface.browse')\n const visibleGlobalGroups = displayedGlobalGroups.slice(0, projectLimit)\n const listResetKey = `${tab}:${q}:${statusFilter}:${sectionFilter}:${refreshKey}`\n\n return (\n <div className=\"memoir-panel\" data-dsh-plugin=\"memoir\" data-dsh-part=\"panel\">\n <div className=\"memoir-header\" data-dsh-part=\"header\">\n <div className=\"memoir-title\">\n {t('panel.title')}\n <div className=\"memoir-subtitle\">{headerSubtitle}</div>\n </div>\n <button type=\"button\" className=\"memoir-iconbtn\" title={t('panel.refresh')} onClick={reload}>\u27F3</button>\n {close === undefined\n ? null\n : <button type=\"button\" className=\"memoir-iconbtn\" title={t('panel.close')} onClick={close}>\u00D7</button>}\n </div>\n <MemoirAbout t={t} announceOnOpen={announceOnOpen} settingsTarget={`${panelId}-settings-panel`} onSettings={() => {\n setSurface('settings')\n document.getElementById(`${panelId}-settings-tab`)?.focus()\n }} />\n <nav className=\"memoir-surface-tabs\" data-dsh-part=\"surface-tabs\" role=\"tablist\" aria-label={t('surface.navigation')}>\n {PANEL_SURFACES.map((item, index) => (\n <button\n type=\"button\"\n id={`${panelId}-${item.id}-tab`}\n className=\"memoir-surface-tab\"\n role=\"tab\"\n aria-selected={surface === item.id}\n aria-controls={`${panelId}-${item.id}-panel`}\n tabIndex={surface === item.id ? 0 : -1}\n data-active={surface === item.id ? 'true' : undefined}\n onClick={() => setSurface(item.id)}\n onKeyDown={(event) => onSurfaceKeyDown(event, index)}\n key={item.id}\n >{t(item.label)}</button>\n ))}\n </nav>\n <div className=\"memoir-surface-stack\">\n <section\n id={`${panelId}-browse-panel`}\n className=\"memoir-surface memoir-browse-surface\"\n role=\"tabpanel\"\n aria-labelledby={`${panelId}-browse-tab`}\n hidden={surface !== 'browse'}\n >\n <div className=\"memoir-browse-head\">\n <div className=\"memoir-tabs\" data-dsh-part=\"tabs\" role=\"tablist\" aria-label={t('browse.scope')}>\n <button type=\"button\" className=\"memoir-tab\" role=\"tab\" aria-selected={tab === 'project'} data-active={tab === 'project' ? 'true' : undefined} onClick={() => setTab('project')}>{t('tab.project')}</button>\n <button type=\"button\" className=\"memoir-tab\" role=\"tab\" aria-selected={tab === 'global'} data-active={tab === 'global' ? 'true' : undefined} onClick={() => setTab('global')}>{t('tab.global')}</button>\n </div>\n <div className=\"memoir-toolbar\" data-dsh-part=\"toolbar\">\n <input className=\"memoir-search\" aria-label={t('toolbar.search')} placeholder={t('toolbar.search')} value={query} onChange={(e) => setQuery(e.target.value)} />\n <label className=\"memoir-status-filter\">\n <span>{t('filter.status')}</span>\n <select value={statusFilter} onChange={(e) => setStatusFilter(e.target.value as MemoirStatus | 'all')}>\n <option value=\"active\">{t('status.active')}</option>\n <option value=\"all\">{t('filter.all')}</option>\n <option value=\"superseded\">{t('status.superseded')}</option>\n <option value=\"archived\">{t('status.archived')}</option>\n </select>\n </label>\n <label className=\"memoir-status-filter\">\n <span>{t('filter.section')}</span>\n <select value={sectionFilter} onChange={(e) => setSectionFilter(e.target.value as SectionKey | 'all')}>\n <option value=\"all\">{t('filter.all')}</option>\n {SECTION_KEYS.map((key) => <option key={key} value={key}>{t('sections.' + key)}</option>)}\n </select>\n </label>\n {tab === 'project' && cwd !== ''\n ? <button type=\"button\" className=\"memoir-primary\" onClick={() => {\n setFormOpen((value) => !value)\n setPendingRecord(null)\n }}>{formOpen ? t('toolbar.cancel') : t('toolbar.add')}</button>\n : null}\n {tab === 'global' && displayedGlobalGroups.length > 0\n ? <div className=\"memoir-project-actions\">\n <button type=\"button\" className=\"memoir-iconbtn\" onClick={() => setAllProjects(true)}>{t('project.expandAll')}</button>\n <button type=\"button\" className=\"memoir-iconbtn\" onClick={() => setAllProjects(false)}>{t('project.collapseAll')}</button>\n </div>\n : null}\n </div>\n {error !== null ? <div className=\"memoir-error\" role=\"alert\">{error}</div> : null}\n </div>\n <div className=\"memoir-surface-scroll memoir-scroll-region\" data-dsh-part=\"browse-scroll\" tabIndex={0} aria-label={t('surface.browse')}>\n {formOpen && tab === 'project' && cwd !== ''\n ? pendingRecord === null\n ? <AddForm t={t} onSubmit={onRecord} onCancel={() => setFormOpen(false)} />\n : <SimilarityResolution\n result={pendingRecord.result}\n t={t}\n busy={busy}\n onResolve={(resolution, targetId) => onRecord(pendingRecord.payload, resolution, targetId)}\n onBack={() => setPendingRecord(null)}\n />\n : null}\n <div className=\"memoir-body\" aria-busy={loading || busy}>\n {loading\n ? <div className=\"memoir-empty\">\u2026</div>\n : tab === 'project'\n ? q !== ''\n ? <RankedResults results={searchResults ?? []} pending={searchResults === null} t={t} openSource={openSource} onDelete={onDelete} onUpdate={onUpdate} />\n : cwd === ''\n ? <div className=\"memoir-empty\"><div className=\"memoir-empty-title\">{t('empty.workspace')}</div><div className=\"memoir-empty-hint\">{t('empty.workspaceHint')}</div></div>\n : projectEntries.length === 0\n ? <div className=\"memoir-empty\"><div className=\"memoir-empty-title\">{t('empty.project')}</div><div className=\"memoir-empty-hint\">{t('empty.projectHint')}</div></div>\n : <SectionedEntries resetKey={listResetKey} entries={projectEntries} t={t} openSource={openSource} onDelete={(entry) => onDelete(entry, project?.path ?? cwd)} onUpdate={(entry, patch) => onUpdate(entry, project?.path ?? cwd, patch)} />\n : q !== '' && searchResults === null\n ? <div className=\"memoir-empty\">\u2026</div>\n : displayedGlobalGroups.length === 0\n ? <div className=\"memoir-empty\"><div className=\"memoir-empty-title\">{projects.length === 0 && q === '' ? t('empty.global') : t('empty.search')}</div><div className=\"memoir-empty-hint\">{projects.length === 0 && q === '' ? t('empty.globalHint') : t('search.ranked')}</div></div>\n : <>\n {visibleGlobalGroups.map((group) => {\n const open = expandedProjects[group.key] === true\n return (\n <ProjectDisclosure\n project={group}\n open={open}\n t={t}\n onToggle={() => setExpandedProjects((current) => ({ ...current, [group.key]: !open }))}\n key={group.key}\n >\n {'results' in group\n ? <>\n <div className=\"memoir-ranked-note\">{t('search.ranked')}</div>\n {group.results.map((result) => <EntryCard key={result.entry.id} entry={result.entry} score={result.score} t={t} openSource={openSource} onDelete={(entry) => onDelete(entry, group.path)} onUpdate={(entry, patch) => onUpdate(entry, group.path, patch)} />)}\n </>\n : <SectionedEntries resetKey={`${listResetKey}:${group.key}`} entries={group.entries} t={t} openSource={openSource} onDelete={(entry) => onDelete(entry, group.path)} onUpdate={(entry, patch) => onUpdate(entry, group.path, patch)} />}\n </ProjectDisclosure>\n )\n })}\n {projectLimit < displayedGlobalGroups.length\n ? <div className=\"memoir-load-more\"><span>{t('pagination.projects')} {visibleGlobalGroups.length}/{displayedGlobalGroups.length}</span><button type=\"button\" className=\"memoir-iconbtn\" onClick={() => setProjectLimit((value) => nextPageSize(value, displayedGlobalGroups.length, PROJECT_PAGE_SIZE))}>{t('pagination.more')}</button></div>\n : null}\n </>}\n </div>\n {busy ? <div className=\"memoir-empty memoir-busy\" aria-live=\"polite\">\u2026</div> : null}\n </div>\n </section>\n\n <section id={`${panelId}-settings-panel`} className=\"memoir-surface\" role=\"tabpanel\" aria-labelledby={`${panelId}-settings-tab`} hidden={surface !== 'settings'}>\n <div className=\"memoir-surface-scroll\" data-dsh-part=\"settings-scroll\" tabIndex={0} aria-label={t('surface.settings')}>\n <MemoirSettingsPanel api={api} t={t} refreshKey={refreshKey} onChanged={reload} alwaysOpen />\n </div>\n </section>\n\n <section id={`${panelId}-hot-memory-panel`} className=\"memoir-surface\" role=\"tabpanel\" aria-labelledby={`${panelId}-hot-memory-tab`} hidden={surface !== 'hot-memory'}>\n <div className=\"memoir-surface-scroll\" data-dsh-part=\"hot-memory-scroll\" tabIndex={0} aria-label={t('surface.hotMemory')}>\n <div className=\"memoir-surface-card\" data-dsh-part=\"hot-memory\">\n <h3>{t('inspector.title')}</h3>\n {hotMemory === null || hotMemory.text === ''\n ? <div className=\"memoir-empty\"><div className=\"memoir-empty-title\">{t('inspector.empty')}</div></div>\n : <>\n <div className=\"memoir-surface-summary\">{t('inspector.selected')}: {hotMemory.selected.length}/{hotMemory.total} \u00B7 ~{hotMemory.estimatedTokens} tokens</div>\n <pre className=\"memoir-inspector-body\">{hotMemory.text}</pre>\n </>}\n </div>\n </div>\n </section>\n\n <section id={`${panelId}-diagnostics-panel`} className=\"memoir-surface\" role=\"tabpanel\" aria-labelledby={`${panelId}-diagnostics-tab`} hidden={surface !== 'diagnostics'}>\n <div className=\"memoir-surface-scroll\" data-dsh-part=\"diagnostics-scroll\" tabIndex={0} aria-label={t('surface.diagnostics')}>\n <div className=\"memoir-surface-card\" data-dsh-part=\"diagnostics\">\n <h3>{t('diag.title')}</h3>\n {diag === null\n ? <div className=\"memoir-empty\">{t('diag.unavailable')}</div>\n : <div className=\"memoir-diagnostics-body\">\n {diag.autoDistill ? <div>\n <h4>{t('distill.title')}</h4>\n <div>{t('distill.worked')}: {diag.autoDistill.workedTurns} \u00B7 {t('distill.agents')}: {diag.autoDistill.agents}/1024</div>\n <div>{t('distill.note')}</div>\n {Object.entries(diag.autoDistill.counts).map(([reason, count]) => <div key={reason}>{t(`distill.${reason}`)}: {count}</div>)}\n {diag.autoDistill.writes ? <div data-dsh-part=\"write-outcomes\">\n <h4>{t('writes.title')}</h4>\n {Object.entries(diag.autoDistill.writes).map(([reason, count]) => <div key={reason}>{t(`writes.${reason}`)}: {count}</div>)}\n <div>{t('writes.note')}</div>\n </div> : null}\n {diag.autoDistill.last ? <div>{t('distill.last')}: {t(`distill.${diag.autoDistill.last.outcome}`)} \u00B7 {new Date(diag.autoDistill.last.at).toLocaleString()} \u00B7 turn {diag.autoDistill.last.turn}</div> : null}\n </div> : null}\n <div>{t('diag.revision')}: {diag.storeRevision} \u00B7 {t('diag.snapshot')}: {diag.snapshotCount}/{diag.snapshotMax}</div>\n {diag.snapshotPersistence ? <div data-dsh-part=\"snapshot-persistence\">\n <h4>{t('snapshot.disk')}</h4>\n <div>{t('snapshot.restored')}: {diag.snapshotPersistence.restored} \u00B7 {t('snapshot.created')}: {diag.snapshotPersistence.created} \u00B7 {t('snapshot.failures')}: {diag.snapshotPersistence.failures}</div>\n <div>{t('snapshot.last')}: {t(`snapshot.${diag.snapshotPersistence.lastStatus}`)}</div>\n {diag.snapshotPersistence.lastError ? <div role=\"status\">{t('snapshot.degraded')} ({t(`snapshot.${diag.snapshotPersistence.lastError}`)})</div> : null}\n <div>{t('snapshot.retention')}</div>\n </div> : null}\n <div>{t('diag.cache')}: {diag.cache.hits}/{diag.cache.loads} {t('diag.hits')} ({Math.round(diag.cache.hitRate * 100)}%) \u00B7 {t('diag.render')}: {Math.round(diag.cache.renderHitRate * 100)}%</div>\n {diag.hotMemory !== null ? <div>{t('diag.hot')}: {diag.hotMemory.selected}/{diag.hotMemory.total} {t('diag.items')} \u00B7 ~{diag.hotMemory.estimatedTokens} tokens \u00B7 {t('diag.budget')} {diag.config.hotMemoryTokens}/{diag.config.hotMemoryMaxTokens}</div> : null}\n <div>{t('diag.retrieval')}: {diag.retrieval.index === null ? '\u2014' : `${diag.retrieval.index.docs} ${t('diag.documents')} \u00B7 ${diag.retrieval.index.terms} ${t('diag.terms')} \u00B7 ${t('diag.epoch')} ${diag.retrieval.index.epoch}`}</div>\n <div>{t('diag.qcache')}: {diag.retrieval.cache.hits} {t('diag.hits')} / {diag.retrieval.cache.misses} {t('diag.misses')} ({Math.round(diag.retrieval.cache.hitRate * 100)}%) \u00B7 {diag.retrieval.cache.size}/{diag.retrieval.cache.capacity} \u00B7 {diag.retrieval.cache.evictions} {t('diag.evicted')}</div>\n {diag.retrieval.lastQuery !== null ? <div>{t('diag.lastQuery')}: {diag.retrieval.lastQuery.latencyMs.toFixed(1)} ms \u00B7 {diag.retrieval.lastQuery.returned}/{diag.retrieval.lastQuery.candidates} {t('diag.returned')}</div> : null}\n {diag.snapshot !== null ? <div>{t('diag.snapshotInfo')}: {diag.snapshot.hash} \u00B7 {t('diag.revision')} {diag.snapshot.storeRevision}</div> : null}\n </div>}\n </div>\n </div>\n </section>\n </div>\n </div>\n )\n}\n", "import { useState, useSyncExternalStore } from 'react'\nimport { ANNOUNCEMENT_VERSION, acknowledgeAnnouncement, hasAcknowledged, subscribeAnnouncement } from './announcement.js'\n\n/** Build-stamped, offline plugin identity. Never inspect workspace Git remotes. */\ndeclare const __MEMOIR_PACKAGE_INFO__: { version: string; hostRange: string; sdkBaseline: string }\nconst repository = 'https://github.com/Qinling-Melon-Farmers/dsh-memoir'\n\nexport function MemoirAbout({ t, onSettings, settingsTarget, announceOnOpen = false }: {\n t: (key: string) => string\n onSettings?: () => void\n settingsTarget?: string\n announceOnOpen?: boolean\n}) {\n const [manualNotice, setManualNotice] = useState(false)\n const seen = useSyncExternalStore(\n notify => subscribeAnnouncement(window, notify),\n () => hasAcknowledged(window),\n () => true,\n )\n const showNotice = manualNotice || (announceOnOpen && !seen)\n return <aside className=\"memoir-plugin-guide\" data-dsh-part=\"plugin-guide\" aria-label={t('guide.label')}>\n <div className=\"memoir-plugin-guide-row\">\n <strong className=\"memoir-plugin-identity\">dsh-memoir <span>v{__MEMOIR_PACKAGE_INFO__.version}</span></strong>\n <nav className=\"memoir-about-links\" aria-label={t('about.links')}>\n <a href={repository} title={t('about.repositoryNote')} target=\"_blank\" rel=\"noopener noreferrer\" referrerPolicy=\"no-referrer\">{t('guide.repository')}</a>\n <a href={`${repository}/blob/main/${t('about.readmeFile')}`} target=\"_blank\" rel=\"noopener noreferrer\" referrerPolicy=\"no-referrer\">{t('about.docs')}</a>\n {onSettings === undefined ? null : <button type=\"button\" className=\"memoir-guide-settings\" aria-controls={settingsTarget} onClick={onSettings}>{t('guide.settings')}</button>}\n </nav>\n </div>\n <details className=\"memoir-about\" data-dsh-part=\"about\">\n <summary>{t('about.title')}</summary>\n <div className=\"memoir-about-body\">\n <p>{t('sidebar.description')}</p>\n <dl>\n <dt>{t('about.host')}</dt><dd>{__MEMOIR_PACKAGE_INFO__.hostRange}</dd>\n <dt>{t('about.baseline')}</dt><dd>{__MEMOIR_PACKAGE_INFO__.sdkBaseline}</dd>\n <dt>{t('about.maintainer')}</dt><dd>Qinling-Melon-Farmers</dd>\n </dl>\n <p>{t('about.repositoryNote')}</p>\n <nav className=\"memoir-about-links\" aria-label={t('about.links')}>\n <a href={repository} target=\"_blank\" rel=\"noopener noreferrer\" referrerPolicy=\"no-referrer\">Qinling-Melon-Farmers/dsh-memoir</a>\n <a href={`${repository}/releases`} target=\"_blank\" rel=\"noopener noreferrer\" referrerPolicy=\"no-referrer\">{t('about.releases')}</a>\n <a href={`${repository}/issues`} target=\"_blank\" rel=\"noopener noreferrer\" referrerPolicy=\"no-referrer\">{t('about.issues')}</a>\n </nav>\n <p className=\"memoir-about-note\">{t('about.updates')}</p>\n <button type=\"button\" className=\"memoir-guide-settings\" onClick={() => setManualNotice(true)}>{t('notice.reopen')}</button>\n </div>\n </details>\n {showNotice ? <section className=\"memoir-announcement\" data-dsh-part=\"announcement\" aria-label={t('notice.title')}>\n <div className=\"memoir-plugin-guide-row\">\n <strong>{t('notice.title')} \u00B7 {ANNOUNCEMENT_VERSION}</strong>\n <button type=\"button\" className=\"memoir-guide-settings\" onClick={() => { acknowledgeAnnouncement(window); setManualNotice(false) }}>{t('notice.dismiss')}</button>\n </div>\n <p>{t('notice.compat')}</p>\n <p>{t('notice.features')}</p>\n <small>{t('notice.privacy')}</small>\n </section> : null}\n </aside>\n}\n", "/** Offline release notice state. This key stores no workspace or memory data. */\nexport const ANNOUNCEMENT_VERSION = '0.9.2'\nexport const ANNOUNCEMENT_KEY = 'dsh-memoir:announcement:last-acknowledged'\nconst EVENT = 'dsh-memoir:announcement-acknowledged'\nconst acknowledged = new WeakMap<Window, string>()\n\nexport function hasAcknowledged(target: Window, version = ANNOUNCEMENT_VERSION): boolean {\n if (acknowledged.get(target) === version) return true\n try { return target.localStorage.getItem(ANNOUNCEMENT_KEY) === version } catch { return false }\n}\n\nexport function acknowledgeAnnouncement(target: Window, version = ANNOUNCEMENT_VERSION): void {\n acknowledged.set(target, version)\n try { target.localStorage.setItem(ANNOUNCEMENT_KEY, version) } catch { /* Page-only fallback. */ }\n const event = target.document.createEvent('Event')\n event.initEvent(EVENT, false, false)\n target.dispatchEvent(event)\n}\n\nexport function subscribeAnnouncement(target: Window, notify: () => void): () => void {\n const storage = (event: StorageEvent) => {\n if (event.key !== ANNOUNCEMENT_KEY && event.key !== null) return\n acknowledged.delete(target)\n notify()\n }\n target.addEventListener(EVENT, notify)\n target.addEventListener('storage', storage)\n return () => {\n target.removeEventListener(EVENT, notify)\n target.removeEventListener('storage', storage)\n }\n}\n", "/** Shared language identifiers only; safe to bundle into the browser. */\nexport const MEMOIR_LANGUAGES = ['zh', 'en', 'de', 'ru'] as const\nexport type MemoirLanguage = typeof MEMOIR_LANGUAGES[number]\nexport const DEFAULT_MEMOIR_LANGUAGE: MemoirLanguage = 'zh'\n\nexport function isMemoirLanguage(value: unknown): value is MemoirLanguage {\n return typeof value === 'string' && MEMOIR_LANGUAGES.some(language => language === value)\n}\n\nexport function resolveMemoirLanguage(value: unknown, fallback: MemoirLanguage = DEFAULT_MEMOIR_LANGUAGE): MemoirLanguage {\n return isMemoirLanguage(value) ? value : fallback\n}\n", "import type { WireEntry, WireProject, WireSearchResult } from './api.js'\nimport type { MemoirStatus, SectionKey } from './types.js'\n\nexport const ENTRY_PAGE_SIZE = 20\nexport const PROJECT_PAGE_SIZE = 20\nexport const ENTRY_PREVIEW_CHAR_LIMIT = 360\nexport const ENTRY_PREVIEW_LINE_LIMIT = 6\n\nexport interface EntryStats {\n total: number\n active: number\n superseded: number\n archived: number\n}\n\nexport interface ProjectGroup {\n key: string\n path: string\n title: string\n updatedAt: number\n entries: WireEntry[]\n stats: EntryStats\n}\n\nexport interface RankedProjectGroup extends Omit<ProjectGroup, 'entries'> {\n results: WireSearchResult[]\n}\n\nexport function entryStatus(entry: WireEntry): MemoirStatus {\n return entry.status ?? 'active'\n}\n\nexport function countEntryStatuses(entries: WireEntry[]): EntryStats {\n const stats: EntryStats = { total: entries.length, active: 0, superseded: 0, archived: 0 }\n for (const entry of entries) stats[entryStatus(entry)] += 1\n return stats\n}\n\nexport function filterEntries(\n entries: WireEntry[],\n status: MemoirStatus | 'all',\n section: SectionKey | 'all',\n): WireEntry[] {\n return entries.filter((entry) =>\n (status === 'all' || entryStatus(entry) === status)\n && (section === 'all' || entry.section === section))\n}\n\n/** Match the host's Windows case-insensitive identity without folding POSIX paths. */\nexport function canonicalProjectPath(path: string): string {\n const normalized = path.trim().replace(/\\\\/g, '/').replace(/\\/{2,}/g, '/').replace(/\\/$/, '')\n if (normalized === '') return '__unscoped__'\n return /^[A-Za-z]:\\//.test(normalized) ? normalized.toLowerCase() : normalized\n}\n\nexport function projectTitleFromPath(path: string): string {\n if (path.trim() === '') return ''\n const parts = path.replace(/\\\\/g, '/').split('/').filter(Boolean)\n return parts.at(-1) ?? path\n}\n\nfunction projectStats(project: WireProject): EntryStats {\n return project.stats ?? countEntryStatuses(project.entries)\n}\n\nexport function buildProjectGroups(\n projects: WireProject[],\n status: MemoirStatus | 'all',\n section: SectionKey | 'all',\n): ProjectGroup[] {\n return projects\n .map((project) => ({\n key: project.key || canonicalProjectPath(project.path),\n path: project.path,\n title: project.title || projectTitleFromPath(project.path),\n updatedAt: project.updatedAt,\n entries: filterEntries(project.entries, status, section),\n stats: projectStats(project),\n }))\n .filter((project) => project.entries.length > 0)\n}\n\nexport function groupRankedResults(\n results: WireSearchResult[],\n projects: WireProject[],\n): RankedProjectGroup[] {\n const metadata = new Map(projects.map((project) => [canonicalProjectPath(project.path), project]))\n const groups = new Map<string, RankedProjectGroup>()\n for (const result of results) {\n const canonicalPath = canonicalProjectPath(result.projectPath)\n const project = metadata.get(canonicalPath)\n const existing = groups.get(canonicalPath)\n if (existing !== undefined) {\n existing.results.push(result)\n continue\n }\n groups.set(canonicalPath, {\n key: project?.key || canonicalPath,\n path: project?.path ?? result.projectPath,\n title: project?.title || projectTitleFromPath(result.projectPath),\n updatedAt: project?.updatedAt ?? result.entry.time,\n stats: project === undefined ? countEntryStatuses([result.entry]) : projectStats(project),\n results: [result],\n })\n }\n return [...groups.values()]\n}\n\nexport function shouldCollapseEntry(content: string): boolean {\n return content.length > ENTRY_PREVIEW_CHAR_LIMIT\n || content.split(/\\r?\\n/).length > ENTRY_PREVIEW_LINE_LIMIT\n}\n\nexport function nextPageSize(current: number, total: number, pageSize: number): number {\n return Math.min(total, current + pageSize)\n}\n", "/** Stable marker for the stylesheet owned by this client plugin. */\nexport const PANEL_STYLE_SELECTOR = 'style[data-dsh-memoir-style]'\n\n/**\n * Mount the panel stylesheet without confusing another plugin-owned style tag\n * carrying the same generic data-plugin value for this stylesheet.\n * @param target - document that owns the DSH web shell.\n * @returns disposer that removes only the stylesheet created by this call.\n */\nexport function mountPanelStyles(target: Document = document): () => void {\n if (target.querySelector(PANEL_STYLE_SELECTOR) !== null) return () => {}\n const tag = target.createElement('style')\n tag.dataset.plugin = 'dsh-memoir'\n tag.dataset.dshMemoirStyle = ''\n tag.textContent = PANEL_CSS\n target.head.appendChild(tag)\n return () => tag.remove()\n}\n\n/**\n * Panel stylesheet (plain string, injected as <style data-plugin=\"dsh-memoir\">).\n * Class names are literal memoir-* prefixes (no CSS-module hashing) so the\n * plain-DOM sidebar entry and the React panel share them.\n *\n * The visual language rides the dsh-web-ui family tokens (--dsw-alias-* /\n * --dsw-specific-* / --dsw-font-family). Every token carries a stack fallback\n * (--bg-panel / --text-primary / ...) so the panel still works in a shell\n * without the web-ui-all plugin, while matching dsh-ssh / dsh-task-board /\n * dsh-skill-explorer wherever those tokens exist (light, dark and skins).\n */\n\nexport const PANEL_CSS = `\n/* --- Native Web / Desktop slot surfaces ---------------------------------- */\n\n.memoir-native-view,\n.memoir-settings-section {\n display: flex;\n flex-direction: column;\n box-sizing: border-box;\n width: 100%;\n height: 100%;\n min-width: 0;\n min-height: 0;\n overflow: hidden;\n background: var(--dsw-alias-bg-base, var(--bg-panel, #ffffff));\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n font-family: var(--dsw-font-family, inherit);\n}\n\n.memoir-settings-section {\n /* Settings already owns a raised surface: do not repaint the chat base. */\n background: transparent;\n}\n\n.memoir-sidebar-title {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n min-width: 0;\n}\n.memoir-sidebar-title svg { flex: 0 0 auto; }\n.memoir-sidebar-view { container-type: inline-size; }\n.memoir-sidebar-view .memoir-panel { padding: 12px; }\n.memoir-sidebar-view .memoir-surface-tabs { flex-wrap: wrap; }\n.memoir-sidebar-view .memoir-entry-actions { flex-wrap: wrap; }\n.memoir-plugin-guide {\n flex: 0 0 auto;\n min-width: 0;\n padding: 8px 10px;\n border: 1px solid var(--dsw-alias-border-l1, var(--border, rgba(128, 128, 128, .22)));\n border-radius: 10px;\n background: var(--dsw-alias-bg-layer-2, var(--bg-card, transparent));\n color: var(--dsw-alias-label-primary, var(--text-primary, inherit));\n font-size: 12px;\n}\n.memoir-plugin-guide-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 6px 12px; }\n.memoir-plugin-identity { overflow-wrap: anywhere; }\n.memoir-plugin-identity span { font-weight: 400; color: var(--dsw-alias-label-secondary, var(--text-secondary, #8a8f9c)); }\n.memoir-about { margin-top: 4px; }\n.memoir-announcement { margin-top: 6px; padding: 10px; border-top: 1px solid var(--dsw-alias-border-l1, rgba(128,128,128,.22)); max-height: min(180px, 24dvh); overflow-y: auto; overscroll-behavior: contain; line-height: 1.5; }\n.memoir-announcement p { margin: 6px 0; }\n.memoir-announcement small { color: var(--dsw-alias-label-secondary, var(--text-secondary, #666)); }\n.memoir-about summary { cursor: pointer; font-weight: 600; padding: 4px; }\n.memoir-about summary:focus-visible,\n.memoir-plugin-guide a:focus-visible,\n.memoir-guide-settings:focus-visible { outline: 2px solid var(--accent, #5284e7); outline-offset: 3px; }\n.memoir-about-body { display: grid; gap: 12px; padding: 10px 4px 4px; max-height: min(200px, 25dvh); overflow-y: auto; overscroll-behavior: contain; font-weight: 400; line-height: 1.65; overflow-wrap: anywhere; }\n.memoir-about-body p { margin: 0; }\n.memoir-about-body dl { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); gap: 6px 12px; margin: 0; }\n.memoir-about-body dd { margin: 0; }\n.memoir-about-links { display: flex; flex-wrap: wrap; gap: 8px 16px; }\n.memoir-about-links a,\n.memoir-guide-settings { color: var(--dsw-alias-interactive-primary, var(--accent, #5284e7)); text-decoration: underline; text-underline-offset: 3px; }\n.memoir-guide-settings { border: 0; background: transparent; padding: 0; font: inherit; cursor: pointer; }\n.memoir-about-note { color: var(--dsw-alias-label-secondary, var(--text-secondary, #666)); font-size: 12px; }\n.memoir-plugin-settings { display: grid; gap: 12px; min-width: 0; color: var(--dsw-alias-label-primary, var(--text-primary, inherit)); font-family: var(--dsw-font-family, inherit); }\n.memoir-plugin-settings .memoir-settings { margin: 0; }\n@container (max-width: 420px) {\n .memoir-sidebar-view .memoir-panel { padding: 8px; }\n .memoir-sidebar-view .memoir-entry { padding: 12px; }\n .memoir-about-body dl { grid-template-columns: minmax(0, 1fr); }\n}\n\n/* --- center-column takeover (mirrors dsh-ssh / dsh-task-board) --------------- */\n\n[data-pane='conversation'],\n[class*='centerCol'] {\n position: relative;\n}\n\n[data-dsh-memoir-view] {\n display: none;\n position: absolute;\n inset: 0;\n z-index: 60;\n background: var(--dsw-alias-bg-base, var(--bg-panel, #ffffff));\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n font-family: var(--dsw-font-family, inherit);\n}\n\n/* The center column is single-occupant; the :not() guards keep the sibling\n panels (task board / ssh) from fighting over visibility. */\nhtml[data-dsh-memoir-active]:not([data-dsh-ssh-active]):not([data-dsh-taskboard-active]) [data-dsh-memoir-view] {\n display: flex;\n flex-direction: column;\n}\nhtml[data-dsh-memoir-active]:not([data-dsh-ssh-active]):not([data-dsh-taskboard-active]) [data-pane='conversation'] > :not([data-dsh-memoir-view]),\nhtml[data-dsh-memoir-active]:not([data-dsh-ssh-active]):not([data-dsh-taskboard-active]) [class*='centerCol'] > :not([data-dsh-memoir-view]) {\n display: none !important;\n}\n\n/* --- panel frame: same shell as dsh-ssh .panel / dsh-task-board .board ------ */\n\n.memoir-panel {\n display: flex;\n flex-direction: column;\n box-sizing: border-box;\n height: 100%;\n min-width: 0;\n min-height: 0;\n padding: 14px 16px 16px;\n gap: 10px;\n background: var(--dsw-alias-bg-base, var(--bg-panel, #ffffff));\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n font-family: var(--dsw-font-family, inherit);\n overflow: hidden;\n}\n\n.memoir-settings-section .memoir-panel {\n padding: 12px 16px 16px;\n background: transparent;\n}\n.memoir-panel *,\n.memoir-panel *::before,\n.memoir-panel *::after {\n box-sizing: border-box;\n}\n\n.memoir-header {\n display: flex;\n align-items: center;\n gap: 10px;\n flex: none;\n padding: 0;\n}\n.memoir-title {\n flex: 1;\n min-width: 0;\n font-size: 16px;\n font-weight: 700;\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n line-height: 1.25;\n}\n.memoir-subtitle {\n font-size: 12px;\n font-weight: 400;\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #8a8f9c));\n margin-top: 6px;\n line-height: 1.5;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Stable secondary navigation: browsing, settings, Hot Memory and diagnostics\n never compete for vertical position in one long document. */\n.memoir-surface-tabs {\n display: flex;\n flex: none;\n gap: 4px;\n min-width: 0;\n padding: 3px;\n overflow-x: auto;\n border: 1px solid var(--dsw-alias-border-l1, rgba(0, 0, 0, .1));\n border-radius: 10px;\n background: var(--dsw-alias-bg-layer-2, var(--bg-card, rgba(0, 0, 0, .02)));\n scrollbar-width: none;\n}\n.memoir-surface-tabs::-webkit-scrollbar {\n display: none;\n}\n.memoir-surface-tab {\n flex: 0 0 auto;\n min-height: 34px;\n padding: 5px 12px;\n border: 0;\n border-radius: 7px;\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #8a8f9c));\n background: transparent;\n font: inherit;\n font-size: 12.5px;\n cursor: pointer;\n white-space: nowrap;\n}\n.memoir-surface-tab:hover {\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n background: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, .06));\n}\n.memoir-surface-tab[data-active='true'] {\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n background: var(--dsw-alias-bg-base, var(--bg-panel, #ffffff));\n box-shadow: 0 1px 3px rgba(0, 0, 0, .08);\n font-weight: 600;\n}\n.memoir-surface-stack,\n.memoir-surface {\n display: flex;\n flex: 1;\n flex-direction: column;\n min-width: 0;\n min-height: 0;\n overflow: hidden;\n}\n.memoir-surface[hidden] {\n display: none;\n}\n.memoir-browse-head {\n display: flex;\n flex: none;\n flex-direction: column;\n gap: 8px;\n min-width: 0;\n}\n.memoir-surface-scroll {\n box-sizing: border-box;\n flex: 1;\n min-width: 0;\n min-height: 0;\n padding: 4px 2px 20px 0;\n overflow-x: hidden;\n overflow-y: auto;\n overscroll-behavior: contain;\n scrollbar-gutter: stable;\n}\n.memoir-native-view:not(.memoir-sidebar-view) .memoir-surface-scroll {\n padding-bottom: calc(var(--dsh-composer-height, 112px) + 16px);\n scroll-padding-bottom: calc(var(--dsh-composer-height, 112px) + 16px);\n}\n\n/* Header icon controls: square ghost icons (dsh-ssh / dsh-task-board iconButton). */\n.memoir-header .memoir-iconbtn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 26px;\n height: 26px;\n padding: 0;\n border: none;\n border-radius: 6px;\n background: transparent;\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #8a8f9c));\n cursor: pointer;\n font-size: 13px;\n}\n.memoir-header .memoir-iconbtn:hover {\n background: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, .06));\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n}\n\n/* --- tab bar: dsh-ssh tabBar / tab ------------------------------------------- */\n\n.memoir-tabs {\n display: flex;\n gap: 2px;\n flex: none;\n padding: 0;\n border-bottom: 1px solid var(--dsw-alias-border-l1, rgba(0, 0, 0, .1));\n}\n.memoir-tab {\n padding: 7px 14px;\n font-size: 13px;\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #8a8f9c));\n background: transparent;\n border: none;\n border-bottom: 2px solid transparent;\n border-radius: 6px 6px 0 0;\n cursor: pointer;\n white-space: nowrap;\n}\n.memoir-tab:hover {\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n background: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, .06));\n}\n.memoir-tab[data-active='true'] {\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n font-weight: 600;\n border-bottom-color: var(--dsw-alias-state-business-primary, #2563eb);\n}\n\n/* --- toolbar / controls ------------------------------------------------------- */\n\n.memoir-toolbar {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 8px;\n flex: none;\n padding: 0;\n}\n.memoir-project-actions {\n display: inline-flex;\n gap: 6px;\n}\n.memoir-search {\n flex: 1 1 200px;\n min-width: 120px;\n padding: 6px 10px;\n font-size: 13px;\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n background: var(--dsw-specific-input-major, var(--bg-card, rgba(0, 0, 0, .02)));\n border: 1px solid var(--dsw-alias-border-l2, rgba(0, 0, 0, .15));\n border-radius: 8px;\n outline: none;\n}\n.memoir-search::placeholder {\n color: var(--dsw-alias-label-tertiary, rgba(0, 0, 0, .45));\n}\n.memoir-status-filter {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 12px;\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #6b7280));\n white-space: nowrap;\n}\n.memoir-status-filter select {\n max-width: 110px;\n padding: 6px 8px;\n font-size: 13px;\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n background: var(--dsw-specific-input-major, var(--bg-card, rgba(0, 0, 0, .02)));\n border: 1px solid var(--dsw-alias-border-l2, rgba(0, 0, 0, .15));\n border-radius: 8px;\n outline: none;\n}\n.memoir-search:focus,\n.memoir-status-filter select:focus {\n border-color: var(--dsw-alias-state-business-primary, #2563eb);\n}\n\n/* --- buttons: web-ui family button language ---------------------------------- */\n\n.memoir-primary {\n border: none;\n border-radius: 8px;\n padding: 6px 14px;\n font-size: 13px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary-foreground, #ffffff);\n background: var(--dsw-alias-button-info-fill, #2563eb);\n cursor: pointer;\n white-space: nowrap;\n}\n.memoir-primary:hover:not(:disabled) {\n background: var(--dsw-alias-button-info-hover, #1d4ed8);\n}\n.memoir-primary:disabled {\n opacity: .5;\n cursor: default;\n}\n.memoir-iconbtn {\n padding: 5px 12px;\n font-size: 12px;\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n background: transparent;\n border: 1px solid var(--dsw-alias-border-l2, rgba(0, 0, 0, .15));\n border-radius: 8px;\n cursor: pointer;\n white-space: nowrap;\n}\n.memoir-iconbtn:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, .06));\n}\n.memoir-iconbtn:disabled {\n opacity: .45;\n cursor: default;\n}\n\n/* --- body / lists ------------------------------------------------------------- */\n\n.memoir-scroll-region {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n overflow-x: hidden;\n overscroll-behavior: contain;\n scrollbar-gutter: stable;\n}\n.memoir-body {\n min-height: 0;\n padding: 4px 0 16px;\n}\n.memoir-surface-scroll > .memoir-form,\n.memoir-surface-scroll > .memoir-similarity {\n margin-bottom: 10px;\n}\n.memoir-load-more {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 10px;\n padding: 10px 0 14px;\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #8a8f9c));\n font-size: 11px;\n}\n.memoir-section-title {\n display: flex;\n align-items: center;\n gap: 6px;\n margin: 12px 0 10px;\n font-size: 13px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n}\n.memoir-count {\n font-weight: 400;\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #8a8f9c));\n}\n\n/* Entry cards: dsh-skill-explorer .skill / dsh-task-board .card surfaces. */\n.memoir-entry {\n border: 1px solid var(--dsw-alias-border-l2, rgba(0, 0, 0, .08));\n border-radius: 12px;\n padding: 14px 16px;\n margin-bottom: 12px;\n background: var(--dsw-alias-bg-layer-2, var(--bg-card, rgba(127, 127, 127, .04)));\n}\n.memoir-entry-meta {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n font-size: 11px;\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #8a8f9c));\n margin-bottom: 10px;\n}\n.memoir-chip {\n display: inline-block;\n padding: 1px 8px;\n font-size: 11px;\n line-height: 1.6;\n border-radius: 999px;\n border: 1px solid var(--dsw-alias-border-l2, rgba(0, 0, 0, .1));\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #6b7280));\n background: transparent;\n white-space: nowrap;\n}\n.memoir-tag {\n /* Tags are metadata, not success alerts. */\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #6b7280));\n background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .06));\n}\n.memoir-source {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n min-width: 0;\n}\n.memoir-source-link,\n.memoir-source-copy {\n appearance: none;\n border: none;\n background: transparent;\n color: var(--dsw-alias-state-business-primary, #2563eb);\n font: inherit;\n cursor: pointer;\n padding: 0;\n}\n.memoir-source-link {\n max-width: 230px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.memoir-source-link:hover,\n.memoir-source-copy:hover {\n text-decoration: underline;\n}\n.memoir-source-copy {\n min-width: 18px;\n}\n.memoir-score {\n float: right;\n display: inline-block;\n padding: 1px 8px;\n font-size: 10px;\n line-height: 1.6;\n border-radius: 999px;\n border: 1px solid var(--dsw-alias-state-business-primary, #2563eb);\n color: var(--dsw-alias-state-business-primary, #2563eb);\n background: transparent;\n opacity: .8;\n}\n.memoir-entry-title {\n font-size: 14px;\n font-weight: 600;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n margin-bottom: 6px;\n overflow-wrap: anywhere;\n}\n.memoir-entry-content {\n font-size: 13px;\n line-height: 1.7;\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n white-space: pre-wrap;\n word-break: break-word;\n}\n.memoir-entry-content[data-collapsible='true']:not([data-expanded='true']) {\n display: -webkit-box;\n overflow: hidden;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 6;\n}\n.memoir-content-toggle {\n margin-top: 5px;\n padding: 1px 0;\n border: 0;\n color: var(--dsw-alias-state-business-primary, #2563eb);\n background: transparent;\n font: inherit;\n font-size: 11px;\n cursor: pointer;\n}\n.memoir-content-toggle:hover {\n text-decoration: underline;\n}\n.memoir-entry-actions {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n margin: 0 24px 12px 0;\n}\n.memoir-delete {\n float: right;\n border: none;\n background: transparent;\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #8a8f9c));\n cursor: pointer;\n border-radius: 6px;\n padding: 2px 6px;\n font-size: 12px;\n}\n.memoir-delete:hover {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n background: var(--dsw-alias-state-error-secondary, rgba(220, 38, 38, .12));\n}\n\n/* Project cards (global tab + ranked grouped results). */\n.memoir-project-card {\n border: 1px solid var(--dsw-alias-border-l1, rgba(0, 0, 0, .1));\n border-radius: 10px;\n padding: 0;\n margin-bottom: 12px;\n background: var(--dsw-alias-bg-layer-2, var(--bg-card, rgba(0, 0, 0, .02)));\n overflow: clip;\n}\n.memoir-project-toggle {\n appearance: none;\n display: flex;\n align-items: flex-start;\n gap: 9px;\n width: 100%;\n padding: 11px 12px;\n border: 0;\n color: inherit;\n background: transparent;\n font: inherit;\n text-align: left;\n cursor: pointer;\n}\n.memoir-project-toggle:hover {\n background: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, .04));\n}\n.memoir-project-chevron {\n flex: none;\n margin-top: 1px;\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #8a8f9c));\n font-size: 18px;\n line-height: 1;\n transition: transform 120ms ease;\n}\n.memoir-project-card[data-expanded='true'] .memoir-project-chevron {\n transform: rotate(90deg);\n}\n.memoir-project-heading {\n display: flex;\n flex: 1;\n flex-direction: column;\n gap: 5px;\n min-width: 0;\n}\n.memoir-project-body {\n padding: 0 12px 10px 30px;\n border-top: 1px solid var(--dsw-alias-border-l1, rgba(0, 0, 0, .08));\n}\n.memoir-project-head {\n display: flex;\n align-items: baseline;\n flex-wrap: wrap;\n gap: 8px;\n}\n.memoir-project-title {\n font-size: 13px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n}\n.memoir-project-path {\n flex: 1;\n min-width: 120px;\n font-size: 10px;\n color: var(--dsw-alias-label-tertiary, rgba(0, 0, 0, .5));\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.memoir-project-meta {\n display: flex;\n flex-wrap: wrap;\n gap: 5px 12px;\n font-size: 11px;\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #8a8f9c));\n}\n\n/* Empty / status / error. */\n.memoir-empty {\n padding: 28px 12px;\n text-align: center;\n font-size: 12.5px;\n color: var(--dsw-alias-label-tertiary, rgba(0, 0, 0, .5));\n}\n.memoir-empty-title {\n font-size: 13px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n margin-bottom: 6px;\n}\n.memoir-empty-hint {\n font-size: 12px;\n}\n.memoir-error {\n padding: 0;\n font-size: 12px;\n color: var(--dsw-alias-state-error-primary, #dc2626);\n}\n\n/* --- forms ------------------------------------------------------------------- */\n\n.memoir-form {\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 12px;\n margin: 0;\n background: var(--dsw-alias-bg-layer-2, var(--bg-card, rgba(0, 0, 0, .02)));\n border: 1px solid var(--dsw-alias-border-l1, rgba(0, 0, 0, .1));\n border-radius: 10px;\n}\n.memoir-form-row {\n display: flex;\n flex-wrap: wrap;\n gap: 10px;\n}\n.memoir-field {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n.memoir-field label {\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #5f6672));\n}\n.memoir-field small {\n font-size: 10px;\n color: var(--dsw-alias-label-tertiary, rgba(0, 0, 0, .55));\n line-height: 1.35;\n}\n.memoir-field input,\n.memoir-field select,\n.memoir-field textarea {\n box-sizing: border-box;\n width: 100%;\n padding: 7px 10px;\n font-size: 13px;\n font-family: inherit;\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n background: var(--dsw-specific-input-major, var(--bg-card, rgba(0, 0, 0, .02)));\n border: 1px solid var(--dsw-alias-border-l2, rgba(0, 0, 0, .15));\n border-radius: 8px;\n outline: none;\n}\n.memoir-field select {\n height: 30px;\n padding: 0 8px;\n}\n.memoir-field textarea {\n min-height: 72px;\n resize: vertical;\n}\n.memoir-field input:focus,\n.memoir-field select:focus,\n.memoir-field textarea:focus {\n border-color: var(--dsw-alias-state-business-primary, #2563eb);\n}\n.memoir-form-actions {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n}\n\n/* --- similar-memory resolution --------------------------------------------- */\n\n.memoir-similarity {\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 12px;\n border: 1px solid var(--dsw-alias-state-warn-tertiary, rgba(217, 119, 6, .4));\n border-radius: 10px;\n background: var(--dsw-alias-bg-layer-2, var(--bg-card, rgba(0, 0, 0, .02)));\n}\n.memoir-similarity-title {\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n font-size: 13px;\n font-weight: 600;\n}\n.memoir-similarity-candidate {\n display: flex;\n flex-direction: column;\n gap: 7px;\n padding: 10px 12px;\n border: 1px solid var(--dsw-alias-border-l2, rgba(0, 0, 0, .12));\n border-radius: 10px;\n background: var(--dsw-alias-bg-layer-3, var(--bg-panel, #ffffff));\n}\n.memoir-similarity-head {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n font-size: 12.5px;\n}\n.memoir-similarity-head strong {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.memoir-similarity-duplicate {\n color: var(--dsw-alias-state-warn-primary, #b45309);\n}\n.memoir-similarity-conflict {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n}\n.memoir-score-static,\n.memoir-similarity-components,\n.memoir-similarity-content {\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #6b7280));\n font-size: 11px;\n}\n.memoir-similarity-content {\n line-height: 1.45;\n white-space: pre-wrap;\n word-break: break-word;\n}\n.memoir-similarity-reasons {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n}\n.memoir-similarity-footer {\n display: flex;\n justify-content: space-between;\n gap: 8px;\n}\n\n/* --- settings (panel + Settings page card) ----------------------------------- */\n\n.memoir-settings {\n margin: 0;\n border-top: 1px solid var(--dsw-alias-separator-primary, rgba(0, 0, 0, .1));\n padding-top: 8px;\n flex: none;\n}\n.memoir-settings-slot {\n list-style: none;\n margin: 0;\n padding: 0;\n border: 1px solid var(--dsw-alias-border-l2, rgba(0, 0, 0, .12));\n border-radius: 12px;\n background: var(--dsw-alias-bg-layer-3, var(--bg-card, rgba(0, 0, 0, .02)));\n transition: border-color .16s, background .16s;\n}\n.memoir-settings-slot:hover {\n border-color: var(--dsw-alias-label-dimmed, rgba(0, 0, 0, .28));\n}\n.memoir-settings-slot-open {\n background: var(--dsw-alias-bg-layer-2, var(--bg-card, rgba(0, 0, 0, .03)));\n border-color: var(--dsw-alias-label-dimmed, rgba(0, 0, 0, .28));\n}\n.memoir-settings-slot-header {\n appearance: none;\n display: flex;\n align-items: center;\n gap: 12px;\n width: 100%;\n padding: 14px 16px;\n color: inherit;\n background: transparent;\n border: 0;\n border-radius: 12px;\n font: inherit;\n text-align: left;\n cursor: pointer;\n}\n.memoir-settings-slot-header:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary, var(--dsw-alias-state-business-primary, #2563eb));\n outline-offset: -2px;\n}\n.memoir-settings-slot-headtext {\n display: flex;\n flex: 1;\n flex-direction: column;\n gap: 4px;\n min-width: 0;\n}\n.memoir-settings-slot-name {\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n font-size: 15px;\n font-weight: 600;\n line-height: 1.4;\n}\n.memoir-settings-slot-description {\n color: var(--dsw-alias-label-tertiary, var(--text-secondary, #8a8f9c));\n font-size: 13px;\n line-height: 1.5;\n}\n.memoir-settings-slot-chevron {\n flex: none;\n color: var(--dsw-alias-label-tertiary, var(--text-secondary, #8a8f9c));\n transition: transform .16s;\n}\n.memoir-settings-slot-chevron-open {\n transform: rotate(180deg);\n}\n.memoir-settings-slot-body {\n margin: 0 16px;\n padding-bottom: 8px;\n border-top: 1px solid var(--dsw-alias-border-l2, rgba(0, 0, 0, .12));\n}\n.memoir-settings-slot .memoir-settings {\n margin: 0;\n padding: 0;\n border-top: none;\n}\n.memoir-settings-slot .memoir-settings-body {\n margin: 0;\n padding: 12px 0 4px;\n border: none;\n border-radius: 0;\n background: transparent;\n max-height: none;\n}\n.memoir-settings-body {\n display: flex;\n flex-direction: column;\n gap: 10px;\n margin-top: 7px;\n padding: 10px;\n border: 1px solid var(--dsw-alias-border-l1, rgba(0, 0, 0, .1));\n border-radius: 8px;\n background: var(--dsw-alias-bg-layer-2, var(--bg-card, rgba(0, 0, 0, .02)));\n}\n.memoir-settings-description,\n.memoir-settings-note,\n.memoir-settings-source {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #8a8f9c));\n line-height: 1.45;\n}\n.memoir-settings-group-title {\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n margin-top: 2px;\n}\n.memoir-settings-switch {\n display: flex;\n align-items: flex-start;\n gap: 8px;\n cursor: pointer;\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n}\n.memoir-settings-switch input {\n margin-top: 3px;\n accent-color: var(--dsw-alias-state-business-primary, #2563eb);\n}\n.memoir-settings-switch span {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n.memoir-settings-switch small,\n.memoir-settings-grid small {\n font-size: 10px;\n color: var(--dsw-alias-label-tertiary, rgba(0, 0, 0, .55));\n line-height: 1.35;\n}\n.memoir-settings-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(min(100%, 180px), 1fr));\n gap: 12px;\n}\n.memoir-settings-grid .memoir-field {\n min-width: 0;\n}\n.memoir-settings-grid .memoir-field > span {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #6b7280));\n}\n.memoir-settings-feedback {\n padding: 0;\n}\n.memoir-settings-success {\n font-size: 12px;\n color: var(--dsw-alias-state-success-primary, #15803d);\n}\n.memoir-surface .memoir-settings {\n margin: 0;\n padding: 0;\n border-top: 0;\n}\n.memoir-surface .memoir-settings-body {\n margin-top: 0;\n}\n.memoir-surface .memoir-settings-body > .memoir-form-actions {\n /* Normal flow avoids painting actions over fields above composer padding. */\n flex-wrap: wrap;\n padding-top: 10px;\n}\n@media (max-width: 760px) {\n .memoir-settings-grid {\n grid-template-columns: 1fr;\n }\n}\n\n/* --- hot memory inspector / diagnostics -------------------------------------- */\n\n.memoir-inspector,\n.memoir-diagnostics {\n margin: 0;\n border-top: 1px solid var(--dsw-alias-separator-primary, rgba(0, 0, 0, .1));\n padding-top: 8px;\n flex: none;\n}\n.memoir-diagnostics-toggle {\n border: none;\n background: transparent;\n color: var(--dsw-alias-state-business-primary, #2563eb);\n cursor: pointer;\n font-size: 12px;\n padding: 2px 0;\n text-align: left;\n}\n.memoir-diagnostics-toggle:hover {\n text-decoration: underline;\n}\n.memoir-inspector-body {\n font-size: 11.5px;\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n margin: 6px 0 0;\n padding: 8px 10px;\n border: 1px solid var(--dsw-alias-border-l2, rgba(0, 0, 0, .1));\n border-radius: 8px;\n background: var(--dsw-alias-bg-layer-2, var(--bg-card, rgba(0, 0, 0, .02)));\n white-space: pre-wrap;\n word-break: break-word;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n max-height: none;\n overflow: visible;\n}\n.memoir-diagnostics-body {\n display: flex;\n flex-direction: column;\n gap: 3px;\n margin-top: 6px;\n font-size: 11px;\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #8a8f9c));\n}\n.memoir-surface-card {\n min-width: 0;\n padding: 14px;\n border: 1px solid var(--dsw-alias-border-l1, rgba(0, 0, 0, .1));\n border-radius: 10px;\n background: var(--dsw-alias-bg-layer-2, var(--bg-card, rgba(0, 0, 0, .02)));\n}\n.memoir-surface-card h3 {\n margin: 0 0 8px;\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n font-size: 14px;\n}\n.memoir-surface-summary {\n margin-bottom: 8px;\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #8a8f9c));\n font-size: 11px;\n}\n.memoir-surface-card .memoir-inspector-body {\n margin-top: 0;\n}\n\n/* --- sidebar entry row (plain DOM, matches the web-ui family rows) ------------- */\n\n.memoir-entry-row {\n box-sizing: border-box;\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n height: 36px;\n padding: 0 10px;\n background: transparent;\n border: none;\n border-radius: 8px;\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #8a8f9c));\n cursor: pointer;\n font-size: 13px;\n white-space: nowrap;\n text-align: left;\n}\n.memoir-entry-row:hover {\n background: var(--dsw-alias-interactive-bg-hover, var(--dsw-specific-sidebar-nav-item-hover, rgba(0, 0, 0, .06)));\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n}\n.memoir-entry-row[data-active='true'] {\n background: var(--dsw-alias-interactive-bg-active, var(--dsw-specific-sidebar-nav-item-active, rgba(0, 0, 0, .08)));\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n font-weight: 600;\n}\n.memoir-entry-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: 0 0 auto;\n width: 24px;\n height: 24px;\n}\n.memoir-entry-icon svg {\n display: block;\n width: 18px;\n height: 18px;\n}\n.memoir-entry-label {\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* Collapsed rail: exact dsh-web-ui-all 0.3.x family geometry. */\n[data-dsh-frame][data-sidebar-collapsed] [data-dsh-memoir-entry].memoir-entry-row,\n[data-sidebar-collapsed] [data-dsh-memoir-entry].memoir-entry-row {\n border-radius: 50%;\n justify-content: center;\n padding: 0;\n width: 36px;\n height: 36px;\n margin: 0 auto 12px;\n}\n[data-dsh-frame][data-sidebar-collapsed] [data-dsh-memoir-entry] .memoir-entry-label,\n[data-sidebar-collapsed] [data-dsh-memoir-entry] .memoir-entry-label {\n display: none;\n}\n\n/* --- focus / motion (web-ui family polish) ------------------------------------ */\n\n.memoir-tab:focus-visible,\n.memoir-surface-tab:focus-visible,\n.memoir-search:focus-visible,\n.memoir-primary:focus-visible,\n.memoir-iconbtn:focus-visible,\n.memoir-delete:focus-visible,\n.memoir-status-filter select:focus-visible,\n.memoir-diagnostics-toggle:focus-visible,\n.memoir-project-toggle:focus-visible,\n.memoir-content-toggle:focus-visible,\n.memoir-field input:focus-visible,\n.memoir-field select:focus-visible,\n.memoir-field textarea:focus-visible,\n.memoir-entry-row:focus-visible {\n outline: 2px solid var(--dsw-alias-state-business-primary, #2563eb);\n outline-offset: 2px;\n}\n.memoir-tab,\n.memoir-surface-tab,\n.memoir-search,\n.memoir-primary,\n.memoir-iconbtn,\n.memoir-delete,\n.memoir-status-filter select,\n.memoir-diagnostics-toggle,\n.memoir-project-toggle,\n.memoir-content-toggle,\n.memoir-field input,\n.memoir-field select,\n.memoir-field textarea,\n.memoir-entry-row {\n transition: background-color 120ms ease, color 120ms ease, border-color 120ms ease, outline-color 120ms ease;\n}\n@media (prefers-reduced-motion: reduce) {\n .memoir-tab,\n .memoir-surface-tab,\n .memoir-search,\n .memoir-primary,\n .memoir-iconbtn,\n .memoir-delete,\n .memoir-status-filter select,\n .memoir-diagnostics-toggle,\n .memoir-project-toggle,\n .memoir-content-toggle,\n .memoir-field input,\n .memoir-field select,\n .memoir-field textarea,\n .memoir-entry-row {\n transition: none;\n }\n}\n\n@media (max-width: 640px) {\n .memoir-panel,\n .memoir-settings-section .memoir-panel {\n padding: 10px 10px 12px;\n gap: 8px;\n }\n .memoir-toolbar {\n align-items: stretch;\n }\n .memoir-search {\n flex: 1 0 100%;\n }\n .memoir-status-filter {\n flex: 1;\n }\n .memoir-status-filter select {\n flex: 1;\n max-width: none;\n }\n .memoir-project-actions {\n width: 100%;\n }\n .memoir-project-body {\n padding-left: 12px;\n }\n}\n\n/* Dark fallback only when the dsw tokens are absent (standalone shells);\n with web-ui-all installed the --dsw-alias-* palette already applies. */\nbody[data-ds-dark-theme] [data-dsh-memoir-view] {\n background: var(--dsw-alias-bg-base, #16181d);\n color: var(--dsw-alias-label-primary, #e6e6e6);\n}\n`\n", "import type { SessionListState } from '@deepseek-ai/dsh-api-session-controller/client'\n\n/** The public mainView retention marker distinguishes the main conversation\n * from independently mounted sidebar sessions. Never fall back to the first\n * catalog row: that could expose another project's memories in Settings. */\nexport function mainWorkspaceCwd(snapshot: Pick<SessionListState, 'byId'>): string {\n const main = Object.values(snapshot.byId).filter(session => (session.retainedBy.mainView ?? 0) > 0)\n return main.length === 1 ? main[0]!.cwd ?? '' : ''\n}\n", "import type { Context } from '@deepseek-ai/cordis'\nimport type { PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { IconProps } from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { UseSessions } from '@deepseek-ai/dsh-client-ui-session/client'\nimport type { SessionListState } from '@deepseek-ai/dsh-api-session-controller/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-sidebar-right/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-session/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-workspace/client'\nimport { useEffect, useState } from 'react'\nimport type { MemoirApi } from './api.js'\nimport { MemoirPanel } from './panel.js'\n\nexport const SIDEBAR_ID = 'dsh-memoir'\n\n/** SVG honors the host's requested size and color; no remote icon request. */\nfunction MemoirIcon({ size = 20, className }: IconProps) {\n return <svg width={size} height={size} className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.75\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\" focusable=\"false\">\n <path d=\"M12 5c-3-2-6-2-9-1v15c3-1 6-1 9 1 3-2 6-2 9-1V4c-3-1-6-1-9 1v15\" />\n </svg>\n}\n\nfunction SidebarMemoir({ api, ctx, t, sessionId, useSessions, useTabInfo }: PropsRuntime<'sidebar.right.pane.tab'> & {\n api: MemoirApi; ctx: Context; t: (key: string) => string; useSessions: UseSessions\n}) {\n const cwd = useSessions((snapshot: SessionListState) => snapshot.byId[sessionId]?.cwd ?? '')\n const { tab } = useTabInfo()\n return <div className=\"memoir-native-view memoir-sidebar-view\" data-dsh-plugin=\"memoir\" data-dsh-part=\"sidebar-view\">\n <MemoirPanel key={sessionId} api={api} cwd={cwd} t={t} onClose={() => tab.actions.close()}\n openSource={id => ctx.uiWorkspace.openSession(id as typeof sessionId)} />\n </div>\n}\n\nfunction SidebarTitle({ t }: { t: (key: string) => string }) {\n const [, refresh] = useState(0)\n useEffect(() => {\n const observer = new MutationObserver(() => refresh(value => value + 1))\n observer.observe(document.documentElement, { attributes: true, attributeFilter: ['lang'] })\n return () => observer.disconnect()\n }, [])\n return <span className=\"memoir-sidebar-title\"><MemoirIcon size={16} />{t('entry.label')}</span>\n}\n\n/** Optional service: absence/reload must not pend the main plugin. */\nexport function watchSidebar(ctx: Context, api: MemoirApi, t: (key: string) => string): () => Promise<void> {\n const pending = ctx.inject(['sidebarRightTabs'], sidebarCtx => {\n sidebarCtx.effect(() => {\n const owned: Array<() => void> = []\n const cleanup = () => { for (const dispose of owned.splice(0).reverse()) dispose() }\n try {\n owned.push(sidebarCtx.sidebarRightTabs.register({\n id: SIDEBAR_ID, kind: SIDEBAR_ID, keepMounted: true,\n title: () => t('entry.label'),\n guide: [{ id: SIDEBAR_ID, order: 30, title: () => t('entry.label'), description: () => t('sidebar.description'), icon: MemoirIcon }],\n }))\n owned.push(sidebarCtx.slots.inject('sidebar.right.pane.tab', () => sidebarCtx.slots.register({\n name: 'sidebar.right.pane.tab', key: SIDEBAR_ID,\n }, props => <SidebarMemoir {...props} api={api} ctx={sidebarCtx} t={t} />)))\n owned.push(sidebarCtx.slots.inject('sidebar.right.pane.tab.title', () => sidebarCtx.slots.register({\n name: 'sidebar.right.pane.tab.title', key: SIDEBAR_ID,\n }, () => <SidebarTitle t={t} />)))\n } catch {\n // A collision or partially unavailable optional owner must not remove\n // another plugin's entries or break Conversation / Settings.\n cleanup()\n sidebarCtx.logger.warn('dsh-memoir: optional sidebar registration unavailable; Conversation and Settings remain active')\n }\n return cleanup\n }, 'dsh-memoir: optional sidebar registration')\n })\n return () => pending.dispose()\n}\n", "import type { Context } from '@deepseek-ai/cordis'\nimport type { PluginConfigViewProps } from '@deepseek-ai/dsh-client-ui-plugin-manager/client'\nimport { useEffect, useState } from 'react'\nimport type { MemoirApi } from './api.js'\nimport { MemoirAbout } from './about.js'\nimport { MemoirSettingsPanel } from './panel.js'\n\n/** Native bundle page, not an official-plugin impostor or a second settings store. */\nfunction PluginSettings({ api, t }: { api: MemoirApi; t: (key: string) => string }) {\n const [revision, refresh] = useState(0)\n const [, languageChanged] = useState(0)\n useEffect(() => {\n const observer = new MutationObserver(() => languageChanged(value => value + 1))\n observer.observe(document.documentElement, { attributes: true, attributeFilter: ['lang'] })\n return () => observer.disconnect()\n }, [])\n return <div className=\"memoir-plugin-settings\" data-dsh-plugin=\"memoir\" data-dsh-part=\"plugin-settings\">\n <MemoirAbout t={t} />\n <MemoirSettingsPanel api={api} t={t} refreshKey={revision} onChanged={() => refresh(value => value + 1)} alwaysOpen />\n </div>\n}\n\n/** Wait for the public slot owner; missing/reloaded plugin manager cannot block Memoir. */\nexport function watchPluginSettings(ctx: Context, api: MemoirApi, t: (key: string) => string): () => void {\n return ctx.slots.inject('plugins.bundle.config', () => ctx.slots.register({\n name: 'plugins.bundle.config', key: 'dsh-memoir',\n }, ({ view }: PluginConfigViewProps) => view === 'summary'\n ? <>{t('sidebar.description')}</>\n : <PluginSettings api={api} t={t} />))\n}\n"],
|
|
4
|
+
"sourcesContent": ["/**\n * Browser-half entry for the DSH 0.2.0 client architecture.\n *\n * The alpha shell removed dsh-client-runtime and exposes additive UI through\n * domain-owned slots. Memoir therefore registers as a native Conversation\n * view and a native Settings section. No CSS-module selector or DOM takeover\n * is used for mounting; the host remains the sole owner of layout and view\n * navigation.\n */\n\nimport type { Context } from '@deepseek-ai/cordis'\nimport type { SessionListState } from '@deepseek-ai/dsh-api-session-controller/client'\nimport type { ConvViewProps } from '@deepseek-ai/dsh-client-ui-conversation/client'\nimport type { UseSessions } from '@deepseek-ai/dsh-client-ui-session/client'\nimport type { PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { SessionId } from '@deepseek-ai/dsh-session/types'\nimport type {} from '@deepseek-ai/dsh-api-session-controller/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-renderer/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-session/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-workspace/client'\nimport { useEffect } from 'react'\nimport { MemoirApi } from './api.js'\nimport { makeT } from './i18n.js'\nimport { MemoirPanel } from './panel.jsx'\nimport { mountPanelStyles } from './styles.js'\nimport { mainWorkspaceCwd } from './native-navigation.js'\nimport { watchSidebar } from './sidebar.js'\nimport { watchPluginSettings } from './plugin-settings.js'\n\ntype NativeGlobalProps = { useSessions: UseSessions }\ntype NativeSettingsSectionProps = PropsRuntime<'settings.section'> & NativeGlobalProps\n\n/** Required alpha services; package.json injects the packages that provide them. */\nexport const inject = ['uiWorkspace', 'slots']\n\n/** Native per-session Conversation view. */\nfunction ConversationMemoirView({\n api,\n ctx,\n t,\n sessionId,\n useSessions,\n viewRequest,\n completeViewRequest,\n openView,\n}: ConvViewProps & NativeGlobalProps & {\n api: MemoirApi\n ctx: Context\n t: (key: string) => string\n}) {\n const cwd = useSessions((snapshot: SessionListState) => snapshot.byId[sessionId]?.cwd ?? '')\n\n // A future native deep-link may select Memoir with an opaque focus token.\n // The current panel has no focus-addressed rows, so acknowledge it once to\n // avoid retaining a stale one-shot request in the Conversation store.\n useEffect(() => {\n if (viewRequest?.view === 'memoir') completeViewRequest()\n }, [viewRequest, completeViewRequest])\n\n return (\n <div\n className=\"memoir-native-view\"\n data-dsh-plugin=\"memoir\"\n data-dsh-part=\"conversation-view\"\n data-conversation-composer-overlay=\"\"\n >\n <MemoirPanel\n api={api}\n cwd={cwd}\n t={t}\n announceOnOpen\n openSource={(sourceSessionId) => {\n if (sourceSessionId === sessionId) openView('chat', '')\n ctx.uiWorkspace.openSession(sourceSessionId as SessionId)\n }}\n />\n </div>\n )\n}\n\n/** Root-scoped Settings page; it also preserves global-memory access with no session selected. */\nfunction SettingsMemoirSection({\n api,\n ctx,\n t,\n close,\n useSessions,\n}: NativeSettingsSectionProps & {\n api: MemoirApi\n ctx: Context\n t: (key: string) => string\n}) {\n const cwd = useSessions(mainWorkspaceCwd)\n return (\n <div className=\"memoir-settings-section\" data-dsh-plugin=\"memoir\" data-dsh-part=\"settings-section\">\n <MemoirPanel\n api={api}\n cwd={cwd}\n t={t}\n onClose={close}\n openSource={(sourceSessionId) => {\n close()\n ctx.uiWorkspace.openSession(sourceSessionId as SessionId)\n }}\n />\n </div>\n )\n}\n\n/**\n * Register the native alpha surfaces.\n * @param rawCtx - DSH alpha client root context.\n */\nexport function apply(rawCtx: Context): void {\n const ctx = rawCtx\n const api = new MemoirApi()\n const t = makeT(document)\n\n ctx.effect(() => mountPanelStyles(), 'dsh-memoir: native alpha styles')\n ctx.effect(() => watchSidebar(ctx, api, t), 'dsh-memoir: optional sidebar')\n ctx.effect(() => watchPluginSettings(ctx, api, t), 'dsh-memoir: optional plugin settings')\n ctx.effect(() => {\n let disposers: Array<() => void> = []\n const register = (): void => {\n for (const dispose of disposers.splice(0)) dispose()\n disposers = [\n ctx.slots.inject('conversation.view', () => ctx.slots.register({\n name: 'conversation.view',\n id: 'memoir',\n order: 20,\n label: () => t('entry.label'),\n }, props => <ConversationMemoirView {...props} api={api} ctx={ctx} t={t} />)),\n ctx.slots.inject('settings.section', () => ctx.slots.register({\n name: 'settings.section',\n id: 'memoir',\n order: 25,\n label: () => t('entry.label'),\n }, props => <SettingsMemoirSection {...props} api={api} ctx={ctx} t={t} />)),\n ]\n }\n\n register()\n // Memoir owns a tiny bilingual dictionary rather than importing the\n // unpublished alpha locale package. Re-registering bumps both native\n // rosters so their labels switch with the shell language immediately.\n const observer = new MutationObserver(register)\n observer.observe(document.documentElement, { attributes: true, attributeFilter: ['lang'] })\n return () => {\n observer.disconnect()\n for (const dispose of disposers.splice(0)) dispose()\n }\n }, 'dsh-memoir: native alpha slots')\n}\n", "{\"version\":\"0.9.3\",\"hostRange\":\">=0.2.0-rc.1 <0.3.0-0 || >=0.2.1-alpha.1 <0.2.1\",\"sdkBaseline\":\"0.2.1-rc.2\"}", "/**\n * Browser API client for the host /api/dsh-memoir routes. The only data path\n * the panel uses \u2014 same-origin fetch, JSON envelope { ok, value | error }.\n * The fetch implementation is injectable for tests.\n */\n\nimport type { MemoirStatus, SectionKey } from './types.ts'\nimport type { MemoirLanguage } from '../host/languages.js'\n\n/** Error carrying the route's JSON error message. */\nexport class MemoirApiError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'MemoirApiError'\n }\n}\n\ninterface EnvelopeResponse {\n status: number\n ok: boolean\n json(): Promise<unknown>\n}\n\n/** Parse the envelope or throw a MemoirApiError (transport or route error). */\nexport async function readEnvelope(response: EnvelopeResponse): Promise<unknown> {\n let body: unknown\n try {\n body = await response.json()\n } catch {\n throw new MemoirApiError(`HTTP ${response.status}: invalid JSON response`)\n }\n if (typeof body !== 'object' || body === null || (body as { ok?: boolean }).ok !== true) {\n const record = body as { error?: { message?: string } } | null\n const message = record && typeof record.error === 'object' && record.error !== null && typeof record.error.message === 'string'\n ? record.error.message\n : `HTTP ${response.status}`\n throw new MemoirApiError(message)\n }\n return (body as { value: unknown }).value\n}\n\n/** Query-string helper (omits undefined/empty values). */\nexport function query(params: Record<string, string | undefined>): string {\n const search = new URLSearchParams()\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== '') search.set(key, String(value))\n }\n const text = search.toString()\n return text === '' ? '' : '?' + text\n}\n\n/** One memory entry as the panel sees it over the wire. */\nexport interface WireEntry {\n id: string\n section: SectionKey\n title?: string\n content: string\n time: number\n source?: { sessionId?: string; turnId?: number }\n /** Legacy v3 wire alias; prefer source.sessionId. */\n sessionId?: string\n importance?: number\n pinned?: boolean\n status?: MemoirStatus\n supersedes?: string[]\n tags?: string[]\n}\n\nexport interface WireProject {\n key: string\n path: string\n title: string\n updatedAt: number\n entries: WireEntry[]\n /** Lifecycle totals before any route-level status/section filter. */\n stats?: { total: number; active: number; superseded: number; archived: number }\n}\n\n/** The host /diagnostics payload (v0.4 observability, v0.4.2 extended). */\nexport interface WireDiagnostics {\n snapshotPersistence?: {\n restored: number; created: number; failures: number\n lastStatus: 'idle' | 'restored' | 'created' | 'volatile'\n lastError: 'invalid-record' | 'record-too-large' | 'unavailable' | null\n }\n autoDistill?: {\n counts: Partial<Record<string, number>>\n writes?: Record<'persisted' | 'afterReminder' | 'failed' | 'canceled' | 'needsResolution' | 'receiptFailed', number>\n workedTurns: number\n agents: number\n last: { outcome: string; at: number; turn: number; toolCalls: number } | null\n }\n storeRevision: number\n snapshotEpoch: number\n cache: {\n revision: number\n epoch: number\n loads: number\n hits: number\n misses: number\n hitRate: number\n fileReads: number\n statProbes: number\n corruptBackups: number\n renders: number\n renderComputes: number\n renderHitRate: number\n lastLoadMs?: number\n }\n snapshotCount: number\n snapshotMax: number\n hotMemory: { selected: number; total: number; estimatedTokens: number } | null\n /** v0.4.2: retrieval index / query cache / last query. */\n retrieval: {\n index: { docs: number; terms: number; epoch: number } | null\n cache: { hits: number; misses: number; evictions: number; hitRate: number; size: number; capacity: number }\n lastQuery: { query: string; latencyMs: number; candidates: number; returned: number; at: number } | null\n }\n /** v0.4.2: the most recently frozen session snapshot. */\n snapshot: { hash: string; createdAt: number; storeRevision: number } | null\n config: {\n language: MemoirLanguage\n announceToAgent: boolean\n autoDistill: boolean\n autoDistillEvery: number\n autoDistillCooldownMin: number\n autoDistillMinTools: number\n hotMemoryTokens: number\n hotMemoryMaxTokens: number\n readDefaultLimit: number\n readMaxLimit: number\n sessionSnapshotMax: number\n queryCacheSize: number\n }\n}\n\n/** Full live runtime settings managed by both GUI settings surfaces. */\nexport interface WireMemoirSettings {\n language: MemoirLanguage\n announceToAgent: boolean\n autoDistill: boolean\n autoDistillEvery: number\n autoDistillCooldownMin: number\n autoDistillMinTools: number\n hotMemoryTokens: number\n hotMemoryMaxTokens: number\n readDefaultLimit: number\n readMaxLimit: number\n sessionSnapshotMax: number\n queryCacheSize: number\n}\n\nexport interface WireMemoirSettingsSnapshot {\n settings: WireMemoirSettings\n source: 'profile' | 'web'\n}\n\n/** v0.5.3 source compatibility aliases. */\nexport type WireAutoDistillSettings = WireMemoirSettings\nexport type WireAutoDistillSettingsSnapshot = WireMemoirSettingsSnapshot\n\n/** One ranked /search hit (v0.4.2: shared RetrievalEngine order). */\nexport interface WireSearchResult {\n projectPath: string\n entry: WireEntry\n score: number\n}\n\nexport type WireRecordResolution = 'update' | 'supersede' | 'force-record'\nexport type WireRecordAction = 'recorded' | 'needs-resolution' | 'updated' | 'superseded' | 'force-recorded'\n\nexport interface WireSimilarityCandidate {\n kind: 'duplicate' | 'conflict'\n score: number\n components: { bm25: number; title: number; tokenJaccard: number }\n reasons: string[]\n entry: WireEntry\n projectPath: string\n}\n\nexport interface WireRecordResult {\n action: WireRecordAction\n recorded: boolean\n entry?: WireEntry\n candidates: WireSimilarityCandidate[]\n}\n\n/** The /hot-memory inspector payload (v0.4.2). */\nexport interface WireHotMemory {\n text: string\n selected: WireEntry[]\n total: number\n estimatedTokens: number\n}\n\nexport interface RecordPayload {\n path: string\n section: SectionKey\n title?: string\n content: string\n importance?: number\n pinned?: boolean\n supersedes?: string[]\n tags?: string[]\n resolution?: WireRecordResolution\n targetId?: string\n}\n\ntype FetchLike = (input: string, init?: RequestInit) => Promise<EnvelopeResponse>\n\n/** The browser half's only data entry point. */\nexport class MemoirApi {\n private readonly fetchImpl: FetchLike\n\n /**\n * @param fetchImpl - injectable fetch (defaults to globalThis.fetch).\n */\n constructor(fetchImpl?: FetchLike) {\n this.fetchImpl = fetchImpl ?? ((...args) => globalThis.fetch(...args) as Promise<EnvelopeResponse>)\n }\n\n /** Read one project's memory (empty project shape when unknown). */\n async project(path: string, options: { section?: SectionKey; query?: string; status?: MemoirStatus | 'all' } = {}): Promise<{ project: WireProject }> {\n const response = await this.fetchImpl('/api/dsh-memoir/project' + query({ path, ...options }))\n return readEnvelope(response) as Promise<{ project: WireProject }>\n }\n\n /** Read the cross-project global index. */\n async global(options: { section?: SectionKey; query?: string; status?: MemoirStatus | 'all' } = {}): Promise<{ projects: WireProject[] }> {\n const response = await this.fetchImpl('/api/dsh-memoir/global' + query({ ...options }))\n return readEnvelope(response) as Promise<{ projects: WireProject[] }>\n }\n\n /** Read runtime diagnostics (cache hit rates, snapshot/hot-memory stats). */\n async diagnostics(path?: string): Promise<WireDiagnostics> {\n const response = await this.fetchImpl('/api/dsh-memoir/diagnostics' + query({ path }))\n return readEnvelope(response) as Promise<WireDiagnostics>\n }\n\n /** Read all live settings and whether they come from Web overrides. */\n async settings(): Promise<WireMemoirSettingsSnapshot> {\n const response = await this.fetchImpl('/api/dsh-memoir/settings')\n return readEnvelope(response) as Promise<WireMemoirSettingsSnapshot>\n }\n\n /** Persist and immediately apply the complete runtime policy. */\n async updateSettings(settings: WireMemoirSettings): Promise<WireMemoirSettingsSnapshot> {\n const response = await this.fetchImpl('/api/dsh-memoir/settings', {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(settings),\n })\n return readEnvelope(response) as Promise<WireMemoirSettingsSnapshot>\n }\n\n /** Remove the Web override and restore the profile defaults captured at boot. */\n async resetSettings(): Promise<WireMemoirSettingsSnapshot> {\n const response = await this.fetchImpl('/api/dsh-memoir/settings', {\n method: 'DELETE',\n headers: { 'content-type': 'application/json' },\n body: '{}',\n })\n return readEnvelope(response) as Promise<WireMemoirSettingsSnapshot>\n }\n\n /**\n * Ranked search over the host RetrievalEngine (v0.4.2) \u2014 the same ranking\n * memoir_read uses, so the GUI search and the agent recall never diverge.\n */\n async search(options: { scope: 'project' | 'global' | 'all'; path?: string; section?: SectionKey; query: string; limit?: number; status?: MemoirStatus | 'all' }): Promise<{ results: WireSearchResult[] }> {\n const response = await this.fetchImpl('/api/dsh-memoir/search' + query({\n scope: options.scope,\n path: options.path,\n section: options.section,\n query: options.query,\n limit: options.limit === undefined ? undefined : String(options.limit),\n status: options.status,\n }))\n return readEnvelope(response) as Promise<{ results: WireSearchResult[] }>\n }\n\n /** Hot-memory preview for one workspace (the inspector). */\n async hotMemory(path: string): Promise<{ hotMemory: WireHotMemory | null }> {\n const response = await this.fetchImpl('/api/dsh-memoir/hot-memory' + query({ path }))\n return readEnvelope(response) as Promise<{ hotMemory: WireHotMemory | null }>\n }\n\n /** Record one entry (host regenerates PROJECT_MEMORY.md). */\n async record(payload: RecordPayload): Promise<WireRecordResult> {\n const response = await this.fetchImpl('/api/dsh-memoir/entries', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n })\n return readEnvelope(response) as Promise<WireRecordResult>\n }\n\n /** Delete one entry by id. */\n async remove(payload: { path: string; id: string }): Promise<{ removed: boolean }> {\n const response = await this.fetchImpl('/api/dsh-memoir/entries', {\n method: 'DELETE',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n })\n return readEnvelope(response) as Promise<{ removed: boolean }>\n }\n\n /** Update entry content or lifecycle metadata without deleting. */\n async update(payload: { path: string; id: string; section?: SectionKey; title?: string | null; content?: string; importance?: number; pinned?: boolean; status?: MemoirStatus; supersedes?: string[]; tags?: string[] }): Promise<{ entry: WireEntry | null; updated: boolean }> {\n const response = await this.fetchImpl('/api/dsh-memoir/entries', {\n method: 'PATCH',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n })\n return readEnvelope(response) as Promise<{ entry: WireEntry | null; updated: boolean }>\n }\n}\n", "/**\n * Bilingual surface copy (zh-first). Pure \u2014 no DOM, unit-testable.\n * The shell owns <html lang>; the panel reads it at render time.\n */\n\nexport type Lang = 'zh' | 'en'\n\nexport const dictionaries: Record<Lang, Record<string, string>> = {\n zh: {\n 'guide.label': '\u8BB0\u5FC6\u63D2\u4EF6\u4FE1\u606F\u4E0E\u5FEB\u6377\u5165\u53E3',\n 'guide.repository': 'GitHub \u9879\u76EE',\n 'guide.settings': '\u6253\u5F00\u8BB0\u5FC6\u8BBE\u7F6E',\n 'sidebar.description': '\u8FB9\u5BF9\u8BDD\u8FB9\u67E5\u770B\u9879\u76EE\u8BB0\u5FC6\u3001Hot Memory \u4E0E\u6765\u6E90\u3002',\n 'about.title': '\u5173\u4E8E\u4E0E\u5E2E\u52A9',\n 'notice.title': '\u672C\u7248\u66F4\u65B0',\n 'notice.dismiss': '\u77E5\u9053\u4E86',\n 'notice.reopen': '\u67E5\u770B\u672C\u7248\u66F4\u65B0',\n 'notice.compat': '0.9.3 \u9002\u914D DSH 0.2.1-rc.2\uFF1B\u4FEE\u590D\u8BB0\u5FC6\u4E2D\u7684\u6A21\u677F\u5B57\u9762\u91CF\u963B\u65AD\u5BF9\u8BDD\u3001Hot Memory \u9884\u7B97\u63D0\u524D\u7EC8\u6B62\uFF0C\u4EE5\u53CA\u5F02\u5E38\u5B58\u50A8\u6587\u4EF6\u7684\u4FDD\u62A4\u7F3A\u53E3\u3002',\n 'notice.features': '\u5347\u7EA7\u5E76\u91CD\u65B0\u52A0\u8F7D\u63D2\u4EF6\u540E\uFF0C\u542B\u6A21\u677F\u5B57\u9762\u91CF\u7684\u65E7\u5FEB\u7167\u65E0\u9700\u624B\u5DE5\u5220\u9664\uFF1B\u539F\u59CB\u8BB0\u5FC6\u4E0D\u6539\u5199\u3002\u65E7\u7248\u5F02\u5E38\u56DE\u6267\u5BFC\u81F4\u7684\u5386\u53F2\u65E5\u5FD7\u6545\u969C\u4ECD\u9700\u5355\u72EC\u6062\u590D\uFF1A\u5148\u53EA\u8BFB\u68C0\u67E5\uFF0C\u5168\u90E8\u5BBF\u4E3B\u9000\u51FA\u5E76\u5907\u4EFD\u540E\uFF0C\u518D\u6309\u6062\u590D\u6307\u5357\u6267\u884C\u3002',\n 'notice.privacy': '\u516C\u544A\u968F\u5305\u5185\u7F6E\uFF0C\u4E0D\u8054\u7F51\u3001\u4E0D\u6539\u8BB0\u5FC6\u3002\u786E\u8BA4\u540E\u672C\u7248\u672C\u4E0D\u518D\u81EA\u52A8\u663E\u793A\uFF1B\u53EF\u5728\u201C\u5173\u4E8E\u4E0E\u5E2E\u52A9\u201D\u91CD\u770B\u3002',\n 'about.host': '\u652F\u6301\u7684 DSH \u8303\u56F4',\n 'about.baseline': '\u5F00\u53D1 SDK \u57FA\u7EBF',\n 'about.maintainer': '\u7EF4\u62A4\u8005',\n 'about.repositoryNote': '\u4EE5\u4E0B\u662F\u8BB0\u5FC6\u63D2\u4EF6\u7684\u9879\u76EE\u4ED3\u5E93\uFF0C\u4E0D\u662F\u5F53\u524D\u4F1A\u8BDD\u5DE5\u4F5C\u533A\u7684 Git \u4ED3\u5E93\u3002',\n 'about.links': '\u63D2\u4EF6\u9879\u76EE\u4E0E\u5E2E\u52A9\u94FE\u63A5',\n 'about.readmeFile': 'README.md',\n 'about.docs': '\u4F7F\u7528\u6587\u6863',\n 'about.releases': '\u7248\u672C\u4E0E\u66F4\u65B0\u65E5\u5FD7',\n 'about.issues': '\u95EE\u9898\u53CD\u9988',\n 'about.updates': '\u66F4\u65B0\u8BF7\u4F7F\u7528\u5BBF\u4E3B\u63D2\u4EF6\u7BA1\u7406\u5668\uFF1B\u5B89\u88C5\u524D\u6838\u5BF9\u76EE\u6807\u7248\u672C\u7684 DSH \u8981\u6C42\uFF0C\u9884\u53D1\u5E03\u901A\u9053\u4E5F\u9700\u5339\u914D\u3002\u672C\u9762\u677F\u4E0D\u81EA\u52A8\u8054\u7F51\u68C0\u67E5\u6216\u5347\u7EA7\uFF0C\u4E0D\u4E0A\u4F20\u5DE5\u4F5C\u533A\u8DEF\u5F84\u6216\u8BB0\u5FC6\u5185\u5BB9\u3002',\n 'snapshot.disk': '\u4F1A\u8BDD\u5FEB\u7167\u6301\u4E45\u5316',\n 'snapshot.restored': '\u4ECE\u78C1\u76D8\u6062\u590D',\n 'snapshot.created': '\u5EFA\u7ACB\u65B0\u57FA\u7EBF',\n 'snapshot.failures': '\u6301\u4E45\u5316\u5931\u8D25',\n 'snapshot.last': '\u6700\u8FD1\u78C1\u76D8\u64CD\u4F5C',\n 'snapshot.idle': '\u5C1A\u672A\u8BFB\u53D6',\n 'snapshot.volatile': '\u964D\u7EA7\u4E3A\u8FDB\u7A0B\u5185\u5FEB\u7167',\n 'snapshot.degraded': '\u65E0\u6CD5\u4FDD\u8BC1\u91CD\u542F\u540E\u524D\u7F00\u4E00\u81F4\uFF1B\u8BF7\u68C0\u67E5\u5FEB\u7167\u5B58\u50A8',\n 'snapshot.invalid-record': '\u683C\u5F0F\u6216\u6821\u9A8C\u4E0D\u7B26\uFF0C\u539F\u6587\u4EF6\u5DF2\u4FDD\u7559',\n 'snapshot.record-too-large': '\u8D85\u51FA\u5FEB\u7167\u5927\u5C0F\u4E0A\u9650',\n 'snapshot.unavailable': '\u8BFB\u5199\u4E0D\u53EF\u7528\u6216\u9501\u8D85\u65F6',\n 'snapshot.retention': 'LRU \u4EC5\u9650\u5236\u5185\u5B58\uFF1B\u78C1\u76D8\u5FEB\u7167\u65E0\u81EA\u52A8\u8FC7\u671F\u3002\u65E7\u4F1A\u8BDD\u9996\u6B21\u5347\u7EA7\u53EF\u80FD\u5EFA\u7ACB\u4E00\u6B21\u65B0\u57FA\u7EBF\uFF1B\u4E0D\u4FDD\u8BC1\u670D\u52A1\u7AEF\u7F13\u5B58\u547D\u4E2D\u3002',\n 'distill.title': '\u81EA\u52A8\u84B8\u998F\u751F\u547D\u5468\u671F',\n 'distill.worked': '\u7D2F\u8BA1\u6709\u6548\u5DE5\u4F5C\u56DE\u5408',\n 'distill.agents': '\u8DDF\u8E2A Agent',\n 'distill.note': '\u672C\u6B21\u8FDB\u7A0B\u5185\u7EDF\u8BA1\uFF1B\u63D0\u9192\u6210\u529F\u4E0D\u4EE3\u8868\u8BB0\u5FC6\u5DF2\u5199\u5165\u3002\u505C\u7528\u81EA\u52A8\u84B8\u998F\u540E\u4ECD\u53EF\u624B\u52A8\u8BB0\u5F55\u3002',\n 'distill.last': '\u6700\u8FD1\u51B3\u7B56',\n 'distill.disabled': '\u81EA\u52A8\u84B8\u998F\u5DF2\u5173\u95ED',\n 'distill.subagent': '\u5B50\u4EE3\u7406\u8DF3\u8FC7',\n 'distill.aborted': '\u4E2D\u6B62\u8DF3\u8FC7',\n 'distill.idle': '\u65E0\u5DE5\u5177\u6D3B\u52A8',\n 'distill.recorded': '\u672C\u56DE\u5408\u5DF2\u4FDD\u5B58\u8BB0\u5FC6\u6216\u66F4\u65B0',\n 'distill.unavailable': '\u4F1A\u8BDD\u6D3B\u52A8\u6295\u5F71\u4E0D\u53EF\u7528\uFF0C\u5DF2\u5B89\u5168\u8DF3\u8FC7',\n 'writes.title': '\u5B9E\u9645\u5199\u5165\u7ED3\u679C',\n 'writes.persisted': '\u5DF2\u4FDD\u5B58\u5199\u5165 / \u66F4\u65B0',\n 'writes.afterReminder': '\u5176\u4E2D\uFF1A\u63D0\u9192\u6240\u5728\u56DE\u5408\u540E\u7EED\u4FDD\u5B58',\n 'writes.failed': '\u5DE5\u5177\u7ED3\u679C\u5931\u8D25',\n 'writes.canceled': '\u5DE5\u5177\u7ED3\u679C\u53D6\u6D88',\n 'writes.needsResolution': '\u76F8\u4F3C\u8BB0\u5FC6\u5F85\u786E\u8BA4\uFF08\u672A\u5199\u5165\uFF09',\n 'writes.receiptFailed': '\u5DF2\u4FDD\u5B58\u4F46\u56DE\u5408\u56DE\u6267\u4E0D\u53EF\u7528',\n 'writes.note': '\u4EC5\u7EDF\u8BA1\u672C\u8FDB\u7A0B\u5185 Agent \u5DE5\u5177\uFF1B\u4FDD\u5B58\u540E\u4ECD\u53EF\u80FD\u88AB\u5BBF\u4E3B\u5224\u5B9A\u53D6\u6D88\uFF0C\u56E0\u6B64\u8BA1\u6570\u53EF\u91CD\u53E0\u3002\u4FDD\u5B58\u4E0E\u63D0\u9192\u7684\u5173\u8054\u4E0D\u8BC1\u660E\u56E0\u679C\u6216\u8BB0\u5FC6\u5185\u5BB9\u6B63\u786E\u3002',\n 'distill.duplicate': '\u91CD\u590D\u6216\u8FC7\u671F\u56DE\u5408',\n 'distill.interval': '\u672A\u8FBE\u56DE\u5408\u95F4\u9694',\n 'distill.tools': '\u672A\u8FBE\u5DE5\u5177\u8C03\u7528\u9608\u503C',\n 'distill.cooldown': '\u51B7\u5374\u4E2D',\n 'distill.queued': '\u5DF2\u6392\u5165\u72EC\u7ACB\u6536\u5C3E\u56DE\u5408',\n 'distill.distillation': '\u8BB0\u5FC6\u6536\u5C3E\u56DE\u5408\uFF0C\u4E0D\u518D\u89E6\u53D1\u84B8\u998F',\n 'distill.failed': '\u63D0\u9192\u63D0\u4EA4\u5931\u8D25',\n 'entry.label': '\u8BB0\u5FC6',\n 'entry.tooltip': '\u6253\u5F00\u8BB0\u5FC6\u9762\u677F\uFF08\u9879\u76EE\u8BB0\u5FC6 / \u5168\u5C40\u8BB0\u5FC6\uFF09',\n 'panel.title': '\u8BB0\u5FC6 Memoir',\n 'panel.close': '\u5173\u95ED',\n 'panel.refresh': '\u5237\u65B0',\n 'surface.navigation': '\u8BB0\u5FC6\u529F\u80FD\u533A',\n 'surface.browse': '\u8BB0\u5FC6\u6D4F\u89C8',\n 'surface.settings': '\u8BB0\u5FC6\u8BBE\u7F6E',\n 'surface.hotMemory': 'Hot Memory',\n 'surface.diagnostics': '\u8BCA\u65AD',\n 'browse.scope': '\u8BB0\u5FC6\u8303\u56F4',\n 'tab.project': '\u9879\u76EE\u8BB0\u5FC6',\n 'tab.global': '\u5168\u5C40\u8BB0\u5FC6',\n 'entry.expand': '\u5C55\u5F00\u6B63\u6587',\n 'entry.collapse': '\u6536\u8D77\u6B63\u6587',\n 'toolbar.search': '\u641C\u7D22\u6807\u9898\u4E0E\u6B63\u6587\u2026',\n 'toolbar.add': '\u6DFB\u52A0\u8BB0\u5FC6',\n 'toolbar.cancel': '\u53D6\u6D88',\n 'form.section': '\u5206\u7C7B',\n 'form.title': '\u6807\u9898\uFF08\u53EF\u9009\uFF09',\n 'form.content': '\u5185\u5BB9',\n 'form.importance': '\u91CD\u8981\u5EA6',\n 'form.importanceHint': '1 \u6700\u4F4E\uFF0C5 \u6700\u9AD8\uFF1B\u4F1A\u5F71\u54CD Hot Memory \u6392\u5E8F\u3002',\n 'form.tags': '\u6807\u7B7E',\n 'form.supersedes': '\u66FF\u4EE3\u7684\u8BB0\u5FC6 ID',\n 'form.pinned': '\u7F6E\u9876\u8FD9\u6761\u8BB0\u5FC6',\n 'form.pinnedHint': '\u7F6E\u9876\u6761\u76EE\u5728 Hot Memory \u9009\u62E9\u4E2D\u4F18\u5148\u3002',\n 'form.submit': '\u8BB0\u5F55',\n 'form.placeholder.title': '\u4E00\u53E5\u8BDD\u6807\u9898\uFF0C\u5982\u300C\u4FEE\u590D pet \u60AC\u505C\u95EA\u9000\u300D',\n 'form.placeholder.content': '\u5177\u4F53\u505A\u4E86\u4EC0\u4E48\u3001\u7ED3\u8BBA\u3001\u6559\u8BAD\u6216\u4E0B\u4E00\u6B65\u600E\u4E48\u505A\u3002\u5EFA\u8BAE\u7CBE\u70BC\u3001\u53EF\u6267\u884C\u3002',\n 'form.placeholder.tags': '\u9017\u53F7\u5206\u9694\uFF0C\u4F8B\u5982 release, windows',\n 'form.placeholder.supersedes': '\u9017\u53F7\u5206\u9694\u7684\u65E7\u8BB0\u5FC6 ID\uFF08\u53EF\u9009\uFF09',\n 'empty.project': '\u672C\u9879\u76EE\u6682\u65E0\u6301\u4E45\u8BB0\u5FC6',\n 'empty.projectHint': '\u8BA9 agent \u7528 memoir_record \u6C89\u6DC0\u7ECF\u9A8C\uFF0C\u6216\u70B9\u300C\u6DFB\u52A0\u8BB0\u5FC6\u300D\u624B\u52A8\u8BB0\u5F55\u3002',\n 'empty.workspace': '\u672A\u6253\u5F00\u9879\u76EE\u4F1A\u8BDD',\n 'empty.workspaceHint': '\u6253\u5F00\u4E00\u4E2A\u9879\u76EE\u4F1A\u8BDD\u540E\uFF0C\u8FD9\u91CC\u663E\u793A\u8BE5\u9879\u76EE\u7684\u6301\u4E45\u8BB0\u5FC6\u3002',\n 'empty.global': '\u5168\u5C40\u7D22\u5F15\u4E3A\u7A7A',\n 'empty.globalHint': '\u5728\u4EFB\u4F55\u9879\u76EE\u91CC\u7528 memoir_record \u8BB0\u5F55\u540E\uFF0C\u4F1A\u51FA\u73B0\u5728\u8FD9\u91CC\u4F9B\u8DE8\u9879\u76EE\u68C0\u7D22\u3002',\n 'empty.search': '\u6CA1\u6709\u5339\u914D\u7684\u6761\u76EE',\n 'load.failed': '\u52A0\u8F7D\u5931\u8D25',\n 'record.failed': '\u8BB0\u5F55\u5931\u8D25',\n 'update.failed': '\u66F4\u65B0\u5931\u8D25',\n 'delete.failed': '\u5220\u9664\u5931\u8D25',\n 'delete.confirm': '\u5220\u9664\u8FD9\u6761\u8BB0\u5FC6\uFF1F',\n 'updated': '\u66F4\u65B0\u4E8E',\n 'entries': '\u6761',\n 'pagination.showing': '\u5DF2\u663E\u793A',\n 'pagination.projects': '\u5DF2\u663E\u793A\u9879\u76EE',\n 'pagination.more': '\u52A0\u8F7D\u66F4\u591A',\n 'project.expandAll': '\u5168\u90E8\u5C55\u5F00',\n 'project.collapseAll': '\u5168\u90E8\u6298\u53E0',\n 'project.unscoped': '\u672A\u5F52\u5C5E',\n 'project.unscopedHint': '\u6CA1\u6709\u9879\u76EE\u6765\u6E90\u7684\u5386\u53F2\u8BB0\u5FC6',\n 'session': '\u4F1A\u8BDD',\n 'source.label': '\u6765\u6E90',\n 'source.turn': '\u56DE\u5408',\n 'source.open': '\u6253\u5F00\u6765\u6E90\u4F1A\u8BDD\uFF08\u56DE\u5408\u7F16\u53F7\u53EF\u590D\u5236\uFF09',\n 'source.copy': '\u590D\u5236\u4F1A\u8BDD\u4E0E\u56DE\u5408\u6807\u8BC6',\n 'source.copied': '\u5DF2\u590D\u5236',\n 'sections.work': '\u5DE5\u4F5C\u8BB0\u5F55',\n 'sections.lessons': '\u7ECF\u9A8C\u6559\u8BAD',\n 'sections.actions': '\u884C\u52A8\u6307\u5357',\n 'sections.note': '\u5907\u6CE8',\n 'diag.title': 'Memory Diagnostics',\n 'diag.revision': 'Store revision',\n 'diag.snapshot': 'Session snapshots',\n 'diag.cache': 'Store cache',\n 'diag.render': 'Render cache',\n 'diag.hot': 'Hot memory',\n 'diag.retrieval': 'Retrieval \u7D22\u5F15',\n 'diag.qcache': 'Query cache',\n 'diag.lastQuery': '\u6700\u8FD1\u67E5\u8BE2',\n 'diag.snapshotInfo': '\u4F1A\u8BDD\u5FEB\u7167',\n 'diag.unavailable': '\u8BCA\u65AD\u4FE1\u606F\u6682\u4E0D\u53EF\u7528',\n 'diag.hits': '\u547D\u4E2D',\n 'diag.misses': '\u672A\u547D\u4E2D',\n 'diag.items': '\u6761',\n 'diag.budget': '\u9884\u7B97',\n 'diag.documents': '\u6587\u6863',\n 'diag.terms': '\u8BCD\u9879',\n 'diag.epoch': '\u4EE3\u6B21',\n 'diag.evicted': '\u5DF2\u6DD8\u6C70',\n 'diag.returned': '\u8FD4\u56DE/\u5019\u9009',\n 'inspector.title': 'Hot Memory \u9884\u89C8',\n 'inspector.empty': '\u672C\u5DE5\u4F5C\u533A\u6682\u65E0 Hot Memory',\n 'inspector.selected': '\u5DF2\u9009\u8BB0\u5FC6',\n 'search.ranked': '\u6309\u76F8\u5173\u6027\u6392\u5E8F',\n 'filter.status': '\u72B6\u6001',\n 'filter.section': '\u5206\u7C7B',\n 'filter.all': '\u5168\u90E8',\n 'status.active': '\u6D3B\u8DC3',\n 'status.superseded': '\u5DF2\u88AB\u66FF\u4EE3',\n 'status.archived': '\u5DF2\u5F52\u6863',\n 'lifecycle.pin': '\u7F6E\u9876',\n 'lifecycle.unpin': '\u53D6\u6D88\u7F6E\u9876',\n 'lifecycle.edit': '\u7F16\u8F91',\n 'lifecycle.save': '\u4FDD\u5B58\u66F4\u65B0',\n 'lifecycle.supersede': '\u6807\u8BB0\u5DF2\u66FF\u4EE3',\n 'lifecycle.unsupersede': '\u6062\u590D\u6D3B\u8DC3',\n 'lifecycle.archive': '\u5F52\u6863',\n 'lifecycle.restore': '\u6062\u590D',\n 'similarity.title': '\u53D1\u73B0\u76F8\u4F3C\u8BB0\u5FC6\uFF0C\u672C\u6B21\u5C1A\u672A\u5199\u5165',\n 'similarity.description': '\u8BF7\u9009\u62E9\u66F4\u65B0\u5DF2\u6709\u8BB0\u5FC6\u3001\u7528\u65B0\u7ED3\u8BBA\u66FF\u4EE3\u5B83\uFF0C\u6216\u660E\u786E\u4FDD\u7559\u4E24\u6761\uFF1B\u63D2\u4EF6\u4E0D\u4F1A\u81EA\u52A8\u5220\u9664\u6216\u5408\u5E76\u3002',\n 'similarity.kind.duplicate': '\u7591\u4F3C\u91CD\u590D',\n 'similarity.kind.conflict': '\u53EF\u80FD\u51B2\u7A81',\n 'similarity.titleScore': '\u6807\u9898',\n 'similarity.update': '\u66F4\u65B0\u8FD9\u4E00\u6761',\n 'similarity.supersede': '\u7528\u65B0\u7ED3\u8BBA\u66FF\u4EE3',\n 'similarity.force': '\u4ECD\u7136\u4FDD\u7559\u4E24\u6761',\n 'similarity.back': '\u8FD4\u56DE\u4FEE\u6539',\n 'similarity.reason.exact-content': '\u6B63\u6587\u4E00\u81F4',\n 'similarity.reason.exact-title': '\u6807\u9898\u4E00\u81F4',\n 'similarity.reason.high-title-overlap': '\u6807\u9898\u9AD8\u5EA6\u76F8\u4F3C',\n 'similarity.reason.high-token-overlap': 'Token \u9AD8\u91CD\u5408',\n 'similarity.reason.bm25-candidate': 'BM25 \u9AD8\u76F8\u5173',\n 'similarity.reason.same-topic-different-content': '\u540C\u4E3B\u9898\u4F46\u5185\u5BB9\u4E0D\u540C',\n 'settings.title': '\u8BB0\u5FC6\u8BBE\u7F6E',\n 'settings.description': '\u5B8C\u6574\u8FD0\u884C\u65F6\u8BBE\u7F6E\uFF1B\u4FDD\u5B58\u540E\u7ACB\u5373\u5E94\u7528\uFF0C\u5E76\u6301\u4E45\u5316\u5230\u672C\u673A DSH \u7528\u6237\u76EE\u5F55\u3002',\n 'settings.language': 'Agent \u4F7F\u7528\u8BED\u8A00',\n 'settings.languageHint': '\u63A7\u5236\u5DE5\u5177\u8BF4\u660E\u3001\u81EA\u52A8\u84B8\u998F\u3001Hot Memory \u6807\u9898\u3001\u5DE5\u5177\u7ED3\u679C\u548C\u9519\u8BEF\uFF1B\u4E0D\u6539\u53D8 Web \u754C\u9762\u8BED\u8A00\u3002',\n 'settings.language.zh': '\u4E2D\u6587',\n 'settings.language.en': 'English',\n 'settings.language.de': 'Deutsch\uFF08\u5FB7\u8BED\uFF09',\n 'settings.language.ru': '\u0420\u0443\u0441\u0441\u043A\u0438\u0439\uFF08\u4FC4\u8BED\uFF09',\n 'settings.expand': '\u5C55\u5F00',\n 'settings.collapse': '\u6298\u53E0',\n 'settings.announce': '\u5411 Agent \u6CE8\u5165\u8BB0\u5FC6',\n 'settings.announceHint': '\u5173\u95ED\u540E\u4E0D\u518D\u5411\u7CFB\u7EDF\u63D0\u793A\u6CE8\u5165\u63D2\u4EF6\u8BF4\u660E\u4E0E Hot Memory\uFF0C\u4F46\u5DE5\u5177\u548C GUI \u4FDD\u6301\u53EF\u7528\u3002',\n 'settings.group.distill': '\u81EA\u52A8\u84B8\u998F',\n 'settings.group.memory': 'Hot Memory\u3001\u53EC\u56DE\u4E0E\u7F13\u5B58',\n 'settings.enabled': '\u542F\u7528\u81EA\u52A8\u84B8\u998F',\n 'settings.enabledHint': '\u5728\u9876\u5C42 agent \u7684\u6709\u6548\u5DE5\u4F5C\u56DE\u5408\u7ED3\u675F\u65F6\u63D0\u9192\u5F52\u7EB3\u8BB0\u5FC6\u3002',\n 'settings.autoDistillEvery': '\u5DE5\u4F5C\u56DE\u5408\u95F4\u9694',\n 'settings.autoDistillEveryHint': '\u6BCF\u7D2F\u8BA1 N \u4E2A worked turn \u6700\u591A\u63D0\u9192\u4E00\u6B21\uFF08\u6700\u5C0F 1\uFF09\u3002',\n 'settings.autoDistillCooldownMin': '\u51B7\u5374\u65F6\u95F4\uFF08\u5206\u949F\uFF09',\n 'settings.autoDistillCooldownMinHint': '\u4E24\u6B21\u6210\u529F\u63D0\u9192\u81F3\u5C11\u95F4\u9694 M \u5206\u949F\uFF08\u6700\u5C0F 0\uFF09\u3002',\n 'settings.autoDistillMinTools': '\u6700\u4F4E\u5DE5\u5177\u8C03\u7528\u6570',\n 'settings.autoDistillMinToolsHint': '\u89E6\u53D1\u56DE\u5408\u81F3\u5C11\u5305\u542B K \u6B21\u5DE5\u5177\u8C03\u7528\uFF08\u6700\u5C0F 1\uFF09\u3002',\n 'settings.hotMemoryTokens': 'Hot Memory \u76EE\u6807 tokens',\n 'settings.hotMemoryTokensHint': '\u5E38\u89C4\u9009\u62E9\u9884\u7B97\uFF0C\u5FC5\u987B\u4E0D\u5927\u4E8E\u786C\u4E0A\u9650\u3002',\n 'settings.hotMemoryMaxTokens': 'Hot Memory \u786C\u4E0A\u9650',\n 'settings.hotMemoryMaxTokensHint': '\u4EFB\u4F55\u65B0\u4F1A\u8BDD\u5FEB\u7167\u90FD\u4E0D\u4F1A\u8D85\u8FC7\u6B64\u9884\u7B97\u3002',\n 'settings.readDefaultLimit': '\u9ED8\u8BA4\u53EC\u56DE\u6761\u6570',\n 'settings.readDefaultLimitHint': 'memoir_read \u672A\u4F20 limit \u65F6\u4F7F\u7528\u3002',\n 'settings.readMaxLimit': '\u6700\u5927\u53EC\u56DE\u6761\u6570',\n 'settings.readMaxLimitHint': 'memoir_read \u7684\u5B9E\u65F6\u4E0A\u9650\uFF0C\u4E0D\u5C0F\u4E8E\u9ED8\u8BA4\u503C\u3002',\n 'settings.sessionSnapshotMax': '\u4F1A\u8BDD\u5FEB\u7167\u5BB9\u91CF',\n 'settings.sessionSnapshotMaxHint': '\u51BB\u7ED3\u63D0\u793A\u524D\u7F00\u7684 LRU \u5BB9\u91CF\uFF1B\u7F29\u5C0F\u65F6\u7ACB\u5373\u6DD8\u6C70\u6700\u65E7\u9879\u3002',\n 'settings.queryCacheSize': '\u67E5\u8BE2\u7F13\u5B58\u5BB9\u91CF',\n 'settings.queryCacheSizeHint': 'BM25 \u67E5\u8BE2 LRU \u5BB9\u91CF\uFF1B\u7F29\u5C0F\u65F6\u7ACB\u5373\u6DD8\u6C70\u6700\u65E7\u9879\u3002',\n 'settings.andHint': '\u4E09\u4E2A\u9891\u7387\u6761\u4EF6\u6309 AND \u5224\u5B9A\uFF1Bidle\u3001aborted\u3001subagent \u548C\u5DF2\u8BB0\u5F55\u8BB0\u5FC6\u7684\u56DE\u5408\u4E0D\u4F1A\u89E6\u53D1\u3002',\n 'settings.liveHint': '\u9884\u7B97\u548C\u53EC\u56DE\u9650\u5236\u7ACB\u5373\u5F71\u54CD\u65B0\u8BF7\u6C42\uFF1B\u5DF2\u51BB\u7ED3\u7684\u4F1A\u8BDD\u5FEB\u7167\u4E0D\u4F1A\u91CD\u5199\uFF0C\u4EE5\u4FDD\u6301\u63D0\u793A\u524D\u7F00\u7F13\u5B58\u7A33\u5B9A\u3002',\n 'settings.source': '\u5F53\u524D\u6765\u6E90',\n 'settings.source.profile': '\u542F\u52A8\u914D\u7F6E',\n 'settings.source.web': 'Web \u6301\u4E45\u5316\u8986\u76D6',\n 'settings.save': '\u4FDD\u5B58\u5E76\u7ACB\u5373\u5E94\u7528',\n 'settings.reset': '\u6062\u590D\u542F\u52A8\u914D\u7F6E',\n 'settings.saved': '\u5DF2\u4FDD\u5B58\uFF0C\u540E\u7EED\u56DE\u5408\u7ACB\u5373\u751F\u6548\u3002',\n 'settings.resetDone': '\u5DF2\u6062\u590D\u672C\u6B21\u542F\u52A8\u65F6\u7684\u914D\u7F6E\u3002',\n 'settings.invalid': '\u8BF7\u8F93\u5165\u6709\u6548\u6570\u503C\uFF1A\u6574\u6570\u9879\u4E0D\u5C0F\u4E8E 1\u3001\u51B7\u5374\u4E0D\u5C0F\u4E8E 0\uFF1B\u786C\u4E0A\u9650\u4E0D\u5F97\u5C0F\u4E8E\u76EE\u6807\u6216\u9ED8\u8BA4\u503C\u3002',\n 'settings.loadFailed': '\u8BBE\u7F6E\u52A0\u8F7D\u5931\u8D25',\n 'settings.saveFailed': '\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25',\n },\n en: {\n 'guide.label': 'Memoir identity and shortcuts',\n 'guide.repository': 'GitHub project',\n 'guide.settings': 'Open memory settings',\n 'sidebar.description': 'Browse project memory, Hot Memory and sources alongside your chat.',\n 'about.title': 'About & help',\n 'notice.title': 'What\u2019s new',\n 'notice.dismiss': 'Got it',\n 'notice.reopen': 'View release highlights',\n 'notice.compat': '0.9.3 supports DSH 0.2.1-rc.2 and fixes template literals blocking chat, premature Hot Memory budget termination, and unsafe handling of unsupported or damaged stores.',\n 'notice.features': 'After upgrading and reloading the plugin, old snapshots with template literals need no manual deletion; original memories are unchanged. Legacy invalid-receipt logs still need separate repair: audit first, stop every host and back up, then follow the recovery guide.',\n 'notice.privacy': 'Bundled offline; no memory changes. Acknowledge once per version, or reopen from About & help.',\n 'about.host': 'Supported DSH range',\n 'about.baseline': 'Development SDK baseline',\n 'about.maintainer': 'Maintainer',\n 'about.repositoryNote': 'These links belong to the memory plugin, not the current workspace Git repository.',\n 'about.links': 'Plugin project and help links',\n 'about.readmeFile': 'README.en.md',\n 'about.docs': 'Documentation',\n 'about.releases': 'Releases & changelog',\n 'about.issues': 'Report an issue',\n 'about.updates': 'Use the host plugin manager to update. Check the target package\u2019s DSH requirements, including its prerelease channel, before installing. This panel does not automatically check or upgrade online, or upload workspace paths or memory content.',\n 'snapshot.disk': 'Durable session snapshots',\n 'snapshot.restored': 'Restored from disk',\n 'snapshot.created': 'New baselines',\n 'snapshot.failures': 'Persistence failures',\n 'snapshot.last': 'Last disk operation',\n 'snapshot.idle': 'Not read yet',\n 'snapshot.volatile': 'Process-local fallback',\n 'snapshot.degraded': 'Prefix stability across restart is not guaranteed; check snapshot storage',\n 'snapshot.invalid-record': 'Invalid format or hash; original file preserved',\n 'snapshot.record-too-large': 'Snapshot size limit exceeded',\n 'snapshot.unavailable': 'Storage unavailable or lock timeout',\n 'snapshot.retention': 'LRU bounds RAM only; disk snapshots do not auto-expire. Older sessions may establish a new baseline once after upgrade. Server-side cache hits are not guaranteed.',\n 'distill.title': 'Automatic distillation lifecycle',\n 'distill.worked': 'Eligible worked turns',\n 'distill.agents': 'Tracked agents',\n 'distill.note': 'Process-local counters; a submitted reminder does not confirm a memory write. Manual recording remains available when disabled.',\n 'distill.last': 'Latest decision',\n 'distill.disabled': 'Automatic distillation disabled',\n 'distill.subagent': 'Subagent skipped',\n 'distill.aborted': 'Aborted turn skipped',\n 'distill.idle': 'No tool activity',\n 'distill.recorded': 'Memory write or update persisted in this turn',\n 'distill.unavailable': 'Activity projection unavailable; skipped safely',\n 'writes.title': 'Actual write outcomes',\n 'writes.persisted': 'Persisted writes / updates',\n 'writes.afterReminder': 'Of these: later saves in a reminded turn',\n 'writes.failed': 'Failed tool results',\n 'writes.canceled': 'Canceled tool results',\n 'writes.needsResolution': 'Similarity needs resolution (no write)',\n 'writes.receiptFailed': 'Saved but turn receipt unavailable',\n 'writes.note': 'Process-local Agent tools only. Host cancellation may follow a save, so counts may overlap. Correlation with a reminder proves neither causation nor semantic correctness.',\n 'distill.duplicate': 'Duplicate or stale turn',\n 'distill.interval': 'Turn interval not reached',\n 'distill.tools': 'Tool threshold not reached',\n 'distill.cooldown': 'Cooldown active',\n 'distill.queued': 'Separate wrap-up turn queued',\n 'distill.distillation': 'Memory wrap-up turn; no recursive reminder',\n 'distill.failed': 'Reminder submission failed',\n 'entry.label': 'Memory',\n 'entry.tooltip': 'Open the memory panel (project / global)',\n 'panel.title': 'Memory Memoir',\n 'panel.close': 'Close',\n 'panel.refresh': 'Refresh',\n 'surface.navigation': 'Memory sections',\n 'surface.browse': 'Browse',\n 'surface.settings': 'Settings',\n 'surface.hotMemory': 'Hot Memory',\n 'surface.diagnostics': 'Diagnostics',\n 'browse.scope': 'Memory scope',\n 'tab.project': 'Project',\n 'tab.global': 'Global',\n 'entry.expand': 'Expand content',\n 'entry.collapse': 'Collapse content',\n 'toolbar.search': 'Search titles and content\u2026',\n 'toolbar.add': 'Add entry',\n 'toolbar.cancel': 'Cancel',\n 'form.section': 'Section',\n 'form.title': 'Title (optional)',\n 'form.content': 'Content',\n 'form.importance': 'Importance',\n 'form.importanceHint': '1 is lowest and 5 is highest; this affects Hot Memory ranking.',\n 'form.tags': 'Tags',\n 'form.supersedes': 'Superseded entry IDs',\n 'form.pinned': 'Pin this entry',\n 'form.pinnedHint': 'Pinned entries receive priority during Hot Memory selection.',\n 'form.submit': 'Record',\n 'form.placeholder.title': 'A one-line title, e.g. \"Fix pet hover crash\"',\n 'form.placeholder.content': 'What was done, the conclusion, the lesson, or the next step. Concise and actionable.',\n 'form.placeholder.tags': 'Comma-separated, for example release, windows',\n 'form.placeholder.supersedes': 'Comma-separated old entry IDs (optional)',\n 'empty.project': 'No persistent memory in this project yet',\n 'empty.projectHint': 'Ask the agent to distill via memoir_record, or add an entry manually.',\n 'empty.workspace': 'No project session open',\n 'empty.workspaceHint': 'Open a project session to see its persistent memory here.',\n 'empty.global': 'The global index is empty',\n 'empty.globalHint': 'Entries recorded via memoir_record in any project appear here for cross-project search.',\n 'empty.search': 'No matching entries',\n 'load.failed': 'Failed to load',\n 'record.failed': 'Failed to record',\n 'update.failed': 'Failed to update',\n 'delete.failed': 'Failed to delete',\n 'delete.confirm': 'Delete this entry?',\n 'updated': 'Updated',\n 'entries': 'entries',\n 'pagination.showing': 'Showing',\n 'pagination.projects': 'Projects shown',\n 'pagination.more': 'Load more',\n 'project.expandAll': 'Expand all',\n 'project.collapseAll': 'Collapse all',\n 'project.unscoped': 'Unscoped',\n 'project.unscopedHint': 'Legacy memories without a project source',\n 'session': 'session',\n 'source.label': 'Source',\n 'source.turn': 'turn',\n 'source.open': 'Open the source session (turn ID can be copied)',\n 'source.copy': 'Copy session and turn identifiers',\n 'source.copied': 'Copied',\n 'sections.work': 'Work Log',\n 'sections.lessons': 'Lessons Learned',\n 'sections.actions': 'Action Guide',\n 'sections.note': 'Notes',\n 'diag.title': 'Memory Diagnostics',\n 'diag.revision': 'Store revision',\n 'diag.snapshot': 'Session snapshots',\n 'diag.cache': 'Store cache',\n 'diag.render': 'Render cache',\n 'diag.hot': 'Hot memory',\n 'diag.retrieval': 'Retrieval index',\n 'diag.qcache': 'Query cache',\n 'diag.lastQuery': 'Last query',\n 'diag.snapshotInfo': 'Session snapshot',\n 'diag.unavailable': 'Diagnostics are temporarily unavailable',\n 'diag.hits': 'hits',\n 'diag.misses': 'misses',\n 'diag.items': 'entries',\n 'diag.budget': 'budget',\n 'diag.documents': 'docs',\n 'diag.terms': 'terms',\n 'diag.epoch': 'epoch',\n 'diag.evicted': 'evicted',\n 'diag.returned': 'returned/candidates',\n 'inspector.title': 'Hot Memory Inspector',\n 'inspector.empty': 'No hot memory in this workspace yet',\n 'inspector.selected': 'Selected memories',\n 'search.ranked': 'Ranked by relevance',\n 'filter.status': 'Status',\n 'filter.section': 'Section',\n 'filter.all': 'All',\n 'status.active': 'Active',\n 'status.superseded': 'Superseded',\n 'status.archived': 'Archived',\n 'lifecycle.pin': 'Pin',\n 'lifecycle.unpin': 'Unpin',\n 'lifecycle.edit': 'Edit',\n 'lifecycle.save': 'Save update',\n 'lifecycle.supersede': 'Mark superseded',\n 'lifecycle.unsupersede': 'Restore active',\n 'lifecycle.archive': 'Archive',\n 'lifecycle.restore': 'Restore',\n 'similarity.title': 'Similar memory found; nothing has been written yet',\n 'similarity.description': 'Update the existing memory, supersede it with the new conclusion, or explicitly keep both. The plugin never deletes or merges automatically.',\n 'similarity.kind.duplicate': 'Likely duplicate',\n 'similarity.kind.conflict': 'Possible conflict',\n 'similarity.titleScore': 'title',\n 'similarity.update': 'Update this entry',\n 'similarity.supersede': 'Supersede with new',\n 'similarity.force': 'Keep both anyway',\n 'similarity.back': 'Back to edit',\n 'similarity.reason.exact-content': 'Exact content',\n 'similarity.reason.exact-title': 'Exact title',\n 'similarity.reason.high-title-overlap': 'High title overlap',\n 'similarity.reason.high-token-overlap': 'High token overlap',\n 'similarity.reason.bm25-candidate': 'High BM25 relevance',\n 'similarity.reason.same-topic-different-content': 'Same topic, different content',\n 'settings.title': 'Memory settings',\n 'settings.description': 'Complete runtime settings; saves apply immediately and persist in the local DSH user directory.',\n 'settings.language': 'Agent-facing language',\n 'settings.languageHint': 'Controls tool schemas, automatic distillation, Hot Memory headings, tool results, and errors; it does not change the Web UI language.',\n 'settings.language.zh': 'Chinese',\n 'settings.language.en': 'English',\n 'settings.language.de': 'Deutsch (German)',\n 'settings.language.ru': '\u0420\u0443\u0441\u0441\u043A\u0438\u0439 (Russian)',\n 'settings.expand': 'Expand',\n 'settings.collapse': 'Collapse',\n 'settings.announce': 'Inject memory for agents',\n 'settings.announceHint': 'When off, plugin guidance and Hot Memory leave the system prompt while tools and the GUI remain available.',\n 'settings.group.distill': 'Auto-distill',\n 'settings.group.memory': 'Hot Memory, recall, and cache',\n 'settings.enabled': 'Enable auto-distill',\n 'settings.enabledHint': 'Prompt top-level agents to distill memory after eligible worked turns.',\n 'settings.autoDistillEvery': 'Worked-turn interval',\n 'settings.autoDistillEveryHint': 'Remind at most once per N accumulated worked turns (minimum 1).',\n 'settings.autoDistillCooldownMin': 'Cooldown (minutes)',\n 'settings.autoDistillCooldownMinHint': 'Require at least M minutes between successful reminders (minimum 0).',\n 'settings.autoDistillMinTools': 'Minimum tool calls',\n 'settings.autoDistillMinToolsHint': 'The triggering turn must contain at least K tool calls (minimum 1).',\n 'settings.hotMemoryTokens': 'Hot Memory target tokens',\n 'settings.hotMemoryTokensHint': 'Normal selection budget; it cannot exceed the hard limit.',\n 'settings.hotMemoryMaxTokens': 'Hot Memory hard limit',\n 'settings.hotMemoryMaxTokensHint': 'No newly frozen session snapshot exceeds this budget.',\n 'settings.readDefaultLimit': 'Default recall count',\n 'settings.readDefaultLimitHint': 'Used when memoir_read omits limit.',\n 'settings.readMaxLimit': 'Maximum recall count',\n 'settings.readMaxLimitHint': 'Live memoir_read ceiling; it cannot be below the default.',\n 'settings.sessionSnapshotMax': 'Session snapshot capacity',\n 'settings.sessionSnapshotMaxHint': 'LRU capacity for frozen prompt prefixes; shrinking evicts the oldest immediately.',\n 'settings.queryCacheSize': 'Query cache capacity',\n 'settings.queryCacheSizeHint': 'BM25 query LRU capacity; shrinking evicts the oldest immediately.',\n 'settings.andHint': 'All three frequency conditions use AND semantics; idle, aborted, subagent, and already-recorded turns do not trigger.',\n 'settings.liveHint': 'Budgets and recall limits affect new requests immediately; frozen session snapshots remain unchanged for prompt-prefix cache stability.',\n 'settings.source': 'Current source',\n 'settings.source.profile': 'startup profile config',\n 'settings.source.web': 'persistent Web override',\n 'settings.save': 'Save and apply now',\n 'settings.reset': 'Restore startup config',\n 'settings.saved': 'Saved; subsequent turns use the new policy immediately.',\n 'settings.resetDone': 'Restored the configuration captured at startup.',\n 'settings.invalid': 'Enter valid values: integer fields are at least 1 and cooldown is at least 0; a hard/maximum value cannot be below its target/default.',\n 'settings.loadFailed': 'Failed to load settings',\n 'settings.saveFailed': 'Failed to save settings',\n },\n}\n\n/** Section keys in canonical display order. */\nexport const SECTION_KEYS: string[] = ['work', 'lessons', 'actions', 'note']\n\n/** Minimal document surface for language detection. */\nexport interface DocumentLike {\n documentElement?: { lang?: string }\n}\n\n/** Current UI language: zh when the shell's <html lang> starts with zh. */\nexport function detectLanguage(documentLike: DocumentLike | undefined): Lang {\n const lang = documentLike?.documentElement?.lang\n return typeof lang === 'string' && lang.startsWith('zh') ? 'zh' : 'en'\n}\n\n/** Pure translation lookup: `translate(lang, key)` with en fallback. */\nexport function translate(lang: string, key: string): string {\n const dict = dictionaries[lang as Lang] ?? dictionaries.en\n return Object.prototype.hasOwnProperty.call(dict, key) ? dict[key] : (dictionaries.en[key] ?? key)\n}\n\n/** Bound translator reading the live <html lang> at each call. */\nexport function makeT(documentLike: DocumentLike): (key: string) => string {\n return (key) => translate(detectLanguage(documentLike), key)\n}\n", "/**\n * The memoir panel: project / global memory tabs, client-side search,\n * manual record form, per-entry delete. Shared by native Conversation,\n * Settings and optional right-sidebar slots; each owns its view state.\n */\n\nimport { Fragment, useEffect, useId, useMemo, useState, useSyncExternalStore, type KeyboardEvent as ReactKeyboardEvent, type ReactNode } from 'react'\nimport { SECTION_KEYS } from './i18n.js'\nimport type { MemoirApi, WireDiagnostics, WireEntry, WireHotMemory, WireMemoirSettings, WireProject, WireRecordResolution, WireRecordResult, WireSearchResult, WireSimilarityCandidate } from './api.js'\nimport type { CwdTracker } from './cwd.js'\nimport type { PanelController } from './controller.js'\nimport type { MemoirStatus, SectionKey } from './types.ts'\nimport { MemoirAbout } from './about.js'\nimport { MEMOIR_LANGUAGES, resolveMemoirLanguage } from '../host/languages.js'\nimport {\n ENTRY_PAGE_SIZE,\n PROJECT_PAGE_SIZE,\n buildProjectGroups,\n filterEntries,\n groupRankedResults,\n nextPageSize,\n shouldCollapseEntry,\n type EntryStats,\n} from './view-model.js'\n\ninterface PanelProps {\n controller?: PanelController\n api: MemoirApi\n cwdTracker?: CwdTracker\n /** Native alpha slots provide a session-bound cwd directly. */\n cwd?: string\n t: (key: string) => string\n openSource?: (sessionId: string, turnId?: number) => void\n /** Native settings may close their owning shell without a legacy controller. */\n onClose?: () => void\n announceOnOpen?: boolean\n}\n\nconst EMPTY_CWD_TRACKER: CwdTracker = {\n getSnapshot: () => '',\n subscribe: () => () => {},\n}\n\ntype EntryPatch = {\n section?: SectionKey\n title?: string | null\n content?: string\n importance?: number\n pinned?: boolean\n status?: MemoirStatus\n supersedes?: string[]\n tags?: string[]\n}\n\nconst parseList = (value: string): string[] =>\n [...new Set(value.split(/[,\uFF0C\\n]/).map((item) => item.trim()).filter((item) => item !== ''))]\n\nasync function copyText(value: string): Promise<boolean> {\n try {\n if (navigator.clipboard !== undefined) {\n await navigator.clipboard.writeText(value)\n return true\n }\n const textarea = document.createElement('textarea')\n textarea.value = value\n textarea.style.position = 'fixed'\n textarea.style.opacity = '0'\n document.body.appendChild(textarea)\n textarea.select()\n const copied = document.execCommand('copy')\n textarea.remove()\n return copied\n } catch {\n return false\n }\n}\n\n/** One entry's meta line: lifecycle, importance, tags and provenance. */\nfunction EntryMeta({ entry, t, openSource }: {\n entry: WireEntry\n t: (key: string) => string\n openSource?: (sessionId: string, turnId?: number) => void\n}) {\n const [copied, setCopied] = useState(false)\n const when = new Date(entry.time)\n const pad = (n: number) => String(n).padStart(2, '0')\n const timeText = `${when.getFullYear()}-${pad(when.getMonth() + 1)}-${pad(when.getDate())} ${pad(when.getHours())}:${pad(when.getMinutes())}`\n const source = entry.source ?? (entry.sessionId === undefined ? undefined : { sessionId: entry.sessionId })\n const sourceText = source === undefined\n ? ''\n : [\n source.sessionId === undefined ? undefined : `sessionId=${source.sessionId}`,\n source.turnId === undefined ? undefined : `turnId=${source.turnId}`,\n ].filter(Boolean).join('\\n')\n const copySource = () => {\n void copyText(sourceText).then((ok) => {\n if (!ok) return\n setCopied(true)\n setTimeout(() => setCopied(false), 1_500)\n })\n }\n return (\n <div className=\"memoir-entry-meta\">\n <span>{timeText}</span>\n <span className=\"memoir-chip\">{t('sections.' + entry.section)}</span>\n {entry.status !== undefined && entry.status !== 'active'\n ? <span className=\"memoir-chip\">{t('status.' + entry.status)}</span>\n : null}\n {entry.pinned === true ? <span className=\"memoir-chip\">{t('lifecycle.pin')}</span> : null}\n <span className=\"memoir-chip\" title={t('form.importanceHint')}>{t('form.importance')}: {entry.importance ?? 3}</span>\n {(entry.tags ?? []).map((tag) => <span className=\"memoir-chip memoir-tag\" key={tag}>#{tag}</span>)}\n {(entry.supersedes?.length ?? 0) > 0\n ? <span className=\"memoir-chip\" title={entry.supersedes?.join('\\n')}>{t('form.supersedes')}: {entry.supersedes?.length}</span>\n : null}\n {source !== undefined\n ? <span className=\"memoir-source\">\n {source.sessionId !== undefined\n ? <button type=\"button\" className=\"memoir-source-link\" title={t('source.open')} onClick={() => openSource?.(source.sessionId!, source.turnId)}>\n {t('source.label')}: {source.sessionId.slice(0, 10)}{source.turnId === undefined ? '' : ` \u00B7 ${t('source.turn')} ${source.turnId}`}\n </button>\n : <span>{t('source.turn')} {source.turnId}</span>}\n <button type=\"button\" className=\"memoir-source-copy\" title={t('source.copy')} onClick={copySource}>{copied ? t('source.copied') : '\u29C9'}</button>\n </span>\n : null}\n </div>\n )\n}\n\nfunction EntryCard({ entry, t, onDelete, onUpdate, openSource, score }: { entry: WireEntry; t: (key: string) => string; onDelete: (entry: WireEntry) => void; onUpdate?: (entry: WireEntry, patch: EntryPatch) => void; openSource?: (sessionId: string, turnId?: number) => void; score?: number }) {\n const [editing, setEditing] = useState(false)\n const [contentExpanded, setContentExpanded] = useState(false)\n const [section, setSection] = useState<SectionKey>(entry.section)\n const [title, setTitle] = useState(entry.title ?? '')\n const [content, setContent] = useState(entry.content)\n const [importance, setImportance] = useState(String(entry.importance ?? 3))\n const [tags, setTags] = useState((entry.tags ?? []).join(', '))\n const [supersedes, setSupersedes] = useState((entry.supersedes ?? []).join(', '))\n const save = () => {\n if (content.trim() === '' || onUpdate === undefined) return\n onUpdate(entry, {\n section,\n title: title.trim() === '' ? null : title.trim(),\n content: content.trim(),\n importance: Number(importance),\n tags: parseList(tags),\n supersedes: parseList(supersedes),\n })\n setEditing(false)\n }\n return (\n <div className=\"memoir-entry\" data-dsh-part=\"entry\">\n <button type=\"button\" className=\"memoir-delete\" title={t('delete.confirm')} onClick={() => onDelete(entry)}>\u00D7</button>\n {onUpdate !== undefined\n ? <div className=\"memoir-entry-actions\">\n <button type=\"button\" className=\"memoir-iconbtn\" onClick={() => setEditing((value) => !value)}>{editing ? t('toolbar.cancel') : t('lifecycle.edit')}</button>\n <button type=\"button\" className=\"memoir-iconbtn\" onClick={() => onUpdate(entry, { pinned: entry.pinned !== true })}>{entry.pinned === true ? t('lifecycle.unpin') : t('lifecycle.pin')}</button>\n {(entry.status ?? 'active') === 'active'\n ? <button type=\"button\" className=\"memoir-iconbtn\" onClick={() => onUpdate(entry, { status: 'superseded' })}>{t('lifecycle.supersede')}</button>\n : <button type=\"button\" className=\"memoir-iconbtn\" onClick={() => onUpdate(entry, { status: 'active' })}>{t('lifecycle.unsupersede')}</button>}\n <button type=\"button\" className=\"memoir-iconbtn\" onClick={() => onUpdate(entry, { status: entry.status === 'archived' ? 'active' : 'archived' })}>{entry.status === 'archived' ? t('lifecycle.restore') : t('lifecycle.archive')}</button>\n </div>\n : null}\n <EntryMeta entry={entry} t={t} openSource={openSource} />\n {score !== undefined\n ? <span className=\"memoir-score\" title={t('search.ranked')}>{score.toFixed(3)}</span>\n : null}\n {editing\n ? <div className=\"memoir-form memoir-entry-editor\">\n <div className=\"memoir-field\">\n <label>{t('form.section')}</label>\n <select value={section} onChange={(e) => setSection(e.target.value as SectionKey)}>\n {SECTION_KEYS.map((key) => <option key={key} value={key}>{t('sections.' + key)}</option>)}\n </select>\n </div>\n <div className=\"memoir-field\">\n <label>{t('form.title')}</label>\n <input value={title} onChange={(e) => setTitle(e.target.value)} />\n </div>\n <div className=\"memoir-field\">\n <label>{t('form.content')}</label>\n <textarea value={content} onChange={(e) => setContent(e.target.value)} />\n </div>\n <div className=\"memoir-form-row\">\n <div className=\"memoir-field\">\n <label>{t('form.importance')}</label>\n <select value={importance} onChange={(e) => setImportance(e.target.value)}>\n {[1, 2, 3, 4, 5].map((value) => <option key={value} value={value}>{value}</option>)}\n </select>\n </div>\n <div className=\"memoir-field\">\n <label>{t('form.tags')}</label>\n <input value={tags} placeholder={t('form.placeholder.tags')} onChange={(e) => setTags(e.target.value)} />\n </div>\n </div>\n <div className=\"memoir-field\">\n <label>{t('form.supersedes')}</label>\n <input value={supersedes} placeholder={t('form.placeholder.supersedes')} onChange={(e) => setSupersedes(e.target.value)} />\n </div>\n <div className=\"memoir-form-actions\">\n <button type=\"button\" className=\"memoir-iconbtn\" onClick={() => setEditing(false)}>{t('toolbar.cancel')}</button>\n <button type=\"button\" className=\"memoir-primary\" onClick={save}>{t('lifecycle.save')}</button>\n </div>\n </div>\n : <>\n {entry.title !== undefined ? <div className=\"memoir-entry-title\">{entry.title}</div> : null}\n <div className=\"memoir-entry-content\" data-expanded={contentExpanded ? 'true' : undefined} data-collapsible={shouldCollapseEntry(entry.content) ? 'true' : undefined}>{entry.content}</div>\n {shouldCollapseEntry(entry.content)\n ? <button\n type=\"button\"\n className=\"memoir-content-toggle\"\n aria-expanded={contentExpanded}\n onClick={() => setContentExpanded((value) => !value)}\n >{contentExpanded ? t('entry.collapse') : t('entry.expand')}</button>\n : null}\n </>}\n </div>\n )\n}\n\n/** Sectioned list with a per-section progressive rendering cap. */\nfunction SectionedEntries({ entries, t, onDelete, onUpdate, openSource, resetKey }: { entries: WireEntry[]; t: (key: string) => string; onDelete: (entry: WireEntry) => void; onUpdate?: (entry: WireEntry, patch: EntryPatch) => void; openSource?: (sessionId: string, turnId?: number) => void; resetKey: string }) {\n const [limit, setLimit] = useState(ENTRY_PAGE_SIZE)\n useEffect(() => setLimit(ENTRY_PAGE_SIZE), [resetKey])\n const groups = useMemo(\n () => SECTION_KEYS.map((key) => ({ key, entries: entries.filter((e) => e.section === key) })).filter((g) => g.entries.length > 0),\n [entries],\n )\n if (groups.length === 0) {\n return (\n <div className=\"memoir-empty\">\n <div className=\"memoir-empty-title\">{t('empty.search')}</div>\n </div>\n )\n }\n const visibleCount = groups.reduce((count, group) => count + Math.min(group.entries.length, limit), 0)\n const maxGroupSize = Math.max(...groups.map((group) => group.entries.length))\n const hasMore = visibleCount < entries.length\n return (\n <Fragment>\n {groups.map((group) => (\n <Fragment key={group.key}>\n <div className=\"memoir-section-title\">\n {t('sections.' + group.key)}\n <span className=\"memoir-count\">({group.entries.length})</span>\n </div>\n {group.entries.slice(0, limit).map((entry) => (\n <EntryCard key={entry.id} entry={entry} t={t} onDelete={onDelete} onUpdate={onUpdate} openSource={openSource} />\n ))}\n </Fragment>\n ))}\n {hasMore\n ? <div className=\"memoir-load-more\">\n <span>{t('pagination.showing')} {visibleCount}/{entries.length}</span>\n <button type=\"button\" className=\"memoir-iconbtn\" onClick={() => setLimit((value) => nextPageSize(value, maxGroupSize, ENTRY_PAGE_SIZE))}>{t('pagination.more')}</button>\n </div>\n : null}\n </Fragment>\n )\n}\n\n/**\n * Ranked project search results (v0.4.2): the host RetrievalEngine order.\n * Global ranked results use the same collapsible project shell as browsing.\n */\nfunction RankedResults({ results, pending, t, onDelete, onUpdate, openSource }: {\n results: WireSearchResult[]\n pending: boolean\n t: (key: string) => string\n onDelete: (entry: WireEntry, path: string) => void\n onUpdate?: (entry: WireEntry, path: string, patch: EntryPatch) => void\n openSource?: (sessionId: string, turnId?: number) => void\n}) {\n if (pending) return <div className=\"memoir-empty\">\u2026</div>\n if (results.length === 0) {\n return (\n <div className=\"memoir-empty\">\n <div className=\"memoir-empty-title\">{t('empty.search')}</div>\n <div className=\"memoir-empty-hint\">{t('search.ranked')}</div>\n </div>\n )\n }\n return (\n <Fragment>\n <div className=\"memoir-ranked-note\">{t('search.ranked')}</div>\n {results.map((r) => (\n <EntryCard key={r.entry.id} entry={r.entry} score={r.score} t={t} onDelete={(entry) => onDelete(entry, r.projectPath)} onUpdate={(entry, patch) => onUpdate?.(entry, r.projectPath, patch)} openSource={openSource} />\n ))}\n </Fragment>\n )\n}\n\nfunction ProjectDisclosure({ project, open, t, onToggle, children }: {\n project: { path: string; title: string; updatedAt: number; stats: EntryStats }\n open: boolean\n t: (key: string) => string\n onToggle: () => void\n children: ReactNode\n}) {\n const when = new Date(project.updatedAt)\n const title = project.title || t('project.unscoped')\n const path = project.path || t('project.unscopedHint')\n return (\n <section className=\"memoir-project-card\" data-expanded={open ? 'true' : undefined}>\n <button type=\"button\" className=\"memoir-project-toggle\" aria-expanded={open} onClick={onToggle}>\n <span className=\"memoir-project-chevron\" aria-hidden=\"true\">\u203A</span>\n <span className=\"memoir-project-heading\">\n <span className=\"memoir-project-head\">\n <span className=\"memoir-project-title\">{title}</span>\n <span className=\"memoir-project-path\" title={project.path}>{path}</span>\n </span>\n <span className=\"memoir-project-meta\">\n <span>{t('status.active')}: {project.stats.active}</span>\n <span>{t('status.archived')}: {project.stats.archived}</span>\n <span>{t('status.superseded')}: {project.stats.superseded}</span>\n <span>{t('updated')} {when.toISOString().slice(0, 16).replace('T', ' ')}</span>\n </span>\n </span>\n </button>\n {open ? <div className=\"memoir-project-body\">{children}</div> : null}\n </section>\n )\n}\n\ntype AddPayload = {\n section: SectionKey\n title?: string\n content: string\n importance: number\n pinned: boolean\n tags: string[]\n supersedes: string[]\n}\n\nfunction AddForm({ t, onSubmit, onCancel }: { t: (key: string) => string; onSubmit: (payload: AddPayload) => void; onCancel: () => void }) {\n const [section, setSection] = useState<SectionKey>('lessons')\n const [title, setTitle] = useState('')\n const [content, setContent] = useState('')\n const [importance, setImportance] = useState('3')\n const [pinned, setPinned] = useState(false)\n const [tags, setTags] = useState('')\n const [supersedes, setSupersedes] = useState('')\n const submit = () => {\n if (content.trim() === '') return\n onSubmit({\n section,\n title: title.trim() === '' ? undefined : title.trim(),\n content: content.trim(),\n importance: Number(importance),\n pinned,\n tags: parseList(tags),\n supersedes: parseList(supersedes),\n })\n }\n return (\n <div className=\"memoir-form\" data-dsh-part=\"entry-form\">\n <div className=\"memoir-form-row\">\n <div className=\"memoir-field\">\n <label>{t('form.section')}</label>\n <select value={section} onChange={(e) => setSection(e.target.value as SectionKey)}>\n {SECTION_KEYS.map((key) => (\n <option key={key} value={key}>{t('sections.' + key)}</option>\n ))}\n </select>\n </div>\n <div className=\"memoir-field\">\n <label>{t('form.title')}</label>\n <input value={title} placeholder={t('form.placeholder.title')} onChange={(e) => setTitle(e.target.value)} />\n </div>\n </div>\n <div className=\"memoir-field\">\n <label>{t('form.content')}</label>\n <textarea value={content} placeholder={t('form.placeholder.content')} onChange={(e) => setContent(e.target.value)} />\n </div>\n <div className=\"memoir-form-row\">\n <div className=\"memoir-field\">\n <label>{t('form.importance')}</label>\n <select value={importance} onChange={(e) => setImportance(e.target.value)}>\n {[1, 2, 3, 4, 5].map((value) => <option key={value} value={value}>{value}</option>)}\n </select>\n <small>{t('form.importanceHint')}</small>\n </div>\n <div className=\"memoir-field\">\n <label>{t('form.tags')}</label>\n <input value={tags} placeholder={t('form.placeholder.tags')} onChange={(e) => setTags(e.target.value)} />\n </div>\n </div>\n <div className=\"memoir-field\">\n <label>{t('form.supersedes')}</label>\n <input value={supersedes} placeholder={t('form.placeholder.supersedes')} onChange={(e) => setSupersedes(e.target.value)} />\n </div>\n <label className=\"memoir-settings-switch\">\n <input type=\"checkbox\" checked={pinned} onChange={(e) => setPinned(e.target.checked)} />\n <span><strong>{t('form.pinned')}</strong><small>{t('form.pinnedHint')}</small></span>\n </label>\n <div className=\"memoir-form-actions\">\n <button type=\"button\" className=\"memoir-iconbtn\" onClick={onCancel}>{t('toolbar.cancel')}</button>\n <button type=\"button\" className=\"memoir-primary\" onClick={submit}>{t('form.submit')}</button>\n </div>\n </div>\n )\n}\n\nfunction SimilarityCandidateCard({ candidate, t, busy, onResolve }: {\n candidate: WireSimilarityCandidate\n t: (key: string) => string\n busy: boolean\n onResolve: (resolution: WireRecordResolution, targetId: string) => void\n}) {\n return (\n <div className=\"memoir-similarity-candidate\">\n <div className=\"memoir-similarity-head\">\n <span className={`memoir-chip memoir-similarity-${candidate.kind}`}>{t(`similarity.kind.${candidate.kind}`)}</span>\n <strong>{candidate.entry.title ?? candidate.entry.content.slice(0, 100)}</strong>\n <span className=\"memoir-score-static\">{Math.round(candidate.score * 100)}%</span>\n </div>\n {candidate.entry.title !== undefined ? <div className=\"memoir-similarity-content\">{candidate.entry.content}</div> : null}\n <div className=\"memoir-similarity-components\">\n BM25 {Math.round(candidate.components.bm25 * 100)}% \u00B7 {t('similarity.titleScore')} {Math.round(candidate.components.title * 100)}% \u00B7 Jaccard {Math.round(candidate.components.tokenJaccard * 100)}%\n </div>\n <div className=\"memoir-similarity-reasons\">\n {candidate.reasons.map((reason) => <span className=\"memoir-chip\" key={reason}>{t(`similarity.reason.${reason}`)}</span>)}\n </div>\n <div className=\"memoir-form-actions\">\n <button type=\"button\" className=\"memoir-iconbtn\" disabled={busy} onClick={() => onResolve('update', candidate.entry.id)}>{t('similarity.update')}</button>\n <button type=\"button\" className=\"memoir-primary\" disabled={busy} onClick={() => onResolve('supersede', candidate.entry.id)}>{t('similarity.supersede')}</button>\n </div>\n </div>\n )\n}\n\nfunction SimilarityResolution({ result, t, busy, onResolve, onBack }: {\n result: WireRecordResult\n t: (key: string) => string\n busy: boolean\n onResolve: (resolution: WireRecordResolution, targetId?: string) => void\n onBack: () => void\n}) {\n return (\n <div className=\"memoir-similarity\" data-dsh-part=\"similarity-resolution\">\n <div className=\"memoir-similarity-title\">{t('similarity.title')}</div>\n <div className=\"memoir-settings-description\">{t('similarity.description')}</div>\n {result.candidates.map((candidate) => (\n <SimilarityCandidateCard key={candidate.entry.id} candidate={candidate} t={t} busy={busy} onResolve={onResolve} />\n ))}\n <div className=\"memoir-similarity-footer\">\n <button type=\"button\" className=\"memoir-iconbtn\" disabled={busy} onClick={onBack}>{t('similarity.back')}</button>\n <button type=\"button\" className=\"memoir-iconbtn\" disabled={busy} onClick={() => onResolve('force-record')}>{t('similarity.force')}</button>\n </div>\n </div>\n )\n}\n\ntype NumericSettingsKey =\n | 'autoDistillEvery'\n | 'autoDistillCooldownMin'\n | 'autoDistillMinTools'\n | 'hotMemoryTokens'\n | 'hotMemoryMaxTokens'\n | 'readDefaultLimit'\n | 'readMaxLimit'\n | 'sessionSnapshotMax'\n | 'queryCacheSize'\n\nconst NUMERIC_SETTINGS: NumericSettingsKey[] = [\n 'autoDistillEvery',\n 'autoDistillCooldownMin',\n 'autoDistillMinTools',\n 'hotMemoryTokens',\n 'hotMemoryMaxTokens',\n 'readDefaultLimit',\n 'readMaxLimit',\n 'sessionSnapshotMax',\n 'queryCacheSize',\n]\n\n/** Persistent, live complete settings shared by the panel and Settings page. */\nexport function MemoirSettingsPanel({ api, t, refreshKey, onChanged, defaultOpen = false, alwaysOpen = false, showDescription = true }: {\n api: MemoirApi\n t: (key: string) => string\n refreshKey: number\n onChanged: () => void\n defaultOpen?: boolean\n alwaysOpen?: boolean\n showDescription?: boolean\n}) {\n const [open, setOpen] = useState(defaultOpen)\n const [settings, setSettings] = useState<WireMemoirSettings | null>(null)\n const [source, setSource] = useState<'profile' | 'web'>('profile')\n const [draft, setDraft] = useState<Record<NumericSettingsKey, string>>({\n autoDistillEvery: '1',\n autoDistillCooldownMin: '0',\n autoDistillMinTools: '1',\n hotMemoryTokens: '900',\n hotMemoryMaxTokens: '1200',\n readDefaultLimit: '8',\n readMaxLimit: '30',\n sessionSnapshotMax: '128',\n queryCacheSize: '128',\n })\n const [busy, setBusy] = useState(false)\n const [message, setMessage] = useState<string | null>(null)\n const [error, setError] = useState<string | null>(null)\n\n const applySnapshot = (snapshot: { settings: WireMemoirSettings; source: 'profile' | 'web' }) => {\n setError(null)\n setSettings(snapshot.settings)\n setSource(snapshot.source)\n setDraft(Object.fromEntries(NUMERIC_SETTINGS.map((key) => [key, String(snapshot.settings[key])])) as Record<NumericSettingsKey, string>)\n }\n\n useEffect(() => {\n let cancelled = false\n api.settings()\n .then((value) => { if (!cancelled) applySnapshot(value) })\n .catch((e: Error) => { if (!cancelled) setError(`${t('settings.loadFailed')}: ${e.message}`) })\n return () => { cancelled = true }\n }, [api, refreshKey])\n\n const save = () => {\n if (settings === null) return\n const parsed = Object.fromEntries(NUMERIC_SETTINGS.map((key) => [key, Number(draft[key])])) as Record<NumericSettingsKey, number>\n const integerKeys = NUMERIC_SETTINGS.filter((key) => key !== 'autoDistillCooldownMin')\n const invalidInteger = integerKeys.some((key) => !Number.isSafeInteger(parsed[key]) || parsed[key] < 1)\n if (\n invalidInteger\n || !Number.isFinite(parsed.autoDistillCooldownMin)\n || parsed.autoDistillCooldownMin < 0\n || parsed.hotMemoryMaxTokens < parsed.hotMemoryTokens\n || parsed.readMaxLimit < parsed.readDefaultLimit\n ) {\n setMessage(null)\n setError(t('settings.invalid'))\n return\n }\n setBusy(true)\n setError(null)\n setMessage(null)\n api.updateSettings({\n language: settings.language,\n announceToAgent: settings.announceToAgent,\n autoDistill: settings.autoDistill,\n ...parsed,\n })\n .then((value) => {\n applySnapshot(value)\n setMessage(t('settings.saved'))\n onChanged()\n })\n .catch((e: Error) => setError(`${t('settings.saveFailed')}: ${e.message}`))\n .finally(() => setBusy(false))\n }\n\n const reset = () => {\n setBusy(true)\n setError(null)\n setMessage(null)\n api.resetSettings()\n .then((value) => {\n applySnapshot(value)\n setMessage(t('settings.resetDone'))\n onChanged()\n })\n .catch((e: Error) => setError(`${t('settings.saveFailed')}: ${e.message}`))\n .finally(() => setBusy(false))\n }\n\n return (\n <div className=\"memoir-settings\" data-dsh-part=\"settings\">\n {!alwaysOpen\n ? <button type=\"button\" className=\"memoir-diagnostics-toggle\" aria-expanded={open} onClick={() => setOpen((value) => !value)}>\n {t('settings.title')} {open ? '\u25BE' : '\u25B8'}\n </button>\n : null}\n {alwaysOpen || open\n ? settings === null\n ? <div className=\"memoir-settings-body\">{error ?? '\u2026'}</div>\n : (\n <div className=\"memoir-settings-body\">\n {showDescription ? <div className=\"memoir-settings-description\">{t('settings.description')}</div> : null}\n <div className=\"memoir-settings-grid\">\n <label className=\"memoir-field\">\n <span>{t('settings.language')}</span>\n <select\n value={settings.language}\n onChange={(event) => setSettings({ ...settings, language: resolveMemoirLanguage(event.target.value) })}\n >\n {MEMOIR_LANGUAGES.map(language => <option key={language} value={language}>{t(`settings.language.${language}`)}</option>)}\n </select>\n <small>{t('settings.languageHint')}</small>\n </label>\n </div>\n <label className=\"memoir-settings-switch\">\n <input\n type=\"checkbox\"\n checked={settings.announceToAgent}\n onChange={(event) => setSettings({ ...settings, announceToAgent: event.target.checked })}\n />\n <span><strong>{t('settings.announce')}</strong><small>{t('settings.announceHint')}</small></span>\n </label>\n <div className=\"memoir-settings-group-title\">{t('settings.group.distill')}</div>\n <label className=\"memoir-settings-switch\">\n <input\n type=\"checkbox\"\n checked={settings.autoDistill}\n onChange={(event) => setSettings({ ...settings, autoDistill: event.target.checked })}\n />\n <span><strong>{t('settings.enabled')}</strong><small>{t('settings.enabledHint')}</small></span>\n </label>\n <div className=\"memoir-settings-grid\">\n {(['autoDistillEvery', 'autoDistillCooldownMin', 'autoDistillMinTools'] as NumericSettingsKey[]).map((key) => (\n <label className=\"memoir-field\" key={key}>\n <span>{t(`settings.${key}`)}</span>\n <input\n type=\"number\"\n min={key === 'autoDistillCooldownMin' ? '0' : '1'}\n step={key === 'autoDistillCooldownMin' ? '0.1' : '1'}\n value={draft[key]}\n onChange={(event) => setDraft({ ...draft, [key]: event.target.value })}\n />\n <small>{t(`settings.${key}Hint`)}</small>\n </label>\n ))}\n </div>\n <div className=\"memoir-settings-note\">{t('settings.andHint')}</div>\n <div className=\"memoir-settings-group-title\">{t('settings.group.memory')}</div>\n <div className=\"memoir-settings-grid\">\n {(['hotMemoryTokens', 'hotMemoryMaxTokens', 'readDefaultLimit', 'readMaxLimit', 'sessionSnapshotMax', 'queryCacheSize'] as NumericSettingsKey[]).map((key) => (\n <label className=\"memoir-field\" key={key}>\n <span>{t(`settings.${key}`)}</span>\n <input\n type=\"number\"\n min=\"1\"\n step=\"1\"\n value={draft[key]}\n onChange={(event) => setDraft({ ...draft, [key]: event.target.value })}\n />\n <small>{t(`settings.${key}Hint`)}</small>\n </label>\n ))}\n </div>\n <div className=\"memoir-settings-note\">{t('settings.liveHint')}</div>\n <div className=\"memoir-settings-source\">{t('settings.source')}: {t(`settings.source.${source}`)}</div>\n {error !== null ? <div className=\"memoir-error memoir-settings-feedback\">{error}</div> : null}\n {message !== null ? <div className=\"memoir-settings-success\">{message}</div> : null}\n <div className=\"memoir-form-actions\">\n <button type=\"button\" className=\"memoir-iconbtn\" disabled={busy || source === 'profile'} onClick={reset}>{t('settings.reset')}</button>\n <button type=\"button\" className=\"memoir-primary\" disabled={busy} onClick={save}>{t('settings.save')}</button>\n </div>\n </div>\n )\n : null}\n </div>\n )\n}\n\ntype PanelSurface = 'browse' | 'settings' | 'hot-memory' | 'diagnostics'\n\nconst PANEL_SURFACES: Array<{ id: PanelSurface; label: string }> = [\n { id: 'browse', label: 'surface.browse' },\n { id: 'settings', label: 'surface.settings' },\n { id: 'hot-memory', label: 'surface.hotMemory' },\n { id: 'diagnostics', label: 'surface.diagnostics' },\n]\n\nexport function MemoirPanel({ controller, api, cwdTracker = EMPTY_CWD_TRACKER, cwd: fixedCwd, t, openSource, onClose, announceOnOpen = false }: PanelProps) {\n const [, setLanguage] = useState(document.documentElement.lang)\n useEffect(() => {\n const observer = new MutationObserver(() => setLanguage(document.documentElement.lang))\n observer.observe(document.documentElement, { attributes: true, attributeFilter: ['lang'] })\n return () => observer.disconnect()\n }, [])\n const trackedCwd = useSyncExternalStore(cwdTracker.subscribe, cwdTracker.getSnapshot)\n const cwd = fixedCwd ?? trackedCwd\n const close = onClose ?? (controller === undefined ? undefined : () => controller.close())\n const panelId = useId().replace(/:/g, '')\n const [surface, setSurface] = useState<PanelSurface>('browse')\n const [tab, setTab] = useState<'project' | 'global'>('project')\n const [query, setQuery] = useState('')\n const [statusFilter, setStatusFilter] = useState<MemoirStatus | 'all'>('active')\n const [sectionFilter, setSectionFilter] = useState<SectionKey | 'all'>('all')\n const [formOpen, setFormOpen] = useState(false)\n const [pendingRecord, setPendingRecord] = useState<{ payload: AddPayload; result: WireRecordResult } | null>(null)\n const [refreshKey, setRefreshKey] = useState(0)\n const [project, setProject] = useState<WireProject | null>(null)\n const [projects, setProjects] = useState<WireProject[]>([])\n const [loading, setLoading] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const [busy, setBusy] = useState(false)\n const [diag, setDiag] = useState<WireDiagnostics | null>(null)\n const [searchResults, setSearchResults] = useState<WireSearchResult[] | null>(null)\n const [hotMemory, setHotMemory] = useState<WireHotMemory | null>(null)\n const [expandedProjects, setExpandedProjects] = useState<Record<string, boolean>>({})\n const [projectLimit, setProjectLimit] = useState(PROJECT_PAGE_SIZE)\n\n const q = query.trim().toLowerCase()\n\n useEffect(() => {\n let cancelled = false\n setError(null)\n if (tab === 'project') {\n if (cwd === '') {\n setProject(null)\n return undefined\n }\n setLoading(true)\n api.project(cwd, { status: 'all' })\n .then((value) => { if (!cancelled) setProject(value.project) })\n .catch((e: Error) => { if (!cancelled) setError(e.message) })\n .finally(() => { if (!cancelled) setLoading(false) })\n } else {\n setLoading(true)\n api.global({ status: 'all' })\n .then((value) => { if (!cancelled) setProjects(value.projects) })\n .catch((e: Error) => { if (!cancelled) setError(e.message) })\n .finally(() => { if (!cancelled) setLoading(false) })\n }\n return () => { cancelled = true }\n }, [tab, cwd, refreshKey])\n\n useEffect(() => {\n let cancelled = false\n // Diagnostics and Hot Memory follow the active workspace independently\n // from browse filters so surface switches never trigger redundant reads.\n api.diagnostics(cwd === '' ? undefined : cwd)\n .then((value) => { if (!cancelled) setDiag(value) })\n .catch(() => { if (!cancelled) setDiag(null) })\n // Hot-memory inspector preview (what the next session inherits).\n if (cwd === '') {\n setHotMemory(null)\n } else {\n api.hotMemory(cwd)\n .then((value) => { if (!cancelled) setHotMemory(value.hotMemory) })\n .catch(() => { if (!cancelled) setHotMemory(null) })\n }\n return () => { cancelled = true }\n }, [cwd, refreshKey])\n\n // v0.4.2: a non-empty query searches through the host RetrievalEngine \u2014\n // the same BM25 ranking memoir_read uses. Debounced; empty query resets.\n useEffect(() => {\n if (q === '') {\n setSearchResults(null)\n return undefined\n }\n if (tab === 'project' && cwd === '') {\n setSearchResults([])\n return undefined\n }\n let cancelled = false\n setSearchResults(null)\n const timer = setTimeout(() => {\n const scope = tab === 'project' ? 'project' : 'global'\n api.search({\n scope,\n path: tab === 'project' && cwd !== '' ? cwd : undefined,\n query: q,\n status: statusFilter,\n section: sectionFilter === 'all' ? undefined : sectionFilter,\n })\n .then((value) => { if (!cancelled) setSearchResults(value.results) })\n .catch((e: Error) => {\n if (!cancelled) {\n setSearchResults([])\n setError(e.message)\n }\n })\n }, 200)\n return () => { cancelled = true; clearTimeout(timer) }\n }, [q, tab, cwd, statusFilter, sectionFilter, refreshKey])\n\n const reload = () => setRefreshKey((k) => k + 1)\n\n const onDelete = (entry: WireEntry, entryPath: string) => {\n if (!window.confirm(t('delete.confirm'))) return\n setBusy(true)\n api.remove({ path: entryPath, id: entry.id })\n .then(() => reload())\n .catch((e: Error) => setError(`${t('delete.failed')}: ${e.message}`))\n .finally(() => setBusy(false))\n }\n\n const onRecord = (payload: AddPayload, resolution?: WireRecordResolution, targetId?: string) => {\n setBusy(true)\n api.record({ path: cwd, ...payload, ...(resolution !== undefined ? { resolution } : {}), ...(targetId !== undefined ? { targetId } : {}) })\n .then((result) => {\n if (result.action === 'needs-resolution') {\n setPendingRecord({ payload, result })\n return\n }\n setPendingRecord(null)\n setFormOpen(false)\n reload()\n })\n .catch((e: Error) => setError(`${t('record.failed')}: ${e.message}`))\n .finally(() => setBusy(false))\n }\n\n const onUpdate = (entry: WireEntry, entryPath: string, patch: EntryPatch) => {\n setBusy(true)\n api.update({ path: entryPath, id: entry.id, ...patch })\n .then(() => reload())\n .catch((e: Error) => setError(`${t('update.failed')}: ${e.message}`))\n .finally(() => setBusy(false))\n }\n\n const projectEntries = useMemo(\n () => project === null ? [] : filterEntries(project.entries, statusFilter, sectionFilter),\n [project, statusFilter, sectionFilter],\n )\n const globalGroups = useMemo(\n () => buildProjectGroups(projects, statusFilter, sectionFilter),\n [projects, statusFilter, sectionFilter],\n )\n const rankedGlobalGroups = useMemo(\n () => groupRankedResults(searchResults ?? [], projects),\n [searchResults, projects],\n )\n const displayedGlobalGroups = q === '' ? globalGroups : rankedGlobalGroups\n const projectSignature = displayedGlobalGroups.map((group) => group.key).join('\\n')\n const narrowingSignature = q === '' && statusFilter === 'active' && sectionFilter === 'all'\n ? ''\n : `${q}\\n${statusFilter}\\n${sectionFilter}\\n${projectSignature}`\n\n useEffect(() => {\n setProjectLimit(PROJECT_PAGE_SIZE)\n }, [tab, q, statusFilter, sectionFilter, refreshKey])\n\n useEffect(() => {\n if (tab !== 'global' || narrowingSignature === '') return\n setExpandedProjects((current) => {\n const next = { ...current }\n for (const group of displayedGlobalGroups) next[group.key] = true\n return next\n })\n }, [tab, narrowingSignature])\n\n const setAllProjects = (open: boolean) => {\n setExpandedProjects((current) => {\n const next = { ...current }\n for (const group of displayedGlobalGroups) next[group.key] = open\n return next\n })\n }\n\n const onSurfaceKeyDown = (event: ReactKeyboardEvent<HTMLButtonElement>, index: number) => {\n let nextIndex: number | undefined\n if (event.key === 'ArrowRight') nextIndex = (index + 1) % PANEL_SURFACES.length\n if (event.key === 'ArrowLeft') nextIndex = (index - 1 + PANEL_SURFACES.length) % PANEL_SURFACES.length\n if (event.key === 'Home') nextIndex = 0\n if (event.key === 'End') nextIndex = PANEL_SURFACES.length - 1\n if (nextIndex === undefined) return\n event.preventDefault()\n const next = PANEL_SURFACES[nextIndex]\n setSurface(next.id)\n document.getElementById(`${panelId}-${next.id}-tab`)?.focus()\n }\n\n const headerSubtitle = surface === 'browse'\n ? (tab === 'project' ? (cwd === '' ? t('empty.workspace') : cwd) : t('tab.global'))\n : t(PANEL_SURFACES.find((item) => item.id === surface)?.label ?? 'surface.browse')\n const visibleGlobalGroups = displayedGlobalGroups.slice(0, projectLimit)\n const listResetKey = `${tab}:${q}:${statusFilter}:${sectionFilter}:${refreshKey}`\n\n return (\n <div className=\"memoir-panel\" data-dsh-plugin=\"memoir\" data-dsh-part=\"panel\">\n <div className=\"memoir-header\" data-dsh-part=\"header\">\n <div className=\"memoir-title\">\n {t('panel.title')}\n <div className=\"memoir-subtitle\">{headerSubtitle}</div>\n </div>\n <button type=\"button\" className=\"memoir-iconbtn\" title={t('panel.refresh')} onClick={reload}>\u27F3</button>\n {close === undefined\n ? null\n : <button type=\"button\" className=\"memoir-iconbtn\" title={t('panel.close')} onClick={close}>\u00D7</button>}\n </div>\n <MemoirAbout t={t} announceOnOpen={announceOnOpen} settingsTarget={`${panelId}-settings-panel`} onSettings={() => {\n setSurface('settings')\n document.getElementById(`${panelId}-settings-tab`)?.focus()\n }} />\n <nav className=\"memoir-surface-tabs\" data-dsh-part=\"surface-tabs\" role=\"tablist\" aria-label={t('surface.navigation')}>\n {PANEL_SURFACES.map((item, index) => (\n <button\n type=\"button\"\n id={`${panelId}-${item.id}-tab`}\n className=\"memoir-surface-tab\"\n role=\"tab\"\n aria-selected={surface === item.id}\n aria-controls={`${panelId}-${item.id}-panel`}\n tabIndex={surface === item.id ? 0 : -1}\n data-active={surface === item.id ? 'true' : undefined}\n onClick={() => setSurface(item.id)}\n onKeyDown={(event) => onSurfaceKeyDown(event, index)}\n key={item.id}\n >{t(item.label)}</button>\n ))}\n </nav>\n <div className=\"memoir-surface-stack\">\n <section\n id={`${panelId}-browse-panel`}\n className=\"memoir-surface memoir-browse-surface\"\n role=\"tabpanel\"\n aria-labelledby={`${panelId}-browse-tab`}\n hidden={surface !== 'browse'}\n >\n <div className=\"memoir-browse-head\">\n <div className=\"memoir-tabs\" data-dsh-part=\"tabs\" role=\"tablist\" aria-label={t('browse.scope')}>\n <button type=\"button\" className=\"memoir-tab\" role=\"tab\" aria-selected={tab === 'project'} data-active={tab === 'project' ? 'true' : undefined} onClick={() => setTab('project')}>{t('tab.project')}</button>\n <button type=\"button\" className=\"memoir-tab\" role=\"tab\" aria-selected={tab === 'global'} data-active={tab === 'global' ? 'true' : undefined} onClick={() => setTab('global')}>{t('tab.global')}</button>\n </div>\n <div className=\"memoir-toolbar\" data-dsh-part=\"toolbar\">\n <input className=\"memoir-search\" aria-label={t('toolbar.search')} placeholder={t('toolbar.search')} value={query} onChange={(e) => setQuery(e.target.value)} />\n <label className=\"memoir-status-filter\">\n <span>{t('filter.status')}</span>\n <select value={statusFilter} onChange={(e) => setStatusFilter(e.target.value as MemoirStatus | 'all')}>\n <option value=\"active\">{t('status.active')}</option>\n <option value=\"all\">{t('filter.all')}</option>\n <option value=\"superseded\">{t('status.superseded')}</option>\n <option value=\"archived\">{t('status.archived')}</option>\n </select>\n </label>\n <label className=\"memoir-status-filter\">\n <span>{t('filter.section')}</span>\n <select value={sectionFilter} onChange={(e) => setSectionFilter(e.target.value as SectionKey | 'all')}>\n <option value=\"all\">{t('filter.all')}</option>\n {SECTION_KEYS.map((key) => <option key={key} value={key}>{t('sections.' + key)}</option>)}\n </select>\n </label>\n {tab === 'project' && cwd !== ''\n ? <button type=\"button\" className=\"memoir-primary\" onClick={() => {\n setFormOpen((value) => !value)\n setPendingRecord(null)\n }}>{formOpen ? t('toolbar.cancel') : t('toolbar.add')}</button>\n : null}\n {tab === 'global' && displayedGlobalGroups.length > 0\n ? <div className=\"memoir-project-actions\">\n <button type=\"button\" className=\"memoir-iconbtn\" onClick={() => setAllProjects(true)}>{t('project.expandAll')}</button>\n <button type=\"button\" className=\"memoir-iconbtn\" onClick={() => setAllProjects(false)}>{t('project.collapseAll')}</button>\n </div>\n : null}\n </div>\n {error !== null ? <div className=\"memoir-error\" role=\"alert\">{error}</div> : null}\n </div>\n <div className=\"memoir-surface-scroll memoir-scroll-region\" data-dsh-part=\"browse-scroll\" tabIndex={0} aria-label={t('surface.browse')}>\n {formOpen && tab === 'project' && cwd !== ''\n ? pendingRecord === null\n ? <AddForm t={t} onSubmit={onRecord} onCancel={() => setFormOpen(false)} />\n : <SimilarityResolution\n result={pendingRecord.result}\n t={t}\n busy={busy}\n onResolve={(resolution, targetId) => onRecord(pendingRecord.payload, resolution, targetId)}\n onBack={() => setPendingRecord(null)}\n />\n : null}\n <div className=\"memoir-body\" aria-busy={loading || busy}>\n {loading\n ? <div className=\"memoir-empty\">\u2026</div>\n : tab === 'project'\n ? q !== ''\n ? <RankedResults results={searchResults ?? []} pending={searchResults === null} t={t} openSource={openSource} onDelete={onDelete} onUpdate={onUpdate} />\n : cwd === ''\n ? <div className=\"memoir-empty\"><div className=\"memoir-empty-title\">{t('empty.workspace')}</div><div className=\"memoir-empty-hint\">{t('empty.workspaceHint')}</div></div>\n : projectEntries.length === 0\n ? <div className=\"memoir-empty\"><div className=\"memoir-empty-title\">{t('empty.project')}</div><div className=\"memoir-empty-hint\">{t('empty.projectHint')}</div></div>\n : <SectionedEntries resetKey={listResetKey} entries={projectEntries} t={t} openSource={openSource} onDelete={(entry) => onDelete(entry, project?.path ?? cwd)} onUpdate={(entry, patch) => onUpdate(entry, project?.path ?? cwd, patch)} />\n : q !== '' && searchResults === null\n ? <div className=\"memoir-empty\">\u2026</div>\n : displayedGlobalGroups.length === 0\n ? <div className=\"memoir-empty\"><div className=\"memoir-empty-title\">{projects.length === 0 && q === '' ? t('empty.global') : t('empty.search')}</div><div className=\"memoir-empty-hint\">{projects.length === 0 && q === '' ? t('empty.globalHint') : t('search.ranked')}</div></div>\n : <>\n {visibleGlobalGroups.map((group) => {\n const open = expandedProjects[group.key] === true\n return (\n <ProjectDisclosure\n project={group}\n open={open}\n t={t}\n onToggle={() => setExpandedProjects((current) => ({ ...current, [group.key]: !open }))}\n key={group.key}\n >\n {'results' in group\n ? <>\n <div className=\"memoir-ranked-note\">{t('search.ranked')}</div>\n {group.results.map((result) => <EntryCard key={result.entry.id} entry={result.entry} score={result.score} t={t} openSource={openSource} onDelete={(entry) => onDelete(entry, group.path)} onUpdate={(entry, patch) => onUpdate(entry, group.path, patch)} />)}\n </>\n : <SectionedEntries resetKey={`${listResetKey}:${group.key}`} entries={group.entries} t={t} openSource={openSource} onDelete={(entry) => onDelete(entry, group.path)} onUpdate={(entry, patch) => onUpdate(entry, group.path, patch)} />}\n </ProjectDisclosure>\n )\n })}\n {projectLimit < displayedGlobalGroups.length\n ? <div className=\"memoir-load-more\"><span>{t('pagination.projects')} {visibleGlobalGroups.length}/{displayedGlobalGroups.length}</span><button type=\"button\" className=\"memoir-iconbtn\" onClick={() => setProjectLimit((value) => nextPageSize(value, displayedGlobalGroups.length, PROJECT_PAGE_SIZE))}>{t('pagination.more')}</button></div>\n : null}\n </>}\n </div>\n {busy ? <div className=\"memoir-empty memoir-busy\" aria-live=\"polite\">\u2026</div> : null}\n </div>\n </section>\n\n <section id={`${panelId}-settings-panel`} className=\"memoir-surface\" role=\"tabpanel\" aria-labelledby={`${panelId}-settings-tab`} hidden={surface !== 'settings'}>\n <div className=\"memoir-surface-scroll\" data-dsh-part=\"settings-scroll\" tabIndex={0} aria-label={t('surface.settings')}>\n <MemoirSettingsPanel api={api} t={t} refreshKey={refreshKey} onChanged={reload} alwaysOpen />\n </div>\n </section>\n\n <section id={`${panelId}-hot-memory-panel`} className=\"memoir-surface\" role=\"tabpanel\" aria-labelledby={`${panelId}-hot-memory-tab`} hidden={surface !== 'hot-memory'}>\n <div className=\"memoir-surface-scroll\" data-dsh-part=\"hot-memory-scroll\" tabIndex={0} aria-label={t('surface.hotMemory')}>\n <div className=\"memoir-surface-card\" data-dsh-part=\"hot-memory\">\n <h3>{t('inspector.title')}</h3>\n {hotMemory === null || hotMemory.text === ''\n ? <div className=\"memoir-empty\"><div className=\"memoir-empty-title\">{t('inspector.empty')}</div></div>\n : <>\n <div className=\"memoir-surface-summary\">{t('inspector.selected')}: {hotMemory.selected.length}/{hotMemory.total} \u00B7 ~{hotMemory.estimatedTokens} tokens</div>\n <pre className=\"memoir-inspector-body\">{hotMemory.text}</pre>\n </>}\n </div>\n </div>\n </section>\n\n <section id={`${panelId}-diagnostics-panel`} className=\"memoir-surface\" role=\"tabpanel\" aria-labelledby={`${panelId}-diagnostics-tab`} hidden={surface !== 'diagnostics'}>\n <div className=\"memoir-surface-scroll\" data-dsh-part=\"diagnostics-scroll\" tabIndex={0} aria-label={t('surface.diagnostics')}>\n <div className=\"memoir-surface-card\" data-dsh-part=\"diagnostics\">\n <h3>{t('diag.title')}</h3>\n {diag === null\n ? <div className=\"memoir-empty\">{t('diag.unavailable')}</div>\n : <div className=\"memoir-diagnostics-body\">\n {diag.autoDistill ? <div>\n <h4>{t('distill.title')}</h4>\n <div>{t('distill.worked')}: {diag.autoDistill.workedTurns} \u00B7 {t('distill.agents')}: {diag.autoDistill.agents}/1024</div>\n <div>{t('distill.note')}</div>\n {Object.entries(diag.autoDistill.counts).map(([reason, count]) => <div key={reason}>{t(`distill.${reason}`)}: {count}</div>)}\n {diag.autoDistill.writes ? <div data-dsh-part=\"write-outcomes\">\n <h4>{t('writes.title')}</h4>\n {Object.entries(diag.autoDistill.writes).map(([reason, count]) => <div key={reason}>{t(`writes.${reason}`)}: {count}</div>)}\n <div>{t('writes.note')}</div>\n </div> : null}\n {diag.autoDistill.last ? <div>{t('distill.last')}: {t(`distill.${diag.autoDistill.last.outcome}`)} \u00B7 {new Date(diag.autoDistill.last.at).toLocaleString()} \u00B7 turn {diag.autoDistill.last.turn}</div> : null}\n </div> : null}\n <div>{t('diag.revision')}: {diag.storeRevision} \u00B7 {t('diag.snapshot')}: {diag.snapshotCount}/{diag.snapshotMax}</div>\n {diag.snapshotPersistence ? <div data-dsh-part=\"snapshot-persistence\">\n <h4>{t('snapshot.disk')}</h4>\n <div>{t('snapshot.restored')}: {diag.snapshotPersistence.restored} \u00B7 {t('snapshot.created')}: {diag.snapshotPersistence.created} \u00B7 {t('snapshot.failures')}: {diag.snapshotPersistence.failures}</div>\n <div>{t('snapshot.last')}: {t(`snapshot.${diag.snapshotPersistence.lastStatus}`)}</div>\n {diag.snapshotPersistence.lastError ? <div role=\"status\">{t('snapshot.degraded')} ({t(`snapshot.${diag.snapshotPersistence.lastError}`)})</div> : null}\n <div>{t('snapshot.retention')}</div>\n </div> : null}\n <div>{t('diag.cache')}: {diag.cache.hits}/{diag.cache.loads} {t('diag.hits')} ({Math.round(diag.cache.hitRate * 100)}%) \u00B7 {t('diag.render')}: {Math.round(diag.cache.renderHitRate * 100)}%</div>\n {diag.hotMemory !== null ? <div>{t('diag.hot')}: {diag.hotMemory.selected}/{diag.hotMemory.total} {t('diag.items')} \u00B7 ~{diag.hotMemory.estimatedTokens} tokens \u00B7 {t('diag.budget')} {diag.config.hotMemoryTokens}/{diag.config.hotMemoryMaxTokens}</div> : null}\n <div>{t('diag.retrieval')}: {diag.retrieval.index === null ? '\u2014' : `${diag.retrieval.index.docs} ${t('diag.documents')} \u00B7 ${diag.retrieval.index.terms} ${t('diag.terms')} \u00B7 ${t('diag.epoch')} ${diag.retrieval.index.epoch}`}</div>\n <div>{t('diag.qcache')}: {diag.retrieval.cache.hits} {t('diag.hits')} / {diag.retrieval.cache.misses} {t('diag.misses')} ({Math.round(diag.retrieval.cache.hitRate * 100)}%) \u00B7 {diag.retrieval.cache.size}/{diag.retrieval.cache.capacity} \u00B7 {diag.retrieval.cache.evictions} {t('diag.evicted')}</div>\n {diag.retrieval.lastQuery !== null ? <div>{t('diag.lastQuery')}: {diag.retrieval.lastQuery.latencyMs.toFixed(1)} ms \u00B7 {diag.retrieval.lastQuery.returned}/{diag.retrieval.lastQuery.candidates} {t('diag.returned')}</div> : null}\n {diag.snapshot !== null ? <div>{t('diag.snapshotInfo')}: {diag.snapshot.hash} \u00B7 {t('diag.revision')} {diag.snapshot.storeRevision}</div> : null}\n </div>}\n </div>\n </div>\n </section>\n </div>\n </div>\n )\n}\n", "import { useState, useSyncExternalStore } from 'react'\nimport { ANNOUNCEMENT_VERSION, acknowledgeAnnouncement, hasAcknowledged, subscribeAnnouncement } from './announcement.js'\n\n/** Build-stamped, offline plugin identity. Never inspect workspace Git remotes. */\ndeclare const __MEMOIR_PACKAGE_INFO__: { version: string; hostRange: string; sdkBaseline: string }\nconst repository = 'https://github.com/Qinling-Melon-Farmers/dsh-memoir'\n\nexport function MemoirAbout({ t, onSettings, settingsTarget, announceOnOpen = false }: {\n t: (key: string) => string\n onSettings?: () => void\n settingsTarget?: string\n announceOnOpen?: boolean\n}) {\n const [manualNotice, setManualNotice] = useState(false)\n const seen = useSyncExternalStore(\n notify => subscribeAnnouncement(window, notify),\n () => hasAcknowledged(window),\n () => true,\n )\n const showNotice = manualNotice || (announceOnOpen && !seen)\n return <aside className=\"memoir-plugin-guide\" data-dsh-part=\"plugin-guide\" aria-label={t('guide.label')}>\n <div className=\"memoir-plugin-guide-row\">\n <strong className=\"memoir-plugin-identity\">dsh-memoir <span>v{__MEMOIR_PACKAGE_INFO__.version}</span></strong>\n <nav className=\"memoir-about-links\" aria-label={t('about.links')}>\n <a href={repository} title={t('about.repositoryNote')} target=\"_blank\" rel=\"noopener noreferrer\" referrerPolicy=\"no-referrer\">{t('guide.repository')}</a>\n <a href={`${repository}/blob/main/${t('about.readmeFile')}`} target=\"_blank\" rel=\"noopener noreferrer\" referrerPolicy=\"no-referrer\">{t('about.docs')}</a>\n {onSettings === undefined ? null : <button type=\"button\" className=\"memoir-guide-settings\" aria-controls={settingsTarget} onClick={onSettings}>{t('guide.settings')}</button>}\n </nav>\n </div>\n <details className=\"memoir-about\" data-dsh-part=\"about\">\n <summary>{t('about.title')}</summary>\n <div className=\"memoir-about-body\">\n <p>{t('sidebar.description')}</p>\n <dl>\n <dt>{t('about.host')}</dt><dd>{__MEMOIR_PACKAGE_INFO__.hostRange}</dd>\n <dt>{t('about.baseline')}</dt><dd>{__MEMOIR_PACKAGE_INFO__.sdkBaseline}</dd>\n <dt>{t('about.maintainer')}</dt><dd>Qinling-Melon-Farmers</dd>\n </dl>\n <p>{t('about.repositoryNote')}</p>\n <nav className=\"memoir-about-links\" aria-label={t('about.links')}>\n <a href={repository} target=\"_blank\" rel=\"noopener noreferrer\" referrerPolicy=\"no-referrer\">Qinling-Melon-Farmers/dsh-memoir</a>\n <a href={`${repository}/releases`} target=\"_blank\" rel=\"noopener noreferrer\" referrerPolicy=\"no-referrer\">{t('about.releases')}</a>\n <a href={`${repository}/issues`} target=\"_blank\" rel=\"noopener noreferrer\" referrerPolicy=\"no-referrer\">{t('about.issues')}</a>\n </nav>\n <p className=\"memoir-about-note\">{t('about.updates')}</p>\n <button type=\"button\" className=\"memoir-guide-settings\" onClick={() => setManualNotice(true)}>{t('notice.reopen')}</button>\n </div>\n </details>\n {showNotice ? <section className=\"memoir-announcement\" data-dsh-part=\"announcement\" aria-label={t('notice.title')}>\n <div className=\"memoir-plugin-guide-row\">\n <strong>{t('notice.title')} \u00B7 {ANNOUNCEMENT_VERSION}</strong>\n <button type=\"button\" className=\"memoir-guide-settings\" onClick={() => { acknowledgeAnnouncement(window); setManualNotice(false) }}>{t('notice.dismiss')}</button>\n </div>\n <p>{t('notice.compat')}</p>\n <p>{t('notice.features')}</p>\n <small>{t('notice.privacy')}</small>\n </section> : null}\n </aside>\n}\n", "/** Offline release notice state. This key stores no workspace or memory data. */\nexport const ANNOUNCEMENT_VERSION = '0.9.3'\nexport const ANNOUNCEMENT_KEY = 'dsh-memoir:announcement:last-acknowledged'\nconst EVENT = 'dsh-memoir:announcement-acknowledged'\nconst acknowledged = new WeakMap<Window, string>()\n\nexport function hasAcknowledged(target: Window, version = ANNOUNCEMENT_VERSION): boolean {\n if (acknowledged.get(target) === version) return true\n try { return target.localStorage.getItem(ANNOUNCEMENT_KEY) === version } catch { return false }\n}\n\nexport function acknowledgeAnnouncement(target: Window, version = ANNOUNCEMENT_VERSION): void {\n acknowledged.set(target, version)\n try { target.localStorage.setItem(ANNOUNCEMENT_KEY, version) } catch { /* Page-only fallback. */ }\n const event = target.document.createEvent('Event')\n event.initEvent(EVENT, false, false)\n target.dispatchEvent(event)\n}\n\nexport function subscribeAnnouncement(target: Window, notify: () => void): () => void {\n const storage = (event: StorageEvent) => {\n if (event.key !== ANNOUNCEMENT_KEY && event.key !== null) return\n acknowledged.delete(target)\n notify()\n }\n target.addEventListener(EVENT, notify)\n target.addEventListener('storage', storage)\n return () => {\n target.removeEventListener(EVENT, notify)\n target.removeEventListener('storage', storage)\n }\n}\n", "/** Shared language identifiers only; safe to bundle into the browser. */\nexport const MEMOIR_LANGUAGES = ['zh', 'en', 'de', 'ru'] as const\nexport type MemoirLanguage = typeof MEMOIR_LANGUAGES[number]\nexport const DEFAULT_MEMOIR_LANGUAGE: MemoirLanguage = 'zh'\n\nexport function isMemoirLanguage(value: unknown): value is MemoirLanguage {\n return typeof value === 'string' && MEMOIR_LANGUAGES.some(language => language === value)\n}\n\nexport function resolveMemoirLanguage(value: unknown, fallback: MemoirLanguage = DEFAULT_MEMOIR_LANGUAGE): MemoirLanguage {\n return isMemoirLanguage(value) ? value : fallback\n}\n", "import type { WireEntry, WireProject, WireSearchResult } from './api.js'\nimport type { MemoirStatus, SectionKey } from './types.js'\n\nexport const ENTRY_PAGE_SIZE = 20\nexport const PROJECT_PAGE_SIZE = 20\nexport const ENTRY_PREVIEW_CHAR_LIMIT = 360\nexport const ENTRY_PREVIEW_LINE_LIMIT = 6\n\nexport interface EntryStats {\n total: number\n active: number\n superseded: number\n archived: number\n}\n\nexport interface ProjectGroup {\n key: string\n path: string\n title: string\n updatedAt: number\n entries: WireEntry[]\n stats: EntryStats\n}\n\nexport interface RankedProjectGroup extends Omit<ProjectGroup, 'entries'> {\n results: WireSearchResult[]\n}\n\nexport function entryStatus(entry: WireEntry): MemoirStatus {\n return entry.status ?? 'active'\n}\n\nexport function countEntryStatuses(entries: WireEntry[]): EntryStats {\n const stats: EntryStats = { total: entries.length, active: 0, superseded: 0, archived: 0 }\n for (const entry of entries) stats[entryStatus(entry)] += 1\n return stats\n}\n\nexport function filterEntries(\n entries: WireEntry[],\n status: MemoirStatus | 'all',\n section: SectionKey | 'all',\n): WireEntry[] {\n return entries.filter((entry) =>\n (status === 'all' || entryStatus(entry) === status)\n && (section === 'all' || entry.section === section))\n}\n\n/** Match the host's Windows case-insensitive identity without folding POSIX paths. */\nexport function canonicalProjectPath(path: string): string {\n const normalized = path.trim().replace(/\\\\/g, '/').replace(/\\/{2,}/g, '/').replace(/\\/$/, '')\n if (normalized === '') return '__unscoped__'\n return /^[A-Za-z]:\\//.test(normalized) ? normalized.toLowerCase() : normalized\n}\n\nexport function projectTitleFromPath(path: string): string {\n if (path.trim() === '') return ''\n const parts = path.replace(/\\\\/g, '/').split('/').filter(Boolean)\n return parts.at(-1) ?? path\n}\n\nfunction projectStats(project: WireProject): EntryStats {\n return project.stats ?? countEntryStatuses(project.entries)\n}\n\nexport function buildProjectGroups(\n projects: WireProject[],\n status: MemoirStatus | 'all',\n section: SectionKey | 'all',\n): ProjectGroup[] {\n return projects\n .map((project) => ({\n key: project.key || canonicalProjectPath(project.path),\n path: project.path,\n title: project.title || projectTitleFromPath(project.path),\n updatedAt: project.updatedAt,\n entries: filterEntries(project.entries, status, section),\n stats: projectStats(project),\n }))\n .filter((project) => project.entries.length > 0)\n}\n\nexport function groupRankedResults(\n results: WireSearchResult[],\n projects: WireProject[],\n): RankedProjectGroup[] {\n const metadata = new Map(projects.map((project) => [canonicalProjectPath(project.path), project]))\n const groups = new Map<string, RankedProjectGroup>()\n for (const result of results) {\n const canonicalPath = canonicalProjectPath(result.projectPath)\n const project = metadata.get(canonicalPath)\n const existing = groups.get(canonicalPath)\n if (existing !== undefined) {\n existing.results.push(result)\n continue\n }\n groups.set(canonicalPath, {\n key: project?.key || canonicalPath,\n path: project?.path ?? result.projectPath,\n title: project?.title || projectTitleFromPath(result.projectPath),\n updatedAt: project?.updatedAt ?? result.entry.time,\n stats: project === undefined ? countEntryStatuses([result.entry]) : projectStats(project),\n results: [result],\n })\n }\n return [...groups.values()]\n}\n\nexport function shouldCollapseEntry(content: string): boolean {\n return content.length > ENTRY_PREVIEW_CHAR_LIMIT\n || content.split(/\\r?\\n/).length > ENTRY_PREVIEW_LINE_LIMIT\n}\n\nexport function nextPageSize(current: number, total: number, pageSize: number): number {\n return Math.min(total, current + pageSize)\n}\n", "/** Stable marker for the stylesheet owned by this client plugin. */\nexport const PANEL_STYLE_SELECTOR = 'style[data-dsh-memoir-style]'\n\n/**\n * Mount the panel stylesheet without confusing another plugin-owned style tag\n * carrying the same generic data-plugin value for this stylesheet.\n * @param target - document that owns the DSH web shell.\n * @returns disposer that removes only the stylesheet created by this call.\n */\nexport function mountPanelStyles(target: Document = document): () => void {\n if (target.querySelector(PANEL_STYLE_SELECTOR) !== null) return () => {}\n const tag = target.createElement('style')\n tag.dataset.plugin = 'dsh-memoir'\n tag.dataset.dshMemoirStyle = ''\n tag.textContent = PANEL_CSS\n target.head.appendChild(tag)\n return () => tag.remove()\n}\n\n/**\n * Panel stylesheet (plain string, injected as <style data-plugin=\"dsh-memoir\">).\n * Class names are literal memoir-* prefixes (no CSS-module hashing) so the\n * plain-DOM sidebar entry and the React panel share them.\n *\n * The visual language rides the dsh-web-ui family tokens (--dsw-alias-* /\n * --dsw-specific-* / --dsw-font-family). Every token carries a stack fallback\n * (--bg-panel / --text-primary / ...) so the panel still works in a shell\n * without the web-ui-all plugin, while matching dsh-ssh / dsh-task-board /\n * dsh-skill-explorer wherever those tokens exist (light, dark and skins).\n */\n\nexport const PANEL_CSS = `\n/* --- Native Web / Desktop slot surfaces ---------------------------------- */\n\n.memoir-native-view,\n.memoir-settings-section {\n display: flex;\n flex-direction: column;\n box-sizing: border-box;\n width: 100%;\n height: 100%;\n min-width: 0;\n min-height: 0;\n overflow: hidden;\n background: var(--dsw-alias-bg-base, var(--bg-panel, #ffffff));\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n font-family: var(--dsw-font-family, inherit);\n}\n\n.memoir-settings-section {\n /* Settings already owns a raised surface: do not repaint the chat base. */\n background: transparent;\n}\n\n.memoir-sidebar-title {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n min-width: 0;\n}\n.memoir-sidebar-title svg { flex: 0 0 auto; }\n.memoir-sidebar-view { container-type: inline-size; }\n.memoir-sidebar-view .memoir-panel { padding: 12px; }\n.memoir-sidebar-view .memoir-surface-tabs { flex-wrap: wrap; }\n.memoir-sidebar-view .memoir-entry-actions { flex-wrap: wrap; }\n.memoir-plugin-guide {\n flex: 0 0 auto;\n min-width: 0;\n padding: 8px 10px;\n border: 1px solid var(--dsw-alias-border-l1, var(--border, rgba(128, 128, 128, .22)));\n border-radius: 10px;\n background: var(--dsw-alias-bg-layer-2, var(--bg-card, transparent));\n color: var(--dsw-alias-label-primary, var(--text-primary, inherit));\n font-size: 12px;\n}\n.memoir-plugin-guide-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 6px 12px; }\n.memoir-plugin-identity { overflow-wrap: anywhere; }\n.memoir-plugin-identity span { font-weight: 400; color: var(--dsw-alias-label-secondary, var(--text-secondary, #8a8f9c)); }\n.memoir-about { margin-top: 4px; }\n.memoir-announcement { margin-top: 6px; padding: 10px; border-top: 1px solid var(--dsw-alias-border-l1, rgba(128,128,128,.22)); max-height: min(180px, 24dvh); overflow-y: auto; overscroll-behavior: contain; line-height: 1.5; }\n.memoir-announcement p { margin: 6px 0; }\n.memoir-announcement small { color: var(--dsw-alias-label-secondary, var(--text-secondary, #666)); }\n.memoir-about summary { cursor: pointer; font-weight: 600; padding: 4px; }\n.memoir-about summary:focus-visible,\n.memoir-plugin-guide a:focus-visible,\n.memoir-guide-settings:focus-visible { outline: 2px solid var(--accent, #5284e7); outline-offset: 3px; }\n.memoir-about-body { display: grid; gap: 12px; padding: 10px 4px 4px; max-height: min(200px, 25dvh); overflow-y: auto; overscroll-behavior: contain; font-weight: 400; line-height: 1.65; overflow-wrap: anywhere; }\n.memoir-about-body p { margin: 0; }\n.memoir-about-body dl { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); gap: 6px 12px; margin: 0; }\n.memoir-about-body dd { margin: 0; }\n.memoir-about-links { display: flex; flex-wrap: wrap; gap: 8px 16px; }\n.memoir-about-links a,\n.memoir-guide-settings { color: var(--dsw-alias-interactive-primary, var(--accent, #5284e7)); text-decoration: underline; text-underline-offset: 3px; }\n.memoir-guide-settings { border: 0; background: transparent; padding: 0; font: inherit; cursor: pointer; }\n.memoir-about-note { color: var(--dsw-alias-label-secondary, var(--text-secondary, #666)); font-size: 12px; }\n.memoir-plugin-settings { display: grid; gap: 12px; min-width: 0; color: var(--dsw-alias-label-primary, var(--text-primary, inherit)); font-family: var(--dsw-font-family, inherit); }\n.memoir-plugin-settings .memoir-settings { margin: 0; }\n@container (max-width: 420px) {\n .memoir-sidebar-view .memoir-panel { padding: 8px; }\n .memoir-sidebar-view .memoir-entry { padding: 12px; }\n .memoir-about-body dl { grid-template-columns: minmax(0, 1fr); }\n}\n\n/* --- center-column takeover (mirrors dsh-ssh / dsh-task-board) --------------- */\n\n[data-pane='conversation'],\n[class*='centerCol'] {\n position: relative;\n}\n\n[data-dsh-memoir-view] {\n display: none;\n position: absolute;\n inset: 0;\n z-index: 60;\n background: var(--dsw-alias-bg-base, var(--bg-panel, #ffffff));\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n font-family: var(--dsw-font-family, inherit);\n}\n\n/* The center column is single-occupant; the :not() guards keep the sibling\n panels (task board / ssh) from fighting over visibility. */\nhtml[data-dsh-memoir-active]:not([data-dsh-ssh-active]):not([data-dsh-taskboard-active]) [data-dsh-memoir-view] {\n display: flex;\n flex-direction: column;\n}\nhtml[data-dsh-memoir-active]:not([data-dsh-ssh-active]):not([data-dsh-taskboard-active]) [data-pane='conversation'] > :not([data-dsh-memoir-view]),\nhtml[data-dsh-memoir-active]:not([data-dsh-ssh-active]):not([data-dsh-taskboard-active]) [class*='centerCol'] > :not([data-dsh-memoir-view]) {\n display: none !important;\n}\n\n/* --- panel frame: same shell as dsh-ssh .panel / dsh-task-board .board ------ */\n\n.memoir-panel {\n display: flex;\n flex-direction: column;\n box-sizing: border-box;\n height: 100%;\n min-width: 0;\n min-height: 0;\n padding: 14px 16px 16px;\n gap: 10px;\n background: var(--dsw-alias-bg-base, var(--bg-panel, #ffffff));\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n font-family: var(--dsw-font-family, inherit);\n overflow: hidden;\n}\n\n.memoir-settings-section .memoir-panel {\n padding: 12px 16px 16px;\n background: transparent;\n}\n.memoir-panel *,\n.memoir-panel *::before,\n.memoir-panel *::after {\n box-sizing: border-box;\n}\n\n.memoir-header {\n display: flex;\n align-items: center;\n gap: 10px;\n flex: none;\n padding: 0;\n}\n.memoir-title {\n flex: 1;\n min-width: 0;\n font-size: 16px;\n font-weight: 700;\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n line-height: 1.25;\n}\n.memoir-subtitle {\n font-size: 12px;\n font-weight: 400;\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #8a8f9c));\n margin-top: 6px;\n line-height: 1.5;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Stable secondary navigation: browsing, settings, Hot Memory and diagnostics\n never compete for vertical position in one long document. */\n.memoir-surface-tabs {\n display: flex;\n flex: none;\n gap: 4px;\n min-width: 0;\n padding: 3px;\n overflow-x: auto;\n border: 1px solid var(--dsw-alias-border-l1, rgba(0, 0, 0, .1));\n border-radius: 10px;\n background: var(--dsw-alias-bg-layer-2, var(--bg-card, rgba(0, 0, 0, .02)));\n scrollbar-width: none;\n}\n.memoir-surface-tabs::-webkit-scrollbar {\n display: none;\n}\n.memoir-surface-tab {\n flex: 0 0 auto;\n min-height: 34px;\n padding: 5px 12px;\n border: 0;\n border-radius: 7px;\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #8a8f9c));\n background: transparent;\n font: inherit;\n font-size: 12.5px;\n cursor: pointer;\n white-space: nowrap;\n}\n.memoir-surface-tab:hover {\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n background: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, .06));\n}\n.memoir-surface-tab[data-active='true'] {\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n background: var(--dsw-alias-bg-base, var(--bg-panel, #ffffff));\n box-shadow: 0 1px 3px rgba(0, 0, 0, .08);\n font-weight: 600;\n}\n.memoir-surface-stack,\n.memoir-surface {\n display: flex;\n flex: 1;\n flex-direction: column;\n min-width: 0;\n min-height: 0;\n overflow: hidden;\n}\n.memoir-surface[hidden] {\n display: none;\n}\n.memoir-browse-head {\n display: flex;\n flex: none;\n flex-direction: column;\n gap: 8px;\n min-width: 0;\n}\n.memoir-surface-scroll {\n box-sizing: border-box;\n flex: 1;\n min-width: 0;\n min-height: 0;\n padding: 4px 2px 20px 0;\n overflow-x: hidden;\n overflow-y: auto;\n overscroll-behavior: contain;\n scrollbar-gutter: stable;\n}\n.memoir-native-view:not(.memoir-sidebar-view) .memoir-surface-scroll {\n padding-bottom: calc(var(--dsh-composer-height, 112px) + 16px);\n scroll-padding-bottom: calc(var(--dsh-composer-height, 112px) + 16px);\n}\n\n/* Header icon controls: square ghost icons (dsh-ssh / dsh-task-board iconButton). */\n.memoir-header .memoir-iconbtn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 26px;\n height: 26px;\n padding: 0;\n border: none;\n border-radius: 6px;\n background: transparent;\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #8a8f9c));\n cursor: pointer;\n font-size: 13px;\n}\n.memoir-header .memoir-iconbtn:hover {\n background: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, .06));\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n}\n\n/* --- tab bar: dsh-ssh tabBar / tab ------------------------------------------- */\n\n.memoir-tabs {\n display: flex;\n gap: 2px;\n flex: none;\n padding: 0;\n border-bottom: 1px solid var(--dsw-alias-border-l1, rgba(0, 0, 0, .1));\n}\n.memoir-tab {\n padding: 7px 14px;\n font-size: 13px;\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #8a8f9c));\n background: transparent;\n border: none;\n border-bottom: 2px solid transparent;\n border-radius: 6px 6px 0 0;\n cursor: pointer;\n white-space: nowrap;\n}\n.memoir-tab:hover {\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n background: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, .06));\n}\n.memoir-tab[data-active='true'] {\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n font-weight: 600;\n border-bottom-color: var(--dsw-alias-state-business-primary, #2563eb);\n}\n\n/* --- toolbar / controls ------------------------------------------------------- */\n\n.memoir-toolbar {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 8px;\n flex: none;\n padding: 0;\n}\n.memoir-project-actions {\n display: inline-flex;\n gap: 6px;\n}\n.memoir-search {\n flex: 1 1 200px;\n min-width: 120px;\n padding: 6px 10px;\n font-size: 13px;\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n background: var(--dsw-specific-input-major, var(--bg-card, rgba(0, 0, 0, .02)));\n border: 1px solid var(--dsw-alias-border-l2, rgba(0, 0, 0, .15));\n border-radius: 8px;\n outline: none;\n}\n.memoir-search::placeholder {\n color: var(--dsw-alias-label-tertiary, rgba(0, 0, 0, .45));\n}\n.memoir-status-filter {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 12px;\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #6b7280));\n white-space: nowrap;\n}\n.memoir-status-filter select {\n max-width: 110px;\n padding: 6px 8px;\n font-size: 13px;\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n background: var(--dsw-specific-input-major, var(--bg-card, rgba(0, 0, 0, .02)));\n border: 1px solid var(--dsw-alias-border-l2, rgba(0, 0, 0, .15));\n border-radius: 8px;\n outline: none;\n}\n.memoir-search:focus,\n.memoir-status-filter select:focus {\n border-color: var(--dsw-alias-state-business-primary, #2563eb);\n}\n\n/* --- buttons: web-ui family button language ---------------------------------- */\n\n.memoir-primary {\n border: none;\n border-radius: 8px;\n padding: 6px 14px;\n font-size: 13px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary-foreground, #ffffff);\n background: var(--dsw-alias-button-info-fill, #2563eb);\n cursor: pointer;\n white-space: nowrap;\n}\n.memoir-primary:hover:not(:disabled) {\n background: var(--dsw-alias-button-info-hover, #1d4ed8);\n}\n.memoir-primary:disabled {\n opacity: .5;\n cursor: default;\n}\n.memoir-iconbtn {\n padding: 5px 12px;\n font-size: 12px;\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n background: transparent;\n border: 1px solid var(--dsw-alias-border-l2, rgba(0, 0, 0, .15));\n border-radius: 8px;\n cursor: pointer;\n white-space: nowrap;\n}\n.memoir-iconbtn:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, .06));\n}\n.memoir-iconbtn:disabled {\n opacity: .45;\n cursor: default;\n}\n\n/* --- body / lists ------------------------------------------------------------- */\n\n.memoir-scroll-region {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n overflow-x: hidden;\n overscroll-behavior: contain;\n scrollbar-gutter: stable;\n}\n.memoir-body {\n min-height: 0;\n padding: 4px 0 16px;\n}\n.memoir-surface-scroll > .memoir-form,\n.memoir-surface-scroll > .memoir-similarity {\n margin-bottom: 10px;\n}\n.memoir-load-more {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 10px;\n padding: 10px 0 14px;\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #8a8f9c));\n font-size: 11px;\n}\n.memoir-section-title {\n display: flex;\n align-items: center;\n gap: 6px;\n margin: 12px 0 10px;\n font-size: 13px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n}\n.memoir-count {\n font-weight: 400;\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #8a8f9c));\n}\n\n/* Entry cards: dsh-skill-explorer .skill / dsh-task-board .card surfaces. */\n.memoir-entry {\n border: 1px solid var(--dsw-alias-border-l2, rgba(0, 0, 0, .08));\n border-radius: 12px;\n padding: 14px 16px;\n margin-bottom: 12px;\n background: var(--dsw-alias-bg-layer-2, var(--bg-card, rgba(127, 127, 127, .04)));\n}\n.memoir-entry-meta {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n font-size: 11px;\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #8a8f9c));\n margin-bottom: 10px;\n}\n.memoir-chip {\n display: inline-block;\n padding: 1px 8px;\n font-size: 11px;\n line-height: 1.6;\n border-radius: 999px;\n border: 1px solid var(--dsw-alias-border-l2, rgba(0, 0, 0, .1));\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #6b7280));\n background: transparent;\n white-space: nowrap;\n}\n.memoir-tag {\n /* Tags are metadata, not success alerts. */\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #6b7280));\n background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .06));\n}\n.memoir-source {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n min-width: 0;\n}\n.memoir-source-link,\n.memoir-source-copy {\n appearance: none;\n border: none;\n background: transparent;\n color: var(--dsw-alias-state-business-primary, #2563eb);\n font: inherit;\n cursor: pointer;\n padding: 0;\n}\n.memoir-source-link {\n max-width: 230px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.memoir-source-link:hover,\n.memoir-source-copy:hover {\n text-decoration: underline;\n}\n.memoir-source-copy {\n min-width: 18px;\n}\n.memoir-score {\n float: right;\n display: inline-block;\n padding: 1px 8px;\n font-size: 10px;\n line-height: 1.6;\n border-radius: 999px;\n border: 1px solid var(--dsw-alias-state-business-primary, #2563eb);\n color: var(--dsw-alias-state-business-primary, #2563eb);\n background: transparent;\n opacity: .8;\n}\n.memoir-entry-title {\n font-size: 14px;\n font-weight: 600;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n margin-bottom: 6px;\n overflow-wrap: anywhere;\n}\n.memoir-entry-content {\n font-size: 13px;\n line-height: 1.7;\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n white-space: pre-wrap;\n word-break: break-word;\n}\n.memoir-entry-content[data-collapsible='true']:not([data-expanded='true']) {\n display: -webkit-box;\n overflow: hidden;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 6;\n}\n.memoir-content-toggle {\n margin-top: 5px;\n padding: 1px 0;\n border: 0;\n color: var(--dsw-alias-state-business-primary, #2563eb);\n background: transparent;\n font: inherit;\n font-size: 11px;\n cursor: pointer;\n}\n.memoir-content-toggle:hover {\n text-decoration: underline;\n}\n.memoir-entry-actions {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n margin: 0 24px 12px 0;\n}\n.memoir-delete {\n float: right;\n border: none;\n background: transparent;\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #8a8f9c));\n cursor: pointer;\n border-radius: 6px;\n padding: 2px 6px;\n font-size: 12px;\n}\n.memoir-delete:hover {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n background: var(--dsw-alias-state-error-secondary, rgba(220, 38, 38, .12));\n}\n\n/* Project cards (global tab + ranked grouped results). */\n.memoir-project-card {\n border: 1px solid var(--dsw-alias-border-l1, rgba(0, 0, 0, .1));\n border-radius: 10px;\n padding: 0;\n margin-bottom: 12px;\n background: var(--dsw-alias-bg-layer-2, var(--bg-card, rgba(0, 0, 0, .02)));\n overflow: clip;\n}\n.memoir-project-toggle {\n appearance: none;\n display: flex;\n align-items: flex-start;\n gap: 9px;\n width: 100%;\n padding: 11px 12px;\n border: 0;\n color: inherit;\n background: transparent;\n font: inherit;\n text-align: left;\n cursor: pointer;\n}\n.memoir-project-toggle:hover {\n background: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, .04));\n}\n.memoir-project-chevron {\n flex: none;\n margin-top: 1px;\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #8a8f9c));\n font-size: 18px;\n line-height: 1;\n transition: transform 120ms ease;\n}\n.memoir-project-card[data-expanded='true'] .memoir-project-chevron {\n transform: rotate(90deg);\n}\n.memoir-project-heading {\n display: flex;\n flex: 1;\n flex-direction: column;\n gap: 5px;\n min-width: 0;\n}\n.memoir-project-body {\n padding: 0 12px 10px 30px;\n border-top: 1px solid var(--dsw-alias-border-l1, rgba(0, 0, 0, .08));\n}\n.memoir-project-head {\n display: flex;\n align-items: baseline;\n flex-wrap: wrap;\n gap: 8px;\n}\n.memoir-project-title {\n font-size: 13px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n}\n.memoir-project-path {\n flex: 1;\n min-width: 120px;\n font-size: 10px;\n color: var(--dsw-alias-label-tertiary, rgba(0, 0, 0, .5));\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.memoir-project-meta {\n display: flex;\n flex-wrap: wrap;\n gap: 5px 12px;\n font-size: 11px;\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #8a8f9c));\n}\n\n/* Empty / status / error. */\n.memoir-empty {\n padding: 28px 12px;\n text-align: center;\n font-size: 12.5px;\n color: var(--dsw-alias-label-tertiary, rgba(0, 0, 0, .5));\n}\n.memoir-empty-title {\n font-size: 13px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n margin-bottom: 6px;\n}\n.memoir-empty-hint {\n font-size: 12px;\n}\n.memoir-error {\n padding: 0;\n font-size: 12px;\n color: var(--dsw-alias-state-error-primary, #dc2626);\n}\n\n/* --- forms ------------------------------------------------------------------- */\n\n.memoir-form {\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 12px;\n margin: 0;\n background: var(--dsw-alias-bg-layer-2, var(--bg-card, rgba(0, 0, 0, .02)));\n border: 1px solid var(--dsw-alias-border-l1, rgba(0, 0, 0, .1));\n border-radius: 10px;\n}\n.memoir-form-row {\n display: flex;\n flex-wrap: wrap;\n gap: 10px;\n}\n.memoir-field {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n.memoir-field label {\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #5f6672));\n}\n.memoir-field small {\n font-size: 10px;\n color: var(--dsw-alias-label-tertiary, rgba(0, 0, 0, .55));\n line-height: 1.35;\n}\n.memoir-field input,\n.memoir-field select,\n.memoir-field textarea {\n box-sizing: border-box;\n width: 100%;\n padding: 7px 10px;\n font-size: 13px;\n font-family: inherit;\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n background: var(--dsw-specific-input-major, var(--bg-card, rgba(0, 0, 0, .02)));\n border: 1px solid var(--dsw-alias-border-l2, rgba(0, 0, 0, .15));\n border-radius: 8px;\n outline: none;\n}\n.memoir-field select {\n height: 30px;\n padding: 0 8px;\n}\n.memoir-field textarea {\n min-height: 72px;\n resize: vertical;\n}\n.memoir-field input:focus,\n.memoir-field select:focus,\n.memoir-field textarea:focus {\n border-color: var(--dsw-alias-state-business-primary, #2563eb);\n}\n.memoir-form-actions {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n}\n\n/* --- similar-memory resolution --------------------------------------------- */\n\n.memoir-similarity {\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 12px;\n border: 1px solid var(--dsw-alias-state-warn-tertiary, rgba(217, 119, 6, .4));\n border-radius: 10px;\n background: var(--dsw-alias-bg-layer-2, var(--bg-card, rgba(0, 0, 0, .02)));\n}\n.memoir-similarity-title {\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n font-size: 13px;\n font-weight: 600;\n}\n.memoir-similarity-candidate {\n display: flex;\n flex-direction: column;\n gap: 7px;\n padding: 10px 12px;\n border: 1px solid var(--dsw-alias-border-l2, rgba(0, 0, 0, .12));\n border-radius: 10px;\n background: var(--dsw-alias-bg-layer-3, var(--bg-panel, #ffffff));\n}\n.memoir-similarity-head {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n font-size: 12.5px;\n}\n.memoir-similarity-head strong {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.memoir-similarity-duplicate {\n color: var(--dsw-alias-state-warn-primary, #b45309);\n}\n.memoir-similarity-conflict {\n color: var(--dsw-alias-state-error-primary, #dc2626);\n}\n.memoir-score-static,\n.memoir-similarity-components,\n.memoir-similarity-content {\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #6b7280));\n font-size: 11px;\n}\n.memoir-similarity-content {\n line-height: 1.45;\n white-space: pre-wrap;\n word-break: break-word;\n}\n.memoir-similarity-reasons {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n}\n.memoir-similarity-footer {\n display: flex;\n justify-content: space-between;\n gap: 8px;\n}\n\n/* --- settings (panel + Settings page card) ----------------------------------- */\n\n.memoir-settings {\n margin: 0;\n border-top: 1px solid var(--dsw-alias-separator-primary, rgba(0, 0, 0, .1));\n padding-top: 8px;\n flex: none;\n}\n.memoir-settings-slot {\n list-style: none;\n margin: 0;\n padding: 0;\n border: 1px solid var(--dsw-alias-border-l2, rgba(0, 0, 0, .12));\n border-radius: 12px;\n background: var(--dsw-alias-bg-layer-3, var(--bg-card, rgba(0, 0, 0, .02)));\n transition: border-color .16s, background .16s;\n}\n.memoir-settings-slot:hover {\n border-color: var(--dsw-alias-label-dimmed, rgba(0, 0, 0, .28));\n}\n.memoir-settings-slot-open {\n background: var(--dsw-alias-bg-layer-2, var(--bg-card, rgba(0, 0, 0, .03)));\n border-color: var(--dsw-alias-label-dimmed, rgba(0, 0, 0, .28));\n}\n.memoir-settings-slot-header {\n appearance: none;\n display: flex;\n align-items: center;\n gap: 12px;\n width: 100%;\n padding: 14px 16px;\n color: inherit;\n background: transparent;\n border: 0;\n border-radius: 12px;\n font: inherit;\n text-align: left;\n cursor: pointer;\n}\n.memoir-settings-slot-header:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary, var(--dsw-alias-state-business-primary, #2563eb));\n outline-offset: -2px;\n}\n.memoir-settings-slot-headtext {\n display: flex;\n flex: 1;\n flex-direction: column;\n gap: 4px;\n min-width: 0;\n}\n.memoir-settings-slot-name {\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n font-size: 15px;\n font-weight: 600;\n line-height: 1.4;\n}\n.memoir-settings-slot-description {\n color: var(--dsw-alias-label-tertiary, var(--text-secondary, #8a8f9c));\n font-size: 13px;\n line-height: 1.5;\n}\n.memoir-settings-slot-chevron {\n flex: none;\n color: var(--dsw-alias-label-tertiary, var(--text-secondary, #8a8f9c));\n transition: transform .16s;\n}\n.memoir-settings-slot-chevron-open {\n transform: rotate(180deg);\n}\n.memoir-settings-slot-body {\n margin: 0 16px;\n padding-bottom: 8px;\n border-top: 1px solid var(--dsw-alias-border-l2, rgba(0, 0, 0, .12));\n}\n.memoir-settings-slot .memoir-settings {\n margin: 0;\n padding: 0;\n border-top: none;\n}\n.memoir-settings-slot .memoir-settings-body {\n margin: 0;\n padding: 12px 0 4px;\n border: none;\n border-radius: 0;\n background: transparent;\n max-height: none;\n}\n.memoir-settings-body {\n display: flex;\n flex-direction: column;\n gap: 10px;\n margin-top: 7px;\n padding: 10px;\n border: 1px solid var(--dsw-alias-border-l1, rgba(0, 0, 0, .1));\n border-radius: 8px;\n background: var(--dsw-alias-bg-layer-2, var(--bg-card, rgba(0, 0, 0, .02)));\n}\n.memoir-settings-description,\n.memoir-settings-note,\n.memoir-settings-source {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #8a8f9c));\n line-height: 1.45;\n}\n.memoir-settings-group-title {\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n margin-top: 2px;\n}\n.memoir-settings-switch {\n display: flex;\n align-items: flex-start;\n gap: 8px;\n cursor: pointer;\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n}\n.memoir-settings-switch input {\n margin-top: 3px;\n accent-color: var(--dsw-alias-state-business-primary, #2563eb);\n}\n.memoir-settings-switch span {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n.memoir-settings-switch small,\n.memoir-settings-grid small {\n font-size: 10px;\n color: var(--dsw-alias-label-tertiary, rgba(0, 0, 0, .55));\n line-height: 1.35;\n}\n.memoir-settings-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(min(100%, 180px), 1fr));\n gap: 12px;\n}\n.memoir-settings-grid .memoir-field {\n min-width: 0;\n}\n.memoir-settings-grid .memoir-field > span {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #6b7280));\n}\n.memoir-settings-feedback {\n padding: 0;\n}\n.memoir-settings-success {\n font-size: 12px;\n color: var(--dsw-alias-state-success-primary, #15803d);\n}\n.memoir-surface .memoir-settings {\n margin: 0;\n padding: 0;\n border-top: 0;\n}\n.memoir-surface .memoir-settings-body {\n margin-top: 0;\n}\n.memoir-surface .memoir-settings-body > .memoir-form-actions {\n /* Normal flow avoids painting actions over fields above composer padding. */\n flex-wrap: wrap;\n padding-top: 10px;\n}\n@media (max-width: 760px) {\n .memoir-settings-grid {\n grid-template-columns: 1fr;\n }\n}\n\n/* --- hot memory inspector / diagnostics -------------------------------------- */\n\n.memoir-inspector,\n.memoir-diagnostics {\n margin: 0;\n border-top: 1px solid var(--dsw-alias-separator-primary, rgba(0, 0, 0, .1));\n padding-top: 8px;\n flex: none;\n}\n.memoir-diagnostics-toggle {\n border: none;\n background: transparent;\n color: var(--dsw-alias-state-business-primary, #2563eb);\n cursor: pointer;\n font-size: 12px;\n padding: 2px 0;\n text-align: left;\n}\n.memoir-diagnostics-toggle:hover {\n text-decoration: underline;\n}\n.memoir-inspector-body {\n font-size: 11.5px;\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n margin: 6px 0 0;\n padding: 8px 10px;\n border: 1px solid var(--dsw-alias-border-l2, rgba(0, 0, 0, .1));\n border-radius: 8px;\n background: var(--dsw-alias-bg-layer-2, var(--bg-card, rgba(0, 0, 0, .02)));\n white-space: pre-wrap;\n word-break: break-word;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n max-height: none;\n overflow: visible;\n}\n.memoir-diagnostics-body {\n display: flex;\n flex-direction: column;\n gap: 3px;\n margin-top: 6px;\n font-size: 11px;\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #8a8f9c));\n}\n.memoir-surface-card {\n min-width: 0;\n padding: 14px;\n border: 1px solid var(--dsw-alias-border-l1, rgba(0, 0, 0, .1));\n border-radius: 10px;\n background: var(--dsw-alias-bg-layer-2, var(--bg-card, rgba(0, 0, 0, .02)));\n}\n.memoir-surface-card h3 {\n margin: 0 0 8px;\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n font-size: 14px;\n}\n.memoir-surface-summary {\n margin-bottom: 8px;\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #8a8f9c));\n font-size: 11px;\n}\n.memoir-surface-card .memoir-inspector-body {\n margin-top: 0;\n}\n\n/* --- sidebar entry row (plain DOM, matches the web-ui family rows) ------------- */\n\n.memoir-entry-row {\n box-sizing: border-box;\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n height: 36px;\n padding: 0 10px;\n background: transparent;\n border: none;\n border-radius: 8px;\n color: var(--dsw-alias-label-secondary, var(--text-secondary, #8a8f9c));\n cursor: pointer;\n font-size: 13px;\n white-space: nowrap;\n text-align: left;\n}\n.memoir-entry-row:hover {\n background: var(--dsw-alias-interactive-bg-hover, var(--dsw-specific-sidebar-nav-item-hover, rgba(0, 0, 0, .06)));\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n}\n.memoir-entry-row[data-active='true'] {\n background: var(--dsw-alias-interactive-bg-active, var(--dsw-specific-sidebar-nav-item-active, rgba(0, 0, 0, .08)));\n color: var(--dsw-alias-label-primary, var(--text-primary, #1f2328));\n font-weight: 600;\n}\n.memoir-entry-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: 0 0 auto;\n width: 24px;\n height: 24px;\n}\n.memoir-entry-icon svg {\n display: block;\n width: 18px;\n height: 18px;\n}\n.memoir-entry-label {\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* Collapsed rail: exact dsh-web-ui-all 0.3.x family geometry. */\n[data-dsh-frame][data-sidebar-collapsed] [data-dsh-memoir-entry].memoir-entry-row,\n[data-sidebar-collapsed] [data-dsh-memoir-entry].memoir-entry-row {\n border-radius: 50%;\n justify-content: center;\n padding: 0;\n width: 36px;\n height: 36px;\n margin: 0 auto 12px;\n}\n[data-dsh-frame][data-sidebar-collapsed] [data-dsh-memoir-entry] .memoir-entry-label,\n[data-sidebar-collapsed] [data-dsh-memoir-entry] .memoir-entry-label {\n display: none;\n}\n\n/* --- focus / motion (web-ui family polish) ------------------------------------ */\n\n.memoir-tab:focus-visible,\n.memoir-surface-tab:focus-visible,\n.memoir-search:focus-visible,\n.memoir-primary:focus-visible,\n.memoir-iconbtn:focus-visible,\n.memoir-delete:focus-visible,\n.memoir-status-filter select:focus-visible,\n.memoir-diagnostics-toggle:focus-visible,\n.memoir-project-toggle:focus-visible,\n.memoir-content-toggle:focus-visible,\n.memoir-field input:focus-visible,\n.memoir-field select:focus-visible,\n.memoir-field textarea:focus-visible,\n.memoir-entry-row:focus-visible {\n outline: 2px solid var(--dsw-alias-state-business-primary, #2563eb);\n outline-offset: 2px;\n}\n.memoir-tab,\n.memoir-surface-tab,\n.memoir-search,\n.memoir-primary,\n.memoir-iconbtn,\n.memoir-delete,\n.memoir-status-filter select,\n.memoir-diagnostics-toggle,\n.memoir-project-toggle,\n.memoir-content-toggle,\n.memoir-field input,\n.memoir-field select,\n.memoir-field textarea,\n.memoir-entry-row {\n transition: background-color 120ms ease, color 120ms ease, border-color 120ms ease, outline-color 120ms ease;\n}\n@media (prefers-reduced-motion: reduce) {\n .memoir-tab,\n .memoir-surface-tab,\n .memoir-search,\n .memoir-primary,\n .memoir-iconbtn,\n .memoir-delete,\n .memoir-status-filter select,\n .memoir-diagnostics-toggle,\n .memoir-project-toggle,\n .memoir-content-toggle,\n .memoir-field input,\n .memoir-field select,\n .memoir-field textarea,\n .memoir-entry-row {\n transition: none;\n }\n}\n\n@media (max-width: 640px) {\n .memoir-panel,\n .memoir-settings-section .memoir-panel {\n padding: 10px 10px 12px;\n gap: 8px;\n }\n .memoir-toolbar {\n align-items: stretch;\n }\n .memoir-search {\n flex: 1 0 100%;\n }\n .memoir-status-filter {\n flex: 1;\n }\n .memoir-status-filter select {\n flex: 1;\n max-width: none;\n }\n .memoir-project-actions {\n width: 100%;\n }\n .memoir-project-body {\n padding-left: 12px;\n }\n}\n\n/* Dark fallback only when the dsw tokens are absent (standalone shells);\n with web-ui-all installed the --dsw-alias-* palette already applies. */\nbody[data-ds-dark-theme] [data-dsh-memoir-view] {\n background: var(--dsw-alias-bg-base, #16181d);\n color: var(--dsw-alias-label-primary, #e6e6e6);\n}\n`\n", "import type { SessionListState } from '@deepseek-ai/dsh-api-session-controller/client'\n\n/** The public mainView retention marker distinguishes the main conversation\n * from independently mounted sidebar sessions. Never fall back to the first\n * catalog row: that could expose another project's memories in Settings. */\nexport function mainWorkspaceCwd(snapshot: Pick<SessionListState, 'byId'>): string {\n const main = Object.values(snapshot.byId).filter(session => (session.retainedBy.mainView ?? 0) > 0)\n return main.length === 1 ? main[0]!.cwd ?? '' : ''\n}\n", "import type { Context } from '@deepseek-ai/cordis'\nimport type { PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { IconProps } from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { UseSessions } from '@deepseek-ai/dsh-client-ui-session/client'\nimport type { SessionListState } from '@deepseek-ai/dsh-api-session-controller/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-sidebar-right/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-session/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-workspace/client'\nimport { useEffect, useState } from 'react'\nimport type { MemoirApi } from './api.js'\nimport { MemoirPanel } from './panel.js'\n\nexport const SIDEBAR_ID = 'dsh-memoir'\n\n/** SVG honors the host's requested size and color; no remote icon request. */\nfunction MemoirIcon({ size = 20, className }: IconProps) {\n return <svg width={size} height={size} className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.75\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\" focusable=\"false\">\n <path d=\"M12 5c-3-2-6-2-9-1v15c3-1 6-1 9 1 3-2 6-2 9-1V4c-3-1-6-1-9 1v15\" />\n </svg>\n}\n\nfunction SidebarMemoir({ api, ctx, t, sessionId, useSessions, useTabInfo }: PropsRuntime<'sidebar.right.pane.tab'> & {\n api: MemoirApi; ctx: Context; t: (key: string) => string; useSessions: UseSessions\n}) {\n const cwd = useSessions((snapshot: SessionListState) => snapshot.byId[sessionId]?.cwd ?? '')\n const { tab } = useTabInfo()\n return <div className=\"memoir-native-view memoir-sidebar-view\" data-dsh-plugin=\"memoir\" data-dsh-part=\"sidebar-view\">\n <MemoirPanel key={sessionId} api={api} cwd={cwd} t={t} onClose={() => tab.actions.close()}\n openSource={id => ctx.uiWorkspace.openSession(id as typeof sessionId)} />\n </div>\n}\n\nfunction SidebarTitle({ t }: { t: (key: string) => string }) {\n const [, refresh] = useState(0)\n useEffect(() => {\n const observer = new MutationObserver(() => refresh(value => value + 1))\n observer.observe(document.documentElement, { attributes: true, attributeFilter: ['lang'] })\n return () => observer.disconnect()\n }, [])\n return <span className=\"memoir-sidebar-title\"><MemoirIcon size={16} />{t('entry.label')}</span>\n}\n\n/** Optional service: absence/reload must not pend the main plugin. */\nexport function watchSidebar(ctx: Context, api: MemoirApi, t: (key: string) => string): () => Promise<void> {\n const pending = ctx.inject(['sidebarRightTabs'], sidebarCtx => {\n sidebarCtx.effect(() => {\n const owned: Array<() => void> = []\n const cleanup = () => { for (const dispose of owned.splice(0).reverse()) dispose() }\n try {\n owned.push(sidebarCtx.sidebarRightTabs.register({\n id: SIDEBAR_ID, kind: SIDEBAR_ID, keepMounted: true,\n title: () => t('entry.label'),\n guide: [{ id: SIDEBAR_ID, order: 30, title: () => t('entry.label'), description: () => t('sidebar.description'), icon: MemoirIcon }],\n }))\n owned.push(sidebarCtx.slots.inject('sidebar.right.pane.tab', () => sidebarCtx.slots.register({\n name: 'sidebar.right.pane.tab', key: SIDEBAR_ID,\n }, props => <SidebarMemoir {...props} api={api} ctx={sidebarCtx} t={t} />)))\n owned.push(sidebarCtx.slots.inject('sidebar.right.pane.tab.title', () => sidebarCtx.slots.register({\n name: 'sidebar.right.pane.tab.title', key: SIDEBAR_ID,\n }, () => <SidebarTitle t={t} />)))\n } catch {\n // A collision or partially unavailable optional owner must not remove\n // another plugin's entries or break Conversation / Settings.\n cleanup()\n sidebarCtx.logger.warn('dsh-memoir: optional sidebar registration unavailable; Conversation and Settings remain active')\n }\n return cleanup\n }, 'dsh-memoir: optional sidebar registration')\n })\n return () => pending.dispose()\n}\n", "import type { Context } from '@deepseek-ai/cordis'\nimport type { PluginConfigViewProps } from '@deepseek-ai/dsh-client-ui-plugin-manager/client'\nimport { useEffect, useState } from 'react'\nimport type { MemoirApi } from './api.js'\nimport { MemoirAbout } from './about.js'\nimport { MemoirSettingsPanel } from './panel.js'\n\n/** Native bundle page, not an official-plugin impostor or a second settings store. */\nfunction PluginSettings({ api, t }: { api: MemoirApi; t: (key: string) => string }) {\n const [revision, refresh] = useState(0)\n const [, languageChanged] = useState(0)\n useEffect(() => {\n const observer = new MutationObserver(() => languageChanged(value => value + 1))\n observer.observe(document.documentElement, { attributes: true, attributeFilter: ['lang'] })\n return () => observer.disconnect()\n }, [])\n return <div className=\"memoir-plugin-settings\" data-dsh-plugin=\"memoir\" data-dsh-part=\"plugin-settings\">\n <MemoirAbout t={t} />\n <MemoirSettingsPanel api={api} t={t} refreshKey={revision} onChanged={() => refresh(value => value + 1)} alwaysOpen />\n </div>\n}\n\n/** Wait for the public slot owner; missing/reloaded plugin manager cannot block Memoir. */\nexport function watchPluginSettings(ctx: Context, api: MemoirApi, t: (key: string) => string): () => void {\n return ctx.slots.inject('plugins.bundle.config', () => ctx.slots.register({\n name: 'plugins.bundle.config', key: 'dsh-memoir',\n }, ({ view }: PluginConfigViewProps) => view === 'summary'\n ? <>{t('sidebar.description')}</>\n : <PluginSettings api={api} t={t} />))\n}\n"],
|
|
5
5
|
"mappings": "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AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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",
|
|
6
6
|
"names": ["import_react", "import_react", "import_jsx_runtime", "query", "import_react", "import_jsx_runtime", "import_react", "import_jsx_runtime", "import_jsx_runtime"]
|
|
7
7
|
}
|