@a9i5k4/dsh-auto-memory 0.1.23 → 0.1.25
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.md +24 -19
- package/README.zh-CN.md +21 -22
- package/lib/client.js +486 -79
- package/lib/index.js +283 -109
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -18,6 +18,7 @@ window.__ModuleLoader__.load({
|
|
|
18
18
|
var useState = React.useState
|
|
19
19
|
var useEffect = React.useEffect
|
|
20
20
|
var useReducer = React.useReducer
|
|
21
|
+
var useRef = React.useRef
|
|
21
22
|
|
|
22
23
|
// ───────────────────────── 控制器 ─────────────────────────
|
|
23
24
|
var listeners = new Set()
|
|
@@ -143,6 +144,7 @@ window.__ModuleLoader__.load({
|
|
|
143
144
|
readFailed: '读取失败: ', ok: '正常', refreshTime: '刷新时间', notYetShort: '尚未',
|
|
144
145
|
empty: '(空)', back: '← 返回', view: '查看',
|
|
145
146
|
clickDateViewLog: '点击日期查看当日日志(append-only):',
|
|
147
|
+
userMemoryBlock: '用户记忆(用户画像 · 跨项目):', userMemoryEmpty: '(空)', userMemoryTruncated: '(内容过长,已截断显示)',
|
|
146
148
|
appended: '已追加', notesPathLabel: '项目笔记: ',
|
|
147
149
|
notesPlaceholder: '想追加到项目笔记的内容…(保存时自动带日期标题)',
|
|
148
150
|
saving: '保存中…', append: '追加',
|
|
@@ -170,8 +172,13 @@ window.__ModuleLoader__.load({
|
|
|
170
172
|
fProjectDir: '项目记忆目录', fProjectDirHint: '相对各工作区的目录名(默认 .dsh-memory)。',
|
|
171
173
|
fInject: '注入记忆上下文', fInjectHint: '每次组装提示词时自动注入 <memory_system> 块。',
|
|
172
174
|
fBudget: '注入预算(字符)', fBudgetHint: '记忆块总预算,超出部分截断。',
|
|
173
|
-
fDays: '注入最近日志天数', fDaysHint: '会话开始时注入最近 N
|
|
175
|
+
fDays: '注入最近日志天数', fDaysHint: '会话开始时注入最近 N 天的工作日志尾部。默认 1。',
|
|
176
|
+
fExtBudget: '外部记忆注入预算(字符)', fExtBudgetHint: '外部记忆来源在上下文中的注入预算。默认 1400(路径模式下影响有限)。',
|
|
177
|
+
fConsolidateMin: '自动沉淀内容门槛(字符)', fConsolidateMinHint: '本轮 user+assistant 总字符低于此值视为寒暄跳过。默认 240。',
|
|
174
178
|
fAway: '暂离阈值(分钟)', fAwayHint: '距上次活动超过该值视为暂离,回归时自动弹出记忆窗口。默认 60。',
|
|
179
|
+
fAutoConsolidate: '自动沉淀(每轮对话结束AI评估)', fAutoConsolidateHint: '关闭后每轮对话结束不再自动调用 AI 评估与写入今日日志。',
|
|
180
|
+
fConsolidate: '自动沉淀间隔(分钟)', fConsolidateHint: '两轮自动沉淀之间的最短间隔。默认 30;非工作时间(22:00-08:00)自动翻倍,避免短时间耗尽每日额度。',
|
|
181
|
+
fConsolidateMax: '自动沉淀每日额度(次)', fConsolidateMaxHint: '每天最多触发自动沉淀的次数,到点后当天不再调用。默认 8。',
|
|
175
182
|
fAutoSum: '自动总结时间点(HH:MM,逗号分隔)', fAutoSumHint: '到点自动生成本时段总结并弹窗展示,如 12:00,18:00,22:00。空=关闭。',
|
|
176
183
|
awayTitle: '欢迎回来', awayMsg: '你离开的这段时间,我已经帮你把日志整理好了。记忆窗口已打开,可以看看这段时间的状况。',
|
|
177
184
|
sumTitle: '时段总结',
|
|
@@ -237,6 +244,7 @@ window.__ModuleLoader__.load({
|
|
|
237
244
|
readFailed: 'Read failed: ', ok: 'OK', refreshTime: 'Refreshed', notYetShort: 'never',
|
|
238
245
|
empty: '(empty)', back: '← Back', view: 'View',
|
|
239
246
|
clickDateViewLog: 'Click a date to view the daily log (append-only):',
|
|
247
|
+
userMemoryBlock: 'User memory (profile · cross-project):', userMemoryEmpty: '(empty)', userMemoryTruncated: '(content truncated for display)',
|
|
240
248
|
appended: 'Appended', notesPathLabel: 'Project notes: ',
|
|
241
249
|
notesPlaceholder: 'Content to append to project notes…(date heading added on save)',
|
|
242
250
|
saving: 'Saving…', append: 'Append',
|
|
@@ -264,8 +272,13 @@ window.__ModuleLoader__.load({
|
|
|
264
272
|
fProjectDir: 'Project memory dir', fProjectDirHint: 'Directory name relative to each workspace (default .dsh-memory).',
|
|
265
273
|
fInject: 'Inject memory context', fInjectHint: 'Auto-inject <memory_system> block into every prompt.',
|
|
266
274
|
fBudget: 'Injection budget (chars)', fBudgetHint: 'Total budget for the memory block; excess is truncated.',
|
|
267
|
-
fDays: 'Recent days injected', fDaysHint: 'Inject tails of the last N days of work logs at session start.',
|
|
275
|
+
fDays: 'Recent days injected', fDaysHint: 'Inject tails of the last N days of work logs at session start. Default 1.',
|
|
276
|
+
fExtBudget: 'External memory injection budget (chars)', fExtBudgetHint: 'Budget for external memory sources in context. Default 1400 (limited effect with path mode).',
|
|
277
|
+
fConsolidateMin: 'Auto-consolidation content threshold (chars)', fConsolidateMinHint: 'Turns with fewer combined user+assistant chars are treated as chit-chat and skipped. Default 240.',
|
|
268
278
|
fAway: 'Away threshold (minutes)', fAwayHint: 'Marked away when inactive longer than this; the memory panel auto-opens on return. Default 60.',
|
|
279
|
+
fAutoConsolidate: 'Auto-consolidation (AI review each turn end)', fAutoConsolidateHint: 'When off, no automatic AI review or daily-log writes at turn end.',
|
|
280
|
+
fConsolidate: 'Auto-consolidate interval (minutes)', fConsolidateHint: 'Minimum gap between auto-consolidations. Default 30; doubled automatically outside work hours (22:00-08:00).',
|
|
281
|
+
fConsolidateMax: 'Daily auto-consolidate quota', fConsolidateMaxHint: 'Max auto-consolidation runs per day; no more runs after the quota is reached. Default 8.',
|
|
269
282
|
fAutoSum: 'Auto summary times (HH:MM, comma-separated)', fAutoSumHint: 'Auto-generate and show a period summary at these times, e.g. 12:00,18:00,22:00. Empty = off.',
|
|
270
283
|
awayTitle: 'Welcome back', awayMsg: 'While you were away, I tidied up your logs. The memory panel is open — take a look at what happened.',
|
|
271
284
|
sumTitle: 'Period summary',
|
|
@@ -308,6 +321,15 @@ window.__ModuleLoader__.load({
|
|
|
308
321
|
var fontScale = 'lg'
|
|
309
322
|
var FONT_SCALES = { sm: '小', md: '标准', lg: '大', xl: '特大' }
|
|
310
323
|
var FONT_SCALE_VALUES = { sm: '0.9', md: '1', lg: '1.15', xl: '1.3' }
|
|
324
|
+
var accentTheme = 'deepseek'
|
|
325
|
+
var graphDensity = 'relaxed'
|
|
326
|
+
var ACCENT_VALUES = { deepseek: '#1d4ed8', graphite: '#8b949e', violet: '#9b8cff' }
|
|
327
|
+
try {
|
|
328
|
+
var savedAccent = localStorage.getItem('dsh-auto-memory.accentTheme.v1')
|
|
329
|
+
var savedDensity = localStorage.getItem('dsh-auto-memory.graphDensity.v1')
|
|
330
|
+
if (ACCENT_VALUES[savedAccent]) accentTheme = savedAccent
|
|
331
|
+
if (savedDensity === 'relaxed' || savedDensity === 'compact') graphDensity = savedDensity
|
|
332
|
+
} catch (e) {}
|
|
311
333
|
var localeListeners = new Set()
|
|
312
334
|
function t(key) { return (I18N[locale] && I18N[locale][key]) || I18N.zh[key] || key }
|
|
313
335
|
function setLocale(l) { if (l !== 'zh' && l !== 'en') return; if (l === locale) return; locale = l; localeListeners.forEach(function (fn) { try { fn(l) } catch (e) {} }) }
|
|
@@ -324,6 +346,24 @@ window.__ModuleLoader__.load({
|
|
|
324
346
|
|
|
325
347
|
// ───────────────────────── 更新弹窗 / 首次指导 ─────────────────────────
|
|
326
348
|
var CHANGELOG = {
|
|
349
|
+
'0.1.25': { zh: [
|
|
350
|
+
'文档:README 界面截图更新为最新实机截图(记忆面板概览/接续/日历/工作区导图/设置),中英双语说明。',
|
|
351
|
+
], en: [
|
|
352
|
+
'Docs: README screenshots refreshed with the latest real captures (panel overview / connect / calendar / workspace mind map / settings) with bilingual captions.',
|
|
353
|
+
] },
|
|
354
|
+
'0.1.24': { zh: [
|
|
355
|
+
'记忆面板:全新液态玻璃 UI——模块箭头滚动、抽屉丝滑展开/收起、工作区 AI 思维导图(拖动画布+缩放)、日历当天时间轴(07:00-22:00)+地点/提醒字段。',
|
|
356
|
+
'注入精简:只注入最近 1 天日志与反思精华,外部记忆改为绝对路径按需读取,新增 memory_read 工具;敏感段落(令牌/密钥)不再注入 prompt。',
|
|
357
|
+
'接续页:按来源查看内容/接入/移除(笔记与用户级独立),已接入来源显示 ✓;不再整段注入外部记忆。',
|
|
358
|
+
'设置页:全部参数可调(注入预算/天数/外部预算、自动沉淀开关/门槛/间隔/额度),浮动保存栏未保存时高亮。',
|
|
359
|
+
'稳定性:修复对话结束时 host 卡死/崩溃(惰性投影移除、超时兜底、延迟启动),自动沉淀恢复正常并每日限频。',
|
|
360
|
+
], en: [
|
|
361
|
+
'Memory panel: brand-new liquid-glass UI — arrow tab scrolling, smooth drawer transitions, AI workspace mind map (pan + zoom), day timeline (07:00-22:00) with location/reminder fields.',
|
|
362
|
+
'Lean injection: only the last day of logs and a reflection digest; external memory is read by absolute path on demand via the new memory_read tool; credentials/tokens are filtered out of the prompt.',
|
|
363
|
+
'Connect tab: per-source view/import/remove (notes vs user-level independently), imported sources show ✓; external memory is no longer injected in bulk.',
|
|
364
|
+
'Settings: every parameter is now adjustable (injection budget/days/external budget, auto-consolidation toggle/threshold/interval/quota) with a floating save bar that highlights unsaved changes.',
|
|
365
|
+
'Stability: fixed host freezes/crashes at turn end (lazy projection removed, timeout fallbacks, delayed start); auto-consolidation recovered with daily rate limiting.',
|
|
366
|
+
] },
|
|
327
367
|
'0.1.23': { zh: [
|
|
328
368
|
'修复:正式发布包首次欢迎文案仍显示“开发版”;发布转换与残留校验已加强,确保开发版和正式版身份完全隔离。',
|
|
329
369
|
], en: [
|
|
@@ -468,7 +508,10 @@ window.__ModuleLoader__.load({
|
|
|
468
508
|
reflectAuto: '/api/dsh-auto-memory/reflect-auto',
|
|
469
509
|
note: '/api/dsh-auto-memory/note',
|
|
470
510
|
external: '/api/dsh-auto-memory/external',
|
|
511
|
+
externalView: '/api/dsh-auto-memory/external-view',
|
|
512
|
+
externalRemove: '/api/dsh-auto-memory/external-remove',
|
|
471
513
|
externalImport: '/api/dsh-auto-memory/external-import',
|
|
514
|
+
calendar: '/api/dsh-auto-memory/calendar',
|
|
472
515
|
summarize: '/api/dsh-auto-memory/summarize',
|
|
473
516
|
greet: '/api/dsh-auto-memory/greet',
|
|
474
517
|
notices: '/api/dsh-auto-memory/notices',
|
|
@@ -482,13 +525,13 @@ window.__ModuleLoader__.load({
|
|
|
482
525
|
async function apiGet(path, params) {
|
|
483
526
|
var res = await fetch(path + query(params))
|
|
484
527
|
var body = await res.json().catch(function () { return {} })
|
|
485
|
-
if (!res.ok) throw new Error(body.error || ('HTTP ' + res.status))
|
|
528
|
+
if (!res.ok) throw new Error(body.error || ('GET ' + path + ' → HTTP ' + res.status))
|
|
486
529
|
return body
|
|
487
530
|
}
|
|
488
531
|
async function apiPost(path, payload) {
|
|
489
532
|
var res = await fetch(path, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(payload) })
|
|
490
533
|
var body = await res.json().catch(function () { return {} })
|
|
491
|
-
if (!res.ok) throw new Error(body.error || ('HTTP ' + res.status))
|
|
534
|
+
if (!res.ok) throw new Error(body.error || ('POST ' + path + ' → HTTP ' + res.status))
|
|
492
535
|
return body
|
|
493
536
|
}
|
|
494
537
|
|
|
@@ -526,16 +569,61 @@ window.__ModuleLoader__.load({
|
|
|
526
569
|
'[data-dam-resize]:hover { opacity: 1; }',
|
|
527
570
|
'[data-dam-btn] { border: none; background: transparent; cursor: pointer; color: inherit; opacity: .75; font-size: calc(13px * var(--dam-scale)); padding: 4px 8px; border-radius: 6px; }',
|
|
528
571
|
'[data-dam-btn]:hover { opacity: 1; background: color-mix(in srgb, var(--dsw-alias-label-secondary, #666) 16%, transparent); }',
|
|
529
|
-
'[data-dam-tabs] { display: flex;
|
|
530
|
-
'[data-dam-
|
|
531
|
-
'[data-dam-
|
|
532
|
-
'[data-dam-
|
|
572
|
+
'[data-dam-tabs-wrap] { display: flex; align-items: center; min-width: 0; border-bottom: 1px solid color-mix(in srgb, var(--dsw-alias-border-l1, rgba(128,128,128,.2)) 55%, transparent); }',
|
|
573
|
+
'[data-dam-tabs] { flex: 1; min-width: 0; overflow: hidden; padding: 5px 4px; scrollbar-width: none; -ms-overflow-style: none; }',
|
|
574
|
+
'[data-dam-tabs]::-webkit-scrollbar { display: none; }',
|
|
575
|
+
'[data-dam-tab-strip] { display: flex; width: max-content; transition: transform .42s cubic-bezier(.22,.8,.2,1); will-change: transform; }',
|
|
576
|
+
'[data-dam-tab] { flex: 0 0 auto; min-width: max-content; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; border: none; background: transparent; cursor: pointer; color: inherit; opacity: .68; padding: 6px 9px; border-radius: 7px; font-size: calc(12.5px * var(--dam-scale)); transition: color .25s ease, background .25s ease, opacity .25s ease, transform .25s ease; }',
|
|
577
|
+
'[data-dam-tabs-arrow] { flex: 0 0 26px; height: 30px; border: 0; background: transparent; color: inherit; cursor: pointer; opacity: .55; font-size: 18px; }',
|
|
578
|
+
'[data-dam-tabs-arrow]:hover:not(:disabled) { opacity: 1; background: color-mix(in srgb, var(--dam-accent, #2456c4) 16%, transparent); transform: scale(1.12); }',
|
|
579
|
+
'[data-dam-tabs-arrow]:active:not(:disabled) { transform: scale(.92); }',
|
|
580
|
+
'[data-dam-tab][data-active="true"] { position: relative; opacity: 1; background: var(--dam-accent, #2456c4); color: #fff; font-weight: 700; box-shadow: 0 3px 10px color-mix(in srgb, var(--dam-accent, #2456c4) 30%, transparent); transform: translateY(-1px); }',
|
|
581
|
+
'[data-dam-tab][data-active="true"]::before { content: ""; position: absolute; left: 3px; top: 7px; bottom: 7px; width: 3px; border-radius: 3px; background: rgba(255,255,255,.9); }',
|
|
582
|
+
'[data-dam-body] { flex: 1 1 auto; min-width: 0; min-height: 0; overflow: auto; padding: 16px; }',
|
|
583
|
+
'[data-dam-settings] { display: grid; grid-template-columns: 92px minmax(0, 1fr); gap: 18px; min-height: 100%; }',
|
|
584
|
+
'[data-dam-settings-nav] { position: sticky; top: 0; align-self: start; display: flex; flex-direction: column; gap: 4px; padding-top: 2px; }',
|
|
585
|
+
'[data-dam-settings-nav] button { border: 0; background: transparent; color: inherit; text-align: left; padding: 8px 9px; border-radius: 8px; cursor: pointer; opacity: .58; font: inherit; font-size: calc(11.5px * var(--dam-scale)); }',
|
|
586
|
+
'[data-dam-settings-nav] button[data-active="true"] { opacity: 1; color: var(--dam-accent, var(--dsw-alias-brand-primary, #4f7cff)); background: color-mix(in srgb, var(--dam-accent, #4f7cff) 11%, transparent); font-weight: 650; }',
|
|
587
|
+
'[data-dam-settings-content] { min-width: 0; padding-bottom: 24px; }',
|
|
588
|
+
'[data-dam-settings-group] { scroll-margin-top: 12px; padding-bottom: 22px; margin-bottom: 24px; border-bottom: 1px solid color-mix(in srgb, var(--dsw-alias-border-l1, #c5cbd3) 38%, transparent); }',
|
|
589
|
+
'[data-dam-settings-group] h3 { margin: 0; color: var(--dsw-alias-label-primary, #1f2328); font-size: calc(14px * var(--dam-scale)); }',
|
|
590
|
+
'[data-dam-settings-group] p { margin: 4px 0 14px; color: var(--dsw-alias-label-secondary, #68717d); font-size: calc(11.5px * var(--dam-scale)); line-height: 1.5; }',
|
|
591
|
+
'[data-dam-settings-row] { padding: 10px 0; }',
|
|
592
|
+
'[data-dam-savebar] { position: sticky; bottom: 0; z-index: 3; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding: 10px 14px; margin: 6px -16px -16px; background: color-mix(in srgb, var(--dsw-alias-bg-overlay, rgba(255,255,255,.92)) 74%, transparent); backdrop-filter: blur(16px) saturate(1.4); -webkit-backdrop-filter: blur(16px) saturate(1.4); border-top: 1px solid color-mix(in srgb, var(--dsw-alias-border-l1, #c5cbd3) 38%, transparent); border-radius: 0 0 14px 14px; transition: background .25s ease; }',
|
|
593
|
+
'[data-dam-savebar] button { opacity: .5; transition: opacity .2s ease, background .2s ease, color .2s ease; }',
|
|
594
|
+
'[data-dam-savebar] button[data-dirty="true"] { opacity: 1; background: var(--dam-accent, #1d4ed8); color: #fff; font-weight: 650; box-shadow: 0 3px 12px color-mix(in srgb, var(--dam-accent, #1d4ed8) 35%, transparent); }',
|
|
595
|
+
'[data-dam-settings-row] > [data-dam-row] { margin-bottom: 3px; }',
|
|
596
|
+
'[data-dam-graph-toolbar] { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-bottom: 1px solid color-mix(in srgb, var(--dsw-alias-border-l1, #c5cbd3) 38%, transparent); }',
|
|
597
|
+
'[data-dam-graph-toolbar] input[type="range"] { flex: 1; min-width: 90px; accent-color: var(--dam-accent, #6b98ff); }',
|
|
598
|
+
'[data-dam-graph] { position: relative; min-height: 420px; overflow: hidden; border: 1px solid color-mix(in srgb, var(--dsw-alias-border-l1, #c5cbd3) 42%, transparent); border-radius: 12px; background: color-mix(in srgb, var(--dsw-alias-bg-layer-1, #f5f6f7) 42%, transparent); }',
|
|
599
|
+
'[data-dam-graph] { cursor: grab; }',
|
|
600
|
+
'[data-dam-graph][data-panning="true"] { cursor: grabbing; user-select: none; }',
|
|
601
|
+
'[data-dam-graph] svg { display: block; width: auto; max-width: none; height: auto; min-height: 520px; transform-origin: 0 0; }',
|
|
602
|
+
'[data-dam-graph-node] { cursor: pointer; }',
|
|
603
|
+
'[data-dam-graph-legend] { display: flex; gap: 12px; flex-wrap: wrap; margin: 10px 0 14px; color: var(--dsw-alias-label-secondary, #68717d); font-size: calc(11px * var(--dam-scale)); }',
|
|
604
|
+
'[data-dam-legend-dot] { display: inline-block; width: 7px; height: 7px; border-radius: 50%; margin-right: 4px; background: var(--dam-accent, #4f7cff); }',
|
|
605
|
+
'[data-dam-legend-dot="branch"] { background: #7d8793; }',
|
|
606
|
+
'[data-dam-legend-dot="leaf"] { background: #b0b7c0; }',
|
|
533
607
|
'[data-dam-kv] { display: grid; grid-template-columns: auto 1fr; gap: 4px 12px; font-size: calc(12.5px * var(--dam-scale)); }',
|
|
534
608
|
'[data-dam-kv] b { opacity: .55; font-weight: 500; }',
|
|
535
609
|
'[data-dam-card] { border: 1px solid color-mix(in srgb, var(--dsw-alias-border-l1, rgba(128,128,128,.22)) 60%, transparent); border-radius: 9px; padding: 8px 10px; margin-bottom: 8px; font-size: calc(12.5px * var(--dam-scale));',
|
|
536
610
|
' background: color-mix(in srgb, var(--dsw-alias-bg-layer-1, rgba(128,128,128,.06)) 40%, transparent); }',
|
|
537
611
|
'[data-dam-card] .dam-date { font-weight: 600; margin-bottom: 4px; }',
|
|
538
612
|
'[data-dam-card] .dam-content { white-space: pre-wrap; word-break: break-word; max-height: 220px; overflow: auto; }',
|
|
613
|
+
'[data-dam-disclosure] { overflow: hidden; opacity: 0; max-height: 0; transform: translateY(-5px) scale(.985); transition: max-height .32s cubic-bezier(.22,.8,.2,1), opacity .2s ease, transform .28s cubic-bezier(.22,.8,.2,1); }',
|
|
614
|
+
'[data-dam-disclosure][data-phase="open"] { opacity: 1; max-height: 1800px; transform: translateY(0) scale(1); }',
|
|
615
|
+
'[data-dam-disclosure][data-phase="closing"] { opacity: 0; max-height: 0; transform: translateY(-5px) scale(.985); }',
|
|
616
|
+
'[data-dam-card], [data-dam-banner] { animation: dam-rise .34s cubic-bezier(.22,.8,.2,1) both; }',
|
|
617
|
+
'@keyframes dam-rise { from { opacity: 0; transform: translateY(7px) scale(.988); } to { opacity: 1; transform: translateY(0) scale(1); } }',
|
|
618
|
+
'@media (prefers-reduced-motion: reduce) { [data-dam-tab-strip], [data-dam-tab], [data-dam-disclosure], [data-dam-card], [data-dam-banner] { transition: none !important; animation: none !important; } }',
|
|
619
|
+
'[data-dam-calendar] { animation: dam-rise .34s cubic-bezier(.22,.8,.2,1) both; }',
|
|
620
|
+
'[data-dam-calendar] [data-dam-calendar-day] { transition: transform .18s ease, border-color .2s ease, background .2s ease, box-shadow .2s ease; }',
|
|
621
|
+
'[data-dam-calendar] [data-dam-calendar-day]:hover { transform: translateY(-1px); border-color: var(--dam-accent, #1d4ed8) !important; box-shadow: 0 4px 12px rgba(0,0,0,.08); }',
|
|
622
|
+
'[data-dam-calendar-event] { animation: dam-event-in .25s cubic-bezier(.22,.8,.2,1) both; transition: transform .18s ease, filter .18s ease; }',
|
|
623
|
+
'[data-dam-calendar-event]:hover { transform: translateX(2px); filter: brightness(1.06); }',
|
|
624
|
+
'[data-dam-calendar-modal] { animation: dam-modal-in .26s cubic-bezier(.22,.8,.2,1) both; }',
|
|
625
|
+
'@keyframes dam-event-in { from { opacity: 0; transform: translateX(-5px); } to { opacity: 1; transform: none; } }',
|
|
626
|
+
'@keyframes dam-modal-in { from { opacity: 0; transform: translateY(10px) scale(.98); } to { opacity: 1; transform: none; } }',
|
|
539
627
|
'[data-dam-banner] { border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary, #e6a23c) 55%, transparent);',
|
|
540
628
|
' background: color-mix(in srgb, var(--dsw-alias-state-warn-primary, #e6a23c) 13%, transparent); border-radius: 9px; padding: 8px 10px; margin-bottom: 10px; font-size: calc(12.5px * var(--dam-scale)); }',
|
|
541
629
|
'[data-dam-input], [data-dam-select] { width: 100%; box-sizing: border-box; background: color-mix(in srgb, var(--dsw-alias-bg-layer-1, rgba(128,128,128,.08)) 45%, transparent); color: inherit; border: 1px solid color-mix(in srgb, var(--dsw-alias-border-l1, rgba(128,128,128,.3)) 60%, transparent); border-radius: 7px; padding: 6px 8px; font: inherit; }',
|
|
@@ -547,6 +635,9 @@ window.__ModuleLoader__.load({
|
|
|
547
635
|
'[data-dam-sidebar-btn][data-active="true"] { opacity: 1; background: color-mix(in srgb, var(--dsw-alias-brand-primary, #4f7cff) 16%, transparent); color: var(--dsw-alias-brand-primary, #4f7cff); }',
|
|
548
636
|
'[data-dam-error] { color: var(--dsw-alias-state-error-primary, #d64545); font-size: 12px; margin-top: 6px; white-space: pre-wrap; }',
|
|
549
637
|
'[data-dam-muted] { opacity: .55; }',
|
|
638
|
+
'[data-dam-loading] { display: flex; align-items: center; justify-content: center; gap: 9px; min-height: 96px; color: var(--dsw-alias-label-secondary, #7d8793); font-size: calc(12px * var(--dam-scale)); }',
|
|
639
|
+
'[data-dam-spinner] { width: 18px; height: 18px; border: 2px solid color-mix(in srgb, var(--dam-accent, #4f7cff) 22%, transparent); border-top-color: var(--dam-accent, #4f7cff); border-radius: 50%; animation: dam-spin .8s linear infinite; }',
|
|
640
|
+
'@keyframes dam-spin { to { transform: rotate(360deg); } }',
|
|
550
641
|
'@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {',
|
|
551
642
|
' [data-dam-panel] { background: var(--dsw-alias-bg-overlay, #ffffff); } }',
|
|
552
643
|
].join('\n')
|
|
@@ -573,7 +664,32 @@ window.__ModuleLoader__.load({
|
|
|
573
664
|
h('div', { className: 'dam-content' }, props.children))
|
|
574
665
|
}
|
|
575
666
|
|
|
576
|
-
function Loading() {
|
|
667
|
+
function Loading(props) {
|
|
668
|
+
var label = props && props.label ? props.label : t('loading')
|
|
669
|
+
return h('div', { 'data-dam-loading': '' }, h('span', { 'data-dam-spinner': '', 'aria-hidden': 'true' }), h('span', null, label))
|
|
670
|
+
}
|
|
671
|
+
function AnimatedDisclosure(props) {
|
|
672
|
+
var open = !!props.open
|
|
673
|
+
var shownPair = useState(open)
|
|
674
|
+
var shown = shownPair[0]
|
|
675
|
+
var setShown = shownPair[1]
|
|
676
|
+
var phasePair = useState(open ? 'open' : 'closed')
|
|
677
|
+
var phase = phasePair[0]
|
|
678
|
+
var setPhase = phasePair[1]
|
|
679
|
+
useEffect(function () {
|
|
680
|
+
var timer
|
|
681
|
+
if (open) {
|
|
682
|
+
setShown(true)
|
|
683
|
+
timer = setTimeout(function () { setPhase('open') }, 16)
|
|
684
|
+
} else if (shown) {
|
|
685
|
+
setPhase('closing')
|
|
686
|
+
timer = setTimeout(function () { setShown(false); setPhase('closed') }, 260)
|
|
687
|
+
}
|
|
688
|
+
return function () { if (timer) clearTimeout(timer) }
|
|
689
|
+
}, [open])
|
|
690
|
+
if (!shown) return null
|
|
691
|
+
return h('div', { 'data-dam-disclosure': '', 'data-phase': phase }, props.children)
|
|
692
|
+
}
|
|
577
693
|
|
|
578
694
|
// ───────────────────────── 侧边栏入口 ─────────────────────────
|
|
579
695
|
function SidebarButton() {
|
|
@@ -684,7 +800,7 @@ window.__ModuleLoader__.load({
|
|
|
684
800
|
h('div', { style: { fontWeight: 600, fontSize: 'calc(12.5px * var(--dam-scale))', lineHeight: 1.5 } }, (isOpen ? '▼ ' : '▶ ') + bigTitle),
|
|
685
801
|
h('div', { 'data-dam-muted': '', style: { fontSize: 'calc(11px * var(--dam-scale))', marginTop: '2px' } },
|
|
686
802
|
dr.label + ' · ' + dr.items.length + t('logEntries') + (cached && cached.at ? ' · ' + t('generatedAt') + new Date(cached.at).toLocaleTimeString() : ''))),
|
|
687
|
-
isOpen
|
|
803
|
+
h(AnimatedDisclosure, { open: isOpen }, h('div', { style: { padding: '4px 2px 2px 8px' } },
|
|
688
804
|
cached && cached.works && cached.works.length ? cached.works.map(function (w, wi) {
|
|
689
805
|
var sk = dr.key + ':w' + wi
|
|
690
806
|
var sOpen = subOpenMap[sk] !== undefined ? subOpenMap[sk] : false
|
|
@@ -702,7 +818,7 @@ window.__ModuleLoader__.load({
|
|
|
702
818
|
})) : null)
|
|
703
819
|
}) : cached && cached.failed ? h('div', { 'data-dam-hint': '', style: { padding: '4px 6px' } }, t('summaryFailed'))
|
|
704
820
|
: cached && cached.summary ? h('div', { 'data-dam-hint': '', style: { padding: '4px 6px' } }, cached.summary)
|
|
705
|
-
: h('div', { 'data-dam-hint': '', style: { padding: '4px 6px' } }, t('summarizing')))
|
|
821
|
+
: h('div', { 'data-dam-hint': '', style: { padding: '4px 6px' } }, t('summarizing'))))))
|
|
706
822
|
})(drawers[d])
|
|
707
823
|
}
|
|
708
824
|
// 待反思提醒
|
|
@@ -728,6 +844,9 @@ window.__ModuleLoader__.load({
|
|
|
728
844
|
var wsPair = useState(null)
|
|
729
845
|
var wsData = wsPair[0]
|
|
730
846
|
var setWsData = wsPair[1]
|
|
847
|
+
var wsOpenPair = useState(false)
|
|
848
|
+
var wsOpen = wsOpenPair[0]
|
|
849
|
+
var setWsOpen = wsOpenPair[1]
|
|
731
850
|
// 每次进入面板 / 点刷新(nonce 变化)/ 面板打开期间每 30s 自动重拉,保证自动沉淀等数据新鲜
|
|
732
851
|
useEffect(function () {
|
|
733
852
|
var alive = true
|
|
@@ -768,19 +887,12 @@ window.__ModuleLoader__.load({
|
|
|
768
887
|
return h('div', null,
|
|
769
888
|
// 今日问候卡:问候语 + 昨天时间轴 + 提醒(纯 GUI 渲染,不干扰对话流)
|
|
770
889
|
h(GreetingCard, { greeting: state.greeting, periodSummary: state.periodSummary, t: t, nonce: props && props.nonce }),
|
|
771
|
-
//
|
|
772
|
-
h('div', { style: { marginTop: '
|
|
773
|
-
h('
|
|
774
|
-
wsData && wsData.workspaces && wsData.workspaces.length
|
|
775
|
-
? wsData.workspaces.
|
|
776
|
-
|
|
777
|
-
h('div', { style: { fontWeight: 600, fontSize: 'calc(12px * var(--dam-scale))' } }, ws.name + (ws.dateRange ? ' · ' + ws.dateRange : '')),
|
|
778
|
-
ws.summary ? h('div', { style: { fontSize: 'calc(12px * var(--dam-scale))', lineHeight: 1.5, marginTop: '3px' } }, ws.summary) : h('div', { 'data-dam-hint': '' }, t('wsNoSummary')),
|
|
779
|
-
(ws.items && ws.items.length) ? ws.items.map(function (it, i) {
|
|
780
|
-
return h('div', { key: i, style: { fontSize: 'calc(11.5px * var(--dam-scale))', marginTop: '2px', opacity: 0.75 } }, '· ' + it)
|
|
781
|
-
}) : null)
|
|
782
|
-
})
|
|
783
|
-
: h('div', { 'data-dam-hint': '' }, t('wsGenerating'))),
|
|
890
|
+
// 跨工作区总结默认折叠,首页把空间留给问候与今日状态
|
|
891
|
+
h('div', { 'data-dam-collapsible': '', style: { marginTop: '16px' } },
|
|
892
|
+
h('button', { 'data-dam-btn': '', onClick: function () { setWsOpen(!wsOpen) }, style: { width: '100%', textAlign: 'left', padding: '11px 12px', fontWeight: 650, borderBottom: '1px solid color-mix(in srgb, var(--dsw-alias-border-l1, #c5cbd3) 38%, transparent)' } }, (wsOpen ? '▾ ' : '▸ ') + t('wsOverview')),
|
|
893
|
+
h(AnimatedDisclosure, { open: wsOpen }, wsData && wsData.workspaces && wsData.workspaces.length
|
|
894
|
+
? h('div', { style: { paddingTop: '10px' } }, h(WorkspaceGraph, { workspaces: wsData.workspaces, graph: wsData.graph, onSelect: function () {} }))
|
|
895
|
+
: h(Loading, { label: locale === 'zh' ? '正在生成跨工作区总结…' : 'Generating workspace overview…' }))),
|
|
784
896
|
state.pendingReflection
|
|
785
897
|
? h(Banner, null, t('pendingReflection') + state.pendingReflection + t('pendingReflectionHint'))
|
|
786
898
|
: null,
|
|
@@ -822,9 +934,16 @@ window.__ModuleLoader__.load({
|
|
|
822
934
|
var contentPair = useState('')
|
|
823
935
|
var content = contentPair[0]
|
|
824
936
|
var setContent = contentPair[1]
|
|
937
|
+
var userPair = useState('')
|
|
938
|
+
var userText = userPair[0]
|
|
939
|
+
var setUserText = userPair[1]
|
|
940
|
+
var userTruncPair = useState(false)
|
|
941
|
+
var userTruncated = userTruncPair[0]
|
|
942
|
+
var setUserTruncated = userTruncPair[1]
|
|
825
943
|
useEffect(function () {
|
|
826
944
|
var alive = true
|
|
827
945
|
apiGet(API.list).then(function (d) { if (alive) setData(d) }).catch(function () {})
|
|
946
|
+
apiGet(API.state).then(function (s) { if (alive && s) { if (typeof s.userText === 'string') setUserText(s.userText); setUserTruncated(!!s.userTextTruncated) } }).catch(function () {})
|
|
828
947
|
return function () { alive = false }
|
|
829
948
|
}, [])
|
|
830
949
|
useEffect(function () {
|
|
@@ -847,6 +966,11 @@ window.__ModuleLoader__.load({
|
|
|
847
966
|
h('button', { 'data-dam-btn': '', onClick: function () { setOpen(log.date + '.md') } }, t('view'))))
|
|
848
967
|
})(data.logs[i])
|
|
849
968
|
}
|
|
969
|
+
// 三级记忆之用户级:当日日志下方展示用户画像(跨项目规则/偏好)
|
|
970
|
+
rows.push(h('div', { 'data-dam-hint': '', style: { marginTop: '12px' } }, t('userMemoryBlock')))
|
|
971
|
+
rows.push(h(Card, { title: 'MEMORY.md (' + (locale === 'zh' ? '用户级' : 'user-level') + ')' },
|
|
972
|
+
h('div', { 'data-dam-content': '' }, userText || t('userMemoryEmpty')),
|
|
973
|
+
userTruncated ? h('div', { 'data-dam-hint': '' }, t('userMemoryTruncated')) : null))
|
|
850
974
|
}
|
|
851
975
|
return h('div', null, rows)
|
|
852
976
|
}
|
|
@@ -977,16 +1101,99 @@ window.__ModuleLoader__.load({
|
|
|
977
1101
|
h('input', { 'data-dam-input': '', placeholder: t('searchPlaceholder'), value: q, onChange: function (e) { setQ(e.target.value) }, onKeyDown: function (e) { if (e.key === 'Enter') search() } }),
|
|
978
1102
|
h('button', { 'data-dam-btn': '', onClick: search, disabled: busy }, t('searchBtn')),
|
|
979
1103
|
h('button', { 'data-dam-btn': '', onClick: smartSearch, disabled: busy }, t('smartSearch'))),
|
|
1104
|
+
busy ? h(Loading, { label: locale === 'zh' ? 'AI 正在分析记忆…' : 'AI is analyzing memory…' }) : null,
|
|
980
1105
|
smart ? h(Card, { title: t('smartAnswer') },
|
|
981
1106
|
h('div', { 'data-dam-content': '' }, smart.answer || t('empty')),
|
|
982
1107
|
smart.keywords && smart.keywords.length ? h('div', { 'data-dam-hint': '', style: { marginTop: '6px' } }, t('keywordsLabel') + smart.keywords.join(' / ')) : null,
|
|
983
|
-
smart.hits && smart.hits.length ? h('div', { 'data-dam-hint': '', style: { marginTop: '6px' } },
|
|
984
|
-
smart.hits.map(function (
|
|
1108
|
+
Array.isArray(smart.hits) && smart.hits.length ? h('div', { 'data-dam-hint': '', style: { marginTop: '6px' } },
|
|
1109
|
+
smart.hits.map(function (hit, i) { return hit && typeof hit === 'object' ? h('div', { key: i, style: { marginTop: '3px', overflowWrap: 'anywhere' } }, '· [' + String(hit.where || '') + '] ' + String(hit.line || '')) : null })) : null)
|
|
985
1110
|
: null,
|
|
986
1111
|
result ? h(Card, { title: t('resultTitle') }, h('div', { 'data-dam-content': '' }, result)) : null)
|
|
987
1112
|
}
|
|
988
1113
|
|
|
989
1114
|
// ───────────────────────── 工作区总览页签(跨工作区全局总结) ─────────────────────────
|
|
1115
|
+
function graphKeywords(text) {
|
|
1116
|
+
return String(text || '').toLowerCase().split(/[\s,,。::;;/|()[\]{}]+/).filter(function (x) { return x.length >= 3 }).slice(0, 18)
|
|
1117
|
+
}
|
|
1118
|
+
function WorkspaceGraph(props) {
|
|
1119
|
+
var workspaces = props.workspaces || []
|
|
1120
|
+
var panPair = useState({ x: 0, y: 0 })
|
|
1121
|
+
var pan = panPair[0]
|
|
1122
|
+
var setPan = panPair[1]
|
|
1123
|
+
var dragPair = useState(false)
|
|
1124
|
+
var panning = dragPair[0]
|
|
1125
|
+
var setPanning = dragPair[1]
|
|
1126
|
+
var startPair = useState(null)
|
|
1127
|
+
var dragStart = startPair[0]
|
|
1128
|
+
var setDragStart = startPair[1]
|
|
1129
|
+
function pointerDown(ev) {
|
|
1130
|
+
if (ev.button !== 0 || (ev.target && ev.target.closest && ev.target.closest('[data-dam-graph-node]'))) return
|
|
1131
|
+
ev.preventDefault()
|
|
1132
|
+
try { if (ev.currentTarget.setPointerCapture) ev.currentTarget.setPointerCapture(ev.pointerId) } catch (e) {}
|
|
1133
|
+
setPanning(true)
|
|
1134
|
+
setDragStart({ x: ev.clientX, y: ev.clientY, px: pan.x, py: pan.y, moved: false, pointerId: ev.pointerId })
|
|
1135
|
+
}
|
|
1136
|
+
function pointerMove(ev) {
|
|
1137
|
+
if (!panning || !dragStart || ev.pointerId !== dragStart.pointerId) return
|
|
1138
|
+
var dx = ev.clientX - dragStart.x, dy = ev.clientY - dragStart.y
|
|
1139
|
+
if (!dragStart.moved && Math.abs(dx) + Math.abs(dy) < 3) return
|
|
1140
|
+
if (!dragStart.moved) { dragStart = Object.assign({}, dragStart, { moved: true }); setDragStart(dragStart) }
|
|
1141
|
+
setPan({ x: dragStart.px + dx, y: dragStart.py + dy })
|
|
1142
|
+
}
|
|
1143
|
+
function pointerUp(ev) {
|
|
1144
|
+
if (!panning || !dragStart || (ev && ev.pointerId !== dragStart.pointerId)) return
|
|
1145
|
+
try { if (ev.currentTarget.releasePointerCapture) ev.currentTarget.releasePointerCapture(dragStart.pointerId) } catch (e) {}
|
|
1146
|
+
setPanning(false); setDragStart(null)
|
|
1147
|
+
}
|
|
1148
|
+
var onSelect = props.onSelect || function () {}
|
|
1149
|
+
var graph = props.graph || {}
|
|
1150
|
+
var scale = Number(props.scale) || 1.2
|
|
1151
|
+
var compact = graphDensity === 'compact'
|
|
1152
|
+
var columns = Math.min(2, Math.max(1, workspaces.length))
|
|
1153
|
+
var rows = Math.ceil(workspaces.length / columns)
|
|
1154
|
+
var width = 920
|
|
1155
|
+
var colGap = 420
|
|
1156
|
+
var rowGap = compact ? 220 : 270
|
|
1157
|
+
var height = Math.max(420, rows * rowGap + 80)
|
|
1158
|
+
var centers = workspaces.map(function (ws, i) {
|
|
1159
|
+
var col = i % columns, row = Math.floor(i / columns)
|
|
1160
|
+
return { ws: ws, x: 160 + col * colGap, y: 72 + row * rowGap, i: i }
|
|
1161
|
+
})
|
|
1162
|
+
var edges = []
|
|
1163
|
+
;(graph.links || []).forEach(function (link) {
|
|
1164
|
+
var from = centers.find(function (c) { return c.ws.name === link.from })
|
|
1165
|
+
var to = centers.find(function (c) { return c.ws.name === link.to })
|
|
1166
|
+
if (from && to) edges.push([from, to, link.label || ''])
|
|
1167
|
+
})
|
|
1168
|
+
var children = []
|
|
1169
|
+
centers.forEach(function (c) {
|
|
1170
|
+
var topics = c.ws.graphTopics && c.ws.graphTopics.length ? c.ws.graphTopics : (c.ws.items || []).map(function (x) { return { label: x, detail: '' } })
|
|
1171
|
+
topics.slice(0, compact ? 3 : 4).forEach(function (topic, j) {
|
|
1172
|
+
var col = j % 2, row = Math.floor(j / 2)
|
|
1173
|
+
children.push({ center: c, item: topic, x: c.x - 105 + col * 210, y: c.y + 82 + row * 56, j: j })
|
|
1174
|
+
})
|
|
1175
|
+
})
|
|
1176
|
+
return h('div', { 'data-dam-graph': '', 'data-panning': panning ? 'true' : undefined, onPointerDown: pointerDown, onPointerMove: pointerMove, onPointerUp: pointerUp, onPointerCancel: pointerUp, onLostPointerCapture: pointerUp },
|
|
1177
|
+
h('svg', { viewBox: '0 0 ' + width + ' ' + height, width: Math.round(width * scale), height: Math.round(height * scale), role: 'img', 'aria-label': t('wsOverview'), style: { touchAction: 'none', userSelect: 'none' } },
|
|
1178
|
+
h('g', { transform: 'translate(' + (pan.x / scale) + ' ' + (pan.y / scale) + ')' },
|
|
1179
|
+
h('g', null, edges.map(function (e, i) {
|
|
1180
|
+
return h('g', { key: 'cross-' + i }, h('line', { x1: e[0].x, y1: e[0].y, x2: e[1].x, y2: e[1].y, stroke: 'var(--dam-accent, #4f7cff)', strokeOpacity: .35, strokeWidth: 1.5, strokeDasharray: '5 6' }), e[2] ? h('text', { x: (e[0].x + e[1].x) / 2, y: (e[0].y + e[1].y) / 2 - 4, textAnchor: 'middle', fontSize: 8, fill: 'var(--dam-accent, #4f7cff)' }, e[2].slice(0, 16)) : null)
|
|
1181
|
+
})),
|
|
1182
|
+
h('g', null, children.map(function (n, i) {
|
|
1183
|
+
return h('g', { key: 'branch-' + i },
|
|
1184
|
+
h('line', { x1: n.center.x, y1: n.center.y + 38, x2: n.x, y2: n.y - 22, stroke: '#8b949e', strokeOpacity: .48, strokeWidth: 1.2 }),
|
|
1185
|
+
h('rect', { x: n.x - (compact ? 82 : 92), y: n.y - 22, width: compact ? 164 : 184, height: 44, rx: 10, fill: 'color-mix(in srgb, var(--dsw-alias-bg-overlay, #fff) 92%, transparent)', stroke: 'color-mix(in srgb, var(--dam-accent, #1d4ed8) 42%, #8b949e)', strokeOpacity: .8 }),
|
|
1186
|
+
h('text', { x: n.x, y: n.y - 5, textAnchor: 'middle', fontSize: compact ? 9.5 : 10.5, fontWeight: 650, fill: 'currentColor' }, String(n.item && n.item.label || n.item || '').slice(0, 22)),
|
|
1187
|
+
h('text', { x: n.x, y: n.y + 10, textAnchor: 'middle', fontSize: 8, fill: '#7d8793' }, String(n.item && n.item.detail || '').slice(0, 26)))
|
|
1188
|
+
})),
|
|
1189
|
+
h('g', null, centers.map(function (c) {
|
|
1190
|
+
return h('g', { key: c.ws.path, 'data-dam-graph-node': '', onPointerDown: function (ev) { ev.stopPropagation() }, onClick: function () { onSelect(c.ws) } },
|
|
1191
|
+
h('rect', { x: c.x - 100, y: c.y - 38, width: 200, height: 76, rx: 16, fill: 'color-mix(in srgb, var(--dam-accent, #1d4ed8) 22%, var(--dsw-alias-bg-overlay, #fff))', stroke: 'var(--dam-accent, #1d4ed8)', strokeWidth: 2 }),
|
|
1192
|
+
h('text', { x: c.x, y: c.y - 5, textAnchor: 'middle', fontSize: compact ? 10.5 : 12, fontWeight: 650, fill: 'currentColor' }, h('tspan', { x: c.x, dy: 0 }, String(c.ws.name || '').slice(0, 12)), h('tspan', { x: c.x, dy: 13 }, String(c.ws.name || '').slice(12, 24))),
|
|
1193
|
+
h('text', { x: c.x, y: c.y + 15, textAnchor: 'middle', fontSize: 8, fill: '#7d8793' }, (c.ws.logCount || 0) + ' ' + t('logEntries')))
|
|
1194
|
+
}))))
|
|
1195
|
+
)
|
|
1196
|
+
}
|
|
990
1197
|
function WorkspaceTab() {
|
|
991
1198
|
var dataPair = useState(null)
|
|
992
1199
|
var data = dataPair[0]
|
|
@@ -1001,20 +1208,32 @@ window.__ModuleLoader__.load({
|
|
|
1001
1208
|
.catch(function () { setBusy(false) })
|
|
1002
1209
|
}
|
|
1003
1210
|
useEffect(function () { load(false) }, [])
|
|
1004
|
-
|
|
1211
|
+
var selectedPair = useState(null)
|
|
1212
|
+
var selected = selectedPair[0]
|
|
1213
|
+
var setSelected = selectedPair[1]
|
|
1214
|
+
var collapsedPair = useState({})
|
|
1215
|
+
var collapsedByPath = collapsedPair[0]
|
|
1216
|
+
var setCollapsedByPath = collapsedPair[1]
|
|
1217
|
+
var graphScalePair = useState(1.0)
|
|
1218
|
+
var graphScale = graphScalePair[0]
|
|
1219
|
+
var setGraphScale = graphScalePair[1]
|
|
1220
|
+
if (!data) return h('div', null, busy ? h(Loading, { label: locale === 'zh' ? 'AI 正在整理工作区…' : 'AI is mapping workspaces…' }) : h(Loading))
|
|
1221
|
+
var workspaces = data.workspaces || []
|
|
1005
1222
|
return h('div', null,
|
|
1006
1223
|
h('div', { 'data-dam-row': '' },
|
|
1007
1224
|
h('button', { 'data-dam-btn': '', onClick: function () { load(true) }, disabled: busy }, busy ? t('refreshing') : t('refresh')),
|
|
1008
1225
|
h('span', { 'data-dam-hint': '' }, data.cached ? (t('generatedAt') + new Date(data.generatedAt).toLocaleTimeString()) : '')),
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
h('div', { 'data-dam-
|
|
1017
|
-
|
|
1226
|
+
workspaces.length ? h('div', null,
|
|
1227
|
+
h('div', { 'data-dam-hint': '', style: { margin: '5px 0 8px' } }, locale === 'zh' ? '中心节点代表工作区;分支为记忆主题;虚线表示共享主题。' : 'Centers are workspaces, branches are topics, and dashed links show shared themes.'),
|
|
1228
|
+
h('div', { 'data-dam-graph-toolbar': '' }, h('span', { 'data-dam-hint': '' }, locale === 'zh' ? '思维导图大小' : 'Map size'), h('input', { type: 'range', min: '0.55', max: '1.75', step: '0.05', value: graphScale, 'aria-label': locale === 'zh' ? '调整思维导图大小' : 'Adjust map size', onChange: function (e) { setGraphScale(Number(e.target.value) || 1.0) } }), h('span', { 'data-dam-hint': '' }, Math.round(graphScale * 100) + '%'), h('button', { 'data-dam-btn': '', title: locale === 'zh' ? '重置视图' : 'Reset view', onClick: function () { setGraphScale(1.0) } }, '⌂')),
|
|
1229
|
+
h('div', { 'data-dam-hint': '' }, locale === 'zh' ? '点击工作区卡片查看摘要;拖动滑块调整图的大小。' : 'Select a workspace card for details; use the slider to resize the map.'),
|
|
1230
|
+
h(WorkspaceGraph, { workspaces: workspaces, graph: data.graph, scale: graphScale, onSelect: function (ws) { setSelected(ws); var n = Object.assign({}, collapsedByPath); n[ws.path] = false; setCollapsedByPath(n) } }),
|
|
1231
|
+
h('div', { style: { marginTop: '12px' } }, workspaces.map(function (ws) {
|
|
1232
|
+
var open = collapsedByPath[ws.path] === false
|
|
1233
|
+
return h('div', { key: ws.path, 'data-dam-card': '', style: { marginBottom: '8px', padding: '0' } },
|
|
1234
|
+
h('button', { 'data-dam-btn': '', 'aria-expanded': open ? 'true' : 'false', onClick: function () { var n = Object.assign({}, collapsedByPath); n[ws.path] = !open; setCollapsedByPath(n); setSelected(ws) }, style: { width: '100%', textAlign: 'left', padding: '10px 12px', fontWeight: 650 } }, (open ? '▾ ' : '▸ ') + ws.name + (ws.dateRange ? ' · ' + ws.dateRange : '')),
|
|
1235
|
+
h(AnimatedDisclosure, { open: open }, h('div', { style: { padding: '4px 12px 12px' } }, ws.summary ? h('div', { 'data-dam-content': '' }, ws.summary) : null, (ws.items || []).map(function (it, i) { return h('div', { key: i, style: { fontSize: 'calc(12px * var(--dam-scale))', marginTop: '4px', lineHeight: 1.55 } }, '· ' + it) }), h('div', { 'data-dam-hint': '' }, ws.path + ' · ' + (ws.logCount || 0) + t('logEntries')))))
|
|
1236
|
+
})) ) : h('div', { 'data-dam-hint': '' }, t('wsNone')))
|
|
1018
1237
|
}
|
|
1019
1238
|
|
|
1020
1239
|
// ───────────────────────── 日历页签 ─────────────────────────
|
|
@@ -1036,11 +1255,20 @@ window.__ModuleLoader__.load({
|
|
|
1036
1255
|
var draftPair = useState(null)
|
|
1037
1256
|
var draft = draftPair[0] // {date, time, quadrant, title}
|
|
1038
1257
|
var setDraft = draftPair[1]
|
|
1258
|
+
var dayViewPair = useState(null)
|
|
1259
|
+
var dayView = dayViewPair[0]
|
|
1260
|
+
var setDayView = dayViewPair[1]
|
|
1039
1261
|
var msgPair = useState('')
|
|
1040
1262
|
var msg = msgPair[0]
|
|
1041
1263
|
var setMsg = msgPair[1]
|
|
1264
|
+
var savingPair = useState(false)
|
|
1265
|
+
var saving = savingPair[0]
|
|
1266
|
+
var setSaving = savingPair[1]
|
|
1267
|
+
var calErrorPair = useState('')
|
|
1268
|
+
var calError = calErrorPair[0]
|
|
1269
|
+
var setCalError = calErrorPair[1]
|
|
1042
1270
|
function load() {
|
|
1043
|
-
apiGet(API.calendar).then(function (d) { if (d) setData(d) }).catch(function () {})
|
|
1271
|
+
apiGet(API.calendar).then(function (d) { if (d) { setData(d); setCalError('') } }).catch(function (e) { setCalError(t('failed') + e.message) })
|
|
1044
1272
|
}
|
|
1045
1273
|
useEffect(function () {
|
|
1046
1274
|
load()
|
|
@@ -1073,7 +1301,7 @@ window.__ModuleLoader__.load({
|
|
|
1073
1301
|
h('button', { 'data-dam-btn': '', onClick: function () { moveMonth(-1) } }, '◀'),
|
|
1074
1302
|
h('span', { style: { fontWeight: 700, flex: 1, textAlign: 'center' } }, month.year + ' / ' + String(month.mon).padStart(2, '0')),
|
|
1075
1303
|
h('button', { 'data-dam-btn': '', onClick: function () { moveMonth(1) } }, '▶'),
|
|
1076
|
-
h('button', { 'data-dam-btn': '', onClick: function () { setDraft({ date: today, time: '09:00', quadrant: '重要不紧急', title: '' }) } }, '+ ' + t('addItem'))))
|
|
1304
|
+
h('button', { 'data-dam-btn': '', onClick: function () { setDraft({ date: today, time: '09:00', quadrant: '重要不紧急', title: '', location: '', reminder: '', note: '' }) } }, '+ ' + t('addItem'))))
|
|
1077
1305
|
// 图例
|
|
1078
1306
|
rows.push(h('div', { 'data-dam-row': '', style: { flexWrap: 'wrap' } },
|
|
1079
1307
|
Object.keys(QUADRANT_STYLE).map(function (q) {
|
|
@@ -1095,7 +1323,8 @@ window.__ModuleLoader__.load({
|
|
|
1095
1323
|
var dayNum = Number(cell.slice(8))
|
|
1096
1324
|
week.push(h('div', {
|
|
1097
1325
|
key: cell,
|
|
1098
|
-
|
|
1326
|
+
'data-dam-calendar-day': '',
|
|
1327
|
+
onClick: function () { setDayView(cell) },
|
|
1099
1328
|
style: {
|
|
1100
1329
|
minHeight: '64px', padding: '4px', cursor: 'pointer', borderRadius: '8px',
|
|
1101
1330
|
border: '1px solid ' + (isToday ? 'var(--dsw-alias-brand-primary, #4f7cff)' : 'color-mix(in srgb, var(--dsw-alias-border-l1, rgba(128,128,128,.3)) 55%, transparent)'),
|
|
@@ -1108,6 +1337,7 @@ window.__ModuleLoader__.load({
|
|
|
1108
1337
|
var qs = QUADRANT_STYLE[en.quadrant] || QUADRANT_STYLE['未分类']
|
|
1109
1338
|
return h('div', {
|
|
1110
1339
|
key: en.time + en.title,
|
|
1340
|
+
'data-dam-calendar-event': '',
|
|
1111
1341
|
title: en.time + ' ' + en.title,
|
|
1112
1342
|
onClick: function (ev) { ev.stopPropagation(); toggleDone(en) },
|
|
1113
1343
|
style: {
|
|
@@ -1125,19 +1355,38 @@ window.__ModuleLoader__.load({
|
|
|
1125
1355
|
}
|
|
1126
1356
|
rows.push(h('div', null, gridRows))
|
|
1127
1357
|
function toggleDone(en) {
|
|
1358
|
+
if (saving) return
|
|
1359
|
+
setSaving(true); setCalError('')
|
|
1128
1360
|
apiPost(API.calendar, { action: en.done ? 'remove' : 'done', date: en.date, time: en.time, title: en.title }).then(function (d) {
|
|
1129
|
-
setMsg(d.result || ''); load()
|
|
1130
|
-
}).catch(function (e) {
|
|
1361
|
+
setMsg(d.result || ''); setSaving(false); load()
|
|
1362
|
+
}).catch(function (e) { setSaving(false); setCalError(t('failed') + e.message) })
|
|
1131
1363
|
}
|
|
1132
1364
|
function saveDraft() {
|
|
1133
|
-
if (!draft || !draft.title.trim()) {
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1365
|
+
if (!draft || !draft.title.trim()) { setCalError(t('needTitle')); return }
|
|
1366
|
+
if (saving) return
|
|
1367
|
+
setSaving(true); setCalError('')
|
|
1368
|
+
apiPost(API.calendar, { date: draft.date, time: draft.time, quadrant: draft.quadrant, title: draft.title.trim(), note: [draft.location ? (locale === 'zh' ? '地点: ' : 'Location: ') + draft.location : '', draft.reminder ? (locale === 'zh' ? '提醒: ' : 'Reminder: ') + draft.reminder : '', draft.note || ''].filter(Boolean).join(' | ') }).then(function (d) {
|
|
1369
|
+
setMsg(d.result || t('saved')); setSaving(false); setDraft(null); load()
|
|
1370
|
+
}).catch(function (e) { setSaving(false); setCalError(t('failed') + e.message) })
|
|
1371
|
+
}
|
|
1372
|
+
// 日期格先打开当天时间轴;点击某个时间槽才创建事件。
|
|
1373
|
+
if (dayView) {
|
|
1374
|
+
var timeline = []
|
|
1375
|
+
for (var hourSlot = 7; hourSlot <= 22; hourSlot++) {
|
|
1376
|
+
(function (hourValue) {
|
|
1377
|
+
var hourText = String(hourValue).padStart(2, '0') + ':00'
|
|
1378
|
+
var hourEvents = dayEntries(dayView).filter(function (en) { return String(en.time || '').slice(0, 2) === String(hourValue).padStart(2, '0') })
|
|
1379
|
+
timeline.push(h('div', { key: hourText, 'data-dam-calendar-slot': '', onClick: function () { setDayView(null); setDraft({ date: dayView, time: hourText, quadrant: '重要不紧急', title: '', location: '', reminder: '', note: '' }) } },
|
|
1380
|
+
h('div', { style: { flex: '0 0 50px', fontSize: 'calc(11px * var(--dam-scale))', opacity: .65 } }, hourText),
|
|
1381
|
+
h('div', { style: { minHeight: '34px', flex: 1, borderLeft: '2px solid color-mix(in srgb, var(--dam-accent, #1d4ed8) 24%, transparent)', paddingLeft: '9px' } }, hourEvents.length ? hourEvents.map(function (en) { var qs = QUADRANT_STYLE[en.quadrant] || QUADRANT_STYLE['未分类']; return h('div', { key: en.time + en.title, 'data-dam-calendar-event': '', onClick: function (ev) { ev.stopPropagation(); toggleDone(en) }, style: { marginBottom: '4px', padding: '4px 7px', borderRadius: 6, background: 'color-mix(in srgb, ' + qs.color + ' 18%, transparent)', color: qs.color, textDecoration: en.done ? 'line-through' : 'none' } }, (en.time || '') + ' ' + en.title + (en.note ? ' · ' + en.note : '')) }) : h('span', { 'data-dam-hint': '' }, locale === 'zh' ? '点击添加事件' : 'Click to add event'))))
|
|
1382
|
+
})(hourSlot)
|
|
1383
|
+
}
|
|
1384
|
+
rows.push(h('div', { 'data-dam-calendar-modal': '', style: { position: 'absolute', inset: 0, zIndex: 10, overflow: 'auto', borderRadius: '16px', background: 'color-mix(in srgb, var(--dsw-alias-bg-overlay, rgba(255,255,255,.9)) 78%, transparent)', backdropFilter: 'blur(20px) saturate(1.4)', WebkitBackdropFilter: 'blur(20px) saturate(1.4)', padding: '16px' } }, h('div', { 'data-dam-row': '' }, h('div', { style: { fontWeight: 700, flex: 1 } }, dayView + ' · ' + (locale === 'zh' ? '当天安排' : 'Day schedule')), h('button', { 'data-dam-btn': '', onClick: function () { setDayView(null) } }, '✕')), timeline))
|
|
1137
1385
|
}
|
|
1138
1386
|
// 添加/编辑浮层(液态玻璃)
|
|
1139
1387
|
if (draft) {
|
|
1140
1388
|
rows.push(h('div', {
|
|
1389
|
+
'data-dam-calendar-modal': '',
|
|
1141
1390
|
style: {
|
|
1142
1391
|
position: 'absolute', inset: 0, zIndex: 10, borderRadius: '16px',
|
|
1143
1392
|
background: 'color-mix(in srgb, var(--dsw-alias-bg-overlay, rgba(255,255,255,.9)) 70%, transparent)',
|
|
@@ -1152,12 +1401,17 @@ window.__ModuleLoader__.load({
|
|
|
1152
1401
|
h('input', { 'data-dam-input': '', type: 'time', value: draft.time, onChange: function (e) { var n = Object.assign({}, draft); n.time = e.target.value || '09:00'; setDraft(n) } }),
|
|
1153
1402
|
h('select', { 'data-dam-select': '', value: draft.quadrant, onChange: function (e) { var n = Object.assign({}, draft); n.quadrant = e.target.value; setDraft(n) } },
|
|
1154
1403
|
['重要紧急', '重要不紧急', '紧急不重要', '不重要不紧急'].map(function (q) { return h('option', { key: q, value: q }, t(QUADRANT_I18N[q])) }))),
|
|
1404
|
+
h('input', { 'data-dam-input': '', placeholder: locale === 'zh' ? '地点(可选)' : 'Location (optional)', value: draft.location || '', onChange: function (e) { var n = Object.assign({}, draft); n.location = e.target.value; setDraft(n) } }),
|
|
1405
|
+
h('input', { 'data-dam-input': '', placeholder: locale === 'zh' ? '提醒内容(可选)' : 'Reminder note (optional)', value: draft.reminder || '', onChange: function (e) { var n = Object.assign({}, draft); n.reminder = e.target.value; setDraft(n) } }),
|
|
1406
|
+
h('textarea', { 'data-dam-input': '', rows: 2, placeholder: locale === 'zh' ? '补充说明(可选)' : 'Details (optional)', value: draft.note || '', onChange: function (e) { var n = Object.assign({}, draft); n.note = e.target.value; setDraft(n) } }),
|
|
1155
1407
|
h('div', { 'data-dam-row': '' },
|
|
1156
|
-
h('button', { 'data-dam-btn': '', onClick: saveDraft }, t('save')),
|
|
1157
|
-
h('button', { 'data-dam-btn': '', onClick: function () { setDraft(null) } }, t('cancel'))
|
|
1408
|
+
h('button', { 'data-dam-btn': '', onClick: saveDraft, disabled: saving }, saving ? (locale === 'zh' ? '保存中…' : 'Saving…') : t('save')),
|
|
1409
|
+
h('button', { 'data-dam-btn': '', onClick: function () { if (!saving) setDraft(null) }, disabled: saving }, t('cancel')),
|
|
1410
|
+
calError ? h('div', { 'data-dam-error': '' }, calError) : null)))
|
|
1158
1411
|
}
|
|
1159
|
-
msg
|
|
1160
|
-
|
|
1412
|
+
if (msg) rows.push(h('div', { 'data-dam-hint': '', style: { marginTop: '8px' } }, msg))
|
|
1413
|
+
if (calError && !draft) rows.push(h('div', { 'data-dam-error': '' }, calError))
|
|
1414
|
+
return h('div', { 'data-dam-calendar': '', style: { position: 'relative' } }, rows)
|
|
1161
1415
|
}
|
|
1162
1416
|
|
|
1163
1417
|
var TOOL_LABEL = { workbuddy: t('aiAssistant'), codebuddy: 'CodeBuddy', claude: 'Claude Code', codex: 'Codex', 'project-files': t('projectFiles') }
|
|
@@ -1174,10 +1428,25 @@ window.__ModuleLoader__.load({
|
|
|
1174
1428
|
var errPair = useState('')
|
|
1175
1429
|
var err = errPair[0]
|
|
1176
1430
|
var setErr = errPair[1]
|
|
1431
|
+
var expandedPair = useState(null)
|
|
1432
|
+
var expanded = expandedPair[0]
|
|
1433
|
+
var setExpanded = expandedPair[1]
|
|
1434
|
+
var viewCachePair = useState({})
|
|
1435
|
+
var viewCache = viewCachePair[0]
|
|
1436
|
+
var setViewCache = viewCachePair[1]
|
|
1437
|
+
var removeArmPair = useState('')
|
|
1438
|
+
var removeArm = removeArmPair[0]
|
|
1439
|
+
var setRemoveArm = removeArmPair[1]
|
|
1440
|
+
var hitsCachePair = useState({})
|
|
1441
|
+
var hitsCache = hitsCachePair[0]
|
|
1442
|
+
var setHitsCache = hitsCachePair[1]
|
|
1443
|
+
var hitsBusyForPair = useState(null)
|
|
1444
|
+
var hitsBusyFor = hitsBusyForPair[0]
|
|
1445
|
+
var setHitsBusyFor = hitsBusyForPair[1]
|
|
1177
1446
|
function load() {
|
|
1178
1447
|
apiGet(API.external).then(function (d) { setSources(d.sources || []) }).catch(function (e) { setErr(e.message) })
|
|
1179
1448
|
}
|
|
1180
|
-
useEffect(function () { load()
|
|
1449
|
+
useEffect(function () { load() }, [])
|
|
1181
1450
|
if (!sources) return err ? h('div', { 'data-dam-error': '' }, err) : h(Loading)
|
|
1182
1451
|
function doImport(source, target) {
|
|
1183
1452
|
var next = Object.assign({}, busy); next[source] = true
|
|
@@ -1185,8 +1454,44 @@ window.__ModuleLoader__.load({
|
|
|
1185
1454
|
apiPost(API.externalImport, { source: source, target: target }).then(function (d) {
|
|
1186
1455
|
var done = Object.assign({}, busy); done[source] = false
|
|
1187
1456
|
setBusy(done); setMsg(d.result || t('imported'))
|
|
1457
|
+
setSources(function (prev) { return (prev || []).map(function (x) { return x.id === source ? Object.assign({}, x, target === 'user' ? { importedUser: true } : { importedNotes: true }) : x }) })
|
|
1458
|
+
load()
|
|
1188
1459
|
}).catch(function (e) { var done = Object.assign({}, busy); done[source] = false; setBusy(done); setErr(e.message) })
|
|
1189
1460
|
}
|
|
1461
|
+
function toggleView(source) {
|
|
1462
|
+
if (expanded === source.id) { setExpanded(null); return }
|
|
1463
|
+
setExpanded(source.id); setRemoveArm('')
|
|
1464
|
+
if (viewCache[source.id] !== undefined) return
|
|
1465
|
+
var n = Object.assign({}, viewCache); n[source.id] = { source: source, loading: true }
|
|
1466
|
+
setViewCache(n)
|
|
1467
|
+
apiGet(API.externalView, { source: source.id }).then(function (d) {
|
|
1468
|
+
var m = Object.assign({}, viewCache); m[source.id] = Object.assign({ source: source }, d, { loading: false })
|
|
1469
|
+
setViewCache(m)
|
|
1470
|
+
}).catch(function (e) {
|
|
1471
|
+
var m = Object.assign({}, viewCache); m[source.id] = { source: source, loading: false, error: e.message }
|
|
1472
|
+
setViewCache(m)
|
|
1473
|
+
})
|
|
1474
|
+
}
|
|
1475
|
+
function removeImported(source, target) {
|
|
1476
|
+
var key = source.id + ':' + (target || '')
|
|
1477
|
+
if (removeArm !== key) { setRemoveArm(key); setMsg(''); return }
|
|
1478
|
+
setRemoveArm('')
|
|
1479
|
+
apiPost(API.externalRemove, { source: source.id, target: target }).then(function (d) {
|
|
1480
|
+
setMsg(d.result || ''); setExpanded(null); load()
|
|
1481
|
+
setSources(function (prev) { return (prev || []).map(function (x) { return x.id === source.id ? Object.assign({}, x, target === 'user' ? { importedUser: false } : target === 'project' ? { importedNotes: false } : { importedUser: false, importedNotes: false }) : x }) })
|
|
1482
|
+
}).catch(function (e) { setErr(t('failed') + e.message) })
|
|
1483
|
+
}
|
|
1484
|
+
function findImported(source) {
|
|
1485
|
+
if (!source) return
|
|
1486
|
+
setHitsBusyFor(source.id)
|
|
1487
|
+
apiPost(API.recall, { query: source.name || source.tool || '' }).then(function (d) {
|
|
1488
|
+
var n = Object.assign({}, hitsCache); n[source.id] = d && d.result ? d.result : (locale === 'zh' ? '未找到相关片段' : 'No matches')
|
|
1489
|
+
setHitsCache(n); setHitsBusyFor(null)
|
|
1490
|
+
}).catch(function (e) {
|
|
1491
|
+
var n = Object.assign({}, hitsCache); n[source.id] = t('failed') + e.message
|
|
1492
|
+
setHitsCache(n); setHitsBusyFor(null)
|
|
1493
|
+
})
|
|
1494
|
+
}
|
|
1190
1495
|
function importAll() {
|
|
1191
1496
|
var md = sources.filter(function (s) { return s.kind !== 'sessions' && s.enabled !== false })
|
|
1192
1497
|
setMsg(t('importing') + md.length + t('importingSuffix')); setErr('')
|
|
@@ -1200,17 +1505,31 @@ window.__ModuleLoader__.load({
|
|
|
1200
1505
|
}
|
|
1201
1506
|
for (var i = 0; i < sources.length; i++) {
|
|
1202
1507
|
(function (s) {
|
|
1508
|
+
var isOpen = expanded === s.id
|
|
1509
|
+
var v = viewCache[s.id]
|
|
1203
1510
|
var actions = []
|
|
1511
|
+
actions.push(h('button', { 'data-dam-btn': '', title: locale === 'zh' ? '只读查看该来源的内容' : 'Read-only view of this source', onClick: function () { toggleView(s) } }, isOpen ? (locale === 'zh' ? '收起' : 'Collapse') : (locale === 'zh' ? '查看内容' : 'View content')))
|
|
1204
1512
|
if (s.kind === 'sessions') {
|
|
1205
1513
|
actions.push(h('span', { 'data-dam-hint': '' }, t('sessionSource') + s.fileCount + t('sessionSourceSuffix')))
|
|
1206
1514
|
} else {
|
|
1207
|
-
actions.push(h('button', { 'data-dam-btn': '',
|
|
1208
|
-
actions.push(h('button', { 'data-dam-btn': '', disabled: !!busy[s.id], onClick: function () { doImport(s.id, '
|
|
1515
|
+
actions.push(s.importedUser ? h('button', { 'data-dam-btn': '', title: locale === 'zh' ? '从用户级记忆删除已导入段落' : 'Delete the imported section from user-level memory', onClick: function () { removeImported(s, 'user') }, style: removeArm === s.id + ':user' ? { background: 'color-mix(in srgb, var(--dsw-alias-state-error-primary, #d64545) 22%, transparent)', color: 'var(--dsw-alias-state-error-primary, #d64545)' } : undefined }, removeArm === s.id + ':user' ? (locale === 'zh' ? '确认删除?' : 'Confirm?') : (locale === 'zh' ? '从 prompt 删除' : 'Delete')) : h('button', { 'data-dam-btn': '', disabled: !!busy[s.id], onClick: function () { doImport(s.id, 'user') } }, t('importToUser')))
|
|
1516
|
+
actions.push(s.importedNotes ? h('button', { 'data-dam-btn': '', title: locale === 'zh' ? '从项目笔记删除已导入段落' : 'Delete the imported section from project notes', onClick: function () { removeImported(s, 'project') }, style: removeArm === s.id + ':project' ? { background: 'color-mix(in srgb, var(--dsw-alias-state-error-primary, #d64545) 22%, transparent)', color: 'var(--dsw-alias-state-error-primary, #d64545)' } : undefined }, removeArm === s.id + ':project' ? (locale === 'zh' ? '确认删除?' : 'Confirm?') : (locale === 'zh' ? '从 prompt 删除' : 'Delete')) : h('button', { 'data-dam-btn': '', disabled: !!busy[s.id], onClick: function () { doImport(s.id, 'project') } }, busy[s.id] ? t('importingOne') : t('importToNotes')))
|
|
1517
|
+
|
|
1209
1518
|
}
|
|
1210
|
-
cards.push(h(Card, { title: s.name + ' · ' + s.tool + (s.enabled === false ? t('disabled') : '') },
|
|
1211
|
-
h('div', { 'data-dam-
|
|
1212
|
-
|
|
1213
|
-
|
|
1519
|
+
cards.push(h(Card, { key: s.id, title: s.name + ' · ' + s.tool + (s.enabled === false ? t('disabled') : '') },
|
|
1520
|
+
h('div', { 'data-dam-row': '', style: { marginBottom: '2px' } }, actions),
|
|
1521
|
+
h(AnimatedDisclosure, { open: isOpen },
|
|
1522
|
+
v && v.loading ? h(Loading, { label: locale === 'zh' ? '正在读取来源…' : 'Reading source…' })
|
|
1523
|
+
: v && v.error ? h('div', { 'data-dam-error': '' }, v.error)
|
|
1524
|
+
: v ? h('div', null,
|
|
1525
|
+
h('div', { 'data-dam-content': '' }, v.content || t('empty')),
|
|
1526
|
+
v.imported !== undefined ? h('div', { 'data-dam-hint': '', style: { marginTop: '6px' } },
|
|
1527
|
+
(locale === 'zh' ? '已接入位置:' : 'Imported at: ') + (v.imported ? (v.locations || []).join(' ; ') : (locale === 'zh' ? '尚未接入' : 'Not imported'))) : null,
|
|
1528
|
+
h('div', { 'data-dam-row': '', style: { marginTop: '8px' } },
|
|
1529
|
+
h('button', { 'data-dam-btn': '', onClick: function () { findImported(s) } }, hitsBusyFor === s.id ? (locale === 'zh' ? '检索中…' : 'Searching…') : (locale === 'zh' ? '在记忆中查找' : 'Find in memory'))),
|
|
1530
|
+
hitsCache[s.id] ? h('div', { 'data-dam-content': '', style: { marginTop: '6px' } }, String(hitsCache[s.id])) : null,
|
|
1531
|
+
h('div', { 'data-dam-hint': '', style: { marginTop: '8px' } }, locale === 'zh' ? '提示:接入后按钮会变成「从 prompt 删除」,可单独删除用户级或项目笔记里的已导入段落;不会删除来源文件。' : 'Note: after import the button becomes "Delete" for that target; source files are never touched.'))
|
|
1532
|
+
: null)))
|
|
1214
1533
|
})(sources[i])
|
|
1215
1534
|
}
|
|
1216
1535
|
return h('div', null,
|
|
@@ -1253,6 +1572,52 @@ window.__ModuleLoader__.load({
|
|
|
1253
1572
|
}
|
|
1254
1573
|
}
|
|
1255
1574
|
|
|
1575
|
+
function TabScroller(props) {
|
|
1576
|
+
var tabs = props.tabs || []
|
|
1577
|
+
var tab = props.tab
|
|
1578
|
+
var setTab = props.setTab
|
|
1579
|
+
var viewportRef = useRef(null)
|
|
1580
|
+
var canLeftPair = useState(false)
|
|
1581
|
+
var canLeft = canLeftPair[0]
|
|
1582
|
+
var setCanLeft = canLeftPair[1]
|
|
1583
|
+
var canRightPair = useState(false)
|
|
1584
|
+
var canRight = canRightPair[0]
|
|
1585
|
+
var setCanRight = canRightPair[1]
|
|
1586
|
+
function refreshArrows() {
|
|
1587
|
+
var vp = viewportRef.current
|
|
1588
|
+
if (!vp) return
|
|
1589
|
+
setCanLeft(vp.scrollLeft > 2)
|
|
1590
|
+
setCanRight(vp.scrollLeft + vp.clientWidth < vp.scrollWidth - 2)
|
|
1591
|
+
}
|
|
1592
|
+
useEffect(function () {
|
|
1593
|
+
var vp = viewportRef.current
|
|
1594
|
+
if (!vp) return
|
|
1595
|
+
refreshArrows()
|
|
1596
|
+
vp.addEventListener('scroll', refreshArrows)
|
|
1597
|
+
var ro = null
|
|
1598
|
+
if (typeof ResizeObserver !== 'undefined') { try { ro = new ResizeObserver(refreshArrows); ro.observe(vp) } catch (e) {} }
|
|
1599
|
+
return function () { vp.removeEventListener('scroll', refreshArrows); if (ro) ro.disconnect() }
|
|
1600
|
+
}, [tabs.length])
|
|
1601
|
+
useEffect(function () {
|
|
1602
|
+
var vp = viewportRef.current
|
|
1603
|
+
if (!vp) return
|
|
1604
|
+
var activeEl = vp.querySelector('[data-active="true"]')
|
|
1605
|
+
if (!activeEl) return
|
|
1606
|
+
var l = activeEl.offsetLeft, w = activeEl.offsetWidth
|
|
1607
|
+
if (l < vp.scrollLeft) vp.scrollTo({ left: Math.max(0, l - 8), behavior: 'smooth' })
|
|
1608
|
+
else if (l + w > vp.scrollLeft + vp.clientWidth) vp.scrollTo({ left: l + w - vp.clientWidth + 8, behavior: 'smooth' })
|
|
1609
|
+
}, [tab])
|
|
1610
|
+
function step(dir) {
|
|
1611
|
+
var vp = viewportRef.current
|
|
1612
|
+
if (!vp) return
|
|
1613
|
+
try { vp.scrollBy({ left: dir * Math.max(90, vp.clientWidth * 0.6), behavior: 'smooth' }) } catch (e) { vp.scrollLeft += dir * 90 }
|
|
1614
|
+
}
|
|
1615
|
+
return h('div', { 'data-dam-tabs-wrap': '' },
|
|
1616
|
+
h('button', { 'data-dam-tabs-arrow': '', title: locale === 'zh' ? '向左滚动模块' : 'Scroll modules left', 'aria-label': locale === 'zh' ? '向左滚动模块' : 'Scroll modules left', disabled: !canLeft, onClick: function () { step(-1) } }, '‹'),
|
|
1617
|
+
h('div', { 'data-dam-tabs': '', ref: viewportRef }, h('div', { 'data-dam-tab-strip': '' }, tabs.map(function (item) { return h('button', { key: item[0], 'data-dam-tab': '', 'data-active': tab === item[0] ? 'true' : undefined, onClick: function () { setTab(item[0]) } }, item[1]) }))),
|
|
1618
|
+
h('button', { 'data-dam-tabs-arrow': '', title: locale === 'zh' ? '向右滚动模块' : 'Scroll modules right', 'aria-label': locale === 'zh' ? '向右滚动模块' : 'Scroll modules right', disabled: !canRight, onClick: function () { step(1) } }, '›'))
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1256
1621
|
function MemoryPanel() {
|
|
1257
1622
|
var tick = useTick()
|
|
1258
1623
|
var tabPair = useState('overview')
|
|
@@ -1281,6 +1646,7 @@ window.__ModuleLoader__.load({
|
|
|
1281
1646
|
width: g.width + 'px',
|
|
1282
1647
|
height: g.height + 'px',
|
|
1283
1648
|
'--dam-scale': FONT_SCALE_VALUES[fontScale] || '1',
|
|
1649
|
+
'--dam-accent': ACCENT_VALUES[accentTheme] || ACCENT_VALUES.deepseek,
|
|
1284
1650
|
}
|
|
1285
1651
|
var dragMove = startPointerDrag(function (dx, dy) {
|
|
1286
1652
|
controller.setGeom({ left: g.left + dx, top: g.top + dy })
|
|
@@ -1300,13 +1666,12 @@ window.__ModuleLoader__.load({
|
|
|
1300
1666
|
onPointerDown: dragMove,
|
|
1301
1667
|
},
|
|
1302
1668
|
h('strong', null, t('autoMemory')),
|
|
1669
|
+
h('span', { 'data-dam-hint': '', style: { fontSize: '10px', opacity: .55 } }, 'v0.1.23-ui'),
|
|
1303
1670
|
h('span', { className: 'dam-spacer' }),
|
|
1304
1671
|
h('button', { 'data-dam-btn': '', title: t('resetPos'), onClick: function () { controller.resetGeom() } }, '⤾'),
|
|
1305
1672
|
h('button', { 'data-dam-btn': '', title: t('refresh'), onClick: function () { setNonce(nonce + 1) } }, '⟳'),
|
|
1306
1673
|
h('button', { 'data-dam-btn': '', title: t('close'), onClick: function () { controller.close() } }, '✕')),
|
|
1307
|
-
h(
|
|
1308
|
-
return h('button', { key: t[0], 'data-dam-tab': '', 'data-active': tab === t[0] ? 'true' : undefined, onClick: function () { setTab(t[0]) } }, t[1])
|
|
1309
|
-
})),
|
|
1674
|
+
h(TabScroller, { tabs: tabs, tab: tab, setTab: setTab }),
|
|
1310
1675
|
h('div', { 'data-dam-body': '' }, body),
|
|
1311
1676
|
h('div', { 'data-dam-resize': '', title: t('dragResize'), onPointerDown: resizeMove }))
|
|
1312
1677
|
}
|
|
@@ -1483,9 +1848,15 @@ window.__ModuleLoader__.load({
|
|
|
1483
1848
|
var errPair = useState('')
|
|
1484
1849
|
var err = errPair[0]
|
|
1485
1850
|
var setErr = errPair[1]
|
|
1851
|
+
var dirtyPair = useState(false)
|
|
1852
|
+
var dirty = dirtyPair[0]
|
|
1853
|
+
var setDirty = dirtyPair[1]
|
|
1486
1854
|
var dbgOpenPair = useState(false)
|
|
1487
1855
|
var dbgOpen = dbgOpenPair[0]
|
|
1488
1856
|
var setDbgOpen = dbgOpenPair[1]
|
|
1857
|
+
var settingsSectionPair = useState('appearance')
|
|
1858
|
+
var settingsSection = settingsSectionPair[0]
|
|
1859
|
+
var setSettingsSection = settingsSectionPair[1]
|
|
1489
1860
|
var browseOpenPair = useState(false)
|
|
1490
1861
|
var browseOpen = browseOpenPair[0]
|
|
1491
1862
|
var setBrowseOpen = browseOpenPair[1]
|
|
@@ -1544,7 +1915,7 @@ window.__ModuleLoader__.load({
|
|
|
1544
1915
|
return function () { alive = false }
|
|
1545
1916
|
}, [])
|
|
1546
1917
|
if (!cfg) return err ? h('div', { 'data-dam-error': '' }, err) : h(Loading)
|
|
1547
|
-
function set(key, value) { var next = Object.assign({}, cfg); next[key] = value; setCfg(next) }
|
|
1918
|
+
function set(key, value) { var next = Object.assign({}, cfg); next[key] = value; setCfg(next); setDirty(true) }
|
|
1548
1919
|
function checkUpdate() {
|
|
1549
1920
|
if (checkingUpdate) return
|
|
1550
1921
|
setCheckingUpdate(true)
|
|
@@ -1563,21 +1934,51 @@ window.__ModuleLoader__.load({
|
|
|
1563
1934
|
function save() {
|
|
1564
1935
|
if (busy) return
|
|
1565
1936
|
setBusy(true); setMsg(''); setErr('')
|
|
1566
|
-
apiPost(API.config, cfg).then(function (d) { setCfg(d.config); setMsg(t('saved') + (d.migrated ? ' ' + d.migrated : '')); setBusy(false); if (d && d.config && d.config.locale) applyLocalePref(d.config.locale) })
|
|
1937
|
+
apiPost(API.config, cfg).then(function (d) { setCfg(d.config); setDirty(false); setMsg(t('saved') + (d.migrated ? ' ' + d.migrated : '')); setBusy(false); if (d && d.config && d.config.locale) applyLocalePref(d.config.locale) })
|
|
1567
1938
|
.catch(function (e) { setErr(e.message); setBusy(false) })
|
|
1568
1939
|
}
|
|
1569
1940
|
function field(label, control, hint) {
|
|
1570
|
-
return h('div',
|
|
1941
|
+
return h('div', { 'data-dam-settings-row': '' },
|
|
1571
1942
|
h('div', { 'data-dam-row': '' }, h('label', null, label), control),
|
|
1572
1943
|
hint ? h('div', { 'data-dam-hint': '' }, hint) : null)
|
|
1573
1944
|
}
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1945
|
+
function setAccent(value) {
|
|
1946
|
+
accentTheme = ACCENT_VALUES[value] ? value : 'deepseek'
|
|
1947
|
+
try { localStorage.setItem('dsh-auto-memory.accentTheme.v1', accentTheme) } catch (e) {}
|
|
1948
|
+
emit()
|
|
1949
|
+
}
|
|
1950
|
+
function setDensity(value) {
|
|
1951
|
+
graphDensity = value === 'compact' ? 'compact' : 'relaxed'
|
|
1952
|
+
try { localStorage.setItem('dsh-auto-memory.graphDensity.v1', graphDensity) } catch (e) {}
|
|
1953
|
+
emit()
|
|
1954
|
+
}
|
|
1955
|
+
var sectionLabels = {
|
|
1956
|
+
appearance: locale === 'zh' ? '外观' : 'Appearance', storage: locale === 'zh' ? '存储' : 'Storage',
|
|
1957
|
+
injection: locale === 'zh' ? '记忆窗口' : 'Memory window', automation: locale === 'zh' ? '自动化' : 'Automation',
|
|
1958
|
+
maintenance: locale === 'zh' ? '维护' : 'Maintenance'
|
|
1959
|
+
}
|
|
1960
|
+
function section(key, title, content) { return h('section', { id: 'dam-settings-' + key, 'data-dam-settings-group': '' }, h('h3', null, title), content) }
|
|
1961
|
+
function jumpToSection(key) {
|
|
1962
|
+
setSettingsSection(key)
|
|
1963
|
+
try { var el = document.getElementById('dam-settings-' + key); if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' }) } catch (e) {}
|
|
1964
|
+
}
|
|
1965
|
+
return h('div', { 'data-dam-settings': '' },
|
|
1966
|
+
h('nav', { 'data-dam-settings-nav': '', 'aria-label': locale === 'zh' ? '设置分组' : 'Settings sections' }, Object.keys(sectionLabels).map(function (key) {
|
|
1967
|
+
return h('button', { key: key, 'data-dam-btn': '', 'data-active': settingsSection === key ? 'true' : undefined, onClick: function () { jumpToSection(key) } }, sectionLabels[key])
|
|
1968
|
+
})),
|
|
1969
|
+
h('div', { 'data-dam-settings-content': '' },
|
|
1970
|
+
section('appearance', sectionLabels.appearance, [
|
|
1971
|
+
h('div', { 'data-dam-hint': '' }, t('settingsHeader')),
|
|
1972
|
+
field(t('fLocale'), h('select', { 'data-dam-select': '', value: cfg.locale || 'system', onChange: function (e) { set('locale', e.target.value) } },
|
|
1973
|
+
LOCALE_IDS_LIST.map(function (id) { return h('option', { key: id, value: id }, id === 'system' ? t('followSystem') : t(id)) })), t('fLocaleHint')),
|
|
1974
|
+
field(t('fFontSize'), h('select', { 'data-dam-select': '', value: fontScale, onChange: function (e) { fontScale = e.target.value; try { localStorage.setItem('dsh-auto-memory.fontScale.v2', fontScale) } catch (ee) {}; try { var pp = document.querySelector('[data-dam-panel]'); if (pp) pp.style.setProperty('--dam-scale', FONT_SCALE_VALUES[fontScale] || '1') } catch (ee2) {}; emit() } },
|
|
1975
|
+
Object.keys(FONT_SCALES).map(function (k) { return h('option', { key: k, value: k }, t('fs' + k.charAt(0).toUpperCase() + k.slice(1))) })), t('fFontSizeHint')),
|
|
1976
|
+
field(locale === 'zh' ? '强调色' : 'Accent color', h('select', { 'data-dam-select': '', value: accentTheme, onChange: function (e) { setAccent(e.target.value) } },
|
|
1977
|
+
h('option', { value: 'deepseek' }, locale === 'zh' ? 'DeepSeek 蓝' : 'DeepSeek blue'), h('option', { value: 'graphite' }, locale === 'zh' ? '石墨灰' : 'Graphite'), h('option', { value: 'violet' }, locale === 'zh' ? '雾紫' : 'Violet')), locale === 'zh' ? '默认使用 DeepSeek 蓝;日历与状态颜色保持语义色。' : 'DeepSeek blue by default; calendar and status colors stay semantic.'),
|
|
1978
|
+
field(locale === 'zh' ? '关系图密度' : 'Graph density', h('select', { 'data-dam-select': '', value: graphDensity, onChange: function (e) { setDensity(e.target.value) } },
|
|
1979
|
+
h('option', { value: 'relaxed' }, locale === 'zh' ? '舒展' : 'Relaxed'), h('option', { value: 'compact' }, locale === 'zh' ? '紧凑' : 'Compact')), locale === 'zh' ? '影响工作区关系图的节点间距和显示数量。' : 'Controls node spacing and detail in the workspace graph.')
|
|
1980
|
+
]),
|
|
1981
|
+
section('storage', sectionLabels.storage, [field(t('fUserDir'), h('input', { 'data-dam-input': '', value: cfg.userMemoryDir, onChange: function (e) { set('userMemoryDir', e.target.value) } }), t('fUserDirHint')),
|
|
1581
1982
|
field(t('fProjectDir'), h('input', { 'data-dam-input': '', value: cfg.projectMemoryDir, onChange: function (e) { set('projectMemoryDir', e.target.value) } }), t('fProjectDirHint')),
|
|
1582
1983
|
field(t('fMemoryRoot'), h('div', { 'data-dam-row': '', style: { flex: 1 } },
|
|
1583
1984
|
h('input', { 'data-dam-input': '', style: { flex: 1 }, value: cfg.memoryRoot || '', onChange: function (e) { set('memoryRoot', e.target.value) } }),
|
|
@@ -1593,30 +1994,36 @@ window.__ModuleLoader__.load({
|
|
|
1593
1994
|
h('div', { 'data-dam-row': '', style: { marginTop: '6px' } },
|
|
1594
1995
|
h('button', { 'data-dam-btn': '', onClick: function () { set('memoryRoot', browsePath); setBrowseOpen(false) } }, t('fSelectDir')),
|
|
1595
1996
|
h('button', { 'data-dam-btn': '', onClick: function () { setBrowseOpen(false) } }, t('close'))))
|
|
1596
|
-
: null,
|
|
1597
|
-
field(t('fInject'), h('input', { type: 'checkbox', checked: !!cfg.injectEnabled, onChange: function (e) { set('injectEnabled', e.target.checked) } }), t('fInjectHint')),
|
|
1997
|
+
: null]),
|
|
1998
|
+
section('injection', sectionLabels.injection, [field(t('fInject'), h('input', { type: 'checkbox', checked: !!cfg.injectEnabled, onChange: function (e) { set('injectEnabled', e.target.checked) } }), t('fInjectHint')),
|
|
1598
1999
|
field(t('fBudget'), h('input', { 'data-dam-input': '', type: 'number', min: 400, value: cfg.injectBudgetChars, onChange: function (e) { set('injectBudgetChars', Number(e.target.value) || 2400) } }), t('fBudgetHint')),
|
|
1599
|
-
field(t('fDays'), h('input', { 'data-dam-input': '', type: 'number', min: 1, max: 14, value: cfg.recentDaysInjected, onChange: function (e) { set('recentDaysInjected', Number(e.target.value) ||
|
|
2000
|
+
field(t('fDays'), h('input', { 'data-dam-input': '', type: 'number', min: 1, max: 14, value: cfg.recentDaysInjected, onChange: function (e) { set('recentDaysInjected', Number(e.target.value) || 1) } }), t('fDaysHint')),
|
|
2001
|
+
field(t('fExtBudget'), h('input', { 'data-dam-input': '', type: 'number', min: 200, value: cfg.externalInjectionChars === undefined ? 1400 : cfg.externalInjectionChars, onChange: function (e) { set('externalInjectionChars', Number(e.target.value) || 1400) } }), t('fExtBudgetHint'))]),
|
|
2002
|
+
section('automation', sectionLabels.automation, [field(t('fConsolidateMin'), h('input', { 'data-dam-input': '', type: 'number', min: 80, value: cfg.autoConsolidateMinChars === undefined ? 240 : cfg.autoConsolidateMinChars, onChange: function (e) { set('autoConsolidateMinChars', Number(e.target.value) || 240) } }), t('fConsolidateMinHint')),
|
|
2003
|
+
field(t('fAutoConsolidate'), h('input', { type: 'checkbox', checked: cfg.autoConsolidate !== false, onChange: function (e) { set('autoConsolidate', e.target.checked) } }), t('fAutoConsolidateHint')),
|
|
2004
|
+
field(t('fConsolidate'), h('input', { 'data-dam-input': '', type: 'number', min: 5, value: cfg.autoConsolidateCooldownMinutes === undefined ? 30 : cfg.autoConsolidateCooldownMinutes, onChange: function (e) { set('autoConsolidateCooldownMinutes', Number(e.target.value) || 30) } }), t('fConsolidateHint')),
|
|
2005
|
+
field(t('fConsolidateMax'), h('input', { 'data-dam-input': '', type: 'number', min: 1, max: 50, value: cfg.autoConsolidateDailyMax === undefined ? 8 : cfg.autoConsolidateDailyMax, onChange: function (e) { set('autoConsolidateDailyMax', Number(e.target.value) || 8) } }), t('fConsolidateMaxHint')),
|
|
1600
2006
|
field(t('fAway'), h('input', { 'data-dam-input': '', type: 'number', min: 1, value: cfg.awayMinutes || 60, onChange: function (e) { set('awayMinutes', Number(e.target.value) || 60) } }), t('fAwayHint')),
|
|
1601
2007
|
field(t('fAutoSum'), h('input', { 'data-dam-input': '', value: (cfg.autoSummaryTimes || []).join(','), onChange: function (e) { set('autoSummaryTimes', String(e.target.value || '').split(',').map(function (s) { return s.trim() }).filter(Boolean)) } }), t('fAutoSumHint')),
|
|
1602
2008
|
field(t('fDayBoundary'), h('input', { 'data-dam-input': '', type: 'number', min: 0, max: 1439, value: (cfg.dayBoundaryMinutes === undefined ? 450 : cfg.dayBoundaryMinutes), onChange: function (e) { set('dayBoundaryMinutes', parseInt(e.target.value || '0', 10)) } }), t('fDayBoundaryHint')),
|
|
1603
2009
|
field(t('fReflect'), h('input', { type: 'checkbox', checked: !!cfg.reflectEnabled, onChange: function (e) { set('reflectEnabled', e.target.checked) } }), t('fReflectHint')),
|
|
1604
2010
|
field(t('fStyle'), h('select', { 'data-dam-select': '', value: cfg.reflectStyle, onChange: function (e) { set('reflectStyle', e.target.value) } },
|
|
1605
|
-
STYLE_IDS.map(function (id) { return h('option', { key: id, value: id }, t('style' + id.charAt(0).toUpperCase() + id.slice(1))) })), t('fStyleHint')),
|
|
1606
|
-
field(t('fVersion'), h('div', { 'data-dam-row': '' },
|
|
2011
|
+
STYLE_IDS.map(function (id) { return h('option', { key: id, value: id }, t('style' + id.charAt(0).toUpperCase() + id.slice(1))) })), t('fStyleHint'))]),
|
|
2012
|
+
section('maintenance', sectionLabels.maintenance, [field(t('fVersion'), h('div', { 'data-dam-row': '' },
|
|
1607
2013
|
h('span', { style: { flex: 1 } }, verInfo ? (verInfo.current || '?') + (verInfo.latest ? ' → ' + verInfo.latest + (verInfo.upToDate ? ' ' + t('upToDate') : ' ' + t('hasUpdate')) : '') : (checkingUpdate ? t('checking') : '—')),
|
|
1608
2014
|
h('button', { 'data-dam-btn': '', onClick: checkUpdate, disabled: checkingUpdate }, checkingUpdate ? t('checking') : t('checkUpdate')),
|
|
1609
2015
|
(verInfo && verInfo.latest && !verInfo.upToDate && verInfo.installKind === 'registry') ? h('button', { 'data-dam-btn': '', onClick: doUpdate, disabled: upBusy, style: { marginLeft: '4px' } }, upBusy ? t('updating') : t('updateNow')) : null,
|
|
1610
2016
|
upMsg ? h('span', { 'data-dam-hint': '' }, upMsg) : null),
|
|
1611
|
-
t('versionCmdHint') + (verInfo && verInfo.error ? ' ' + t('versionError') + verInfo.error : '') + (verInfo && verInfo.installKind === 'dev-link' ? ' ' + t('devLinkHint') : '') + (verInfo && !verInfo.installKind ? ' ' + t('noProfileHint') : '')),
|
|
1612
|
-
h('div', { 'data-dam-
|
|
1613
|
-
h('button', { 'data-dam-btn': '', onClick: save, disabled: busy }, busy ? t('saving') : t('saveSettings')),
|
|
1614
|
-
|
|
2017
|
+
t('versionCmdHint') + (verInfo && verInfo.error ? ' ' + t('versionError') + verInfo.error : '') + (verInfo && verInfo.installKind === 'dev-link' ? ' ' + t('devLinkHint') : '') + (verInfo && !verInfo.installKind ? ' ' + t('noProfileHint') : ''))]),
|
|
2018
|
+
h('div', { 'data-dam-savebar': '' },
|
|
2019
|
+
h('button', { 'data-dam-btn': '', 'data-dirty': dirty ? 'true' : undefined, onClick: save, disabled: busy }, busy ? t('saving') : (dirty ? (locale === 'zh' ? '保存更改' : 'Save changes') : t('saveSettings'))),
|
|
2020
|
+
dirty ? h('span', { 'data-dam-hint': '' }, locale === 'zh' ? '有未保存的更改' : 'Unsaved changes') : null,
|
|
2021
|
+
msg ? h('span', { 'data-dam-hint': '' }, msg) : null),
|
|
1615
2022
|
// 调试中心(折叠):模块状态一览,方便排查问题/提 issue
|
|
1616
2023
|
h('div', { style: { marginTop: '14px', borderTop: '1px solid color-mix(in srgb, var(--dsw-alias-border-l1, rgba(128,128,128,.2)) 55%, transparent)', paddingTop: '10px' } },
|
|
1617
2024
|
h('button', { 'data-dam-btn': '', onClick: function () { setDbgOpen(!dbgOpen) } }, (dbgOpen ? '▴ ' : '▾ ') + t('debugCenter')),
|
|
1618
2025
|
dbgOpen ? h('div', { style: { marginTop: '8px' } }, h(DebugCenter)) : null),
|
|
1619
|
-
err ? h('div', { 'data-dam-error': '' }, err) : null)
|
|
2026
|
+
err ? h('div', { 'data-dam-error': '' }, err) : null))
|
|
1620
2027
|
}
|
|
1621
2028
|
|
|
1622
2029
|
// ───────────────────────── 插件挂载 ─────────────────────────
|