@musnows/scriverse 0.5.9 → 0.5.11
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/ai.js +62 -7
- package/dist/ai.js.map +1 -1
- package/dist/app.js +44 -5
- package/dist/app.js.map +1 -1
- package/dist/cli-contract.js +25 -0
- package/dist/cli-contract.js.map +1 -1
- package/dist/cli-core.js +3 -0
- package/dist/cli-core.js.map +1 -1
- package/dist/database.js +48 -1
- package/dist/database.js.map +1 -1
- package/dist/public/app.js +609 -74
- package/dist/public/entity-version.js +2 -0
- package/dist/public/index.html +10 -2
- package/dist/public/markdown.js +6 -1
- package/dist/public/page-route.d.ts +1 -1
- package/dist/public/page-route.js +1 -0
- package/dist/public/stream-typewriter.d.ts +19 -0
- package/dist/public/stream-typewriter.js +79 -0
- package/dist/public/styles.css +75 -9
- package/dist/public/vditor-line-number-layout.d.ts +14 -0
- package/dist/public/vditor-line-number-layout.js +51 -0
- package/dist/public/work-permissions.d.ts +2 -2
- package/dist/public/work-permissions.js +8 -0
- package/dist/store.js +108 -2
- package/dist/store.js.map +1 -1
- package/dist/user-auth.js +12 -5
- package/dist/user-auth.js.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/dist/work-permissions.js +9 -0
- package/dist/work-permissions.js.map +1 -1
- package/package.json +1 -1
package/dist/store.js
CHANGED
|
@@ -7,6 +7,7 @@ import { currentRequestActor } from "./request-context.js";
|
|
|
7
7
|
import { classifyWorkModulePermissions, emptyWorkModulePermissions, fullWorkModulePermissions, storedWorkModulePermissions } from "./work-permissions.js";
|
|
8
8
|
import { countWords, documentShortSearchTerms, id, json, normalizeDocumentSearchText, normalizeParagraphSpacing, now, splitDocumentParagraphs } from "./utils.js";
|
|
9
9
|
const defaultPlatformPageSizes = {
|
|
10
|
+
drafts: 30,
|
|
10
11
|
settings: 30,
|
|
11
12
|
characters: 30,
|
|
12
13
|
races: 30,
|
|
@@ -29,6 +30,7 @@ function platformPageSizes(value) {
|
|
|
29
30
|
: defaultPlatformPageSizes[key];
|
|
30
31
|
};
|
|
31
32
|
return {
|
|
33
|
+
drafts: pageSize("drafts"),
|
|
32
34
|
settings: pageSize("settings"),
|
|
33
35
|
characters: pageSize("characters"),
|
|
34
36
|
races: pageSize("races"),
|
|
@@ -110,6 +112,7 @@ function settingsFromKnowledgeSections(sections) {
|
|
|
110
112
|
export const versionedEntityTypes = [
|
|
111
113
|
"work",
|
|
112
114
|
"volume",
|
|
115
|
+
"draft",
|
|
113
116
|
"setting",
|
|
114
117
|
"race",
|
|
115
118
|
"organization",
|
|
@@ -237,6 +240,8 @@ export class Store {
|
|
|
237
240
|
return this.getWork(entityId);
|
|
238
241
|
if (type === "volume")
|
|
239
242
|
return this.getVolume(entityId);
|
|
243
|
+
if (type === "draft")
|
|
244
|
+
return this.getDraft(entityId);
|
|
240
245
|
if (type === "setting")
|
|
241
246
|
return this.getSetting(entityId);
|
|
242
247
|
if (type === "race")
|
|
@@ -287,6 +292,12 @@ export class Store {
|
|
|
287
292
|
keywords: entity.keywords,
|
|
288
293
|
sortOrder: entity.sortOrder
|
|
289
294
|
};
|
|
295
|
+
if (type === "draft")
|
|
296
|
+
return {
|
|
297
|
+
draftType: entity.draftType,
|
|
298
|
+
title: entity.title,
|
|
299
|
+
content: entity.content
|
|
300
|
+
};
|
|
290
301
|
if (type === "setting")
|
|
291
302
|
return {
|
|
292
303
|
title: entity.title,
|
|
@@ -393,6 +404,7 @@ export class Store {
|
|
|
393
404
|
const entities = [
|
|
394
405
|
...this.db.all("SELECT id, updated_at FROM works").map((row) => ["work", requiredString(row, "id"), requiredString(row, "updated_at")]),
|
|
395
406
|
...this.db.all("SELECT id, updated_at FROM volumes").map((row) => ["volume", requiredString(row, "id"), requiredString(row, "updated_at")]),
|
|
407
|
+
...this.db.all("SELECT id, updated_at FROM drafts").map((row) => ["draft", requiredString(row, "id"), requiredString(row, "updated_at")]),
|
|
396
408
|
...this.db.all("SELECT id, updated_at FROM settings").map((row) => ["setting", requiredString(row, "id"), requiredString(row, "updated_at")]),
|
|
397
409
|
...this.db.all("SELECT id, updated_at FROM races").map((row) => ["race", requiredString(row, "id"), requiredString(row, "updated_at")]),
|
|
398
410
|
...this.db.all("SELECT id, updated_at FROM organizations").map((row) => ["organization", requiredString(row, "id"), requiredString(row, "updated_at")]),
|
|
@@ -474,6 +486,8 @@ export class Store {
|
|
|
474
486
|
restored = this.updateWork(entityId, snapshot, expectedVersionNo, "restore", sourceRef, changeNote);
|
|
475
487
|
else if (type === "volume")
|
|
476
488
|
restored = this.updateVolume(entityId, snapshot, expectedVersionNo, "restore", sourceRef, changeNote);
|
|
489
|
+
else if (type === "draft")
|
|
490
|
+
restored = this.updateDraft(entityId, snapshot, "restore", sourceRef, changeNote, expectedVersionNo);
|
|
477
491
|
else if (type === "setting")
|
|
478
492
|
restored = this.updateSetting(entityId, snapshot, "restore", sourceRef, changeNote, expectedVersionNo);
|
|
479
493
|
else if (type === "race")
|
|
@@ -513,6 +527,9 @@ export class Store {
|
|
|
513
527
|
if (type === "volume") {
|
|
514
528
|
return this.db.transaction(() => this.insertVolumeWithId(workId, entityId, snapshot, "restore", sourceRef, changeNote));
|
|
515
529
|
}
|
|
530
|
+
if (type === "draft") {
|
|
531
|
+
return this.insertDraftWithId(workId, entityId, snapshot, "restore", sourceRef, changeNote);
|
|
532
|
+
}
|
|
516
533
|
if (type === "setting") {
|
|
517
534
|
return this.insertSettingWithId(workId, entityId, snapshot, "restore", sourceRef, changeNote);
|
|
518
535
|
}
|
|
@@ -668,7 +685,7 @@ export class Store {
|
|
|
668
685
|
autoRunConsecutiveFailures: Math.max(0, Number(row?.auto_run_consecutive_failures ?? 0) || 0),
|
|
669
686
|
bookSummaryContextPercent: Math.min(90, Math.max(1, Number(row?.book_summary_context_percent ?? 50) || 50)),
|
|
670
687
|
contextCompactThreshold: Math.min(90, Math.max(50, Number(row?.context_compact_threshold ?? 85) || 85)),
|
|
671
|
-
agentTools: json(String(row?.agent_tools_json ?? '["story_index","read_chapters","search_story_entities","grep","read_character_sections"]'), ["story_index", "read_chapters", "search_story_entities", "grep", "read_character_sections"])
|
|
688
|
+
agentTools: json(String(row?.agent_tools_json ?? '["story_index","read_chapters","search_story_entities","grep","read_character_sections","search_drafts"]'), ["story_index", "read_chapters", "search_story_entities", "grep", "read_character_sections", "search_drafts"])
|
|
672
689
|
.map((tool) => tool === "query_story_knowledge" ? "search_story_entities" : tool)
|
|
673
690
|
.filter((tool, index, tools) => tools.indexOf(tool) === index),
|
|
674
691
|
updatedAt: String(row?.updated_at ?? "")
|
|
@@ -2163,6 +2180,94 @@ export class Store {
|
|
|
2163
2180
|
FROM chapters c JOIN volumes v ON v.id = c.volume_id WHERE c.id = ? AND c.work_id = ?`, chapterId, workId);
|
|
2164
2181
|
return row ? numberValue(row, "sequence") : Number.MAX_SAFE_INTEGER;
|
|
2165
2182
|
}
|
|
2183
|
+
createDraft(workId, input, source = "create", sourceRef = null) {
|
|
2184
|
+
this.getWork(workId);
|
|
2185
|
+
return this.insertDraftWithId(workId, id("draft"), input, source, sourceRef);
|
|
2186
|
+
}
|
|
2187
|
+
insertDraftWithId(workId, draftId, input, source = "create", sourceRef = null, changeNote = "") {
|
|
2188
|
+
const timestamp = now();
|
|
2189
|
+
this.db.transaction(() => {
|
|
2190
|
+
this.db.run(`INSERT INTO drafts (id, work_id, draft_type, title, content, created_at, updated_at)
|
|
2191
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`, draftId, workId, input.draftType, input.title, input.content, timestamp, timestamp);
|
|
2192
|
+
this.syncMarkdownAttachmentReferences(workId, "draft", draftId, input.content);
|
|
2193
|
+
this.recordEntityVersion("draft", draftId, source, sourceRef, changeNote || "建立创作草稿", timestamp);
|
|
2194
|
+
this.audit(workId, source === "restore" ? "draft.restored" : "draft.created", "draft", draftId, {
|
|
2195
|
+
draftType: input.draftType,
|
|
2196
|
+
source,
|
|
2197
|
+
sourceRef
|
|
2198
|
+
});
|
|
2199
|
+
});
|
|
2200
|
+
return this.getDraft(draftId);
|
|
2201
|
+
}
|
|
2202
|
+
listDrafts(workId, draftType, includeContent = false) {
|
|
2203
|
+
this.getWork(workId);
|
|
2204
|
+
return this.db.all(`SELECT * FROM drafts WHERE work_id = ? AND (? IS NULL OR draft_type = ?)
|
|
2205
|
+
ORDER BY updated_at DESC, title`, workId, draftType ?? null, draftType ?? null).map((row) => this.mapDraft(row, includeContent));
|
|
2206
|
+
}
|
|
2207
|
+
listDraftsPage(workId, pagination, draftType, includeContent = false) {
|
|
2208
|
+
this.getWork(workId);
|
|
2209
|
+
const page = paginationSql(pagination);
|
|
2210
|
+
const rows = this.db.all(`SELECT * FROM drafts WHERE work_id = ? AND (? IS NULL OR draft_type = ?)
|
|
2211
|
+
ORDER BY updated_at DESC, title${page.sql}`, workId, draftType ?? null, draftType ?? null, ...page.params);
|
|
2212
|
+
return paginated(rows.map((row) => this.mapDraft(row, includeContent)), pagination);
|
|
2213
|
+
}
|
|
2214
|
+
searchDrafts(workId, query, draftType, limit = 20) {
|
|
2215
|
+
this.getWork(workId);
|
|
2216
|
+
const safeLimit = Math.min(30, Math.max(1, Math.trunc(limit)));
|
|
2217
|
+
const normalizedQuery = query.normalize("NFKC").trim();
|
|
2218
|
+
const escapedQuery = normalizedQuery.replace(/[\\%_]/gu, "\\$&");
|
|
2219
|
+
const pattern = `%${escapedQuery}%`;
|
|
2220
|
+
const rows = normalizedQuery
|
|
2221
|
+
? this.db.all(`SELECT * FROM drafts
|
|
2222
|
+
WHERE work_id = ? AND (? IS NULL OR draft_type = ?)
|
|
2223
|
+
AND (title LIKE ? ESCAPE '\\' COLLATE NOCASE OR content LIKE ? ESCAPE '\\' COLLATE NOCASE)
|
|
2224
|
+
ORDER BY CASE WHEN title LIKE ? ESCAPE '\\' COLLATE NOCASE THEN 0 ELSE 1 END, updated_at DESC
|
|
2225
|
+
LIMIT ?`, workId, draftType ?? null, draftType ?? null, pattern, pattern, pattern, safeLimit)
|
|
2226
|
+
: this.db.all(`SELECT * FROM drafts WHERE work_id = ? AND (? IS NULL OR draft_type = ?)
|
|
2227
|
+
ORDER BY updated_at DESC, title LIMIT ?`, workId, draftType ?? null, draftType ?? null, safeLimit);
|
|
2228
|
+
return rows.map((row) => this.mapDraft(row, true));
|
|
2229
|
+
}
|
|
2230
|
+
getDraft(draftId) {
|
|
2231
|
+
const row = this.db.get("SELECT * FROM drafts WHERE id = ?", draftId);
|
|
2232
|
+
if (!row)
|
|
2233
|
+
throw notFound("草稿");
|
|
2234
|
+
return this.mapDraft(row, true);
|
|
2235
|
+
}
|
|
2236
|
+
updateDraft(draftId, input, source = "manual", sourceRef = null, changeNote = "", expectedVersionNo) {
|
|
2237
|
+
const current = this.getDraft(draftId);
|
|
2238
|
+
const content = input.content ?? String(current.content);
|
|
2239
|
+
this.db.transaction(() => {
|
|
2240
|
+
this.assertExpectedVersion("draft", draftId, expectedVersionNo, "草稿");
|
|
2241
|
+
this.db.run("UPDATE drafts SET draft_type = ?, title = ?, content = ?, updated_at = ? WHERE id = ?", input.draftType ?? String(current.draftType), input.title ?? String(current.title), content, now(), draftId);
|
|
2242
|
+
this.syncMarkdownAttachmentReferences(String(current.workId), "draft", draftId, content);
|
|
2243
|
+
this.recordEntityVersion("draft", draftId, source, sourceRef, changeNote || "更新创作草稿");
|
|
2244
|
+
this.audit(String(current.workId), "draft.updated", "draft", draftId, { fields: Object.keys(input), source, sourceRef });
|
|
2245
|
+
});
|
|
2246
|
+
return this.getDraft(draftId);
|
|
2247
|
+
}
|
|
2248
|
+
deleteDraft(draftId, expectedVersionNo) {
|
|
2249
|
+
const current = this.getDraft(draftId);
|
|
2250
|
+
this.db.transaction(() => {
|
|
2251
|
+
this.assertExpectedVersion("draft", draftId, expectedVersionNo, "草稿");
|
|
2252
|
+
this.recordEntityVersion("draft", draftId, "delete", null, "删除创作草稿");
|
|
2253
|
+
this.clearMarkdownAttachmentReferences("draft", draftId);
|
|
2254
|
+
this.db.run("DELETE FROM drafts WHERE id = ?", draftId);
|
|
2255
|
+
this.audit(String(current.workId), "draft.deleted", "draft", draftId);
|
|
2256
|
+
});
|
|
2257
|
+
}
|
|
2258
|
+
mapDraft(row, includeContent) {
|
|
2259
|
+
const content = requiredString(row, "content");
|
|
2260
|
+
return {
|
|
2261
|
+
id: requiredString(row, "id"),
|
|
2262
|
+
workId: requiredString(row, "work_id"),
|
|
2263
|
+
draftType: requiredString(row, "draft_type"),
|
|
2264
|
+
title: requiredString(row, "title"),
|
|
2265
|
+
...(includeContent ? { content } : { contentPreview: content.replace(/\s+/gu, " ").trim().slice(0, 320) }),
|
|
2266
|
+
versionNo: this.currentEntityVersionNo("draft", requiredString(row, "id")),
|
|
2267
|
+
createdAt: requiredString(row, "created_at"),
|
|
2268
|
+
updatedAt: requiredString(row, "updated_at")
|
|
2269
|
+
};
|
|
2270
|
+
}
|
|
2166
2271
|
createSetting(workId, input, source = "create", sourceRef = null) {
|
|
2167
2272
|
this.getWork(workId);
|
|
2168
2273
|
return this.insertSettingWithId(workId, id("setting"), input, source, sourceRef);
|
|
@@ -5445,9 +5550,10 @@ export class Store {
|
|
|
5445
5550
|
exportWork(workId) {
|
|
5446
5551
|
const tree = this.getWorkTree(workId);
|
|
5447
5552
|
return {
|
|
5448
|
-
schemaVersion:
|
|
5553
|
+
schemaVersion: 8,
|
|
5449
5554
|
exportedAt: now(),
|
|
5450
5555
|
work: tree,
|
|
5556
|
+
drafts: this.listDrafts(workId, undefined, true),
|
|
5451
5557
|
settings: this.listSettings(workId),
|
|
5452
5558
|
characters: this.listCharacters(workId, true, true),
|
|
5453
5559
|
races: this.listRaces(workId),
|