@actalk/inkos-core 1.3.6 → 1.3.7

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 (444) hide show
  1. package/dist/agent/agent-session.d.ts +7 -7
  2. package/dist/agent/agent-session.d.ts.map +1 -1
  3. package/dist/agent/agent-session.js +392 -63
  4. package/dist/agent/agent-session.js.map +1 -1
  5. package/dist/agent/agent-system-prompt.d.ts.map +1 -1
  6. package/dist/agent/agent-system-prompt.js +20 -16
  7. package/dist/agent/agent-system-prompt.js.map +1 -1
  8. package/dist/agent/agent-tools.d.ts +4 -1
  9. package/dist/agent/agent-tools.d.ts.map +1 -1
  10. package/dist/agent/agent-tools.js +81 -64
  11. package/dist/agent/agent-tools.js.map +1 -1
  12. package/dist/agents/architect.d.ts +18 -20
  13. package/dist/agents/architect.d.ts.map +1 -1
  14. package/dist/agents/architect.js +513 -632
  15. package/dist/agents/architect.js.map +1 -1
  16. package/dist/agents/chapter-analyzer.d.ts.map +1 -1
  17. package/dist/agents/chapter-analyzer.js +10 -6
  18. package/dist/agents/chapter-analyzer.js.map +1 -1
  19. package/dist/agents/composer.d.ts +1 -13
  20. package/dist/agents/composer.d.ts.map +1 -1
  21. package/dist/agents/composer.js +297 -290
  22. package/dist/agents/composer.js.map +1 -1
  23. package/dist/agents/consolidator.d.ts +17 -1
  24. package/dist/agents/consolidator.d.ts.map +1 -1
  25. package/dist/agents/consolidator.js +44 -6
  26. package/dist/agents/consolidator.js.map +1 -1
  27. package/dist/agents/continuity.d.ts +4 -1
  28. package/dist/agents/continuity.d.ts.map +1 -1
  29. package/dist/agents/continuity.js +111 -21
  30. package/dist/agents/continuity.js.map +1 -1
  31. package/dist/agents/length-normalizer.d.ts.map +1 -1
  32. package/dist/agents/length-normalizer.js +1 -4
  33. package/dist/agents/length-normalizer.js.map +1 -1
  34. package/dist/agents/planner-context.d.ts +54 -0
  35. package/dist/agents/planner-context.d.ts.map +1 -0
  36. package/dist/agents/planner-context.js +245 -0
  37. package/dist/agents/planner-context.js.map +1 -0
  38. package/dist/agents/planner-prompts.d.ts +36 -0
  39. package/dist/agents/planner-prompts.d.ts.map +1 -0
  40. package/dist/agents/planner-prompts.js +350 -0
  41. package/dist/agents/planner-prompts.js.map +1 -0
  42. package/dist/agents/planner.d.ts +39 -11
  43. package/dist/agents/planner.d.ts.map +1 -1
  44. package/dist/agents/planner.js +212 -195
  45. package/dist/agents/planner.js.map +1 -1
  46. package/dist/agents/polisher.d.ts +33 -0
  47. package/dist/agents/polisher.d.ts.map +1 -0
  48. package/dist/agents/polisher.js +122 -0
  49. package/dist/agents/polisher.js.map +1 -0
  50. package/dist/agents/post-write-validator.d.ts +1 -0
  51. package/dist/agents/post-write-validator.d.ts.map +1 -1
  52. package/dist/agents/post-write-validator.js +13 -0
  53. package/dist/agents/post-write-validator.js.map +1 -1
  54. package/dist/agents/reviser.d.ts +6 -2
  55. package/dist/agents/reviser.d.ts.map +1 -1
  56. package/dist/agents/reviser.js +379 -98
  57. package/dist/agents/reviser.js.map +1 -1
  58. package/dist/agents/rules-reader.d.ts +15 -2
  59. package/dist/agents/rules-reader.d.ts.map +1 -1
  60. package/dist/agents/rules-reader.js +49 -6
  61. package/dist/agents/rules-reader.js.map +1 -1
  62. package/dist/agents/state-validator.d.ts +9 -1
  63. package/dist/agents/state-validator.d.ts.map +1 -1
  64. package/dist/agents/state-validator.js +37 -1
  65. package/dist/agents/state-validator.js.map +1 -1
  66. package/dist/agents/writer-prompts.d.ts +1 -0
  67. package/dist/agents/writer-prompts.d.ts.map +1 -1
  68. package/dist/agents/writer-prompts.js +272 -29
  69. package/dist/agents/writer-prompts.js.map +1 -1
  70. package/dist/agents/writer.d.ts +12 -3
  71. package/dist/agents/writer.d.ts.map +1 -1
  72. package/dist/agents/writer.js +77 -107
  73. package/dist/agents/writer.js.map +1 -1
  74. package/dist/index.d.ts +20 -5
  75. package/dist/index.d.ts.map +1 -1
  76. package/dist/index.js +19 -5
  77. package/dist/index.js.map +1 -1
  78. package/dist/interaction/book-session-store.d.ts.map +1 -1
  79. package/dist/interaction/book-session-store.js +84 -69
  80. package/dist/interaction/book-session-store.js.map +1 -1
  81. package/dist/interaction/events.d.ts +2 -2
  82. package/dist/interaction/project-tools.d.ts +1 -0
  83. package/dist/interaction/project-tools.d.ts.map +1 -1
  84. package/dist/interaction/project-tools.js +51 -3
  85. package/dist/interaction/project-tools.js.map +1 -1
  86. package/dist/interaction/session-transcript-legacy.d.ts +4 -0
  87. package/dist/interaction/session-transcript-legacy.d.ts.map +1 -0
  88. package/dist/interaction/session-transcript-legacy.js +100 -0
  89. package/dist/interaction/session-transcript-legacy.js.map +1 -0
  90. package/dist/interaction/session-transcript-restore.d.ts +17 -0
  91. package/dist/interaction/session-transcript-restore.d.ts.map +1 -0
  92. package/dist/interaction/session-transcript-restore.js +493 -0
  93. package/dist/interaction/session-transcript-restore.js.map +1 -0
  94. package/dist/interaction/session-transcript-schema.d.ts +402 -0
  95. package/dist/interaction/session-transcript-schema.d.ts.map +1 -0
  96. package/dist/interaction/session-transcript-schema.js +59 -0
  97. package/dist/interaction/session-transcript-schema.js.map +1 -0
  98. package/dist/interaction/session-transcript.d.ts +14 -0
  99. package/dist/interaction/session-transcript.d.ts.map +1 -0
  100. package/dist/interaction/session-transcript.js +152 -0
  101. package/dist/interaction/session-transcript.js.map +1 -0
  102. package/dist/interaction/session.d.ts +10 -10
  103. package/dist/interaction/session.d.ts.map +1 -1
  104. package/dist/interaction/session.js +5 -3
  105. package/dist/interaction/session.js.map +1 -1
  106. package/dist/llm/provider.d.ts +6 -9
  107. package/dist/llm/provider.d.ts.map +1 -1
  108. package/dist/llm/provider.js +255 -63
  109. package/dist/llm/provider.js.map +1 -1
  110. package/dist/llm/providers/endpoints/ai360.d.ts +10 -0
  111. package/dist/llm/providers/endpoints/ai360.d.ts.map +1 -0
  112. package/dist/llm/providers/endpoints/ai360.js +34 -0
  113. package/dist/llm/providers/endpoints/ai360.js.map +1 -0
  114. package/dist/llm/providers/endpoints/anthropic.d.ts +12 -0
  115. package/dist/llm/providers/endpoints/anthropic.d.ts.map +1 -0
  116. package/dist/llm/providers/endpoints/anthropic.js +72 -0
  117. package/dist/llm/providers/endpoints/anthropic.js.map +1 -0
  118. package/dist/llm/providers/endpoints/astronCodingPlan.d.ts +16 -0
  119. package/dist/llm/providers/endpoints/astronCodingPlan.d.ts.map +1 -0
  120. package/dist/llm/providers/endpoints/astronCodingPlan.js +16 -0
  121. package/dist/llm/providers/endpoints/astronCodingPlan.js.map +1 -0
  122. package/dist/llm/providers/endpoints/baichuan.d.ts +10 -0
  123. package/dist/llm/providers/endpoints/baichuan.d.ts.map +1 -0
  124. package/dist/llm/providers/endpoints/baichuan.js +20 -0
  125. package/dist/llm/providers/endpoints/baichuan.js.map +1 -0
  126. package/dist/llm/providers/endpoints/bailian.d.ts +25 -0
  127. package/dist/llm/providers/endpoints/bailian.d.ts.map +1 -0
  128. package/dist/llm/providers/endpoints/bailian.js +42 -0
  129. package/dist/llm/providers/endpoints/bailian.js.map +1 -0
  130. package/dist/llm/providers/endpoints/bailianCodingPlan.d.ts +10 -0
  131. package/dist/llm/providers/endpoints/bailianCodingPlan.d.ts.map +1 -0
  132. package/dist/llm/providers/endpoints/bailianCodingPlan.js +22 -0
  133. package/dist/llm/providers/endpoints/bailianCodingPlan.js.map +1 -0
  134. package/dist/llm/providers/endpoints/custom.d.ts +16 -0
  135. package/dist/llm/providers/endpoints/custom.d.ts.map +1 -0
  136. package/dist/llm/providers/endpoints/custom.js +15 -0
  137. package/dist/llm/providers/endpoints/custom.js.map +1 -0
  138. package/dist/llm/providers/endpoints/deepseek.d.ts +17 -0
  139. package/dist/llm/providers/endpoints/deepseek.d.ts.map +1 -0
  140. package/dist/llm/providers/endpoints/deepseek.js +20 -0
  141. package/dist/llm/providers/endpoints/deepseek.js.map +1 -0
  142. package/dist/llm/providers/endpoints/giteeai.d.ts +10 -0
  143. package/dist/llm/providers/endpoints/giteeai.d.ts.map +1 -0
  144. package/dist/llm/providers/endpoints/giteeai.js +33 -0
  145. package/dist/llm/providers/endpoints/giteeai.js.map +1 -0
  146. package/dist/llm/providers/endpoints/githubCopilot.d.ts +10 -0
  147. package/dist/llm/providers/endpoints/githubCopilot.d.ts.map +1 -0
  148. package/dist/llm/providers/endpoints/githubCopilot.js +35 -0
  149. package/dist/llm/providers/endpoints/githubCopilot.js.map +1 -0
  150. package/dist/llm/providers/endpoints/glmCodingPlan.d.ts +9 -0
  151. package/dist/llm/providers/endpoints/glmCodingPlan.d.ts.map +1 -0
  152. package/dist/llm/providers/endpoints/glmCodingPlan.js +21 -0
  153. package/dist/llm/providers/endpoints/glmCodingPlan.js.map +1 -0
  154. package/dist/llm/providers/endpoints/google.d.ts +12 -0
  155. package/dist/llm/providers/endpoints/google.d.ts.map +1 -0
  156. package/dist/llm/providers/endpoints/google.js +41 -0
  157. package/dist/llm/providers/endpoints/google.js.map +1 -0
  158. package/dist/llm/providers/endpoints/hunyuan.d.ts +10 -0
  159. package/dist/llm/providers/endpoints/hunyuan.d.ts.map +1 -0
  160. package/dist/llm/providers/endpoints/hunyuan.js +34 -0
  161. package/dist/llm/providers/endpoints/hunyuan.js.map +1 -0
  162. package/dist/llm/providers/endpoints/infiniai.d.ts +10 -0
  163. package/dist/llm/providers/endpoints/infiniai.d.ts.map +1 -0
  164. package/dist/llm/providers/endpoints/infiniai.js +64 -0
  165. package/dist/llm/providers/endpoints/infiniai.js.map +1 -0
  166. package/dist/llm/providers/endpoints/internlm.d.ts +10 -0
  167. package/dist/llm/providers/endpoints/internlm.d.ts.map +1 -0
  168. package/dist/llm/providers/endpoints/internlm.js +20 -0
  169. package/dist/llm/providers/endpoints/internlm.js.map +1 -0
  170. package/dist/llm/providers/endpoints/kimiCodingPlan.d.ts +9 -0
  171. package/dist/llm/providers/endpoints/kimiCodingPlan.d.ts.map +1 -0
  172. package/dist/llm/providers/endpoints/kimiCodingPlan.js +17 -0
  173. package/dist/llm/providers/endpoints/kimiCodingPlan.js.map +1 -0
  174. package/dist/llm/providers/endpoints/longcat.d.ts +9 -0
  175. package/dist/llm/providers/endpoints/longcat.d.ts.map +1 -0
  176. package/dist/llm/providers/endpoints/longcat.js +18 -0
  177. package/dist/llm/providers/endpoints/longcat.js.map +1 -0
  178. package/dist/llm/providers/endpoints/minimax.d.ts +15 -0
  179. package/dist/llm/providers/endpoints/minimax.d.ts.map +1 -0
  180. package/dist/llm/providers/endpoints/minimax.js +26 -0
  181. package/dist/llm/providers/endpoints/minimax.js.map +1 -0
  182. package/dist/llm/providers/endpoints/minimaxCodingPlan.d.ts +9 -0
  183. package/dist/llm/providers/endpoints/minimaxCodingPlan.d.ts.map +1 -0
  184. package/dist/llm/providers/endpoints/minimaxCodingPlan.js +21 -0
  185. package/dist/llm/providers/endpoints/minimaxCodingPlan.js.map +1 -0
  186. package/dist/llm/providers/endpoints/mistral.d.ts +11 -0
  187. package/dist/llm/providers/endpoints/mistral.d.ts.map +1 -0
  188. package/dist/llm/providers/endpoints/mistral.js +31 -0
  189. package/dist/llm/providers/endpoints/mistral.js.map +1 -0
  190. package/dist/llm/providers/endpoints/modelscope.d.ts +10 -0
  191. package/dist/llm/providers/endpoints/modelscope.d.ts.map +1 -0
  192. package/dist/llm/providers/endpoints/modelscope.js +22 -0
  193. package/dist/llm/providers/endpoints/modelscope.js.map +1 -0
  194. package/dist/llm/providers/endpoints/moonshot.d.ts +12 -0
  195. package/dist/llm/providers/endpoints/moonshot.d.ts.map +1 -0
  196. package/dist/llm/providers/endpoints/moonshot.js +29 -0
  197. package/dist/llm/providers/endpoints/moonshot.js.map +1 -0
  198. package/dist/llm/providers/endpoints/newapi.d.ts +14 -0
  199. package/dist/llm/providers/endpoints/newapi.d.ts.map +1 -0
  200. package/dist/llm/providers/endpoints/newapi.js +14 -0
  201. package/dist/llm/providers/endpoints/newapi.js.map +1 -0
  202. package/dist/llm/providers/endpoints/ollama.d.ts +12 -0
  203. package/dist/llm/providers/endpoints/ollama.d.ts.map +1 -0
  204. package/dist/llm/providers/endpoints/ollama.js +63 -0
  205. package/dist/llm/providers/endpoints/ollama.js.map +1 -0
  206. package/dist/llm/providers/endpoints/openai.d.ts +12 -0
  207. package/dist/llm/providers/endpoints/openai.d.ts.map +1 -0
  208. package/dist/llm/providers/endpoints/openai.js +67 -0
  209. package/dist/llm/providers/endpoints/openai.js.map +1 -0
  210. package/dist/llm/providers/endpoints/opencodeCodingPlan.d.ts +9 -0
  211. package/dist/llm/providers/endpoints/opencodeCodingPlan.d.ts.map +1 -0
  212. package/dist/llm/providers/endpoints/opencodeCodingPlan.js +23 -0
  213. package/dist/llm/providers/endpoints/opencodeCodingPlan.js.map +1 -0
  214. package/dist/llm/providers/endpoints/openrouter.d.ts +15 -0
  215. package/dist/llm/providers/endpoints/openrouter.d.ts.map +1 -0
  216. package/dist/llm/providers/endpoints/openrouter.js +74 -0
  217. package/dist/llm/providers/endpoints/openrouter.js.map +1 -0
  218. package/dist/llm/providers/endpoints/ppio.d.ts +15 -0
  219. package/dist/llm/providers/endpoints/ppio.d.ts.map +1 -0
  220. package/dist/llm/providers/endpoints/ppio.js +73 -0
  221. package/dist/llm/providers/endpoints/ppio.js.map +1 -0
  222. package/dist/llm/providers/endpoints/qiniu.d.ts +10 -0
  223. package/dist/llm/providers/endpoints/qiniu.d.ts.map +1 -0
  224. package/dist/llm/providers/endpoints/qiniu.js +24 -0
  225. package/dist/llm/providers/endpoints/qiniu.js.map +1 -0
  226. package/dist/llm/providers/endpoints/sensenova.d.ts +10 -0
  227. package/dist/llm/providers/endpoints/sensenova.d.ts.map +1 -0
  228. package/dist/llm/providers/endpoints/sensenova.js +37 -0
  229. package/dist/llm/providers/endpoints/sensenova.js.map +1 -0
  230. package/dist/llm/providers/endpoints/siliconcloud.d.ts +14 -0
  231. package/dist/llm/providers/endpoints/siliconcloud.d.ts.map +1 -0
  232. package/dist/llm/providers/endpoints/siliconcloud.js +114 -0
  233. package/dist/llm/providers/endpoints/siliconcloud.js.map +1 -0
  234. package/dist/llm/providers/endpoints/spark.d.ts +14 -0
  235. package/dist/llm/providers/endpoints/spark.d.ts.map +1 -0
  236. package/dist/llm/providers/endpoints/spark.js +21 -0
  237. package/dist/llm/providers/endpoints/spark.js.map +1 -0
  238. package/dist/llm/providers/endpoints/stepfun.d.ts +10 -0
  239. package/dist/llm/providers/endpoints/stepfun.d.ts.map +1 -0
  240. package/dist/llm/providers/endpoints/stepfun.js +27 -0
  241. package/dist/llm/providers/endpoints/stepfun.js.map +1 -0
  242. package/dist/llm/providers/endpoints/tencentcloud.d.ts +10 -0
  243. package/dist/llm/providers/endpoints/tencentcloud.d.ts.map +1 -0
  244. package/dist/llm/providers/endpoints/tencentcloud.js +17 -0
  245. package/dist/llm/providers/endpoints/tencentcloud.js.map +1 -0
  246. package/dist/llm/providers/endpoints/volcengine.d.ts +10 -0
  247. package/dist/llm/providers/endpoints/volcengine.d.ts.map +1 -0
  248. package/dist/llm/providers/endpoints/volcengine.js +44 -0
  249. package/dist/llm/providers/endpoints/volcengine.js.map +1 -0
  250. package/dist/llm/providers/endpoints/volcengineCodingPlan.d.ts +19 -0
  251. package/dist/llm/providers/endpoints/volcengineCodingPlan.d.ts.map +1 -0
  252. package/dist/llm/providers/endpoints/volcengineCodingPlan.js +25 -0
  253. package/dist/llm/providers/endpoints/volcengineCodingPlan.js.map +1 -0
  254. package/dist/llm/providers/endpoints/wenxin.d.ts +10 -0
  255. package/dist/llm/providers/endpoints/wenxin.d.ts.map +1 -0
  256. package/dist/llm/providers/endpoints/wenxin.js +98 -0
  257. package/dist/llm/providers/endpoints/wenxin.js.map +1 -0
  258. package/dist/llm/providers/endpoints/xai.d.ts +11 -0
  259. package/dist/llm/providers/endpoints/xai.d.ts.map +1 -0
  260. package/dist/llm/providers/endpoints/xai.js +25 -0
  261. package/dist/llm/providers/endpoints/xai.js.map +1 -0
  262. package/dist/llm/providers/endpoints/xiaomimimo.d.ts +12 -0
  263. package/dist/llm/providers/endpoints/xiaomimimo.d.ts.map +1 -0
  264. package/dist/llm/providers/endpoints/xiaomimimo.js +16 -0
  265. package/dist/llm/providers/endpoints/xiaomimimo.js.map +1 -0
  266. package/dist/llm/providers/endpoints/zeroone.d.ts +10 -0
  267. package/dist/llm/providers/endpoints/zeroone.d.ts.map +1 -0
  268. package/dist/llm/providers/endpoints/zeroone.js +26 -0
  269. package/dist/llm/providers/endpoints/zeroone.js.map +1 -0
  270. package/dist/llm/providers/endpoints/zhipu.d.ts +12 -0
  271. package/dist/llm/providers/endpoints/zhipu.d.ts.map +1 -0
  272. package/dist/llm/providers/endpoints/zhipu.js +51 -0
  273. package/dist/llm/providers/endpoints/zhipu.js.map +1 -0
  274. package/dist/llm/providers/index.d.ts +5 -0
  275. package/dist/llm/providers/index.d.ts.map +1 -0
  276. package/dist/llm/providers/index.js +67 -0
  277. package/dist/llm/providers/index.js.map +1 -0
  278. package/dist/llm/providers/lookup.d.ts +16 -0
  279. package/dist/llm/providers/lookup.d.ts.map +1 -0
  280. package/dist/llm/providers/lookup.js +68 -0
  281. package/dist/llm/providers/lookup.js.map +1 -0
  282. package/dist/llm/providers/probe.d.ts +11 -0
  283. package/dist/llm/providers/probe.d.ts.map +1 -0
  284. package/dist/llm/providers/probe.js +24 -0
  285. package/dist/llm/providers/probe.js.map +1 -0
  286. package/dist/llm/providers/types.d.ts +71 -0
  287. package/dist/llm/providers/types.d.ts.map +1 -0
  288. package/dist/llm/providers/types.js +9 -0
  289. package/dist/llm/providers/types.js.map +1 -0
  290. package/dist/llm/providers/verify.d.ts +27 -0
  291. package/dist/llm/providers/verify.d.ts.map +1 -0
  292. package/dist/llm/providers/verify.js +77 -0
  293. package/dist/llm/providers/verify.js.map +1 -0
  294. package/dist/llm/secrets.d.ts.map +1 -1
  295. package/dist/llm/secrets.js +27 -2
  296. package/dist/llm/secrets.js.map +1 -1
  297. package/dist/llm/service-presets.d.ts +13 -3
  298. package/dist/llm/service-presets.d.ts.map +1 -1
  299. package/dist/llm/service-presets.js +78 -42
  300. package/dist/llm/service-presets.js.map +1 -1
  301. package/dist/llm/service-resolver.d.ts +1 -1
  302. package/dist/llm/service-resolver.d.ts.map +1 -1
  303. package/dist/llm/service-resolver.js +13 -0
  304. package/dist/llm/service-resolver.js.map +1 -1
  305. package/dist/models/book-rules.d.ts +23 -1
  306. package/dist/models/book-rules.d.ts.map +1 -1
  307. package/dist/models/book-rules.js +54 -2
  308. package/dist/models/book-rules.js.map +1 -1
  309. package/dist/models/input-governance.d.ts +20 -244
  310. package/dist/models/input-governance.d.ts.map +1 -1
  311. package/dist/models/input-governance.js +7 -51
  312. package/dist/models/input-governance.js.map +1 -1
  313. package/dist/models/project.d.ts +29 -28
  314. package/dist/models/project.d.ts.map +1 -1
  315. package/dist/models/project.js +11 -9
  316. package/dist/models/project.js.map +1 -1
  317. package/dist/models/runtime-state.d.ts +120 -0
  318. package/dist/models/runtime-state.d.ts.map +1 -1
  319. package/dist/models/runtime-state.js +12 -0
  320. package/dist/models/runtime-state.js.map +1 -1
  321. package/dist/pipeline/agent.d.ts.map +1 -1
  322. package/dist/pipeline/agent.js +59 -10
  323. package/dist/pipeline/agent.js.map +1 -1
  324. package/dist/pipeline/chapter-review-cycle.d.ts +11 -4
  325. package/dist/pipeline/chapter-review-cycle.d.ts.map +1 -1
  326. package/dist/pipeline/chapter-review-cycle.js +156 -73
  327. package/dist/pipeline/chapter-review-cycle.js.map +1 -1
  328. package/dist/pipeline/chapter-truth-validation.d.ts +2 -1
  329. package/dist/pipeline/chapter-truth-validation.d.ts.map +1 -1
  330. package/dist/pipeline/chapter-truth-validation.js +1 -1
  331. package/dist/pipeline/chapter-truth-validation.js.map +1 -1
  332. package/dist/pipeline/persisted-governed-plan.d.ts +1 -0
  333. package/dist/pipeline/persisted-governed-plan.d.ts.map +1 -1
  334. package/dist/pipeline/persisted-governed-plan.js +181 -66
  335. package/dist/pipeline/persisted-governed-plan.js.map +1 -1
  336. package/dist/pipeline/runner.d.ts +20 -17
  337. package/dist/pipeline/runner.d.ts.map +1 -1
  338. package/dist/pipeline/runner.js +359 -84
  339. package/dist/pipeline/runner.js.map +1 -1
  340. package/dist/state/manager.d.ts.map +1 -1
  341. package/dist/state/manager.js +44 -4
  342. package/dist/state/manager.js.map +1 -1
  343. package/dist/state/memory-db.d.ts +6 -0
  344. package/dist/state/memory-db.d.ts.map +1 -1
  345. package/dist/state/memory-db.js.map +1 -1
  346. package/dist/state/runtime-state-store.d.ts.map +1 -1
  347. package/dist/state/runtime-state-store.js +4 -1
  348. package/dist/state/runtime-state-store.js.map +1 -1
  349. package/dist/state/state-projections.d.ts +3 -1
  350. package/dist/state/state-projections.d.ts.map +1 -1
  351. package/dist/state/state-projections.js +58 -15
  352. package/dist/state/state-projections.js.map +1 -1
  353. package/dist/utils/book-id.d.ts +4 -0
  354. package/dist/utils/book-id.d.ts.map +1 -0
  355. package/dist/utils/book-id.js +27 -0
  356. package/dist/utils/book-id.js.map +1 -0
  357. package/dist/utils/chapter-cadence.js +1 -0
  358. package/dist/utils/chapter-cadence.js.map +1 -1
  359. package/dist/utils/chapter-memo-parser.d.ts +19 -0
  360. package/dist/utils/chapter-memo-parser.d.ts.map +1 -0
  361. package/dist/utils/chapter-memo-parser.js +114 -0
  362. package/dist/utils/chapter-memo-parser.js.map +1 -0
  363. package/dist/utils/config-loader.d.ts +7 -11
  364. package/dist/utils/config-loader.d.ts.map +1 -1
  365. package/dist/utils/config-loader.js +13 -253
  366. package/dist/utils/config-loader.js.map +1 -1
  367. package/dist/utils/context-assembly.d.ts +24 -0
  368. package/dist/utils/context-assembly.d.ts.map +1 -0
  369. package/dist/utils/context-assembly.js +77 -0
  370. package/dist/utils/context-assembly.js.map +1 -0
  371. package/dist/utils/effective-llm-config.d.ts +34 -0
  372. package/dist/utils/effective-llm-config.d.ts.map +1 -0
  373. package/dist/utils/effective-llm-config.js +417 -0
  374. package/dist/utils/effective-llm-config.js.map +1 -0
  375. package/dist/utils/governed-working-set.js +1 -1
  376. package/dist/utils/governed-working-set.js.map +1 -1
  377. package/dist/utils/hook-ledger-validator.d.ts +82 -0
  378. package/dist/utils/hook-ledger-validator.d.ts.map +1 -0
  379. package/dist/utils/hook-ledger-validator.js +225 -0
  380. package/dist/utils/hook-ledger-validator.js.map +1 -0
  381. package/dist/utils/hook-lifecycle.d.ts +5 -0
  382. package/dist/utils/hook-lifecycle.d.ts.map +1 -1
  383. package/dist/utils/hook-lifecycle.js +32 -0
  384. package/dist/utils/hook-lifecycle.js.map +1 -1
  385. package/dist/utils/hook-policy.d.ts +0 -17
  386. package/dist/utils/hook-policy.d.ts.map +1 -1
  387. package/dist/utils/hook-policy.js +0 -30
  388. package/dist/utils/hook-policy.js.map +1 -1
  389. package/dist/utils/hook-promotion.d.ts +83 -0
  390. package/dist/utils/hook-promotion.d.ts.map +1 -0
  391. package/dist/utils/hook-promotion.js +241 -0
  392. package/dist/utils/hook-promotion.js.map +1 -0
  393. package/dist/utils/hook-stale-detection.d.ts +51 -0
  394. package/dist/utils/hook-stale-detection.d.ts.map +1 -0
  395. package/dist/utils/hook-stale-detection.js +125 -0
  396. package/dist/utils/hook-stale-detection.js.map +1 -0
  397. package/dist/utils/llm-endpoint-auth.d.ts +5 -0
  398. package/dist/utils/llm-endpoint-auth.d.ts.map +1 -0
  399. package/dist/utils/llm-endpoint-auth.js +36 -0
  400. package/dist/utils/llm-endpoint-auth.js.map +1 -0
  401. package/dist/utils/llm-env.d.ts +14 -0
  402. package/dist/utils/llm-env.d.ts.map +1 -0
  403. package/dist/utils/llm-env.js +53 -0
  404. package/dist/utils/llm-env.js.map +1 -0
  405. package/dist/utils/memory-retrieval.d.ts +23 -1
  406. package/dist/utils/memory-retrieval.d.ts.map +1 -1
  407. package/dist/utils/memory-retrieval.js +45 -2
  408. package/dist/utils/memory-retrieval.js.map +1 -1
  409. package/dist/utils/narrative-control.d.ts +16 -0
  410. package/dist/utils/narrative-control.d.ts.map +1 -0
  411. package/dist/utils/narrative-control.js +131 -0
  412. package/dist/utils/narrative-control.js.map +1 -0
  413. package/dist/utils/path-safety.d.ts +2 -0
  414. package/dist/utils/path-safety.d.ts.map +1 -0
  415. package/dist/utils/path-safety.js +11 -0
  416. package/dist/utils/path-safety.js.map +1 -0
  417. package/dist/utils/planning-materials.d.ts +35 -0
  418. package/dist/utils/planning-materials.d.ts.map +1 -0
  419. package/dist/utils/planning-materials.js +123 -0
  420. package/dist/utils/planning-materials.js.map +1 -0
  421. package/dist/utils/proxy-fetch.d.ts +9 -0
  422. package/dist/utils/proxy-fetch.d.ts.map +1 -0
  423. package/dist/utils/proxy-fetch.js +31 -0
  424. package/dist/utils/proxy-fetch.js.map +1 -0
  425. package/dist/utils/runtime-writer.d.ts +14 -0
  426. package/dist/utils/runtime-writer.d.ts.map +1 -0
  427. package/dist/utils/runtime-writer.js +21 -0
  428. package/dist/utils/runtime-writer.js.map +1 -0
  429. package/dist/utils/spot-fix-patches.d.ts +7 -0
  430. package/dist/utils/spot-fix-patches.d.ts.map +1 -1
  431. package/dist/utils/spot-fix-patches.js +109 -36
  432. package/dist/utils/spot-fix-patches.js.map +1 -1
  433. package/dist/utils/story-markdown.d.ts.map +1 -1
  434. package/dist/utils/story-markdown.js +104 -6
  435. package/dist/utils/story-markdown.js.map +1 -1
  436. package/dist/utils/writing-methodology.d.ts +10 -0
  437. package/dist/utils/writing-methodology.d.ts.map +1 -0
  438. package/dist/utils/writing-methodology.js +163 -0
  439. package/dist/utils/writing-methodology.js.map +1 -0
  440. package/package.json +3 -2
  441. package/dist/utils/hook-agenda.d.ts +0 -21
  442. package/dist/utils/hook-agenda.d.ts.map +0 -1
  443. package/dist/utils/hook-agenda.js +0 -95
  444. package/dist/utils/hook-agenda.js.map +0 -1
