dsh-lite-memory 0.18.26 → 0.18.27

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.
@@ -83,9 +83,10 @@
83
83
  **范围路由**:模型给的 `scope` 是提案,不是命令。
84
84
 
85
85
  - 显式 `scope="global"` 表示「用户在这一次对话里要求存全局」,只有用户确实这么说才传;模型自己觉得通用不是理由。显式全局不再因为缺少 `evidenceRef` 被降级。
86
- - 仍然会拦住的两类:设备事实没有条件(`machine` / `targetOs` / `runtime` / `shell` 至少一个),以及正文或依据里出现本机路径、回环地址、端口的「通用流程」——后者换台机器/换个项目就不成立,留在项目层。
86
+ - 仍然会拦住的两类:设备事实没有条件(`machine` / `targetOs` / `runtime` / `shell` 至少一个),以及正文或依据里写死本机路径、回环地址、端口却没声明适用环境的「通用流程」——后者换台机器/换个项目就不成立,留在项目层。
87
+ - 声明了上述环境条件的本机流程(例如本机特有的命令包装)可以进全局层:条件不成立的机器上不会拿出来用;命令名/工具名本身不算本机痕迹。
87
88
  - `memoryClass="project_fact"` 不因写了 `global` 就变全局:项目事实换个项目本来就不成立。
88
- - 按类别推导(没有显式 `scope`)保持更严:`portable_procedure` 没有 `evidenceRef` 就落项目层。
89
+ - 按类别推导(没有显式 `scope`)保持更严:`portable_procedure` 没有 `evidenceRef`、也没有环境条件时落项目层。
89
90
  - 每次降级都要能解释:只在降级时返回 `scopeNote` 一行,说明为什么没进全局、怎么改才进得去;正常落全局或落项目不带这行。
90
91
 
91
92
  **限额与腾位**:每层活跃条目软上限 200、硬上限 1000;单条正文 4096 字节;单层总字节 1 MiB。到硬上限时把最久没被读的活跃条目移进归档,并在结果里写明「已归档「标题」腾位」,不拒绝新记忆;单条正文超限只报错、不截断。
@@ -0,0 +1,5 @@
1
+ # 0.18.27
2
+
3
+ - 可信上下文补上宿主真实平台(`darwin → macos`,`win32 → windows`):条件写 `targetOs` 的规则从「永远待确认」变成按平台裁决,macOS 上写的本机流程在 macOS 上直接生效。
4
+ - 此前全局层只能收「声明了 machine/runtime 条件」的流程,但条件无从比对;这次把能自动核验的那一维接上,条件不再只是摆设。
5
+ - 召回夹具改用与平台无关的条件,避免 CI 与开发机行为不一致。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-lite-memory",
3
- "version": "0.18.26",
3
+ "version": "0.18.27",
4
4
  "description": "On-demand memory for the DeepSeek Harness: nothing resident, at most three small cards on a real hit, bodies read on demand.",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -460,6 +460,8 @@ const pass = (text, id) => async () => ({
460
460
  messages: [{ role: 'user', id, source: { kind: 'user' }, content: [{ type: 'text', text }] }],
461
461
  });
462
462
  const recall = promptContexts.find((entry) => entry.name === 'lite-memory:recall');
463
+ /* CI 冷启动偶尔超过召回耗时上限,逻辑断言不该被「这轮先不注入」判失败。 */
464
+ globalThis.__liteMemoryRecall?.setDeadlineMs?.(5000);
463
465
  assert.ok(recall, 'recall context registered');
464
466
  assert.equal(recall.order, 60);
465
467
  assert.equal(recall.interpolate, false);
@@ -545,6 +547,8 @@ const evoEnter = async () => ({
545
547
  });
546
548
  await preStep({ agent: evoAgent, signal: evoSig, turn: '21' }, evoEnter);
547
549
  const evoRecall = promptContexts.find((entry) => entry.name === 'lite-memory:recall');
550
+ /* CI 冷启动偶尔超过召回耗时上限,逻辑断言不该被「这轮先不注入」判失败。 */
551
+ globalThis.__liteMemoryRecall?.setDeadlineMs?.(5000);
548
552
  assert.match(evoRecall.text({ agent: evoAgent, signal: evoSig }), /开场三句内给结论/);
549
553
  assert.equal(evoRecall.text({ agent: evoAgent, signal: evoSig }).includes('README'), false);
550
554
 
@@ -33,6 +33,8 @@ function boot() {
33
33
  };
34
34
  apply(ctx, { mode: 'adaptive' });
35
35
  const provider = promptContexts.find((entry) => entry.name === 'lite-memory:recall');
36
+ /* CI 冷启动偶尔超过召回耗时上限,逻辑断言不该被「这轮先不注入」判失败。 */
37
+ globalThis.__liteMemoryRecall?.setDeadlineMs?.(5000);
36
38
  const exec = (name, args, agent) => defs.get(name).execute(args, { agent });
37
39
  const preStep = (payload, decision) => handlers.get('agent/pre-step').at(-1)(payload, async () => decision);
38
40
  return { exec, preStep, text: (agent, signal) => provider.text({ agent, signal }), debug: globalThis.__liteMemoryRecall };
