dsh-novel-write-engine 0.2.4 → 0.2.6

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
@@ -68,6 +68,9 @@ declare const ERROR_CODES: {
68
68
  /** The exact same keyed submission already failed in the same context. */
69
69
  readonly RETRY_UNCHANGED: "ENGINE_RETRY_UNCHANGED";
70
70
  readonly GATE_BLOCKED: "ENGINE_GATE_BLOCKED";
71
+ readonly CHECK_SUBMISSION_INVALID: "ENGINE_CHECK_SUBMISSION_INVALID";
72
+ readonly PENDING_PARTIAL: "ENGINE_PENDING_PARTIAL";
73
+ readonly IO_PERMISSION: "ENGINE_IO_PERMISSION";
71
74
  readonly READING_PROOF_INVALID: "ENGINE_READING_PROOF_INVALID";
72
75
  readonly SCORE_MISMATCH: "ENGINE_SCORE_MISMATCH";
73
76
  /** A revision tried to rewrite reviewer-owned issue fields. */
@@ -178,13 +181,18 @@ interface CheckDocument {
178
181
  evidence: string;
179
182
  note: string;
180
183
  }>;
184
+ /** 0.2.5: explain a persisted content failure; historical checks omit it. */
185
+ findings?: BlockingItem[];
181
186
  };
182
187
  /** Advisory codes the author has explicitly acknowledged for this content. */
183
188
  acknowledged?: string[];
189
+ /** 0.2.5: content failures consume the check budget; submission errors never persist. */
190
+ failure_class?: 'submission' | 'content';
191
+ counted?: boolean;
184
192
  verdict: 'pass' | 'fail';
185
193
  }
186
194
  /** Every persisted document whose damage status/panel can report. */
187
- 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';
195
+ type StateErrorCode = 'PROJECT_UNREADABLE' | 'PIPELINE_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';
188
196
  /** A state document that exists but cannot be read safely. */
