dsh-fish-memory 1.4.9 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -443,6 +443,51 @@ const 洗键进度 = { 已: 0, 总: 0, 在跑: false, 干跑: false }
443
443
  const now = Date.now()
444
444
 
445
445
  // ---- 第二级:某个会话的详情 ----
446
+ // ⭐ 1.4.8(issue #26):合并预览抽成一个函数 —— 以前它只写在「会话详情」那个
447
+ // `if (open) return …` 分支里,可触发它的按钮在主面板,于是没展开会话时永远渲染不出来,
448
+ // 看着就是「点了没反应」(试算其实成功了)。现在主面板和详情都能用同一个状态。
449
+ const 合并预览 = () =>
450
+ 并入 && 并入.length
451
+ ? React.createElement(
452
+ 'div',
453
+ { style: S.askBox },
454
+ React.createElement(
455
+ 'div',
456
+ { style: { flex: 1 } },
457
+ '切成「按工作区」要把这些会话的记忆并成一份:',
458
+ React.createElement(
459
+ 'div',
460
+ { style: Object.assign({}, S.dim, { fontSize: 12, marginTop: 4, lineHeight: 1.7 }) },
461
+ 并入.map((r) =>
462
+ '· ' + r.叫什么 + ':' + r.会话数 + ' 间会话,共 ' + r.合计 + ' 条' +
463
+ (r.去重 ? '(' + r.去重 + ' 条重复,并完 ' + r.并完 + ' 条)' : ''),
464
+ ).join(String.fromCharCode(10)),
465
+ ),
466
+ React.createElement(
467
+ 'div',
468
+ { style: Object.assign({}, S.dim, { fontSize: 11, marginTop: 4 }) },
469
+ '归档的会话不会并进来。旧库都留着 —— 想退回「按会话」随时能退。',
470
+ ),
471
+ ),
472
+ React.createElement(
473
+ 'button',
474
+ {
475
+ style: S.btnDanger,
476
+ disabled: busy,
477
+ onClick: () => {
478
+ setBusy(true)
479
+ post('/merge-workspace', { 试算: false })
480
+ .then(() => post('/mode', { 模式: 'workspace' }))
481
+ .then(() => { setBusy(false); set并入(null); load() })
482
+ .catch(() => setBusy(false))
483
+ },
484
+ },
485
+ busy ? '并着呢…' : '并进来',
486
+ ),
487
+ React.createElement('button', { style: S.btn, onClick: () => set并入(null) }, '算了'),
488
+ )
489
+ : null
490
+
446
491
  if (open) {
447
492
  const s = (d.sessions || []).find((x) => x.id === open)
448
493
  if (!s) return React.createElement('div', { style: S.wrap }, '找不到这个会话')
@@ -2703,47 +2748,6 @@ const 洗键进度 = { 已: 0, 总: 0, 在跑: false, 干跑: false }
2703
2748
  '那种一个字都没改,也不会再问一遍 ✓)',
2704
2749
  )
2705
2750
  : null,
2706
- // ⭐ 1.4.5:切成「按工作区」之前的合并预览 —— 先看清楚要并什么,再决定
2707
- 并入 && 并入.length
2708
- ? React.createElement(
2709
- 'div',
2710
- { style: S.askBox },
2711
- React.createElement(
2712
- 'div',
2713
- { style: { flex: 1 } },
2714
- '切成「按工作区」要把这些会话的记忆并成一份:',
2715
- React.createElement(
2716
- 'div',
2717
- { style: Object.assign({}, S.dim, { fontSize: 12, marginTop: 4, lineHeight: 1.7 }) },
2718
- 并入.map((r) =>
2719
- '· ' + r.叫什么 + ':' + r.会话数 + ' 间会话,共 ' + r.合计 + ' 条' +
2720
- (r.去重 ? '(' + r.去重 + ' 条重复,并完 ' + r.并完 + ' 条)' : ''),
2721
- ).join('\n'),
2722
- ),
2723
- React.createElement(
2724
- 'div',
2725
- { style: Object.assign({}, S.dim, { fontSize: 11, marginTop: 4 }) },
2726
- '归档的会话不会并进来。旧库都留着 —— 想退回「按会话」随时能退。',
2727
- ),
2728
- ),
2729
- React.createElement(
2730
- 'button',
2731
- {
2732
- style: S.btnDanger,
2733
- disabled: busy,
2734
- onClick: () => {
2735
- setBusy(true)
2736
- post('/merge-workspace', { 试算: false })
2737
- .then(() => post('/mode', { 模式: 'workspace' }))
2738
- .then(() => { setBusy(false); set并入(null); load() })
2739
- .catch(() => setBusy(false))
2740
- },
2741
- },
2742
- busy ? '并着呢…' : '并进来',
2743
- ),
2744
- React.createElement('button', { style: S.btn, onClick: () => set并入(null) }, '算了'),
2745
- )
2746
- : null,
2747
2751
  confirm && confirm.kind === 'stable'