@@ -2,7 +2,7 @@ import { chatCompletion, createLLMClient } from "../llm/provider.js";
2
2
  import { ArchitectAgent } from "../agents/architect.js";
3
3
  import { FoundationReviewerAgent } from "../agents/foundation-reviewer.js";
4
4
  import { PlannerAgent } from "../agents/planner.js";
5
- import { ComposerAgent } from "../agents/composer.js";
5
+ import { composeGovernedChapter } from "../agents/composer.js";
6
6
  import { WriterAgent } from "../agents/writer.js";
7
7
  import { LengthNormalizerAgent } from "../agents/length-normalizer.js";
8
8
  import { ChapterAnalyzerAgent } from "../agents/chapter-analyzer.js";
@@ -18,16 +18,17 @@ import { MemoryDB } from "../state/memory-db.js";
18
18
  import { dispatchNotification, dispatchWebhookEvent } from "../notify/dispatcher.js";
19
19
  import { buildLengthSpec, countChapterLength, formatLengthCount, isOutsideHardRange, isOutsideSoftRange, resolveLengthCountingMode } from "../utils/length-metrics.js";
20
20
  import { analyzeLongSpanFatigue } from "../utils/long-span-fatigue.js";
21
+ import { buildWritingMethodologySection } from "../utils/writing-methodology.js";
22
+ import { isNewLayoutBook, readCharacterContext, readStoryFrame, readVolumeMap, } from "../utils/outline-paths.js";
21
23
  import { loadNarrativeMemorySeed, loadSnapshotCurrentStateFacts } from "../state/runtime-state-store.js";
