@waterwx/dsh-novel-forge 1.1.4 → 1.1.5

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/lib/client.js CHANGED
@@ -65,8 +65,12 @@ window.__ModuleLoader__.load({
65
65
  cover: "/api/dsh-novel-forge/blurb/cover",
66
66
  /** 剧情线管理:增删改 + 关联章节。 */
67
67
  plotlines: "/api/dsh-novel-forge/plotlines",
68
+ /** 角色库:AI 提炼 / 采纳 / 更新 / 删除。 */
69
+ roles: "/api/dsh-novel-forge/roles",
68
70
  /** 作者复盘补跑:对已写章节补齐 authorReview(全书流式 / 单章 JSON)。 */
69
71
  reviewBackfill: "/api/dsh-novel-forge/review/backfill",
72
+ /** 章节复位:generating 卡死 → pending(可重新生成)。 */
73
+ chapterReset: "/api/dsh-novel-forge/chapter/reset",
70
74
  /** 敏感词检查:全书已写章节或指定文本。 */
71
75
  sensitiveCheck: "/api/dsh-novel-forge/sensitive-check",
72
76
  config: "/api/dsh-novel-forge/config",
@@ -220,6 +224,14 @@ window.__ModuleLoader__.load({
220
224
  async reviewBackfillAll(onFrame) {
221
225
  await this.streamJob(NOVEL_API.reviewBackfill, {}, onFrame);
222
226
  }
227
+ /** 章节复位:generating 卡死 → pending。 */
228
+ async chapterReset(no) {
229
+ return postJson(NOVEL_API.chapterReset, { chapterNo: no });
230
+ }
231
+ /** 角色库:AI 提炼 / 采纳 / 更新 / 删除。 */
232
+ async roles(req) {
233
+ return postJson(NOVEL_API.roles, req);
234
+ }
223
235
  /** 小说简介:AI 生成/补全(partial 留空 = 全量),或手动保存。 */
224
236
  async blurb(action, text, partial) {
225
237
  return postJson(NOVEL_API.blurb, {
@@ -765,205 +777,205 @@ window.__ModuleLoader__.load({
765
777
  document.head.appendChild(tag);
766
778
  }
767
779
  var panel_module_css_default = {
768
- "bookCreateOutline": "CUIYUW_bookCreateOutline",
769
- "progressBar": "CUIYUW_progressBar",
770
- "navAboutUpdate": "CUIYUW_navAboutUpdate",
771
- "progressLineDone": "CUIYUW_progressLineDone",
772
- "cardTitle": "CUIYUW_cardTitle",
773
- "buttonPrimary": "CUIYUW_buttonPrimary",
774
- "dashJourney": "CUIYUW_dashJourney",
775
- "volumeGroup": "CUIYUW_volumeGroup",
776
- "chatScroll": "CUIYUW_chatScroll",
780
+ "headerProgress": "CUIYUW_headerProgress",
781
+ "assetGrid": "CUIYUW_assetGrid",
782
+ "textarea": "CUIYUW_textarea",
783
+ "entryIcon": "CUIYUW_entryIcon",
784
+ "assistantStatus": "CUIYUW_assistantStatus",
785
+ "assistantResize": "CUIYUW_assistantResize",
786
+ "navTabIcon": "CUIYUW_navTabIcon",
787
+ "workflowHint": "CUIYUW_workflowHint",
788
+ "chapter": "CUIYUW_chapter",
789
+ "bookCardBody": "CUIYUW_bookCardBody",
790
+ "navGroupLabel": "CUIYUW_navGroupLabel",
791
+ "bookshelf": "CUIYUW_bookshelf",
792
+ "navAbout": "CUIYUW_navAbout",
793
+ "dashHeroSparkle": "CUIYUW_dashHeroSparkle",
794
+ "dashJourneyStages": "CUIYUW_dashJourneyStages",
795
+ "panelNavCollapsed": "CUIYUW_panelNavCollapsed",
796
+ "fieldLabel": "CUIYUW_fieldLabel",
797
+ "dashHeroActionBody": "CUIYUW_dashHeroActionBody",
798
+ "todoItem": "CUIYUW_todoItem",
799
+ "toolLive": "CUIYUW_toolLive",
800
+ "assistantFloatHeader": "CUIYUW_assistantFloatHeader",
801
+ "createBookView": "CUIYUW_createBookView",
802
+ "row": "CUIYUW_row",
803
+ "wsColumns": "CUIYUW_wsColumns",
804
+ "workflowRow": "CUIYUW_workflowRow",
805
+ "fadeIn": "CUIYUW_fadeIn",
806
+ "bookChipMeta": "CUIYUW_bookChipMeta",
807
+ "assetStatValue": "CUIYUW_assetStatValue",
808
+ "progressLineError": "CUIYUW_progressLineError",
809
+ "bookChipName": "CUIYUW_bookChipName",
777
810
  "toolSteps": "CUIYUW_toolSteps",
778
- "createBookTitle": "CUIYUW_createBookTitle",
779
- "coverPreview": "CUIYUW_coverPreview",
780
- "dashStage": "CUIYUW_dashStage",
781
- "legendNew": "CUIYUW_legendNew",
782
- "dashJourneyBar": "CUIYUW_dashJourneyBar",
783
- "outlineReadonly": "CUIYUW_outlineReadonly",
811
+ "dashHeroEyebrow": "CUIYUW_dashHeroEyebrow",
812
+ "todoText": "CUIYUW_todoText",
813
+ "createBookIcon": "CUIYUW_createBookIcon",
814
+ "dropzoneActive": "CUIYUW_dropzoneActive",
815
+ "iconButton": "CUIYUW_iconButton",
816
+ "fileList": "CUIYUW_fileList",
817
+ "badge": "CUIYUW_badge",
818
+ "chatScroll": "CUIYUW_chatScroll",
819
+ "workflowList": "CUIYUW_workflowList",
820
+ "wsPage": "CUIYUW_wsPage",
821
+ "assetStatDetail": "CUIYUW_assetStatDetail",
822
+ "diffAdd": "CUIYUW_diffAdd",
823
+ "dashStageDot": "CUIYUW_dashStageDot",
784
824
  "chatRole": "CUIYUW_chatRole",
785
- "diffTagOld": "CUIYUW_diffTagOld",
825
+ "todoDanger": "CUIYUW_todoDanger",
826
+ "navTabBadgeDanger": "CUIYUW_navTabBadgeDanger",
827
+ "bookCreateOutline": "CUIYUW_bookCreateOutline",
828
+ "dashHeroAction": "CUIYUW_dashHeroAction",
829
+ "diffOld": "CUIYUW_diffOld",
786
830
  "badgeError": "CUIYUW_badgeError",
787
- "dashStageCurrent": "CUIYUW_dashStageCurrent",
788
- "toolStep": "CUIYUW_toolStep",
789
- "navGroupSep": "CUIYUW_navGroupSep",
790
- "navGroupLabel": "CUIYUW_navGroupLabel",
791
- "diffAdd": "CUIYUW_diffAdd",
831
+ "progress": "CUIYUW_progress",
832
+ "dashJourneyBar": "CUIYUW_dashJourneyBar",
792
833
  "wsSelected": "CUIYUW_wsSelected",
793
- "todoInfo": "CUIYUW_todoInfo",
794
- "panelSubtitle": "CUIYUW_panelSubtitle",
795
- "meta": "CUIYUW_meta",
796
- "genreDesc": "CUIYUW_genreDesc",
797
- "chapterTitle": "CUIYUW_chapterTitle",
798
- "diffText": "CUIYUW_diffText",
799
- "fieldLabel": "CUIYUW_fieldLabel",
800
- "dashFact": "CUIYUW_dashFact",
834
+ "badgeDone": "CUIYUW_badgeDone",
835
+ "headerProgressDot": "CUIYUW_headerProgressDot",
836
+ "reviewBox": "CUIYUW_reviewBox",
837
+ "toolStepActive": "CUIYUW_toolStepActive",
838
+ "button": "CUIYUW_button",
839
+ "volumeGroup": "CUIYUW_volumeGroup",
840
+ "assetStatLabel": "CUIYUW_assetStatLabel",
801
841
  "bookCreateCard": "CUIYUW_bookCreateCard",
802
- "spaceBetween": "CUIYUW_spaceBetween",
803
- "assistantStatusBusy": "CUIYUW_assistantStatusBusy",
804
- "bookCardCoverTitle": "CUIYUW_bookCardCoverTitle",
805
- "bookshelfLabel": "CUIYUW_bookshelfLabel",
842
+ "createBookTop": "CUIYUW_createBookTop",
843
+ "dashStageDone": "CUIYUW_dashStageDone",
844
+ "genreDesc": "CUIYUW_genreDesc",
806
845
  "dashJourneyFill": "CUIYUW_dashJourneyFill",
807
- "chapterList": "CUIYUW_chapterList",
808
- "chapterMain": "CUIYUW_chapterMain",
809
- "busyRow": "CUIYUW_busyRow",
846
+ "wsPreview": "CUIYUW_wsPreview",
847
+ "onlyChanges": "CUIYUW_onlyChanges",
848
+ "toolStepError": "CUIYUW_toolStepError",
849
+ "wsPageHeader": "CUIYUW_wsPageHeader",
850
+ "view": "CUIYUW_view",
851
+ "todoWarning": "CUIYUW_todoWarning",
810
852
  "diffTagNew": "CUIYUW_diffTagNew",
811
- "bookCardName": "CUIYUW_bookCardName",
812
- "button": "CUIYUW_button",
813
- "dashStageDone": "CUIYUW_dashStageDone",
814
- "navTabIcon": "CUIYUW_navTabIcon",
815
- "bookChipName": "CUIYUW_bookChipName",
816
- "badge": "CUIYUW_badge",
817
- "navTabBadgeWarn": "CUIYUW_navTabBadgeWarn",
853
+ "dashFacts": "CUIYUW_dashFacts",
854
+ "input": "CUIYUW_input",
818
855
  "tab": "CUIYUW_tab",
819
- "navTabLabel": "CUIYUW_navTabLabel",
820
- "bigProgressBarFill": "CUIYUW_bigProgressBarFill",
821
- "wsPageHeader": "CUIYUW_wsPageHeader",
822
- "navTabBadge": "CUIYUW_navTabBadge",
856
+ "pulse": "CUIYUW_pulse",
857
+ "progressLineLive": "CUIYUW_progressLineLive",
858
+ "assistantFloat": "CUIYUW_assistantFloat",
859
+ "bookCardTitleRow": "CUIYUW_bookCardTitleRow",
823
860
  "dashHeroBook": "CUIYUW_dashHeroBook",
824
- "toolStepName": "CUIYUW_toolStepName",
825
- "todoItem": "CUIYUW_todoItem",
826
- "coverPlaceholder": "CUIYUW_coverPlaceholder",
827
- "createBookTop": "CUIYUW_createBookTop",
828
- "navTabBadgeDanger": "CUIYUW_navTabBadgeDanger",
829
- "dashHeroEyebrow": "CUIYUW_dashHeroEyebrow",
830
- "toolStepStatus": "CUIYUW_toolStepStatus",
831
- "navAboutRow": "CUIYUW_navAboutRow",
832
- "navTab": "CUIYUW_navTab",
833
- "dashGrid": "CUIYUW_dashGrid",
834
- "assistantFloatHeader": "CUIYUW_assistantFloatHeader",
835
- "chapterBeats": "CUIYUW_chapterBeats",
836
- "workflowDotActive": "CUIYUW_workflowDotActive",
837
- "iconButton": "CUIYUW_iconButton",
838
- "assistantStatus": "CUIYUW_assistantStatus",
839
- "workflowHint": "CUIYUW_workflowHint",
840
- "bookChipActive": "CUIYUW_bookChipActive",
841
- "entry": "CUIYUW_entry",
842
- "badgeDone": "CUIYUW_badgeDone",
843
- "diffSameBody": "CUIYUW_diffSameBody",
861
+ "bookCardProgressBar": "CUIYUW_bookCardProgressBar",
862
+ "diffLegend": "CUIYUW_diffLegend",
863
+ "buttonDanger": "CUIYUW_buttonDanger",
864
+ "bookCardProgressFill": "CUIYUW_bookCardProgressFill",
865
+ "bigProgressBar": "CUIYUW_bigProgressBar",
866
+ "shelfHeader": "CUIYUW_shelfHeader",
867
+ "workflowDotDone": "CUIYUW_workflowDotDone",
868
+ "bigProgressBarFill": "CUIYUW_bigProgressBarFill",
869
+ "bookCreateForm": "CUIYUW_bookCreateForm",
870
+ "diffList": "CUIYUW_diffList",
871
+ "chapterMain": "CUIYUW_chapterMain",
872
+ "badgeRejected": "CUIYUW_badgeRejected",
873
+ "legendNew": "CUIYUW_legendNew",
874
+ "diffText": "CUIYUW_diffText",
875
+ "diffTagOld": "CUIYUW_diffTagOld",
876
+ "panelBody": "CUIYUW_panelBody",
844
877
  "shelfView": "CUIYUW_shelfView",
845
- "workflowBody": "CUIYUW_workflowBody",
878
+ "bookCard": "CUIYUW_bookCard",
879
+ "panelSubtitle": "CUIYUW_panelSubtitle",
880
+ "dashStageCurrent": "CUIYUW_dashStageCurrent",
881
+ "panelContent": "CUIYUW_panelContent",
846
882
  "buttonSmall": "CUIYUW_buttonSmall",
847
- "assetStat": "CUIYUW_assetStat",
848
- "field": "CUIYUW_field",
849
- "chapterNum": "CUIYUW_chapterNum",
850
- "bookCardCover": "CUIYUW_bookCardCover",
851
- "progressLine": "CUIYUW_progressLine",
852
- "chapterActions": "CUIYUW_chapterActions",
853
- "progressBarFill": "CUIYUW_progressBarFill",
854
- "bookshelf": "CUIYUW_bookshelf",
855
- "assetGrid": "CUIYUW_assetGrid",
856
- "navAbout": "CUIYUW_navAbout",
857
- "badgeRejected": "CUIYUW_badgeRejected",
858
- "assetStatValue": "CUIYUW_assetStatValue",
859
- "bookCardBody": "CUIYUW_bookCardBody",
860
- "bookChip": "CUIYUW_bookChip",
861
- "bookCardProgressBar": "CUIYUW_bookCardProgressBar",
862
- "badgePending": "CUIYUW_badgePending",
863
- "dashHeroActionBody": "CUIYUW_dashHeroActionBody",
864
- "assistantFloat": "CUIYUW_assistantFloat",
865
- "shelfGrid": "CUIYUW_shelfGrid",
883
+ "badgeGenerating": "CUIYUW_badgeGenerating",
884
+ "wsPreviewText": "CUIYUW_wsPreviewText",
885
+ "dashGrid": "CUIYUW_dashGrid",
866
886
  "entryLabel": "CUIYUW_entryLabel",
867
- "bookCardCoverFallback": "CUIYUW_bookCardCoverFallback",
868
- "textarea": "CUIYUW_textarea",
869
- "diffOld": "CUIYUW_diffOld",
870
- "headerProgress": "CUIYUW_headerProgress",
871
887
  "assistantFloatBody": "CUIYUW_assistantFloatBody",
872
- "todoDanger": "CUIYUW_todoDanger",
873
- "chatBubbleAssistant": "CUIYUW_chatBubbleAssistant",
874
- "wsColumn": "CUIYUW_wsColumn",
875
- "wsEditor": "CUIYUW_wsEditor",
876
- "diffList": "CUIYUW_diffList",
877
- "liveText": "CUIYUW_liveText",
878
- "progressLineLive": "CUIYUW_progressLineLive",
879
- "wsPreview": "CUIYUW_wsPreview",
880
- "assetStatLabel": "CUIYUW_assetStatLabel",
881
- "diffNew": "CUIYUW_diffNew",
882
- "dashHeroSparkle": "CUIYUW_dashHeroSparkle",
883
- "bookCardProgressFill": "CUIYUW_bookCardProgressFill",
888
+ "chapterPreview": "CUIYUW_chapterPreview",
889
+ "navGroup": "CUIYUW_navGroup",
890
+ "createBookTitle": "CUIYUW_createBookTitle",
891
+ "bookChip": "CUIYUW_bookChip",
892
+ "panelHeader": "CUIYUW_panelHeader",
893
+ "progressBar": "CUIYUW_progressBar",
894
+ "toolStep": "CUIYUW_toolStep",
895
+ "buttonPrimary": "CUIYUW_buttonPrimary",
896
+ "busyRow": "CUIYUW_busyRow",
897
+ "bookCardActive": "CUIYUW_bookCardActive",
898
+ "tabBar": "CUIYUW_tabBar",
899
+ "field": "CUIYUW_field",
900
+ "card": "CUIYUW_card",
901
+ "badgePending": "CUIYUW_badgePending",
902
+ "volumeGroupToggle": "CUIYUW_volumeGroupToggle",
903
+ "chapterActions": "CUIYUW_chapterActions",
904
+ "dashFact": "CUIYUW_dashFact",
905
+ "diffSame": "CUIYUW_diffSame",
884
906
  "bookAddIcon": "CUIYUW_bookAddIcon",
885
- "workflowList": "CUIYUW_workflowList",
907
+ "diffNew": "CUIYUW_diffNew",
908
+ "navTabBadgeWarn": "CUIYUW_navTabBadgeWarn",
909
+ "navTabLabel": "CUIYUW_navTabLabel",
910
+ "chapterList": "CUIYUW_chapterList",
911
+ "progressLine": "CUIYUW_progressLine",
912
+ "bookCardBlurb": "CUIYUW_bookCardBlurb",
913
+ "spaceBetween": "CUIYUW_spaceBetween",
914
+ "coverPlaceholder": "CUIYUW_coverPlaceholder",
915
+ "bookCardCover": "CUIYUW_bookCardCover",
916
+ "badgeWritten": "CUIYUW_badgeWritten",
917
+ "toolStepIcon": "CUIYUW_toolStepIcon",
918
+ "dropzoneIcon": "CUIYUW_dropzoneIcon",
919
+ "outlineReadonly": "CUIYUW_outlineReadonly",
920
+ "coverPreview": "CUIYUW_coverPreview",
886
921
  "chatBubbleUser": "CUIYUW_chatBubbleUser",
887
- "bigProgressBar": "CUIYUW_bigProgressBar",
922
+ "panel": "CUIYUW_panel",
923
+ "cardTitle": "CUIYUW_cardTitle",
924
+ "chatBubbleAssistant": "CUIYUW_chatBubbleAssistant",
925
+ "navTab": "CUIYUW_navTab",
926
+ "dashHeroArrow": "CUIYUW_dashHeroArrow",
888
927
  "dashHeroActionTitle": "CUIYUW_dashHeroActionTitle",
889
- "bookCardTitleRow": "CUIYUW_bookCardTitleRow",
928
+ "bookChipActive": "CUIYUW_bookChipActive",
929
+ "panelNav": "CUIYUW_panelNav",
890
930
  "diffDel": "CUIYUW_diffDel",
891
- "dashHeroArrow": "CUIYUW_dashHeroArrow",
892
- "progressLineError": "CUIYUW_progressLineError",
893
- "wsColumns": "CUIYUW_wsColumns",
894
- "fadeIn": "CUIYUW_fadeIn",
895
- "bookChipMeta": "CUIYUW_bookChipMeta",
896
- "toolLive": "CUIYUW_toolLive",
897
- "createBookView": "CUIYUW_createBookView",
898
- "bookAdd": "CUIYUW_bookAdd",
899
- "dropzoneIcon": "CUIYUW_dropzoneIcon",
900
- "shelfHeader": "CUIYUW_shelfHeader",
901
- "volumeGroupToggle": "CUIYUW_volumeGroupToggle",
902
- "badgeWritten": "CUIYUW_badgeWritten",
903
- "createBookIcon": "CUIYUW_createBookIcon",
904
- "assistantResize": "CUIYUW_assistantResize",
905
- "navGroup": "CUIYUW_navGroup",
906
- "panelTitle": "CUIYUW_panelTitle",
907
- "dashJourneyStages": "CUIYUW_dashJourneyStages",
908
- "chapter": "CUIYUW_chapter",
931
+ "bookCardCoverFallback": "CUIYUW_bookCardCoverFallback",
932
+ "dashHeroTitle": "CUIYUW_dashHeroTitle",
933
+ "workflowBody": "CUIYUW_workflowBody",
934
+ "bookChipRemove": "CUIYUW_bookChipRemove",
935
+ "wsSelectedText": "CUIYUW_wsSelectedText",
936
+ "navSpacer": "CUIYUW_navSpacer",
937
+ "navTabBadge": "CUIYUW_navTabBadge",
938
+ "navGroupSep": "CUIYUW_navGroupSep",
939
+ "progressBarFill": "CUIYUW_progressBarFill",
940
+ "toolStepStatus": "CUIYUW_toolStepStatus",
941
+ "diffSameBody": "CUIYUW_diffSameBody",
942
+ "volumeGroupHeader": "CUIYUW_volumeGroupHeader",
943
+ "legendOld": "CUIYUW_legendOld",
909
944
  "navTabBadgeDone": "CUIYUW_navTabBadgeDone",
910
945
  "dashHero": "CUIYUW_dashHero",
911
- "toolStepError": "CUIYUW_toolStepError",
946
+ "panelTitle": "CUIYUW_panelTitle",
947
+ "chapterTitle": "CUIYUW_chapterTitle",
948
+ "wsEditor": "CUIYUW_wsEditor",
949
+ "chapterBeats": "CUIYUW_chapterBeats",
950
+ "bookCardName": "CUIYUW_bookCardName",
951
+ "navAboutRow": "CUIYUW_navAboutRow",
912
952
  "bookshelfList": "CUIYUW_bookshelfList",
913
- "panelHeader": "CUIYUW_panelHeader",
914
- "badgeGenerating": "CUIYUW_badgeGenerating",
915
- "entryIcon": "CUIYUW_entryIcon",
916
- "assetStatDetail": "CUIYUW_assetStatDetail",
917
- "workflowRow": "CUIYUW_workflowRow",
953
+ "bookAdd": "CUIYUW_bookAdd",
954
+ "dropzone": "CUIYUW_dropzone",
955
+ "toolStepName": "CUIYUW_toolStepName",
956
+ "workflowLabel": "CUIYUW_workflowLabel",
957
+ "bookshelfLabel": "CUIYUW_bookshelfLabel",
958
+ "navAboutUpdate": "CUIYUW_navAboutUpdate",
959
+ "todoInfo": "CUIYUW_todoInfo",
960
+ "shelfGrid": "CUIYUW_shelfGrid",
961
+ "assistantStatusBusy": "CUIYUW_assistantStatusBusy",
962
+ "createBookCard": "CUIYUW_createBookCard",
963
+ "workflowDotActive": "CUIYUW_workflowDotActive",
964
+ "diffChange": "CUIYUW_diffChange",
965
+ "liveText": "CUIYUW_liveText",
966
+ "assetStat": "CUIYUW_assetStat",
967
+ "progressLineDone": "CUIYUW_progressLineDone",
968
+ "entry": "CUIYUW_entry",
918
969
  "workflowDot": "CUIYUW_workflowDot",
919
- "navSpacer": "CUIYUW_navSpacer",
920
- "fileList": "CUIYUW_fileList",
921
970
  "bookAddCard": "CUIYUW_bookAddCard",
922
- "todoWarning": "CUIYUW_todoWarning",
923
- "reviewBox": "CUIYUW_reviewBox",
924
- "panelNavCollapsed": "CUIYUW_panelNavCollapsed",
925
- "dashHeroTitle": "CUIYUW_dashHeroTitle",
926
- "bookCard": "CUIYUW_bookCard",
927
- "diffChange": "CUIYUW_diffChange",
928
- "wsPreviewText": "CUIYUW_wsPreviewText",
929
- "volumeGroupHeader": "CUIYUW_volumeGroupHeader",
971
+ "wsColumn": "CUIYUW_wsColumn",
972
+ "dashStage": "CUIYUW_dashStage",
973
+ "bookCardCoverTitle": "CUIYUW_bookCardCoverTitle",
974
+ "chapterNum": "CUIYUW_chapterNum",
975
+ "meta": "CUIYUW_meta",
930
976
  "toolStepDetail": "CUIYUW_toolStepDetail",
931
- "panelNav": "CUIYUW_panelNav",
932
- "panelBody": "CUIYUW_panelBody",
933
- "toolStepIcon": "CUIYUW_toolStepIcon",
934
- "legendOld": "CUIYUW_legendOld",
935
- "bookCardBlurb": "CUIYUW_bookCardBlurb",
936
- "todoText": "CUIYUW_todoText",
937
- "progress": "CUIYUW_progress",
938
- "diffColumn": "CUIYUW_diffColumn",
939
- "headerProgressDot": "CUIYUW_headerProgressDot",
940
- "pulse": "CUIYUW_pulse",
941
- "onlyChanges": "CUIYUW_onlyChanges",
942
- "diffLegend": "CUIYUW_diffLegend",
943
- "dashHeroAction": "CUIYUW_dashHeroAction",
944
- "row": "CUIYUW_row",
945
- "dashStageDot": "CUIYUW_dashStageDot",
946
- "card": "CUIYUW_card",
947
- "createBookCard": "CUIYUW_createBookCard",
948
- "workflowLabel": "CUIYUW_workflowLabel",
949
- "bookChipRemove": "CUIYUW_bookChipRemove",
950
- "dropzone": "CUIYUW_dropzone",
951
- "input": "CUIYUW_input",
952
- "workflowDotDone": "CUIYUW_workflowDotDone",
953
- "dropzoneActive": "CUIYUW_dropzoneActive",
954
- "panelContent": "CUIYUW_panelContent",
955
- "toolStepActive": "CUIYUW_toolStepActive",
956
- "wsPage": "CUIYUW_wsPage",
957
- "chapterPreview": "CUIYUW_chapterPreview",
958
- "tabBar": "CUIYUW_tabBar",
959
- "view": "CUIYUW_view",
960
- "dashFacts": "CUIYUW_dashFacts",
961
- "bookCardActive": "CUIYUW_bookCardActive",
962
- "bookCreateForm": "CUIYUW_bookCreateForm",
963
- "wsSelectedText": "CUIYUW_wsSelectedText",
964
- "buttonDanger": "CUIYUW_buttonDanger",
965
- "diffSame": "CUIYUW_diffSame",
966
- "panel": "CUIYUW_panel"
977
+ "dashJourney": "CUIYUW_dashJourney",
978
+ "diffColumn": "CUIYUW_diffColumn"
967
979
  };
968
980
  //#endregion
969
981
  //#region src/client/panel/AssistantTab.tsx
@@ -3446,10 +3458,15 @@ window.__ModuleLoader__.load({
3446
3458
  label: "大世界",
3447
3459
  icon: "🌍"
3448
3460
  },
3461
+ {
3462
+ id: "roles",
3463
+ label: "角色库",
3464
+ icon: "👥"
3465
+ },
3449
3466
  {
3450
3467
  id: "characters",
3451
3468
  label: "人物志",
3452
- icon: "👥"
3469
+ icon: "🧾"
3453
3470
  },
3454
3471
  {
3455
3472
  id: "foreshadow",
@@ -3500,7 +3517,7 @@ window.__ModuleLoader__.load({
3500
3517
  label: tt("tab.settings"),
3501
3518
  icon: "⚙️"
3502
3519
  };
3503
- const PLUGIN_VERSION = "1.1.4";
3520
+ const PLUGIN_VERSION = "1.1.5";
3504
3521
  /** GitHub 仓库地址(关于区块点击跳转)。 */
3505
3522
  const REPO_URL = "https://github.com/watersxya/dsh-novel-forge";
3506
3523
  /** Whether any chapter is being generated right now. */
@@ -3850,6 +3867,26 @@ window.__ModuleLoader__.load({
3850
3867
  const [plotlineDraft, setPlotlineDraft] = (0, react.useState)(null);
3851
3868
  /** 角色知情度编辑草稿(角色名 → 文本,每行一条)。 */
3852
3869
  const [knowledgeDraft, setKnowledgeDraft] = (0, react.useState)({});
3870
+ /** 角色库:AI 提炼候选(null = 未运行;localStorage 持久化,刷新不丢)。 */
3871
+ const [roleCandidates, setRoleCandidates] = (0, react.useState)(() => {
3872
+ try {
3873
+ const raw = window.localStorage.getItem("dsh-novel-forge.role.candidates");
3874
+ if (raw !== null) {
3875
+ const parsed = JSON.parse(raw);
3876
+ return Array.isArray(parsed) && parsed.length > 0 ? parsed : null;
3877
+ }
3878
+ } catch {}
3879
+ return null;
3880
+ });
3881
+ /** 角色库:编辑草稿(null = 不在编辑)。 */
3882
+ const [roleDraft, setRoleDraft] = (0, react.useState)(null);
3883
+ /** 角色库候选持久化:提炼/采纳后写回 localStorage。 */
3884
+ (0, react.useEffect)(() => {
3885
+ try {
3886
+ if (roleCandidates !== null && roleCandidates.length > 0) window.localStorage.setItem("dsh-novel-forge.role.candidates", JSON.stringify(roleCandidates));
3887
+ else window.localStorage.removeItem("dsh-novel-forge.role.candidates");
3888
+ } catch {}
3889
+ }, [roleCandidates]);
3853
3890
  /** 全书敏感词检查结果(null = 未运行)。 */
3854
3891
  const [sensHits, setSensHits] = (0, react.useState)(null);
3855
3892
  const [sensScanned, setSensScanned] = (0, react.useState)(0);
@@ -4056,6 +4093,8 @@ window.__ModuleLoader__.load({
4056
4093
  setConfig(status.config);
4057
4094
  setConfigDraft(status.config);
4058
4095
  setProject(status.project ?? null);
4096
+ if (status.project?.roleStatus !== void 0) setCharCards(status.project.roleStatus);
4097
+ else setCharCards(null);
4059
4098
  setGeneratedFiles(status.generatedFiles);
4060
4099
  const withDraft = status.project?.chapters.find((c) => c.pendingDraft !== void 0 && c.pendingDraft !== "");
4061
4100
  setDraftNo(withDraft?.no ?? null);
@@ -4196,6 +4235,28 @@ window.__ModuleLoader__.load({
4196
4235
  setBusyLabel("");
4197
4236
  }
4198
4237
  };
4238
+ /** 章节复位:generating 卡死 → pending(可重新生成)。 */
4239
+ const handleChapterReset = async (no) => {
4240
+ setBusy(true);
4241
+ setError("");
4242
+ try {
4243
+ await api.chapterReset(no);
4244
+ setProject((prev) => prev === null ? prev : {
4245
+ ...prev,
4246
+ chapters: prev.chapters.map((c) => c.no === no ? {
4247
+ ...c,
4248
+ status: "pending",
4249
+ error: void 0
4250
+ } : c)
4251
+ });
4252
+ pushProgress(`第 ${no} 章已复位为待生成,可重新生成`, "info");
4253
+ } catch (err) {
4254
+ setError(err.message);
4255
+ pushProgress(`复位失败:${err.message}`, "error");
4256
+ } finally {
4257
+ setBusy(false);
4258
+ }
4259
+ };
4199
4260
  /** 剧情线:保存草稿(新增或更新)。 */
4200
4261
  const handlePlotlineSave = async () => {
4201
4262
  if (plotlineDraft === null) return;
@@ -4446,26 +4507,94 @@ window.__ModuleLoader__.load({
4446
4507
  setBusyLabel("");
4447
4508
  }
4448
4509
  };
4449
- /** 保存角色知情度(bible.characters 整体更新)。 */
4450
- const handleKnowledgeSave = async () => {
4451
- if (bible === void 0) return;
4452
- const characters = bible.characters.map((card) => ({
4453
- ...card,
4454
- knowledge: (knowledgeDraft[card.name] ?? (card.knowledge ?? []).join("\n")).split("\n").map((l) => l.trim()).filter((l) => l !== "")
4455
- }));
4510
+ /** 角色库:AI 从全书提炼角色候选。 */
4511
+ const handleRolesExtract = async () => {
4512
+ setBusy(true);
4513
+ setBusyLabel("✨ 提炼角色库中…");
4514
+ setError("");
4515
+ try {
4516
+ const result = await api.roles({ op: "extract" });
4517
+ const inLibrary = new Set((project?.roles ?? []).map((r) => r.name));
4518
+ const fresh = (result.candidates ?? []).filter((r) => !inLibrary.has(r.name));
4519
+ setRoleCandidates((prev) => {
4520
+ return [...(prev ?? []).filter((p) => !fresh.some((f) => f.name === p.name)), ...fresh];
4521
+ });
4522
+ pushProgress(`AI 提炼出 ${fresh.length} 个新角色(已排除 ${(result.candidates?.length ?? 0) - fresh.length} 个已收录)`, "done");
4523
+ } catch (err) {
4524
+ setError(err.message);
4525
+ pushProgress(`角色提炼失败:${err.message}`, "error");
4526
+ } finally {
4527
+ setBusy(false);
4528
+ setBusyLabel("");
4529
+ }
4530
+ };
4531
+ /** 角色库:采纳候选(或修改后采纳)。 */
4532
+ const handleRoleAdopt = async (role) => {
4456
4533
  setBusy(true);
4457
4534
  setError("");
4458
4535
  try {
4459
- const result = await api.biblePatch({ characters });
4460
- setProject((prev) => prev === null || prev.bible === void 0 ? prev : {
4536
+ const result = await api.roles({
4537
+ op: "adopt",
4538
+ role
4539
+ });
4540
+ setProject((prev) => prev === null ? prev : {
4461
4541
  ...prev,
4462
- bible: result.bible,
4542
+ roles: result.roles,
4543
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
4544
+ });
4545
+ setRoleCandidates((prev) => prev === null ? prev : prev.filter((r) => r !== role));
4546
+ pushProgress(`已加入角色库:${role.name}`, "done");
4547
+ } catch (err) {
4548
+ setError(err.message);
4549
+ } finally {
4550
+ setBusy(false);
4551
+ }
4552
+ };
4553
+ /** 角色库:保存编辑草稿。 */
4554
+ const handleRoleSave = async () => {
4555
+ if (roleDraft === null) return;
4556
+ if (roleDraft.name.trim() === "") {
4557
+ setError("角色名不能为空");
4558
+ return;
4559
+ }
4560
+ setBusy(true);
4561
+ setError("");
4562
+ try {
4563
+ const result = await api.roles({
4564
+ op: "update",
4565
+ role: roleDraft
4566
+ });
4567
+ setProject((prev) => prev === null ? prev : {
4568
+ ...prev,
4569
+ roles: result.roles,
4570
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
4571
+ });
4572
+ setRoleDraft(null);
4573
+ pushProgress(`角色已保存:${roleDraft.name}`, "done");
4574
+ } catch (err) {
4575
+ setError(err.message);
4576
+ } finally {
4577
+ setBusy(false);
4578
+ }
4579
+ };
4580
+ /** 角色库:删除角色。 */
4581
+ const handleRoleRemove = async (name) => {
4582
+ if (!window.confirm(`确定从角色库删除「${name}」?`)) return;
4583
+ setBusy(true);
4584
+ setError("");
4585
+ try {
4586
+ const result = await api.roles({
4587
+ op: "remove",
4588
+ name
4589
+ });
4590
+ setProject((prev) => prev === null ? prev : {
4591
+ ...prev,
4592
+ roles: result.roles,
4463
4593
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
4464
4594
  });
4465
- pushProgress("角色知情度已保存(生成/审稿都会严格遵守信息差)", "done");
4595
+ pushProgress(`已从角色库删除:${name}`, "info");
4466
4596
  } catch (err) {
4467
4597
  setError(err.message);
4468
- pushProgress(`保存知情度失败:${err.message}`, "error");
4469
4598
  } finally {
4470
4599
  setBusy(false);
4471
4600
  }
@@ -7339,6 +7468,16 @@ window.__ModuleLoader__.load({
7339
7468
  },
7340
7469
  children: tt("plan.write")
7341
7470
  }),
7471
+ chapter.status === "generating" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7472
+ type: "button",
7473
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
7474
+ disabled: busy,
7475
+ onClick: () => {
7476
+ handleChapterReset(chapter.no);
7477
+ },
7478
+ title: "生成卡死/中断时可复位为待生成,重新生成",
7479
+ children: "🔄 复位"
7480
+ }),
7342
7481
  (chapter.status === "written" || chapter.status === "rejected") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7343
7482
  type: "button",
7344
7483
  className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
@@ -7776,80 +7915,445 @@ window.__ModuleLoader__.load({
7776
7915
  pushProgress(`大世界已保存:${w.realms.length} 境界 · ${w.regions.length} 区域 · ${w.factions.length} 势力`, "done");
7777
7916
  }
7778
7917
  }),
7779
- activeTab === "characters" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7918
+ activeTab === "roles" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7780
7919
  className: panel_module_css_default.card,
7920
+ style: {
7921
+ flex: 1,
7922
+ minHeight: 0
7923
+ },
7781
7924
  children: [
7782
7925
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7783
7926
  className: panel_module_css_default.row,
7784
- style: { justifyContent: "space-between" },
7785
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7927
+ style: {
7928
+ justifyContent: "space-between",
7929
+ flexWrap: "wrap"
7930
+ },
7931
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
7786
7932
  className: panel_module_css_default.cardTitle,
7787
- children: "人物志(当前状态)"
7788
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7933
+ children: [
7934
+ "👥 角色库(",
7935
+ (project?.roles ?? []).length,
7936
+ " 个)"
7937
+ ]
7938
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7789
7939
  className: panel_module_css_default.row,
7790
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7791
- type: "button",
7792
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
7793
- disabled: busy || doneCount === 0,
7794
- onClick: () => {
7795
- handleFactsBackfill();
7796
- },
7797
- title: "历史章节(编年录功能上线前生成的)批量抽取事实",
7798
- children: "📥 回填编年录"
7799
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7940
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7800
7941
  type: "button",
7801
7942
  className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall} ${panel_module_css_default.buttonPrimary}`,
7802
- disabled: busy || (project?.facts ?? []).length === 0,
7943
+ disabled: busy || doneCount === 0,
7803
7944
  onClick: () => {
7804
- handleCharactersRefresh();
7945
+ handleRolesExtract();
7805
7946
  },
7806
- children: "↻ 从编年录刷新"
7807
- })]
7947
+ title: "AI 扫描大纲/编年录/已写章节,提炼完整角色库(含女主/女配/反派定位)",
7948
+ children: "✨ 从全书提炼角色"
7949
+ })
7808
7950
  })]
7809
7951
  }),
7810
- charCards === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7811
- className: panel_module_css_default.meta,
7812
- children: (project?.facts ?? []).length === 0 ? "暂无编年录(生成章节后自动积累人物状态/境界/资源/关系等事实),刷新按钮将在有事实后可用。" : "点击「从编年录刷新」聚合各人物当前状态(境界/资源/伤势/心境)。"
7813
- }) : charCards.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7952
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7814
7953
  className: panel_module_css_default.meta,
7815
- children: "未识别到人物信息。"
7816
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7954
+ children: "角色库是全书角色主表:定位(女主/女配/配角/反派)、身份、关系网、成长线、知情度——生成与审稿都会按定位规格刻画互动。"
7955
+ }),
7956
+ roleCandidates !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7817
7957
  style: {
7818
7958
  display: "flex",
7819
7959
  flexDirection: "column",
7820
- gap: 6
7960
+ gap: 6,
7961
+ border: "1px solid var(--nf-info)",
7962
+ borderRadius: 12,
7963
+ padding: 10
7821
7964
  },
7822
- children: charCards.map((card) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7823
- style: {
7824
- border: "1px solid var(--nf-border)",
7825
- borderRadius: 8,
7826
- padding: "6px 10px",
7827
- fontSize: 12
7828
- },
7829
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7965
+ children: [
7966
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7830
7967
  className: panel_module_css_default.row,
7831
- style: { justifyContent: "space-between" },
7832
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: card.name }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
7833
- className: panel_module_css_default.meta,
7834
- children: [
7835
- card.role === "protagonist" ? "主角" : card.role === "supporting" ? "配角" : card.role === "antagonist" ? "反派" : "其他",
7836
- " · 出场 ",
7837
- card.appearances,
7838
- " 次 · 最近 第 ",
7839
- card.lastChapter,
7840
- " 章"
7841
- ]
7968
+ style: {
7969
+ justifyContent: "space-between",
7970
+ flexWrap: "wrap"
7971
+ },
7972
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("b", { children: [
7973
+ "✨ AI 提炼候选(",
7974
+ roleCandidates.length,
7975
+ ")"
7976
+ ] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7977
+ type: "button",
7978
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
7979
+ onClick: () => {
7980
+ setRoleCandidates(null);
7981
+ },
7982
+ children: "收起"
7842
7983
  })]
7843
- }), card.status !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7984
+ }),
7985
+ roleCandidates.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7844
7986
  className: panel_module_css_default.meta,
7845
- children: ["状态:", card.status]
7846
- })]
7847
- }, card.name))
7848
- }),
7849
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7850
- className: panel_module_css_default.meta,
7851
- children: "人物志由「道藏」人物名单 + 「编年录」聚合而来,随章节生成自动保持最新。"
7852
- })
7987
+ children: "未提炼到角色。"
7988
+ }),
7989
+ roleCandidates.map((r, i) => {
7990
+ const label = {
7991
+ protagonist: "主角",
7992
+ female_lead: "女主",
7993
+ female_support: "女配",
7994
+ support: "配角",
7995
+ antagonist: "反派",
7996
+ extra: "路人"
7997
+ }[r.roleLabel];
7998
+ const color = r.roleLabel === "protagonist" ? "var(--nf-success)" : r.roleLabel === "female_lead" ? "var(--nf-accent)" : r.roleLabel === "antagonist" ? "var(--nf-error)" : "var(--nf-text-3)";
7999
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8000
+ style: {
8001
+ border: "1px solid var(--nf-border)",
8002
+ borderRadius: 8,
8003
+ padding: "6px 10px",
8004
+ fontSize: 12
8005
+ },
8006
+ children: [
8007
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8008
+ className: panel_module_css_default.row,
8009
+ style: {
8010
+ justifyContent: "space-between",
8011
+ flexWrap: "wrap"
8012
+ },
8013
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
8014
+ style: {
8015
+ display: "flex",
8016
+ alignItems: "center",
8017
+ gap: 6,
8018
+ flexWrap: "wrap"
8019
+ },
8020
+ children: [
8021
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: r.name }),
8022
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8023
+ className: panel_module_css_default.badge,
8024
+ style: {
8025
+ borderColor: color,
8026
+ color
8027
+ },
8028
+ children: label
8029
+ }),
8030
+ r.identity !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8031
+ className: panel_module_css_default.meta,
8032
+ children: r.identity
8033
+ })
8034
+ ]
8035
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
8036
+ style: {
8037
+ display: "flex",
8038
+ gap: 6
8039
+ },
8040
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8041
+ type: "button",
8042
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall} ${panel_module_css_default.buttonPrimary}`,
8043
+ disabled: busy,
8044
+ onClick: () => {
8045
+ handleRoleAdopt(r);
8046
+ },
8047
+ children: "+ 采纳"
8048
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8049
+ type: "button",
8050
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
8051
+ disabled: busy,
8052
+ onClick: () => {
8053
+ setRoleDraft(r);
8054
+ },
8055
+ title: "修改后再采纳(候选列表保留)",
8056
+ children: "✏️ 修改后采纳"
8057
+ })]
8058
+ })]
8059
+ }),
8060
+ r.goals !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8061
+ className: panel_module_css_default.meta,
8062
+ children: ["目标:", r.goals]
8063
+ }),
8064
+ r.relations.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8065
+ className: panel_module_css_default.meta,
8066
+ children: ["关系:", r.relations.join("、")]
8067
+ })
8068
+ ]
8069
+ }, i);
8070
+ })
8071
+ ]
8072
+ }),
8073
+ roleDraft !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8074
+ style: {
8075
+ display: "flex",
8076
+ flexDirection: "column",
8077
+ gap: 8,
8078
+ border: "1px solid var(--nf-accent)",
8079
+ borderRadius: 12,
8080
+ padding: 10
8081
+ },
8082
+ children: [
8083
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8084
+ className: panel_module_css_default.row,
8085
+ style: { flexWrap: "wrap" },
8086
+ children: [
8087
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8088
+ className: panel_module_css_default.field,
8089
+ style: {
8090
+ flex: 1,
8091
+ minWidth: 140
8092
+ },
8093
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
8094
+ className: panel_module_css_default.fieldLabel,
8095
+ children: "角色名"
8096
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
8097
+ className: panel_module_css_default.input,
8098
+ value: roleDraft.name,
8099
+ onChange: (e) => {
8100
+ setRoleDraft({
8101
+ ...roleDraft,
8102
+ name: e.target.value
8103
+ });
8104
+ }
8105
+ })]
8106
+ }),
8107
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8108
+ className: panel_module_css_default.field,
8109
+ style: { flex: 1 },
8110
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
8111
+ className: panel_module_css_default.fieldLabel,
8112
+ children: "定位"
8113
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
8114
+ className: panel_module_css_default.input,
8115
+ value: roleDraft.roleLabel,
8116
+ onChange: (e) => {
8117
+ setRoleDraft({
8118
+ ...roleDraft,
8119
+ roleLabel: e.target.value
8120
+ });
8121
+ },
8122
+ children: [
8123
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
8124
+ value: "protagonist",
8125
+ children: "主角"
8126
+ }),
8127
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
8128
+ value: "female_lead",
8129
+ children: "女主"
8130
+ }),
8131
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
8132
+ value: "female_support",
8133
+ children: "女配"
8134
+ }),
8135
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
8136
+ value: "support",
8137
+ children: "配角"
8138
+ }),
8139
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
8140
+ value: "antagonist",
8141
+ children: "反派"
8142
+ }),
8143
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
8144
+ value: "extra",
8145
+ children: "路人"
8146
+ })
8147
+ ]
8148
+ })]
8149
+ }),
8150
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8151
+ className: panel_module_css_default.field,
8152
+ style: { flex: 2 },
8153
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
8154
+ className: panel_module_css_default.fieldLabel,
8155
+ children: "身份"
8156
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
8157
+ className: panel_module_css_default.input,
8158
+ value: roleDraft.identity,
8159
+ onChange: (e) => {
8160
+ setRoleDraft({
8161
+ ...roleDraft,
8162
+ identity: e.target.value
8163
+ });
8164
+ }
8165
+ })]
8166
+ })
8167
+ ]
8168
+ }),
8169
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8170
+ className: panel_module_css_default.field,
8171
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
8172
+ className: panel_module_css_default.fieldLabel,
8173
+ children: "目标"
8174
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
8175
+ className: panel_module_css_default.textarea,
8176
+ style: { minHeight: 44 },
8177
+ value: roleDraft.goals,
8178
+ onChange: (e) => {
8179
+ setRoleDraft({
8180
+ ...roleDraft,
8181
+ goals: e.target.value
8182
+ });
8183
+ }
8184
+ })]
8185
+ }),
8186
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8187
+ className: panel_module_css_default.field,
8188
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
8189
+ className: panel_module_css_default.fieldLabel,
8190
+ children: "关系网(每行一条:角色名(关系))"
8191
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
8192
+ className: panel_module_css_default.textarea,
8193
+ style: { minHeight: 44 },
8194
+ value: roleDraft.relations.join("\n"),
8195
+ onChange: (e) => {
8196
+ setRoleDraft({
8197
+ ...roleDraft,
8198
+ relations: e.target.value.split("\n").map((l) => l.trim()).filter((l) => l !== "")
8199
+ });
8200
+ }
8201
+ })]
8202
+ }),
8203
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8204
+ className: panel_module_css_default.field,
8205
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
8206
+ className: panel_module_css_default.fieldLabel,
8207
+ children: "成长线(每行一条:阶段:说明)"
8208
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
8209
+ className: panel_module_css_default.textarea,
8210
+ style: { minHeight: 44 },
8211
+ value: roleDraft.arc.join("\n"),
8212
+ onChange: (e) => {
8213
+ setRoleDraft({
8214
+ ...roleDraft,
8215
+ arc: e.target.value.split("\n").map((l) => l.trim()).filter((l) => l !== "")
8216
+ });
8217
+ }
8218
+ })]
8219
+ }),
8220
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8221
+ className: panel_module_css_default.field,
8222
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
8223
+ className: panel_module_css_default.fieldLabel,
8224
+ children: "知情度(每行一条该角色知道的信息)"
8225
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
8226
+ className: panel_module_css_default.textarea,
8227
+ style: { minHeight: 44 },
8228
+ value: roleDraft.knowledge.join("\n"),
8229
+ onChange: (e) => {
8230
+ setRoleDraft({
8231
+ ...roleDraft,
8232
+ knowledge: e.target.value.split("\n").map((l) => l.trim()).filter((l) => l !== "")
8233
+ });
8234
+ }
8235
+ })]
8236
+ }),
8237
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8238
+ className: panel_module_css_default.row,
8239
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8240
+ type: "button",
8241
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall} ${panel_module_css_default.buttonPrimary}`,
8242
+ disabled: busy,
8243
+ onClick: () => {
8244
+ handleRoleSave();
8245
+ },
8246
+ children: "保存"
8247
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8248
+ type: "button",
8249
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
8250
+ onClick: () => {
8251
+ setRoleDraft(null);
8252
+ },
8253
+ children: "取消"
8254
+ })]
8255
+ })
8256
+ ]
8257
+ }),
8258
+ (project?.roles ?? []).length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8259
+ className: panel_module_css_default.meta,
8260
+ children: "角色库为空——点「✨ 从全书提炼角色」自动建立,或手动新增。"
8261
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8262
+ style: {
8263
+ display: "flex",
8264
+ flexDirection: "column",
8265
+ gap: 6
8266
+ },
8267
+ children: (project?.roles ?? []).map((r) => {
8268
+ const label = {
8269
+ protagonist: "主角",
8270
+ female_lead: "女主",
8271
+ female_support: "女配",
8272
+ support: "配角",
8273
+ antagonist: "反派",
8274
+ extra: "路人"
8275
+ }[r.roleLabel];
8276
+ const color = r.roleLabel === "protagonist" ? "var(--nf-success)" : r.roleLabel === "female_lead" ? "var(--nf-accent)" : r.roleLabel === "antagonist" ? "var(--nf-error)" : "var(--nf-text-3)";
8277
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8278
+ style: {
8279
+ border: "1px solid var(--nf-border)",
8280
+ borderRadius: 8,
8281
+ padding: "6px 10px",
8282
+ fontSize: 12
8283
+ },
8284
+ children: [
8285
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8286
+ className: panel_module_css_default.row,
8287
+ style: {
8288
+ justifyContent: "space-between",
8289
+ flexWrap: "wrap"
8290
+ },
8291
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
8292
+ style: {
8293
+ display: "flex",
8294
+ alignItems: "center",
8295
+ gap: 6,
8296
+ flexWrap: "wrap"
8297
+ },
8298
+ children: [
8299
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: r.name }),
8300
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8301
+ className: panel_module_css_default.badge,
8302
+ style: {
8303
+ borderColor: color,
8304
+ color
8305
+ },
8306
+ children: label
8307
+ }),
8308
+ r.identity !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8309
+ className: panel_module_css_default.meta,
8310
+ children: r.identity
8311
+ })
8312
+ ]
8313
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
8314
+ style: {
8315
+ display: "flex",
8316
+ gap: 6
8317
+ },
8318
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8319
+ type: "button",
8320
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
8321
+ disabled: busy,
8322
+ onClick: () => {
8323
+ setRoleDraft(r);
8324
+ },
8325
+ children: "编辑"
8326
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8327
+ type: "button",
8328
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
8329
+ disabled: busy,
8330
+ onClick: () => {
8331
+ handleRoleRemove(r.name);
8332
+ },
8333
+ children: "删除"
8334
+ })]
8335
+ })]
8336
+ }),
8337
+ r.goals !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8338
+ className: panel_module_css_default.meta,
8339
+ children: ["目标:", r.goals]
8340
+ }),
8341
+ r.relations.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8342
+ className: panel_module_css_default.meta,
8343
+ children: ["关系:", r.relations.join("、")]
8344
+ }),
8345
+ r.arc.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8346
+ className: panel_module_css_default.meta,
8347
+ children: ["成长线:", r.arc.join(" → ")]
8348
+ }),
8349
+ r.knowledge.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8350
+ className: panel_module_css_default.meta,
8351
+ children: ["知情度:", r.knowledge.join(";")]
8352
+ })
8353
+ ]
8354
+ }, r.name);
8355
+ })
8356
+ })
7853
8357
  ]
7854
8358
  }),
7855
8359
  activeTab === "characters" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -7857,66 +8361,90 @@ window.__ModuleLoader__.load({
7857
8361
  children: [
7858
8362
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7859
8363
  className: panel_module_css_default.row,
7860
- style: {
7861
- justifyContent: "space-between",
7862
- flexWrap: "wrap"
7863
- },
8364
+ style: { justifyContent: "space-between" },
7864
8365
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7865
8366
  className: panel_module_css_default.cardTitle,
7866
- children: "角色知情度(信息差管理)"
7867
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7868
- type: "button",
7869
- className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall} ${panel_module_css_default.buttonPrimary}`,
7870
- disabled: busy || (bible?.characters ?? []).length === 0,
7871
- onClick: () => {
7872
- handleKnowledgeSave();
7873
- },
7874
- children: "💾 保存知情度"
8367
+ children: "人物志(当前状态)"
8368
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8369
+ className: panel_module_css_default.row,
8370
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8371
+ type: "button",
8372
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
8373
+ disabled: busy || doneCount === 0,
8374
+ onClick: () => {
8375
+ handleFactsBackfill();
8376
+ },
8377
+ title: "历史章节(编年录功能上线前生成的)批量抽取事实",
8378
+ children: "📥 回填编年录"
8379
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8380
+ type: "button",
8381
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall} ${panel_module_css_default.buttonPrimary}`,
8382
+ disabled: busy || (project?.facts ?? []).length === 0,
8383
+ onClick: () => {
8384
+ handleCharactersRefresh();
8385
+ },
8386
+ children: "↻ 从编年录刷新"
8387
+ })]
7875
8388
  })]
7876
8389
  }),
7877
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8390
+ charCards === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7878
8391
  className: panel_module_css_default.meta,
7879
- children: "填写每个角色「已经知道」的事实/秘密(每行一条)。生成与审稿会严格遵守:未列出的信息该角色一律不知道——避免\"不该知道的人知道了\"。"
7880
- }),
7881
- (bible?.characters ?? []).length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8392
+ children: (project?.facts ?? []).length === 0 ? "暂无编年录(生成章节后自动积累人物状态/境界/资源/关系等事实),刷新按钮将在有事实后可用。" : "点击「从编年录刷新」聚合各人物当前状态(境界/资源/伤势/心境)。"
8393
+ }) : charCards.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7882
8394
  className: panel_module_css_default.meta,
7883
- children: "暂无角色卡——先在「道藏」提炼设定。"
8395
+ children: "未识别到人物信息。"
7884
8396
  }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7885
8397
  style: {
7886
8398
  display: "flex",
7887
8399
  flexDirection: "column",
7888
- gap: 8
8400
+ gap: 6
7889
8401
  },
7890
- children: bible.characters.map((card) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8402
+ children: charCards.map((card) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7891
8403
  style: {
7892
8404
  border: "1px solid var(--nf-border)",
7893
- borderRadius: 10,
7894
- padding: "8px 10px",
8405
+ borderRadius: 8,
8406
+ padding: "6px 10px",
7895
8407
  fontSize: 12
7896
8408
  },
7897
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7898
- className: panel_module_css_default.row,
7899
- style: { justifyContent: "space-between" },
7900
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: card.name }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8409
+ children: [
8410
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8411
+ className: panel_module_css_default.row,
8412
+ style: { justifyContent: "space-between" },
8413
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: card.name }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
8414
+ className: panel_module_css_default.meta,
8415
+ children: [
8416
+ card.role === "protagonist" ? "主角" : card.role === "supporting" ? "配角" : card.role === "antagonist" ? "反派" : "其他",
8417
+ " · 出场 ",
8418
+ card.appearances,
8419
+ " 次 · 最近 第 ",
8420
+ card.lastChapter,
8421
+ " 章"
8422
+ ]
8423
+ })]
8424
+ }),
8425
+ card.status !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7901
8426
  className: panel_module_css_default.meta,
7902
- children: card.role === "protagonist" ? "主角" : card.role === "supporting" ? "配角" : card.role === "antagonist" ? "反派" : "其他"
7903
- })]
7904
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
7905
- className: panel_module_css_default.textarea,
7906
- style: {
7907
- minHeight: 52,
7908
- fontSize: 12
7909
- },
7910
- placeholder: "每行一条该角色知道的信息,例如:林越的真实身份 / 古玉残片的秘密…",
7911
- value: knowledgeDraft[card.name] ?? (card.knowledge ?? []).join("\n"),
7912
- onChange: (e) => {
7913
- setKnowledgeDraft((prev) => ({
7914
- ...prev,
7915
- [card.name]: e.target.value
7916
- }));
7917
- }
7918
- })]
8427
+ children: ["状态:", card.status]
8428
+ }),
8429
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8430
+ className: panel_module_css_default.row,
8431
+ style: { marginTop: 4 },
8432
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8433
+ type: "button",
8434
+ className: `${panel_module_css_default.button} ${panel_module_css_default.buttonSmall}`,
8435
+ onClick: () => {
8436
+ setActiveTab("roles");
8437
+ },
8438
+ title: "在角色库中查看/编辑该角色档案",
8439
+ children: "📖 查看档案"
8440
+ })
8441
+ })
8442
+ ]
7919
8443
  }, card.name))
8444
+ }),
8445
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8446
+ className: panel_module_css_default.meta,
8447
+ children: "人物志由「道藏」人物名单 + 「编年录」聚合而来,随章节生成自动保持最新。"
7920
8448
  })
7921
8449
  ]
7922
8450
  }),