@waterwx/dsh-novel-forge 1.3.2 → 1.3.3
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/README.md +2 -2
- package/lib/client.js +239 -239
- package/lib/index.js +18 -9
- package/lib/index.js.map +1 -1
- package/lib/types/bookshelf.d.ts +1 -1
- package/lib/types/index.d.ts +1 -1
- package/package.json +2 -2
- package/src/bookshelf.ts +2 -2
- package/src/index.ts +7 -5
- package/scripts/assistant-frames.txt +0 -8
- package/scripts/diagnose-adapter.mts +0 -81
- package/scripts/diagnose-assistant.mjs +0 -58
- package/scripts/diagnose-bible.mjs +0 -72
- package/scripts/diagnose-harness.mts +0 -75
- package/scripts/novel-forge-restart.log +0 -10
- package/scripts/novel-forge-web.stderr.log +0 -2
- package/scripts/novel-forge-web.stdout.log +0 -1
- package/scripts/outline-sample.txt +0 -449
- package/scripts/probe.mjs +0 -6
- package/scripts/restart-web.ps1 +0 -88
- package/scripts/smoke.mts +0 -72
- package/scripts/upload-github.ps1 +0 -51
|
@@ -1 +0,0 @@
|
|
|
1
|
-
dsh web: http://127.0.0.1:3080
|
|
@@ -1,449 +0,0 @@
|
|
|
1
|
-
《归墟玉主》
|
|
2
|
-
|
|
3
|
-
200 万字完整版 · 官方全书大纲(最终定稿)
|
|
4
|
-
|
|
5
|
-
一、全书基础档案
|
|
6
|
-
|
|
7
|
-
书名:归墟玉主
|
|
8
|
-
|
|
9
|
-
题材:穿越修仙、苟道发育、秘境冒险、收集养成、炼丹炼器、渔翁得利爽文
|
|
10
|
-
|
|
11
|
-
总规划字数:200 万字
|
|
12
|
-
|
|
13
|
-
单章篇幅:3000–4000 字
|
|
14
|
-
|
|
15
|
-
总章节区间:520–550 章
|
|
16
|
-
|
|
17
|
-
核心对标风格
|
|
18
|
-
|
|
19
|
-
资源闭环玩法:原材料采集 → 成品制作 → 神鼎升华,资源复利滚雪球成长
|
|
20
|
-
|
|
21
|
-
长线收集体系:古玉残片解锁墟境功能,持续开放新玩法
|
|
22
|
-
|
|
23
|
-
叙事基调:阴影猎手视角,恶人厮杀夺宝,主角坐收渔利;全程主角主线,无大段反派灌水剧情
|
|
24
|
-
|
|
25
|
-
核心卖点
|
|
26
|
-
|
|
27
|
-
摆烂吃瓜反差人设、痞坏杀伐行事风格
|
|
28
|
-
|
|
29
|
-
上古归墟神鼎升华体系
|
|
30
|
-
|
|
31
|
-
现代厨房炼丹、3D 打印制符炼器
|
|
32
|
-
|
|
33
|
-
古今混搭独一份金手指
|
|
34
|
-
|
|
35
|
-
无后宫
|
|
36
|
-
|
|
37
|
-
附带记忆代价长线伏笔
|
|
38
|
-
|
|
39
|
-
数值逻辑自洽无冲突
|
|
40
|
-
|
|
41
|
-
二、主角完整人设
|
|
42
|
-
|
|
43
|
-
姓名:林越
|
|
44
|
-
|
|
45
|
-
前世:现代普通外卖员,暴雨送餐遭遇空间异变穿越;能吃苦、思维灵活、观察力强,保有普通人完整情感
|
|
46
|
-
|
|
47
|
-
今生开局:宗门五行杂灵根杂役,身处底层受尽冷眼,性格隐忍、行事务实清醒
|
|
48
|
-
|
|
49
|
-
性格标签
|
|
50
|
-
|
|
51
|
-
痞坏嘴贫:只言语打趣拆台,有分寸感;对方反感立刻收敛,不单独纠缠异性
|
|
52
|
-
|
|
53
|
-
杀伐不圣母:主动出手加害、夺宝行凶之徒赶尽杀绝;无仇无辜修士绝不主动寻衅杀戮
|
|
54
|
-
|
|
55
|
-
情感克制清醒:无后宫,欣赏美人但不纠缠胁迫;收集残片、守护两世记忆优先级高于情爱,可走独行或唯一知己路线,拒绝工业糖精暧昧
|
|
56
|
-
|
|
57
|
-
自控有底线:初次使用水镜有窥私念头,触发墟境隐私惩罚后彻底杜绝低俗想法,有色心无歪路
|
|
58
|
-
|
|
59
|
-
苟道核心思维:能蹲则蹲、擅长坐山观虎斗,绝不无脑正面冲锋,凡事预留后手
|
|
60
|
-
|
|
61
|
-
标志性习惯
|
|
62
|
-
|
|
63
|
-
储物袋常备墟境产出可乐、香烟
|
|
64
|
-
|
|
65
|
-
对阵同级强敌开战前喝可乐定心,仅心理习惯,无战力加成
|
|
66
|
-
|
|
67
|
-
香烟仅凝神抗心魔,无战斗增益
|
|
68
|
-
|
|
69
|
-
人物内外反差
|
|
70
|
-
|
|
71
|
-
对外:秘境阴影猎手,杀伐狠辣、行踪神秘,各大修士视之为幕后反派
|
|
72
|
-
|
|
73
|
-
对内:贪恋地球零食、念旧重情,毕生目标守护爷爷与地球前世记忆
|
|
74
|
-
|
|
75
|
-
三、核心金手指:归墟墟境
|
|
76
|
-
|
|
77
|
-
起源:爷爷祖传古玉,穿越时空崩塌时碎玉护魂;主角仅持有一块残片,剩余残片散落整片修真大陆;古玉秘辛世间无人知晓,外人无法完整激活墟境功能
|
|
78
|
-
|
|
79
|
-
1. 全域制衡规则(杜绝永久无敌,全程保留危机)
|
|
80
|
-
|
|
81
|
-
普通修士、妖兽、妖王无法察觉墟境,仅能看见林越气息凭空消失
|
|
82
|
-
|
|
83
|
-
化神及以上大能、遗迹守护神魂可感知墟境空间波动
|
|
84
|
-
|
|
85
|
-
触发条件:长期定点蹲守吃瓜、高频批量使用加工设施、残片剧烈共鸣、多次肉身入鼎淬炼
|
|
86
|
-
|
|
87
|
-
大能仅能锁定一片大致区域大范围搜山,无法看穿墟内、无法攻入墟境、无法精准定位主角
|
|
88
|
-
|
|
89
|
-
墟内单次最长停留时限:墟境七日,超时空间剧烈波动,极易被大能追踪
|
|
90
|
-
|
|
91
|
-
离开墟境只能返回进入时的原地,不支持远距离定点瞬移
|
|
92
|
-
|
|
93
|
-
2. 墟境功能分区
|
|
94
|
-
|
|
95
|
-
【核心至宝:归墟神鼎】
|
|
96
|
-
|
|
97
|
-
上古青铜鼎,墟境根基。两套独立运行规则,互不干扰。
|
|
98
|
-
|
|
99
|
-
(1)肉身入鼎 · 境界洗礼(主角独有特权)
|
|
100
|
-
|
|
101
|
-
每一个大境界终身仅有一次肉身入鼎洗礼资格,使用后无法回溯重洗
|
|
102
|
-
|
|
103
|
-
鼎内可承受冲刷时长绑定自身境界,境界越高停留越久;超时肉身、神魂会被鼎力重创
|
|
104
|
-
|
|
105
|
-
洗礼效果:彻底根除全部修行暗伤,提纯灵根与本源灵力,将当前境界打磨至完美无瑕根基
|
|
106
|
-
|
|
107
|
-
完美根基增益:灵力纯度、肉身强度、神魂承载、续航、自愈、突破难度全面碾压普通同阶,修行上限大幅提升
|
|
108
|
-
|
|
109
|
-
(2)成品淬炼 · 器物升华
|
|
110
|
-
|
|
111
|
-
仅可投入完整成品:丹药、制式符箓、兵器、护甲、法宝
|
|
112
|
-
|
|
113
|
-
灵草、矿石、妖兽内丹等原材料禁止直接入鼎,强行投入只会分解浪费
|
|
114
|
-
|
|
115
|
-
淬炼无次数上限,反复投入可消除瑕疵、补全道韵、提升品级;强化上限受主角当前境界限制
|
|
116
|
-
|
|
117
|
-
— · — · — · — · — · — · —
|
|
118
|
-
|
|
119
|
-
【生活区:故土小筑】(第二枚古玉残片解锁)
|
|
120
|
-
|
|
121
|
-
升级路线:单层小平房 → 两层独栋别墅 → 庭院完整宅院
|
|
122
|
-
|
|
123
|
-
升级条件:主角境界提升 + 收集古玉残片
|
|
124
|
-
|
|
125
|
-
① 溯源水镜(侦查吃瓜工具)
|
|
126
|
-
|
|
127
|
-
仅观测主角所处同一片地域,无法跨大洲远距离探查
|
|
128
|
-
|
|
129
|
-
仅能观看画面,无法读取神识传音,天然存在信息差
|
|
130
|
-
|
|
131
|
-
隐私屏蔽机制:厮杀、寻宝、议事画面清晰;沐浴、更衣、休眠画面自动模糊;刻意窥探私密场景会刺痛识海,男女一视同仁
|
|
132
|
-
|
|
133
|
-
② 七日刷新便民超市(纯情绪道具,不参与修炼体系)
|
|
134
|
-
|
|
135
|
-
货品:各类现代零食、碳酸饮料、卷烟、家常食材;墟境固定周期刷新,单次总量有限,不可无限囤积
|
|
136
|
-
|
|
137
|
-
效果:1:1 还原地球口感,仅微弱舒缓心魔、安神;无修为、疗伤、突破增益,完全不能替代丹药
|
|
138
|
-
|
|
139
|
-
硬性限制:所有超市物品带出墟境仅能留存一个时辰,时限一过灵光消散、彻底风化失效
|
|
140
|
-
|
|
141
|
-
作用:满足穿越者思乡口腹欲,支撑战前喝可乐人设仪式
|
|
142
|
-
|
|
143
|
-
③ 现代厨房(专属丹药生产线)
|
|
144
|
-
|
|
145
|
-
消耗野外采集灵草、妖兽内丹,搭配丹方炼制丹药成品
|
|
146
|
-
|
|
147
|
-
境界锁阶,不可越阶炼制高阶神丹
|
|
148
|
-
|
|
149
|
-
境界达标即可炼出基础极品丹,无人工炼制缺陷
|
|
150
|
-
|
|
151
|
-
基础丹药存在上限,想要提升药效、圆满品级,必须送入归墟神鼎二次淬炼
|
|
152
|
-
|
|
153
|
-
④ 墟境 3D 打印机(第四枚残片解锁,制符 + 制式炼器)
|
|
154
|
-
|
|
155
|
-
投放符纸、灵墨打印各类战斗、探测、防御符箓
|
|
156
|
-
|
|
157
|
-
投放矿石、灵金、器胚打造兵器、护甲、探险工具
|
|
158
|
-
|
|
159
|
-
限制:无法打印本命道兵、传承至宝、禁术符箓
|
|
160
|
-
|
|
161
|
-
打印产物仅标准上品,威力存在天花板,需神鼎淬炼才能质变升级
|
|
162
|
-
|
|
163
|
-
不能凭空创造全新符箓、专属功法器具,全部依赖野外原材料供给
|
|
164
|
-
|
|
165
|
-
3. 长线暗线:神魂同化代价
|
|
166
|
-
|
|
167
|
-
融合残片越多、频繁透支神鼎力量,主角神魂会被墟境本源同化:超市文字模糊、别墅景物褪色、地球前世记忆碎片化流失。
|
|
168
|
-
|
|
169
|
-
终极双向抉择:
|
|
170
|
-
|
|
171
|
-
集齐全部残片,登临大道巅峰,永久遗忘爷爷与地球人生
|
|
172
|
-
|
|
173
|
-
主动舍弃部分本源力量,完整留存两世所有记忆,守住自身人性
|
|
174
|
-
|
|
175
|
-
四、古玉残片核心规则
|
|
176
|
-
|
|
177
|
-
残片仅与林越神魂共鸣,只指引大致方位,秘境禁制可屏蔽感应
|
|
178
|
-
|
|
179
|
-
外人拾取残片仅有微弱安神效果,无法开启墟境、神鼎任何功能
|
|
180
|
-
|
|
181
|
-
整片大陆无势力追杀夺玉,不存在全民寻宝俗套剧情
|
|
182
|
-
|
|
183
|
-
残片唯一获取渠道:外出探索秘境、上古遗迹,墟内无法自产
|
|
184
|
-
|
|
185
|
-
五、完整资源闭环铁律
|
|
186
|
-
|
|
187
|
-
完整产业链流程
|
|
188
|
-
|
|
189
|
-
外出冒险搜集原材料 → 厨房 / 3D 打印机加工基础成品 → 归墟神鼎淬炼高阶成品
|
|
190
|
-
|
|
191
|
-
墟境自产
|
|
192
|
-
|
|
193
|
-
现代零食
|
|
194
|
-
|
|
195
|
-
厨房丹药
|
|
196
|
-
|
|
197
|
-
3D 制式符器
|
|
198
|
-
|
|
199
|
-
休憩悟道空间
|
|
200
|
-
|
|
201
|
-
墟境无法产出
|
|
202
|
-
|
|
203
|
-
高阶灵材
|
|
204
|
-
|
|
205
|
-
稀有矿石
|
|
206
|
-
|
|
207
|
-
本命材料
|
|
208
|
-
|
|
209
|
-
古玉残片
|
|
210
|
-
|
|
211
|
-
所有提升境界、战斗攻坚的核心资源,必须外出冒险、清缴恶徒、坊市交易、探索遗迹获取。
|
|
212
|
-
|
|
213
|
-
六、战力体系规则
|
|
214
|
-
|
|
215
|
-
核心原则:完美根基 ≠ 同阶无敌,更不能随意跨大境界乱杀。
|
|
216
|
-
|
|
217
|
-
三大根基无法弥补的硬性差距
|
|
218
|
-
|
|
219
|
-
功法、传承绝杀秘术差距
|
|
220
|
-
|
|
221
|
-
高阶法宝、海量丹药符箓、稀有消耗品储备差距
|
|
222
|
-
|
|
223
|
-
百年厮杀经验、搏命心性、布局偷袭手段差距
|
|
224
|
-
|
|
225
|
-
统一对战梯度
|
|
226
|
-
|
|
227
|
-
普通同阶修士:林越凭借完美根基稳占上风,轻松压制取胜
|
|
228
|
-
|
|
229
|
-
同阶天骄(身怀秘术 / 传承宝器):五五开,依靠伏击、墟境拉扯、神鼎装备取胜
|
|
230
|
-
|
|
231
|
-
跨一小段位:依靠计谋、地形、鼎炼消耗品艰难险胜
|
|
232
|
-
|
|
233
|
-
跨完整大境界:绝不正面硬拼,仅能躲避、远程骚扰,无正面斩杀能力
|
|
234
|
-
|
|
235
|
-
七、关键剧情桥段定稿
|
|
236
|
-
|
|
237
|
-
数名追兵穷追不舍,林越身负伤势,灵力损耗巨大,正面迎战毫无胜算。危急时刻心念一动,遁入归墟墟境。
|
|
238
|
-
|
|
239
|
-
墟境中央,青铜归墟神鼎静静悬浮。往日他只往鼎中投放各类器物淬炼提纯,从未想过人能否亲身踏入。外界追杀的气息隔着空间隐约传来,已然无路可退。
|
|
240
|
-
|
|
241
|
-
林越咬紧牙关:"横竖难逃一死,死马当活马医,赌一把!"纵身跃入归墟神鼎。
|
|
242
|
-
|
|
243
|
-
浑厚苍茫的本源之力席卷全身,道则信息涌入识海:肉身停留时长受境界限制,每一大境界仅有一次肉身洗礼机缘。
|
|
244
|
-
|
|
245
|
-
他借鼎内力量修复伤势、打磨根基,临近时限方才跃出鼎外。感受体内所有隐患尽数消除,修为抵达无瑕圆满的完美境界。
|
|
246
|
-
|
|
247
|
-
林越舒展身躯,望着青铜大鼎低声轻笑自语:
|
|
248
|
-
|
|
249
|
-
"我记得前世有个动漫主角,拥有聚宝盆,只会往里面丢宝物提纯,到头自己都没进去,真是胆小。"
|
|
250
|
-
|
|
251
|
-
随即神色收敛,暗自警醒:
|
|
252
|
-
|
|
253
|
-
"底子圆满只是底盘扎实,万万不可膨胀。秘术、经验、底牌样样欠缺,真以为能横着走,早晚栽大跟头。"
|
|
254
|
-
|
|
255
|
-
八、全书五卷分卷大纲
|
|
256
|
-
|
|
257
|
-
第一卷:杂役墟醒
|
|
258
|
-
|
|
259
|
-
字数区间:0–30 万字
|
|
260
|
-
|
|
261
|
-
章节区间:1–80 章
|
|
262
|
-
|
|
263
|
-
卷定位:开局底层发育、墟境规则落地、绝境入鼎名场面
|
|
264
|
-
|
|
265
|
-
主线剧情
|
|
266
|
-
|
|
267
|
-
开篇铺垫:外卖穿越、古玉碎护魂完整背景
|
|
268
|
-
|
|
269
|
-
五行杂灵根杂役受欺凌,隐忍暗中发育
|
|
270
|
-
|
|
271
|
-
割手滴血认主,解锁归墟与神鼎,摸索器物淬炼
|
|
272
|
-
|
|
273
|
-
宗门恶徒围杀,绝境肉身入鼎,解锁完美境界机制
|
|
274
|
-
|
|
275
|
-
试水溯源水镜,窥私触发屏障,彻底删除低俗剧情
|
|
276
|
-
|
|
277
|
-
回收宗门废料加工提纯,赚取第一笔修炼资源
|
|
278
|
-
|
|
279
|
-
完美根基悄悄拉开差距,低调打脸宗门天骄
|
|
280
|
-
|
|
281
|
-
神魂感应残片,主线确定:走遍大荒集齐残片,守护两世记忆
|
|
282
|
-
|
|
283
|
-
隐藏实力出师,踏入大世界
|
|
284
|
-
|
|
285
|
-
本卷爽点
|
|
286
|
-
|
|
287
|
-
底层翻盘
|
|
288
|
-
|
|
289
|
-
废料升值
|
|
290
|
-
|
|
291
|
-
完美根基碾压
|
|
292
|
-
|
|
293
|
-
绝境自救
|
|
294
|
-
|
|
295
|
-
收尾:正式开启大陆冒险
|
|
296
|
-
|
|
297
|
-
— · — · — · — · — · — · —
|
|
298
|
-
|
|
299
|
-
第二卷:墟境吃瓜行
|
|
300
|
-
|
|
301
|
-
字数区间:30–70 万字
|
|
302
|
-
|
|
303
|
-
章节区间:81–180 章
|
|
304
|
-
|
|
305
|
-
卷定位:阴影猎手人设定型,吃瓜名场面集中
|
|
306
|
-
|
|
307
|
-
解锁内容:第二枚残片,故土小筑全套设施
|
|
308
|
-
|
|
309
|
-
固定循环
|
|
310
|
-
|
|
311
|
-
追踪残片 → 秘境遇恶人厮杀 → 墟内炼丹打印观战 → 敌人两败俱伤后收割
|
|
312
|
-
|
|
313
|
-
核心设定
|
|
314
|
-
|
|
315
|
-
外界传言秘境猎手,外人视其为反派,只诛杀作恶之人
|
|
316
|
-
|
|
317
|
-
新增危机:长期蹲守引来大能空间探查
|
|
318
|
-
|
|
319
|
-
爽点
|
|
320
|
-
|
|
321
|
-
渔翁收割
|
|
322
|
-
|
|
323
|
-
极品丹药
|
|
324
|
-
|
|
325
|
-
戏耍敌人
|
|
326
|
-
|
|
327
|
-
资源复利
|
|
328
|
-
|
|
329
|
-
— · — · — · — · — · — · —
|
|
330
|
-
|
|
331
|
-
第三卷:残片逐大荒
|
|
332
|
-
|
|
333
|
-
字数区间:70–120 万字
|
|
334
|
-
|
|
335
|
-
章节区间:181–310 章
|
|
336
|
-
|
|
337
|
-
卷定位:大世界开放,资源自由
|
|
338
|
-
|
|
339
|
-
解锁内容:3D 打印机、完整墟境拓展区
|
|
340
|
-
|
|
341
|
-
主线剧情
|
|
342
|
-
|
|
343
|
-
遍历各类遗迹秘境搜寻残片
|
|
344
|
-
|
|
345
|
-
收割模式常态化,符箓兵器用于拉扯消耗
|
|
346
|
-
|
|
347
|
-
对敌嘴狠杀伐,名号响彻大荒
|
|
348
|
-
|
|
349
|
-
记忆流失伏笔出现
|
|
350
|
-
|
|
351
|
-
看点
|
|
352
|
-
|
|
353
|
-
碎片收集
|
|
354
|
-
|
|
355
|
-
完整产业链
|
|
356
|
-
|
|
357
|
-
多元秘境开荒
|
|
358
|
-
|
|
359
|
-
— · — · — · — · — · — · —
|
|
360
|
-
|
|
361
|
-
第四卷:大能窥渊
|
|
362
|
-
|
|
363
|
-
字数区间:120–165 万字
|
|
364
|
-
|
|
365
|
-
章节区间:311–430 章
|
|
366
|
-
|
|
367
|
-
卷定位:高压悬疑,世界观揭秘
|
|
368
|
-
|
|
369
|
-
主线剧情
|
|
370
|
-
|
|
371
|
-
残片过半,大能常态化追踪探查
|
|
372
|
-
|
|
373
|
-
不能长期蹲守,主动放弃机缘躲避搜捕
|
|
374
|
-
|
|
375
|
-
揭露古玉本源、穿越并非偶然
|
|
376
|
-
|
|
377
|
-
记忆流失带来内心挣扎
|
|
378
|
-
|
|
379
|
-
周旋上古神魂与大宗势力
|
|
380
|
-
|
|
381
|
-
看点
|
|
382
|
-
|
|
383
|
-
空间博弈
|
|
384
|
-
|
|
385
|
-
真相层层揭开
|
|
386
|
-
|
|
387
|
-
心智成长
|
|
388
|
-
|
|
389
|
-
— · — · — · — · — · — · —
|
|
390
|
-
|
|
391
|
-
第五卷:归墟择世
|
|
392
|
-
|
|
393
|
-
字数区间:165–200 万字
|
|
394
|
-
|
|
395
|
-
章节区间:431–540 章
|
|
396
|
-
|
|
397
|
-
卷定位:最终收官,双结局
|
|
398
|
-
|
|
399
|
-
主线剧情
|
|
400
|
-
|
|
401
|
-
集齐大部分残片,神鼎本源解封
|
|
402
|
-
|
|
403
|
-
完整揭露上古界崩塌、护玉秘辛
|
|
404
|
-
|
|
405
|
-
记忆遗忘风险达到顶峰
|
|
406
|
-
|
|
407
|
-
黑暗残余现世,大陆终极危机
|
|
408
|
-
|
|
409
|
-
清算所有敌对势力
|
|
410
|
-
|
|
411
|
-
主角做出终极选择
|
|
412
|
-
|
|
413
|
-
双结局
|
|
414
|
-
|
|
415
|
-
结局 A(温情):舍弃部分力量,保留全部两世记忆
|
|
416
|
-
|
|
417
|
-
结局 B(热血):背负记忆登临诸天巅峰
|
|
418
|
-
|
|
419
|
-
九、全书永久写作红线
|
|
420
|
-
|
|
421
|
-
无后宫、无擦边、无偷窥低俗剧情
|
|
422
|
-
|
|
423
|
-
主角仅言语打趣,不羞辱胁迫他人
|
|
424
|
-
|
|
425
|
-
不圣母,作恶者斩草除根,无辜者不主动出手
|
|
426
|
-
|
|
427
|
-
无全大陆追杀夺玉剧情
|
|
428
|
-
|
|
429
|
-
墟、神鼎只是辅助,全程存在大能威胁,无永久无敌
|
|
430
|
-
|
|
431
|
-
主线以主角视角,不灌水反派长篇剧情
|
|
432
|
-
|
|
433
|
-
零食仅人设道具,不能替代丹药疗伤突破
|
|
434
|
-
|
|
435
|
-
完美根基仅优势,禁止无脑碾压、跨大境界乱杀
|
|
436
|
-
|
|
437
|
-
十、全书核心弹幕记忆梗
|
|
438
|
-
|
|
439
|
-
这群恶人拼死拼活,全程给林越送货上门!
|
|
440
|
-
|
|
441
|
-
外面打得生死搏杀,主角躲墟境别墅吃零食看戏。
|
|
442
|
-
|
|
443
|
-
别人炼丹炼器全靠赌,主角加工完直接送神鼎拉满品质。
|
|
444
|
-
|
|
445
|
-
看似最像反派的猎手,下手只杀作恶夺宝之徒。
|
|
446
|
-
|
|
447
|
-
苟到极致,搭配神鼎升华,便是同阶天花板。
|
|
448
|
-
|
|
449
|
-
前世动漫那聚宝盆主人太保守,哪有肉身入鼎修成完美根基香。
|
package/scripts/probe.mjs
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
// TEMP: extractRoles 插入点探测——确认 refreshPlotlineProgress 结束位置
|
|
2
|
-
import { readFileSync } from 'node:fs'
|
|
3
|
-
const src = readFileSync('D:/ryan work/harness/plugins/novel-forge/src/engine.ts', 'utf8')
|
|
4
|
-
const idx = src.indexOf('return typeof raw.progress === \'string\'')
|
|
5
|
-
console.log('refreshPlotlineProgress return 位置:', idx)
|
|
6
|
-
console.log('其后 200 字:', src.slice(idx, idx + 200).replace(/\n/g, ' '))
|
package/scripts/restart-web.ps1
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
# Restart the dsh web service to load the novel-forge plugin, then verify.
|
|
2
|
-
# Run fully detached (Start-Process) so it survives the host process being
|
|
3
|
-
# killed. Logs to novel-forge-restart.log.
|
|
4
|
-
param(
|
|
5
|
-
[int]$DelaySeconds = 20,
|
|
6
|
-
[int]$OldPid = 0
|
|
7
|
-
)
|
|
8
|
-
$ErrorActionPreference = 'Continue'
|
|
9
|
-
$log = Join-Path $PSScriptRoot 'novel-forge-restart.log'
|
|
10
|
-
function Log($msg) {
|
|
11
|
-
$line = "[{0}] {1}" -f (Get-Date -Format 'HH:mm:ss'), $msg
|
|
12
|
-
Add-Content -Path $log -Value $line
|
|
13
|
-
Write-Host $line
|
|
14
|
-
}
|
|
15
|
-
Set-Content -Path $log -Value "=== novel-forge restart started $(Get-Date) ==="
|
|
16
|
-
|
|
17
|
-
Log "waiting $DelaySeconds seconds for the current turn to finish..."
|
|
18
|
-
Start-Sleep -Seconds $DelaySeconds
|
|
19
|
-
|
|
20
|
-
# 1. Kill the old dsh web host: whatever PID listens on 3080, plus $OldPid if given.
|
|
21
|
-
$listenerPids = @()
|
|
22
|
-
$netstatLines = netstat -ano | Select-String 'LISTENING'
|
|
23
|
-
foreach ($line in $netstatLines) {
|
|
24
|
-
if ($line -match ':3080\s.*LISTENING\s+(\d+)\s*$') {
|
|
25
|
-
$listenerPids += [int]$Matches[1]
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
$targets = @($listenerPids | Select-Object -Unique)
|
|
29
|
-
if ($OldPid -gt 0) { $targets += $OldPid }
|
|
30
|
-
$targets = @($targets | Select-Object -Unique)
|
|
31
|
-
if ($targets.Count -eq 0) {
|
|
32
|
-
Log "no process found listening on 3080 (nothing to kill)"
|
|
33
|
-
} else {
|
|
34
|
-
foreach ($pid0 in $targets) {
|
|
35
|
-
$p = Get-Process -Id $pid0 -ErrorAction SilentlyContinue
|
|
36
|
-
if ($p) {
|
|
37
|
-
Log "killing dsh web (PID $pid0)..."
|
|
38
|
-
Stop-Process -Id $pid0 -Force -ErrorAction SilentlyContinue
|
|
39
|
-
} else {
|
|
40
|
-
Log "PID $pid0 not found (already gone?)"
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
Start-Sleep -Seconds 4
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
# 2. Start the new dsh web from the harness checkout.
|
|
47
|
-
$harness = 'D:\ryan work\harness\app'
|
|
48
|
-
$node = 'C:\Program Files\nodejs\node.exe'
|
|
49
|
-
$stdout = Join-Path $PSScriptRoot 'novel-forge-web.stdout.log'
|
|
50
|
-
$stderr = Join-Path $PSScriptRoot 'novel-forge-web.stderr.log'
|
|
51
|
-
Log "starting new dsh web..."
|
|
52
|
-
$proc = Start-Process -FilePath $node -ArgumentList '--import','tsx/esm','apps/cli/src/bin.ts','web' -WorkingDirectory $harness -RedirectStandardOutput $stdout -RedirectStandardError $stderr -PassThru -WindowStyle Hidden
|
|
53
|
-
Log "new dsh web PID: $($proc.Id)"
|
|
54
|
-
|
|
55
|
-
# 3. Poll the GUI until it responds (max 120s).
|
|
56
|
-
$ready = $false
|
|
57
|
-
for ($i = 0; $i -lt 60; $i++) {
|
|
58
|
-
Start-Sleep -Seconds 2
|
|
59
|
-
try {
|
|
60
|
-
$r = Invoke-WebRequest -Uri 'http://127.0.0.1:3080' -UseBasicParsing -TimeoutSec 3
|
|
61
|
-
if ($r.StatusCode -eq 200) { $ready = $true; Log "GUI up after $($i * 2)s"; break }
|
|
62
|
-
} catch { }
|
|
63
|
-
}
|
|
64
|
-
if (-not $ready) {
|
|
65
|
-
Log "FAIL: GUI did not come up in time. stderr tail:"
|
|
66
|
-
Get-Content $stderr -Tail 30 -ErrorAction SilentlyContinue | ForEach-Object { Log " $_" }
|
|
67
|
-
exit 1
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
# 4. Verify the novel-forge status endpoint.
|
|
71
|
-
Start-Sleep -Seconds 2
|
|
72
|
-
try {
|
|
73
|
-
$s = Invoke-WebRequest -Uri 'http://127.0.0.1:3080/api/dsh-novel-forge/status' -UseBasicParsing -TimeoutSec 5
|
|
74
|
-
Log "novel-forge status endpoint: HTTP $($s.StatusCode)"
|
|
75
|
-
Log "body: $($s.Content)"
|
|
76
|
-
} catch {
|
|
77
|
-
Log "FAIL: novel-forge status endpoint unreachable: $($_.Exception.Message)"
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
# 5. Verify the client bundle route.
|
|
81
|
-
try {
|
|
82
|
-
$b = Invoke-WebRequest -Uri 'http://127.0.0.1:3080/plugins/@waterwx%2Fdsh-novel-forge/client.js' -UseBasicParsing -TimeoutSec 5
|
|
83
|
-
Log "client bundle route: HTTP $($b.StatusCode), length $($b.RawContentLength)"
|
|
84
|
-
} catch {
|
|
85
|
-
Log "WARN: client bundle route check failed: $($_.Exception.Message)"
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
Log "=== done ==="
|
package/scripts/smoke.mts
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Smoke test for the host-half logic that needs no harness: docx extraction,
|
|
3
|
-
* project state round-trip, and chapter file naming. Run with:
|
|
4
|
-
* node --import tsx scripts/smoke.mts
|
|
5
|
-
*/
|
|
6
|
-
import { mkdtempSync, readFileSync, writeFileSync, existsSync } from 'node:fs'
|
|
7
|
-
import { tmpdir } from 'node:os'
|
|
8
|
-
import { join } from 'node:path'
|
|
9
|
-
import { extractDocxText, readOutlineFromDocx } from '../src/docx.ts'
|
|
10
|
-
import {
|
|
11
|
-
chapterFileName,
|
|
12
|
-
createProject,
|
|
13
|
-
inferBookName,
|
|
14
|
-
listChapterFiles,
|
|
15
|
-
loadProject,
|
|
16
|
-
saveProject,
|
|
17
|
-
syncProjectWithDisk,
|
|
18
|
-
} from '../src/engine.ts'
|
|
19
|
-
import type { ChapterPlan } from '../src/protocol.ts'
|
|
20
|
-
|
|
21
|
-
let failures = 0
|
|
22
|
-
function check(name: string, ok: boolean, detail = ''): void {
|
|
23
|
-
if (ok) console.log(` ✔ ${name}`)
|
|
24
|
-
else {
|
|
25
|
-
failures++
|
|
26
|
-
console.error(` ✘ ${name}${detail !== '' ? ` — ${detail}` : ''}`)
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
console.log('docx extraction:')
|
|
31
|
-
const outlinePath = 'D:\\ryan work\\harness\\novels\\归墟玉主\\《归墟玉主》全书大纲_重新排版版.docx'
|
|
32
|
-
if (existsSync(outlinePath)) {
|
|
33
|
-
const text = readOutlineFromDocx(outlinePath)
|
|
34
|
-
check('extracts non-empty text', text.length > 100, `len=${text.length}`)
|
|
35
|
-
check('contains book title', text.includes('归墟玉主'), text.slice(0, 40))
|
|
36
|
-
check('contains protagonist name', text.includes('林越'))
|
|
37
|
-
check('contains 金手指', text.includes('墟境') || text.includes('神鼎'))
|
|
38
|
-
console.log(` excerpt: ${text.slice(0, 60).replace(/\n/g, ' ')}…`)
|
|
39
|
-
} else {
|
|
40
|
-
check('outline docx exists', false, outlinePath)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
console.log('engine helpers:')
|
|
44
|
-
const outline = '《测试书》\n第一章设定:主角穿越修仙。'
|
|
45
|
-
check('inferBookName', inferBookName(outline) === '测试书', inferBookName(outline))
|
|
46
|
-
|
|
47
|
-
const chapter: ChapterPlan = {
|
|
48
|
-
no: 3,
|
|
49
|
-
title: '初入宗门/试炼',
|
|
50
|
-
beats: 'b',
|
|
51
|
-
targetChars: 3000,
|
|
52
|
-
status: 'pending',
|
|
53
|
-
}
|
|
54
|
-
const fileName = chapterFileName(chapter)
|
|
55
|
-
check('chapterFileName sanitizes', fileName === '第003章_初入宗门试炼.md', fileName)
|
|
56
|
-
|
|
57
|
-
const dir = mkdtempSync(join(tmpdir(), 'novel-forge-smoke-'))
|
|
58
|
-
const project = createProject(outline)
|
|
59
|
-
project.chapters = [chapter]
|
|
60
|
-
saveProject(dir, project)
|
|
61
|
-
const loaded = loadProject(dir)
|
|
62
|
-
check('project round-trip', loaded !== undefined && loaded.chapters.length === 1 && loaded.bookName === '测试书')
|
|
63
|
-
|
|
64
|
-
// Simulate a generated file on disk + status sync.
|
|
65
|
-
writeFileSync(join(dir, fileName), '# 第3章 初入宗门/试炼\n\n正文……', 'utf8')
|
|
66
|
-
const files = listChapterFiles(dir)
|
|
67
|
-
check('listChapterFiles finds it', files.includes(fileName), files.join(','))
|
|
68
|
-
syncProjectWithDisk(project, dir)
|
|
69
|
-
check('sync marks done', project.chapters[0]?.status === 'done' && project.chapters[0]?.file === fileName)
|
|
70
|
-
|
|
71
|
-
console.log(failures === 0 ? '\nALL PASS' : `\n${failures} FAILURES`)
|
|
72
|
-
process.exit(failures === 0 ? 0 : 1)
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
# Upload the dsh-novel-forge project to GitHub via the Contents API.
|
|
2
|
-
# Uses the current token (passed as $env:GH_TOKEN) — one PUT per file,
|
|
3
|
-
# directories are created implicitly. Retries transient failures once.
|
|
4
|
-
param(
|
|
5
|
-
[string]$Owner = "watersxya",
|
|
6
|
-
[string]$Repo = "dsh-novel-forge",
|
|
7
|
-
[string]$SourceDir = "C:\Users\Ryan\Desktop\ai xiaoshuo",
|
|
8
|
-
[string]$Branch = "main"
|
|
9
|
-
)
|
|
10
|
-
$ErrorActionPreference = 'Stop'
|
|
11
|
-
$token = $env:GH_TOKEN
|
|
12
|
-
if ([string]::IsNullOrEmpty($token)) { Write-Host "GH_TOKEN env var required"; exit 1 }
|
|
13
|
-
$headers = @{
|
|
14
|
-
Authorization = "Bearer $token"
|
|
15
|
-
'User-Agent' = 'dsh-novel-forge-uploader'
|
|
16
|
-
'X-GitHub-Api-Version' = '2022-11-28'
|
|
17
|
-
}
|
|
18
|
-
$base = "https://api.github.com/repos/$Owner/$Repo/contents"
|
|
19
|
-
$files = Get-ChildItem $SourceDir -Recurse -File
|
|
20
|
-
$log = Join-Path $SourceDir 'upload-log.txt'
|
|
21
|
-
"=== upload started $(Get-Date) ===" | Set-Content $log -Encoding UTF8
|
|
22
|
-
$ok = 0; $failed = 0
|
|
23
|
-
foreach ($file in $files) {
|
|
24
|
-
$rel = $file.FullName.Substring($SourceDir.Length + 1).Replace('\', '/')
|
|
25
|
-
$bytes = [System.IO.File]::ReadAllBytes($file.FullName)
|
|
26
|
-
$contentB64 = [System.Convert]::ToBase64String($bytes)
|
|
27
|
-
$body = @{ message = "Add $rel"; content = $contentB64; branch = $Branch } | ConvertTo-Json
|
|
28
|
-
$done = $false
|
|
29
|
-
for ($attempt = 1; $attempt -le 2 -and -not $done; $attempt++) {
|
|
30
|
-
try {
|
|
31
|
-
$null = Invoke-RestMethod -Uri "$base/$rel" -Headers $headers -Method PUT -Body $body -ContentType "application/json" -TimeoutSec 60
|
|
32
|
-
$done = $true
|
|
33
|
-
$ok++
|
|
34
|
-
"[OK] $rel" | Add-Content $log -Encoding UTF8
|
|
35
|
-
} catch {
|
|
36
|
-
$resp = $_.Exception.Response
|
|
37
|
-
$status = if ($resp) { [int]$resp.StatusCode } else { 0 }
|
|
38
|
-
if ($attempt -eq 2 -or $status -ne 502 -and $status -ne 503) {
|
|
39
|
-
$msg = if ($resp) { (New-Object System.IO.StreamReader($resp.GetResponseStream())).ReadToEnd() } else { $_.Exception.Message }
|
|
40
|
-
$failed++
|
|
41
|
-
"[FAIL] $rel -> HTTP $status $msg" | Add-Content $log -Encoding UTF8
|
|
42
|
-
Write-Host "[FAIL] $rel -> HTTP $status"
|
|
43
|
-
break
|
|
44
|
-
}
|
|
45
|
-
Start-Sleep -Seconds 3
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
if ($done) { Write-Host "[OK] $rel" }
|
|
49
|
-
}
|
|
50
|
-
"=== done: ok=$ok failed=$failed ===" | Add-Content $log -Encoding UTF8
|
|
51
|
-
Write-Host "=== done: ok=$ok failed=$failed ==="
|