dto.js 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. import { promises as fs } from 'node:fs'
  2. import path from 'node:path'
  3. import { assembleBookStatus } from '../prep/book-status.js'
  4. /**
  5. * 为 AI 态组装上下文 DTO(M3 只备料,不调 AI)。M4 吃 DTO 出结构化产物,
  6. * 产物回流由 M3 落盘(M4 不碰文件)。每个 DTO 标注 `期望产物` 告诉 M4 该产出什么。
  7. * @param {{repoPath, cache}} ctx
  8. * @param {number} 序
  9. * @param {object} base 路由已知信息(failures / 卷 / nextChapter)
  10. */
  11. export async function buildDto(ctx, 序, base = {}) {
  12. switch (序) {
  13. case 0:
  14. return {
  15. state: 'repair-confirm',
  16. failures: base.failures || [],
  17. 期望产物: '逐个给出「保留作者意图」的修复方案,作者确认后由 M3 写回',
  18. }
  19. case 1:
  20. return {
  21. state: 'create-book',
  22. 缺: await whatsMissing(ctx),
  23. 期望产物: '问答生成 book.yaml + 总纲 + 第一卷卷纲(由 M3 落盘 + 登记 books.jsonl)',
  24. }
  25. case 4: {
  26. const status = await assembleBookStatus(ctx)
  27. return {
  28. state: 'volume-review',
  29. 卷: base.卷,
  30. 全书近况: status.ok ? status.markdown : '',
  31. 悬了太久: status.ok ? status.data.悬了太久 : [],
  32. 期望产物: '卷摘要 + 下卷卷纲 + 伏笔机会候选(作者勾选后 M3 生成条目)',
  33. }
  34. }
  35. case 6: {
  36. const status = await assembleBookStatus(ctx)
  37. return {
  38. state: 'draft-outline',
  39. nextChapter: base.nextChapter,
  40. 全书近况: status.ok ? status.markdown : '',
  41. 期望产物: '工作区/细纲.md(含本章定位声明 + 本章要写到的事 + 备选,由 M3 落盘);卷近尾声时提案可含收卷提议(依据卷纲进度与卷规模参考值,作者确认后定稿写入 收卷: 是)',
  42. }
  43. }
  44. default:
  45. return { state: base.state || 'unknown' }
  46. }
  47. }
  48. async function whatsMissing(ctx) {
  49. const missing = []
  50. for (const [label, rel] of [
  51. ['book.yaml', 'book.yaml'],
  52. ['总纲', '大纲/总纲.md'],
  53. ]) {
  54. try {
  55. await fs.access(path.join(ctx.repoPath, rel))
  56. } catch {
  57. missing.push(label)
  58. }
  59. }
  60. return missing
  61. }