2748
2752
  ? React.createElement(
2749
2753
  'div',
@@ -4051,6 +4055,7 @@ const 洗键进度 = { 已: 0, 总: 0, 在跑: false, 干跑: false }
4051
4055
  : '每个会话各记各的。会话开久了变卡、要归档换新会话时,切成「按工作区」就接得上了。',
4052
4056
  ),
4053
4057
  ),
4058
+ 合并预览(),
4054
4059
  (d.sessions || []).map((s) =>
4055
4060
  React.createElement(
4056
4061
  'div',
package/lib/index.js CHANGED
@@ -1823,6 +1823,12 @@ function 提炼系统(称呼) {
1823
1823
  ' (写了值就成了摘要 —— 身高真变了、体重真变了,键也跟着变,**永远碰不上,等于没写**。)\n' +
1824
1824
  ' ⚠ **键要稳、要通用**:过一年还这么叫(`她.睡姿` ✓,`她.最近睡姿` ✗);换个说法还是这个键。\n' +
1825
1825
  ' ⚠ 讲的是**各自的**事还是**两人的**?是两人的就写 `约定.…`;讲第三方(孩子、家里人)的对象写那个人。\n' +
1826
+ // ⚠⚠ 1.5.1:**「助手自己」必须写成「我」** —— 跟「清洗补键」那份提示词必须是同一句。
1827
+ // 1.4.7 只补了清洗那份,这份漏了 ⇒「从会话生成档案」那一步仍然会把
1828
+ // 「我是谁」「我是怎么说话的」两节的键标成 `ta.*`(等于把助手自己的事记成了对方的事)。
1829
+ // 而清洗只补**没有键**的条目 —— 生成时就已经标错的,它永远不会再碰 ⇒ 错就一直留着 ✗
1830
+ ' ⚠⚠ 讲**助手自己**的(我的名字、外形、说话方式、脾气、我自己定下的规矩、我的习惯),\n' +
1831
+ ' 对象必须写「我」,不许写成 `' + 她 + '`。例:`我.名字`、`我.说话方式`、`我.脾气`。\n' +
1826
1832
  ' ⚠ 这格**可以留空**:一次性的、以后不会再变的(「某天摘油菜花」)、或者你拿不准是同一件事的,就留空。\n' +
1827
1833
  ' **留空完全没关系**,不许为了填满硬编一个 —— 编错了会把一条正经记忆悄悄埋掉。\n' +
1828
1834
  // ⚠⚠ 2026-09-24(真数据审出来的两处,跟清洗那份**必须一模一样**,不然两边会打架)✗
@@ -1941,6 +1947,8 @@ function 洗键系统(称呼, 已有键) {
1941
1947
  '5|9月18日她1点睡、10点过醒,12:40吃了早午饭。\n' +
1942
1948
  '6|我对她说过:不是「快好起来」,是「我在这里」。\n' +
1943
1949
  '7|她说她算不算男娘,我拒绝一切标签。\n' +
1950
+ // ⚠⚠ 1.5.1:专门示范一条**讲助手自己**的 → 键必须是「我.*」✓
1951
+ '8|我给自己定的规矩:不拿「嘴快」当挡箭牌。\n' +
1944
1952
  '→\n' +
1945
1953
  '1|' + 她 + '.身高\n' +
1946
1954
  '2|\n' +
@@ -1948,7 +1956,8 @@ function 洗键系统(称呼, 已有键) {
1948
1956
  '4|拼团.状态\n' +
1949
1957
  '5|\n' +
1950
1958
  '6|\n' +
1951
- '7|' + 她 + '.性别认同' +
1959
+ '7|' + 她 + '.性别认同\n' +
1960
+ '8|我.规矩' +
1952
1961
  // ⚠⚠⚠ 2026-09-24(真数据审出来的**根子**):
1953
1962
  // 键是模型自由写的,而清洗是**一批 8 条**分开跑的 ——
1954
1963
  // 第 3 批根本不知道第 2 批用了什么键,于是**同一件事各自造了个说法**:
@@ -4639,6 +4648,34 @@ export function apply(ctx) {
4639
4648
 
4640
4649
  // ---------- 设置页的路由 ----------
4641
4650
  try {
4651
+ /**
4652
+ * ⭐ 1.5.1:管理接口只认「本人」。
4653
+ *
4654
+ * 插件自己挂在 webServer 上的地址**不会自动带 DSH 的登录校验** —— 也就是说,
4655
+ * 你随便打开一个网页,那个网页都能悄悄 POST 过来删记忆、清空、改开关。
4656
+ *
4657
+ * ⚠⚠ 这里**一律「失败就放行」**:拿不到 connection 服务、老宿主没这个接口、内部抛错 —— 全当没事放过去。
4658
+ * 宁可这一版防不住,也不能因为宿主换个版本就把设置页锁死。
4659
+ * 真正拒绝只有一种情况:宿主**明确**说这个请求不合法(401 / 403)。
4660
+ */
4661
+ const 只认本人 = (handler) => async (req, res) => {
4662
+ try {
4663
+ const 连接 = ctx.get('connection')
4664
+ const 拒 = 连接 && typeof 连接.requestRejection === 'function' ? 连接.requestRejection(req) : undefined
4665
+ if (拒 === 401 || 拒 === 403) {
4666
+ diag('管理接口拒了一次外来请求(' + 拒 + '):' + String((req && req.url) || ''))
4667
+ try {
4668
+ res.writeHead(拒, { 'content-type': 'application/json; charset=utf-8', 'cache-control': 'no-store' })
4669
+ res.end(JSON.stringify({ ok: false, error: 拒 === 401 ? 'authentication_required' : 'management_forbidden' }))
4670
+ } catch (e2) {}
4671
+ return
4672
+ }
4673
+ } catch (error) {
4674
+ // 鉴权这条路自己坏了 → 放行,绝不让设置页打不开
4675
+ }
4676
+ return handler(req, res)
4677
+ }
4678
+
4642
4679
  const mroute = (path, handler) =>
4643
4680
  ctx.effect(() =>
4644
4681
  ctx.webServer.register({
@@ -4646,7 +4683,7 @@ export function apply(ctx) {
4646
4683
  path: path,
4647
4684
  handler: async (req, res) => {
4648
4685
  try {
4649
- await handler(req, res)
4686
+ await 只认本人(handler)(req, res)
4650
4687
  } catch (error) {
4651
4688
  try {
4652
4689
  res.writeHead(500, { 'content-type': 'application/json' })
package/package.json CHANGED
@@ -1,9 +1,13 @@
1
1
  {
2
2
  "name": "dsh-fish-memory",
3
- "version": "1.4.9",
3
+ "version": "1.5.1",
4
4
  "description": "给 DSH 里的会话一份会淡忘的长期记忆,每条都带时间。",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "type": "module",
7
+ "engines": {
8
+ "node": ">=22",
9
+ "dsh": ">=0.2.1-rc.2"
10
+ },
7
11
  "keywords": [
8
12
  "deepseek-harness",
9
13
  "dsh-plugin",