@musnows/scriverse 0.5.1 → 0.5.2

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/app.js CHANGED
@@ -358,7 +358,7 @@ const contextSchema = z.object({
358
358
  });
359
359
  const analysisTaskTypeSchema = z.enum(["structure", "chapter-analysis", "character-extraction", "character-summary", "character-identity-audit", "timeline-analysis", "worldview-analysis", "setting-extraction", "consistency-check", "report-update", "book-analysis"]);
360
360
  const relationshipAnalysisScopeSchema = z.object({
361
- type: z.enum(["chapter", "book"]),
361
+ type: z.enum(["chapter", "book", "settings"]),
362
362
  chapterId: identifier.optional(),
363
363
  includeAllSettings: z.boolean().optional(),
364
364
  additionalPrompt: z.string().trim().max(10_000).optional(),
@@ -434,16 +434,84 @@ function redactRaceMembers(record, permissions) {
434
434
  function redactOrganizationMembers(record, permissions) {
435
435
  return permissions.characters === "none" ? { ...record, memberIds: [], members: [] } : record;
436
436
  }
437
+ const taskResultPermissionModules = {
438
+ "chapter-analysis": "prose",
439
+ "character-extraction": "characters",
440
+ "character-summary": "characters",
441
+ "character-identity-audit": "reviews",
442
+ "timeline-analysis": "timeline",
443
+ "relationship-analysis": "relationships",
444
+ "worldview-analysis": "settings",
445
+ "setting-extraction": "settings",
446
+ "consistency-check": "reviews",
447
+ "book-analysis": "prose",
448
+ structure: "outlines",
449
+ "report-update": "prose"
450
+ };
451
+ function requiredTaskResultModule(taskType) {
452
+ return taskResultPermissionModules[String(taskType)];
453
+ }
437
454
  function redactTaskCharacterNames(record, permissions) {
438
455
  const { scopeSummaryWithoutCharacterNames, ...result } = record;
439
- if (permissions.characters !== "none")
440
- return result;
441
- if (typeof scopeSummaryWithoutCharacterNames === "string")
442
- result.scopeSummary = scopeSummaryWithoutCharacterNames;
443
- const scope = recordValue(result.scope);
444
- if (scope) {
445
- const { targetCharacters: _targetCharacters, ...redactedScope } = scope;
446
- result.scope = redactedScope;
456
+ const proseRestricted = permissions.prose === "none";
457
+ const proseScope = recordValue(result.scope);
458
+ const selectionScopeRestricted = proseRestricted
459
+ && (proseScope?.type === "selection" || String(result.scopeSummary ?? "").startsWith("选定内容:"));
460
+ if (selectionScopeRestricted) {
461
+ if (proseScope) {
462
+ const { selection: _selection, ...redactedScope } = proseScope;
463
+ result.scope = redactedScope;
464
+ }
465
+ result.scopeSummary = "选定内容(正文读取权限受限)";
466
+ if (Array.isArray(result.scopeDetails)) {
467
+ result.scopeDetails = result.scopeDetails.map((item) => {
468
+ const detail = recordValue(item);
469
+ return detail?.type === "selection" ? { type: "selection", restricted: true } : item;
470
+ });
471
+ }
472
+ }
473
+ const characterRestricted = permissions.characters === "none";
474
+ if (characterRestricted) {
475
+ if (!selectionScopeRestricted && typeof scopeSummaryWithoutCharacterNames === "string")
476
+ result.scopeSummary = scopeSummaryWithoutCharacterNames;
477
+ const scope = recordValue(result.scope);
478
+ if (scope) {
479
+ const { targetCharacters: _targetCharacters, ...redactedScope } = scope;
480
+ result.scope = redactedScope;
481
+ }
482
+ const taskResult = recordValue(result.result);
483
+ if (taskResult) {
484
+ const redactedTaskResult = { ...taskResult };
485
+ if (Array.isArray(taskResult.relationshipResults)) {
486
+ redactedTaskResult.relationshipResults = taskResult.relationshipResults.map((value) => {
487
+ const relationship = recordValue(value);
488
+ if (!relationship)
489
+ return value;
490
+ const { fromCharacterName: _fromCharacterName, toCharacterName: _toCharacterName, ...redactedRelationship } = relationship;
491
+ return redactedRelationship;
492
+ });
493
+ }
494
+ const analysisTarget = recordValue(taskResult.analysisTarget);
495
+ if (analysisTarget) {
496
+ const { characterNames: _characterNames, ...redactedAnalysisTarget } = analysisTarget;
497
+ redactedTaskResult.analysisTarget = redactedAnalysisTarget;
498
+ }
499
+ result.result = redactedTaskResult;
500
+ }
501
+ }
502
+ const resultSummary = recordValue(result.resultSummary);
503
+ const characterSensitiveTask = ["character-extraction", "character-summary", "character-identity-audit", "relationship-analysis"]
504
+ .includes(String(result.taskType));
505
+ const requiredResultModule = requiredTaskResultModule(result.taskType);
506
+ const resultRestricted = requiredResultModule !== undefined && permissions[requiredResultModule] === "none";
507
+ if (resultSummary && (resultRestricted || (characterRestricted && characterSensitiveTask))) {
508
+ result.resultSummary = {
509
+ ...resultSummary,
510
+ analysisContent: `${String(resultSummary.title ?? "AI 分析")};范围:${String(result.scopeSummary ?? "未指定")}`,
511
+ summary: "当前账号缺少相关资料的读取权限,无法展示对应的可读结论。",
512
+ sections: [],
513
+ restricted: true
514
+ };
447
515
  }
448
516
  return result;
449
517
  }
@@ -1354,12 +1422,20 @@ export function createRuntime(options) {
1354
1422
  app.post("/api/works/:workId/tasks/auto-run", (request, response) => {
1355
1423
  data(response, ai.startAutoRunBatch(request.params.workId));
1356
1424
  });
1425
+ app.get("/api/tasks/:taskId/detail", (request, response) => data(response, redactTaskCharacterNames(store.getTaskDetail(request.params.taskId), requestPermissions(request))));
1426
+ app.get("/api/tasks/:taskId/result", (request, response) => {
1427
+ const task = store.getTaskResultPayload(request.params.taskId);
1428
+ const permissions = requestPermissions(request);
1429
+ const requiredModule = requiredTaskResultModule(task.taskType);
1430
+ if (requiredModule && permissions[requiredModule] === "none") {
1431
+ throw new AppError(403, "WORK_MODULE_READ_DENIED", "你没有读取该分析结果对应资料模块的权限");
1432
+ }
1433
+ const redacted = redactTaskCharacterNames(task, permissions);
1434
+ data(response, { taskId: task.id, result: redacted.result });
1435
+ });
1357
1436
  app.get("/api/tasks/:taskId", (request, response) => data(response, redactTaskCharacterNames(store.getTask(request.params.taskId), requestPermissions(request))));
1358
1437
  app.get("/api/tasks/:taskId/trace", (request, response) => data(response, ai.getTaskTrace(request.params.taskId)));
1359
- app.get("/api/tasks/:taskId/trace/calls/:callId", (request, response) => {
1360
- const full = parse(z.enum(["true", "false"]).default("false"), request.query.full ?? "false") === "true";
1361
- data(response, ai.getTaskTraceCall(request.params.taskId, request.params.callId, full));
1362
- });
1438
+ app.get("/api/tasks/:taskId/trace/calls/:callId", (request, response) => data(response, ai.getTaskTraceCall(request.params.taskId, request.params.callId)));
1363
1439
  app.post("/api/tasks/:taskId/run", async (request, response) => {
1364
1440
  const input = parse(z.object({ modelId: identifier.optional() }), request.body ?? {});
1365
1441
  data(response, redactTaskCharacterNames(await ai.runTask(request.params.taskId, input.modelId), requestPermissions(request)));