@musnows/scriverse 0.5.7 → 0.5.9
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 +350 -67
- package/dist/ai.js.map +1 -1
- package/dist/app.js +51 -35
- package/dist/app.js.map +1 -1
- package/dist/cli-core.js +161 -20
- package/dist/cli-core.js.map +1 -1
- package/dist/database.js +72 -0
- package/dist/database.js.map +1 -1
- package/dist/hybrid-search.js +106 -0
- package/dist/hybrid-search.js.map +1 -0
- package/dist/public/app.js +252 -57
- package/dist/public/display-labels.js +13 -1
- package/dist/public/global-search.d.ts +6 -5
- package/dist/public/global-search.js +44 -3
- package/dist/public/index.html +21 -8
- package/dist/public/race-hierarchy.js +0 -35
- package/dist/public/styles.css +27 -6
- package/dist/relationship-search.js +21 -2
- package/dist/relationship-search.js.map +1 -1
- package/dist/store.js +167 -6
- package/dist/store.js.map +1 -1
- package/dist/user-auth.js +27 -1
- package/dist/user-auth.js.map +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/app.js
CHANGED
|
@@ -16,6 +16,7 @@ import { Database } from "./database.js";
|
|
|
16
16
|
import { assertSafeDocxArchive } from "./docx-security.js";
|
|
17
17
|
import { TASK_TYPES } from "./domain.js";
|
|
18
18
|
import { AppError } from "./errors.js";
|
|
19
|
+
import { HYBRID_SEARCH_TYPES } from "./hybrid-search.js";
|
|
19
20
|
import { applyImportFileHints, parseNovelText } from "./parser.js";
|
|
20
21
|
import { Store, versionedEntityTypes } from "./store.js";
|
|
21
22
|
import { parsePagination } from "./pagination.js";
|
|
@@ -30,7 +31,7 @@ import { currentRequestActor, runWithRequestActor } from "./request-context.js";
|
|
|
30
31
|
import { APP_VERSION } from "./version.js";
|
|
31
32
|
import { fullWorkModulePermissions, proseReplacementPermissionModules } from "./work-permissions.js";
|
|
32
33
|
import { CollaborationPresence, entityEditorPageKey, presencePageKinds } from "./collaboration-presence.js";
|
|
33
|
-
import { clearSessionCookie, createCliApiScopeMiddleware, createUserSessionMiddleware, createWorkAuthorizationMiddleware, relationshipAnalysisReadModules, setSessionCookie, UserAuthService } from "./user-auth.js";
|
|
34
|
+
import { analysisTaskReadModules, clearSessionCookie, createCliApiScopeMiddleware, createUserSessionMiddleware, createWorkAuthorizationMiddleware, relationshipAnalysisReadModules, setSessionCookie, UserAuthService } from "./user-auth.js";
|
|
34
35
|
const nonEmpty = z.string().trim().min(1);
|
|
35
36
|
const identifier = z.string().trim().min(1).max(200);
|
|
36
37
|
const optionalStrings = z.array(z.string()).optional();
|
|
@@ -239,6 +240,7 @@ const raceSchema = z.object({
|
|
|
239
240
|
settingsSections: knowledgeSectionsSchema.optional(),
|
|
240
241
|
memberIds: z.array(identifier).max(1000).optional()
|
|
241
242
|
}).strict();
|
|
243
|
+
const raceHierarchyScopeSchema = z.enum(["roots", "descendants"]).optional();
|
|
242
244
|
const chapterOutlineSchema = z.object({
|
|
243
245
|
goal: z.string().max(100_000).optional(),
|
|
244
246
|
conflict: z.string().max(100_000).optional(),
|
|
@@ -355,6 +357,8 @@ const workAiSettingsSchema = z.object({
|
|
|
355
357
|
autoRunEnabled: z.boolean().optional(),
|
|
356
358
|
autoRunConcurrency: z.number().int().min(1).max(8).optional(),
|
|
357
359
|
autoRunBatchLimit: z.number().int().min(1).max(200).optional(),
|
|
360
|
+
autoRunDailyTaskLimit: z.number().int().min(0).max(10_000).optional(),
|
|
361
|
+
autoRunFailureThreshold: z.number().int().min(1).max(10).optional(),
|
|
358
362
|
bookSummaryContextPercent: z.number().int().min(1).max(90).optional(),
|
|
359
363
|
contextCompactThreshold: z.number().int().min(50).max(90).optional(),
|
|
360
364
|
agentTools: z.array(z.enum(["story_index", "read_chapters", "grep", "search_story_entities", "read_character_sections"])).max(5).optional()
|
|
@@ -626,11 +630,7 @@ export function createRuntime(options) {
|
|
|
626
630
|
};
|
|
627
631
|
const captcha = new ImageCaptchaService({ revealAnswer: options.revealCaptchaAnswer === true });
|
|
628
632
|
const ai = new AiManager(store, new CredentialVault(options.masterSecret), options.fetchImpl ?? fetch, options.security ? (url) => assertSafeAiEndpoint(url, options.security?.allowPrivateAiEndpoints) : undefined, (task, actor) => {
|
|
629
|
-
|
|
630
|
-
return;
|
|
631
|
-
const requiredModules = relationshipAnalysisReadModules(task.scope);
|
|
632
|
-
if (requiredModules.length === 0)
|
|
633
|
-
return;
|
|
633
|
+
const requiredModules = analysisTaskReadModules(task.taskType, task.scope);
|
|
634
634
|
const creator = actor ? null : database.get("SELECT created_by_user_id FROM analysis_tasks WHERE id = ?", String(task.id));
|
|
635
635
|
const userId = actor?.userId ?? (typeof creator?.created_by_user_id === "string" ? creator.created_by_user_id : null);
|
|
636
636
|
if (!userId)
|
|
@@ -1013,6 +1013,11 @@ export function createRuntime(options) {
|
|
|
1013
1013
|
store.deleteChapter(request.params.chapterId, input.expectedVersionNo);
|
|
1014
1014
|
noContent(response);
|
|
1015
1015
|
});
|
|
1016
|
+
app.delete("/api/chapters/:chapterId/permanent", (request, response) => {
|
|
1017
|
+
const input = parse(z.object({ expectedVersionNo: expectedVersionNoSchema }).strict(), request.body ?? {});
|
|
1018
|
+
store.permanentlyDeleteChapter(request.params.chapterId, input.expectedVersionNo);
|
|
1019
|
+
noContent(response);
|
|
1020
|
+
});
|
|
1016
1021
|
app.get("/api/chapters/:chapterId/versions", (request, response) => {
|
|
1017
1022
|
const pagination = parsePagination(request.query);
|
|
1018
1023
|
data(response, pagination ? store.listChapterVersionsPage(request.params.chapterId, pagination) : store.listChapterVersions(request.params.chapterId));
|
|
@@ -1275,9 +1280,19 @@ export function createRuntime(options) {
|
|
|
1275
1280
|
noContent(response);
|
|
1276
1281
|
});
|
|
1277
1282
|
app.get("/api/works/:workId/races", (request, response) => {
|
|
1283
|
+
const hierarchyScope = parse(raceHierarchyScopeSchema, request.query.scope);
|
|
1278
1284
|
const pagination = parsePagination(request.query);
|
|
1285
|
+
if (hierarchyScope && pagination) {
|
|
1286
|
+
throw new AppError(400, "RACE_HIERARCHY_PAGINATION_CONFLICT", "分层种族请求不能同时使用分页参数");
|
|
1287
|
+
}
|
|
1279
1288
|
const includeMarkdown = request.query.includeContent === "true";
|
|
1280
|
-
const races =
|
|
1289
|
+
const races = hierarchyScope
|
|
1290
|
+
? hierarchyScope === "roots"
|
|
1291
|
+
? { items: store.listRacesByHierarchyScope(request.params.workId, hierarchyScope, includeMarkdown), total: store.countRaces(request.params.workId) }
|
|
1292
|
+
: store.listRacesByHierarchyScope(request.params.workId, hierarchyScope, includeMarkdown)
|
|
1293
|
+
: pagination
|
|
1294
|
+
? store.listRacesPage(request.params.workId, pagination, includeMarkdown)
|
|
1295
|
+
: store.listRaces(request.params.workId, includeMarkdown);
|
|
1281
1296
|
const permissions = requestPermissions(request, request.params.workId);
|
|
1282
1297
|
data(response, mapRecords(races, (race) => redactRaceMembers(race, permissions)));
|
|
1283
1298
|
});
|
|
@@ -1453,6 +1468,7 @@ export function createRuntime(options) {
|
|
|
1453
1468
|
data(response, pagination ? store.listReviewItemsPage(request.params.workId, pagination, status) : store.listReviewItems(request.params.workId, status));
|
|
1454
1469
|
});
|
|
1455
1470
|
app.post("/api/works/:workId/reviews", (request, response) => data(response, store.createReviewItem(request.params.workId, parse(reviewSchema, request.body)), 201));
|
|
1471
|
+
app.get("/api/reviews/:reviewId", (request, response) => data(response, store.getReviewItem(request.params.reviewId)));
|
|
1456
1472
|
app.patch("/api/reviews/:reviewId", (request, response) => data(response, store.updateReviewItem(request.params.reviewId, parse(reviewSchema.partial(), request.body))));
|
|
1457
1473
|
app.post("/api/reviews/:reviewId/character-resolution", (request, response) => {
|
|
1458
1474
|
const input = parse(z.discriminatedUnion("action", [
|
|
@@ -1497,17 +1513,15 @@ export function createRuntime(options) {
|
|
|
1497
1513
|
const permissions = requestPermissions(request, request.params.workId);
|
|
1498
1514
|
for (const taskId of store.listOldestPendingTaskIds(request.params.workId, store.countPendingTasks(request.params.workId))) {
|
|
1499
1515
|
const task = store.getTask(taskId);
|
|
1500
|
-
|
|
1501
|
-
continue;
|
|
1502
|
-
const deniedModules = relationshipAnalysisReadModules(task.scope).filter((module) => permissions[module] === "none");
|
|
1516
|
+
const deniedModules = analysisTaskReadModules(task.taskType, task.scope).filter((module) => permissions[module] === "none");
|
|
1503
1517
|
if (deniedModules.length > 0) {
|
|
1504
|
-
throw new AppError(403, "WORK_MODULE_READ_DENIED", "
|
|
1518
|
+
throw new AppError(403, "WORK_MODULE_READ_DENIED", "你没有读取待运行分析任务所需资料模块的权限", {
|
|
1505
1519
|
taskId,
|
|
1506
1520
|
modules: deniedModules
|
|
1507
1521
|
});
|
|
1508
1522
|
}
|
|
1509
1523
|
}
|
|
1510
|
-
data(response, ai.
|
|
1524
|
+
data(response, ai.resumeAutoRun(request.params.workId));
|
|
1511
1525
|
});
|
|
1512
1526
|
app.get("/api/tasks/:taskId/detail", (request, response) => data(response, redactTaskCharacterNames(store.getTaskDetail(request.params.taskId), requestPermissions(request))));
|
|
1513
1527
|
app.get("/api/tasks/:taskId/result", (request, response) => {
|
|
@@ -1526,14 +1540,12 @@ export function createRuntime(options) {
|
|
|
1526
1540
|
app.post("/api/tasks/:taskId/run", async (request, response) => {
|
|
1527
1541
|
const input = parse(z.object({ modelId: identifier.optional() }), request.body ?? {});
|
|
1528
1542
|
const task = store.getTask(request.params.taskId);
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
});
|
|
1536
|
-
}
|
|
1543
|
+
const permissions = requestPermissions(request, String(task.workId));
|
|
1544
|
+
const deniedModules = analysisTaskReadModules(task.taskType, task.scope).filter((module) => permissions[module] === "none");
|
|
1545
|
+
if (deniedModules.length > 0) {
|
|
1546
|
+
throw new AppError(403, "WORK_MODULE_READ_DENIED", "你没有读取本次分析所需资料模块的权限", {
|
|
1547
|
+
modules: deniedModules
|
|
1548
|
+
});
|
|
1537
1549
|
}
|
|
1538
1550
|
data(response, redactTaskCharacterNames(await ai.runTask(request.params.taskId, input.modelId, request.authUser ? {
|
|
1539
1551
|
userId: request.authUser.userId,
|
|
@@ -1543,14 +1555,12 @@ export function createRuntime(options) {
|
|
|
1543
1555
|
app.post("/api/tasks/:taskId/rerun", (request, response) => {
|
|
1544
1556
|
parse(z.object({}).strict(), request.body ?? {});
|
|
1545
1557
|
const task = store.getTask(request.params.taskId);
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
});
|
|
1553
|
-
}
|
|
1558
|
+
const permissions = requestPermissions(request, String(task.workId));
|
|
1559
|
+
const deniedModules = analysisTaskReadModules(task.taskType, task.scope).filter((module) => permissions[module] === "none");
|
|
1560
|
+
if (deniedModules.length > 0) {
|
|
1561
|
+
throw new AppError(403, "WORK_MODULE_READ_DENIED", "你没有读取本次分析所需资料模块的权限", {
|
|
1562
|
+
modules: deniedModules
|
|
1563
|
+
});
|
|
1554
1564
|
}
|
|
1555
1565
|
data(response, redactTaskCharacterNames(ai.rerunTask(request.params.taskId), requestPermissions(request)), 201);
|
|
1556
1566
|
});
|
|
@@ -1610,12 +1620,14 @@ export function createRuntime(options) {
|
|
|
1610
1620
|
});
|
|
1611
1621
|
app.patch("/api/works/:workId/ai-settings", (request, response) => {
|
|
1612
1622
|
const workId = request.params.workId;
|
|
1623
|
+
const input = parse(workAiSettingsSchema, request.body);
|
|
1613
1624
|
const before = store.getWorkAiSettings(workId);
|
|
1614
|
-
|
|
1625
|
+
let updated = store.updateWorkAiSettings(workId, input);
|
|
1615
1626
|
if (updated.autoRunEnabled) {
|
|
1616
|
-
if (!before.autoRunEnabled)
|
|
1617
|
-
ai.
|
|
1618
|
-
|
|
1627
|
+
if (input.autoRunEnabled === true && !before.autoRunEnabled)
|
|
1628
|
+
updated = ai.resumeAutoRun(workId);
|
|
1629
|
+
else
|
|
1630
|
+
ai.scheduleAutoRun(workId);
|
|
1619
1631
|
}
|
|
1620
1632
|
data(response, updated);
|
|
1621
1633
|
});
|
|
@@ -1853,9 +1865,13 @@ export function createRuntime(options) {
|
|
|
1853
1865
|
const pagination = parsePagination(request.query);
|
|
1854
1866
|
data(response, pagination ? ai.listCallsPage(request.params.workId, pagination) : ai.listCalls(request.params.workId));
|
|
1855
1867
|
});
|
|
1856
|
-
app.get("/api/works/:workId/search", (request, response) => {
|
|
1857
|
-
const query = parse(z.
|
|
1858
|
-
|
|
1868
|
+
app.get("/api/works/:workId/search", async (request, response) => {
|
|
1869
|
+
const query = parse(z.object({
|
|
1870
|
+
q: z.string().trim().min(1).max(500),
|
|
1871
|
+
type: z.enum(HYBRID_SEARCH_TYPES).optional(),
|
|
1872
|
+
limit: z.coerce.number().int().min(1).max(100).optional()
|
|
1873
|
+
}).strict(), request.query);
|
|
1874
|
+
data(response, await ai.searchWork(request.params.workId, query.q, { type: query.type, limit: query.limit }));
|
|
1859
1875
|
});
|
|
1860
1876
|
app.get("/api/works/:workId/export", async (request, response) => {
|
|
1861
1877
|
const format = parse(z.enum(["json", "txt", "markdown"]), request.query.format ?? "json");
|