dsh-novel-write-engine 0.1.3 → 0.2.0

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/index.d.ts CHANGED
@@ -22,8 +22,8 @@ declare const SCENE_TYPES: readonly ["战斗/动作章", "日常过渡章", "情
22
22
  type SceneType = (typeof SCENE_TYPES)[number];
23
23
  /** A violation is blocking unless the rule pack declares it advisory. */
24
24
  type Severity = 'blocker' | 'advisory';
25
- /** All twenty-two service operations. */
26
- declare const OPERATIONS: readonly ["initProject", "archiveChapter", "amend", "rollback", "submitWorldPlan", "submitChapterPlan", "submitDraft", "submitReview", "submitRevision", "runCheck", "getStatus", "getBrief", "countWords", "queryState", "diff", "auditHistory", "advise", "export", "panelSummary", "panelChapters", "panelGates", "stats"];
25
+ /** All thirty-one service operations (22 inherited from 0.1.x, 9 book-level). */
26
+ declare const OPERATIONS: readonly ["initProject", "archiveChapter", "amend", "rollback", "reopenChapter", "submitWorldPlan", "submitChapterPlan", "submitDraft", "submitReview", "submitRevision", "runCheck", "submitBookPlan", "submitOutline", "importOutline", "submitWorldbook", "getStatus", "getBrief", "countWords", "queryState", "diff", "auditHistory", "advise", "search", "doctor", "report", "guide", "export", "panelSummary", "panelChapters", "panelGates", "stats"];
27
27
  type Operation = (typeof OPERATIONS)[number];
28
28
  /** Structured, non-fatal note attached to a successful result. */
29
29
  interface Warning {
@@ -72,6 +72,8 @@ declare const ERROR_CODES: {
72
72
  readonly PATH_ESCAPE: "ENGINE_PATH_ESCAPE";
73
73
  readonly LOCK_TIMEOUT: "ENGINE_LOCK_TIMEOUT";
74
74
  readonly TXN_ABORTED: "ENGINE_TXN_ABORTED";
75
+ readonly JOURNAL_MISSING: "ENGINE_JOURNAL_MISSING";
76
+ readonly TXN_IN_PROGRESS: "ENGINE_TXN_IN_PROGRESS";
75
77
  readonly RULEPACK_INVALID: "ENGINE_RULEPACK_INVALID";
76
78
  readonly ID_EXHAUSTED: "ENGINE_ID_EXHAUSTED";
77
79
  readonly CONFIG_INVALID: "ENGINE_CONFIG_INVALID";
@@ -172,7 +174,7 @@ interface CheckDocument {
172
174
  verdict: 'pass' | 'fail';
173
175
  }
174
176
  /** Every persisted document whose damage status/panel can report. */
175
- type StateErrorCode = 'PROJECT_UNREADABLE' | 'PLAN_UNREADABLE' | 'WORLD_PLAN_UNREADABLE' | 'REVIEW_UNREADABLE' | 'CHECK_UNREADABLE' | 'CHAPTERS_UNREADABLE' | 'CHARACTERS_UNREADABLE' | 'WORLD_UNREADABLE' | 'LOCKS_UNREADABLE' | 'TIMELINE_UNREADABLE' | 'FORESHADOWS_UNREADABLE' | 'RELATIONSHIPS_UNREADABLE' | 'HANDOFF_UNREADABLE';
177
+ type StateErrorCode = 'PROJECT_UNREADABLE' | 'PLAN_UNREADABLE' | 'WORLD_PLAN_UNREADABLE' | 'REVIEW_UNREADABLE' | 'CHECK_UNREADABLE' | 'CHAPTERS_UNREADABLE' | 'CHARACTERS_UNREADABLE' | 'WORLD_UNREADABLE' | 'LOCKS_UNREADABLE' | 'TIMELINE_UNREADABLE' | 'FORESHADOWS_UNREADABLE' | 'RELATIONSHIPS_UNREADABLE' | 'HANDOFF_UNREADABLE' | 'OUTLINE_UNREADABLE' | 'WORLDBOOK_UNREADABLE';
176
178
  /** A state document that exists but cannot be read safely. */
177
179
  interface StateError {
178
180
  path: string;
@@ -526,6 +528,265 @@ interface ChapterPlanInput {
526
528
  /** Optional in 0.1.3: older plans remain readable; new plans may name 1–8 actors. */
527
529
  cast?: ChapterCastMember[];
528
530
  }
531
+ /** Book-level pitch and structure, persisted in `outline/outline.yaml`. */
532
+ interface BookPlan {
533
+ premise: string;
534
+ logline: string;
535
+ themes: string[];
536
+ tone: string;
537
+ pov: string;
538
+ audience: string;
539
+ selling_points: string[];
540
+ ending: string;
541
+ /** Strict mode requires a chapter card before P2/P3 for every chapter. */
542
+ strict: boolean;
543
+ /** True once the author explicitly chose strict on/off; used for the first-outline default. */
544
+ strict_explicit?: boolean;
545
+ }
546
+ /** One volume of the planned book. `end_chapter` is inclusive. */
547
+ interface OutlineVolume {
548
+ id: string;
549
+ title: string;
550
+ start_chapter: number;
551
+ end_chapter: number;
552
+ goal: string;
553
+ arc: string;
554
+ climax: string;
555
+ status: 'planned' | 'writing' | 'done';
556
+ }
557
+ /** One planned chapter card. Only the archive transaction may write the archived fields. */
558
+ interface OutlineChapter {
559
+ num: number;
560
+ volume: number | null;
561
+ title: string;
562
+ scene_type: SceneType;
563
+ goal: string;
564
+ conflict: string;
565
+ hook: string;
566
+ cast: string[];
567
+ target_words: [number, number];
568
+ notes: string;
569
+ status: 'planned' | 'archived';
570
+ archived_at: string | null;
571
+ word_count: number | null;
572
+ score: number | null;
573
+ }
574
+ /** The planning SSOT read by P1–P8, PG-13, report, doctor and export. */
575
+ interface OutlineDocument {
576
+ schema_version: 1;
577
+ updated_at: string;
578
+ book: BookPlan;
579
+ volumes: OutlineVolume[];
580
+ chapters: OutlineChapter[];
581
+ }
582
+ /** One worldbuilding rule/constraint. */
583
+ interface WorldbookRule {
584
+ name: string;
585
+ description: string;
586
+ }
587
+ /** One faction in the world bible. */
588
+ interface WorldbookFaction {
589
+ name: string;
590
+ description: string;
591
+ goal: string;
592
+ }
593
+ /** One location in the world bible. */
594
+ interface WorldbookLocation {
595
+ name: string;
596
+ description: string;
597
+ layout: string;
598
+ capacity: number;
599
+ }
600
+ /** One planned character (not the post-prose ledger entry). */
601
+ interface WorldbookCharacter {
602
+ name: string;
603
+ role: string;
604
+ description: string;
605
+ arc: string;
606
+ }
607
+ /** One glossary entry. */
608
+ interface WorldbookGlossary {
609
+ term: string;
610
+ definition: string;
611
+ }
612
+ /** One backstory event. */
613
+ interface WorldbookBackstory {
614
+ time: string;
615
+ event: string;
616
+ }
617
+ /** Worldbuilding plan, persisted in `outline/worldbook.yaml`. */
618
+ interface WorldbookDocument {
619
+ schema_version: 1;
620
+ updated_at: string;
621
+ premise: string;
622
+ setting: string;
623
+ rules: WorldbookRule[];
624
+ factions: WorldbookFaction[];
625
+ locations: WorldbookLocation[];
626
+ characters: WorldbookCharacter[];
627
+ glossary: WorldbookGlossary[];
628
+ backstory: WorldbookBackstory[];
629
+ themes: string[];
630
+ }
631
+ /** One hit from `novel_search`; the scope names the source family. */
632
+ interface SearchResultItem {
633
+ kind: 'chapters' | 'summaries' | 'outline' | 'worldbook' | 'ledgers';
634
+ chapter?: number;
635
+ title?: string;
636
+ paragraph?: number;
637
+ snippet: string;
638
+ }
639
+ /** Search response; `total` counts every matching segment, `results` is capped by `limit`. */
640
+ interface SearchReport {
641
+ query: string;
642
+ scope: 'all' | 'chapters' | 'summaries' | 'outline' | 'worldbook' | 'ledgers';
643
+ total: number;
644
+ truncated: boolean;
645
+ results: SearchResultItem[];
646
+ }
647
+ /** One structured health check. */
648
+ interface DoctorCheck {
649
+ id: string;
650
+ severity: 'ok' | 'info' | 'warning' | 'error';
651
+ title: string;
652
+ detail: string;
653
+ hint?: string;
654
+ }
655
+ /** `novel_doctor` payload; a missing project is reported, never thrown. */
656
+ interface DoctorReport {
657
+ ok: boolean;
658
+ root: string;
659
+ checks: DoctorCheck[];
660
+ summary: {
661
+ errors: number;
662
+ warnings: number;
663
+ infos: number;
664
+ };
665
+ }
666
+ /** Book-wide quality, outline, cast and pacing aggregates. */
667
+ interface BookReport {
668
+ progress: {
669
+ archived: number;
670
+ target: number | null;
671
+ words: number;
672
+ average_words: number;
673
+ percent: number;
674
+ remaining_words: number | null;
675
+ };
676
+ outline: {
677
+ present: boolean;
678
+ strict: boolean;
679
+ planned: number;
680
+ archived: number;
681
+ coverage: number;
682
+ volumes: Array<{
683
+ title: string;
684
+ start: number;
685
+ end: number;
686
+ planned: number;
687
+ archived: number;
688
+ }>;
689
+ drift: Array<{
690
+ chapter: number;
691
+ field: string;
692
+ planned: string;
693
+ actual: string;
694
+ }>;
695
+ };
696
+ worldbook: {
697
+ present: boolean;
698
+ characters: number;
699
+ locations: number;
700
+ factions: number;
701
+ rules: number;
702
+ glossary: number;
703
+ backstory: number;
704
+ };
705
+ quality: {
706
+ average: number;
707
+ median: number;
708
+ min: number;
709
+ max: number;
710
+ last_five: number[];
711
+ trend: number;
712
+ dimensions: Array<{
713
+ id: string;
714
+ average: number;
715
+ samples: number;
716
+ }>;
717
+ };
718
+ pacing: {
719
+ scene_types: Record<string, number>;
720
+ hook_strength: Record<string, number>;
721
+ plot_advancement: Record<string, number>;
722
+ longest: {
723
+ chapter: number;
724
+ words: number;
725
+ } | null;
726
+ shortest: {
727
+ chapter: number;
728
+ words: number;
729
+ } | null;
730
+ };
731
+ cast: {
732
+ total: number;
733
+ top: Array<{
734
+ name: string;
735
+ appearances: number;
736
+ last_seen: number;
737
+ role: string;
738
+ }>;
739
+ };
740
+ foreshadows: {
741
+ open: number;
742
+ dormant: number;
743
+ overdue: number;
744
+ resolved: number;
745
+ oldest: Array<{
746
+ id: string;
747
+ title: string;
748
+ last_touched: number;
749
+ age: number;
750
+ }>;
751
+ };
752
+ timeline: {
753
+ events: number;
754
+ first_chapter: number | null;
755
+ last_chapter: number | null;
756
+ };
757
+ relationships: {
758
+ total: number;
759
+ types: Record<string, number>;
760
+ };
761
+ activity: Array<{
762
+ at: string;
763
+ op: string;
764
+ chapter: number;
765
+ status: string;
766
+ }>;
767
+ warnings: string[];
768
+ }
769
+ /** One onboarding step. */
770
+ interface GuideStep {
771
+ id: string;
772
+ title: string;
773
+ detail: string;
774
+ done: boolean;
775
+ tool?: string;
776
+ }
777
+ /** `novel_guide` payload. */
778
+ interface GuideReport {
779
+ state: 'no-project' | 'new' | 'planning' | 'writing' | 'blocked' | 'finished';
780
+ title: string;
781
+ steps: GuideStep[];
782
+ next: {
783
+ tool: string;
784
+ args: Record<string, unknown>;
785
+ reason: string;
786
+ };
787
+ commands: string[];
788
+ tips: string[];
789
+ }
529
790
  /** Draft submission payload. */
530
791
  interface DraftInput {
531
792
  chapter: number;
@@ -598,6 +859,12 @@ interface GateInput {
598
859
  /** The three preceding chapters, newest first, for the duplicate rule. */
599
860
  previousTexts: string[];
600
861
  priorSceneTypes: SceneType[];
862
+ /** 0.2.0 planning input; undefined means "no outline" for older fixtures. */
863
+ outline?: OutlineDocument | null;
864
+ /** The chapter plan's target range, used by PG-13. */
865
+ planTargetWords?: [number, number] | null;
866
+ /** The chapter plan's declared cast names, used by PG-13. */
867
+ planCast?: string[] | null;
601
868
  }
602
869
  /** Gate evaluation outcome. */
603
870
  interface GateResult {
@@ -636,6 +903,30 @@ interface StatusReport {
636
903
  volume_name?: string;
637
904
  act?: string;
638
905
  act_progress?: string;
906
+ /** 0.2.0 book-level visibility; absent on older synthetic payloads. */
907
+ book?: {
908
+ premise: string;
909
+ logline: string;
910
+ strict: boolean;
911
+ outline: {
912
+ present: boolean;
913
+ total: number;
914
+ planned: number;
915
+ archived: number;
916
+ coverage: number;
917
+ volumes: number;
918
+ current: OutlineChapter | null;
919
+ };
920
+ worldbook: {
921
+ present: boolean;
922
+ characters: number;
923
+ locations: number;
924
+ factions: number;
925
+ rules: number;
926
+ glossary: number;
927
+ backstory: number;
928
+ };
929
+ };
639
930
  next: {
640
931
  tool: string;
641
932
  args: Record<string, unknown>;
@@ -674,8 +965,8 @@ interface DiffReport {
674
965
  line: string;
675
966
  }>;
676
967
  }
677
- /** Export capabilities. */
678
- type ExportKind = 'md' | 'txt' | 'epub';
968
+ /** Export capabilities; the last three are book-planning deliverables. */
969
+ type ExportKind = 'md' | 'txt' | 'epub' | 'outline' | 'worldbook' | 'proposal';
679
970
  /** One blacklisted word. */
680
971
  interface TermEntry {
681
972
  term: string;
@@ -803,13 +1094,65 @@ interface Rulepack {
803
1094
  exemptions: string[];
804
1095
  }
805
1096
  /** Every persisted document the engine knows how to load. */
806
- type DocKind = 'project' | 'pipeline' | 'chapters' | 'characters' | 'world' | 'locks' | 'foreshadows' | 'timeline' | 'relationships' | 'handoff' | 'review' | 'check' | 'worldPlan' | 'chapterPlan';
1097
+ type DocKind = 'project' | 'pipeline' | 'chapters' | 'characters' | 'world' | 'locks' | 'foreshadows' | 'timeline' | 'relationships' | 'handoff' | 'review' | 'check' | 'worldPlan' | 'chapterPlan' | 'outline' | 'worldbook';
807
1098
  /** One project row in the cross-project registry. */
808
1099
  interface RegistryEntry {
809
1100
  root: string;
810
1101
  title: string;
811
1102
  updated_at: string;
812
1103
  }
1104
+ interface BookPatch {
1105
+ premise?: string;
1106
+ logline?: string;
1107
+ themes?: string[];
1108
+ tone?: string;
1109
+ pov?: string;
1110
+ audience?: string;
1111
+ selling_points?: string[];
1112
+ ending?: string;
1113
+ strict?: boolean;
1114
+ /** Internal provenance for an explicit strict choice. */
1115
+ strict_explicit?: boolean;
1116
+ }
1117
+ interface VolumeInput {
1118
+ id?: string;
1119
+ title: string;
1120
+ start_chapter: number;
1121
+ end_chapter: number;
1122
+ goal?: string;
1123
+ arc?: string;
1124
+ climax?: string;
1125
+ status?: OutlineVolume['status'];
1126
+ }
1127
+ interface OutlineChapterInput {
1128
+ num: number;
1129
+ volume?: number | null;
1130
+ title: string;
1131
+ scene_type: SceneType;
1132
+ goal: string;
1133
+ conflict: string;
1134
+ hook: string;
1135
+ cast?: string[];
1136
+ target_words: [number, number];
1137
+ notes?: string;
1138
+ }
1139
+ interface OutlineInput {
1140
+ book?: BookPatch;
1141
+ volumes?: VolumeInput[];
1142
+ chapters: OutlineChapterInput[];
1143
+ strict?: boolean;
1144
+ }
1145
+ interface WorldbookPatch {
1146
+ premise?: string;
1147
+ setting?: string;
1148
+ rules?: WorldbookRule[];
1149
+ factions?: WorldbookFaction[];
1150
+ locations?: WorldbookLocation[];
1151
+ characters?: WorldbookCharacter[];
1152
+ glossary?: WorldbookGlossary[];
1153
+ backstory?: WorldbookBackstory[];
1154
+ themes?: string[];
1155
+ }
813
1156
  /** One rendered task book. */
814
1157
  interface BriefDocument {
815
1158
  stage: BriefStage;
@@ -846,6 +1189,7 @@ declare const GATES: {
846
1189
  readonly 'PG-10': "CONSISTENCY";
847
1190
  readonly 'PG-11': "ROUNDS";
848
1191
  readonly 'PG-12': "ARCHIVE_ATOMIC";
1192
+ readonly 'PG-13': "OUTLINE_ALIGNMENT";
849
1193
  };
850
1194
  type GateId = keyof typeof GATES;
851
1195
  /** Everything gate evaluation needs beyond the input: taste comes from the pack. */
@@ -857,7 +1201,7 @@ interface GateOptions {
857
1201
  declare function parseParagraphLocation(location: string): number | null;
858
1202
  /** Verify one reading-proof reference against the manuscript. */
859
1203
  declare function verifyReference(text: string, reference: ReadingProofReference): string | null;
860
- /** Evaluate all twelve gates and return every blocking item, in canonical order. */
1204
+ /** Evaluate all thirteen gates and return every blocking item, in canonical order. */
861
1205
  declare function evaluateGates(input: GateInput, options: GateOptions): GateResult;
862
1206
  /**
863
1207
  * Which gates apply to an operation. A gate that does not apply must not run:
@@ -912,6 +1256,53 @@ interface PanelSnapshot {
912
1256
  done: boolean;
913
1257
  active: boolean;
914
1258
  }>;
1259
+ /** 0.2.0 book-level planning and health blocks. */
1260
+ book?: PanelBook;
1261
+ quality?: {
1262
+ averageScore: number;
1263
+ scores: number[];
1264
+ trend: number;
1265
+ };
1266
+ health?: {
1267
+ ok: boolean;
1268
+ blocking: number;
1269
+ stateErrors: number;
1270
+ };
1271
+ activity?: Array<{
1272
+ at: string;
1273
+ op: string;
1274
+ chapter: number;
1275
+ status: string;
1276
+ }>;
1277
+ }
1278
+ interface PanelBook {
1279
+ premise: string;
1280
+ logline: string;
1281
+ strict: boolean;
1282
+ target: number | null;
1283
+ outline: {
1284
+ present: boolean;
1285
+ total: number;
1286
+ planned: number;
1287
+ archived: number;
1288
+ coverage: number;
1289
+ volumes: Array<{
1290
+ title: string;
1291
+ start: number;
1292
+ end: number;
1293
+ planned: number;
1294
+ archived: number;
1295
+ }>;
1296
+ };
1297
+ worldbook: {
1298
+ present: boolean;
1299
+ characters: number;
1300
+ locations: number;
1301
+ factions: number;
1302
+ rules: number;
1303
+ glossary: number;
1304
+ backstory: number;
1305
+ };
915
1306
  }
916
1307
  interface PanelSummaryDto {
917
1308
  schemaVersion: number;
@@ -942,6 +1333,24 @@ interface PanelSummaryDto {
942
1333
  };
943
1334
  /** Absent for older payloads; false means the current chapter cycle is done. */
944
1335
  finished?: boolean;
1336
+ /** 0.2.0 planning, quality, health and activity blocks. */
1337
+ book?: PanelBook;
1338
+ quality?: {
1339
+ averageScore: number;
1340
+ scores: number[];
1341
+ trend: number;
1342
+ };
1343
+ health?: {
1344
+ ok: boolean;
1345
+ blocking: number;
1346
+ stateErrors: number;
1347
+ };
1348
+ activity?: Array<{
1349
+ at: string;
1350
+ op: string;
1351
+ chapter: number;
1352
+ status: string;
1353
+ }>;
945
1354
  }
946
1355
  interface PanelChapterRow {
947
1356
  num: number;
@@ -1021,6 +1430,31 @@ type EngineEvent = {
1021
1430
  path: string;
1022
1431
  reason: string;
1023
1432
  };
1433
+ } | {
1434
+ name: 'novel/planned';
1435
+ payload: {
1436
+ schemaVersion: 1;
1437
+ projectRoot: string;
1438
+ kind: 'blueprint' | 'outline' | 'worldbook';
1439
+ chapters: number;
1440
+ volumes: number;
1441
+ };
1442
+ } | {
1443
+ name: 'novel/reopened';
1444
+ payload: {
1445
+ schemaVersion: 1;
1446
+ projectRoot: string;
1447
+ chapter: number;
1448
+ restore_txid: string;
1449
+ };
1450
+ } | {
1451
+ name: 'novel/exported';
1452
+ payload: {
1453
+ schemaVersion: 1;
1454
+ projectRoot: string;
1455
+ kind: string;
1456
+ files: number;
1457
+ };
1024
1458
  };
1025
1459
  interface InitProjectInput {
1026
1460
  title: string;
@@ -1031,6 +1465,17 @@ interface InitProjectInput {
1031
1465
  words_per_chapter?: [number, number];
1032
1466
  total_chapters?: number | null;
1033
1467
  dialogue_ratio?: [number, number];
1468
+ /** 0.2.0 book-planning seed; every field is optional. */
1469
+ premise?: string;
1470
+ logline?: string;
1471
+ themes?: string[];
1472
+ tone?: string;
1473
+ pov?: string;
1474
+ audience?: string;
1475
+ selling_points?: string[];
1476
+ ending?: string;
1477
+ /** Strict outline is opt-in; a new project defaults to false. */
1478
+ strict_outline?: boolean;
1034
1479
  root?: string;
1035
1480
  }
1036
1481
  interface StatusInput {
@@ -1070,7 +1515,7 @@ interface RevisionSubmission extends Omit<RevisionInput, 'summary'> {
1070
1515
  }
1071
1516
  interface CheckSubmission {
1072
1517
  chapter: number;
1073
- /** The four P6 semantic items; omission is a failed check, never a pass. */
1518
+ /** The five P6 semantic items; omission is a failed check, never a pass. */
1074
1519
  semantic: SemanticItem[];
1075
1520
  scope?: string[];
1076
1521
  root?: string;
@@ -1096,7 +1541,7 @@ interface RollbackSubmission {
1096
1541
  root?: string;
1097
1542
  }
1098
1543
  interface DiffInput {
1099
- chapter: number;
1544
+ chapter?: number;
1100
1545
  before?: string;
1101
1546
  after?: string;
1102
1547
  root?: string;
@@ -1124,6 +1569,43 @@ interface WordCountInput {
1124
1569
  chapter?: number;
1125
1570
  root?: string;
1126
1571
  }
1572
+ interface BookPlanSubmission extends BookPatch {
1573
+ volumes?: VolumeInput[];
1574
+ root?: string;
1575
+ }
1576
+ interface OutlineSubmission extends OutlineInput {
1577
+ root?: string;
1578
+ }
1579
+ interface OutlineImportSubmission {
1580
+ format: 'markdown' | 'yaml' | 'json';
1581
+ content: string;
1582
+ dry_run?: boolean;
1583
+ root?: string;
1584
+ }
1585
+ interface WorldbookSubmission extends WorldbookPatch {
1586
+ root?: string;
1587
+ }
1588
+ interface ReopenSubmission {
1589
+ chapter: number;
1590
+ /** A reopen is a history-changing maintenance action; the reason is mandatory. */
1591
+ reason: string;
1592
+ root?: string;
1593
+ }
1594
+ interface SearchInput {
1595
+ query: string;
1596
+ scope?: 'all' | 'chapters' | 'summaries' | 'outline' | 'worldbook' | 'ledgers';
1597
+ limit?: number;
1598
+ root?: string;
1599
+ }
1600
+ interface DoctorInput {
1601
+ root?: string;
1602
+ }
1603
+ interface ReportSubmission {
1604
+ root?: string;
1605
+ }
1606
+ interface GuideInput {
1607
+ root?: string;
1608
+ }
1127
1609
  /**
1128
1610
  * The single write authority. Tools, commands, the panel and task books never
1129
1611
  * touch a file; every mutation is one of these operations.
@@ -1174,6 +1656,39 @@ declare class EngineService {
1174
1656
  chapter: number;
1175
1657
  stage: Stage;
1176
1658
  }>>;
1659
+ submitBookPlan(input: BookPlanSubmission): Promise<OpResult<{
1660
+ premise: string;
1661
+ logline: string;
1662
+ strict: boolean;
1663
+ volumes: number;
1664
+ chapters: number;
1665
+ }>>;
1666
+ submitOutline(input: OutlineSubmission): Promise<OpResult<{
1667
+ planned: number;
1668
+ archived: number;
1669
+ total: number;
1670
+ strict: boolean;
1671
+ volumes: number;
1672
+ }>>;
1673
+ importOutline(input: OutlineImportSubmission): Promise<OpResult<{
1674
+ format: string;
1675
+ planned: number;
1676
+ archived: number;
1677
+ total: number;
1678
+ warnings: string[];
1679
+ preview: string;
1680
+ applied: boolean;
1681
+ }>>;
1682
+ submitWorldbook(input: WorldbookSubmission): Promise<OpResult<{
1683
+ sections: string[];
1684
+ entries: number;
1685
+ counts: Record<string, number>;
1686
+ }>>;
1687
+ reopenChapter(input: ReopenSubmission): Promise<OpResult<{
1688
+ chapter: number;
1689
+ stage: Stage;
1690
+ restore_txid: string;
1691
+ }>>;
1177
1692
  /**
1178
1693
  * Read-only paths must surface a committed-journal mismatch. The write path
1179
1694
  * already fails closed; without this, status recommends the next write and
@@ -1194,6 +1709,11 @@ declare class EngineService {
1194
1709
  blocking: BlockingItem[];
1195
1710
  state_errors: StateError[];
1196
1711
  }>>;
1712
+ search(input: SearchInput): Promise<OpResult<SearchReport>>;
1713
+ doctor(input?: DoctorInput): Promise<OpResult<DoctorReport>>;
1714
+ private recoveryForSafe;
1715
+ report(input?: ReportSubmission): Promise<OpResult<BookReport>>;
1716
+ guide(input?: GuideInput): Promise<OpResult<GuideReport>>;
1197
1717
  getBrief(input: BriefInput): Promise<OpResult<{
1198
1718
  stage: string;
1199
1719
  chapter: number;
@@ -1286,6 +1806,12 @@ declare class EngineService {
1286
1806
  averageScore: number;
1287
1807
  lastScore: number;
1288
1808
  openForeshadows: number;
1809
+ plannedChapters: number;
1810
+ outlineCoverage: number;
1811
+ blueprintReady: boolean;
1812
+ worldbookEntries: number;
1813
+ strictOutline: boolean;
1814
+ targetChapters: number | null;
1289
1815
  }>;
1290
1816
  private registry;
1291
1817
  /** List known projects (convenience only; a project opens without a row). */
@@ -1327,6 +1853,47 @@ declare class EngineService {
1327
1853
  preview: string;
1328
1854
  applied: boolean;
1329
1855
  }>>;
1856
+ /**
1857
+ * Planning writes use project targets as invariants. The fallback project is
1858
+ * only for reads; writing against its null target (or default word range)
1859
+ * would create a document the real novel.yaml rejects after repair.
1860
+ */
1861
+ private assertProjectReadable;
1862
+ /**
1863
+ * Planning documents are read-only inputs to the write tools. A corrupt file
1864
+ * must be repaired explicitly with novel_amend; allowing a normal write to
1865
+ * proceed would silently replace every planned card or worldbook section it
1866
+ * could not read.
1867
+ */
1868
+ private assertPlanningDocumentReadable;
1869
+ /**
1870
+ * A strict outline cannot silently lose the active chapter's card while the
1871
+ * chapter is still being written. Otherwise a late replacement turns a
1872
+ * strict project non-strict in effect and archive would auto-create the card
1873
+ * the author was required to provide.
1874
+ */
1875
+ private assertActiveCardPreserved;
1876
+ /**
1877
+ * The outline is a derived progress view and the PG-13 input. Every write
1878
+ * path must stage a document the loader will accept; otherwise a successful
1879
+ * archive/planning call can leave the project with an unreadable outline and
1880
+ * an unreachable repair path. Auto-created cards are normalized by book.ts;
1881
+ * this is the final fail-closed boundary for all callers.
1882
+ */
1883
+ private assertOutlineWritable;
1884
+ /**
1885
+ * total_chapters is a hard ceiling everywhere: outline cards already enforce
1886
+ * it, and writing/archiving a chapter past it would make the auto-created
1887
+ * archived card invalid. Fail at the first stage instead of after the draft.
1888
+ */
1889
+ private assertChapterWithinTarget;
1890
+ /**
1891
+ * Without the chapter index, normalizeOutlineChapters cannot re-add archived
1892
+ * cards and cannot prove that a replacement did not delete them. Planning
1893
+ * writes must wait for a chapters repair; only novel_amend may repair it.
1894
+ */
1895
+ private assertArchiveIndexReadable;
1896
+ private bookStatus;
1330
1897
  private panelSnapshot;
1331
1898
  /**
1332
1899
  * The archive stage has only one legal operation, so a status/panel that
@@ -1340,6 +1907,8 @@ declare class EngineService {
1340
1907
  private roundsLimitBlock;
1341
1908
  /** Pipeline blockers plus budget exhaustion, so status/panel cannot say "all clear". */
1342
1909
  private effectiveBlocking;
1910
+ /** The PG-13 block that status must show before P2/P3 even tries to write. */
1911
+ private outlineGateBlock;
1343
1912
  /**
1344
1913
  * A review that exists but cannot be tied to the pipeline digest would let a
1345
1914
  * hand-edited review pass archive. Archive already fails closed; status and
@@ -1360,7 +1929,19 @@ declare class EngineService {
1360
1929
  private nextArgs;
1361
1930
  private metricsFor;
1362
1931
  private readChapter;
1932
+ /**
1933
+ * archive-digests.json is a derived mirror, not a source of truth. A damaged
1934
+ * mirror must never make every write unreachable; rebuild the missing rows
1935
+ * from the chapter index and let the next archive rewrite a valid file.
1936
+ */
1937
+ private readArchiveDigests;
1363
1938
  private latestBackup;
1939
+ /**
1940
+ * A manuscript export with an unreadable chapter index cannot prove which
1941
+ * chapters exist. Refusing is preferable to writing a short book that looks
1942
+ * complete; the repair path is novel_amend, not a silent partial export.
1943
+ */
1944
+ private assertExportIndexReadable;
1364
1945
  private chaptersForExport;
1365
1946
  private machine;
1366
1947
  private briefContextFor;
@@ -1375,6 +1956,10 @@ declare class EngineService {
1375
1956
  private assertGates;
1376
1957
  private assertChapterParameter;
1377
1958
  private assertChapter;
1959
+ /** True when anything survives in the project directory besides novel.yaml. */
1960
+ private projectStateExists;
1961
+ /** A live writer lock makes a read-only snapshot potentially torn. */
1962
+ private lockIsLive;
1378
1963
  private load;
1379
1964
  /** A repair may bypass the journal hash only when the document is unreadable. */
1380
1965
  private stateDocIsUnreadable;
@@ -1402,6 +1987,8 @@ declare function renderPlainText(project: NovelProject, chapters: readonly Expor
1402
1987
  declare function renderBlurb(project: NovelProject): string;
1403
1988
  /** Cover as a standalone SVG string; text is escaped, palette is theme-neutral. */
1404
1989
  declare function renderCover(project: NovelProject): string;
1990
+ /** A book-level proposal for editors, platforms and the author's own pitch. */
1991
+ declare function renderProposal(project: NovelProject, outline: OutlineDocument, worldbook: WorldbookDocument, chapters: readonly ChapterRecord[]): string;
1405
1992
  /** XHTML chapter document for the EPUB package. */
1406
1993
  declare function renderEpubChapter(chapter: ExportChapter): string;
1407
1994
  declare const name = "dsh-novel-write-engine";
@@ -1426,4 +2013,4 @@ declare const Config: Schema<Config>;
1426
2013
  * created lazily per project root.
1427
2014
  */
1428
2015
  declare function apply(ctx: Context, config: Config): void;
1429
- export { AdviceReport, ArchiveHandoff, AuditRow, BlockingItem, BriefDocument, BriefLibrary, BriefStage, ChapterCastMember, ChapterPlanInput, ChapterRecord, ChapterStatusRow, ChapterSummary, ChaptersDocument, CharacterDelta, CharactersDocument, CheckDocument, Config, Deduction, DeltaAction, DiffReport, DraftInput, ERROR_CODES, EngineBlockedError, EngineError, EngineFaultError, EngineInputError, EngineService, ErrorCode, ExportChapter, ExportKind, ForeshadowDelta, ForeshadowsDocument, GENRES, GateInput, GateOptions, GateResult, Genre, HandoffDocument, LocksDocument, MachineMetrics, NovelProject, OPERATIONS, OpResult, Operation, PLATFORMS, PanelChapterRow, PanelChaptersDto, PanelDraft, PanelGatesDto, PanelSnapshot, PanelSummaryDto, PipelineState, Platform, ReadingProof, ReadingProofReference, RelationshipDelta, RelationshipsDocument, ReviewDocument, ReviewInput, ReviewIssue, RevisionInput, RoundCounters, SCENE_TYPES, SCHEMA_VERSION, SceneType, ScoreDimension, SemanticItem, Severity, Stage, StateDelta, StateError, StateErrorCode, StatusReport, TimelineDelta, TimelineDocument, Violation, Warning, WordMetrics, WorldDelta, WorldDocument, WorldPlanInput, applicableGates, apply, blockedError, briefStageFor, chapterHeading, evaluateGates, faultError, gateName, inject, inputError, loadRulepack, name, parseParagraphLocation, phaseStrip, projectChapter, projectChapters, projectGates, projectSummary, renderBlurb, renderCover, renderEpubChapter, renderMarkdown, renderPlainText, verifyReference };
2016
+ export { AdviceReport, ArchiveHandoff, AuditRow, BlockingItem, BookPlan, BookReport, BriefDocument, BriefLibrary, BriefStage, ChapterCastMember, ChapterPlanInput, ChapterRecord, ChapterStatusRow, ChapterSummary, ChaptersDocument, CharacterDelta, CharactersDocument, CheckDocument, Config, Deduction, DeltaAction, DiffReport, DoctorCheck, DoctorReport, DraftInput, ERROR_CODES, EngineBlockedError, EngineError, EngineFaultError, EngineInputError, EngineService, ErrorCode, ExportChapter, ExportKind, ForeshadowDelta, ForeshadowsDocument, GENRES, GateInput, GateOptions, GateResult, Genre, GuideReport, GuideStep, HandoffDocument, LocksDocument, MachineMetrics, NovelProject, OPERATIONS, OpResult, Operation, OutlineChapter, OutlineDocument, OutlineVolume, PLATFORMS, PanelBook, PanelChapterRow, PanelChaptersDto, PanelDraft, PanelGatesDto, PanelSnapshot, PanelSummaryDto, PipelineState, Platform, ReadingProof, ReadingProofReference, RelationshipDelta, RelationshipsDocument, ReviewDocument, ReviewInput, ReviewIssue, RevisionInput, RoundCounters, SCENE_TYPES, SCHEMA_VERSION, SceneType, ScoreDimension, SearchReport, SearchResultItem, SemanticItem, Severity, Stage, StateDelta, StateError, StateErrorCode, StatusReport, TimelineDelta, TimelineDocument, Violation, Warning, WordMetrics, WorldDelta, WorldDocument, WorldPlanInput, WorldbookBackstory, WorldbookCharacter, WorldbookDocument, WorldbookFaction, WorldbookGlossary, WorldbookLocation, WorldbookRule, applicableGates, apply, blockedError, briefStageFor, chapterHeading, evaluateGates, faultError, gateName, inject, inputError, loadRulepack, name, parseParagraphLocation, phaseStrip, projectChapter, projectChapters, projectGates, projectSummary, renderBlurb, renderCover, renderEpubChapter, renderMarkdown, renderPlainText, renderProposal, verifyReference };