@flowingspring/dsh-workspace-memory 0.1.0 → 0.2.1

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/DESIGN.md CHANGED
@@ -104,6 +104,20 @@ rebuilt from active entries. A bounded history is kept before replacement.
104
104
  - `memory_search` remains the Agentic second-search seam: an Agent can issue
105
105
  alternate queries when the automatic first recall is insufficient.
106
106
 
107
+ ### Settings memory browser
108
+
109
+ The Web client contributes a top-level `settings.section` named `记忆`. It reads
110
+ the same store through two loopback, read-only Host routes:
111
+
112
+ - `GET /workspace-memory/api/v1/scopes` lists the global scope and persisted
113
+ workspace descriptors.
114
+ - `GET /workspace-memory/api/v1/scope?cwd=...` returns a redacted summary,
115
+ active entries, and checkpoint counters for one scope.
116
+
117
+ The browser never opens checkpoint Markdown or writes the JSON files directly.
118
+ Mutations continue to go through the memory engine so its per-scope locks,
119
+ deduplication, secret checks, and atomic writes remain authoritative.
120
+
107
121
  ## Voco integration
108
122
 
109
123
  - Before frontend routing, Voco optionally calls `workspaceMemory.recall`.
package/README.md CHANGED
@@ -17,6 +17,7 @@ Session 共享一份稳定摘要和长期原子记忆,并通过可选 Cordis
17
17
  - Agent turn 结束只进入 checkpoint 缓冲,不会每轮强制调用记忆蒸馏模型。
18
18
  - LLM 只蒸馏长期有效事实;重复/近重复事实会更新原条目。
19
19
  - 提供 `memory_search`、`memory_remember`、`memory_forget` 工具。
20
+ - Web profile 设置中提供“记忆”页面,可查看全局记忆和不同项目的脱敏摘要、结构化条目。
20
21
  - 凭据形态内容默认拒绝持久化,并在模型输入前脱敏。
21
22
  - 没有安装本插件时,`dsh-voco` 保持原有行为。
22
23
 
@@ -89,6 +90,10 @@ workspace-memory/
89
90
  `memory_entries.json` 是事实来源;`memory_summary.md` 是自动注入的短摘要;
90
91
  `checkpoints/` 保留每次阶段性蒸馏的可审计 Markdown 记录。
91
92
 
93
+ 设置中的“记忆”页面是只读浏览器:前端通过 Host 的内部读取接口访问同一套
94
+ Store,按照 `scope.json` 显示项目目录。它不会直接读写 JSON 文件,也不会展示
95
+ 包含完整对话的 checkpoint 原文。
96
+
92
97
  ## 开发验证
93
98
 
94
99
  源码与测试均使用 TypeScript;`pnpm build` 将 ESM JavaScript 和类型声明生成到