22
24
  import { rewriteStructuredStateFromMarkdown } from "../state/state-bootstrap.js";
23
25
  import { readFile, readdir, writeFile, mkdir, rename, rm, stat } from "node:fs/promises";
24
26
  import { join } from "node:path";
25
- import { readStoryFrame, readVolumeMap, readCharacterContext, readCurrentStateWithFallback, isNewLayoutBook } from "../utils/outline-paths.js";
26
27
  import { parseStateDegradedReviewNote, resolveStateDegradedBaseStatus, retrySettlementAfterValidationFailure, } from "./chapter-state-recovery.js";
27
28
  import { persistChapterArtifacts } from "./chapter-persistence.js";
28
29
  import { runChapterReviewCycle } from "./chapter-review-cycle.js";
29
30
  import { validateChapterTruthPersistence } from "./chapter-truth-validation.js";
30
- import { loadPersistedPlan, relativeToBookDir } from "./persisted-governed-plan.js";
31
+ import { loadPersistedPlan, relativeToBookDir, savePersistedPlan } from "./persisted-governed-plan.js";
31
32
  const SEQUENCE_LEVEL_CATEGORIES = new Set([
32
33
  "Pacing Monotony", "节奏单调",
33
34
  "Mood Monotony", "情绪单调",
@@ -39,6 +40,118 @@ const SEQUENCE_LEVEL_CATEGORIES = new Set([
39
40
  function isSequenceLevelCategory(category) {
40
41
  return SEQUENCE_LEVEL_CATEGORIES.has(category);
41
42
  }
43
+ const DEFAULT_IMPORT_FOUNDATION_MAX_FULL_TEXT_CHARS = 80_000;
44
+ const DEFAULT_IMPORT_CHAPTER_EXCERPT_CHARS = 6_000;
45
+ const DEFAULT_IMPORT_TITLE_CATALOG_CHARS = 24_000;
46
+ const DEFAULT_IMPORT_EDGE_CHAPTER_COUNT = 4;
47
+ const DEFAULT_IMPORT_MIDDLE_ANCHOR_COUNT = 8;
48
+ function formatImportedChapter(chapter, index, language, content = chapter.content) {
49
+ return language === "en"
50
+ ? `Chapter ${index + 1}: ${chapter.title}\n\n${content}`
51
+ : `第${index + 1}章 ${chapter.title}\n\n${content}`;
52
+ }
53
+ function estimateImportFullTextLength(chapters) {
54
+ return chapters.reduce((total, chapter) => total + chapter.title.length + chapter.content.length + 24, 0);
55
+ }
56
+ function excerptHeadTail(text, maxChars, language) {
57
+ const clean = text.trim();
58
+ if (clean.length <= maxChars)
59
+ return clean;
60
+ const headChars = Math.max(200, Math.floor(maxChars * 0.6));
61
+ const tailChars = Math.max(200, maxChars - headChars);
62
+ const omitted = clean.length - headChars - tailChars;
63
+ const marker = language === "en"
64
+ ? `\n\n[... ${omitted} chars omitted for import-context budget ...]\n\n`
65
+ : `\n\n【中间省略 ${omitted} 字,用于控制导入上下文预算】\n\n`;
66
+ return `${clean.slice(0, headChars).trimEnd()}${marker}${clean.slice(-tailChars).trimStart()}`;
67
+ }
68
+ function pickImportAnchorIndexes(chapterCount, edgeChapterCount, middleAnchorCount) {
69
+ const selected = new Set();
70
+ for (let i = 0; i < Math.min(edgeChapterCount, chapterCount); i++)
71
+ selected.add(i);
72
+ for (let i = Math.max(0, chapterCount - edgeChapterCount); i < chapterCount; i++)
73
+ selected.add(i);
74
+ const middleStart = Math.min(edgeChapterCount, chapterCount);
75
+ const middleEnd = Math.max(middleStart, chapterCount - edgeChapterCount);
76
+ const middleSize = middleEnd - middleStart;
77
+ const anchors = Math.min(middleAnchorCount, middleSize);
78
+ for (let i = 0; i < anchors; i++) {
79
+ const offset = Math.floor(((i + 1) * middleSize) / (anchors + 1));
80
+ selected.add(Math.min(chapterCount - 1, middleStart + offset));
81
+ }
82
+ return [...selected].sort((a, b) => a - b);
83
+ }
84
+ function buildTitleCatalog(chapters, language, maxChars) {
85
+ const lines = chapters.map((chapter, index) => language === "en"
86
+ ? `- Chapter ${index + 1}: ${chapter.title} (${chapter.content.length} chars)`
87
+ : `- 第${index + 1}章:${chapter.title}(${chapter.content.length}字)`);
88
+ const joined = lines.join("\n");
89
+ if (joined.length <= maxChars)
90
+ return joined;
91
+ const headBudget = Math.floor(maxChars * 0.55);
92
+ const tailBudget = maxChars - headBudget;
93
+ const head = [];
94
+ const tail = [];
95
+ let headChars = 0;
96
+ let tailChars = 0;
97
+ for (const line of lines) {
98
+ if (headChars + line.length + 1 > headBudget)
99
+ break;
100
+ head.push(line);
101
+ headChars += line.length + 1;
102
+ }
103
+ for (let i = lines.length - 1; i >= 0; i--) {
104
+ const line = lines[i];
105
+ if (tailChars + line.length + 1 > tailBudget)
106
+ break;
107
+ tail.unshift(line);
108
+ tailChars += line.length + 1;
109
+ }
110
+ const omitted = lines.length - head.length - tail.length;
111
+ const marker = language === "en"
112
+ ? `- ... ${omitted} chapter titles omitted ...`
113
+ : `- ……中间 ${omitted} 个章节标题省略……`;
114
+ return [...head, marker, ...tail].join("\n");
115
+ }
116
+ export function buildImportFoundationSource(chapters, language, options = {}) {
117
+ const maxFullTextChars = options.maxFullTextChars ?? DEFAULT_IMPORT_FOUNDATION_MAX_FULL_TEXT_CHARS;
118
+ const chapterExcerptChars = options.chapterExcerptChars ?? DEFAULT_IMPORT_CHAPTER_EXCERPT_CHARS;
119
+ const titleCatalogChars = options.titleCatalogChars ?? DEFAULT_IMPORT_TITLE_CATALOG_CHARS;
120
+ const edgeChapterCount = options.edgeChapterCount ?? DEFAULT_IMPORT_EDGE_CHAPTER_COUNT;
121
+ const middleAnchorCount = options.middleAnchorCount ?? DEFAULT_IMPORT_MIDDLE_ANCHOR_COUNT;
122
+ if (estimateImportFullTextLength(chapters) <= maxFullTextChars) {
123
+ return chapters.map((chapter, index) => formatImportedChapter(chapter, index, language)).join("\n\n---\n\n");
124
+ }
125
+ const anchorIndexes = pickImportAnchorIndexes(chapters.length, edgeChapterCount, middleAnchorCount);
126
+ const header = language === "en"
127
+ ? [
128
+ "## Import foundation source package",
129
+ "",
130
+ `The imported book has ${chapters.length} chapters. To avoid overflowing the LLM context, this package keeps the opening chapters, ending/continuation point, selected middle anchors, and a capped title catalog. Full chapters will still be replayed sequentially after foundation generation to rebuild truth files.`,
131
+ ].join("\n")
132
+ : [
133
+ "## 导入基础设定压缩资料包",
134
+ "",
135
+ `本次导入共 ${chapters.length} 章。为避免超出 LLM 上下文,这里保留开篇、结尾续写点、少量中段锚点和标题目录;完整章节将在后续顺序回放中逐章分析并沉淀 truth files。`,
136
+ ].join("\n");
137
+ const catalogTitle = language === "en" ? "## Capped chapter title catalog" : "## 章节标题目录(截断)";
138
+ const anchorsTitle = language === "en" ? "## Source excerpts for architecture" : "## 用于反推基础设定的正文摘录";
139
+ const anchorText = anchorIndexes
140
+ .map((index) => {
141
+ const chapter = chapters[index];
142
+ return formatImportedChapter(chapter, index, language, excerptHeadTail(chapter.content, chapterExcerptChars, language));
143
+ })
144
+ .join("\n\n---\n\n");
145
+ return [
146
+ header,
147
+ "",
148
+ catalogTitle,
149
+ buildTitleCatalog(chapters, language, titleCatalogChars),
150
+ "",
151
+ anchorsTitle,
152
+ anchorText,
153
+ ].join("\n");
154
+ }
42
155
  export class PipelineRunner {
43
156
  state;
44
157
  config;
@@ -98,7 +211,7 @@ export class PipelineRunner {
98
211
  }
99
212
  }
100
213
  async generateAndReviewFoundation(params) {
101
- const maxRetries = params.maxRetries ?? 2;
214
+ const maxRetries = params.maxRetries ?? this.config.foundationReviewRetries ?? 2;
102
215
  let foundation = await params.generate();
103
216
  for (let attempt = 0; attempt < maxRetries; attempt++) {
104
217
  this.logStage(params.stageLanguage, {
@@ -207,7 +320,6 @@ export class PipelineRunner {
207
320
  apiKey,
208
321
  model: override.model,
209
322
  temperature: base?.temperature ?? 0.7,
210
- maxTokens: base?.maxTokens ?? 8192,
211
323
  thinkingBudget: base?.thinkingBudget ?? 0,
212
324
  apiFormat,
213
325
  stream,
@@ -252,12 +364,13 @@ export class PipelineRunner {
252
364
  const bookDir = this.state.bookDir(book.id);
253
365
  const stagingBookDir = join(this.state.booksDir, `.tmp-book-create-${book.id}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`);
254
366
  const stageLanguage = await this.resolveBookLanguage(book);
367
+ const effectiveExternalContext = options.externalContext ?? this.config.externalContext;
255
368
  this.logStage(stageLanguage, { zh: "生成基础设定", en: "generating foundation" });
256
369
  const { profile: gp } = await this.loadGenreProfile(book.genre);
257
370
  const reviewer = new FoundationReviewerAgent(this.agentCtxFor("foundation-reviewer", book.id));
258
371
  const resolvedLanguage = (book.language ?? gp.language) === "en" ? "en" : "zh";
259
372
  const foundation = await this.generateAndReviewFoundation({
260
- generate: (reviewFeedback) => architect.generateFoundation(book, options.externalContext ?? this.config.externalContext, reviewFeedback),
373
+ generate: (reviewFeedback) => architect.generateFoundation(book, effectiveExternalContext, reviewFeedback),
261
374
  reviewer,
262
375
  mode: "original",
263
376
  language: resolvedLanguage,
@@ -268,8 +381,13 @@ export class PipelineRunner {
268
381
  await this.state.saveBookConfigAt(stagingBookDir, book);
269
382
  this.logStage(stageLanguage, { zh: "写入基础设定文件", en: "writing foundation files" });
270
383
  await architect.writeFoundationFiles(stagingBookDir, foundation, gp.numericalSystem, book.language ?? gp.language);
384
+ if (effectiveExternalContext && effectiveExternalContext.trim().length > 0) {
385
+ const storyDir = join(stagingBookDir, "story");
386
+ await mkdir(storyDir, { recursive: true });
387
+ await writeFile(join(storyDir, "brief.md"), effectiveExternalContext, "utf-8");
388
+ }
271
389
  this.logStage(stageLanguage, { zh: "初始化控制文档", en: "initializing control documents" });
272
- await this.state.ensureControlDocumentsAt(stagingBookDir, book.language ?? gp.language, options.authorIntent ?? this.config.externalContext);
390
+ await this.state.ensureControlDocumentsAt(stagingBookDir, book.language ?? gp.language, options.authorIntent ?? effectiveExternalContext);
273
391
  if (options.currentFocus?.trim()) {
274
392
  await writeFile(join(stagingBookDir, "story", "current_focus.md"), options.currentFocus.trimEnd() + "\n", "utf-8");
275
393
  }
@@ -290,32 +408,20 @@ export class PipelineRunner {
290
408
  }
291
409
  }
292
410
  /**
293
- * Revise an existing book's foundation 把已有书的架构稿重写(legacy 条目式升级
294
- * 到段落式 / Phase 5 书按 feedback 再次调整细节),把架构稿相关文件备份到
295
- * story/.backup-<phase4|phase5>-<timestamp>/。
411
+ * Revise an existing book foundation without touching runtime chapter state.
296
412
  *
297
- * 关键约束:**只改架构稿文件**(outline/ + roles/ + 4 legacy shim),
298
- * 不动任何运行时状态文件(current_state / pending_hooks / particle_ledger /
299
- * subplot_board / emotional_arcs)—— context-transform 里给 LLM 的 upgrade
300
- * hint 承诺"升级只改架构稿,不动已写的章节"保持一致。
301
- *
302
- * 两种来源:
303
- * - legacy 书(没有 outline/story_frame.md):读 story_bible.md 等 4 个
304
- * flat 文件作为原内容
305
- * - Phase 5 书(outline/story_frame.md 已存在):读 outline/ + roles/ 的
306
- * 权威内容作为原内容——**不能读 flat 文件**,那些是 shim(只有指针 + 2000
307
- * 字摘录)会丢信息
413
+ * Legacy books read the flat foundation files as source. Phase 5+ books read
414
+ * the authoritative outline/ and roles/ files instead of the compatibility
415
+ * shims, otherwise large role/story details can be lost during rewrite.
308
416
  */
309
417
  async reviseFoundation(bookId, feedback) {
310
418
  const bookDir = this.state.bookDir(bookId);
311
419
  const storyDir = join(bookDir, "story");
312
420
  const isPhase5 = await isNewLayoutBook(bookDir);
313
- // 1. 备份架构稿相关文件(不包含运行时状态文件,那些不会被动)
314
421
  const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
315
422
  const backupTag = isPhase5 ? "phase5" : "phase4";
316
423
  const backupDir = join(storyDir, `.backup-${backupTag}-${timestamp}`);
317
424
  await mkdir(backupDir, { recursive: true });
318
- // 备份 legacy flat 文件(两种书都有这几个——legacy 是权威,Phase 5 是 shim)
319
425
  const flatFiles = ["story_bible.md", "volume_outline.md", "book_rules.md", "character_matrix.md"];
320
426
  for (const fileName of flatFiles) {
321
427
  try {
@@ -323,33 +429,27 @@ export class PipelineRunner {
323
429
  await writeFile(join(backupDir, fileName), content, "utf-8");
324
430
  }
325
431
  catch {
326
- /* 文件不存在就跳过 */
432
+ // Missing legacy shim files are fine for partially migrated books.
327
433
  }
328
434
  }
329
- // Phase 5 书还要备份权威来源:outline/ 和 roles/ 两个目录
330
435
  if (isPhase5) {
331
436
  await this.copyDirShallow(join(storyDir, "outline"), join(backupDir, "outline"));
332
437
  await this.copyDirRecursive(join(storyDir, "roles"), join(backupDir, "roles"));
333
438
  }
334
- // 2. 读原内容作为 reviseFrom 输入 —— 必须从权威源读
335
439
  const book = await this.state.loadBookConfig(bookId);
336
- let oldStoryBible, oldVolumeOutline, oldBookRules, oldCharacterMatrix;
440
+ let oldStoryBible;
441
+ let oldVolumeOutline;
442
+ let oldBookRules;
443
+ let oldCharacterMatrix;
337
444
  if (isPhase5) {
338
- // Phase 5 书的 story_bible.md / volume_outline.md / character_matrix.md
339
- // 都是 shim(只有指针 + 摘录),信息不完整。从 outline-paths helper 读
340
- // 权威文件:outline/story_frame.md / outline/volume_map.md / roles/**/*.md
341
445
  [oldStoryBible, oldVolumeOutline, oldCharacterMatrix] = await Promise.all([
342
446
  readStoryFrame(bookDir),
343
447
  readVolumeMap(bookDir),
344
448
  readCharacterContext(bookDir),
345
449
  ]);
346
- // book_rules.md 在 Phase 5 下虽然是 shim,但 YAML frontmatter 已经搬到
347
- // story_frame.md 顶部了(writeFoundationFiles 做的合并),这里读 shim
348
- // 文件 OK——里面的"叙事指引摘录"部分是唯一遗留信息。
349
450
  oldBookRules = await readFile(join(storyDir, "book_rules.md"), "utf-8").catch(() => "");
350
451
  }
351
452
  else {
352
- // legacy 书:4 个 flat 文件就是权威
353
453
  [oldStoryBible, oldVolumeOutline, oldBookRules, oldCharacterMatrix] = await Promise.all([
354
454
  readFile(join(storyDir, "story_bible.md"), "utf-8").catch(() => ""),
355
455
  readFile(join(storyDir, "volume_outline.md"), "utf-8").catch(() => ""),
@@ -357,7 +457,6 @@ export class PipelineRunner {
357
457
  readFile(join(storyDir, "character_matrix.md"), "utf-8").catch(() => ""),
358
458
  ]);
359
459
  }
360
- // 3. 架构师按 reviseFrom + feedback 重写
361
460
  const architect = new ArchitectAgent(this.agentCtxFor("architect", bookId));
362
461
  const foundation = await architect.generateFoundation(book, undefined, undefined, {
363
462
  reviseFrom: {
@@ -368,7 +467,6 @@ export class PipelineRunner {
368
467
  userFeedback: feedback,
369
468
  },
370
469
  });
371
- // 4. 可选 foundation-reviewer 审核——挂了只 warn 不阻断
372
470
  const reviewer = new FoundationReviewerAgent(this.agentCtxFor("foundation-reviewer", bookId));
373
471
  const resolvedLanguage = (book.language ?? "zh") === "en" ? "en" : "zh";
374
472
  try {
@@ -378,13 +476,12 @@ export class PipelineRunner {
378
476
  language: resolvedLanguage,
379
477
  });
380
478
  if (!review.passed) {
381
- this.config.logger?.warn?.(`[reviseFoundation] 审核未通过,仍接受转换结果。反馈:${review.overallFeedback ?? ""}`);
479
+ this.config.logger?.warn?.(`[reviseFoundation] Foundation review did not pass; accepting rewrite. Feedback: ${review.overallFeedback ?? ""}`);
382
480
  }
383
481
  }
384
482
  catch (error) {
385
- this.config.logger?.warn?.(`[reviseFoundation] 审核调用失败,跳过:${error instanceof Error ? error.message : String(error)}`);
483
+ this.config.logger?.warn?.(`[reviseFoundation] Foundation review failed and was skipped: ${error instanceof Error ? error.message : String(error)}`);
386
484
  }
387
- // 5. 目录补全 → 写新文件(mode="revise" 不动运行时状态 + 清空旧 role 文件)
388
485
  const outlineDir = join(storyDir, "outline");
389
486
  await mkdir(outlineDir, { recursive: true });
390
487
  await mkdir(join(storyDir, "roles", "主要角色"), { recursive: true });
@@ -392,7 +489,6 @@ export class PipelineRunner {
392
489
  const { profile: gp } = await this.loadGenreProfile(book.genre);
393
490
  await architect.writeFoundationFiles(bookDir, foundation, gp.numericalSystem, book.language ?? gp.language, "revise");
394
491
  }
395
- /** Shallow copy (non-recursive) — used to back up outline/ which has no subdirs. */
396
492
  async copyDirShallow(src, dest) {
397
493
  try {
398
494
  await mkdir(dest, { recursive: true });
@@ -403,15 +499,14 @@ export class PipelineRunner {
403
499
  await writeFile(join(dest, entry), content, "utf-8");
404
500
  }
405
501
  catch {
406
- /* skip files we can't read */
502
+ // Skip unreadable files.
407
503
  }
408
504
  }));
409
505
  }
410
506
  catch {
411
- /* src doesn't exist nothing to back up */
507
+ // Source directory does not exist.
412
508
  }
413
509
  }
414
- /** Recursive copy — used to back up roles/ which has 主要角色/ + 次要角色/. */
415
510
  async copyDirRecursive(src, dest) {
416
511
  try {
417
512
  await mkdir(dest, { recursive: true });
@@ -428,13 +523,13 @@ export class PipelineRunner {
428
523
  await writeFile(destPath, content, "utf-8");
429
524
  }
430
525
  catch {
431
- /* skip */
526
+ // Skip unreadable files.
432
527
  }
433
528
  }
434
529
  }
435
530
  }
436
531
  catch {
437
- /* src doesn't exist */
532
+ // Source directory does not exist.
438
533
  }
439
534
  }
440
535
  /** Import external source material and generate fanfic_canon.md */
@@ -613,7 +708,7 @@ export class PipelineRunner {
613
708
  chapterNumber,
614
709
  intentPath: relativeToBookDir(bookDir, plan.runtimePath),
615
710
  goal: plan.intent.goal,
616
- conflicts: plan.intent.conflicts.map((conflict) => `${conflict.type}: ${conflict.resolution}`),
711
+ conflicts: [],
617
712
  };
618
713
  }
619
714
  async composeChapter(bookId, context) {
@@ -629,7 +724,7 @@ export class PipelineRunner {
629
724
  chapterNumber,
630
725
  intentPath: relativeToBookDir(bookDir, plan.runtimePath),
631
726
  goal: plan.intent.goal,
632
- conflicts: plan.intent.conflicts.map((conflict) => `${conflict.type}: ${conflict.resolution}`),
727
+ conflicts: [],
633
728
  contextPath: relativeToBookDir(bookDir, composed.contextPath),
634
729
  ruleStackPath: relativeToBookDir(bookDir, composed.ruleStackPath),
635
730
  tracePath: relativeToBookDir(bookDir, composed.tracePath),
@@ -723,6 +818,7 @@ export class PipelineRunner {
723
818
  auditOptions: reviseControlInput
724
819
  ? {
725
820
  chapterIntent: reviseControlInput.plan.intentMarkdown,
821
+ chapterMemo: reviseControlInput.plan.memo,
726
822
  contextPackage: reviseControlInput.composed.contextPackage,
727
823
  ruleStack: reviseControlInput.composed.ruleStack,
728
824
  }
@@ -751,6 +847,8 @@ export class PipelineRunner {
751
847
  const reviseOutput = await reviser.reviseChapter(bookDir, content, targetChapter, preRevision.auditResult.issues, mode, book.genre, reviseControlInput
752
848
  ? {
753
849
  chapterIntent: reviseControlInput.plan.intentMarkdown,
850
+ chapterMemo: reviseControlInput.plan.memo,
851
+ chapterIntentData: reviseControlInput.plan.intent,
754
852
  contextPackage: reviseControlInput.composed.contextPackage,
755
853
  ruleStack: reviseControlInput.composed.ruleStack,
756
854
  lengthSpec,
@@ -776,6 +874,7 @@ export class PipelineRunner {
776
874
  ? {
777
875
  temperature: 0,
778
876
  chapterIntent: reviseControlInput.plan.intentMarkdown,
877
+ chapterMemo: reviseControlInput.plan.memo,
779
878
  contextPackage: reviseControlInput.composed.contextPackage,
780
879
  ruleStack: reviseControlInput.composed.ruleStack,
781
880
  truthFileOverrides: {
@@ -914,12 +1013,19 @@ export class PipelineRunner {
914
1013
  return "(文件不存在)";
915
1014
  }
916
1015
  };
1016
+ // Phase 5: prefer the new prose outline files; fall back to legacy paths.
1017
+ const readOutline = async (newRel, legacyRel) => {
1018
+ const preferred = await readSafe(join(storyDir, newRel));
1019
+ if (preferred.trim() && preferred !== "(文件不存在)")
1020
+ return preferred;
1021
+ return readSafe(join(storyDir, legacyRel));
1022
+ };
917
1023
  const [currentState, particleLedger, pendingHooks, storyBible, volumeOutline, bookRules] = await Promise.all([
918
1024
  readSafe(join(storyDir, "current_state.md")),
919
1025
  readSafe(join(storyDir, "particle_ledger.md")),
920
1026
  readSafe(join(storyDir, "pending_hooks.md")),
921
- readStoryFrame(bookDir, "(文件不存在)"),
922
- readVolumeMap(bookDir, "(文件不存在)"),
1027
+ readOutline("outline/story_frame.md", "story_bible.md"),
1028
+ readOutline("outline/volume_map.md", "volume_outline.md"),
923
1029
  readSafe(join(storyDir, "book_rules.md")),
924
1030
  ]);
925
1031
  return { currentState, particleLedger, pendingHooks, storyBible, volumeOutline, bookRules };
@@ -984,6 +1090,8 @@ export class PipelineRunner {
984
1090
  const reducedControlInput = writeInput.chapterIntent && writeInput.contextPackage && writeInput.ruleStack
985
1091
  ? {
986
1092
  chapterIntent: writeInput.chapterIntent,
1093
+ chapterMemo: writeInput.chapterMemo,
1094
+ chapterIntentData: writeInput.chapterIntentData,
987
1095
  contextPackage: writeInput.contextPackage,
988
1096
  ruleStack: writeInput.ruleStack,
989
1097
  }
@@ -991,6 +1099,10 @@ export class PipelineRunner {
991
1099
  const { profile: gp } = await this.loadGenreProfile(book.genre);
992
1100
  const pipelineLang = book.language ?? gp.language;
993
1101
  const lengthSpec = buildLengthSpec(wordCount ?? book.chapterWordCount, pipelineLang);
1102
+ const { normalizePostWriteSurface, validatePostWrite: postWriteValidate, } = await import("../agents/post-write-validator.js");
1103
+ const { validateHookLedger } = await import("../utils/hook-ledger-validator.js");
1104
+ const { readBookRules } = await import("../agents/rules-reader.js");
1105
+ const parsedBookRules = (await readBookRules(bookDir))?.rules ?? null;
994
1106
  // 1. Write chapter
995
1107
  const writer = new WriterAgent(this.agentCtxFor("writer", bookId));
996
1108
  this.logStage(stageLanguage, { zh: "撰写章节草稿", en: "writing chapter draft" });
@@ -1024,11 +1136,27 @@ export class PipelineRunner {
1024
1136
  lengthSpec,
1025
1137
  chapterIntent: writeInput.chapterIntent,
1026
1138
  }),
1139
+ normalizePostWriteSurface: (chapterContent) => normalizePostWriteSurface(chapterContent, pipelineLang),
1027
1140
  assertChapterContentNotEmpty: (content, stage) => this.assertChapterContentNotEmpty(content, chapterNumber, stage),
1028
1141
  addUsage: PipelineRunner.addUsage,
1029
- restoreLostAuditIssues: (previous, next) => this.restoreLostAuditIssues(previous, next),
1030
- analyzeAITells,
1031
- analyzeSensitiveWords,
1142
+ analyzeAITells: (content) => analyzeAITells(content, pipelineLang),
1143
+ analyzeSensitiveWords: (content) => analyzeSensitiveWords(content, undefined, pipelineLang),
1144
+ runPostWriteChecks: (content) => {
1145
+ const baseIssues = postWriteValidate(content, gp, parsedBookRules, pipelineLang)
1146
+ .filter((v) => v.severity === "error")
1147
+ .map((v) => ({
1148
+ severity: "critical",
1149
+ category: v.rule,
1150
+ description: v.description,
1151
+ suggestion: v.suggestion,
1152
+ }));
1153
+ // Phase 9-3: verify the draft acts on every hook the memo committed to.
1154
+ const memoBody = writeInput.chapterMemo?.body ?? "";
1155
+ const ledgerIssues = memoBody
1156
+ ? validateHookLedger(memoBody, content)
1157
+ : [];
1158
+ return [...baseIssues, ...ledgerIssues];
1159
+ },
1032
1160
  logWarn: (message) => this.logWarn(pipelineLang, message),
1033
1161
  logStage: (message) => this.logStage(stageLanguage, message),
1034
1162
  });
@@ -1039,6 +1167,59 @@ export class PipelineRunner {
1039
1167
  let auditResult = reviewResult.auditResult;
1040
1168
  const postReviseCount = reviewResult.postReviseCount;
1041
1169
  const normalizeApplied = reviewResult.normalizeApplied;
1170
+ // 3b. File-layer polish pass — runs AFTER structural audit accepts the
1171
+ // chapter. Polisher only touches sentence craft / paragraph shape /
1172
+ // wording / sensory detail / dialogue naturalness. Plot / character /
1173
+ // mainline stay frozen. Skipped when audit did not produce a passing
1174
+ // chapter (leave the failing draft visible for the next cycle) or when
1175
+ // length is dangerously off-range (normalize should handle it, not polish).
1176
+ if (auditResult.passed) {
1177
+ try {
1178
+ const { PolisherAgent } = await import("../agents/polisher.js");
1179
+ const polisher = new PolisherAgent(this.agentCtxFor("polisher", bookId));
1180
+ this.logStage(stageLanguage, { zh: "文字层润色", en: "polishing prose" });
1181
+ const polishOutput = await polisher.polishChapter({
1182
+ chapterContent: finalContent,
1183
+ chapterNumber,
1184
+ chapterMemo: reducedControlInput?.chapterMemo,
1185
+ language: pipelineLang === "en" ? "en" : "zh",
1186
+ });
1187
+ totalUsage = PipelineRunner.addUsage(totalUsage, polishOutput.tokenUsage);
1188
+ if (polishOutput.changed && polishOutput.polishedContent.trim().length > 0) {
1189
+ finalContent = normalizePostWriteSurface(polishOutput.polishedContent, pipelineLang);
1190
+ finalWordCount = countChapterLength(finalContent, lengthSpec.countingMode);
1191
+ }
1192
+ }
1193
+ catch (error) {
1194
+ this.logWarn(pipelineLang, {
1195
+ zh: `润色阶段失败:${error instanceof Error ? error.message : String(error)}`,
1196
+ en: `polish stage failed: ${error instanceof Error ? error.message : String(error)}`,
1197
+ });
1198
+ }
1199
+ }
1200
+ // 3c. Lightweight per-chapter promotion pass — check if any hooks should
1201
+ // be promoted based on advanced_count derived from chapter_summaries.
1202
+ // Runs BEFORE persistence so the reviewer of the NEXT chapter sees the
1203
+ // updated ledger. No LLM calls — pure ledger parse + threshold check.
1204
+ {
1205
+ const { rerunPromotionPass } = await import("../utils/hook-promotion.js");
1206
+ const { parsePendingHooksMarkdown, renderHookSnapshot } = await import("../utils/story-markdown.js");
1207
+ const promotionStoryDir = join(bookDir, "story");
1208
+ const ledgerPath = join(promotionStoryDir, "pending_hooks.md");
1209
+ const ledgerRaw = await readFile(ledgerPath, "utf-8").catch(() => "");
1210
+ if (ledgerRaw.trim()) {
1211
+ const hooks = parsePendingHooksMarkdown(ledgerRaw);
1212
+ if (hooks.length > 0) {
1213
+ const summariesRaw = await readFile(join(promotionStoryDir, "chapter_summaries.md"), "utf-8").catch(() => "");
1214
+ const promotionResult = rerunPromotionPass(hooks, summariesRaw);
1215
+ if (promotionResult.updated) {
1216
+ const ledgerLang = /[\u4e00-\u9fff]/.test(ledgerRaw) ? "zh" : "en";
1217
+ await writeFile(ledgerPath, renderHookSnapshot([...promotionResult.hooks], ledgerLang), "utf-8");
1218
+ this.config.logger?.info(`[promotion] ${promotionResult.flippedCount} hook(s) promoted after chapter ${chapterNumber}`);
1219
+ }
1220
+ }
1221
+ }
1222
+ }
1042
1223
  // 4. Save the final chapter and truth files from a single persistence source
1043
1224
  this.logStage(stageLanguage, { zh: "落盘最终章节", en: "persisting final chapter" });
1044
1225
  this.logStage(stageLanguage, { zh: "生成最终真相文件", en: "rebuilding final truth files" });
@@ -1102,10 +1283,13 @@ export class PipelineRunner {
1102
1283
  // 4.1 Validate settler output before writing
1103
1284
  this.logStage(stageLanguage, { zh: "校验真相文件变更", en: "validating truth file updates" });
1104
1285
  const storyDir = join(bookDir, "story");
1105
- const [oldState, oldHooks, oldLedger] = await Promise.all([
1286
+ const [oldState, oldHooks, oldLedger, authorityStoryFrame, authorityBookRules, authorityChapterSummaries] = await Promise.all([
1106
1287
  readFile(join(storyDir, "current_state.md"), "utf-8").catch(() => ""),
1107
1288
  readFile(join(storyDir, "pending_hooks.md"), "utf-8").catch(() => ""),
1108
1289
  readFile(join(storyDir, "particle_ledger.md"), "utf-8").catch(() => ""),
1290
+ readStoryFrame(bookDir).catch(() => ""),
1291
+ readFile(join(storyDir, "book_rules.md"), "utf-8").catch(() => ""),
1292
+ readFile(join(storyDir, "chapter_summaries.md"), "utf-8").catch(() => ""),
1109
1293
  ]);
1110
1294
  const validator = new StateValidatorAgent(this.agentCtxFor("state-validator", bookId));
1111
1295
  const truthValidation = await validateChapterTruthPersistence({
@@ -1123,6 +1307,11 @@ export class PipelineRunner {
1123
1307
  oldHooks,
1124
1308
  oldLedger,
1125
1309
  },
1310
+ authorityContext: {
1311
+ storyFrame: authorityStoryFrame,
1312
+ bookRules: authorityBookRules,
1313
+ chapterSummaries: authorityChapterSummaries,
1314
+ },
1126
1315
  reducedControlInput,
1127
1316
  language: pipelineLang,
1128
1317
  logWarn: (message) => this.logWarn(pipelineLang, message),
@@ -1464,21 +1653,36 @@ export class PipelineRunner {
1464
1653
  * Also saves the statistical style_profile.json.
1465
1654
  */
1466
1655
  async generateStyleGuide(bookId, referenceText, sourceName) {
1467
- if (referenceText.length < 500) {
1468
- throw new Error(`Reference text too short (${referenceText.length} chars, minimum 500). Provide at least 2000 chars for reliable style extraction.`);
1656
+ const sample = referenceText.trim();
1657
+ if (!sample) {
1658
+ throw new Error("Reference text is required for style extraction.");
1469
1659
  }
1470
1660
  const { analyzeStyle } = await import("../agents/style-analyzer.js");
1471
1661
  const bookDir = this.state.bookDir(bookId);
1472
1662
  const storyDir = join(bookDir, "story");
1473
1663
  await mkdir(storyDir, { recursive: true });
1474
1664
  // Statistical fingerprint
1475
- const profile = analyzeStyle(referenceText, sourceName);
1665
+ const profile = analyzeStyle(sample, sourceName);
1476
1666
  await writeFile(join(storyDir, "style_profile.json"), JSON.stringify(profile, null, 2), "utf-8");
1477
- // LLM qualitative extraction
1478
- const response = await chatCompletion(this.config.client, this.config.model, [
1479
- {
1480
- role: "system",
1481
- content: `你是一位文学风格分析专家。分析参考文本的写作风格,提取可供模仿的定性特征。
1667
+ const book = await this.state.loadBookConfig(bookId);
1668
+ const { profile: gp } = await this.loadGenreProfile(book.genre);
1669
+ const lang = (book.language ?? gp.language) === "en" ? "en" : "zh";
1670
+ let qualitativeGuide;
1671
+ if (sample.length < 500) {
1672
+ qualitativeGuide = this.buildDeterministicStyleGuide(profile, {
1673
+ language: lang,
1674
+ reason: lang === "en"
1675
+ ? `The sample is short (${sample.length} chars), so this guide uses the statistical fingerprint instead of LLM qualitative extraction.`
1676
+ : `样本文本较短(${sample.length}字),本次先使用统计指纹生成文风指南,不强行调用 LLM 做定性拆解。`,
1677
+ });
1678
+ }
1679
+ else {
1680
+ try {
1681
+ // LLM qualitative extraction
1682
+ const response = await chatCompletion(this.config.client, this.config.model, [
1683
+ {
1684
+ role: "system",
1685
+ content: `你是一位文学风格分析专家。分析参考文本的写作风格,提取可供模仿的定性特征。
1482
1686
 
1483
1687
  输出格式(Markdown):
1484
1688
  ## 叙事声音与语气
@@ -1506,14 +1710,76 @@ export class PipelineRunner {
1506
1710
  (任何值得模仿的个人写作习惯)
1507
1711
 
1508
1712
  分析必须基于原文实际特征,不要泛泛而谈。每个部分用1-2个原文例句佐证。`,
1509
- },
1510
- {
1511
- role: "user",
1512
- content: `分析以下参考文本的写作风格:\n\n${referenceText.slice(0, 20000)}`,
1513
- },
1514
- ], { temperature: 0.3 });
1515
- await writeFile(join(storyDir, "style_guide.md"), response.content, "utf-8");
1516
- return response.content;
1713
+ },
1714
+ {
1715
+ role: "user",
1716
+ content: `分析以下参考文本的写作风格:\n\n${sample.slice(0, 20000)}`,
1717
+ },
1718
+ ], { temperature: 0.3 });
1719
+ qualitativeGuide = response.content.trim()
1720
+ ? response.content
1721
+ : this.buildDeterministicStyleGuide(profile, {
1722
+ language: lang,
1723
+ reason: lang === "en"
1724
+ ? "The LLM returned empty style analysis; using the statistical fingerprint fallback."
1725
+ : "LLM 未返回有效文风分析,本次使用统计指纹兜底生成文风指南。",
1726
+ });
1727
+ }
1728
+ catch (error) {
1729
+ qualitativeGuide = this.buildDeterministicStyleGuide(profile, {
1730
+ language: lang,
1731
+ reason: lang === "en"
1732
+ ? `LLM qualitative extraction failed: ${error instanceof Error ? error.message : String(error)}. Using the statistical fingerprint fallback.`
1733
+ : `LLM 定性拆解失败:${error instanceof Error ? error.message : String(error)}。本次使用统计指纹兜底生成文风指南。`,
1734
+ });
1735
+ }
1736
+ }
1737
+ const craftMethodology = buildWritingMethodologySection(lang);
1738
+ const fullStyleGuide = `${qualitativeGuide}\n\n${craftMethodology}`;
1739
+ await writeFile(join(storyDir, "style_guide.md"), fullStyleGuide, "utf-8");
1740
+ return fullStyleGuide;
1741
+ }
1742
+ buildDeterministicStyleGuide(profile, options) {
1743
+ if (options.language === "en") {
1744
+ return [
1745
+ "# Style Guide",
1746
+ "",
1747
+ `> ${options.reason}`,
1748
+ "",
1749
+ "## Statistical Fingerprint",
1750
+ `- Source: ${profile.sourceName ?? "unknown"}`,
1751
+ `- Average sentence length: ${profile.avgSentenceLength}`,
1752
+ `- Sentence length variance: ${profile.sentenceLengthStdDev}`,
1753
+ `- Average paragraph length: ${profile.avgParagraphLength}`,
1754
+ `- Vocabulary diversity: ${Math.round(profile.vocabularyDiversity * 100)}%`,
1755
+ profile.topPatterns.length > 0 ? `- Repeated openings: ${profile.topPatterns.join(", ")}` : "- Repeated openings: none obvious in this sample",
1756
+ profile.rhetoricalFeatures.length > 0 ? `- Rhetorical features: ${profile.rhetoricalFeatures.join(", ")}` : "- Rhetorical features: none obvious in this sample",
1757
+ "",
1758
+ "## How To Use",
1759
+ "- Treat this as a lightweight style fingerprint, not a full imitation bible.",
1760
+ "- Keep sentence and paragraph rhythm close to the sample when drafting.",
1761
+ "- If this guide feels too thin, import a longer excerpt later; the file will be replaced.",
1762
+ ].join("\n");
1763
+ }
1764
+ return [
1765
+ "# 文风指南",
1766
+ "",
1767
+ `> ${options.reason}`,
1768
+ "",
1769
+ "## 统计风格指纹",
1770
+ `- 来源:${profile.sourceName ?? "unknown"}`,
1771
+ `- 平均句长:${profile.avgSentenceLength}`,
1772
+ `- 句长波动:${profile.sentenceLengthStdDev}`,
1773
+ `- 平均段落长度:${profile.avgParagraphLength}`,
1774
+ `- 词汇多样性:${Math.round(profile.vocabularyDiversity * 100)}%`,
1775
+ profile.topPatterns.length > 0 ? `- 高频句首/模式:${profile.topPatterns.join("、")}` : "- 高频句首/模式:样本内不明显",
1776
+ profile.rhetoricalFeatures.length > 0 ? `- 修辞特征:${profile.rhetoricalFeatures.join("、")}` : "- 修辞特征:样本内不明显",
1777
+ "",
1778
+ "## 使用方式",
1779
+ "- 这是一份轻量文风指纹,不是完整仿写圣经。",
1780
+ "- 后续写作优先参考句长、段落长度、节奏波动和可见修辞。",
1781
+ "- 如果想得到更稳定的定性拆解,后续可以导入更长片段覆盖本文件。",
1782
+ ].join("\n");
1517
1783
  }
1518
1784
  /**
1519
1785
  * Import canon from parent book for spinoff writing.
@@ -1541,15 +1807,22 @@ export class PipelineRunner {
1541
1807
  }
1542
1808
  };
1543
1809
  const parentBook = await this.state.loadBookConfig(parentBookId);
1810
+ // Phase 5: parent book may be on the new prose layout; prefer outline/.
1811
+ const readParentOutline = async (newRel, legacyRel) => {
1812
+ const preferred = await readSafe(join(parentDir, "story", newRel));
1813
+ if (preferred.trim() && preferred !== "(无)")
1814
+ return preferred;
1815
+ return readSafe(join(parentDir, "story", legacyRel));
1816
+ };
1544
1817
  const [storyBible, currentState, ledger, hooks, summaries, subplots, emotions, matrix] = await Promise.all([
1545
- readStoryFrame(parentDir, "(无)"),
1546
- readCurrentStateWithFallback(parentDir, "(无)"),
1818
+ readParentOutline("outline/story_frame.md", "story_bible.md"),
1819
+ readSafe(join(parentDir, "story/current_state.md")),
1547
1820
  readSafe(join(parentDir, "story/particle_ledger.md")),
1548
1821
  readSafe(join(parentDir, "story/pending_hooks.md")),
1549
1822
  readSafe(join(parentDir, "story/chapter_summaries.md")),
1550
1823
  readSafe(join(parentDir, "story/subplot_board.md")),
1551
1824
  readSafe(join(parentDir, "story/emotional_arcs.md")),
1552
- readCharacterContext(parentDir, "(无)"),
1825
+ readSafe(join(parentDir, "story/character_matrix.md")),
1553
1826
  ]);
1554
1827
  const response = await chatCompletion(this.config.client, this.config.model, [
1555
1828
  {
@@ -1679,7 +1952,7 @@ ${matrix}`,
1679
1952
  * Import existing chapters into a book. Reverse-engineers all truth files
1680
1953
  * via sequential replay so the Writer and Auditor can continue naturally.
1681
1954
  *
1682
- * Step 1: Generate foundation (story_bible, volume_outline, book_rules) from all chapters.
1955
+ * Step 1: Generate foundation (story_frame, volume_map, book_rules) from all chapters.
1683
1956
  * Step 2: Sequentially replay each chapter through ChapterAnalyzer to build truth files.
1684
1957
  */
1685
1958
  async importChapters(input) {
@@ -1697,31 +1970,29 @@ ${matrix}`,
1697
1970
  zh: `步骤 1:从 ${input.chapters.length} 章生成基础设定...`,
1698
1971
  en: `Step 1: Generating foundation from ${input.chapters.length} chapters...`,
1699
1972
  }));
1700
- const allText = input.chapters.map((c, i) => resolvedLanguage === "en"
1701
- ? `Chapter ${i + 1}: ${c.title}\n\n${c.content}`
1702
- : `第${i + 1}章 ${c.title}\n\n${c.content}`).join("\n\n---\n\n");
1973
+ const foundationSource = buildImportFoundationSource(input.chapters, resolvedLanguage);
1703
1974
  const architect = new ArchitectAgent(this.agentCtxFor("architect", input.bookId));
1704
1975
  const isSeries = input.importMode === "series";
1705
1976
  const foundation = isSeries
1706
1977
  ? await this.generateAndReviewFoundation({
1707
- generate: (reviewFeedback) => architect.generateFoundationFromImport(book, allText, undefined, reviewFeedback, { importMode: "series" }),
1978
+ generate: (reviewFeedback) => architect.generateFoundationFromImport(book, foundationSource, undefined, reviewFeedback, { importMode: "series" }),
1708
1979
  reviewer: new FoundationReviewerAgent(this.agentCtxFor("foundation-reviewer", input.bookId)),
1709
1980
  mode: "series",
1710
1981
  language: resolvedLanguage === "en" ? "en" : "zh",
1711
1982
  stageLanguage: resolvedLanguage,
1712
1983
  })
1713
- : await architect.generateFoundationFromImport(book, allText);
1984
+ : await architect.generateFoundationFromImport(book, foundationSource);
1714
1985
  await architect.writeFoundationFiles(bookDir, foundation, gp.numericalSystem, resolvedLanguage);
1715
1986
  await this.resetImportReplayTruthFiles(bookDir, resolvedLanguage);
1716
1987
  await this.state.saveChapterIndex(input.bookId, []);
1717
1988
  await this.state.snapshotState(input.bookId, 0);
1718
1989
  // Generate style guide from imported chapters
1719
- if (allText.length >= 500) {
1990
+ if (foundationSource.length >= 500) {
1720
1991
  log?.info(this.localize(resolvedLanguage, {
1721
1992
  zh: "提取原文风格指纹...",
1722
1993
  en: "Extracting source style fingerprint...",
1723
1994
  }));
1724
- await this.tryGenerateStyleGuide(input.bookId, allText, book.title, resolvedLanguage);
1995
+ await this.tryGenerateStyleGuide(input.bookId, foundationSource, book.title, resolvedLanguage);
1725
1996
  }
1726
1997
  log?.info(this.localize(resolvedLanguage, {
1727
1998
  zh: "基础设定已生成。",
@@ -1868,9 +2139,10 @@ ${matrix}`,
1868
2139
  const { plan, composed } = await this.createGovernedArtifacts(book, bookDir, chapterNumber, externalContext, { reuseExistingIntentWhenContextMissing: true });
1869
2140
  return {
1870
2141
  chapterIntent: plan.intentMarkdown,
2142
+ chapterMemo: plan.memo,
2143
+ chapterIntentData: plan.intent,
1871
2144
  contextPackage: composed.contextPackage,
1872
2145
  ruleStack: composed.ruleStack,
1873
- trace: composed.trace,
1874
2146
  };
1875
2147
  }
1876
2148
  async resetImportReplayTruthFiles(bookDir, language) {
@@ -2367,8 +2639,7 @@ ${matrix}`,
2367
2639
  }
2368
2640
  async createGovernedArtifacts(book, bookDir, chapterNumber, externalContext, options) {
2369
2641
  const plan = await this.resolveGovernedPlan(book, bookDir, chapterNumber, externalContext, options);
2370
- const composer = new ComposerAgent(this.agentCtxFor("composer", book.id));
2371
- const composed = await composer.composeChapter({
2642
+ const composed = await composeGovernedChapter({
2372
2643
  book,
2373
2644
  bookDir,
2374
2645
  chapterNumber,
@@ -2384,12 +2655,16 @@ ${matrix}`,
2384
2655
  return persisted;
2385
2656
  }
2386
2657
  const planner = new PlannerAgent(this.agentCtxFor("planner", book.id));
2387
- return planner.planChapter({
2658
+ const plan = await planner.planChapter({
2388
2659
  book,
2389
2660
  bookDir,
2390
2661
  chapterNumber,
2391
2662
  externalContext,
2392
2663
  });
2664
+ // Persist in the new memo format so subsequent compose/write phases can
2665
+ // skip the planner LLM call when no new context is supplied.
2666
+ await savePersistedPlan(bookDir, plan);
2667
+ return plan;
2393
2668
  }
2394
2669
  async emitWebhook(event, bookId, chapterNumber, data) {
2395
2670
  if (!this.config.notifyChannels || this.config.notifyChannels.length === 0)