@thread-memory/core 0.1.1 → 1.0.0
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/dist/assets.d.ts +14 -0
- package/dist/assets.js +104 -0
- package/dist/assets.js.map +1 -0
- package/dist/assets.test.d.ts +1 -0
- package/dist/assets.test.js +88 -0
- package/dist/assets.test.js.map +1 -0
- package/dist/behavior-contract.d.ts +2 -0
- package/dist/behavior-contract.js +9 -0
- package/dist/behavior-contract.js.map +1 -0
- package/dist/closing.d.ts +11 -0
- package/dist/closing.js +37 -0
- package/dist/closing.js.map +1 -0
- package/dist/delta.d.ts +24 -0
- package/dist/delta.js +55 -0
- package/dist/delta.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/isolation.test.js +3 -5
- package/dist/isolation.test.js.map +1 -1
- package/dist/light-confirm.d.ts +3 -21
- package/dist/light-confirm.js +80 -97
- package/dist/light-confirm.js.map +1 -1
- package/dist/light-confirm.test.js +185 -103
- package/dist/light-confirm.test.js.map +1 -1
- package/dist/lineage.test.js +10 -12
- package/dist/lineage.test.js.map +1 -1
- package/dist/nav.d.ts +26 -0
- package/dist/nav.js +139 -0
- package/dist/nav.js.map +1 -0
- package/dist/nav.test.d.ts +1 -0
- package/dist/nav.test.js +100 -0
- package/dist/nav.test.js.map +1 -0
- package/dist/query-tool.d.ts +20 -0
- package/dist/query-tool.js +61 -0
- package/dist/query-tool.js.map +1 -0
- package/dist/query.test.js +8 -5
- package/dist/query.test.js.map +1 -1
- package/dist/schema.d.ts +3 -1
- package/dist/schema.js +104 -1
- package/dist/schema.js.map +1 -1
- package/dist/schema.test.js +90 -3
- package/dist/schema.test.js.map +1 -1
- package/dist/sediment.test.d.ts +1 -0
- package/dist/sediment.test.js +89 -0
- package/dist/sediment.test.js.map +1 -0
- package/dist/segment.d.ts +3 -0
- package/dist/segment.js +84 -0
- package/dist/segment.js.map +1 -0
- package/dist/segment.test.d.ts +1 -0
- package/dist/segment.test.js +37 -0
- package/dist/segment.test.js.map +1 -0
- package/dist/state-delta.test.d.ts +1 -0
- package/dist/state-delta.test.js +90 -0
- package/dist/state-delta.test.js.map +1 -0
- package/dist/status-card.d.ts +7 -0
- package/dist/status-card.js +108 -3
- package/dist/status-card.js.map +1 -1
- package/dist/status-card.test.js +76 -3
- package/dist/status-card.test.js.map +1 -1
- package/dist/store.d.ts +121 -11
- package/dist/store.js +425 -61
- package/dist/store.js.map +1 -1
- package/dist/store.test.js +120 -10
- package/dist/store.test.js.map +1 -1
- package/dist/v7.test.d.ts +1 -0
- package/dist/v7.test.js +106 -0
- package/dist/v7.test.js.map +1 -0
- package/package.json +2 -1
package/dist/schema.js
CHANGED
|
@@ -1,4 +1,26 @@
|
|
|
1
|
-
|
|
1
|
+
import { segment } from "./segment.js";
|
|
2
|
+
import { isIndexable } from "./governor.js";
|
|
3
|
+
export const SCHEMA_VERSION = 8;
|
|
4
|
+
// FTS 表 DDL(0-e 定案:jieba 预分词 shadow 列 body_seg,unicode61 按空格分词)。
|
|
5
|
+
// contentless(content=''):FTS 仅存分词索引,不映射 content 表列(body_seg 在 events 表不存在,
|
|
6
|
+
// 外部内容表模式会报 no such column);查询永远 JOIN events 取原文,FTS 列只用于 MATCH。
|
|
7
|
+
// 单一来源:store.ts 的 EVENTS_SCHEMA 与迁移重建共用此 DDL,避免两处漂移。
|
|
8
|
+
// 主表:body_seg(jieba 词级)——unicode61 tokenizer。
|
|
9
|
+
export const EVENTS_FTS_DDL = `CREATE VIRTUAL TABLE IF NOT EXISTS events_fts USING fts5(
|
|
10
|
+
body_seg,
|
|
11
|
+
content='',
|
|
12
|
+
tokenize='unicode61'
|
|
13
|
+
);`;
|
|
14
|
+
// v6 兜底表(0-e 定案第 5 条落地):trigram 内置 tokenizer 作子串召回兜底。
|
|
15
|
+
// "用户只记得半句"(查询是正文 token 的连续子串、jieba 分词无法命中)时主路径 0 命中,
|
|
16
|
+
// 由本表短语匹配兜底(trigram 对连续字符序列做 3-gram 索引,短语 = 子串匹配)。
|
|
17
|
+
// 双表而非单表双列:better-sqlite3 内置 SQLite(3.53.2)不支持 FTS5 列级 tokenizer
|
|
18
|
+
// 覆盖("b tokenize='trigram'" parse error),独立表是可行的同语义实现(2026-08-18 修正)。
|
|
19
|
+
export const EVENTS_FTS_TRI_DDL = `CREATE VIRTUAL TABLE IF NOT EXISTS events_fts_tri USING fts5(
|
|
20
|
+
body,
|
|
21
|
+
content='',
|
|
22
|
+
tokenize='trigram'
|
|
23
|
+
);`;
|
|
2
24
|
// 双库(B④):事件库(events/episodes/spills/lineage_edges 事件域)与结构化库
|
|
3
25
|
// (goals/decisions/feedback/entities/decision_entities/metrics/lineage_edges 结构化域)
|
|
4
26
|
// 各库独立 schema_version 表、独立迁移链,共用 SCHEMA_VERSION。
|
|
@@ -27,6 +49,29 @@ export function ensureSchema(db, kind) {
|
|
|
27
49
|
db.exec(`ALTER TABLE events ADD COLUMN isolation INTEGER NOT NULL DEFAULT 0`);
|
|
28
50
|
db.exec(`CREATE INDEX IF NOT EXISTS idx_events_project ON events(project_key, ts)`);
|
|
29
51
|
db.exec(`CREATE UNIQUE INDEX IF NOT EXISTS idx_events_origin ON events(origin) WHERE origin IS NOT NULL`);
|
|
52
|
+
// v5(0-e 定案):FTS 从 unicode61(body 单字) 重建为 body_seg(jieba 预分词)。
|
|
53
|
+
// fts5 虚拟表不支持 ALTER 加列 → DROP + 重建 + 全量回填(events 原文表不受影响)。
|
|
54
|
+
// v6(trigram 兜底表):主表已存在但兜底表缺失/为空 → 重建回填(v5 库升级触发)。
|
|
55
|
+
// 判断依据 = 兜底表数据量(CREATE IF NOT EXISTS 后空表 = 未回填,需重建;不能只看表存在)。
|
|
56
|
+
db.exec(EVENTS_FTS_DDL);
|
|
57
|
+
db.exec(EVENTS_FTS_TRI_DDL);
|
|
58
|
+
const triCount = db.prepare(`SELECT COUNT(*) AS c FROM events_fts_tri`).get().c;
|
|
59
|
+
const ftsCols = cols("events_fts");
|
|
60
|
+
if (!ftsCols.has("body_seg") || triCount === 0) {
|
|
61
|
+
db.exec(`DROP TABLE IF EXISTS events_fts`);
|
|
62
|
+
db.exec(`DROP TABLE IF EXISTS events_fts_tri`);
|
|
63
|
+
db.exec(EVENTS_FTS_DDL);
|
|
64
|
+
db.exec(EVENTS_FTS_TRI_DDL);
|
|
65
|
+
const rows = db.prepare(`SELECT id, kind, body FROM events`).all();
|
|
66
|
+
const insSeg = db.prepare(`INSERT INTO events_fts(rowid, body_seg) VALUES (?, ?)`);
|
|
67
|
+
const insTri = db.prepare(`INSERT INTO events_fts_tri(rowid, body) VALUES (?, ?)`);
|
|
68
|
+
for (const r of rows) {
|
|
69
|
+
if (isIndexable(r.kind)) {
|
|
70
|
+
insSeg.run(r.id, segment(r.body));
|
|
71
|
+
insTri.run(r.id, r.body);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
30
75
|
db.exec(`CREATE TABLE IF NOT EXISTS spills (
|
|
31
76
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
32
77
|
event_id INTEGER NOT NULL REFERENCES events(id),
|
|
@@ -84,6 +129,64 @@ export function ensureSchema(db, kind) {
|
|
|
84
129
|
name TEXT NOT NULL,
|
|
85
130
|
value REAL NOT NULL,
|
|
86
131
|
ts TEXT NOT NULL
|
|
132
|
+
);`);
|
|
133
|
+
// 轻确认候选(§1.5.3d):规则粗筛暂存,未确认绝不进正式表。
|
|
134
|
+
// prompt_count = 已提示次数(衰减控制);last_prompt_ts = 上次提示时间(超时丢弃);kind = decision|preference(影响分级)。
|
|
135
|
+
db.exec(`CREATE TABLE IF NOT EXISTS pending_candidates (
|
|
136
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
137
|
+
session_id TEXT NOT NULL,
|
|
138
|
+
text TEXT NOT NULL,
|
|
139
|
+
kind TEXT NOT NULL DEFAULT 'preference',
|
|
140
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
141
|
+
source_event INTEGER,
|
|
142
|
+
created_at TEXT NOT NULL,
|
|
143
|
+
prompt_count INTEGER NOT NULL DEFAULT 0,
|
|
144
|
+
last_prompt_ts TEXT,
|
|
145
|
+
project_key TEXT,
|
|
146
|
+
isolation INTEGER NOT NULL DEFAULT 0
|
|
147
|
+
);`);
|
|
148
|
+
db.exec(`CREATE INDEX IF NOT EXISTS idx_pending_project ON pending_candidates(project_key, status)`);
|
|
149
|
+
db.exec(`CREATE INDEX IF NOT EXISTS idx_pending_session ON pending_candidates(session_id, status)`);
|
|
150
|
+
// v8(G5 跨会话 delta):updated_at 补齐(goals/feedback/pending_candidates 原只有 created_at)。
|
|
151
|
+
// 必须在全部 CREATE 之后(旧库首次升级时 pending_candidates 可能尚不存在)
|
|
152
|
+
for (const t of ["goals", "feedback", "pending_candidates"]) {
|
|
153
|
+
const c = cols(t);
|
|
154
|
+
if (!c.has("updated_at")) {
|
|
155
|
+
db.exec(`ALTER TABLE ${t} ADD COLUMN updated_at TEXT`);
|
|
156
|
+
db.exec(`UPDATE ${t} SET updated_at = created_at WHERE updated_at IS NULL`);
|
|
157
|
+
}
|
|
158
|
+
db.exec(`CREATE INDEX IF NOT EXISTS idx_${t}_updated ON ${t}(project_key, updated_at)`);
|
|
159
|
+
}
|
|
160
|
+
// v7(MAX 批 1 地基):产出/文档登记 + 待办 + 送达水位(跨会话 delta 触发判定持久化,G5)
|
|
161
|
+
db.exec(`CREATE TABLE IF NOT EXISTS knowledge_assets (
|
|
162
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
163
|
+
path TEXT NOT NULL,
|
|
164
|
+
title TEXT NOT NULL,
|
|
165
|
+
topic TEXT,
|
|
166
|
+
scenario TEXT,
|
|
167
|
+
session_id TEXT NOT NULL,
|
|
168
|
+
source_event INTEGER,
|
|
169
|
+
created_at TEXT NOT NULL,
|
|
170
|
+
isolation INTEGER NOT NULL DEFAULT 0
|
|
171
|
+
);`);
|
|
172
|
+
db.exec(`CREATE INDEX IF NOT EXISTS idx_assets_session ON knowledge_assets(session_id, created_at)`);
|
|
173
|
+
db.exec(`CREATE INDEX IF NOT EXISTS idx_assets_visible ON knowledge_assets(isolation, created_at)`);
|
|
174
|
+
db.exec(`CREATE TABLE IF NOT EXISTS todos (
|
|
175
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
176
|
+
session_id TEXT NOT NULL,
|
|
177
|
+
text TEXT NOT NULL,
|
|
178
|
+
basis TEXT,
|
|
179
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
180
|
+
created_at TEXT NOT NULL,
|
|
181
|
+
project_key TEXT,
|
|
182
|
+
isolation INTEGER NOT NULL DEFAULT 0
|
|
183
|
+
);`);
|
|
184
|
+
db.exec(`CREATE INDEX IF NOT EXISTS idx_todos_project ON todos(project_key, status)`);
|
|
185
|
+
db.exec(`CREATE INDEX IF NOT EXISTS idx_todos_session ON todos(session_id, status)`);
|
|
186
|
+
db.exec(`CREATE TABLE IF NOT EXISTS thread_meta (
|
|
187
|
+
key TEXT PRIMARY KEY,
|
|
188
|
+
value TEXT NOT NULL,
|
|
189
|
+
updated_at TEXT NOT NULL
|
|
87
190
|
);`);
|
|
88
191
|
}
|
|
89
192
|
db.prepare(`INSERT INTO schema_version (version, applied_at) VALUES (?, ?)`).run(SCHEMA_VERSION, new Date().toISOString());
|
package/dist/schema.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
|
package/dist/schema.test.js
CHANGED
|
@@ -29,7 +29,7 @@ describe("schema v2 migration (B④ 双库)", () => {
|
|
|
29
29
|
for (const t of ["spills", "schema_version"]) {
|
|
30
30
|
expect(db.prepare(`SELECT 1 FROM sqlite_master WHERE type='table' AND name=?`).get(t), `table ${t}`).toBeTruthy();
|
|
31
31
|
}
|
|
32
|
-
expect(db.prepare("SELECT MAX(version) AS v FROM schema_version").get().v).toBe(
|
|
32
|
+
expect(db.prepare("SELECT MAX(version) AS v FROM schema_version").get().v).toBe(8);
|
|
33
33
|
db.close();
|
|
34
34
|
rmSync(dir, { recursive: true, force: true });
|
|
35
35
|
});
|
|
@@ -69,10 +69,97 @@ describe("schema v2 migration (B④ 双库)", () => {
|
|
|
69
69
|
for (const col of ["project_key", "scope", "origin", "isolation"])
|
|
70
70
|
expect(cols.has(col), `${t}.${col}`).toBe(true);
|
|
71
71
|
}
|
|
72
|
-
for (const t of ["entities", "decision_entities", "metrics", "session_isolation", "schema_version"]) {
|
|
72
|
+
for (const t of ["entities", "decision_entities", "metrics", "session_isolation", "pending_candidates", "knowledge_assets", "todos", "thread_meta", "schema_version"]) {
|
|
73
73
|
expect(db.prepare(`SELECT 1 FROM sqlite_master WHERE type='table' AND name=?`).get(t), `table ${t}`).toBeTruthy();
|
|
74
74
|
}
|
|
75
|
-
expect(db.prepare("SELECT MAX(version) AS v FROM schema_version").get().v).toBe(
|
|
75
|
+
expect(db.prepare("SELECT MAX(version) AS v FROM schema_version").get().v).toBe(8);
|
|
76
|
+
db.close();
|
|
77
|
+
rmSync(dir, { recursive: true, force: true });
|
|
78
|
+
});
|
|
79
|
+
it("v4 FTS 表(body 单字)→ v5 重建为 body_seg 并回填(0-e 中文检索升级)", () => {
|
|
80
|
+
const dir = mkdtempSync(join(tmpdir(), "thread-migrate-fts-"));
|
|
81
|
+
const dbPath = join(dir, "events.db");
|
|
82
|
+
const db = new Database(dbPath);
|
|
83
|
+
// 模拟 v4 库:events + 旧结构 FTS(body 列 unicode61)
|
|
84
|
+
db.exec(`CREATE TABLE events (
|
|
85
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
86
|
+
session_id TEXT NOT NULL,
|
|
87
|
+
kind TEXT NOT NULL,
|
|
88
|
+
ts TEXT NOT NULL,
|
|
89
|
+
seq INTEGER NOT NULL,
|
|
90
|
+
body TEXT NOT NULL,
|
|
91
|
+
meta TEXT,
|
|
92
|
+
truncated INTEGER NOT NULL DEFAULT 0,
|
|
93
|
+
project_key TEXT,
|
|
94
|
+
scope TEXT NOT NULL DEFAULT 'project',
|
|
95
|
+
origin TEXT,
|
|
96
|
+
spilled INTEGER NOT NULL DEFAULT 0,
|
|
97
|
+
isolation INTEGER NOT NULL DEFAULT 0
|
|
98
|
+
);
|
|
99
|
+
INSERT INTO events (session_id, kind, ts, seq, body) VALUES
|
|
100
|
+
('s1', 'user_message', '2026-08-18T00:00:00.000Z', 1, '登录方案改成JWT'),
|
|
101
|
+
('s1', 'tool_call', '2026-08-18T00:00:01.000Z', 2, 'pwsh 大块工具输出不建索引');
|
|
102
|
+
CREATE VIRTUAL TABLE events_fts USING fts5(body, content='events', content_rowid='id', tokenize='unicode61');
|
|
103
|
+
INSERT INTO events_fts(rowid, body) VALUES (1, '登 录 方 案 改 成 jwt');`);
|
|
104
|
+
ensureSchema(db, "events");
|
|
105
|
+
// 重建后:body_seg 列存在,indexable 行已分词回填,tool_call 不建索引
|
|
106
|
+
// contentless 表不能 SELECT 列值,用 MATCH 验证索引内容
|
|
107
|
+
const ftsCols = new Set(db.prepare("PRAGMA table_info(events_fts)").all().map((c) => c.name));
|
|
108
|
+
expect(ftsCols.has("body_seg")).toBe(true);
|
|
109
|
+
const hit = db.prepare("SELECT rowid FROM events_fts WHERE events_fts MATCH ?").get("登录");
|
|
110
|
+
expect(hit?.rowid).toBe(1);
|
|
111
|
+
const toolHit = db.prepare("SELECT rowid FROM events_fts WHERE events_fts MATCH ?").get("pwsh");
|
|
112
|
+
expect(toolHit).toBeUndefined();
|
|
113
|
+
expect(db.prepare("SELECT MAX(version) AS v FROM schema_version").get().v).toBe(8);
|
|
114
|
+
db.close();
|
|
115
|
+
rmSync(dir, { recursive: true, force: true });
|
|
116
|
+
});
|
|
117
|
+
it("v5 FTS 表(无 events_fts_tri)→ v6 重建主表 + 建 trigram 兜底表并回填", () => {
|
|
118
|
+
const dir = mkdtempSync(join(tmpdir(), "thread-migrate-fts6-"));
|
|
119
|
+
const dbPath = join(dir, "events.db");
|
|
120
|
+
const db = new Database(dbPath);
|
|
121
|
+
// 模拟 v5 库:events + body_seg FTS(无 events_fts_tri 兜底表)
|
|
122
|
+
db.exec(`CREATE TABLE events (
|
|
123
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
124
|
+
session_id TEXT NOT NULL,
|
|
125
|
+
kind TEXT NOT NULL,
|
|
126
|
+
ts TEXT NOT NULL,
|
|
127
|
+
seq INTEGER NOT NULL,
|
|
128
|
+
body TEXT NOT NULL,
|
|
129
|
+
meta TEXT,
|
|
130
|
+
truncated INTEGER NOT NULL DEFAULT 0,
|
|
131
|
+
project_key TEXT,
|
|
132
|
+
scope TEXT NOT NULL DEFAULT 'project',
|
|
133
|
+
origin TEXT,
|
|
134
|
+
spilled INTEGER NOT NULL DEFAULT 0,
|
|
135
|
+
isolation INTEGER NOT NULL DEFAULT 0
|
|
136
|
+
);
|
|
137
|
+
INSERT INTO events (session_id, kind, ts, seq, body) VALUES
|
|
138
|
+
('s1', 'user_message', '2026-08-18T00:00:00.000Z', 1, '模型选定 deepseek-v4-flash 作为主力'),
|
|
139
|
+
('s1', 'tool_call', '2026-08-18T00:00:01.000Z', 2, 'pwsh 工具输出不建索引');
|
|
140
|
+
CREATE VIRTUAL TABLE events_fts USING fts5(body_seg, content='', tokenize='unicode61');
|
|
141
|
+
INSERT INTO events_fts(rowid, body_seg) VALUES (1, '模型 选定 deepseek v4 flash 作为 主力');`);
|
|
142
|
+
ensureSchema(db, "events");
|
|
143
|
+
// 重建后:主表 body_seg 保留 + 兜底表 events_fts_tri 存在且回填——
|
|
144
|
+
// 子串「eepseek」可经 trigram 兜底表短语命中
|
|
145
|
+
const triExists = db
|
|
146
|
+
.prepare(`SELECT 1 FROM sqlite_master WHERE type='table' AND name='events_fts_tri'`)
|
|
147
|
+
.get() !== undefined;
|
|
148
|
+
expect(triExists).toBe(true);
|
|
149
|
+
const sub = db
|
|
150
|
+
.prepare(`SELECT rowid FROM events_fts_tri WHERE events_fts_tri MATCH '"eepseek"'`)
|
|
151
|
+
.get();
|
|
152
|
+
expect(sub?.rowid).toBe(1);
|
|
153
|
+
// 主路径表无「eepseek」token(词级)
|
|
154
|
+
const seg = db
|
|
155
|
+
.prepare(`SELECT rowid FROM events_fts WHERE events_fts MATCH '"eepseek"'`)
|
|
156
|
+
.get();
|
|
157
|
+
expect(seg).toBeUndefined();
|
|
158
|
+
// tool_call 不建索引
|
|
159
|
+
const toolHit = db
|
|
160
|
+
.prepare(`SELECT rowid FROM events_fts_tri WHERE events_fts_tri MATCH '"pwsh"'`)
|
|
161
|
+
.get();
|
|
162
|
+
expect(toolHit).toBeUndefined();
|
|
76
163
|
db.close();
|
|
77
164
|
rmSync(dir, { recursive: true, force: true });
|
|
78
165
|
});
|
package/dist/schema.test.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.test.js","sourceRoot":"","sources":["../src/schema.test.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"schema.test.js","sourceRoot":"","sources":["../src/schema.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { PENDING_TODO_BASIS, sedimentClosingTodos } from "./closing.js";
|
|
6
|
+
import { ThreadStore } from "./store.js";
|
|
7
|
+
function makeStore() {
|
|
8
|
+
const dir = mkdtempSync(join(tmpdir(), "thread-sediment-"));
|
|
9
|
+
const store = new ThreadStore({ eventsPath: join(dir, "events.db"), structuredPath: join(dir, "structured.db"), projectKey: "demo" });
|
|
10
|
+
return { store, dir };
|
|
11
|
+
}
|
|
12
|
+
describe("sedimentClosingTodos(收尾自动沉淀,1.2)", () => {
|
|
13
|
+
it("active goals → todos(text 带未完成标记,basis=goal:<id>)", () => {
|
|
14
|
+
const { store, dir } = makeStore();
|
|
15
|
+
try {
|
|
16
|
+
store.addGoal("s1", "完成批 2", { projectKey: "demo" });
|
|
17
|
+
const result = sedimentClosingTodos(store, "s1", { projectKey: "demo" });
|
|
18
|
+
expect(result.goalTodosCreated).toBe(1);
|
|
19
|
+
const todos = store.listTodos({ sessionId: "s1" });
|
|
20
|
+
expect(todos).toHaveLength(1);
|
|
21
|
+
expect(todos[0].text).toBe("完成批 2(未完成)");
|
|
22
|
+
expect(todos[0].basis).toBe("goal:1");
|
|
23
|
+
}
|
|
24
|
+
finally {
|
|
25
|
+
store.close();
|
|
26
|
+
rmSync(dir, { recursive: true, force: true });
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
it("幂等:重复沉淀不产生重复 todo", () => {
|
|
30
|
+
const { store, dir } = makeStore();
|
|
31
|
+
try {
|
|
32
|
+
store.addGoal("s1", "目标 A", { projectKey: "demo" });
|
|
33
|
+
sedimentClosingTodos(store, "s1", { projectKey: "demo" });
|
|
34
|
+
const again = sedimentClosingTodos(store, "s1", { projectKey: "demo" });
|
|
35
|
+
expect(again.goalTodosCreated).toBe(0);
|
|
36
|
+
expect(again.goalTodosSkipped).toBe(1);
|
|
37
|
+
expect(store.listTodos({ sessionId: "s1" })).toHaveLength(1);
|
|
38
|
+
}
|
|
39
|
+
finally {
|
|
40
|
+
store.close();
|
|
41
|
+
rmSync(dir, { recursive: true, force: true });
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
it("pending 候选归集 todo(每会话一条,basis=/thread-pending)", () => {
|
|
45
|
+
const { store, dir } = makeStore();
|
|
46
|
+
try {
|
|
47
|
+
store.addPendingCandidate({ sessionId: "s1", text: "候选决策", kind: "decision", projectKey: "demo" });
|
|
48
|
+
const result = sedimentClosingTodos(store, "s1", { projectKey: "demo" });
|
|
49
|
+
expect(result.pendingTodoCreated).toBe(true);
|
|
50
|
+
const todo = store.listTodos({ sessionId: "s1", basis: PENDING_TODO_BASIS });
|
|
51
|
+
expect(todo).toHaveLength(1);
|
|
52
|
+
expect(todo[0].text).toContain("1 条");
|
|
53
|
+
// 重复沉淀:pending todo 已存在 → 不再创建
|
|
54
|
+
const again = sedimentClosingTodos(store, "s1", { projectKey: "demo" });
|
|
55
|
+
expect(again.pendingTodoCreated).toBe(false);
|
|
56
|
+
}
|
|
57
|
+
finally {
|
|
58
|
+
store.close();
|
|
59
|
+
rmSync(dir, { recursive: true, force: true });
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
it("无候选 → 不产生 pending todo", () => {
|
|
63
|
+
const { store, dir } = makeStore();
|
|
64
|
+
try {
|
|
65
|
+
const result = sedimentClosingTodos(store, "s1", { projectKey: "demo" });
|
|
66
|
+
expect(result.pendingTodoCreated).toBe(false);
|
|
67
|
+
expect(store.listTodos({ sessionId: "s1" })).toHaveLength(0);
|
|
68
|
+
}
|
|
69
|
+
finally {
|
|
70
|
+
store.close();
|
|
71
|
+
rmSync(dir, { recursive: true, force: true });
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
it("目标完成 → todo 同步 done(关闭即沉淀的自愈,2026-08-20)", () => {
|
|
75
|
+
const { store, dir } = makeStore();
|
|
76
|
+
try {
|
|
77
|
+
const g = store.addGoal("s1", "目标 X", { projectKey: "demo" });
|
|
78
|
+
sedimentClosingTodos(store, "s1", { projectKey: "demo" });
|
|
79
|
+
expect(store.listTodos({ sessionId: "s1" })[0].status).toBe("pending");
|
|
80
|
+
store.updateGoalStatus("s1", g.id, "completed");
|
|
81
|
+
expect(store.listTodos({ sessionId: "s1" })[0].status).toBe("done");
|
|
82
|
+
}
|
|
83
|
+
finally {
|
|
84
|
+
store.close();
|
|
85
|
+
rmSync(dir, { recursive: true, force: true });
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
//# sourceMappingURL=sediment.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sediment.test.js","sourceRoot":"","sources":["../src/sediment.test.ts"],"names":[],"mappings":"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"}
|
package/dist/segment.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// 中文分词封装(0-e 定案:jieba 预分词 shadow 列,@node-rs/jieba napi-rs 预编译)。
|
|
2
|
+
// 2.x API:Jieba.withDict(dict) 需显式加载词典(dict.txt 随包分发);loadDict() 已弃用。
|
|
3
|
+
// 容错:jieba 加载失败(平台无预编译二进制等)→ 降级为单字空格(unicode61 可索引),
|
|
4
|
+
// 检索质量降级而非报错——符合"旁路可失败不阻塞主路径"约定(AGENTS.md 工作流约定 2/3)。
|
|
5
|
+
import { createRequire } from "node:module";
|
|
6
|
+
let jieba;
|
|
7
|
+
let loadTried = false;
|
|
8
|
+
// ESM 无全局 require(type: module),用 createRequire 加载 CJS 原生包
|
|
9
|
+
const esmRequire = createRequire(import.meta.url);
|
|
10
|
+
function loadJieba() {
|
|
11
|
+
if (loadTried) {
|
|
12
|
+
return jieba;
|
|
13
|
+
}
|
|
14
|
+
loadTried = true;
|
|
15
|
+
try {
|
|
16
|
+
// 动态加载:顶层 import 失败会直接崩(原生模块缺平台二进制时),此处兜底
|
|
17
|
+
const mod = esmRequire("@node-rs/jieba");
|
|
18
|
+
const { dict } = esmRequire("@node-rs/jieba/dict");
|
|
19
|
+
jieba = mod.Jieba.withDict(dict);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
jieba = undefined;
|
|
23
|
+
}
|
|
24
|
+
return jieba;
|
|
25
|
+
}
|
|
26
|
+
// CJK 单字空格化(降级路径 + 保底):每个中文字符两侧加空格,unicode61 按空格分词
|
|
27
|
+
export function cjkSpace(text) {
|
|
28
|
+
return text
|
|
29
|
+
.replace(/([\u3400-\u9fff\uf900-\ufaff])/g, " $1 ")
|
|
30
|
+
.replace(/\s+/g, " ")
|
|
31
|
+
.trim();
|
|
32
|
+
}
|
|
33
|
+
// 纯标点/符号 token 过滤(jieba 会把"、"","":"等切为独立 token,FTS 索引是噪声)
|
|
34
|
+
const PUNCT_RE = /^[\p{P}\p{S}\s]+$/u;
|
|
35
|
+
// 查询侧停用词(高频虚词/泛化词):全 OR 语义下这些词会把无关内容拉进候选集,
|
|
36
|
+
// 过滤后召回精度交给 BM25 排序。仅查询路径使用——索引保留全文("决策"等词须能命中)。
|
|
37
|
+
const QUERY_STOPWORDS = new Set([
|
|
38
|
+
"的", "了", "是", "在", "和", "与", "及", "或", "把", "被", "就", "都", "而", "等",
|
|
39
|
+
"之", "其", "这", "那", "也", "还", "于", "以", "为", "对", "从", "到", "吗", "呢",
|
|
40
|
+
"吧", "啊", "哦", "嗯", "我", "你", "他", "她", "它", "我们", "你们", "他们", "咱们",
|
|
41
|
+
"怎么", "什么", "如何", "为啥", "为什么", "一个", "这个", "那个", "一下", "一下下",
|
|
42
|
+
"有", "没", "不", "没", "无", "请", "帮", "要", "想", "能", "会", "去", "来",
|
|
43
|
+
]);
|
|
44
|
+
function cleanTokens(tokens, { stopwords } = {}) {
|
|
45
|
+
return tokens.filter((t) => {
|
|
46
|
+
if (t.trim().length === 0 || PUNCT_RE.test(t)) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
if (stopwords && QUERY_STOPWORDS.has(t)) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
return true;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
// 预分词:jieba 词级分词 → 空格连接(供 FTS body_seg 列索引);失败降级单字
|
|
56
|
+
export function segment(text) {
|
|
57
|
+
const j = loadJieba();
|
|
58
|
+
if (j) {
|
|
59
|
+
try {
|
|
60
|
+
return cleanTokens(j.cut(text)).join(" ");
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// 分词异常降级单字
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return cjkSpace(text);
|
|
67
|
+
}
|
|
68
|
+
// 查询侧对称分词:返回 token 列表(jieba 词级 + 停用词过滤);失败降级单字
|
|
69
|
+
export function segmentQuery(query) {
|
|
70
|
+
const j = loadJieba();
|
|
71
|
+
if (j) {
|
|
72
|
+
try {
|
|
73
|
+
const tokens = cleanTokens(j.cut(query), { stopwords: true });
|
|
74
|
+
if (tokens.length > 0) {
|
|
75
|
+
return tokens;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
// 分词异常降级单字
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return cjkSpace(query).split(/\s+/).filter(Boolean);
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=segment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"segment.js","sourceRoot":"","sources":["../src/segment.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { cjkSpace, segment, segmentQuery } from "./segment.js";
|
|
3
|
+
describe("segment(0-e:jieba 预分词 shadow 列)", () => {
|
|
4
|
+
it("中文按词切分(词级,非单字)", () => {
|
|
5
|
+
const out = segment("登录方案改成JWT部署到周五");
|
|
6
|
+
expect(out).toContain("登录");
|
|
7
|
+
expect(out).toContain("方案");
|
|
8
|
+
expect(out).not.toContain("登 录"); // 不再是单字空格
|
|
9
|
+
});
|
|
10
|
+
it("过滤纯标点 token(、,:等不进索引)", () => {
|
|
11
|
+
const out = segment("决策不丢、目标不漂移、不重复提问");
|
|
12
|
+
expect(out.split(/\s+/)).not.toContain("、");
|
|
13
|
+
});
|
|
14
|
+
it("英文/数字保持空格分词", () => {
|
|
15
|
+
const out = segment("run the full test suite with JWT");
|
|
16
|
+
expect(out).toContain("JWT");
|
|
17
|
+
});
|
|
18
|
+
it("降级路径:cjkSpace 单字空格(jieba 不可用时兜底)", () => {
|
|
19
|
+
expect(cjkSpace("登录方案")).toBe("登 录 方 案");
|
|
20
|
+
expect(segment("")).toBe("");
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
describe("segmentQuery(查询侧对称分词)", () => {
|
|
24
|
+
it("中文查询切为词 token", () => {
|
|
25
|
+
const tokens = segmentQuery("登录方案怎么定的");
|
|
26
|
+
expect(tokens).toContain("登录");
|
|
27
|
+
expect(tokens.length).toBeGreaterThan(0);
|
|
28
|
+
});
|
|
29
|
+
it("英文查询保持词级", () => {
|
|
30
|
+
expect(segmentQuery("how does auth work")).toContain("auth");
|
|
31
|
+
});
|
|
32
|
+
it("空查询 → 空 token 列表", () => {
|
|
33
|
+
expect(segmentQuery("")).toEqual([]);
|
|
34
|
+
expect(segmentQuery(" ")).toEqual([]);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
//# sourceMappingURL=segment.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"segment.test.js","sourceRoot":"","sources":["../src/segment.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE/D,QAAQ,CAAC,iCAAiC,EAAE,GAAG,EAAE;IAC/C,EAAE,CAAC,gBAAgB,EAAE,GAAG,EAAE;QACxB,MAAM,GAAG,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;QACtC,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAC5B,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAC5B,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;QAC/B,MAAM,GAAG,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;QACxC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,aAAa,EAAE,GAAG,EAAE;QACrB,MAAM,GAAG,GAAG,OAAO,CAAC,kCAAkC,CAAC,CAAC;QACxD,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACzC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,eAAe,EAAE,GAAG,EAAE;QACvB,MAAM,MAAM,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;QACxC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,UAAU,EAAE,GAAG,EAAE;QAClB,MAAM,CAAC,YAAY,CAAC,oBAAoB,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAC1B,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACrC,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { getStateDelta, renderStateDelta } from "./delta.js";
|
|
6
|
+
import { ThreadStore } from "./store.js";
|
|
7
|
+
function makeStore() {
|
|
8
|
+
const dir = mkdtempSync(join(tmpdir(), "thread-delta-"));
|
|
9
|
+
const store = new ThreadStore({ eventsPath: join(dir, "events.db"), structuredPath: join(dir, "structured.db"), projectKey: "demo" });
|
|
10
|
+
return { store, dir };
|
|
11
|
+
}
|
|
12
|
+
describe("getStateDelta (G5 cross-session state delta)", () => {
|
|
13
|
+
it("other-session decisions/goals/feedback/candidates hit; own rows excluded", () => {
|
|
14
|
+
const { store, dir } = makeStore();
|
|
15
|
+
try {
|
|
16
|
+
store.proposeDecision("s-a", "decision A", { projectKey: "demo" });
|
|
17
|
+
store.addGoal("s-b", "goal B", { projectKey: "demo" });
|
|
18
|
+
store.addFeedback("s-b", "pref B", "preference", { projectKey: "demo" });
|
|
19
|
+
store.addPendingCandidate({ sessionId: "s-a", text: "candidate C", kind: "decision", projectKey: "demo" });
|
|
20
|
+
store.addGoal("s-me", "my own goal", { projectKey: "demo" });
|
|
21
|
+
const delta = getStateDelta(store, { projectKey: "demo", since: "2020-01-01T00:00:00.000Z", excludeSessionId: "s-me", viewerSessionId: "s-me" });
|
|
22
|
+
expect(delta.decisions.map((d) => d.text)).toEqual(["decision A"]);
|
|
23
|
+
expect(delta.goals.map((g) => g.text)).toEqual(["goal B"]);
|
|
24
|
+
expect(delta.feedback.map((f) => f.text)).toEqual(["pref B"]);
|
|
25
|
+
expect(delta.pending.map((p) => p.text)).toEqual(["candidate C"]);
|
|
26
|
+
}
|
|
27
|
+
finally {
|
|
28
|
+
store.close();
|
|
29
|
+
rmSync(dir, { recursive: true, force: true });
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
it("since watermark: older rows don't hit", () => {
|
|
33
|
+
const { store, dir } = makeStore();
|
|
34
|
+
try {
|
|
35
|
+
store.proposeDecision("s-a", "old decision", { projectKey: "demo", ts: "2026-08-19T00:00:00.000Z" });
|
|
36
|
+
const delta = getStateDelta(store, { projectKey: "demo", since: "2026-08-20T00:00:00.000Z", excludeSessionId: "s-me", viewerSessionId: "s-me" });
|
|
37
|
+
expect(delta.decisions).toHaveLength(0);
|
|
38
|
+
}
|
|
39
|
+
finally {
|
|
40
|
+
store.close();
|
|
41
|
+
rmSync(dir, { recursive: true, force: true });
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
it("isolation: isolated rows invisible to others (isolated viewer skip is caller-side)", () => {
|
|
45
|
+
const { store, dir } = makeStore();
|
|
46
|
+
try {
|
|
47
|
+
store.proposeDecision("s-iso", "isolated decision", { projectKey: "demo", isolation: true });
|
|
48
|
+
const delta = getStateDelta(store, { projectKey: "demo", since: "2020-01-01T00:00:00.000Z", excludeSessionId: "s-me", viewerSessionId: "s-me" });
|
|
49
|
+
expect(delta.decisions).toHaveLength(0);
|
|
50
|
+
// 隔离查看方的"无跨会话 delta"由调用方判定(viewer 隔离 → 不注入);本函数只负责写入方过滤
|
|
51
|
+
const viewerIsolated = store.getSessionIsolation("s-iso");
|
|
52
|
+
expect(viewerIsolated).toBe(false);
|
|
53
|
+
}
|
|
54
|
+
finally {
|
|
55
|
+
store.close();
|
|
56
|
+
rmSync(dir, { recursive: true, force: true });
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
it("status transitions surface via updated_at (goal completed)", () => {
|
|
60
|
+
const { store, dir } = makeStore();
|
|
61
|
+
try {
|
|
62
|
+
const g = store.addGoal("s-a", "goal X", { projectKey: "demo" });
|
|
63
|
+
store.updateGoalStatus("s-a", g.id, "completed");
|
|
64
|
+
const delta = getStateDelta(store, { projectKey: "demo", since: "2020-01-01T00:00:00.000Z", excludeSessionId: "s-me", viewerSessionId: "s-me" });
|
|
65
|
+
expect(delta.goals).toHaveLength(1);
|
|
66
|
+
expect(delta.goals[0].status).toBe("completed");
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
store.close();
|
|
70
|
+
rmSync(dir, { recursive: true, force: true });
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
describe("renderStateDelta (2.3.2 format)", () => {
|
|
75
|
+
it("with changes -> headed block", () => {
|
|
76
|
+
const text = renderStateDelta({
|
|
77
|
+
goals: [],
|
|
78
|
+
decisions: [{ id: 3, text: "plan A", session_id: "session-abc12345", updated_at: "t", status: "active" }],
|
|
79
|
+
feedback: [],
|
|
80
|
+
pending: [],
|
|
81
|
+
});
|
|
82
|
+
expect(text).toContain("[Thread");
|
|
83
|
+
expect(text).toContain("plan A");
|
|
84
|
+
expect(text).toContain("abc1234");
|
|
85
|
+
});
|
|
86
|
+
it("empty -> undefined (zero injection)", () => {
|
|
87
|
+
expect(renderStateDelta({ goals: [], decisions: [], feedback: [], pending: [] })).toBeUndefined();
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
//# sourceMappingURL=state-delta.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-delta.test.js","sourceRoot":"","sources":["../src/state-delta.test.ts"],"names":[],"mappings":"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"}
|