dsh-prime-memory 0.26.19 → 0.26.20

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/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # 更新日志(Changelog)
2
2
 
3
+ ## [0.26.20] — 2026-11-02
4
+
5
+ - **内部命名与计划对齐**:共用取数助手按其计划原名 `mergeRoomCatalog()` 落地(0.26.18/0.26.19 线上产物里叫 `roomCountsBySlug()`,功能与形状不变,纯内部导出名,无外部消费方)。同时重写该函数的文档注释:原先「四处同形中三处已正确」的表述不准确,现按实证写明 rooms-export / room-admin list / 候选词表三处已接,而 rooms-get 端点除计数外还要把注册表 `source`/`label` 覆盖回已存在条目,属不同形状,有意不接(该处就地留了说明注释)。
6
+ - **真机启动自证(新)**:在隔离的一次性 profile `t44probe`(`--from-default-profile web` 新建,不触碰任何现有 profile)上安装 `dsh-prime-memory@0.26.19` 与 `dsh-reference-session-collector`,以 `dsh --profile t44probe` 启动宿主:正常起立于 `http://127.0.0.1:3080/`,token 换 cookie 后根路径 200,装载全程无 compat 报错、无拒载(该线 `engines.dsh` 0.2.0-rc.2 在声明内)。**注意边界**:本自证只覆盖「装载与启动不异常」,#20 的随机端口探针分支仍未在此验证 —— web 线宿主端口是固定默认 3080,随机监听口只存在于桌面端宿主,该分支仍待桌面端装机冒烟。
7
+
3
8
  ## [0.26.19] — 2026-11-02
4
9
 
5
10
  - **#20 加固(属性测试 + 形状一致)**:新增 `resolveDrscBaseUrl` 优先级的确定性属性测试(固定种子 mulberry32,400 + 300 组随机组合),钉住四条不变式:显式值恒为终值、有非空 trustedHosts 条目时 origin 不得抢位、origin 只替换那句 8080、前两档之外的来源一律不回显 Host 头。**该测试首遍即抓出一处真实形状不一致**:显式值/条目分支会给裸 authority 补 `http://` 前缀,而新增的 origin 分支原样透传不补——若调用方递的是 `127.0.0.1:<port>` 这类 authority(而非宿主 `getOrigin()` 返回的全 URL),就会拼出无 scheme 的基址。已抽单一 `withScheme()` 让三档共用同一规范化。
@@ -27,14 +27,19 @@ export declare const ROOM_CANDIDATES_KEY = "roomCandidates";
27
27
  export declare const ROOM_REVIEW_KEY = "roomReview";
28
28
  export type RoomReviewState = 'pending' | 'confirmed' | 'skipped';
29
29
  /**
30
- * `listRooms()` 结果里的 slug→计数索引(单点定义,供四个消费方共用)。
30
+ * `listRooms()` 结果的 slug→计数索引(单点取数口径,名字沿用计划里的
31
+ * `mergeRoomCatalog`:它要收的就是「注册表条目 × 自生长条目的合并词表」这一步的
32
+ * 取数语义,返回值本身是查表用的 Map,不产出合并后的目录)。
31
33
  *
32
- * 为何需要它(issue #27):同一句「注册表条目的真实计数」在本仓写了四处,其中三处
33
- * 已经是对的形态(`stats.ts` 的 rooms-get / rooms-export、`tools` 的 room-admin list),
34
- * 只有候选词表这一处把算好的计数**写死成 0**。计数一旦有本地定义就有分叉位,
35
- * 所以取数口径收到这里,各调用点只剩「查不到时给多少」这一个本地决策。
34
+ * 为何需要它(issue #27):同一句「注册表条目的真实计数」在本仓写过四处,其中三处
35
+ * 已接这里(本文件的候选词表、`stats.ts` 的 rooms-export、`tools` 的 room-admin
36
+ * list),只有候选词表那一处历史上把算好的计数**写死成 0**。计数一旦有本地定义就有
37
+ * 分叉位,所以取数口径收到这里,各调用点只剩「查不到时给多少」这一个本地决策。
38
+ *
39
+ * 第四处 `stats.ts` 的 rooms-get 有意不接:它除计数外还要把注册表的
40
+ * `source`/`label` 覆盖回已存在条目,不属同一个形状(见那处的注释)。
36
41
  */
