novel-writer-cli 0.0.1

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.
Files changed (116) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +103 -0
  3. package/agents/chapter-writer.md +142 -0
  4. package/agents/character-weaver.md +117 -0
  5. package/agents/consistency-auditor.md +85 -0
  6. package/agents/plot-architect.md +128 -0
  7. package/agents/quality-judge.md +232 -0
  8. package/agents/style-analyzer.md +109 -0
  9. package/agents/style-refiner.md +97 -0
  10. package/agents/summarizer.md +128 -0
  11. package/agents/world-builder.md +161 -0
  12. package/dist/__tests__/character-voice.test.js +445 -0
  13. package/dist/__tests__/commit-prototype-pollution.test.js +45 -0
  14. package/dist/__tests__/engagement.test.js +382 -0
  15. package/dist/__tests__/foreshadow-visibility.test.js +131 -0
  16. package/dist/__tests__/hook-ledger.test.js +1028 -0
  17. package/dist/__tests__/naming-lint.test.js +132 -0
  18. package/dist/__tests__/narrative-health-injection.test.js +359 -0
  19. package/dist/__tests__/next-step-prejudge-guardrails.test.js +325 -0
  20. package/dist/__tests__/next-step-title-fix.test.js +153 -0
  21. package/dist/__tests__/platform-profile.test.js +274 -0
  22. package/dist/__tests__/promise-ledger.test.js +189 -0
  23. package/dist/__tests__/readability-lint.test.js +209 -0
  24. package/dist/__tests__/text-utils.test.js +39 -0
  25. package/dist/__tests__/title-policy.test.js +147 -0
  26. package/dist/advance.js +75 -0
  27. package/dist/character-voice.js +805 -0
  28. package/dist/checkpoint.js +126 -0
  29. package/dist/cli.js +563 -0
  30. package/dist/cliche-lint.js +515 -0
  31. package/dist/commit.js +1460 -0
  32. package/dist/consistency-auditor.js +684 -0
  33. package/dist/engagement.js +687 -0
  34. package/dist/errors.js +7 -0
  35. package/dist/fingerprint.js +16 -0
  36. package/dist/foreshadow-visibility.js +214 -0
  37. package/dist/fs-utils.js +68 -0
  38. package/dist/hook-ledger.js +721 -0
  39. package/dist/hook-policy.js +107 -0
  40. package/dist/instruction-gates.js +51 -0
  41. package/dist/instructions.js +406 -0
  42. package/dist/latest-summary-loader.js +29 -0
  43. package/dist/lock.js +121 -0
  44. package/dist/naming-lint.js +531 -0
  45. package/dist/ner.js +73 -0
  46. package/dist/next-step.js +408 -0
  47. package/dist/novel-ask.js +270 -0
  48. package/dist/output.js +9 -0
  49. package/dist/platform-constraints.js +518 -0
  50. package/dist/platform-profile.js +325 -0
  51. package/dist/prejudge-guardrails.js +370 -0
  52. package/dist/project.js +40 -0
  53. package/dist/promise-ledger.js +723 -0
  54. package/dist/readability-lint.js +555 -0
  55. package/dist/safe-parse.js +36 -0
  56. package/dist/safe-path.js +29 -0
  57. package/dist/scoring-weights.js +290 -0
  58. package/dist/steps.js +60 -0
  59. package/dist/text-utils.js +18 -0
  60. package/dist/title-policy.js +251 -0
  61. package/dist/type-guards.js +6 -0
  62. package/dist/validate.js +131 -0
  63. package/docs/user/README.md +17 -0
  64. package/docs/user/guardrails.md +179 -0
  65. package/docs/user/interactive-gates.md +124 -0
  66. package/docs/user/novel-cli.md +289 -0
  67. package/docs/user/ops.md +123 -0
  68. package/docs/user/quick-start.md +97 -0
  69. package/docs/user/spec-system.md +166 -0
  70. package/docs/user/storylines.md +144 -0
  71. package/package.json +48 -0
  72. package/schemas/README.md +18 -0
  73. package/schemas/character-voice-drift.schema.json +135 -0
  74. package/schemas/character-voice-profiles.schema.json +141 -0
  75. package/schemas/engagement-metrics.schema.json +38 -0
  76. package/schemas/hook-ledger.schema.json +108 -0
  77. package/schemas/platform-profile.schema.json +235 -0
  78. package/schemas/promise-ledger.schema.json +97 -0
  79. package/scripts/calibrate-quality-judge.sh +91 -0
  80. package/scripts/compare-regression-runs.sh +86 -0
  81. package/scripts/lib/_common.py +131 -0
  82. package/scripts/lib/calibrate_quality_judge.py +312 -0
  83. package/scripts/lib/compare_regression_runs.py +142 -0
  84. package/scripts/lib/run_regression.py +621 -0
  85. package/scripts/lint-blacklist.sh +201 -0
  86. package/scripts/lint-cliche.sh +370 -0
  87. package/scripts/lint-readability.sh +404 -0
  88. package/scripts/query-foreshadow.sh +252 -0
  89. package/scripts/run-ner.sh +669 -0
  90. package/scripts/run-regression.sh +122 -0
  91. package/skills/cli-step/SKILL.md +158 -0
  92. package/skills/continue/SKILL.md +348 -0
  93. package/skills/continue/references/context-contracts.md +169 -0
  94. package/skills/continue/references/continuity-checks.md +187 -0
  95. package/skills/continue/references/file-protocols.md +64 -0
  96. package/skills/continue/references/foreshadowing.md +130 -0
  97. package/skills/continue/references/gate-decision.md +53 -0
  98. package/skills/continue/references/periodic-maintenance.md +46 -0
  99. package/skills/novel-writing/SKILL.md +77 -0
  100. package/skills/novel-writing/references/quality-rubric.md +140 -0
  101. package/skills/novel-writing/references/style-guide.md +145 -0
  102. package/skills/start/SKILL.md +458 -0
  103. package/skills/start/references/quality-review.md +86 -0
  104. package/skills/start/references/setting-update.md +44 -0
  105. package/skills/start/references/vol-planning.md +61 -0
  106. package/skills/start/references/vol-review.md +58 -0
  107. package/skills/status/SKILL.md +116 -0
  108. package/skills/status/references/sample-output.md +60 -0
  109. package/templates/ai-blacklist.json +79 -0
  110. package/templates/brief-template.md +46 -0
  111. package/templates/genre-weight-profiles.json +90 -0
  112. package/templates/novel-ask/example.answer.json +12 -0
  113. package/templates/novel-ask/example.question.json +51 -0
  114. package/templates/platform-profile.json +148 -0
  115. package/templates/style-profile-template.json +58 -0
  116. package/templates/web-novel-cliche-lint.json +41 -0
