@whispering233/ai-editor-db 0.0.57 → 0.0.59
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/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/migrations/012_practice.d.ts +4 -0
- package/dist/migrations/012_practice.d.ts.map +1 -0
- package/dist/migrations/012_practice.js +47 -0
- package/dist/migrations/012_practice.js.map +1 -0
- package/dist/migrations/013_author_practice.d.ts +4 -0
- package/dist/migrations/013_author_practice.d.ts.map +1 -0
- package/dist/migrations/013_author_practice.js +60 -0
- package/dist/migrations/013_author_practice.js.map +1 -0
- package/dist/migrations/index.d.ts +3 -1
- package/dist/migrations/index.d.ts.map +1 -1
- package/dist/migrations/index.js +14 -3
- package/dist/migrations/index.js.map +1 -1
- package/dist/queries/practice.d.ts +168 -0
- package/dist/queries/practice.d.ts.map +1 -0
- package/dist/queries/practice.js +339 -0
- package/dist/queries/practice.js.map +1 -0
- package/dist/schema.d.ts +7 -1
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +7 -1
- package/dist/schema.js.map +1 -1
- package/dist/storage/project.d.ts +2 -0
- package/dist/storage/project.d.ts.map +1 -1
- package/dist/storage/project.js +11 -1
- package/dist/storage/project.js.map +1 -1
- package/dist/tables.d.ts +397 -1
- package/dist/tables.d.ts.map +1 -1
- package/dist/tables.js +70 -0
- package/dist/tables.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
// @whispering233/ai-editor-db 作家文风练习读写(practice_samples / practice_free_pieces /
|
|
2
|
+
// practice_style_packs,2026-10 改版)
|
|
3
|
+
//
|
|
4
|
+
// 练习工作区(`kind = "practice"`,一位预置作家 = 一个工作区)专属数据:
|
|
5
|
+
// **库写入唯一入口 = 本模块**(禁止绕过直接写表)。语义与不变式见 `docs/design/60-practice.md` §5、
|
|
6
|
+
// 字段契约见 `docs/db/schema.md`「练习三表」、响应形状见 `docs/api/120-api-practice.md`。
|
|
7
|
+
//
|
|
8
|
+
// 口径(与文档逐条对应):
|
|
9
|
+
// - **物理删**:练习数据无回收站(无 deleted_at);删除幂等(不存在 → null / false,不抛错)
|
|
10
|
+
// - **范文不可变**:`text` 只在建样本时落库,无更新入口
|
|
11
|
+
// - **每列只有一个写入口**:`draft` 只有用户(updatePracticeSampleDraft / updatePracticePieceDraft)、
|
|
12
|
+
// `feedback` 只有提交点评工具(updatePracticeFeedback / updatePracticePieceFeedback)、
|
|
13
|
+
// `topic` / `brief` 只有出题工具(updatePracticePieceTopic)
|
|
14
|
+
// - **无外键、无索引**:`work_id` 的存在性由写入侧按 shared 预置作品清单守卫;单工作区数据量小、列表全扫
|
|
15
|
+
// - **列表只出投影**:不回正文 / 稿件 / 卡体(`charCount` 走 SQL `length(...)`,不把长文拉进内存;
|
|
16
|
+
// `feedback` 只读出用于判定 `hasFeedback`,不进返回值)
|
|
17
|
+
// - **JSON 列防御解析**:`feedback` text 模式(不用 drizzle `mode:'json'`),坏值按 null
|
|
18
|
+
// - **素材包只存用户覆盖**:无覆盖 = 无行(读侧回退 shared 预置常量),删行 = 恢复预置
|
|
19
|
+
//
|
|
20
|
+
// 返回值形态沿用 db 包既有口径:**详情 / 写入 = 存储形态行(snake_case)**、
|
|
21
|
+
// **列表 = API 投影形状(camelCase,同 EntitySummary 先例)**——列表投影是 db 侧派生
|
|
22
|
+
// (charCount / hasDraft / hasFeedback),不由调用方复算。
|
|
23
|
+
import { asc, desc, eq, sql } from "drizzle-orm";
|
|
24
|
+
import { generateId } from "@whispering233/ai-editor-shared";
|
|
25
|
+
import { withTransaction } from "../connection.js";
|
|
26
|
+
import { nowIso } from "../storage/atomic.js";
|
|
27
|
+
import { queryDb } from "../query-db.js";
|
|
28
|
+
import { practiceFreePieces, practiceSamples, practiceStylePacks } from "../tables.js";
|
|
29
|
+
/**
|
|
30
|
+
* 解析 `feedback` 列(防御解析,同 entity.ts parseDataColumn 先例):
|
|
31
|
+
* 非法 JSON / 非对象(含数组 / JSON `null`)一律按 null——否则单条坏行会打挂读取;
|
|
32
|
+
* **合法 JSON 对象一律原样返回**(含 `{}`——**卡内形状校验在写入侧**,读侧不做形状特判)。
|
|
33
|
+
* 坏值不静默写回(修复入口 = 重跑点评,见 docs/api/120-api-practice.md)。
|
|
34
|
+
*/
|
|
35
|
+
function parseFeedbackColumn(value) {
|
|
36
|
+
if (typeof value !== "string")
|
|
37
|
+
return null;
|
|
38
|
+
try {
|
|
39
|
+
const parsed = JSON.parse(value);
|
|
40
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))
|
|
41
|
+
return null;
|
|
42
|
+
return parsed;
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/** 行映射:列名直映射(同 DDL)+ `feedback` 防御解析 */
|
|
49
|
+
function toSampleRow(row) {
|
|
50
|
+
return { ...row, feedback: parseFeedbackColumn(row.feedback) };
|
|
51
|
+
}
|
|
52
|
+
/** 行映射:列名直映射(同 DDL)+ `feedback` 防御解析 */
|
|
53
|
+
function toPieceRow(row) {
|
|
54
|
+
return { ...row, topic_source: row.topic_source, feedback: parseFeedbackColumn(row.feedback) };
|
|
55
|
+
}
|
|
56
|
+
// ============ 范文样本(practice_samples) ============
|
|
57
|
+
/**
|
|
58
|
+
* 全工作区样本列表(`GET /practice/samples`):按 `updated_at` 倒序(同值用 id 升序作稳定次序,
|
|
59
|
+
* 避免同毫秒写入的列表顺序不稳定)、**只出投影列**——范文正文与卡体不进内存(charCount 走 SQL)。
|
|
60
|
+
*
|
|
61
|
+
* `hasDraft` = `draft <> ''`(SQL 判定);`hasFeedback` = 点评卡**防御解析后非 null**——
|
|
62
|
+
* 与详情同口径:坏 JSON 行在列表与详情一致地呈现为「未点评」(故本查询读出 `feedback` 列但不进返回值)。
|
|
63
|
+
*/
|
|
64
|
+
export function listPracticeSamples(db) {
|
|
65
|
+
const rows = queryDb(db)
|
|
66
|
+
.select({
|
|
67
|
+
id: practiceSamples.id,
|
|
68
|
+
workId: practiceSamples.work_id,
|
|
69
|
+
excerptLabel: practiceSamples.excerpt_label,
|
|
70
|
+
charCount: sql `length(${practiceSamples.text})`,
|
|
71
|
+
hasDraft: sql `(${practiceSamples.draft} <> '')`,
|
|
72
|
+
feedback: practiceSamples.feedback,
|
|
73
|
+
createdAt: practiceSamples.created_at,
|
|
74
|
+
updatedAt: practiceSamples.updated_at,
|
|
75
|
+
})
|
|
76
|
+
.from(practiceSamples)
|
|
77
|
+
.orderBy(desc(practiceSamples.updated_at), asc(practiceSamples.id))
|
|
78
|
+
.all();
|
|
79
|
+
return rows.map((row) => ({
|
|
80
|
+
id: row.id,
|
|
81
|
+
workId: row.workId ?? null,
|
|
82
|
+
excerptLabel: row.excerptLabel,
|
|
83
|
+
charCount: row.charCount,
|
|
84
|
+
hasDraft: row.hasDraft === 1,
|
|
85
|
+
hasFeedback: parseFeedbackColumn(row.feedback) !== null,
|
|
86
|
+
createdAt: row.createdAt,
|
|
87
|
+
updatedAt: row.updatedAt,
|
|
88
|
+
}));
|
|
89
|
+
}
|
|
90
|
+
/** 按 id 取样本详情(`GET /practice/samples/:id`;含范文全文、稿件与防御解析后的点评卡);不存在返回 null */
|
|
91
|
+
export function getPracticeSample(db, id) {
|
|
92
|
+
const row = queryDb(db).select().from(practiceSamples).where(eq(practiceSamples.id, id)).get();
|
|
93
|
+
return row === undefined ? null : toSampleRow(row);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* 新建样本(`POST /practice/samples`):id = `ps-` + nanoid、`draft` = 空串、`feedback` = NULL、
|
|
97
|
+
* created_at = updated_at = 写入时刻。`work_id` 缺省 / null = 「其他」(存在性校验在写入侧 = 路由 schema);
|
|
98
|
+
* `excerpt_label` 缺省 = 空串。**范文 `text` 落库后不可变**(无更新入口)。
|
|
99
|
+
* @returns 新行(存储形态)
|
|
100
|
+
*/
|
|
101
|
+
export function createPracticeSample(db, input) {
|
|
102
|
+
const now = nowIso();
|
|
103
|
+
const row = {
|
|
104
|
+
id: generateId("ps-"),
|
|
105
|
+
work_id: input.workId ?? null,
|
|
106
|
+
excerpt_label: input.excerptLabel ?? "",
|
|
107
|
+
text: input.text,
|
|
108
|
+
draft: "",
|
|
109
|
+
feedback: null,
|
|
110
|
+
created_at: now,
|
|
111
|
+
updated_at: now,
|
|
112
|
+
};
|
|
113
|
+
queryDb(db)
|
|
114
|
+
.insert(practiceSamples)
|
|
115
|
+
.values({
|
|
116
|
+
id: row.id,
|
|
117
|
+
work_id: row.work_id,
|
|
118
|
+
excerpt_label: row.excerpt_label,
|
|
119
|
+
text: row.text,
|
|
120
|
+
draft: row.draft,
|
|
121
|
+
feedback: null,
|
|
122
|
+
created_at: row.created_at,
|
|
123
|
+
updated_at: row.updated_at,
|
|
124
|
+
})
|
|
125
|
+
.run();
|
|
126
|
+
return row;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* 保存仿写稿(`PUT /practice/samples/:id`)——样本侧**唯一的用户写稿入口**(AI 工具面没有写稿工具)。
|
|
130
|
+
* 整体覆盖 `draft`(允许空串 = 清空稿件),推进 `updated_at`;范文 `text` 与 `feedback` 一概不动。
|
|
131
|
+
* 并发口径 = 后写覆盖(不带版本戳,同结构化数据/参考资料)。
|
|
132
|
+
* @returns `{ updatedAt }`(版本戳);样本不存在返回 null(路由层映射 404)
|
|
133
|
+
*/
|
|
134
|
+
export function updatePracticeSampleDraft(db, id, draft) {
|
|
135
|
+
return withTransaction(db, () => {
|
|
136
|
+
if (getPracticeSample(db, id) === null)
|
|
137
|
+
return null;
|
|
138
|
+
const updatedAt = nowIso();
|
|
139
|
+
queryDb(db)
|
|
140
|
+
.update(practiceSamples)
|
|
141
|
+
.set({ draft, updated_at: updatedAt })
|
|
142
|
+
.where(eq(practiceSamples.id, id))
|
|
143
|
+
.run();
|
|
144
|
+
return { updatedAt };
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* 写入仿写点评卡(`submit_style_feedback` 工具的唯一落库入口)——**只写 `feedback`**(JSON 序列化写入),
|
|
149
|
+
* 推进 `updated_at`;范文 `text` 与用户稿 `draft` 一概不动(**AI 能写它自己的产出,不能写用户的产出**)。
|
|
150
|
+
* 卡内形状(字段/引用子串校验)在写入侧 = 提交点评工具,本层只序列化(同 document 先例:库层不校验块体)。
|
|
151
|
+
* @returns `{ updatedAt }`(版本戳);样本不存在返回 null
|
|
152
|
+
*/
|
|
153
|
+
export function updatePracticeFeedback(db, id, feedback) {
|
|
154
|
+
return withTransaction(db, () => {
|
|
155
|
+
if (getPracticeSample(db, id) === null)
|
|
156
|
+
return null;
|
|
157
|
+
const updatedAt = nowIso();
|
|
158
|
+
queryDb(db)
|
|
159
|
+
.update(practiceSamples)
|
|
160
|
+
.set({ feedback: JSON.stringify(feedback), updated_at: updatedAt })
|
|
161
|
+
.where(eq(practiceSamples.id, id))
|
|
162
|
+
.run();
|
|
163
|
+
return { updatedAt };
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* 删除样本(`DELETE /practice/samples/:id`):物理删(练习数据无回收站),行随工作区存续独立。
|
|
168
|
+
* @returns 是否删掉了行(false = 样本不存在,路由层映射 404;重复删除仍返回 false 而不抛错)
|
|
169
|
+
*/
|
|
170
|
+
export function deletePracticeSample(db, id) {
|
|
171
|
+
return queryDb(db).delete(practiceSamples).where(eq(practiceSamples.id, id)).run().changes > 0;
|
|
172
|
+
}
|
|
173
|
+
// ============ 自由练习(practice_free_pieces) ============
|
|
174
|
+
/**
|
|
175
|
+
* 全工作区自由练习列表(`GET /practice/free`):按 `updated_at` 倒序(同值用 id 升序作稳定次序)、
|
|
176
|
+
* **只出投影列**(`charCount` 走 SQL `length(draft)`,稿件不进内存);`hasFeedback` 口径同样本列表。
|
|
177
|
+
*/
|
|
178
|
+
export function listPracticePieces(db) {
|
|
179
|
+
const rows = queryDb(db)
|
|
180
|
+
.select({
|
|
181
|
+
id: practiceFreePieces.id,
|
|
182
|
+
topic: practiceFreePieces.topic,
|
|
183
|
+
brief: practiceFreePieces.brief,
|
|
184
|
+
topicSource: practiceFreePieces.topic_source,
|
|
185
|
+
charCount: sql `length(${practiceFreePieces.draft})`,
|
|
186
|
+
hasDraft: sql `(${practiceFreePieces.draft} <> '')`,
|
|
187
|
+
feedback: practiceFreePieces.feedback,
|
|
188
|
+
createdAt: practiceFreePieces.created_at,
|
|
189
|
+
updatedAt: practiceFreePieces.updated_at,
|
|
190
|
+
})
|
|
191
|
+
.from(practiceFreePieces)
|
|
192
|
+
.orderBy(desc(practiceFreePieces.updated_at), asc(practiceFreePieces.id))
|
|
193
|
+
.all();
|
|
194
|
+
return rows.map((row) => ({
|
|
195
|
+
id: row.id,
|
|
196
|
+
topic: row.topic,
|
|
197
|
+
brief: row.brief,
|
|
198
|
+
topicSource: row.topicSource,
|
|
199
|
+
charCount: row.charCount,
|
|
200
|
+
hasDraft: row.hasDraft === 1,
|
|
201
|
+
hasFeedback: parseFeedbackColumn(row.feedback) !== null,
|
|
202
|
+
createdAt: row.createdAt,
|
|
203
|
+
updatedAt: row.updatedAt,
|
|
204
|
+
}));
|
|
205
|
+
}
|
|
206
|
+
/** 按 id 取自由练习详情(`GET /practice/free/:id`;含稿件与防御解析后的点评卡);不存在返回 null */
|
|
207
|
+
export function getPracticePiece(db, id) {
|
|
208
|
+
const row = queryDb(db).select().from(practiceFreePieces).where(eq(practiceFreePieces.id, id)).get();
|
|
209
|
+
return row === undefined ? null : toPieceRow(row);
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* 新建自由练习篇(`POST /practice/free`):id = `pf-` + nanoid、`draft` = 空串、`feedback` = NULL、
|
|
213
|
+
* created_at = updated_at = 写入时刻。`topic` / `brief` 缺省 = 空串(`topic_source = "ai"` 的空题目行
|
|
214
|
+
* 正是「待出题」状态,题目由出题工具补写);`topic` 与 `topic_source` 的一致性校验在写入侧 = 路由 schema。
|
|
215
|
+
* @returns 新行(存储形态)
|
|
216
|
+
*/
|
|
217
|
+
export function createPracticePiece(db, input) {
|
|
218
|
+
const now = nowIso();
|
|
219
|
+
const row = {
|
|
220
|
+
id: generateId("pf-"),
|
|
221
|
+
topic: input.topic ?? "",
|
|
222
|
+
brief: input.brief ?? "",
|
|
223
|
+
topic_source: input.topicSource,
|
|
224
|
+
draft: "",
|
|
225
|
+
feedback: null,
|
|
226
|
+
created_at: now,
|
|
227
|
+
updated_at: now,
|
|
228
|
+
};
|
|
229
|
+
queryDb(db)
|
|
230
|
+
.insert(practiceFreePieces)
|
|
231
|
+
.values({
|
|
232
|
+
id: row.id,
|
|
233
|
+
topic: row.topic,
|
|
234
|
+
brief: row.brief,
|
|
235
|
+
topic_source: row.topic_source,
|
|
236
|
+
draft: row.draft,
|
|
237
|
+
feedback: null,
|
|
238
|
+
created_at: row.created_at,
|
|
239
|
+
updated_at: row.updated_at,
|
|
240
|
+
})
|
|
241
|
+
.run();
|
|
242
|
+
return row;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* 保存自由练习稿(`PUT /practice/free/:id`)——自由练习侧**唯一的用户写稿入口**。
|
|
246
|
+
* 口径与仿写稿完全一致(整体覆盖、允许空串、后写覆盖):`topic` / `brief` / `feedback` 一概不动。
|
|
247
|
+
* @returns `{ updatedAt }`(版本戳);篇不存在返回 null(路由层映射 404)
|
|
248
|
+
*/
|
|
249
|
+
export function updatePracticePieceDraft(db, id, draft) {
|
|
250
|
+
return withTransaction(db, () => {
|
|
251
|
+
if (getPracticePiece(db, id) === null)
|
|
252
|
+
return null;
|
|
253
|
+
const updatedAt = nowIso();
|
|
254
|
+
queryDb(db)
|
|
255
|
+
.update(practiceFreePieces)
|
|
256
|
+
.set({ draft, updated_at: updatedAt })
|
|
257
|
+
.where(eq(practiceFreePieces.id, id))
|
|
258
|
+
.run();
|
|
259
|
+
return { updatedAt };
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* 写入题目与写作要求(`submit_practice_topic` 工具的唯一落库入口)——**只写 `topic` / `brief`**,
|
|
264
|
+
* 推进 `updated_at`;用户稿 `draft` 与 `feedback` 一概不动。
|
|
265
|
+
* `brief` 省略 = 不改(工具 schema 里 brief 可选;部分更新口径:省略的字段保持原值)。
|
|
266
|
+
* 「题目非空 → 抛错拒写」的守卫在工具层(写入侧),本层只落库。
|
|
267
|
+
* @returns `{ updatedAt }`(版本戳);篇不存在返回 null
|
|
268
|
+
*/
|
|
269
|
+
export function updatePracticePieceTopic(db, id, patch) {
|
|
270
|
+
return withTransaction(db, () => {
|
|
271
|
+
const existing = getPracticePiece(db, id);
|
|
272
|
+
if (existing === null)
|
|
273
|
+
return null;
|
|
274
|
+
const updatedAt = nowIso();
|
|
275
|
+
queryDb(db)
|
|
276
|
+
.update(practiceFreePieces)
|
|
277
|
+
.set({ topic: patch.topic, brief: patch.brief ?? existing.brief, updated_at: updatedAt })
|
|
278
|
+
.where(eq(practiceFreePieces.id, id))
|
|
279
|
+
.run();
|
|
280
|
+
return { updatedAt };
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* 写入自由练习点评卡(`submit_free_feedback` 工具的唯一落库入口)——**只写 `feedback`**,
|
|
285
|
+
* 推进 `updated_at`;`topic` / `brief` / `draft` 一概不动。卡体形状校验同仿写(在写入侧)。
|
|
286
|
+
* @returns `{ updatedAt }`(版本戳);篇不存在返回 null
|
|
287
|
+
*/
|
|
288
|
+
export function updatePracticePieceFeedback(db, id, feedback) {
|
|
289
|
+
return withTransaction(db, () => {
|
|
290
|
+
if (getPracticePiece(db, id) === null)
|
|
291
|
+
return null;
|
|
292
|
+
const updatedAt = nowIso();
|
|
293
|
+
queryDb(db)
|
|
294
|
+
.update(practiceFreePieces)
|
|
295
|
+
.set({ feedback: JSON.stringify(feedback), updated_at: updatedAt })
|
|
296
|
+
.where(eq(practiceFreePieces.id, id))
|
|
297
|
+
.run();
|
|
298
|
+
return { updatedAt };
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* 删除自由练习篇(`DELETE /practice/free/:id`):物理删(不满意的 AI 出题 = 删掉重建,不做覆盖式换题)。
|
|
303
|
+
* @returns 是否删掉了行(false = 篇不存在,路由层映射 404;重复删除仍返回 false 而不抛错)
|
|
304
|
+
*/
|
|
305
|
+
export function deletePracticePiece(db, id) {
|
|
306
|
+
return queryDb(db).delete(practiceFreePieces).where(eq(practiceFreePieces.id, id)).run().changes > 0;
|
|
307
|
+
}
|
|
308
|
+
// ============ 风格说明素材包(practice_style_packs) ============
|
|
309
|
+
/**
|
|
310
|
+
* 取某作家的用户覆盖(`GET /practice/style-pack` 的 `customized` / `updatedAt` 与生效内容来源)。
|
|
311
|
+
* **生效内容 = 覆盖 `??` shared 预置**(回退逻辑在调用侧)。无覆盖返回 null。
|
|
312
|
+
*/
|
|
313
|
+
export function getStylePack(db, authorId) {
|
|
314
|
+
return queryDb(db).select().from(practiceStylePacks).where(eq(practiceStylePacks.author_id, authorId)).get() ?? null;
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* 写入用户覆盖(`PUT /practice/style-pack`):一作家一行,存在即覆盖,`updated_at` 推进。
|
|
318
|
+
* @returns 写入后的行(存储形态)
|
|
319
|
+
*/
|
|
320
|
+
export function upsertStylePack(db, authorId, content) {
|
|
321
|
+
const updatedAt = nowIso();
|
|
322
|
+
queryDb(db)
|
|
323
|
+
.insert(practiceStylePacks)
|
|
324
|
+
.values({ author_id: authorId, content, updated_at: updatedAt })
|
|
325
|
+
.onConflictDoUpdate({
|
|
326
|
+
target: practiceStylePacks.author_id,
|
|
327
|
+
set: { content, updated_at: updatedAt },
|
|
328
|
+
})
|
|
329
|
+
.run();
|
|
330
|
+
return { author_id: authorId, content, updated_at: updatedAt };
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* 删除用户覆盖(`DELETE /practice/style-pack`)= **恢复预置**。
|
|
334
|
+
* @returns 是否删掉了行(false = 本来就没有覆盖——幂等口径,路由层照常返回 200 与预置内容)
|
|
335
|
+
*/
|
|
336
|
+
export function deleteStylePack(db, authorId) {
|
|
337
|
+
return queryDb(db).delete(practiceStylePacks).where(eq(practiceStylePacks.author_id, authorId)).run().changes > 0;
|
|
338
|
+
}
|
|
339
|
+
//# sourceMappingURL=practice.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"practice.js","sourceRoot":"","sources":["../../src/queries/practice.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,mCAAmC;AACnC,EAAE;AACF,iDAAiD;AACjD,uEAAuE;AACvE,wEAAwE;AACxE,EAAE;AACF,eAAe;AACf,gEAAgE;AAChE,oCAAoC;AACpC,sFAAsF;AACtF,+EAA+E;AAC/E,uDAAuD;AACvD,kEAAkE;AAClE,wEAAwE;AACxE,4CAA4C;AAC5C,yEAAyE;AACzE,uDAAuD;AACvD,EAAE;AACF,oDAAoD;AACpD,gEAAgE;AAChE,gDAAgD;AAEhD,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAW,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAgEvF;;;;;GAKG;AACH,SAAS,mBAAmB,CAAC,KAAc;IACzC,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC3C,IAAI,CAAC;QACH,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC1C,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;YAAE,OAAO,IAAI,CAAC;QACxF,OAAO,MAA0B,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,wCAAwC;AACxC,SAAS,WAAW,CAAC,GAAsE;IACzF,OAAO,EAAE,GAAG,GAAG,EAAE,QAAQ,EAAE,mBAAmB,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;AACjE,CAAC;AAED,wCAAwC;AACxC,SAAS,UAAU,CACjB,GAA4G;IAE5G,OAAO,EAAE,GAAG,GAAG,EAAE,YAAY,EAAE,GAAG,CAAC,YAAmC,EAAE,QAAQ,EAAE,mBAAmB,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;AACxH,CAAC;AAED,mDAAmD;AAEnD;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAC,EAAM;IACxC,MAAM,IAAI,GAAG,OAAO,CAAC,EAAE,CAAC;SACrB,MAAM,CAAC;QACN,EAAE,EAAE,eAAe,CAAC,EAAE;QACtB,MAAM,EAAE,eAAe,CAAC,OAAO;QAC/B,YAAY,EAAE,eAAe,CAAC,aAAa;QAC3C,SAAS,EAAE,GAAG,CAAQ,UAAU,eAAe,CAAC,IAAI,GAAG;QACvD,QAAQ,EAAE,GAAG,CAAQ,IAAI,eAAe,CAAC,KAAK,SAAS;QACvD,QAAQ,EAAE,eAAe,CAAC,QAAQ;QAClC,SAAS,EAAE,eAAe,CAAC,UAAU;QACrC,SAAS,EAAE,eAAe,CAAC,UAAU;KACtC,CAAC;SACD,IAAI,CAAC,eAAe,CAAC;SACrB,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,EAAE,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;SAClE,GAAG,EAAE,CAAC;IACT,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACxB,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,IAAI;QAC1B,YAAY,EAAE,GAAG,CAAC,YAAY;QAC9B,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,QAAQ,EAAE,GAAG,CAAC,QAAQ,KAAK,CAAC;QAC5B,WAAW,EAAE,mBAAmB,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,IAAI;QACvD,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,SAAS,EAAE,GAAG,CAAC,SAAS;KACzB,CAAC,CAAC,CAAC;AACN,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,iBAAiB,CAAC,EAAM,EAAE,EAAU;IAClD,MAAM,GAAG,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,eAAe,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;IAC/F,OAAO,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;AACrD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAClC,EAAM,EACN,KAAsE;IAEtE,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;IACrB,MAAM,GAAG,GAAsB;QAC7B,EAAE,EAAE,UAAU,CAAC,KAAK,CAAC;QACrB,OAAO,EAAE,KAAK,CAAC,MAAM,IAAI,IAAI;QAC7B,aAAa,EAAE,KAAK,CAAC,YAAY,IAAI,EAAE;QACvC,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,KAAK,EAAE,EAAE;QACT,QAAQ,EAAE,IAAI;QACd,UAAU,EAAE,GAAG;QACf,UAAU,EAAE,GAAG;KAChB,CAAC;IACF,OAAO,CAAC,EAAE,CAAC;SACR,MAAM,CAAC,eAAe,CAAC;SACvB,MAAM,CAAC;QACN,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,aAAa,EAAE,GAAG,CAAC,aAAa;QAChC,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,QAAQ,EAAE,IAAI;QACd,UAAU,EAAE,GAAG,CAAC,UAAU;QAC1B,UAAU,EAAE,GAAG,CAAC,UAAU;KAC3B,CAAC;SACD,GAAG,EAAE,CAAC;IACT,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,yBAAyB,CAAC,EAAM,EAAE,EAAU,EAAE,KAAa;IACzE,OAAO,eAAe,CAAC,EAAE,EAAE,GAAG,EAAE;QAC9B,IAAI,iBAAiB,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QACpD,MAAM,SAAS,GAAG,MAAM,EAAE,CAAC;QAC3B,OAAO,CAAC,EAAE,CAAC;aACR,MAAM,CAAC,eAAe,CAAC;aACvB,GAAG,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC;aACrC,KAAK,CAAC,EAAE,CAAC,eAAe,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;aACjC,GAAG,EAAE,CAAC;QACT,OAAO,EAAE,SAAS,EAAE,CAAC;IACvB,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CACpC,EAAM,EACN,EAAU,EACV,QAA0B;IAE1B,OAAO,eAAe,CAAC,EAAE,EAAE,GAAG,EAAE;QAC9B,IAAI,iBAAiB,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QACpD,MAAM,SAAS,GAAG,MAAM,EAAE,CAAC;QAC3B,OAAO,CAAC,EAAE,CAAC;aACR,MAAM,CAAC,eAAe,CAAC;aACvB,GAAG,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC;aAClE,KAAK,CAAC,EAAE,CAAC,eAAe,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;aACjC,GAAG,EAAE,CAAC;QACT,OAAO,EAAE,SAAS,EAAE,CAAC;IACvB,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,EAAM,EAAE,EAAU;IACrD,OAAO,OAAO,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,eAAe,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,OAAO,GAAG,CAAC,CAAC;AACjG,CAAC;AAED,uDAAuD;AAEvD;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,EAAM;IACvC,MAAM,IAAI,GAAG,OAAO,CAAC,EAAE,CAAC;SACrB,MAAM,CAAC;QACN,EAAE,EAAE,kBAAkB,CAAC,EAAE;QACzB,KAAK,EAAE,kBAAkB,CAAC,KAAK;QAC/B,KAAK,EAAE,kBAAkB,CAAC,KAAK;QAC/B,WAAW,EAAE,kBAAkB,CAAC,YAAY;QAC5C,SAAS,EAAE,GAAG,CAAQ,UAAU,kBAAkB,CAAC,KAAK,GAAG;QAC3D,QAAQ,EAAE,GAAG,CAAQ,IAAI,kBAAkB,CAAC,KAAK,SAAS;QAC1D,QAAQ,EAAE,kBAAkB,CAAC,QAAQ;QACrC,SAAS,EAAE,kBAAkB,CAAC,UAAU;QACxC,SAAS,EAAE,kBAAkB,CAAC,UAAU;KACzC,CAAC;SACD,IAAI,CAAC,kBAAkB,CAAC;SACxB,OAAO,CAAC,IAAI,CAAC,kBAAkB,CAAC,UAAU,CAAC,EAAE,GAAG,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC;SACxE,GAAG,EAAE,CAAC;IACT,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACxB,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,WAAW,EAAE,GAAG,CAAC,WAAkC;QACnD,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,QAAQ,EAAE,GAAG,CAAC,QAAQ,KAAK,CAAC;QAC5B,WAAW,EAAE,mBAAmB,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,IAAI;QACvD,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,SAAS,EAAE,GAAG,CAAC,SAAS;KACzB,CAAC,CAAC,CAAC;AACN,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,gBAAgB,CAAC,EAAM,EAAE,EAAU;IACjD,MAAM,GAAG,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;IACrG,OAAO,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;AACpD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CACjC,EAAM,EACN,KAA2E;IAE3E,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;IACrB,MAAM,GAAG,GAAqB;QAC5B,EAAE,EAAE,UAAU,CAAC,KAAK,CAAC;QACrB,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,EAAE;QACxB,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,EAAE;QACxB,YAAY,EAAE,KAAK,CAAC,WAAW;QAC/B,KAAK,EAAE,EAAE;QACT,QAAQ,EAAE,IAAI;QACd,UAAU,EAAE,GAAG;QACf,UAAU,EAAE,GAAG;KAChB,CAAC;IACF,OAAO,CAAC,EAAE,CAAC;SACR,MAAM,CAAC,kBAAkB,CAAC;SAC1B,MAAM,CAAC;QACN,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,YAAY,EAAE,GAAG,CAAC,YAAY;QAC9B,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,QAAQ,EAAE,IAAI;QACd,UAAU,EAAE,GAAG,CAAC,UAAU;QAC1B,UAAU,EAAE,GAAG,CAAC,UAAU;KAC3B,CAAC;SACD,GAAG,EAAE,CAAC;IACT,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CAAC,EAAM,EAAE,EAAU,EAAE,KAAa;IACxE,OAAO,eAAe,CAAC,EAAE,EAAE,GAAG,EAAE;QAC9B,IAAI,gBAAgB,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QACnD,MAAM,SAAS,GAAG,MAAM,EAAE,CAAC;QAC3B,OAAO,CAAC,EAAE,CAAC;aACR,MAAM,CAAC,kBAAkB,CAAC;aAC1B,GAAG,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC;aACrC,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;aACpC,GAAG,EAAE,CAAC;QACT,OAAO,EAAE,SAAS,EAAE,CAAC;IACvB,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,wBAAwB,CACtC,EAAM,EACN,EAAU,EACV,KAAwC;IAExC,OAAO,eAAe,CAAC,EAAE,EAAE,GAAG,EAAE;QAC9B,MAAM,QAAQ,GAAG,gBAAgB,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAC1C,IAAI,QAAQ,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QACnC,MAAM,SAAS,GAAG,MAAM,EAAE,CAAC;QAC3B,OAAO,CAAC,EAAE,CAAC;aACR,MAAM,CAAC,kBAAkB,CAAC;aAC1B,GAAG,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,QAAQ,CAAC,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC;aACxF,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;aACpC,GAAG,EAAE,CAAC;QACT,OAAO,EAAE,SAAS,EAAE,CAAC;IACvB,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,2BAA2B,CACzC,EAAM,EACN,EAAU,EACV,QAA0B;IAE1B,OAAO,eAAe,CAAC,EAAE,EAAE,GAAG,EAAE;QAC9B,IAAI,gBAAgB,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QACnD,MAAM,SAAS,GAAG,MAAM,EAAE,CAAC;QAC3B,OAAO,CAAC,EAAE,CAAC;aACR,MAAM,CAAC,kBAAkB,CAAC;aAC1B,GAAG,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC;aAClE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;aACpC,GAAG,EAAE,CAAC;QACT,OAAO,EAAE,SAAS,EAAE,CAAC;IACvB,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,EAAM,EAAE,EAAU;IACpD,OAAO,OAAO,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,OAAO,GAAG,CAAC,CAAC;AACvG,CAAC;AAED,0DAA0D;AAE1D;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,EAAM,EAAE,QAAgB;IACnD,OAAO,OAAO,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC;AACvH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,EAAM,EAAE,QAAgB,EAAE,OAAe;IACvE,MAAM,SAAS,GAAG,MAAM,EAAE,CAAC;IAC3B,OAAO,CAAC,EAAE,CAAC;SACR,MAAM,CAAC,kBAAkB,CAAC;SAC1B,MAAM,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC;SAC/D,kBAAkB,CAAC;QAClB,MAAM,EAAE,kBAAkB,CAAC,SAAS;QACpC,GAAG,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE;KACxC,CAAC;SACD,GAAG,EAAE,CAAC;IACT,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC;AACjE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,EAAM,EAAE,QAAgB;IACtD,OAAO,OAAO,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,OAAO,GAAG,CAAC,CAAC;AACpH,CAAC"}
|
package/dist/schema.d.ts
CHANGED
|
@@ -22,8 +22,14 @@ import type Database from "better-sqlite3";
|
|
|
22
22
|
* 创作根配置的快照;纯 DDL 无数据搬移,存量行回填 1,migrations/010_decompose_concurrency.ts)。
|
|
23
23
|
* v10 → v11(拆解功能移除,2026-09):DROP 上述两表(拆解整功能已移除,见 CHANGELOG——
|
|
24
24
|
* 009/010 保留只为旧库升级链连续;纯 DDL 无数据搬移,migrations/011_drop_decompose.ts)。
|
|
25
|
+
* v11 → v12(文风仿写练习,2026-10):新增 `practice_targets` / `practice_samples` 两表
|
|
26
|
+
* (练习工作区专属,纯 DDL 无数据搬移——旧项目没有练习行,migrations/012_practice.ts)。
|
|
27
|
+
* v12 → v13(作家文风练习改版,2026-10):DROP 旧 `practice_targets` / 旧 `practice_samples`
|
|
28
|
+
* (含 `idx_practice_samples_target`)→ 建 `practice_samples` 新形状 / `practice_free_pieces` /
|
|
29
|
+
* `practice_style_packs` 三表(一位预置作家 = 一个工作区,旧目标模型被整体替换;
|
|
30
|
+
* 纯 DDL 无数据搬移,migrations/013_author_practice.ts)。
|
|
25
31
|
*/
|
|
26
|
-
export declare const SCHEMA_VERSION =
|
|
32
|
+
export declare const SCHEMA_VERSION = 13;
|
|
27
33
|
/**
|
|
28
34
|
* 建表:执行全部 DDL(CREATE TABLE/INDEX IF NOT EXISTS,定义于 tables.ts),幂等,可重复调用。
|
|
29
35
|
* 打开数据库后由 connection.openDatabase 自动调用。
|
package/dist/schema.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAG3C
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAG3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,cAAc,KAAK,CAAC;AAEjC;;;GAGG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAExD;AAED,2DAA2D;AAC3D,wBAAgB,cAAc,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,MAAM,CAE5D;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAK3E"}
|
package/dist/schema.js
CHANGED
|
@@ -27,8 +27,14 @@ import { CREATE_TABLES_SQL } from "./tables.js";
|
|
|
27
27
|
* 创作根配置的快照;纯 DDL 无数据搬移,存量行回填 1,migrations/010_decompose_concurrency.ts)。
|
|
28
28
|
* v10 → v11(拆解功能移除,2026-09):DROP 上述两表(拆解整功能已移除,见 CHANGELOG——
|
|
29
29
|
* 009/010 保留只为旧库升级链连续;纯 DDL 无数据搬移,migrations/011_drop_decompose.ts)。
|
|
30
|
+
* v11 → v12(文风仿写练习,2026-10):新增 `practice_targets` / `practice_samples` 两表
|
|
31
|
+
* (练习工作区专属,纯 DDL 无数据搬移——旧项目没有练习行,migrations/012_practice.ts)。
|
|
32
|
+
* v12 → v13(作家文风练习改版,2026-10):DROP 旧 `practice_targets` / 旧 `practice_samples`
|
|
33
|
+
* (含 `idx_practice_samples_target`)→ 建 `practice_samples` 新形状 / `practice_free_pieces` /
|
|
34
|
+
* `practice_style_packs` 三表(一位预置作家 = 一个工作区,旧目标模型被整体替换;
|
|
35
|
+
* 纯 DDL 无数据搬移,migrations/013_author_practice.ts)。
|
|
30
36
|
*/
|
|
31
|
-
export const SCHEMA_VERSION =
|
|
37
|
+
export const SCHEMA_VERSION = 13; // +练习三表(013 重建:旧两表 DROP,纯 DDL)
|
|
32
38
|
/**
|
|
33
39
|
* 建表:执行全部 DDL(CREATE TABLE/INDEX IF NOT EXISTS,定义于 tables.ts),幂等,可重复调用。
|
|
34
40
|
* 打开数据库后由 connection.openDatabase 自动调用。
|
package/dist/schema.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,qDAAqD;AACrD,EAAE;AACF,kDAAkD;AAClD,oCAAoC;AACpC,kFAAkF;AAGlF,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,qDAAqD;AACrD,EAAE;AACF,kDAAkD;AAClD,oCAAoC;AACpC,kFAAkF;AAGlF,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,EAAE,CAAC,CAAC,+BAA+B;AAEjE;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,EAAqB;IAChD,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;AAC7B,CAAC;AAED,2DAA2D;AAC3D,MAAM,UAAU,cAAc,CAAC,EAAqB;IAClD,OAAO,EAAE,CAAC,MAAM,CAAC,cAAc,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAW,CAAC;AAC/D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,EAAqB,EAAE,OAAe;IACnE,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,oCAAoC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACzE,CAAC;IACD,EAAE,CAAC,MAAM,CAAC,kBAAkB,OAAO,EAAE,CAAC,CAAC;AACzC,CAAC"}
|
|
@@ -12,6 +12,8 @@ export declare const AGENTS_FILE_NAME = "AGENTS.md";
|
|
|
12
12
|
* 不存在则无法合成默认值(id 需生成、name 需取目录名,属初始化逻辑)。
|
|
13
13
|
*
|
|
14
14
|
* 文件存在但 JSON 损坏:**抛错**,不静默重建(同 readOutlineFile 的取舍)。
|
|
15
|
+
* 工作区类型(kind)读侧容忍:缺失 / 非字符串 / 未知值均不视为有效类型(缺失不在返回对象上补键,
|
|
16
|
+
* 避免被写回盘上),有效类型由 shared `resolveWorkspaceKind()` 在消费点兜底。
|
|
15
17
|
*
|
|
16
18
|
* @param dir 项目根目录
|
|
17
19
|
* @returns 项目配置;文件不存在返回 null
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../../src/storage/project.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../../src/storage/project.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAIzE,8BAA8B;AAC9B,eAAO,MAAM,iBAAiB,iBAAiB,CAAC;AAEhD,0CAA0C;AAC1C,eAAO,MAAM,gBAAgB,cAAc,CAAC;AAE5C;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CAIrE;AA8BD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAE7E;AAID;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAEzD;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAElE;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAO7D"}
|
package/dist/storage/project.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
// 项目规则唯一事实源 = 项目目录 (取代 project.json `prompt` 字段,不再读写)。
|
|
7
7
|
import { join } from "node:path";
|
|
8
8
|
import { statSync } from "node:fs";
|
|
9
|
+
import { resolveWorkspaceKind } from "@whispering233/ai-editor-shared";
|
|
9
10
|
import { readTextFileOrNull, writeJsonAtomic, writeTextAtomic } from "./atomic.js";
|
|
10
11
|
/** project.json 文件名(项目根目录) */
|
|
11
12
|
export const PROJECT_FILE_NAME = "project.json";
|
|
@@ -20,6 +21,8 @@ export const AGENTS_FILE_NAME = "AGENTS.md";
|
|
|
20
21
|
* 不存在则无法合成默认值(id 需生成、name 需取目录名,属初始化逻辑)。
|
|
21
22
|
*
|
|
22
23
|
* 文件存在但 JSON 损坏:**抛错**,不静默重建(同 readOutlineFile 的取舍)。
|
|
24
|
+
* 工作区类型(kind)读侧容忍:缺失 / 非字符串 / 未知值均不视为有效类型(缺失不在返回对象上补键,
|
|
25
|
+
* 避免被写回盘上),有效类型由 shared `resolveWorkspaceKind()` 在消费点兜底。
|
|
23
26
|
*
|
|
24
27
|
* @param dir 项目根目录
|
|
25
28
|
* @returns 项目配置;文件不存在返回 null
|
|
@@ -47,7 +50,14 @@ function validateProjectFile(parsed) {
|
|
|
47
50
|
typeof parsed.schema_version !== "number") {
|
|
48
51
|
throw new Error("project.json 顶层结构不符(需 {id:string, name:string, schema_version:number, ...})");
|
|
49
52
|
}
|
|
50
|
-
|
|
53
|
+
const config = parsed;
|
|
54
|
+
// 工作区类型(kind)读侧容忍:非字符串 / 未知值 → 剔出(不在此补缺省值)——补键会被
|
|
55
|
+
// PUT /project/config 的 config 展开写回盘上,把「只读兜底」变成静默迁移;
|
|
56
|
+
// 有效类型由 shared 的 resolveWorkspaceKind() 在各消费点(API 输出 / 目录映射 / 守卫)唯一兜底
|
|
57
|
+
if (config.kind !== undefined && resolveWorkspaceKind(config.kind) !== config.kind) {
|
|
58
|
+
delete config.kind;
|
|
59
|
+
}
|
|
60
|
+
return config;
|
|
51
61
|
}
|
|
52
62
|
/**
|
|
53
63
|
* 原子写 project.json(同款流程:临时文件 + fsync + rename)。
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project.js","sourceRoot":"","sources":["../../src/storage/project.ts"],"names":[],"mappings":"AAAA,sDAAsD;AACtD,EAAE;AACF,iFAAiF;AACjF,+CAA+C;AAC/C,4BAA4B;AAC5B,uDAAuD;AAEvD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnF,8BAA8B;AAC9B,MAAM,CAAC,MAAM,iBAAiB,GAAG,cAAc,CAAC;AAEhD,0CAA0C;AAC1C,MAAM,CAAC,MAAM,gBAAgB,GAAG,WAAW,CAAC;AAE5C
|
|
1
|
+
{"version":3,"file":"project.js","sourceRoot":"","sources":["../../src/storage/project.ts"],"names":[],"mappings":"AAAA,sDAAsD;AACtD,EAAE;AACF,iFAAiF;AACjF,+CAA+C;AAC/C,4BAA4B;AAC5B,uDAAuD;AAEvD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnF,8BAA8B;AAC9B,MAAM,CAAC,MAAM,iBAAiB,GAAG,cAAc,CAAC;AAEhD,0CAA0C;AAC1C,MAAM,CAAC,MAAM,gBAAgB,GAAG,WAAW,CAAC;AAE5C;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,MAAM,GAAG,GAAG,kBAAkB,CAAC,IAAI,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAC7D,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC9B,OAAO,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,4BAA4B;AAC3E,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,mBAAmB,CAAC,MAAe;IAC1C,IACE,OAAO,MAAM,KAAK,QAAQ;QAC1B,MAAM,KAAK,IAAI;QACf,OAAQ,MAAkC,CAAC,EAAE,KAAK,QAAQ;QAC1D,OAAQ,MAAkC,CAAC,IAAI,KAAK,QAAQ;QAC5D,OAAQ,MAAkC,CAAC,cAAc,KAAK,QAAQ,EACtE,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,6EAA6E,CAAC,CAAC;IACjG,CAAC;IACD,MAAM,MAAM,GAAG,MAA2B,CAAC;IAC5C,iDAAiD;IACjD,qDAAqD;IACrD,sEAAsE;IACrE,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,IAAI,oBAAoB,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC;QACnF,OAAO,MAAM,CAAC,IAAI,CAAC;IACrB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAW,EAAE,MAAyB;IACrE,eAAe,CAAC,IAAI,CAAC,GAAG,EAAE,iBAAiB,CAAC,EAAE,MAAM,CAAC,CAAC;AACxD,CAAC;AAED,mCAAmC;AAEnC;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,OAAO,kBAAkB,CAAC,IAAI,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC,CAAC;AACzD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW,EAAE,OAAe;IAC1D,eAAe,CAAC,IAAI,CAAC,GAAG,EAAE,gBAAgB,CAAC,EAAE,OAAO,CAAC,CAAC;AACxD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAC5C,IAAI,CAAC;QACH,OAAO,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;IACnE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QAClE,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC"}
|