189
197
  interface StateError {
190
198
  path: string;
@@ -255,6 +263,12 @@ interface ChapterSummary {
255
263
  abilities: string[];
256
264
  artifacts: string[];
257
265
  };
266
+ /** Optional P3/P5 verbatim manuscript anchors for readable entity names. */
267
+ new_element_anchors?: {
268
+ locations?: Record<string, string[]>;
269
+ abilities?: Record<string, string[]>;
270
+ artifacts?: Record<string, string[]>;
271
+ };
258
272
  resource_changes: Array<{
259
273
  character: string;
260
274
  resource: string;
@@ -423,6 +437,8 @@ interface WorldDocument {
423
437
  schema_version: 1;
424
438
  locations: Array<{
425
439
  name: string;
440
+ /** 0.2.6 additive: readable-name anchors; old ledgers omit this. */
441
+ anchors?: string[];
426
442
  first_appearance: number;
427
443
  locked: boolean;
428
444
  description: string;
@@ -785,6 +801,12 @@ interface BookReport {
785
801
  glossary: number;
786
802
  backstory: number;
787
803
  facts?: number;
804
+ /** 0.2.6 persisted world-ledger anchors, capped for report payloads. */
805
+ anchors?: Array<{
806
+ name: string;
807
+ kind: string;
808
+ anchors: string[];
809
+ }>;
788
810
  };
789
811
  quality: {
790
812
  average: number;
@@ -953,6 +975,10 @@ interface GateInput {
953
975
  summary: ChapterSummary | null;
954
976
  /** P5 may omit `summary`; when omitted, the previous plan summary is reused. */
955
977
  summaryProvided?: boolean;
978
+ /** Summary-only repair: no manuscript change, no P4/P6 proof requirement. */
979
+ summaryOnly?: boolean;
980
+ /** The last write was a summary-only repair; P6 may continue without a new brief. */
981
+ summaryOnlyRevision?: boolean;
956
982
  review: ReviewDocument | null;
957
983
  check: CheckDocument | null;
958
984
  /** When set, result-bearing gates run only the named check scopes. */
@@ -1030,6 +1056,8 @@ interface StatusReport {
1030
1056
  stage: Stage;
1031
1057
  rounds: RoundCounters;
1032
1058
  blocking: BlockingItem[];
1059
+ /** Non-blocking recovery notes, e.g. a recoverable pending transaction. */
1060
+ warnings?: Warning[];
1033
1061
  /** plan/review/check/ledger files that exist but cannot be read safely. */
1034
1062
  state_errors: StateError[];
1035
1063
  metrics: WordMetrics | null;
@@ -1122,6 +1150,39 @@ interface DiffReport {
1122
1150
  }
1123
1151
  /** Export capabilities; the last three are book-planning deliverables. */
1124
1152
  type ExportKind = 'md' | 'txt' | 'epub' | 'outline' | 'worldbook' | 'proposal';
1153
+ type SemanticItemState = 'pass' | 'fail' | 'missing' | 'invalid' | 'not_found' | 'too_short' | 'duplicate' | 'overlap' | 'same_sentence' | 'boundary';
1154
+ type SemanticConflictKind = 'duplicate' | 'same_sentence' | 'interval_overlap';
1155
+ interface SemanticConflict {
1156
+ kind: SemanticConflictKind;
1157
+ other_id: string;
1158
+ /** Only for interval_overlap; a verbatim excerpt, capped at 120 characters. */
1159
+ overlap_text?: string;
1160
+ overlap_chars?: number;
1161
+ /** overlap_chars / min(quoteA, quoteB), 0..1. */
1162
+ overlap_ratio?: number;
1163
+ paragraphs?: number[];
1164
+ /** Only for same_sentence. */
1165
+ sentence?: {
1166
+ id: number;
1167
+ text: string;
1168
+ paragraph: number;
1169
+ };
1170
+ }
1171
+ interface SemanticNearest {
1172
+ paragraph: number;
1173
+ quote: string;
1174
+ score: number;
1175
+ }
1176
+ interface SemanticItemResult {
1177
+ id: string;
1178
+ state: SemanticItemState;
1179
+ quote?: string;
1180
+ detail?: string;
1181
+ nearest?: SemanticNearest;
1182
+ /** Kept for older adapters; the full pair is in `conflicts`. */
1183
+ conflict_with?: string;
1184
+ conflicts?: SemanticConflict[];
1185
+ }
1125
1186
  /** One blacklisted word. */
1126
1187
  interface TermEntry {
1127
1188
  term: string;
@@ -1376,6 +1437,130 @@ declare function applicableGates(input: GateInput): GateId[];
1376
1437
  declare function gateName(id: GateId): string;
1377
1438
  /** Which brief stage an operation requires; `null` means no brief gate. */
1378
1439
  declare function briefStageFor(operation: GateInput['operation'], stage: Stage): GateInput['briefStage'];
1440
+ /** v6 read-only book data. All windows are explicit in the field names. */
1441
+ interface PanelCardData {
1442
+ num: number;
1443
+ title: string;
1444
+ scene_type: string;
1445
+ goal: string;
1446
+ conflict: string;
1447
+ hook: string;
1448
+ cast: string[];
1449
+ target_words: [number, number];
1450
+ status: 'planned' | 'archived';
1451
+ }
1452
+ interface PanelWorldEntry {
1453
+ name: string;
1454
+ description: string;
1455
+ anchors?: string[];
1456
+ }
1457
+ interface PanelBookData {
1458
+ identity: {
1459
+ author: string;
1460
+ description: string;
1461
+ created_at: string;
1462
+ targets: {
1463
+ words_per_chapter: [number, number];
1464
+ total_chapters: number | null;
1465
+ dialogue_ratio: [number, number];
1466
+ };
1467
+ };
1468
+ blueprint: {
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
+ };
1478
+ progress: {
1479
+ archived: number;
1480
+ target: number | null;
1481
+ words_archived: number;
1482
+ words_with_draft: number;
1483
+ average_words: number;
1484
+ remaining_words: number | null;
1485
+ remaining_words_basis: 'actual_average' | 'minimum_target' | 'none';
1486
+ percent: number;
1487
+ };
1488
+ current: {
1489
+ card: PanelCardData | null;
1490
+ chapter: number;
1491
+ stage: Stage;
1492
+ rounds: {
1493
+ review: number;
1494
+ revise: number;
1495
+ check: number;
1496
+ };
1497
+ manuscript_hash: string | null;
1498
+ metrics: WordMetrics | null;
1499
+ };
1500
+ worldbook: {
1501
+ counts: Omit<BookReport['worldbook'], 'anchors'>;
1502
+ locations: PanelWorldEntry[];
1503
+ factions: PanelWorldEntry[];
1504
+ rules: PanelWorldEntry[];
1505
+ facts: Array<{
1506
+ alias: string;
1507
+ value: number;
1508
+ unit: string;
1509
+ }>;
1510
+ };
1511
+ cast: {
1512
+ total: number;
1513
+ top: Array<{
1514
+ name: string;
1515
+ role: string;
1516
+ appearances: number;
1517
+ last_seen: number;
1518
+ }>;
1519
+ };
1520
+ relationships: {
1521
+ total: number;
1522
+ types: Record<string, number>;
1523
+ };
1524
+ foreshadows: BookReport['foreshadows'];
1525
+ timeline: BookReport['timeline'];
1526
+ outline: {
1527
+ drift: BookReport['outline']['drift'];
1528
+ };
1529
+ quality: {
1530
+ average: number;
1531
+ median: number;
1532
+ min: number;
1533
+ max: number;
1534
+ last_ten_average: number;
1535
+ trend: number | null;
1536
+ trend_basis: BookReport['quality']['trend_basis'];
1537
+ samples: number;
1538
+ attempts: number;
1539
+ dimensions: BookReport['quality']['dimensions'];
1540
+ };
1541
+ pacing: BookReport['pacing'];
1542
+ effort: BookReport['effort'];
1543
+ health: {
1544
+ state_errors: Array<{
1545
+ path: string;
1546
+ code: string;
1547
+ message: string;
1548
+ }>;
1549
+ outline: {
1550
+ present: boolean;
1551
+ error: string | null;
1552
+ };
1553
+ worldbook: {
1554
+ present: boolean;
1555
+ error: string | null;
1556
+ };
1557
+ pending: {
1558
+ state: string;
1559
+ txid: string;
1560
+ detail: string;
1561
+ } | null;
1562
+ };
1563
+ }
1379
1564
  /** The shared read model: everything the panel, status and commands render. */
1380
1565
  interface PanelDraft {
1381
1566
  num: number;
@@ -1434,6 +1619,7 @@ interface PanelSnapshot {
1434
1619
  ok: boolean;
1435
1620
  blocking: number;
1436
1621
  stateErrors: number;
1622
+ pending?: boolean;
1437
1623
  };
1438
1624
  activity?: Array<{
1439
1625
  at: string;
@@ -1454,6 +1640,14 @@ interface PanelSnapshot {
1454
1640
  code: string;
1455
1641
  detail: string;
1456
1642
  }>;
1643
+ /** Crash-left pending transaction; complete/untouched are warnings. */
1644
+ pending?: {
1645
+ state: string;
1646
+ txid: string;
1647
+ detail: string;
1648
+ };
1649
+ /** v6 read-only book data; v5 payloads omit it. */
1650
+ bookData?: PanelBookData;
1457
1651
  }
1458
1652
  interface PanelBook {
1459
1653
  premise: string;
@@ -1535,6 +1729,7 @@ interface PanelSummaryDto {
1535
1729
  ok: boolean;
1536
1730
  blocking: number;
1537
1731
  stateErrors: number;
1732
+ pending?: boolean;
1538
1733
  };
1539
1734
  activity?: Array<{
1540
1735
  at: string;
@@ -1555,6 +1750,14 @@ interface PanelSummaryDto {
1555
1750
  code: string;
1556
1751
  detail: string;
1557
1752
  }>;
1753
+ /** Crash-left pending transaction; complete/untouched are warnings. */
1754
+ pending?: {
1755
+ state: string;
1756
+ txid: string;
1757
+ detail: string;
1758
+ };
1759
+ /** v6 read-only book data; v5 payloads omit it. */
1760
+ bookData?: PanelBookData;
1558
1761
  }
1559
1762
  interface PanelChapterRow {
1560
1763
  num: number;
@@ -1565,6 +1768,15 @@ interface PanelChapterRow {
1565
1768
  status: 'passed' | 'blocked' | 'draft';
1566
1769
  /** One-line summary shown when the row is expanded. */
1567
1770
  details: string;
1771
+ sceneType?: string;
1772
+ dialogueRatio?: number;
1773
+ hookStrength?: number;
1774
+ finalCheck?: 'pass' | 'fail' | null;
1775
+ reviews?: number;
1776
+ revisions?: number;
1777
+ checks?: number;
1778
+ rollbacks?: number;
1779
+ archivedAt?: string | null;
1568
1780
  }
1569
1781
  interface PanelChaptersDto {
1570
1782
  schemaVersion: number;
@@ -1784,8 +1996,8 @@ interface RevisionSubmission extends Omit<RevisionInput, 'summary'> {
1784
1996
  summary?: ChapterSummary;
1785
1997
  /** Updated issue statuses/evidence; the review document is patched in place. */
1786
1998
  issues?: ReviewDocument['issues'];
1787
- /** Proof that the revised text was read; PG-09 verifies it against the new text. */
1788
- proof: ReadingProof;
1999
+ /** Proof that the revised text was read; required for content/patch revisions. */
2000
+ proof?: ReadingProof;
1789
2001
  root?: string;
1790
2002
  }
1791
2003
  interface CheckSubmission {
@@ -1875,6 +2087,7 @@ interface OutlineMutationResult {
1875
2087
  volumes: number;
1876
2088
  added: number[];
1877
2089
  updated: number[];
2090
+ reindexed: number[];
1878
2091
  removed: number[];
1879
2092
  volumes_added: string[];
1880
2093
  volumes_updated: string[];
@@ -1882,6 +2095,7 @@ interface OutlineMutationResult {
1882
2095
  dry_run?: boolean;
1883
2096
  would_add?: number[];
1884
2097
  would_update?: number[];
2098
+ would_reindex?: number[];
1885
2099
  would_remove?: number[];
1886
2100
  }
1887
2101
  interface OutlineSubmission extends OutlineInput {
@@ -1931,8 +2145,12 @@ declare class EngineService {
1931
2145
  private readonly stores;
1932
2146
  private readonly mutex;
1933
2147
  private readonly replay;
2148
+ /** Bumped when an export artifact disappeared; makes the replay key miss. */
2149
+ private readonly exportArtifactEpoch;
1934
2150
  /** Status, panel and gates ask for the same stage context repeatedly. */
1935
2151
  private readonly briefContextCache;
2152
+ /** The 15s panel poll reuses the heavy book projection until revision/damage changes. */
2153
+ private readonly panelCache;
1936
2154
  private readonly briefs;
1937
2155
  private readonly now;
1938
2156
  private readonly metadataMutex;
@@ -2126,6 +2344,8 @@ declare class EngineService {
2126
2344
  chapter: number;
2127
2345
  stage: Stage;
2128
2346
  metrics: WordMetrics;
2347
+ summary_only?: boolean;
2348
+ rounds_consumed?: 0 | 1;
2129
2349
  }>>;
2130
2350
  runCheck(input: CheckSubmission): Promise<OpResult<{
2131
2351
  chapter: number;
@@ -2136,12 +2356,26 @@ declare class EngineService {
2136
2356
  acknowledged: string[];
2137
2357
  metrics: WordMetrics;
2138
2358
  stage: Stage;
2359
+ semantic: {
2360
+ items: SemanticItemResult[];
2361
+ findings: BlockingItem[];
2362
+ };
2363
+ rounds: {
2364
+ check: number;
2365
+ };
2366
+ counted: boolean;
2139
2367
  }>>;
2140
2368
  archiveChapter(input: ArchiveSubmission): Promise<OpResult<{
2141
2369
  chapter: number;
2142
2370
  assigned_ids: Record<string, string>;
2143
2371
  metrics: WordMetrics;
2144
2372
  score: number;
2373
+ delta_warnings?: Warning[];
2374
+ normalized_world?: Record<string, {
2375
+ from: 'created' | 'updated' | 'no_change';
2376
+ to: 'created' | 'updated' | 'no_change';
2377
+ reason: 'existing-created-as-updated' | 'missing-updated-as-created' | 'missing-no-change-as-created';
2378
+ }>;
2145
2379
  }>>;
2146
2380
  amend(input: AmendSubmission): Promise<OpResult<{
2147
2381
  path: string;
@@ -2320,6 +2554,12 @@ declare class EngineService {
2320
2554
  * could not read.
2321
2555
  */
2322
2556
  private assertPlanningDocumentReadable;
2557
+ /**
2558
+ * `strict_explicit` is an internal provenance bit, not an author choice.
2559
+ * Exposing it lets a caller forge "the author chose strict:false" without
2560
+ * going through the strict option. Stored documents may still contain it.
2561
+ */
2562
+ private assertPublicBookHasNoStrictExplicit;
2323
2563
  /**
2324
2564
  * An import is a full replacement, unlike novel_outline's keyed upsert. It
2325
2565
  * must not silently lose the active card while strict mode still requires it.
@@ -2432,7 +2672,7 @@ declare const PLUGIN_NAME = "dsh-novel-write-engine";
2432
2672
  declare const PANEL_ID = "novel-workshop";
2433
2673
  declare const PANEL_ROUTE = "/api/novel-write-engine/panel";
2434
2674
  declare const SKILL_NAME = "novel-write-engine";
2435
- declare const REMOTE_VERSION = 5;
2675
+ declare const REMOTE_VERSION = 6;
2436
2676
  /** The panel is a recent-history view; the wire payload and UI use one cap. */
2437
2677
  declare const PANEL_CHAPTER_LIMIT = 30;
2438
2678
  /** Project-relative locations. Every write goes through these constants. */