dsh-prime-memory 0.20.0-beta.16 → 0.20.0-beta.18
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
|
@@ -17,6 +17,21 @@
|
|
|
17
17
|
- **建议状态(`longtask-hint-get`)以纯端点提供**:判定 = 上下文占用达 `contextThresholdPct` 或 todo 漂移达 `driftThreshold`(部署配置可调);配合 `longtask-compress-tail` 作手动压缩入口。
|
|
18
18
|
- **撤下浮动球 UI(`client/src/longtask-fab.ts`;beta.1 起曾随包发布)**:悬浮建议面板的归属本在 context-compression 侧(「建议启动压缩」是其领域),pm 属误载——2026-10-02 用户裁定撤下。撤下不违座位契约(settings.section 恰一个 + 输入栏 pill,body 单例不占座位),但全应用级 overlay 会与其他插件的悬浮 UI 抢占屏幕角落;长任务开关与手动压缩入口待长任务定版时落记忆设置分节。
|
|
19
19
|
- **`session-mode-set` 的 `mode` 转为可选**:与 `longTask` 二选一必传——纯切长任务开关不再被迫发送档位(旧客户端恒传 mode,行为不变)。响应 `mode` 改回当前生效值。
|
|
20
|
+
## [0.20.0-beta.18] — 2026-10-02
|
|
21
|
+
|
|
22
|
+
### 维护
|
|
23
|
+
|
|
24
|
+
- lint 清账:beta.17 的 isTag→isRoomSlug 替换遗留 stats.ts / rooms-registry.ts 两个死 import(发布门漏检——管道后 `$?` 取的是 tail 退出码,D2 坑复犯)。无功能变更。
|
|
25
|
+
## [0.20.0-beta.17] — 2026-10-02
|
|
26
|
+
|
|
27
|
+
> **重启后 hall/room 关系丢失修复**:`rooms-registry.json` 的加载器仍在用 `isTag` 过滤 slug——重启读盘时所有 `major/minor` 两级条目被当非法**静默丢弃**(单段 hall 能通过所以留存)。这是 isTag/isRoomSlug 混用的第三处;同批扫掉了 `normTags` 的同款雷。
|
|
28
|
+
|
|
29
|
+
### 修复
|
|
30
|
+
|
|
31
|
+
- **加载器丢两级条目**(`store/rooms-registry.ts` init):过滤改 `isRoomSlug`。**你磁盘上的 rooms-registry.json 数据完好**(两级条目一直在文件里,只是启动时被丢)——升级重载后关系自动恢复,无需任何修复操作。
|
|
32
|
+
- **normTags 洗掉 slash 标签**(`metadata-validators.ts`):"所有 tags 写回点都必须过这里"的闸用 isTag,归类写回的 `hall/minor` 标签在下次蒸馏/重标触及时会被静默剥掉。现放行两级 room slug(三级仍拒);`isRoomSlug` 事实源就近移入该文件(避免依赖环),rooms-registry re-export 兼容。
|
|
33
|
+
- **list-records 两级 tag 过滤被误拒**(stats.ts tagSel 同款):改 `isRoomSlug`——Hall 页点两级 room 的记录筛选此前会 400。
|
|
34
|
+
- 红测试先行 ×3(持久化回环两级保留 / normTags 放行 / 集成两级 tag 过滤),验红后修复回绿。
|
|
20
35
|
## [0.20.0-beta.16] — 2026-10-02
|
|
21
36
|
|
|
22
37
|
> **自生长未注册 slug 直接归入 hall**:底部「自生长未注册」区的每个 chip 现在可拖到 hall 头上——收编 + 归为其子类一步完成。
|
|
@@ -10,6 +10,11 @@
|
|
|
10
10
|
* 已是 string 的变量收窄成 `never`(该分支内无法再 `.slice`,已在 wing-backfill 踩过)。
|
|
11
11
|
*/
|
|
12
12
|
export declare function isWingId(v: unknown): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* 两级 Room slug(`major` 或 `major/minor`,各段满足 isTag;至多一个 slash)。
|
|
15
|
+
* Room 注册表/归类写回的 tags 域;与 rooms-registry.ts 同一事实源(就近定义避免依赖环)。
|
|
16
|
+
*/
|
|
17
|
+
export declare function isRoomSlug(v: unknown): boolean;
|
|
13
18
|
/** 同为布尔谓词(理由见 isWingId 注释)。 */
|
|
14
19
|
export declare function isTag(v: unknown): boolean;
|
|
15
20
|
/**
|
|
@@ -31,6 +31,16 @@ export function isWingId(v) {
|
|
|
31
31
|
}
|
|
32
32
|
/** 标签(Room 的构成单元)校验:小写字母数字连字符,1-32 字符。 */
|
|
33
33
|
const TAG_RE = /^[a-z0-9][a-z0-9-]{0,31}$/;
|
|
34
|
+
/**
|
|
35
|
+
* 两级 Room slug(`major` 或 `major/minor`,各段满足 isTag;至多一个 slash)。
|
|
36
|
+
* Room 注册表/归类写回的 tags 域;与 rooms-registry.ts 同一事实源(就近定义避免依赖环)。
|
|
37
|
+
*/
|
|
38
|
+
export function isRoomSlug(v) {
|
|
39
|
+
if (typeof v !== 'string')
|
|
40
|
+
return false;
|
|
41
|
+
const parts = v.split('/');
|
|
42
|
+
return parts.length <= 2 && parts.every((p) => TAG_RE.test(p));
|
|
43
|
+
}
|
|
34
44
|
/** 同为布尔谓词(理由见 isWingId 注释)。 */
|
|
35
45
|
export function isTag(v) {
|
|
36
46
|
return typeof v === 'string' && TAG_RE.test(v);
|
|
@@ -47,7 +57,7 @@ export function normTags(v, max = 3) {
|
|
|
47
57
|
if (typeof raw !== 'string')
|
|
48
58
|
continue;
|
|
49
59
|
const t = raw.trim().toLowerCase();
|
|
50
|
-
if (!isTag(t) || out.includes(t))
|
|
60
|
+
if (!(isTag(t) || isRoomSlug(t)) || out.includes(t))
|
|
51
61
|
continue;
|
|
52
62
|
out.push(t);
|
|
53
63
|
if (out.length >= max)
|
package/dist/stats.js
CHANGED
|
@@ -27,7 +27,7 @@ import { sourceAnchorLabels } from './pipeline/anchors.js';
|
|
|
27
27
|
import { readSupersedeMarker } from './store/supersede.js';
|
|
28
28
|
import { isSnapshotName } from './store/l1-snapshot.js';
|
|
29
29
|
import { WING_CATALOG, WING_FALLBACK } from './types.js';
|
|
30
|
-
import {
|
|
30
|
+
import { isRoomSlug } from './metadata-validators.js';
|
|
31
31
|
import { InProcMemoryBackend } from './store/memory-backend.js';
|
|
32
32
|
import { isWingCorner } from './store/session-modes.js';
|
|
33
33
|
import { startWingBackfill } from './wing-backfill.js';
|
|
@@ -953,8 +953,8 @@ export async function handleEndpoint(endpoint, payload, deps) {
|
|
|
953
953
|
const retiredSel = typeof p.retired === 'boolean' ? p.retired : undefined;
|
|
954
954
|
// Room 过滤:tag 是**自生长**的 slug(无枚举),只做形状与长度校验(SQL 侧参数化)
|
|
955
955
|
const tagSel = typeof p.tag === 'string' ? p.tag.trim().slice(0, 64) : '';
|
|
956
|
-
if (tagSel && !
|
|
957
|
-
throw new Error('tag 非法(
|
|
956
|
+
if (tagSel && !isRoomSlug(tagSel))
|
|
957
|
+
throw new Error('tag 非法(两级制:major 或 major/minor,各段小写字母数字连字符)');
|
|
958
958
|
// 孤儿记忆筛选(与 tag 互斥,tag 优先):只认显式布尔,其余视为缺省。
|
|
959
959
|
const untaggedSel = p.untagged === true && !tagSel;
|
|
960
960
|
// R13 多值归一: halls 数组只留非空字符串(≤40 字符),去重,上限 8(角数);
|
|
@@ -18,10 +18,10 @@ export interface RoomRegistryEntry {
|
|
|
18
18
|
}
|
|
19
19
|
export type RoomRegistryInput = Pick<RoomRegistryEntry, 'slug'> & Partial<Pick<RoomRegistryEntry, 'label' | 'description' | 'source' | 'aliases'>>;
|
|
20
20
|
/**
|
|
21
|
-
* 两级 Room slug
|
|
22
|
-
*
|
|
21
|
+
* 两级 Room slug(`major` 或 `major/minor`):事实源在 metadata-validators.ts
|
|
22
|
+
* (normTags 写回闸同源放行),此处 re-export 兼容既有导入。
|
|
23
23
|
*/
|
|
24
|
-
export
|
|
24
|
+
export { isRoomSlug } from '../metadata-validators.js';
|
|
25
25
|
/** 大类归属:`major/minor` 取 major;平级 slug 自身即大类。 */
|
|
26
26
|
export declare function majorOf(slug: string): string;
|
|
27
27
|
export declare class RoomRegistryStore {
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* 自生长目录**,绝不阻塞 rooms-get / 标注器(R2 红线)。
|
|
12
12
|
*/
|
|
13
13
|
import * as path from 'node:path';
|
|
14
|
-
import {
|
|
14
|
+
import { isRoomSlug } from '../metadata-validators.js';
|
|
15
15
|
import { readJsonStrict, atomicWriteText, ensureDir } from '../util/io.js';
|
|
16
16
|
/** 版本常量(file-versions 同款集中纪律;registry 为独立 sidecar 文件)。 */
|
|
17
17
|
export const ROOMS_REGISTRY_FILE_VERSION = 1;
|
|
@@ -20,17 +20,10 @@ const REGISTRY_MAJOR_CAP = 200;
|
|
|
20
20
|
/** 全量保险上限(大类+小类总和;防极端滥用)。 */
|
|
21
21
|
const REGISTRY_TOTAL_CAP = 2000;
|
|
22
22
|
/**
|
|
23
|
-
* 两级 Room slug
|
|
24
|
-
*
|
|
23
|
+
* 两级 Room slug(`major` 或 `major/minor`):事实源在 metadata-validators.ts
|
|
24
|
+
* (normTags 写回闸同源放行),此处 re-export 兼容既有导入。
|
|
25
25
|
*/
|
|
26
|
-
export
|
|
27
|
-
if (typeof v !== 'string')
|
|
28
|
-
return false;
|
|
29
|
-
const parts = v.split('/');
|
|
30
|
-
if (parts.length > 2)
|
|
31
|
-
return false;
|
|
32
|
-
return parts.every((p) => isTag(p));
|
|
33
|
-
}
|
|
26
|
+
export { isRoomSlug } from '../metadata-validators.js';
|
|
34
27
|
/** 大类归属:`major/minor` 取 major;平级 slug 自身即大类。 */
|
|
35
28
|
export function majorOf(slug) {
|
|
36
29
|
const i = slug.indexOf('/');
|
|
@@ -68,8 +61,8 @@ export class RoomRegistryStore {
|
|
|
68
61
|
}
|
|
69
62
|
const rooms = Array.isArray(read.value.rooms) ? read.value.rooms : [];
|
|
70
63
|
for (const r of rooms) {
|
|
71
|
-
if (!r || typeof r.slug !== 'string' || !
|
|
72
|
-
continue; // 非法 slug
|
|
64
|
+
if (!r || typeof r.slug !== 'string' || !isRoomSlug(r.slug))
|
|
65
|
+
continue; // 非法 slug 丢弃——两级制,isTag 会误丢 hall/minor(beta.17 修)
|
|
73
66
|
this.entries.push({
|
|
74
67
|
slug: r.slug,
|
|
75
68
|
label: typeof r.label === 'string' ? r.label : undefined,
|