dsh-novel-write-engine 0.2.7 → 0.2.9
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/CHANGELOG.md +42 -0
- package/README.md +27 -23
- package/briefs/P3.md +1 -0
- package/briefs/P4.md +1 -1
- package/briefs/P8.md +1 -1
- package/lib/client.js +928 -125
- package/lib/index.d.ts +151 -10
- package/lib/index.js +1498 -262
- package/lib/types/client/dto.d.ts +32 -9
- package/lib/types/client/panel.d.ts +19 -1
- package/lib/types/client/viewmodel.d.ts +13 -4
- package/lib/types/constants.d.ts +2 -0
- package/lib/types/panel-contract.d.ts +2 -2
- package/lib/types/types.d.ts +55 -2
- package/package.json +8 -3
- package/presets/novel-write-engine.patch.yml +4 -0
- package/rulepacks/default.yaml +13 -5
- package/skills/entry.md +2 -1
|
@@ -11,6 +11,23 @@ export interface BlockingDto {
|
|
|
11
11
|
detail: string;
|
|
12
12
|
hint?: string;
|
|
13
13
|
}
|
|
14
|
+
/** Chapter-boundary projection; absent on older payloads. */
|
|
15
|
+
export interface ProgressDto {
|
|
16
|
+
active_chapter: number;
|
|
17
|
+
stage: string;
|
|
18
|
+
current: {
|
|
19
|
+
chapter: number;
|
|
20
|
+
stage: string;
|
|
21
|
+
} | null;
|
|
22
|
+
last_archived: number | null;
|
|
23
|
+
next: {
|
|
24
|
+
chapter: number;
|
|
25
|
+
stage: 'P1';
|
|
26
|
+
} | null;
|
|
27
|
+
finished: boolean;
|
|
28
|
+
label: string;
|
|
29
|
+
resume: string;
|
|
30
|
+
}
|
|
14
31
|
export interface SummaryDto {
|
|
15
32
|
schemaVersion: number;
|
|
16
33
|
panelId: string;
|
|
@@ -21,8 +38,11 @@ export interface SummaryDto {
|
|
|
21
38
|
platform: string;
|
|
22
39
|
chapter: number;
|
|
23
40
|
stage: string;
|
|
41
|
+
progress?: ProgressDto;
|
|
24
42
|
revision: number;
|
|
25
43
|
totalWords: number;
|
|
44
|
+
archivedWords?: number;
|
|
45
|
+
draftWords?: number;
|
|
26
46
|
totalChapters: number;
|
|
27
47
|
/** Book-wide archived average; absent on older payloads. */
|
|
28
48
|
averageScore?: number;
|
|
@@ -75,6 +95,7 @@ export interface SummaryDto {
|
|
|
75
95
|
};
|
|
76
96
|
quality?: {
|
|
77
97
|
averageScore: number;
|
|
98
|
+
last_ten_average?: number | null;
|
|
78
99
|
scores: number[];
|
|
79
100
|
trend: number | null;
|
|
80
101
|
trend_basis?: 'last_five_vs_previous_five' | 'insufficient_samples' | 'insufficient_history';
|
|
@@ -117,7 +138,7 @@ export interface ChapterRowDto {
|
|
|
117
138
|
num: number;
|
|
118
139
|
title: string;
|
|
119
140
|
wordCount: number;
|
|
120
|
-
score: number;
|
|
141
|
+
score: number | null;
|
|
121
142
|
stage: string;
|
|
122
143
|
status: 'passed' | 'blocked' | 'draft';
|
|
123
144
|
details?: string;
|
|
@@ -136,13 +157,6 @@ export interface ChaptersDto {
|
|
|
136
157
|
panelId: string;
|
|
137
158
|
rows: ChapterRowDto[];
|
|
138
159
|
}
|
|
139
|
-
export interface GatesDto {
|
|
140
|
-
schemaVersion: number;
|
|
141
|
-
panelId: string;
|
|
142
|
-
stage: string;
|
|
143
|
-
blocking: BlockingDto[];
|
|
144
|
-
explanations: string[];
|
|
145
|
-
}
|
|
146
160
|
export interface ProjectOptionDto {
|
|
147
161
|
root: string;
|
|
148
162
|
title: string;
|
|
@@ -168,11 +182,20 @@ export interface PanelPayloadDto {
|
|
|
168
182
|
selection: PanelSelectionDto;
|
|
169
183
|
summary?: SummaryDto;
|
|
170
184
|
chapters?: ChaptersDto;
|
|
171
|
-
gates?: GatesDto;
|
|
172
185
|
resume?: {
|
|
173
186
|
text: string;
|
|
174
187
|
};
|
|
175
188
|
missing?: PanelMissingDto;
|
|
176
189
|
error?: string;
|
|
177
190
|
empty?: true;
|
|
191
|
+
/** Additive v7 section payload. */
|
|
192
|
+
payload_version?: 7;
|
|
193
|
+
section?: string;
|
|
194
|
+
items?: unknown;
|
|
195
|
+
total?: number;
|
|
196
|
+
returned?: number;
|
|
197
|
+
truncated?: boolean;
|
|
198
|
+
next_cursor?: string | null;
|
|
199
|
+
updated_at?: string;
|
|
200
|
+
etag?: string;
|
|
178
201
|
}
|
|
@@ -1,10 +1,28 @@
|
|
|
1
1
|
import { type ReactElement } from 'react';
|
|
2
2
|
import { buildView, type PanelView } from './viewmodel.js';
|
|
3
|
+
import type { PanelPayloadDto } from './dto.js';
|
|
4
|
+
export type PanelTab = 'overview' | 'chapters' | 'characters' | 'foreshadows' | 'worldbook' | 'quality' | 'health';
|
|
5
|
+
export interface PanelSectionState {
|
|
6
|
+
loading: boolean;
|
|
7
|
+
error: string | null;
|
|
8
|
+
payload: PanelPayloadDto | null;
|
|
9
|
+
}
|
|
10
|
+
export interface ChapterQuery {
|
|
11
|
+
search: string;
|
|
12
|
+
status: 'all' | 'archived' | 'draft';
|
|
13
|
+
scene: string;
|
|
14
|
+
sort: 'num_asc' | 'num_desc';
|
|
15
|
+
cursor: string;
|
|
16
|
+
}
|
|
17
|
+
export interface ChapterDetailState {
|
|
18
|
+
chapter: number;
|
|
19
|
+
section: PanelSectionState;
|
|
20
|
+
}
|
|
3
21
|
/**
|
|
4
22
|
* Pure view: given a view model, return the element tree. Keeping the hooks in
|
|
5
23
|
* `NovelPanel` makes every visual state renderable without a browser.
|
|
6
24
|
*/
|
|
7
|
-
export declare function panelElement(view: PanelView, loading: boolean, onRefresh: () => void, onSelectProject?: (root: string | null) => void): ReactElement;
|
|
25
|
+
export declare function panelElement(view: PanelView, loading: boolean, onRefresh: () => void, onSelectProject?: (root: string | null) => void, tab?: PanelTab, onTab?: (tab: PanelTab) => void, section?: PanelSectionState | null, chapterQuery?: ChapterQuery, onChapterQuery?: (patch: Partial<ChapterQuery>) => void, sectionSearch?: string, onSectionSearch?: (value: string) => void, chapterDetail?: ChapterDetailState | null, onChapterDetail?: (chapter: number | null) => void, qualityDetail?: ChapterDetailState | null, onQualityDetail?: (chapter: number | null) => void): ReactElement;
|
|
8
26
|
/** Stateful wrapper: fetch once, refresh on demand and after returning to the tab. */
|
|
9
27
|
export declare function NovelPanel(): ReactElement;
|
|
10
28
|
/** Sidebar icon: a small book mark, inheriting the current text colour. */
|
|
@@ -14,8 +14,8 @@ export interface PanelChapter {
|
|
|
14
14
|
words: string;
|
|
15
15
|
wordCount: number;
|
|
16
16
|
score: string;
|
|
17
|
-
scoreValue: number;
|
|
18
|
-
scorePercent: number;
|
|
17
|
+
scoreValue: number | null;
|
|
18
|
+
scorePercent: number | null;
|
|
19
19
|
badge: string;
|
|
20
20
|
tone: 'ok' | 'bad' | 'muted';
|
|
21
21
|
details: string;
|
|
@@ -69,6 +69,8 @@ export interface PanelView {
|
|
|
69
69
|
stageLabel: string;
|
|
70
70
|
/** The whole book reached its configured target; stage `done` alone is only one chapter. */
|
|
71
71
|
finished: boolean;
|
|
72
|
+
/** Active chapter number for lazy quality detail. */
|
|
73
|
+
chapter: number;
|
|
72
74
|
revisionLabel: string;
|
|
73
75
|
phases: PanelPhase[];
|
|
74
76
|
rows: PanelChapter[];
|
|
@@ -82,6 +84,8 @@ export interface PanelView {
|
|
|
82
84
|
stats: {
|
|
83
85
|
chapters: number;
|
|
84
86
|
words: number;
|
|
87
|
+
archivedWords?: number;
|
|
88
|
+
draftWords?: number;
|
|
85
89
|
averageScore: number;
|
|
86
90
|
blocking: number;
|
|
87
91
|
};
|
|
@@ -117,7 +121,7 @@ export interface PanelView {
|
|
|
117
121
|
};
|
|
118
122
|
quality: {
|
|
119
123
|
averageScore: number;
|
|
120
|
-
lastTenAverage: number;
|
|
124
|
+
lastTenAverage: number | null;
|
|
121
125
|
bookMedian: number;
|
|
122
126
|
bookMin: number;
|
|
123
127
|
bookMax: number;
|
|
@@ -125,6 +129,7 @@ export interface PanelView {
|
|
|
125
129
|
id: string;
|
|
126
130
|
average: number;
|
|
127
131
|
samples: number;
|
|
132
|
+
max?: number;
|
|
128
133
|
}>;
|
|
129
134
|
scores: number[];
|
|
130
135
|
trend: number | null;
|
|
@@ -169,6 +174,9 @@ export interface PanelView {
|
|
|
169
174
|
nextDetail: string;
|
|
170
175
|
nextTool: string;
|
|
171
176
|
emptyCommand: string;
|
|
177
|
+
/** Last successful sync / last background failure; filled by NovelPanel. */
|
|
178
|
+
lastSync?: string | null;
|
|
179
|
+
syncError?: string | null;
|
|
172
180
|
/** Compatibility fields used by older cards and tests. */
|
|
173
181
|
revision: string;
|
|
174
182
|
next: string;
|
|
@@ -181,7 +189,8 @@ export declare const PANEL_SCHEMA_VERSION = 6;
|
|
|
181
189
|
*/
|
|
182
190
|
export declare function buildView(payload: PanelPayloadDto | null, error?: string | null): PanelView;
|
|
183
191
|
/** Fetch the panel payload; failures become a plain message, never a throw. */
|
|
184
|
-
export declare function fetchPanel(fetcher: typeof fetch, path: string, signal?: AbortSignal): Promise<{
|
|
192
|
+
export declare function fetchPanel(fetcher: typeof fetch, path: string, signal?: AbortSignal, etag?: string): Promise<{
|
|
185
193
|
payload: PanelPayloadDto | null;
|
|
186
194
|
error: string | null;
|
|
195
|
+
notModified?: boolean;
|
|
187
196
|
}>;
|
package/lib/types/constants.d.ts
CHANGED
|
@@ -5,6 +5,8 @@ export declare const PANEL_ID = "novel-workshop";
|
|
|
5
5
|
export declare const PANEL_ROUTE = "/api/novel-write-engine/panel";
|
|
6
6
|
export declare const SKILL_NAME = "novel-write-engine";
|
|
7
7
|
export declare const REMOTE_VERSION = 6;
|
|
8
|
+
/** User-visible panel/tutorial version; keep in sync with package.json. */
|
|
9
|
+
export declare const PANEL_VERSION = "0.2.9";
|
|
8
10
|
/** The panel is a recent-history view; the wire payload and UI use one cap. */
|
|
9
11
|
export declare const PANEL_CHAPTER_LIMIT = 30;
|
|
10
12
|
/** Project-relative locations. Every write goes through these constants. */
|
|
@@ -45,7 +45,7 @@ export interface PanelBookData {
|
|
|
45
45
|
average_words: number;
|
|
46
46
|
remaining_words: number | null;
|
|
47
47
|
remaining_words_basis: 'actual_average' | 'minimum_target' | 'none';
|
|
48
|
-
percent: number;
|
|
48
|
+
percent: number | null;
|
|
49
49
|
};
|
|
50
50
|
current: {
|
|
51
51
|
card: PanelCardData | null;
|
|
@@ -93,7 +93,7 @@ export interface PanelBookData {
|
|
|
93
93
|
median: number;
|
|
94
94
|
min: number;
|
|
95
95
|
max: number;
|
|
96
|
-
last_ten_average: number;
|
|
96
|
+
last_ten_average: number | null;
|
|
97
97
|
trend: number | null;
|
|
98
98
|
trend_basis: BookReport['quality']['trend_basis'];
|
|
99
99
|
samples: number;
|
package/lib/types/types.d.ts
CHANGED
|
@@ -217,6 +217,18 @@ export interface WordMetrics {
|
|
|
217
217
|
paragraph_count: number;
|
|
218
218
|
paragraph_max_words: number;
|
|
219
219
|
}
|
|
220
|
+
/** Protected evidence copied from the archived outline card at archive time. */
|
|
221
|
+
export interface ArchivedCardSnapshot {
|
|
222
|
+
title: string;
|
|
223
|
+
scene_type: SceneType;
|
|
224
|
+
target_words: [number, number];
|
|
225
|
+
cast: string[];
|
|
226
|
+
goal: string;
|
|
227
|
+
conflict: string;
|
|
228
|
+
hook: string;
|
|
229
|
+
notes: string;
|
|
230
|
+
archived_at: string | null;
|
|
231
|
+
}
|
|
220
232
|
/** Derived chapter row kept in `state/chapters.yaml`. */
|
|
221
233
|
export interface ChapterRecord {
|
|
222
234
|
num: number;
|
|
@@ -239,6 +251,10 @@ export interface ChapterRecord {
|
|
|
239
251
|
assigned_ids?: Record<string, string>;
|
|
240
252
|
/** Digest of the archive request that produced this row. */
|
|
241
253
|
archive_digest?: string;
|
|
254
|
+
/** Immutable card fields written by the archive transaction, not by amend. */
|
|
255
|
+
archive_card?: ArchivedCardSnapshot;
|
|
256
|
+
/** Canonical digest of archive_card; v1-prefixed like archive_digest. */
|
|
257
|
+
archive_card_digest?: string;
|
|
242
258
|
}
|
|
243
259
|
/** Summary block the model supplies with a draft and the engine persists. */
|
|
244
260
|
export interface ChapterSummary {
|
|
@@ -301,8 +317,8 @@ export interface CharacterDelta {
|
|
|
301
317
|
role?: string;
|
|
302
318
|
profile?: Record<string, unknown>;
|
|
303
319
|
current_state?: Record<string, unknown>;
|
|
320
|
+
/** Chapter is engine-assigned from the archive transaction, not caller-supplied. */
|
|
304
321
|
growth?: {
|
|
305
|
-
chapter: number;
|
|
306
322
|
change: string;
|
|
307
323
|
status_change: string;
|
|
308
324
|
};
|
|
@@ -760,7 +776,7 @@ export interface BookReport {
|
|
|
760
776
|
target: number | null;
|
|
761
777
|
words: number;
|
|
762
778
|
average_words: number;
|
|
763
|
-
percent: number;
|
|
779
|
+
percent: number | null;
|
|
764
780
|
remaining_words: number | null;
|
|
765
781
|
remaining_words_min: number | null;
|
|
766
782
|
remaining_words_average: number | null;
|
|
@@ -825,6 +841,7 @@ export interface BookReport {
|
|
|
825
841
|
id: string;
|
|
826
842
|
average: number;
|
|
827
843
|
samples: number;
|
|
844
|
+
max: number;
|
|
828
845
|
}>;
|
|
829
846
|
};
|
|
830
847
|
/** Per-chapter effort survives archive (pipeline rounds are reset). */
|
|
@@ -972,6 +989,8 @@ export interface GateInput {
|
|
|
972
989
|
briefStage: BriefStage | null;
|
|
973
990
|
draftTitle: string | null;
|
|
974
991
|
sceneType: SceneType | null;
|
|
992
|
+
/** The submitted/active plan narrator; PG-05 uses it before a draft exists. */
|
|
993
|
+
narrator?: string | null;
|
|
975
994
|
summary: ChapterSummary | null;
|
|
976
995
|
/** P5 may omit `summary`; when omitted, the previous plan summary is reused. */
|
|
977
996
|
summaryProvided?: boolean;
|
|
@@ -1034,6 +1053,36 @@ export interface Selection {
|
|
|
1034
1053
|
title?: string;
|
|
1035
1054
|
created_at?: string;
|
|
1036
1055
|
}
|
|
1056
|
+
/**
|
|
1057
|
+
* One human-readable projection of the pipeline's chapter boundary.
|
|
1058
|
+
*
|
|
1059
|
+
* `pipeline.chapter`/`stage` are protocol values: after archiving chapter N the
|
|
1060
|
+
* pipeline points at N+1 and still says `done` because `done` describes the
|
|
1061
|
+
* chapter that was just archived. This projection is the only place that turns
|
|
1062
|
+
* those values into "chapter N archived; chapter N+1 starts at P1".
|
|
1063
|
+
*/
|
|
1064
|
+
export interface ChapterProgress {
|
|
1065
|
+
active_chapter: number;
|
|
1066
|
+
stage: Stage;
|
|
1067
|
+
/** The chapter currently being written; null while `stage === 'done'`. */
|
|
1068
|
+
current: {
|
|
1069
|
+
chapter: number;
|
|
1070
|
+
stage: Stage;
|
|
1071
|
+
} | null;
|
|
1072
|
+
/** Highest archived chapter, or null before the first archive. */
|
|
1073
|
+
last_archived: number | null;
|
|
1074
|
+
/** Next chapter to start at P1; null while writing or after the book is finished. */
|
|
1075
|
+
next: {
|
|
1076
|
+
chapter: number;
|
|
1077
|
+
stage: 'P1';
|
|
1078
|
+
} | null;
|
|
1079
|
+
/** True only when the configured target has been reached at `stage === 'done'`. */
|
|
1080
|
+
finished: boolean;
|
|
1081
|
+
/** One line for status cards, commands and the panel. */
|
|
1082
|
+
label: string;
|
|
1083
|
+
/** Sentence used by the resume prompt instead of "当前第 N 章,阶段 done". */
|
|
1084
|
+
resume: string;
|
|
1085
|
+
}
|
|
1037
1086
|
/** The `getStatus` payload. */
|
|
1038
1087
|
export interface StatusReport {
|
|
1039
1088
|
project: {
|
|
@@ -1054,6 +1103,8 @@ export interface StatusReport {
|
|
|
1054
1103
|
/** SHA-256 of the active manuscript, or null when the stage has no draft. */
|
|
1055
1104
|
manuscript_hash: string | null;
|
|
1056
1105
|
stage: Stage;
|
|
1106
|
+
/** Chapter-boundary projection shared by every human-readable surface. */
|
|
1107
|
+
progress?: ChapterProgress;
|
|
1057
1108
|
rounds: RoundCounters;
|
|
1058
1109
|
blocking: BlockingItem[];
|
|
1059
1110
|
/** Non-blocking recovery notes, e.g. a recoverable pending transaction. */
|
|
@@ -1106,6 +1157,8 @@ export interface StatusReport {
|
|
|
1106
1157
|
export interface AdviceReport {
|
|
1107
1158
|
stage: Stage;
|
|
1108
1159
|
chapter: number;
|
|
1160
|
+
/** Same chapter-boundary projection as getStatus. */
|
|
1161
|
+
progress?: ChapterProgress;
|
|
1109
1162
|
tool: string;
|
|
1110
1163
|
args: Record<string, unknown>;
|
|
1111
1164
|
reason: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-novel-write-engine",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.9",
|
|
4
4
|
"description": "Novel writing engine for DeepSeek Harness: state machine, gates, rulepacks and ledgers moved from prompts into code.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dsh-plugin",
|
|
@@ -63,7 +63,8 @@
|
|
|
63
63
|
],
|
|
64
64
|
"external": [
|
|
65
65
|
"react",
|
|
66
|
-
"react/jsx-runtime"
|
|
66
|
+
"react/jsx-runtime",
|
|
67
|
+
"react-dom"
|
|
67
68
|
]
|
|
68
69
|
}
|
|
69
70
|
},
|
|
@@ -98,7 +99,8 @@
|
|
|
98
99
|
"@deepseek-ai/dsh-skill": "^0.2.0-rc.1 || ^0.2.1-rc.1",
|
|
99
100
|
"@deepseek-ai/schemastery": "^3.18.5",
|
|
100
101
|
"@deepseek-ai/dsh-tools": "^0.2.0-rc.1 || ^0.2.1-rc.1",
|
|
101
|
-
"react": "^18.0.0 || ^19.0.0"
|
|
102
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
103
|
+
"react-dom": "^18.0.0 || ^19.0.0"
|
|
102
104
|
},
|
|
103
105
|
"peerDependenciesMeta": {
|
|
104
106
|
"@deepseek-ai/dsh-client-ui-layout": {
|
|
@@ -112,6 +114,9 @@
|
|
|
112
114
|
},
|
|
113
115
|
"react": {
|
|
114
116
|
"optional": true
|
|
117
|
+
},
|
|
118
|
+
"react-dom": {
|
|
119
|
+
"optional": true
|
|
115
120
|
}
|
|
116
121
|
},
|
|
117
122
|
"devDependencies": {
|
|
@@ -17,6 +17,10 @@
|
|
|
17
17
|
- 正文只经 novel_write_draft,改稿只经 novel_revise;归档只走 novel_archive,且必须带 state_delta。没有别的写入口。
|
|
18
18
|
- 字数、引号、格式、门控结论一律以引擎返回为准,不要自己估算,也不要复述旧数字。
|
|
19
19
|
- 评审每一分都要指到具体扣分项;指不出来就不要扣。
|
|
20
|
+
- 参数是严格 JSON:只用英文双引号,不写注释、尾逗号和 Markdown 围栏;不要把对象再包成 JSON 字符串,不要重复编码。
|
|
21
|
+
- 写工具一次只提交一个:novel_write_draft、novel_review、novel_check、novel_archive 读完结果再走下一步。
|
|
22
|
+
- 参数解析失败时不要原样重发大对象;先 novel_brief 重取当前阶段字段,缩小对象并逐字段核对。
|
|
23
|
+
- 归档只带 state_delta,不带 summary;归档后下一章从 novel_brief P1 重新开始。
|
|
20
24
|
- 设定、前章细节、伏笔状态拿不准就查 novel_state,不许编。
|
|
21
25
|
- { id: time-context, name: '@deepseek-ai/dsh-time-context' }
|
|
22
26
|
- { id: tool-skill, name: '@deepseek-ai/dsh-tool-skill' }
|
package/rulepacks/default.yaml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
schema_version: 1
|
|
2
2
|
name: default
|
|
3
|
-
version: "1.0
|
|
3
|
+
version: "1.1.0"
|
|
4
4
|
|
|
5
5
|
lexicon:
|
|
6
6
|
zero_tolerance:
|
|
@@ -182,10 +182,16 @@ platform:
|
|
|
182
182
|
jinjiang: { words_per_chapter: [2500, 4000], dialogue_ratio: [0.35, 0.55] }
|
|
183
183
|
|
|
184
184
|
genres:
|
|
185
|
-
玄幻修仙:
|
|
186
|
-
|
|
185
|
+
玄幻修仙:
|
|
186
|
+
note: "力量体系必须自洽;升级要有代价,境界不能靠形容词抬升。"
|
|
187
|
+
profile: { water_words: 0.30, pleasure_density: 2 }
|
|
188
|
+
都市现代:
|
|
189
|
+
note: "现实都市,冲突来自资源、关系与规则;爽点要落在可验证的行动上。"
|
|
190
|
+
profile: { water_words: 0.32, pleasure_density: 1 }
|
|
187
191
|
西方奇幻: { note: "种族、语言与力量来源要建条目;奇观不能替代人物选择。" }
|
|
188
|
-
悬疑推理:
|
|
192
|
+
悬疑推理:
|
|
193
|
+
note: "线索先于解答出现;每个伏笔都要在归档台账中可核销。"
|
|
194
|
+
profile: { period_density: { min: 1.5, max: 12 }, water_words: 0.30 }
|
|
189
195
|
科幻: { note: "技术设定只写对情节有用的部分;禁止用术语代替冲突。" }
|
|
190
196
|
游戏系统: { note: "系统提示是世界观内文本;奖励与惩罚必须可追踪。" }
|
|
191
197
|
历史架空: { note: "礼制、称谓与器物要经得起基本推敲;不写现代口号。" }
|
|
@@ -193,7 +199,9 @@ genres:
|
|
|
193
199
|
轻小说: { note: "关系推进靠具体互动,不靠内心独白宣布;对话要能区分说话人。" }
|
|
194
200
|
军事: { note: "战术细节服务于人物选择;不写武器参数清单。" }
|
|
195
201
|
末世流: { note: "生存资源必须记账;恐惧来自规则崩塌,不靠突然的音效式形容词。" }
|
|
196
|
-
言情:
|
|
202
|
+
言情:
|
|
203
|
+
note: "亲密关系按阶梯推进;单次独白要短,情绪落在动作上。"
|
|
204
|
+
profile: { period_density: { min: 1.5, max: 12 }, pleasure_density: 2 }
|
|
197
205
|
|
|
198
206
|
crosschapter:
|
|
199
207
|
duplicate_similarity: 0.9
|
package/skills/entry.md
CHANGED
|
@@ -77,7 +77,8 @@ description: 引擎版小说创作流程——状态、门控、字数与写盘
|
|
|
77
77
|
|
|
78
78
|
## 工具怎么用
|
|
79
79
|
|
|
80
|
-
-
|
|
80
|
+
- 参数是严格 JSON 对象:英文双引号、无注释/尾逗号/围栏;`summary`、`dimensions`、`issues`、`proof` 是结构化对象/数组,按任务书字段填,不要再包成 JSON 字符串。
|
|
81
|
+
- 写工具一次只提交一个;参数解析失败时先重取 `novel_brief`,缩小对象再试,不要原样重发。
|
|
81
82
|
- `novel_check` 必须带五个语义项(`L2-SCENE-ANCHOR` / `L2-CHARACTER-STATE` / `L2-CAUSALITY` / `L2-VOICE` / `L2-POV`),每项都要有正文逐字引用,且来自不同句子;缺一项即校验不过。
|
|
82
83
|
- 失败分三类:参数错(改参数)、门控没过(改正文)、系统故障(查目录/稍后重试)。错误消息里的 code 说明属于哪类。
|
|
83
84
|
- 门控失败会一次列出**全部**阻塞项;一次改完再交,不要逐条试。
|