@@ -0,0 +1,174 @@
1
+ import { useEffect, useMemo, useState, useSyncExternalStore } from 'react';
2
+ import { createElement as h } from 'react';
3
+ const NS = 'workspace-memory';
4
+ const zh = {
5
+ nav: '记忆',
6
+ title: '记忆',
7
+ refresh: '刷新',
8
+ global: '全局记忆',
9
+ workspace: '项目记忆',
10
+ current: '当前项目',
11
+ emptyScopes: '还没有已记录的项目记忆',
12
+ summary: '摘要记忆',
13
+ entries: '结构化记忆',
14
+ search: '筛选记忆',
15
+ searchPlaceholder: '搜索标题、内容或标签',
16
+ noSummary: '暂无摘要',
17
+ noEntries: '暂无结构化记忆',
18
+ loading: '正在读取…',
19
+ failed: '读取记忆失败',
20
+ retry: '重试',
21
+ pending: '待整理',
22
+ checkpoints: '整理次数',
23
+ updated: '最近更新',
24
+ all: '全部',
25
+ count: '条',
26
+ };
27
+ const en = {
28
+ nav: 'Memory',
29
+ title: 'Memory',
30
+ refresh: 'Refresh',
31
+ global: 'Global memory',
32
+ workspace: 'Project memory',
33
+ current: 'Current project',
34
+ emptyScopes: 'No project memories recorded yet',
35
+ summary: 'Summary memory',
36
+ entries: 'Structured memory',
37
+ search: 'Filter memory',
38
+ searchPlaceholder: 'Search title, content, or tags',
39
+ noSummary: 'No summary yet',
40
+ noEntries: 'No structured memories yet',
41
+ loading: 'Loading…',
42
+ failed: 'Unable to read memory',
43
+ retry: 'Retry',
44
+ pending: 'Pending',
45
+ checkpoints: 'Checkpoints',
46
+ updated: 'Last updated',
47
+ all: 'All',
48
+ count: '',
49
+ };
50
+ function useSnapshot(source) {
51
+ return useSyncExternalStore(source.subscribe, source.getSnapshot, source.getSnapshot);
52
+ }
53
+ function workspaceName(cwd, fallback) {
54
+ const normalized = cwd.replaceAll('\\', '/').replace(/\/+$/u, '');
55
+ const name = normalized.split('/').filter(Boolean).at(-1);
56
+ return name ?? fallback;
57
+ }
58
+ function formatDate(value) {
59
+ if (value === undefined || value === '')
60
+ return '';
61
+ const date = new Date(value);
62
+ return Number.isFinite(date.getTime()) ? date.toLocaleString() : value;
63
+ }
64
+ function iconRefresh() {
65
+ return h('svg', { width: 16, height: 16, viewBox: '0 0 16 16', 'aria-hidden': true }, h('path', { d: 'M13 4.8A5.5 5.5 0 1 0 13.5 9', fill: 'none', stroke: 'currentColor', strokeWidth: 1.4, strokeLinecap: 'round' }), h('path', { d: 'M10.8 2.8h2.8v2.8', fill: 'none', stroke: 'currentColor', strokeWidth: 1.4, strokeLinecap: 'round', strokeLinejoin: 'round' }));
66
+ }
67
+ function MemorySection({ t, sessions }) {
68
+ const sessionList = useSnapshot(sessions.list);
69
+ const currentCwd = sessionList.current === undefined ? '' : sessionList.byId[sessionList.current]?.cwd ?? '';
70
+ const [scopes, setScopes] = useState([]);
71
+ const [selectedKey, setSelectedKey] = useState('global');
72
+ const [payload, setPayload] = useState();
73
+ const [query, setQuery] = useState('');
74
+ const [loading, setLoading] = useState(true);
75
+ const [error, setError] = useState(false);
76
+ const loadScopes = async () => {
77
+ const response = await fetch('/workspace-memory/api/v1/scopes');
78
+ if (!response.ok)
79
+ throw new Error(`scope list failed (${response.status})`);
80
+ const result = await response.json();
81
+ return Array.isArray(result.scopes) ? result.scopes : [];
82
+ };
83
+ const loadScope = async (cwd) => {
84
+ const response = await fetch(`/workspace-memory/api/v1/scope?cwd=${encodeURIComponent(cwd)}`);
85
+ if (!response.ok)
86
+ throw new Error(`scope read failed (${response.status})`);
87
+ return await response.json();
88
+ };
89
+ const reload = async (cwd) => {
90
+ setLoading(true);
91
+ setError(false);
92
+ try {
93
+ const nextScopes = await loadScopes();
94
+ setScopes(nextScopes);
95
+ const next = await loadScope(cwd ?? payload?.scope.cwd ?? currentCwd);
96
+ setPayload(next);
97
+ setSelectedKey(next.scope.key);
98
+ }
99
+ catch {
100
+ setError(true);
101
+ }
102
+ finally {
103
+ setLoading(false);
104
+ }
105
+ };
106
+ useEffect(() => {
107
+ void reload(currentCwd);
108
+ // The initial project follows the current session; later changes are user-selected.
109
+ // eslint-disable-next-line react-hooks/exhaustive-deps
110
+ }, []);
111
+ const options = useMemo(() => {
112
+ const known = new Map(scopes.map(scope => [scope.key, scope]));
113
+ const currentKey = `current:${currentCwd.toLocaleLowerCase()}`;
114
+ if (currentCwd !== '' && !known.has(currentKey) && !scopes.some(scope => scope.cwd.toLocaleLowerCase() === currentCwd.toLocaleLowerCase())) {
115
+ known.set(currentKey, {
116
+ key: currentKey,
117
+ cwd: currentCwd,
118
+ kind: 'workspace',
119
+ entryCount: 0,
120
+ hasSummary: false,
121
+ pending: 0,
122
+ checkpointCount: 0,
123
+ });
124
+ }
125
+ return [...known.values()];
126
+ }, [scopes, currentCwd]);
127
+ const filteredEntries = useMemo(() => {
128
+ const normalized = query.trim().toLocaleLowerCase();
129
+ if (normalized === '')
130
+ return payload?.entries ?? [];
131
+ return (payload?.entries ?? []).filter(entry => [entry.title, entry.description, entry.content, ...entry.tags]
132
+ .join(' ').toLocaleLowerCase().includes(normalized));
133
+ }, [payload, query]);
134
+ const onSelect = (key) => {
135
+ const option = options.find(scope => scope.key === key);
136
+ if (option === undefined)
137
+ return;
138
+ setSelectedKey(key);
139
+ void reload(option.cwd);
140
+ };
141
+ const colors = {
142
+ text: 'var(--ds-color-text-primary, #f1f1f1)',
143
+ secondary: 'var(--ds-color-text-secondary, #a7a7ad)',
144
+ border: 'var(--ds-color-border, rgba(255,255,255,.12))',
145
+ surface: 'var(--ds-color-bg-secondary, rgba(255,255,255,.045))',
146
+ accent: 'var(--ds-color-primary, #8ab4ff)',
147
+ };
148
+ return h('section', { style: { color: colors.text, maxWidth: 820, paddingBottom: 24 } }, h('header', { style: { display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 16, marginBottom: 18 } }, h('div', null, h('h2', { style: { margin: 0, fontSize: 20, fontWeight: 650 } }, t('title')), h('p', { style: { margin: '6px 0 0', color: colors.secondary, fontSize: 12, wordBreak: 'break-all' } }, payload?.scope.cwd || t('global'))), h('button', {
149
+ type: 'button', title: t('refresh'), 'aria-label': t('refresh'), onClick: () => { void reload(); },
150
+ style: { display: 'inline-flex', alignItems: 'center', justifyContent: 'center', width: 34, height: 34, border: `1px solid ${colors.border}`, borderRadius: 6, background: 'transparent', color: colors.text, cursor: 'pointer' },
151
+ }, iconRefresh())), h('div', { style: { display: 'grid', gap: 8, marginBottom: 18 } }, h('label', { style: { color: colors.secondary, fontSize: 12 } }, t('current')), h('select', {
152
+ value: selectedKey, onChange: (event) => { onSelect(event.target.value); },
153
+ style: { minHeight: 38, padding: '0 10px', color: colors.text, background: colors.surface, border: `1px solid ${colors.border}`, borderRadius: 6 },
154
+ }, options.length === 0
155
+ ? h('option', { value: '' }, t('emptyScopes'))
156
+ : options.map(scope => h('option', { key: scope.key, value: scope.key }, scope.kind === 'global' ? t('global') : workspaceName(scope.cwd, t('workspace')))))), error && h('div', { role: 'alert', style: { padding: 12, border: `1px solid ${colors.border}`, borderRadius: 6, color: colors.secondary, display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 12 } }, h('span', null, t('failed')), h('button', { type: 'button', onClick: () => { void reload(); }, style: { color: colors.accent, background: 'transparent', border: 0, cursor: 'pointer' } }, t('retry'))), loading && h('p', { style: { color: colors.secondary } }, t('loading')), !loading && !error && h('div', { style: { display: 'grid', gap: 16 } }, h('div', { style: { display: 'flex', gap: 16, color: colors.secondary, fontSize: 12, flexWrap: 'wrap' } }, h('span', null, `${payload?.entries.length ?? 0}${t('count')}`), h('span', null, `${t('pending')}: ${payload?.state.pending ?? 0}`), h('span', null, `${t('checkpoints')}: ${payload?.state.checkpointCount ?? 0}`)), h('article', { style: { border: `1px solid ${colors.border}`, borderRadius: 6, padding: 14, background: colors.surface } }, h('h3', { style: { margin: '0 0 10px', fontSize: 14 } }, t('summary')), h('pre', { style: { margin: 0, color: colors.secondary, whiteSpace: 'pre-wrap', wordBreak: 'break-word', font: 'inherit', lineHeight: 1.55 } }, payload?.summary.trim() || t('noSummary'))), h('div', { style: { display: 'grid', gap: 10 } }, h('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12 } }, h('h3', { style: { margin: 0, fontSize: 14 } }, `${t('entries')} (${filteredEntries.length})`), h('input', { type: 'search', value: query, placeholder: t('searchPlaceholder'), 'aria-label': t('search'), onChange: (event) => { setQuery(event.target.value); }, style: { minHeight: 32, width: 230, maxWidth: '48%', padding: '0 9px', color: colors.text, background: 'transparent', border: `1px solid ${colors.border}`, borderRadius: 6 } })), filteredEntries.length === 0 && h('p', { style: { color: colors.secondary, margin: 0 } }, t('noEntries')), filteredEntries.map(entry => h('details', { key: entry.id, style: { border: `1px solid ${colors.border}`, borderRadius: 6, padding: '10px 12px', background: colors.surface } }, h('summary', { style: { cursor: 'pointer', display: 'flex', gap: 8, alignItems: 'baseline' } }, h('strong', { style: { fontSize: 13 } }, entry.title), h('span', { style: { color: colors.secondary, fontSize: 11 } }, entry.type)), h('p', { style: { margin: '10px 0 0', color: colors.secondary, lineHeight: 1.5, whiteSpace: 'pre-wrap', wordBreak: 'break-word' } }, entry.content), entry.tags.length > 0 && h('div', { style: { marginTop: 10, color: colors.accent, fontSize: 11 } }, entry.tags.join(' · ')), entry.updatedAt !== undefined && h('div', { style: { marginTop: 8, color: colors.secondary, fontSize: 11 } }, `${t('updated')}: ${formatDate(entry.updatedAt)}`))))));
157
+ }
158
+ export const inject = ['slots', 'locale', 'sessions'];
159
+ export function apply(ctx) {
160
+ ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'workspace-memory: dictionaries');
161
+ const translate = ctx.locale.bind(NS);
162
+ const t = (key) => {
163
+ const translated = translate(key);
164
+ return translated || zh[key];
165
+ };
166
+ ctx.slots.inject('settings.section', () => ctx.slots.register({
167
+ name: 'settings.section',
168
+ id: 'workspace-memory',
169
+ order: 50,
170
+ label: () => t('nav'),
171
+ locale: NS,
172
+ }, () => h(MemorySection, { t, sessions: ctx.sessions })));
173
+ }
174
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.tsx"],"names":[],"mappings":"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"}
package/lib/client.js ADDED
@@ -0,0 +1,367 @@
1
+ window.__ModuleLoader__.load({
2
+ id: "@flowingspring/dsh-workspace-memory",
3
+ factory: (require) => {
4
+ var module = { exports: {} };
5
+ var exports = module.exports;
6
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
+ let react = require("react");
8
+ //#region src/client/index.tsx
9
+ const NS = "workspace-memory";
10
+ const zh = {
11
+ nav: "记忆",
12
+ title: "记忆",
13
+ refresh: "刷新",
14
+ global: "全局记忆",
15
+ workspace: "项目记忆",
16
+ current: "当前项目",
17
+ emptyScopes: "还没有已记录的项目记忆",
18
+ summary: "摘要记忆",
19
+ entries: "结构化记忆",
20
+ search: "筛选记忆",
21
+ searchPlaceholder: "搜索标题、内容或标签",
22
+ noSummary: "暂无摘要",
23
+ noEntries: "暂无结构化记忆",
24
+ loading: "正在读取…",
25
+ failed: "读取记忆失败",
26
+ retry: "重试",
27
+ pending: "待整理",
28
+ checkpoints: "整理次数",
29
+ updated: "最近更新",
30
+ all: "全部",
31
+ count: "条"
32
+ };
33
+ const en = {
34
+ nav: "Memory",
35
+ title: "Memory",
36
+ refresh: "Refresh",
37
+ global: "Global memory",
38
+ workspace: "Project memory",
39
+ current: "Current project",
40
+ emptyScopes: "No project memories recorded yet",
41
+ summary: "Summary memory",
42
+ entries: "Structured memory",
43
+ search: "Filter memory",
44
+ searchPlaceholder: "Search title, content, or tags",
45
+ noSummary: "No summary yet",
46
+ noEntries: "No structured memories yet",
47
+ loading: "Loading…",
48
+ failed: "Unable to read memory",
49
+ retry: "Retry",
50
+ pending: "Pending",
51
+ checkpoints: "Checkpoints",
52
+ updated: "Last updated",
53
+ all: "All",
54
+ count: ""
55
+ };
56
+ function useSnapshot(source) {
57
+ return (0, react.useSyncExternalStore)(source.subscribe, source.getSnapshot, source.getSnapshot);
58
+ }
59
+ function workspaceName(cwd, fallback) {
60
+ return cwd.replaceAll("\\", "/").replace(/\/+$/u, "").split("/").filter(Boolean).at(-1) ?? fallback;
61
+ }
62
+ function formatDate(value) {
63
+ if (value === void 0 || value === "") return "";
64
+ const date = new Date(value);
65
+ return Number.isFinite(date.getTime()) ? date.toLocaleString() : value;
66
+ }
67
+ function iconRefresh() {
68
+ return (0, react.createElement)("svg", {
69
+ width: 16,
70
+ height: 16,
71
+ viewBox: "0 0 16 16",
72
+ "aria-hidden": true
73
+ }, (0, react.createElement)("path", {
74
+ d: "M13 4.8A5.5 5.5 0 1 0 13.5 9",
75
+ fill: "none",
76
+ stroke: "currentColor",
77
+ strokeWidth: 1.4,
78
+ strokeLinecap: "round"
79
+ }), (0, react.createElement)("path", {
80
+ d: "M10.8 2.8h2.8v2.8",
81
+ fill: "none",
82
+ stroke: "currentColor",
83
+ strokeWidth: 1.4,
84
+ strokeLinecap: "round",
85
+ strokeLinejoin: "round"
86
+ }));
87
+ }
88
+ function MemorySection({ t, sessions }) {
89
+ const sessionList = useSnapshot(sessions.list);
90
+ const currentCwd = sessionList.current === void 0 ? "" : sessionList.byId[sessionList.current]?.cwd ?? "";
91
+ const [scopes, setScopes] = (0, react.useState)([]);
92
+ const [selectedKey, setSelectedKey] = (0, react.useState)("global");
93
+ const [payload, setPayload] = (0, react.useState)();
94
+ const [query, setQuery] = (0, react.useState)("");
95
+ const [loading, setLoading] = (0, react.useState)(true);
96
+ const [error, setError] = (0, react.useState)(false);
97
+ const loadScopes = async () => {
98
+ const response = await fetch("/workspace-memory/api/v1/scopes");
99
+ if (!response.ok) throw new Error(`scope list failed (${response.status})`);
100
+ const result = await response.json();
101
+ return Array.isArray(result.scopes) ? result.scopes : [];
102
+ };
103
+ const loadScope = async (cwd) => {
104
+ const response = await fetch(`/workspace-memory/api/v1/scope?cwd=${encodeURIComponent(cwd)}`);
105
+ if (!response.ok) throw new Error(`scope read failed (${response.status})`);
106
+ return await response.json();
107
+ };
108
+ const reload = async (cwd) => {
109
+ setLoading(true);
110
+ setError(false);
111
+ try {
112
+ const nextScopes = await loadScopes();
113
+ setScopes(nextScopes);
114
+ const next = await loadScope(cwd ?? payload?.scope.cwd ?? currentCwd);
115
+ setPayload(next);
116
+ setSelectedKey(next.scope.key);
117
+ } catch {
118
+ setError(true);
119
+ } finally {
120
+ setLoading(false);
121
+ }
122
+ };
123
+ (0, react.useEffect)(() => {
124
+ reload(currentCwd);
125
+ }, []);
126
+ const options = (0, react.useMemo)(() => {
127
+ const known = new Map(scopes.map((scope) => [scope.key, scope]));
128
+ const currentKey = `current:${currentCwd.toLocaleLowerCase()}`;
129
+ if (currentCwd !== "" && !known.has(currentKey) && !scopes.some((scope) => scope.cwd.toLocaleLowerCase() === currentCwd.toLocaleLowerCase())) known.set(currentKey, {
130
+ key: currentKey,
131
+ cwd: currentCwd,
132
+ kind: "workspace",
133
+ entryCount: 0,
134
+ hasSummary: false,
135
+ pending: 0,
136
+ checkpointCount: 0
137
+ });
138
+ return [...known.values()];
139
+ }, [scopes, currentCwd]);
140
+ const filteredEntries = (0, react.useMemo)(() => {
141
+ const normalized = query.trim().toLocaleLowerCase();
142
+ if (normalized === "") return payload?.entries ?? [];
143
+ return (payload?.entries ?? []).filter((entry) => [
144
+ entry.title,
145
+ entry.description,
146
+ entry.content,
147
+ ...entry.tags
148
+ ].join(" ").toLocaleLowerCase().includes(normalized));
149
+ }, [payload, query]);
150
+ const onSelect = (key) => {
151
+ const option = options.find((scope) => scope.key === key);
152
+ if (option === void 0) return;
153
+ setSelectedKey(key);
154
+ reload(option.cwd);
155
+ };
156
+ const colors = {
157
+ text: "var(--ds-color-text-primary, #f1f1f1)",
158
+ secondary: "var(--ds-color-text-secondary, #a7a7ad)",
159
+ border: "var(--ds-color-border, rgba(255,255,255,.12))",
160
+ surface: "var(--ds-color-bg-secondary, rgba(255,255,255,.045))",
161
+ accent: "var(--ds-color-primary, #8ab4ff)"
162
+ };
163
+ return (0, react.createElement)("section", { style: {
164
+ color: colors.text,
165
+ maxWidth: 820,
166
+ paddingBottom: 24
167
+ } }, (0, react.createElement)("header", { style: {
168
+ display: "flex",
169
+ alignItems: "flex-start",
170
+ justifyContent: "space-between",
171
+ gap: 16,
172
+ marginBottom: 18
173
+ } }, (0, react.createElement)("div", null, (0, react.createElement)("h2", { style: {
174
+ margin: 0,
175
+ fontSize: 20,
176
+ fontWeight: 650
177
+ } }, t("title")), (0, react.createElement)("p", { style: {
178
+ margin: "6px 0 0",
179
+ color: colors.secondary,
180
+ fontSize: 12,
181
+ wordBreak: "break-all"
182
+ } }, payload?.scope.cwd || t("global"))), (0, react.createElement)("button", {
183
+ type: "button",
184
+ title: t("refresh"),
185
+ "aria-label": t("refresh"),
186
+ onClick: () => {
187
+ reload();
188
+ },
189
+ style: {
190
+ display: "inline-flex",
191
+ alignItems: "center",
192
+ justifyContent: "center",
193
+ width: 34,
194
+ height: 34,
195
+ border: `1px solid ${colors.border}`,
196
+ borderRadius: 6,
197
+ background: "transparent",
198
+ color: colors.text,
199
+ cursor: "pointer"
200
+ }
201
+ }, iconRefresh())), (0, react.createElement)("div", { style: {
202
+ display: "grid",
203
+ gap: 8,
204
+ marginBottom: 18
205
+ } }, (0, react.createElement)("label", { style: {
206
+ color: colors.secondary,
207
+ fontSize: 12
208
+ } }, t("current")), (0, react.createElement)("select", {
209
+ value: selectedKey,
210
+ onChange: (event) => {
211
+ onSelect(event.target.value);
212
+ },
213
+ style: {
214
+ minHeight: 38,
215
+ padding: "0 10px",
216
+ color: colors.text,
217
+ background: colors.surface,
218
+ border: `1px solid ${colors.border}`,
219
+ borderRadius: 6
220
+ }
221
+ }, options.length === 0 ? (0, react.createElement)("option", { value: "" }, t("emptyScopes")) : options.map((scope) => (0, react.createElement)("option", {
222
+ key: scope.key,
223
+ value: scope.key
224
+ }, scope.kind === "global" ? t("global") : workspaceName(scope.cwd, t("workspace")))))), error && (0, react.createElement)("div", {
225
+ role: "alert",
226
+ style: {
227
+ padding: 12,
228
+ border: `1px solid ${colors.border}`,
229
+ borderRadius: 6,
230
+ color: colors.secondary,
231
+ display: "flex",
232
+ justifyContent: "space-between",
233
+ alignItems: "center",
234
+ gap: 12
235
+ }
236
+ }, (0, react.createElement)("span", null, t("failed")), (0, react.createElement)("button", {
237
+ type: "button",
238
+ onClick: () => {
239
+ reload();
240
+ },
241
+ style: {
242
+ color: colors.accent,
243
+ background: "transparent",
244
+ border: 0,
245
+ cursor: "pointer"
246
+ }
247
+ }, t("retry"))), loading && (0, react.createElement)("p", { style: { color: colors.secondary } }, t("loading")), !loading && !error && (0, react.createElement)("div", { style: {
248
+ display: "grid",
249
+ gap: 16
250
+ } }, (0, react.createElement)("div", { style: {
251
+ display: "flex",
252
+ gap: 16,
253
+ color: colors.secondary,
254
+ fontSize: 12,
255
+ flexWrap: "wrap"
256
+ } }, (0, react.createElement)("span", null, `${payload?.entries.length ?? 0}${t("count")}`), (0, react.createElement)("span", null, `${t("pending")}: ${payload?.state.pending ?? 0}`), (0, react.createElement)("span", null, `${t("checkpoints")}: ${payload?.state.checkpointCount ?? 0}`)), (0, react.createElement)("article", { style: {
257
+ border: `1px solid ${colors.border}`,
258
+ borderRadius: 6,
259
+ padding: 14,
260
+ background: colors.surface
261
+ } }, (0, react.createElement)("h3", { style: {
262
+ margin: "0 0 10px",
263
+ fontSize: 14
264
+ } }, t("summary")), (0, react.createElement)("pre", { style: {
265
+ margin: 0,
266
+ color: colors.secondary,
267
+ whiteSpace: "pre-wrap",
268
+ wordBreak: "break-word",
269
+ font: "inherit",
270
+ lineHeight: 1.55
271
+ } }, payload?.summary.trim() || t("noSummary"))), (0, react.createElement)("div", { style: {
272
+ display: "grid",
273
+ gap: 10
274
+ } }, (0, react.createElement)("div", { style: {
275
+ display: "flex",
276
+ alignItems: "center",
277
+ justifyContent: "space-between",
278
+ gap: 12
279
+ } }, (0, react.createElement)("h3", { style: {
280
+ margin: 0,
281
+ fontSize: 14
282
+ } }, `${t("entries")} (${filteredEntries.length})`), (0, react.createElement)("input", {
283
+ type: "search",
284
+ value: query,
285
+ placeholder: t("searchPlaceholder"),
286
+ "aria-label": t("search"),
287
+ onChange: (event) => {
288
+ setQuery(event.target.value);
289
+ },
290
+ style: {
291
+ minHeight: 32,
292
+ width: 230,
293
+ maxWidth: "48%",
294
+ padding: "0 9px",
295
+ color: colors.text,
296
+ background: "transparent",
297
+ border: `1px solid ${colors.border}`,
298
+ borderRadius: 6
299
+ }
300
+ })), filteredEntries.length === 0 && (0, react.createElement)("p", { style: {
301
+ color: colors.secondary,
302
+ margin: 0
303
+ } }, t("noEntries")), filteredEntries.map((entry) => (0, react.createElement)("details", {
304
+ key: entry.id,
305
+ style: {
306
+ border: `1px solid ${colors.border}`,
307
+ borderRadius: 6,
308
+ padding: "10px 12px",
309
+ background: colors.surface
310
+ }
311
+ }, (0, react.createElement)("summary", { style: {
312
+ cursor: "pointer",
313
+ display: "flex",
314
+ gap: 8,
315
+ alignItems: "baseline"
316
+ } }, (0, react.createElement)("strong", { style: { fontSize: 13 } }, entry.title), (0, react.createElement)("span", { style: {
317
+ color: colors.secondary,
318
+ fontSize: 11
319
+ } }, entry.type)), (0, react.createElement)("p", { style: {
320
+ margin: "10px 0 0",
321
+ color: colors.secondary,
322
+ lineHeight: 1.5,
323
+ whiteSpace: "pre-wrap",
324
+ wordBreak: "break-word"
325
+ } }, entry.content), entry.tags.length > 0 && (0, react.createElement)("div", { style: {
326
+ marginTop: 10,
327
+ color: colors.accent,
328
+ fontSize: 11
329
+ } }, entry.tags.join(" · ")), entry.updatedAt !== void 0 && (0, react.createElement)("div", { style: {
330
+ marginTop: 8,
331
+ color: colors.secondary,
332
+ fontSize: 11
333
+ } }, `${t("updated")}: ${formatDate(entry.updatedAt)}`))))));
334
+ }
335
+ const inject = [
336
+ "slots",
337
+ "locale",
338
+ "sessions"
339
+ ];
340
+ function apply(ctx) {
341
+ ctx.effect(() => ctx.locale.register(NS, {
342
+ zh,
343
+ en
344
+ }), "workspace-memory: dictionaries");
345
+ const translate = ctx.locale.bind(NS);
346
+ const t = (key) => {
347
+ return translate(key) || zh[key];
348
+ };
349
+ ctx.slots.inject("settings.section", () => ctx.slots.register({
350
+ name: "settings.section",
351
+ id: "workspace-memory",
352
+ order: 50,
353
+ label: () => t("nav"),
354
+ locale: NS
355
+ }, () => (0, react.createElement)(MemorySection, {
356
+ t,
357
+ sessions: ctx.sessions
358
+ })));
359
+ }
360
+ //#endregion
361
+ exports.apply = apply;
362
+ exports.inject = inject;
363
+ return module.exports;
364
+ }
365
+ });
366
+
367
+ //# sourceMappingURL=client.js.map