@a9i5k4/dsh-auto-memory 2.2.1 → 2.2.2
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 +1 -1
- package/README.zh-CN.md +1 -1
- package/lib/client.js +202 -4
- package/lib/index.js +25 -5
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
</details>
|
|
52
52
|
|
|
53
53
|
<p align="center">
|
|
54
|
-
<a href="README.zh-CN.md">中文</a> · <b>English</b> · License BSD-3-Clause · <code>pnpm add @a9i5k4/dsh-auto-memory</code> · <a href="https://qm.qq.com/q/v7Asxn6vPa">QQ group</a>
|
|
54
|
+
<a href="README.zh-CN.md">中文</a> · <b>English</b> · License BSD-3-Clause · <code>pnpm add @a9i5k4/dsh-auto-memory</code> · <a href="docs/USER-GUIDE.zh-CN.md">📖 User guide (settings & tuning)</a> · <a href="https://qm.qq.com/q/v7Asxn6vPa">QQ group</a>
|
|
55
55
|
</p>
|
|
56
56
|
|
|
57
57
|
---
|
package/README.zh-CN.md
CHANGED
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
</details>
|
|
52
52
|
|
|
53
53
|
<p align="center">
|
|
54
|
-
<b>中文</b> · <a href="README.md">English</a> · License BSD-3-Clause · <code>pnpm add @a9i5k4/dsh-auto-memory</code> · <a href="https://qm.qq.com/q/v7Asxn6vPa">QQ 交流群</a>
|
|
54
|
+
<b>中文</b> · <a href="README.md">English</a> · License BSD-3-Clause · <code>pnpm add @a9i5k4/dsh-auto-memory</code> · <a href="docs/USER-GUIDE.zh-CN.md">📖 用户文档(设置与调优)</a> · <a href="https://qm.qq.com/q/v7Asxn6vPa">QQ 交流群</a>
|
|
55
55
|
</p>
|
|
56
56
|
|
|
57
57
|
---
|
package/lib/client.js
CHANGED
|
@@ -271,6 +271,7 @@ window.__ModuleLoader__.load({
|
|
|
271
271
|
fMaintSchedule: '定时 30 天蒸馏', fMaintScheduleHint: '每天到点自动把超过 30 天的旧日志蒸馏归档(等价 memory_maintain);无旧日志时零成本跳过。',
|
|
272
272
|
fMaintScheduleTime: '蒸馏触发时间', fMaintScheduleTimeHint: 'HH:MM,默认 10:00(与固化时间错开)。',
|
|
273
273
|
waterCardTitle: '上下文水位', waterAutoSrc: '自动检测', waterManualSrc: '手动设定', waterMeterOfficial: '官方计量', waterMeterHeuristic: '启发式降级', waterThresholdHint: '水位达到 {t} 时注入交接建议并自动补写账本;计量优先用官方 token-meter(与聊天框 context ring 同源),不可用时降级启发式估算;窗口大小自动取自当前模型(settings.yaml contextWindow),也可在下方手动覆盖。',
|
|
274
|
+
autoContTitle: '自动接续', autoContHint: '开启后:水位达到阈值且会话空闲(连续两轮水位不增长)时,倒计时 30 秒自动执行一键接续(总结→写账本→同工作区开新会话→注入接续材料);触发后 30 分钟内不重复;随时可取消。', autoContOn: '自动接续:开', autoContOff: '自动接续:关', autoContThreshold: '阈值', autoContCountdown: '⏳ {s} 秒后自动接续(总结并开新会话)…', autoContCancel: '取消',
|
|
274
275
|
continueCardTitle: '一键接续', continueCardHint: '写好交接账本→创建新会话→把交接材料作为首条消息预载,并自动切换到新会话继续任务(接续材料含白板节选+最新账本;当前工作区无账本时自动取全局最近一篇)。', continueBtn: '一键接续到新会话', continueBusy: '处理中…',
|
|
275
276
|
fStyle: '反思风格', fStyleHint: '生活化 / 专业性 / 由内容决定。',
|
|
276
277
|
fLocale: '界面语言', fLocaleHint: '默认跟随 DSH 系统语言;也可手动指定中文 / English。', followSystem: '跟随系统语言',
|
|
@@ -418,6 +419,7 @@ window.__ModuleLoader__.load({
|
|
|
418
419
|
fMaintSchedule: 'Scheduled 30-day distill', fMaintScheduleHint: 'Once a day at the set time, distill & archive logs older than 30 days (same flow as memory_maintain); zero cost when nothing to archive.',
|
|
419
420
|
fMaintScheduleTime: 'Distill time', fMaintScheduleTimeHint: 'HH:MM, default 10:00 (staggered from the consolidation time).',
|
|
420
421
|
waterCardTitle: 'Context water level', waterAutoSrc: 'auto-detected', waterManualSrc: 'manual', waterMeterOfficial: 'official meter', waterMeterHeuristic: 'heuristic fallback', waterThresholdHint: 'Past {t} of the window, the handoff advisory is injected and the skeleton ledger is backfilled; metering prefers the official token-meter (same source as the chat context ring), falling back to the heuristic when unavailable; the window auto-follows the active model (settings.yaml contextWindow) or your manual override below.',
|
|
422
|
+
autoContTitle: 'Auto continue', autoContHint: 'When on: once the water level passes the threshold and the session is idle (level unchanged across two polls), a 30s countdown auto-runs One-click continue (summarize → write ledger → open a new session in the same workspace → inject the handoff prompt); suppressed for 30 minutes after each run; cancel anytime.', autoContOn: 'Auto continue: on', autoContOff: 'Auto continue: off', autoContThreshold: 'Threshold', autoContCountdown: '⏳ Auto-continue in {s}s (summarize & open new session)…', autoContCancel: 'Cancel',
|
|
421
423
|
continueCardTitle: 'One-click continue', continueCardHint: 'Writes the handoff ledger → creates a new session → injects the handoff material as the first message → switches to the new session automatically (material = PLAN excerpt + latest ledger; falls back to the most recent global ledger when this workspace has none).', continueBtn: 'Continue in a new session', continueBusy: 'Working…',
|
|
422
424
|
fStyle: 'Reflection style', fStyleHint: 'Life-style / Professional / Auto.',
|
|
423
425
|
fLocale: 'UI language', fLocaleHint: 'Follows the DSH system language by default; you can also pin Chinese / English.', followSystem: 'Follow system language',
|
|
@@ -499,6 +501,17 @@ window.__ModuleLoader__.load({
|
|
|
499
501
|
|
|
500
502
|
// ───────────────────────── 更新弹窗 / 首次指导 ─────────────────────────
|
|
501
503
|
var CHANGELOG = {
|
|
504
|
+
'2.2.2': { zh: [
|
|
505
|
+
'修复:一键接续在部分环境报「harness 未提供 remote.session」——补上官方 remote 注入面(@deepseek-ai/dsh-api-remotes),重启后自动建会话/切换/注入恢复可用。',
|
|
506
|
+
'修复:语义引擎检测面板「未就绪」与「一切就绪」同屏矛盾、缺失时不弹安装引导——检测面补 Python int8 探测(无装=未就绪),按当前引擎模式自动弹出对应安装引导卡。',
|
|
507
|
+
'★ 新增自动接续:水位达阈值(默认 0.8,可调)且会话空闲时,右下角 30 秒可取消倒计时后自动完成「写交接账本→建新会话→注入接续材料」并切换,无需任何按钮或打开面板(常驻监听,默认开;触发后 30 分钟冷却)。',
|
|
508
|
+
'📖 新增用户文档(README 下载区旁「📖 用户文档」):逐组说明每个设置项怎么调,含语义引擎/自动接续/交接白板/常见问题排查。',
|
|
509
|
+
], en: [
|
|
510
|
+
'Fix: one-click continue reported "remote.session unavailable" in some environments — the official remote inject surface (@deepseek-ai/dsh-api-remotes) is now declared; session create/switch/inject works again after a restart.',
|
|
511
|
+
'Fix: semantic detect panel showed "not ready" and "everything ready" at once, and no setup guide appeared when assets were missing — the probe now checks Python int8 too, and the matching setup guide auto-opens per engine mode.',
|
|
512
|
+
'★ New: auto-continue — when the water level passes the threshold (default 0.8, adjustable) and the session is idle, a cancelable 30s countdown auto-runs "write ledger → create session → inject handoff material" and switches; no button or open panel needed (resident watcher, on by default, 30min cooldown).',
|
|
513
|
+
'📖 New user guide (link next to the install command in the README): every settings group explained, incl. semantic engines / auto-continue / whiteboard / troubleshooting.',
|
|
514
|
+
] },
|
|
502
515
|
'2.2.1': { zh: [
|
|
503
516
|
'★ 一键接续:白板页签新增「一键接续」——自动写交接账本 → 创建新会话(沿用工作区/权限/模型)→ 接续材料作为首条消息预载并自动切换;材料附旧会话完整对话转写文件,新窗口的 AI 可随时回读旧会话全部内容。',
|
|
504
517
|
'★ 水位 v2:计量优先官方 token-meter(与聊天框 context ring 同源,免疫重启/压缩/流式干扰),启发式仅作降级;水位卡标注当前计量来源,窗口自动取官方路由容量。',
|
|
@@ -1836,6 +1849,9 @@ window.__ModuleLoader__.load({
|
|
|
1836
1849
|
err ? h('div', { 'data-dam-error': '' }, err) : null)
|
|
1837
1850
|
}
|
|
1838
1851
|
|
|
1852
|
+
// M-CM6-C 自动接续跨渲染状态(apply 作用域,插件生命周期存活;组件重挂不重置)
|
|
1853
|
+
var autoState = { cdIv: null, lastTokens: null }
|
|
1854
|
+
|
|
1839
1855
|
function PlanTab() {
|
|
1840
1856
|
var dataPair = useState(null)
|
|
1841
1857
|
var data = dataPair[0]
|
|
@@ -1853,6 +1869,39 @@ window.__ModuleLoader__.load({
|
|
|
1853
1869
|
var contMsgPair = useState('')
|
|
1854
1870
|
var contMsg = contMsgPair[0]
|
|
1855
1871
|
var setContMsg = contMsgPair[1]
|
|
1872
|
+
// M-CM6-C 自动接续(水位阈值触发,默认关;轮询 handoff-state,连续两轮水位不增长视为会话空闲)
|
|
1873
|
+
var autoPair = useState(null)
|
|
1874
|
+
var autoCfg = autoPair[0]
|
|
1875
|
+
var setAutoCfg = autoPair[1]
|
|
1876
|
+
var cdPair = useState(0)
|
|
1877
|
+
var cd = cdPair[0]
|
|
1878
|
+
var setCd = cdPair[1]
|
|
1879
|
+
useEffect(function () {
|
|
1880
|
+
apiGet(API.config).then(function (c) {
|
|
1881
|
+
setAutoCfg({ enabled: !(c && c.autoContinueEnabled === false), threshold: (c && Number(c.autoContinueThreshold)) || 0.8 })
|
|
1882
|
+
}).catch(function () { setAutoCfg({ enabled: false, threshold: 0.7 }) })
|
|
1883
|
+
}, [])
|
|
1884
|
+
var autoSave = function (patch) {
|
|
1885
|
+
setAutoCfg(function (p) { return Object.assign({}, p, patch) })
|
|
1886
|
+
apiPost(API.config, patch).catch(function () {})
|
|
1887
|
+
}
|
|
1888
|
+
var autoCancel = function () {
|
|
1889
|
+
if (autoState.cdIv) { clearInterval(autoState.cdIv); autoState.cdIv = null }
|
|
1890
|
+
setCd(0)
|
|
1891
|
+
}
|
|
1892
|
+
var autoStartCountdown = function () {
|
|
1893
|
+
if (autoState.cdIv) return
|
|
1894
|
+
var left = 30
|
|
1895
|
+
setCd(left)
|
|
1896
|
+
autoState.cdIv = setInterval(function () {
|
|
1897
|
+
left -= 1
|
|
1898
|
+
if (left <= 0) {
|
|
1899
|
+
clearInterval(autoState.cdIv); autoState.cdIv = null; setCd(0)
|
|
1900
|
+
try { localStorage.setItem('dsh-auto-memory.autoCont.last', String(Date.now())) } catch (eL) {}
|
|
1901
|
+
oneClickContinue()
|
|
1902
|
+
} else setCd(left)
|
|
1903
|
+
}, 1000)
|
|
1904
|
+
}
|
|
1856
1905
|
async function oneClickContinue() {
|
|
1857
1906
|
if (contBusy) return
|
|
1858
1907
|
setContBusy(true)
|
|
@@ -1892,6 +1941,30 @@ window.__ModuleLoader__.load({
|
|
|
1892
1941
|
apiGet(API.handoffState, { file: open }).then(function (d) { if (alive) setContent(d.text || '') }).catch(function () {})
|
|
1893
1942
|
return function () { alive = false }
|
|
1894
1943
|
}, [open])
|
|
1944
|
+
useEffect(function () {
|
|
1945
|
+
if (!autoCfg || !autoCfg.enabled) return
|
|
1946
|
+
var alive = true
|
|
1947
|
+
var tick = function () {
|
|
1948
|
+
apiGet(API.handoffState).then(function (d) {
|
|
1949
|
+
if (!alive || !d || !d.enabled) return
|
|
1950
|
+
var wl = d.waterLevel || {}
|
|
1951
|
+
if (!wl.window || !(wl.ratio >= (autoCfg.threshold || 0.7))) { autoState.lastTokens = null; return }
|
|
1952
|
+
var idle = autoState.lastTokens !== null && wl.tokens === autoState.lastTokens
|
|
1953
|
+
autoState.lastTokens = wl.tokens
|
|
1954
|
+
if (!idle) return
|
|
1955
|
+
var last = 0
|
|
1956
|
+
try { last = Number(localStorage.getItem('dsh-auto-memory.autoCont.last') || 0) } catch (eL) {}
|
|
1957
|
+
if (Date.now() - last < 30 * 60 * 1000) return
|
|
1958
|
+
autoStartCountdown()
|
|
1959
|
+
}).catch(function () {})
|
|
1960
|
+
}
|
|
1961
|
+
var iv = setInterval(tick, 20000)
|
|
1962
|
+
tick()
|
|
1963
|
+
return function () { alive = false; clearInterval(iv) }
|
|
1964
|
+
}, [autoCfg && autoCfg.enabled, autoCfg && autoCfg.threshold])
|
|
1965
|
+
useEffect(function () {
|
|
1966
|
+
return function () { if (autoState.cdIv) { clearInterval(autoState.cdIv); autoState.cdIv = null } }
|
|
1967
|
+
}, [])
|
|
1895
1968
|
if (!data) return h(Loading)
|
|
1896
1969
|
if (!data.enabled) return h(Card, { title: t('planTitle') }, h('div', { 'data-dam-hint': '' }, t('planDisabled')))
|
|
1897
1970
|
var wl = data.waterLevel || {}
|
|
@@ -1909,6 +1982,16 @@ window.__ModuleLoader__.load({
|
|
|
1909
1982
|
h('div', { 'data-dam-hint': '', style: { marginTop: '4px' } }, t('waterThresholdHint').replace('{t}', String(wl.threshold || 0.8))),
|
|
1910
1983
|
])))
|
|
1911
1984
|
}
|
|
1985
|
+
if (autoCfg && wl.window > 0) {
|
|
1986
|
+
rows.unshift(h(Card, { title: t('autoContTitle') }, h('div', { 'data-dam-content': '' }, [
|
|
1987
|
+
h('div', { 'data-dam-hint': '', style: { marginBottom: '6px' } }, t('autoContHint')),
|
|
1988
|
+
h('div', { 'data-dam-row': '' },
|
|
1989
|
+
h('button', { 'data-dam-btn': '', onClick: function () { autoCancel(); autoSave({ autoContinueEnabled: !autoCfg.enabled }) } }, autoCfg.enabled ? t('autoContOn') : t('autoContOff')),
|
|
1990
|
+
h('label', { 'data-dam-hint': '', style: { marginLeft: '8px' } }, t('autoContThreshold') + ' ',
|
|
1991
|
+
h('input', { 'data-dam-input': '', type: 'number', min: 0.5, max: 0.95, step: 0.05, value: String(autoCfg.threshold), style: { width: '64px' }, onChange: function (e) { var v = Number(e.target.value); if (v >= 0.5 && v <= 0.95) autoSave({ autoContinueThreshold: v }) } }))),
|
|
1992
|
+
cd > 0 ? h('div', { 'data-dam-hint': '', style: { marginTop: '6px', color: '#d4744f' } }, t('autoContCountdown').replace('{s}', String(cd)) + ' ', h('button', { 'data-dam-btn': '', onClick: autoCancel }, t('autoContCancel'))) : null,
|
|
1993
|
+
])))
|
|
1994
|
+
}
|
|
1912
1995
|
if (open) {
|
|
1913
1996
|
rows.unshift(h(Card, { title: t('planFileTitle') + ' · ' + open }, h('div', { 'data-dam-content': '' }, content || t('empty'))))
|
|
1914
1997
|
rows.push(h('button', { 'data-dam-btn': '', onClick: function () { setOpen(null); setContent('') } }, t('back')))
|
|
@@ -3198,6 +3281,105 @@ window.__ModuleLoader__.load({
|
|
|
3198
3281
|
// ───────────────────────── 设置页 ─────────────────────────
|
|
3199
3282
|
var STYLE_IDS = ['auto', 'life', 'professional']
|
|
3200
3283
|
var LOCALE_IDS_LIST = ['system', 'zh', 'en']
|
|
3284
|
+
// M-CM6-C v2·常驻自动接续 watcher(2026-09-08):全局生效,与面板/页签是否打开无关。
|
|
3285
|
+
// 条件:autoContinueEnabled !== false(缺省=开)&& 水位≥阈值(缺省0.8)&& 连续两轮 tokens 不增长(会话空闲)
|
|
3286
|
+
// && 距上次触发>30min → 30s 可取消倒计时 → 自动执行接续(写账本→建会话→切换→注入材料)。
|
|
3287
|
+
function AutoContinueHost() {
|
|
3288
|
+
var cfgP = useState(null)
|
|
3289
|
+
var acCfg = cfgP[0]
|
|
3290
|
+
var setAcCfg = cfgP[1]
|
|
3291
|
+
var cdP = useState(0)
|
|
3292
|
+
var acCd = cdP[0]
|
|
3293
|
+
var setAcCd = cdP[1]
|
|
3294
|
+
var stP = useState(null)
|
|
3295
|
+
var acSt = stP[0]
|
|
3296
|
+
var setAcSt = stP[1]
|
|
3297
|
+
var bsP = useState(false)
|
|
3298
|
+
var acBusy = bsP[0]
|
|
3299
|
+
var setAcBusy = bsP[1]
|
|
3300
|
+
useEffect(function () {
|
|
3301
|
+
var alive = true
|
|
3302
|
+
var load = function () {
|
|
3303
|
+
apiGet(API.config).then(function (c) { if (alive) setAcCfg(c || {}) }).catch(function () {})
|
|
3304
|
+
}
|
|
3305
|
+
load()
|
|
3306
|
+
var iv = setInterval(load, 30000)
|
|
3307
|
+
return function () { alive = false; clearInterval(iv) }
|
|
3308
|
+
}, [])
|
|
3309
|
+
useEffect(function () {
|
|
3310
|
+
var on = !(acCfg && acCfg.autoContinueEnabled === false)
|
|
3311
|
+
if (!on) return
|
|
3312
|
+
var thr = (acCfg && Number(acCfg.autoContinueThreshold)) || 0.8
|
|
3313
|
+
var alive = true
|
|
3314
|
+
var tick = function () {
|
|
3315
|
+
apiGet(API.handoffState).then(function (d) {
|
|
3316
|
+
if (!alive || !d || !d.enabled) return
|
|
3317
|
+
var wl = d.waterLevel || {}
|
|
3318
|
+
if (!wl.window || !(wl.ratio >= thr)) { autoState.lastTokens = null; return }
|
|
3319
|
+
var idle = autoState.lastTokens !== null && wl.tokens === autoState.lastTokens
|
|
3320
|
+
autoState.lastTokens = wl.tokens
|
|
3321
|
+
if (!idle || autoState.cdIv || acBusy) return
|
|
3322
|
+
var last = 0
|
|
3323
|
+
try { last = Number(localStorage.getItem('dsh-auto-memory.autoCont.last') || 0) } catch (eL) {}
|
|
3324
|
+
if (Date.now() - last < 30 * 60 * 1000) return
|
|
3325
|
+
setAcSt(null)
|
|
3326
|
+
var left = 30
|
|
3327
|
+
setAcCd(left)
|
|
3328
|
+
autoState.cdIv = setInterval(function () {
|
|
3329
|
+
left -= 1
|
|
3330
|
+
if (left <= 0) {
|
|
3331
|
+
clearInterval(autoState.cdIv); autoState.cdIv = null; setAcCd(0)
|
|
3332
|
+
runAutoContinue()
|
|
3333
|
+
} else setAcCd(left)
|
|
3334
|
+
}, 1000)
|
|
3335
|
+
}).catch(function () {})
|
|
3336
|
+
}
|
|
3337
|
+
var iv = setInterval(tick, 20000)
|
|
3338
|
+
tick()
|
|
3339
|
+
return function () { alive = false; clearInterval(iv) }
|
|
3340
|
+
}, [acCfg && acCfg.autoContinueEnabled === false, acCfg && (Number(acCfg.autoContinueThreshold) || 0.8), acBusy])
|
|
3341
|
+
var cancelAc = function () {
|
|
3342
|
+
if (autoState.cdIv) { clearInterval(autoState.cdIv); autoState.cdIv = null }
|
|
3343
|
+
setAcCd(0)
|
|
3344
|
+
}
|
|
3345
|
+
var runAutoContinue = function () {
|
|
3346
|
+
if (acBusy) return
|
|
3347
|
+
if (!remoteFace || !remoteFace.session || typeof remoteFace.session.create !== 'function') {
|
|
3348
|
+
setAcSt(locale === 'zh' ? '✗ remote.session 不可用——请重启 dsh web 后重试' : '✗ remote.session unavailable — restart dsh web')
|
|
3349
|
+
return
|
|
3350
|
+
}
|
|
3351
|
+
setAcBusy(true)
|
|
3352
|
+
setAcSt(locale === 'zh' ? '正在自动接续:写账本→建新会话→注入材料…' : 'Auto-continuing: ledger → new session → inject…')
|
|
3353
|
+
apiPost(API.handoffContinue, {}).then(function (d) {
|
|
3354
|
+
if (!d || !d.ok) throw new Error((d && d.error) || 'no handoff material')
|
|
3355
|
+
var p
|
|
3356
|
+
try { p = remoteFace.session.create(d.ws ? { cwd: d.ws } : {}) } catch (eC) { p = remoteFace.session.create({}) }
|
|
3357
|
+
return p.then(function (created) {
|
|
3358
|
+
var newId = created && (created.sessionId || created.id)
|
|
3359
|
+
if (!newId) throw new Error('create: no sessionId')
|
|
3360
|
+
var chain = Promise.resolve()
|
|
3361
|
+
if (d.provider && d.model && typeof remoteFace.session.selectModel === 'function') {
|
|
3362
|
+
chain = chain.then(function () { try { return remoteFace.session.selectModel({ sessionId: newId, provider: d.provider, model: d.model }) } catch (eM) { return null } })
|
|
3363
|
+
}
|
|
3364
|
+
return chain.then(function () {
|
|
3365
|
+
try { if (sessions && typeof sessions.open === 'function') sessions.open(newId) } catch (eO) {}
|
|
3366
|
+
var reqId = (window.crypto && typeof crypto.randomUUID === 'function') ? crypto.randomUUID() : 'ac-' + Date.now() + '-' + Math.random().toString(36).slice(2)
|
|
3367
|
+
return remoteFace.session.prompt({ requestId: reqId, sessionId: newId, mode: 'queue', content: [{ type: 'text', text: d.carryText }] })
|
|
3368
|
+
})
|
|
3369
|
+
})
|
|
3370
|
+
}).then(function () {
|
|
3371
|
+
try { localStorage.setItem('dsh-auto-memory.autoCont.last', String(Date.now())) } catch (eL) {}
|
|
3372
|
+
setAcSt(locale === 'zh' ? '✓ 已自动接续到新会话,可直接上手' : '✓ Auto-continued into a new session')
|
|
3373
|
+
setAcBusy(false)
|
|
3374
|
+
}).catch(function (e) { setAcSt('✗ ' + String(e && e.message ? e.message : e)); setAcBusy(false) })
|
|
3375
|
+
}
|
|
3376
|
+
if (acCd > 0 || acSt) {
|
|
3377
|
+
return h('div', { 'data-dam-autocont': '', style: { position: 'fixed', right: '16px', bottom: '16px', zIndex: 9000, maxWidth: 'min(440px, calc(100vw - 32px))', boxSizing: 'border-box', padding: '10px 12px', borderRadius: '12px', border: '1px solid rgba(128,128,128,.35)', background: 'rgba(18,22,30,.93)', color: '#e8eaed', fontSize: '12px', lineHeight: '1.55', fontFamily: 'system-ui', boxShadow: '0 10px 30px rgba(0,0,0,.35)', backdropFilter: 'blur(10px)' } },
|
|
3378
|
+
acCd > 0 ? h('div', null, t('autoContCountdown').replace('{s}', String(acCd)), ' ', h('button', { style: { marginLeft: '6px', border: '1px solid rgba(232,234,237,.45)', borderRadius: '8px', background: 'transparent', color: '#e8eaed', cursor: 'pointer', padding: '2px 10px' }, onClick: cancelAc }, t('autoContCancel'))) : null,
|
|
3379
|
+
acSt ? h('div', { style: acCd > 0 ? { marginTop: '4px' } : {} }, acSt) : null)
|
|
3380
|
+
}
|
|
3381
|
+
return null
|
|
3382
|
+
}
|
|
3201
3383
|
function SettingsPage() {
|
|
3202
3384
|
var tickPair = useTick()
|
|
3203
3385
|
var cfgPair = useState(null)
|
|
@@ -3423,7 +3605,15 @@ window.__ModuleLoader__.load({
|
|
|
3423
3605
|
if (detBusy) return
|
|
3424
3606
|
setDetOpen(true)
|
|
3425
3607
|
setDetBusy(true)
|
|
3426
|
-
apiGet(API.semanticDeepDetect).then(function (d) {
|
|
3608
|
+
apiGet(API.semanticDeepDetect).then(function (d) {
|
|
3609
|
+
setDet(d || {}); setDetBusy(false)
|
|
3610
|
+
// 2026-09-08:检测发现缺失时按当前模式自动打开对应安装引导卡(兑现「缺失时自动弹安装引导」)
|
|
3611
|
+
var rec = d && d.recommendation
|
|
3612
|
+
var mode = (cfg && cfg.semanticEngineMode) || 'auto'
|
|
3613
|
+
if (rec === 'setup-python' && mode === 'python') setGuide('python')
|
|
3614
|
+
else if ((rec === 'download-model' || rec === 'install-peer' || rec === 'setup-both') && mode !== 'python') setGuide('js')
|
|
3615
|
+
else if (rec === 'setup-both' && mode === 'python') setGuide('python')
|
|
3616
|
+
}).catch(function () { setDet({ failed: true }); setDetBusy(false) })
|
|
3427
3617
|
fetch('/api/dsh-auto-memory/semantic-status').then(function (r2) { return r2.json() }).then(function (j2) { setSem(Object.assign({ loaded: true }, j2)) }).catch(function () {})
|
|
3428
3618
|
}
|
|
3429
3619
|
function onEngineModeChange(e) {
|
|
@@ -3517,18 +3707,23 @@ window.__ModuleLoader__.load({
|
|
|
3517
3707
|
} else if (det) {
|
|
3518
3708
|
kids.push(row('JS 引擎模型', det.ready ? '✓ 就绪' : '✗ 未就绪'))
|
|
3519
3709
|
if (det.assetPath) kids.push(row('模型路径', String(det.assetPath).slice(-72) + (det.assetBytes ? ' (' + Math.round(det.assetBytes / 1048576) + 'MB)' : '')))
|
|
3520
|
-
|
|
3710
|
+
var pyReady = (det && det.pythonInt8Present !== undefined) ? det.pythonInt8Present : sem.pythonInt8Present
|
|
3711
|
+
kids.push(row('Python 模型(int8)', (pyReady === undefined || pyReady === null) ? (locale === 'zh' ? '状态未知' : 'unknown') : (pyReady ? '✓ 就绪' : '✗ 未就绪')))
|
|
3521
3712
|
kids.push(row('当前生效档位', tierText))
|
|
3522
3713
|
if (det.deep && det.deep.integrated) kids.push(row('深度扫描', locale === 'zh' ? '发现并热接入 ' + (det.deep.foundDirs || []).length + ' 处推理库(无需重启即生效)' : 'Hot-adopted ' + (det.deep.foundDirs || []).length + ' runtime dir(s) (no restart needed)'))
|
|
3523
3714
|
if (det.recommendation && det.recommendation !== 'none') {
|
|
3524
3715
|
kids.push(h('div', { 'data-dam-hint': '', style: { margin: '8px 0 6px' } }, locale === 'zh' ? '检测到缺失项,联动安装助手:' : 'Missing assets detected — open the setup assistant:'))
|
|
3525
3716
|
var btns = []
|
|
3526
3717
|
if (det.recommendation === 'download-model' || det.recommendation === 'setup-both') btns.push(h('button', { key: 'js', 'data-dam-btn': '', style: { marginRight: '6px' }, onClick: function () { setGuide('js'); setDetOpen(false) } }, locale === 'zh' ? '打开 JS 安装引导' : 'Open JS setup'))
|
|
3527
|
-
if (det.recommendation === 'setup-both') btns.push(h('button', { key: 'py', 'data-dam-btn': '', onClick: function () { setGuide('python'); setDetOpen(false) } }, locale === 'zh' ? '打开 Python 向导' : 'Open Python wizard'))
|
|
3718
|
+
if (det.recommendation === 'setup-both' || det.recommendation === 'setup-python') btns.push(h('button', { key: 'py', 'data-dam-btn': '', onClick: function () { setGuide('python'); setDetOpen(false) } }, locale === 'zh' ? '打开 Python 向导' : 'Open Python wizard'))
|
|
3528
3719
|
if (det.recommendation === 'install-peer') kids.push(h('div', { 'data-dam-hint': '', style: { marginTop: '4px' } }, locale === 'zh' ? '模型已就绪但推理库(@huggingface/transformers)缺失:请在其它设备安装后重试检测,或按 JS 引导重装。' : 'Model ready but runtime (@huggingface/transformers) missing: install it and re-scan, or reinstall via JS setup.'))
|
|
3529
3720
|
if (btns.length) kids.push(h('div', { style: { display: 'flex', gap: '6px' } }, btns))
|
|
3530
|
-
} else if (det.ready) {
|
|
3721
|
+
} else if (det.ready && det.pythonInt8Present !== false) {
|
|
3531
3722
|
kids.push(h('div', { 'data-dam-hint': '', style: { marginTop: '8px' } }, locale === 'zh' ? '✓ 一切就绪,无需安装。' : '✓ Everything is ready.'))
|
|
3723
|
+
} else if (det.ready) {
|
|
3724
|
+
// 2026-09-08 修复:JS 就绪但 Python 缺失不再显示「一切就绪」(此前 recommendation=none 导致矛盾+无引导)
|
|
3725
|
+
kids.push(h('div', { 'data-dam-hint': '', style: { margin: '8px 0 6px' } }, locale === 'zh' ? 'JS 引擎就绪;Python 模型未安装——仅影响 Python 引擎模式,当前模式不受影响。' : 'JS engine ready; the Python model is not installed — only the Python engine mode is affected.'))
|
|
3726
|
+
kids.push(h('div', { style: { display: 'flex', gap: '6px' } }, [h('button', { 'data-dam-btn': '', onClick: function () { setGuide('python'); setDetOpen(false) } }, locale === 'zh' ? '打开 Python 向导' : 'Open Python wizard')]))
|
|
3532
3727
|
}
|
|
3533
3728
|
}
|
|
3534
3729
|
return h('div', { 'data-dam-detect-panel': '', style: panelStyle }, kids)
|
|
@@ -3953,6 +4148,9 @@ window.__ModuleLoader__.load({
|
|
|
3953
4148
|
surfaceDisposers.push(slots.inject('shell.overlay', function () {
|
|
3954
4149
|
return slots.register({ name: 'shell.overlay', id: 'auto-memory-dialogs', order: 6 }, function () { return h(DialogHost) })
|
|
3955
4150
|
}))
|
|
4151
|
+
surfaceDisposers.push(slots.inject('shell.overlay', function () {
|
|
4152
|
+
return slots.register({ name: 'shell.overlay', id: 'auto-memory-autocont', order: 7 }, function () { return h(AutoContinueHost) })
|
|
4153
|
+
}))
|
|
3956
4154
|
surfaceDisposers.push(slots.inject('settings.section', function () {
|
|
3957
4155
|
return slots.register({ name: 'settings.section', id: 'auto-memory', order: 25, label: t('autoMemory') + ' (pre)' }, function (props) { return h(SettingsPage, { close: props && props.close }) })
|
|
3958
4156
|
}))
|
package/lib/index.js
CHANGED
|
@@ -5302,14 +5302,25 @@ export function apply(ctx, config) {
|
|
|
5302
5302
|
} catch (_) { /* 扫描失败按未命中处理 */ }
|
|
5303
5303
|
}
|
|
5304
5304
|
const after = await engine.semanticAssetProbe()
|
|
5305
|
-
|
|
5306
|
-
|
|
5307
|
-
|
|
5308
|
-
|
|
5305
|
+
// 2026-09-08 修复:检测面补 Python int8 探测——此前 recommendation 只看 JS 的 after.ready,
|
|
5306
|
+
// JS 就绪+Python 模型缺失时恒报 'none',面板同屏「Python ✗ 未就绪」与「✓ 一切就绪」且永不弹安装引导。
|
|
5307
|
+
let pythonInt8Present = false
|
|
5308
|
+
try {
|
|
5309
|
+
const fsMod = await import('node:fs')
|
|
5310
|
+
const pyCands = (engine._pythonSetup ? [engine._pythonSetup.modelPath()] : []).concat([
|
|
5311
|
+
path.join(pluginRootDir(), 'python', 'bench', 'models-xenova-bge-m3-int8', 'onnx', 'model_int8.onnx'),
|
|
5312
|
+
])
|
|
5313
|
+
pythonInt8Present = pyCands.some((c) => fsMod.existsSync(c))
|
|
5314
|
+
} catch (_) {}
|
|
5315
|
+
const recommendation = (after.ready && pythonInt8Present) ? 'none'
|
|
5316
|
+
: !after.ready ? ((!after.assetPresent && !after.peerPresent) ? 'setup-both'
|
|
5317
|
+
: (!after.peerPresent) ? 'install-peer' : 'download-model')
|
|
5318
|
+
: 'setup-python'
|
|
5309
5319
|
return {
|
|
5310
5320
|
assetPresent: after.assetPresent,
|
|
5311
5321
|
peerPresent: after.peerPresent,
|
|
5312
5322
|
ready: after.ready,
|
|
5323
|
+
pythonInt8Present,
|
|
5313
5324
|
assetBytes: after.assetBytes,
|
|
5314
5325
|
assetPath: after.assetPath,
|
|
5315
5326
|
resolvedTier: await engine.resolveSemanticTier(),
|
|
@@ -5324,7 +5335,16 @@ export function apply(ctx, config) {
|
|
|
5324
5335
|
// 2026-08-27 修正:区分引擎模式(修复「怎么切都显示 C2」)。
|
|
5325
5336
|
// lexical→c1 强制;python→c3(高级档);auto/js→资产就绪 c2 否则 c1。
|
|
5326
5337
|
if (mode === 'lexical') return 'c1'
|
|
5327
|
-
if (mode === 'python')
|
|
5338
|
+
if (mode === 'python') {
|
|
5339
|
+
// 2026-09-08 修复:python 模式不再无条件报 C3——int8 模型缺失时实际在词法兜底,应报 c1。
|
|
5340
|
+
try {
|
|
5341
|
+
const fsMod = await import('node:fs')
|
|
5342
|
+
const pyCands = (engine._pythonSetup ? [engine._pythonSetup.modelPath()] : []).concat([
|
|
5343
|
+
path.join(pluginRootDir(), 'python', 'bench', 'models-xenova-bge-m3-int8', 'onnx', 'model_int8.onnx'),
|
|
5344
|
+
])
|
|
5345
|
+
return pyCands.some((c) => fsMod.existsSync(c)) ? 'c3' : 'c1'
|
|
5346
|
+
} catch (_) { return 'c1' }
|
|
5347
|
+
}
|
|
5328
5348
|
try { return (await engine.semanticAssetProbe()).ready ? 'c2' : 'c1' } catch (_) { return 'c1' }
|
|
5329
5349
|
}
|
|
5330
5350
|
// context-host refs 选择钩子:C2 就绪时返回 {scores:Map};任何失败回退词法序。
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@a9i5k4/dsh-auto-memory",
|
|
3
3
|
"description": "Proactive associative memory for DSH: zero-prompt recall injected before the model speaks, three-layer auto-consolidation, skill crystallization, and Astra-style context management - handoff ledgers, PLAN whiteboard, water-level sensing. Local-first, model-agnostic, zero deps. 主动联想记忆+Astra 式上下文管理:自动唤回/自动沉淀/技能固化/交接账本与白板跨窗口续命/水位感知。",
|
|
4
|
-
"version": "2.2.
|
|
4
|
+
"version": "2.2.2",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"exports": {
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
},
|
|
23
23
|
"client": {
|
|
24
24
|
"inject": [
|
|
25
|
+
"@deepseek-ai/dsh-api-remotes",
|
|
25
26
|
"@deepseek-ai/dsh-client-runtime",
|
|
26
27
|
"@deepseek-ai/dsh-client-connection",
|
|
27
28
|
"@deepseek-ai/dsh-client-ui-slots",
|