@@ -39,6 +39,8 @@ function boot(mode = 'adaptive') {
39
39
  apply(ctx, { mode });
40
40
  const debug = globalThis.__liteMemoryRecall;
41
41
  const provider = promptContexts.find((entry) => entry.name === 'lite-memory:recall');
42
+ /* CI 冷启动偶尔超过召回耗时上限,逻辑断言不该被「这轮先不注入」判失败。 */
43
+ globalThis.__liteMemoryRecall?.setDeadlineMs?.(5000);
42
44
  assert.ok(provider, 'recall provider registered');
43
45
  assert.equal(provider.order, 60);
44
46
  assert.equal(provider.interpolate, false);
@@ -111,8 +113,8 @@ const linuxOnly = save(scopeA, {
111
113
  tags: ['插件', '构建'],
112
114
  when: '',
113
115
  applicability: 'conditional',
114
- conditions: [{ key: 'targetOs', value: 'linux' }],
115
- summary: '只在 Linux CI 上跑构建检查',
116
+ conditions: [{ key: 'machine', value: '别的机器' }],
117
+ summary: '只在另一台机器上跑构建检查',
116
118
  });
117
119
  const unresolved = save(scopeA, { title: '发布前要检查什么', tags: ['发布', '检查'], when: '发布前', applicability: 'unresolved' });
118
120
  const globalHot = save(global, { title: '插件改动后先热刷新', tags: ['插件', '热刷新'], summary: '全局规矩:先热刷新再谈重启' });
@@ -266,10 +268,10 @@ assert.notEqual(bootA.provider.text({ agent: agentB, signal: signalB }), prepare
266
268
  const cwdC = mkdir('c');
267
269
  const scopeC = store.scopeOf(cwdC);
268
270
  save(scopeC, {
269
- title: '只在 Linux 上跑构建检查',
271
+ title: '只在另一台机器上跑构建检查',
270
272
  tags: ['构建'],
271
273
  applicability: 'conditional',
272
- conditions: [{ key: 'targetOs', value: 'linux' }],
274
+ conditions: [{ key: 'machine', value: '别的机器' }],
273
275
  });
274
276
  save(scopeC, { title: '发布前检查清单', tags: ['发布'], when: '发布前', applicability: 'unresolved' });
275
277
  const agent = makeAgent('agent-cond', cwdC);
@@ -33,6 +33,8 @@ function boot(mode = 'adaptive') {
33
33
  };
34
34
  apply(ctx, { mode });
35
35
  const provider = promptContexts.find((entry) => entry.name === 'lite-memory:recall');
36
+ /* CI 冷启动偶尔超过召回耗时上限,逻辑断言不该被「这轮先不注入」判失败。 */
37
+ globalThis.__liteMemoryRecall?.setDeadlineMs?.(5000);
36
38
  assert.ok(provider, 'recall provider registered');
37
39
  const exec = (name, args, agent) => defs.get(name).execute(args, { agent });
38
40
  const preStep = (payload, decision) => handlers.get('agent/pre-step').at(-1)(payload, async () => decision);
@@ -70,7 +70,11 @@ test('条件裁决:不把不知道当不存在,也不把未解决当普遍
70
70
  const record = { id: 'mem_000000000001', applicability: 'conditional', conditions: [{ key: 'targetOs', value: 'macOS' }], when: '' };
71
71
  assert.equal(view.evaluate(record, ctxOf(null, { targetOs: 'macos' })).state, 'match');
72
72
  assert.equal(view.evaluate(record, ctxOf(null, { targetOs: 'linux' })).state, 'mismatch');
73
- assert.equal(view.evaluate(record, ctxOf(null, {})).state, 'unknown');
73
+ assert.equal(ctxOf(null, {}).targetOs, view.hostTargetOs());
74
+ const hostRecord = { ...record, conditions: [{ key: 'targetOs', value: view.hostTargetOs() || 'macos' }] };
75
+ assert.equal(view.evaluate(hostRecord, ctxOf(null, {})).state, 'match');
76
+ const machineOnly = { ...record, conditions: [{ key: 'machine', value: '这台机器' }] };
77
+ assert.equal(view.evaluate(machineOnly, ctxOf(null, {})).state, 'unknown');
74
78
  const unresolved = { ...record, applicability: 'unresolved', conditions: [] };
75
79
  assert.equal(view.statusOf(unresolved, ctxOf(null, {})), 'needs_context');
76
80
  assert.equal(view.canAutoRecall(unresolved, ctxOf(null, {})), false);
package/view.js CHANGED
@@ -152,7 +152,8 @@ export function validateApplicability(applicability, conditions, selection, when
152
152
  export function trustedContext(scope, options = {}) {
153
153
  const cwd = typeof options.cwd === 'string' && options.cwd ? options.cwd : (scope && scope.cwd) || '';
154
154
  return {
155
- targetOs: options.targetOs,
155
+ /** 宿主的真实平台是可信上下文:条件里写 targetOs 的规则本职就是按平台生效。 */
156
+ targetOs: options.targetOs === undefined ? hostTargetOs() : options.targetOs,
156
157
  shell: options.shell,
157
158
  runtime: options.runtime,
158
159
  machine: options.machine,
@@ -166,6 +167,15 @@ export function trustedContext(scope, options = {}) {
166
167
  };
167
168
  }
168
169
 
170
+ /** 只报归一化后的平台名;未知平台不硬猜,留给条件判 unknown。 */
171
+ export function hostTargetOs() {
172
+ const platform = typeof process !== 'undefined' && process ? process.platform : '';
173
+ if (platform === 'darwin') return 'macos';
174
+ if (platform === 'win32') return 'windows';
175
+ if (platform === 'linux') return 'linux';
176
+ return '';
177
+ }
178
+
169
179
  function sameText(left, right) {
170
180
  return plain(left, PATH_CHARS).toLowerCase() === plain(right, PATH_CHARS).toLowerCase();
171
181
  }