37
- export declare function roomCountsBySlug(rooms: readonly RoomCount[]): Map<string, number>;
42
+ export declare function mergeRoomCatalog(rooms: readonly RoomCount[]): Map<string, number>;
38
43
  /** 复查与候选操作对 L1 的最小依赖面(便于测试注入)。 */
39
44
  export interface RoomReviewStore {
40
45
  list(opts: {
@@ -3,14 +3,19 @@ import { callLLM, parseJsonLogged } from './llm.js';
3
3
  export const ROOM_CANDIDATES_KEY = 'roomCandidates';
4
4
  export const ROOM_REVIEW_KEY = 'roomReview';
5
5
  /**
6
- * `listRooms()` 结果里的 slug→计数索引(单点定义,供四个消费方共用)。
6
+ * `listRooms()` 结果的 slug→计数索引(单点取数口径,名字沿用计划里的
7
+ * `mergeRoomCatalog`:它要收的就是「注册表条目 × 自生长条目的合并词表」这一步的
8
+ * 取数语义,返回值本身是查表用的 Map,不产出合并后的目录)。
7
9
  *
8
- * 为何需要它(issue #27):同一句「注册表条目的真实计数」在本仓写了四处,其中三处
9
- * 已经是对的形态(`stats.ts` 的 rooms-get / rooms-export、`tools` 的 room-admin list),
10
- * 只有候选词表这一处把算好的计数**写死成 0**。计数一旦有本地定义就有分叉位,
11
- * 所以取数口径收到这里,各调用点只剩「查不到时给多少」这一个本地决策。
10
+ * 为何需要它(issue #27):同一句「注册表条目的真实计数」在本仓写过四处,其中三处
11
+ * 已接这里(本文件的候选词表、`stats.ts` 的 rooms-export、`tools` 的 room-admin
12
+ * list),只有候选词表那一处历史上把算好的计数**写死成 0**。计数一旦有本地定义就有
13
+ * 分叉位,所以取数口径收到这里,各调用点只剩「查不到时给多少」这一个本地决策。
14
+ *
15
+ * 第四处 `stats.ts` 的 rooms-get 有意不接:它除计数外还要把注册表的
16
+ * `source`/`label` 覆盖回已存在条目,不属同一个形状(见那处的注释)。
12
17
  */
13
- export function roomCountsBySlug(rooms) {
18
+ export function mergeRoomCatalog(rooms) {
14
19
  return new Map(rooms.map((r) => [r.room, r.count]));
15
20
  }
16
21
  /** 解析标注器输出的逐条候选(容错:id 配对失败丢弃;isRoomSlug 校验(两级制);目录内优先,≤3)。 */
@@ -124,7 +129,7 @@ export async function annotateOrphanCandidates(ctx, cfg, io, limit = 40, overrid
124
129
  // 后果是方向性的:词表里只有未注册项显示真数,归类器收到的唯一规模证据恰好与
125
130
  // 「优先挂靠现有词表」这条规则反向——按推荐用法先 pre-register 的词表反而全变空壳。
126
131
  // `?? 0` 保留原语义:只有「注册了但库里确实零绑定」的新 Room 才显示 0。
127
- const grownCounts = roomCountsBySlug(grown);
132
+ const grownCounts = mergeRoomCatalog(grown);
128
133
  const merged = [
129
134
  ...regActive.map((e) => ({ room: e.slug, count: grownCounts.get(e.slug) ?? 0, label: e.label, description: e.description })),
130
135
  ...grown.filter((r) => !regSet.has(r.room)).map((r) => ({ room: r.room, count: r.count })),
package/dist/stats.js CHANGED
@@ -19,7 +19,7 @@ import { typeCatalogEntries } from './memory-types.js';
19
19
  import { effectiveCfg } from './pipeline/runner.js';
20
20
  import { emptyRecallStats } from './hooks/recall.js';
21
21
  import { buildRouteChain, decideSendableEffort, LAYER_DEFAULT_BUDGETS, layerChainOrNull, resolveModelContextWindow, resolveModelEfforts, resolveModelRoute } from './llm.js';
22
- import { mergeRoom, renameRoom, roomCountsBySlug } from './room-review.js';
22
+ import { mergeRoom, renameRoom, mergeRoomCatalog } from './room-review.js';
23
23
  import { scanSources } from './memport/scan.js';
24
24
  import { projectDistillChain, validateDistillChain } from './settings.js';
25
25
  import { RECEIPTS_QUERY_LIMIT_MAX, dimensionOf, toReceiptView } from './store/receipts.js';
@@ -805,6 +805,9 @@ export async function handleEndpoint(endpoint, payload, deps) {
805
805
  // 端点层合并注册表(Agent A 设计):注册表 active 条目 count=0 补齐并带
806
806
  // source/label(source 用条目真实来源——收编 grown ≠ 预注册,⭐角标靠它区分);
807
807
  // 自生长条目标 source='grown'。不动 listRooms() 的缓存语义。
808
+ // 本处不接 `mergeRoomCatalog()`(计划点名的第四处):缺失条目这里固定写 0
809
+ // 且不做 `?? 实数` 回查,同时还要把注册表 source/label 覆盖回已存在条目(下方
810
+ // else 支)——取数以外的富形状,进共用助手需拆第二个返回面,不划算。
808
811
  const merged = rooms.map((r) => ({ ...r, source: 'grown' }));
809
812
  const registry = roomRegistry?.listActive() ?? [];
810
813
  for (const e of registry) {
@@ -1149,7 +1152,7 @@ export async function handleEndpoint(endpoint, payload, deps) {
1149
1152
  };
1150
1153
  if (kind === 'rooms') {
1151
1154
  const registry = roomRegistry?.list() ?? [];
1152
- const counts = roomCountsBySlug(stores.l1.listRooms());
1155
+ const counts = mergeRoomCatalog(stores.l1.listRooms());
1153
1156
  const lines = ['slug,count,source,label,description,status,aliases'];
1154
1157
  let n = 0;
1155
1158
  const seen = new Set();
@@ -23,7 +23,7 @@ import { isRetired, readSupersedeMarker, stripSupersedeMarker } from '../store/s
23
23
  import { listConflictPairs, renderConflictResolution, renderConflicts, resolveConflictPair } from '../conflict-service.js';
24
24
  import { WING_CATALOG, WING_FALLBACK, normPersistence, normScope, resolveRecordScope } from '../types.js';
25
25
  import { scopeFilterOf, workspaceIdOf } from '../workspace.js';
26
- import { annotateOrphanCandidates, confirmReview, mergeRoom, nextReview, pendingReviewCount, roomCountsBySlug, renameRoom, skipReview, } from '../room-review.js';
26
+ import { annotateOrphanCandidates, confirmReview, mergeRoom, nextReview, pendingReviewCount, mergeRoomCatalog, renameRoom, skipReview, } from '../room-review.js';
27
27
  import { applyGovernanceWeights } from '../store/governance.js';
28
28
  import { resolveRepoScope } from '../repo-scope.js';
29
29
  import { GRAPH_STATUS_LABELS } from '../prompts/graph-projection.js';
@@ -386,9 +386,9 @@ graphWrite) {
386
386
  return { notice: 'Room 注册表未装配(需要插件重载以初始化)。' };
387
387
  const registry = roomRegistry.list();
388
388
  const counts = stores.l1.listRooms();
389
- // 取数口径单点(`roomCountsBySlug` 注释说明了为何收它):本行原先对每个注册条目
389
+ // 取数口径单点(`mergeRoomCatalog` 注释说明了为何收它):本行原先对每个注册条目
390
390
  // 线性 find,上限 200 条注册表 × N 个 Room——语义相同、形状不同就是分叉位。
391
- const countOf = roomCountsBySlug(counts);
391
+ const countOf = mergeRoomCatalog(counts);
392
392
  const regLines = registry.map((e) => `- ${e.slug}${e.label ? `(${e.label})` : ''} [${e.source}/${e.status}] 现有 ${countOf.get(e.slug) ?? 0} 条${e.description ? ` — ${e.description}` : ''}`);
393
393
  const grownOnly = counts.filter((r) => !registry.some((e) => e.slug === r.room));
394
394
  return {
package/dsh.plugin.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "dsh-prime-memory",
3
3
  "name": "dsh-prime-memory",
4
- "version": "0.26.19",
4
+ "version": "0.26.20",
5
5
  "description": {
6
6
  "en": "Layered distilled memory plugin (L0 capture → L1 atomic memory → L2 scenes → L3 persona) with automatic recall injection before each model step.",
7
7
  "zh": "L0~L3 分层蒸馏记忆插件:自动捕获对话、抽取原子记忆、整合场景块、蒸馏核心画像,并在模型步骤前自动召回注入。"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-prime-memory",
3
- "version": "0.26.19",
3
+ "version": "0.26.20",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org",
6
6
  "access": "public",