@@ -0,0 +1,126 @@
1
+ import { join } from "node:path";
2
+ import { NovelCliError } from "./errors.js";
3
+ import { readJsonFile, writeJsonFile } from "./fs-utils.js";
4
+ import { isPlainObject } from "./type-guards.js";
5
+ export const PIPELINE_STAGES = ["drafting", "drafted", "refined", "judged", "revising", "committed"];
6
+ function asInt(value) {
7
+ if (typeof value !== "number")
8
+ return null;
9
+ if (!Number.isInteger(value))
10
+ return null;
11
+ return value;
12
+ }
13
+ function asString(value) {
14
+ if (typeof value !== "string")
15
+ return null;
16
+ return value;
17
+ }
18
+ function asNullableInt(value) {
19
+ if (value === undefined)
20
+ return undefined;
21
+ if (value === null)
22
+ return null;
23
+ return asInt(value);
24
+ }
25
+ function parseCheckpoint(data) {
26
+ if (!isPlainObject(data)) {
27
+ throw new NovelCliError(".checkpoint.json must be a JSON object.", 2);
28
+ }
29
+ const lastCompleted = asInt(data.last_completed_chapter);
30
+ if (lastCompleted === null || lastCompleted < 0) {
31
+ throw new NovelCliError(".checkpoint.json.last_completed_chapter must be an int >= 0.", 2);
32
+ }
33
+ const currentVolume = asInt(data.current_volume);
34
+ if (currentVolume === null || currentVolume < 0) {
35
+ throw new NovelCliError(".checkpoint.json.current_volume must be an int >= 0.", 2);
36
+ }
37
+ const orchestratorState = data.orchestrator_state;
38
+ if (orchestratorState !== undefined && asString(orchestratorState) === null) {
39
+ throw new NovelCliError(".checkpoint.json.orchestrator_state must be a string when present.", 2);
40
+ }
41
+ const pipelineStageRaw = data.pipeline_stage;
42
+ let pipelineStage;
43
+ if (pipelineStageRaw === undefined) {
44
+ pipelineStage = undefined;
45
+ }
46
+ else if (pipelineStageRaw === null) {
47
+ pipelineStage = null;
48
+ }
49
+ else if (typeof pipelineStageRaw === "string") {
50
+ if (PIPELINE_STAGES.includes(pipelineStageRaw)) {
51
+ pipelineStage = pipelineStageRaw;
52
+ }
53
+ else {
54
+ throw new NovelCliError(`.checkpoint.json.pipeline_stage must be one of: ${PIPELINE_STAGES.join(", ")} (or null)`, 2);
55
+ }
56
+ }
57
+ else {
58
+ throw new NovelCliError(`.checkpoint.json.pipeline_stage must be a string (or null)`, 2);
59
+ }
60
+ const inflightRaw = data.inflight_chapter;
61
+ const inflight = asNullableInt(inflightRaw);
62
+ if (inflightRaw !== undefined && inflight === null && inflightRaw !== null) {
63
+ throw new NovelCliError(".checkpoint.json.inflight_chapter must be an int >= 0 (or null).", 2);
64
+ }
65
+ if (inflight !== undefined && inflight !== null && inflight < 0) {
66
+ throw new NovelCliError(".checkpoint.json.inflight_chapter must be an int >= 0 (or null).", 2);
67
+ }
68
+ const revision = data.revision_count;
69
+ if (revision !== undefined) {
70
+ const rc = asInt(revision);
71
+ if (rc === null || rc < 0) {
72
+ throw new NovelCliError(".checkpoint.json.revision_count must be an int >= 0 when present.", 2);
73
+ }
74
+ }
75
+ const hookFix = data.hook_fix_count;
76
+ if (hookFix !== undefined) {
77
+ const hc = asInt(hookFix);
78
+ if (hc === null || hc < 0) {
79
+ throw new NovelCliError(".checkpoint.json.hook_fix_count must be an int >= 0 when present.", 2);
80
+ }
81
+ }
82
+ const titleFix = data.title_fix_count;
83
+ if (titleFix !== undefined) {
84
+ const tc = asInt(titleFix);
85
+ if (tc === null || tc < 0) {
86
+ throw new NovelCliError(".checkpoint.json.title_fix_count must be an int >= 0 when present.", 2);
87
+ }
88
+ }
89
+ const pending = data.pending_actions;
90
+ if (pending !== undefined && !Array.isArray(pending)) {
91
+ throw new NovelCliError(".checkpoint.json.pending_actions must be an array when present.", 2);
92
+ }
93
+ const lastTime = data.last_checkpoint_time;
94
+ if (lastTime !== undefined && asString(lastTime) === null) {
95
+ throw new NovelCliError(".checkpoint.json.last_checkpoint_time must be a string when present.", 2);
96
+ }
97
+ const checkpoint = {
98
+ ...data,
99
+ last_completed_chapter: lastCompleted,
100
+ current_volume: currentVolume
101
+ };
102
+ if (orchestratorState !== undefined)
103
+ checkpoint.orchestrator_state = orchestratorState;
104
+ if (pipelineStage !== undefined)
105
+ checkpoint.pipeline_stage = pipelineStage;
106
+ if (inflight !== undefined)
107
+ checkpoint.inflight_chapter = inflight;
108
+ return checkpoint;
109
+ }
110
+ export async function readCheckpoint(projectRootDir) {
111
+ const checkpointPath = join(projectRootDir, ".checkpoint.json");
112
+ const raw = await readJsonFile(checkpointPath);
113
+ try {
114
+ return parseCheckpoint(raw);
115
+ }
116
+ catch (err) {
117
+ if (err instanceof NovelCliError)
118
+ throw err;
119
+ const message = err instanceof Error ? err.message : String(err);
120
+ throw new NovelCliError(`Invalid checkpoint: ${message}`, 2);
121
+ }
122
+ }
123
+ export async function writeCheckpoint(projectRootDir, checkpoint) {
124
+ const checkpointPath = join(projectRootDir, ".checkpoint.json");
125
+ await writeJsonFile(checkpointPath, checkpoint);
126
+ }