auto-mode.test.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. import { test } from 'node:test'
  2. import assert from 'node:assert/strict'
  3. import path from 'node:path'
  4. import { promises as fs } from 'node:fs'
  5. import { determineNextState } from '../../src/state-machine/index.js'
  6. import { stageChapter, rejectFrom } from '../../src/staging/index.js'
  7. import { createGit } from '../../src/finalize/git.js'
  8. import { gitBookCtx } from '../commands/_helper.js'
  9. // 开关矩阵(PRD #14):自动确认细纲 × 连写。全关=既有回归(router.test.js 全量);
  10. // 本文件测:单开细纲自动确认的序 6 标志、批次进行中的序 3 明细。全开端到端见 finalize-batch.test.js AC1。
  11. async function reachOutline(ctx) {
  12. // sample-book 工作区自带细纲 → 会命中序 3,清掉以到达序 6
  13. await fs.rm(path.join(ctx.repoPath, '工作区', '细纲.md'), { force: true })
  14. }
  15. async function setBookYaml(ctx, key, value) {
  16. const p = path.join(ctx.repoPath, 'book.yaml')
  17. const src = await fs.readFile(p, 'utf8')
  18. const line = `${key}: ${value}`
  19. const re = new RegExp(`^${key}:.*$`, 'm')
  20. await fs.writeFile(p, re.test(src) ? src.replace(re, line) : `${src}${line}\n`, 'utf8')
  21. // book.yaml 在跟踪面内(决策 D6),不补登会被序 2 拦——模拟 relink 已完成
  22. const git = createGit(ctx.repoPath)
  23. await git.ensureIdentity()
  24. await git.add(['book.yaml'])
  25. await git.commit(`fix(手改): 配置 ${key}`)
  26. }
  27. async function stage3(ctx) {
  28. await fs.mkdir(path.join(ctx.repoPath, '工作区'), { recursive: true })
  29. await fs.writeFile(
  30. path.join(ctx.repoPath, '工作区', '审稿.md'),
  31. '# 第 3 章审稿单\n\n> 完整两审模式。\n> 共 0 个问题:0 阻断。\n',
  32. 'utf8'
  33. )
  34. const r = await stageChapter(ctx, {
  35. chapterNum: 3,
  36. payload: {
  37. frontMatter: {
  38. 章号: 3,
  39. 标题: '连写3',
  40. 卷: 1,
  41. 书内时间: '夏月初三',
  42. 字数: 100,
  43. 章定位: '推进',
  44. 钩子: '危机钩-强',
  45. 情绪定位: '铺垫',
  46. 伏笔: ['推进 伏笔-001'],
  47. },
  48. body: '第3章正文。',
  49. workspaceFiles: [],
  50. },
  51. })
  52. assert.equal(r.ok, true, r.error)
  53. }
  54. test('开关矩阵:全关 → 序 6 dto.自动确认细纲=false,行为与既有一致', async () => {
  55. const { ctx, cleanup } = await gitBookCtx()
  56. try {
  57. await reachOutline(ctx)
  58. const r = await determineNextState(ctx)
  59. assert.equal(r.序, 6, JSON.stringify(r))
  60. assert.equal(r.dto.自动确认细纲, false)
  61. assert.match(r.dto.期望产物, /作者确认/)
  62. } finally {
  63. await cleanup()
  64. }
  65. })
  66. test('开关矩阵:自动确认细纲开 → 序 6 dto 标志与提案直接生效指引', async () => {
  67. const { ctx, cleanup } = await gitBookCtx()
  68. try {
  69. await reachOutline(ctx)
  70. await setBookYaml(ctx, '自动确认细纲', 'true')
  71. const r = await determineNextState(ctx)
  72. assert.equal(r.序, 6, JSON.stringify(r))
  73. assert.equal(r.dto.自动确认细纲, true)
  74. assert.match(r.dto.期望产物, /不再问作者/)
  75. } finally {
  76. await cleanup()
  77. }
  78. })
  79. test('批次进行中:序 3 dto.批次 带章清单与「继续下一章」建议;打回后建议重写', async () => {
  80. const { ctx, cleanup } = await gitBookCtx()
  81. try {
  82. await reachOutline(ctx)
  83. await stage3(ctx)
  84. const r = await determineNextState(ctx)
  85. assert.equal(r.序, 3, JSON.stringify(r))
  86. assert.equal(r.state, 'resume')
  87. assert.equal(r.dto.从哪继续, '待定稿批次续跑')
  88. assert.equal(r.dto.批次.章数, 1)
  89. assert.deepEqual(r.dto.批次.章, [{ 章号: 3, 标题: '连写3', 状态: '待审收' }])
  90. assert.match(r.dto.批次.建议, /继续批内下一章(第 4 章)/)
  91. const rej = await rejectFrom(ctx.repoPath, 3)
  92. assert.equal(rej.ok, true, rej.error)
  93. const r2 = await determineNextState(ctx)
  94. assert.equal(r2.序, 3)
  95. assert.match(r2.dto.批次.建议, /重写打回章(第 3 章)/)
  96. } finally {
  97. await cleanup()
  98. }
  99. })
  100. test('批次进行中:停止命中(写满)→ 序 3 建议批量过稿', async () => {
  101. const { ctx, cleanup } = await gitBookCtx()
  102. try {
  103. await reachOutline(ctx)
  104. await setBookYaml(ctx, '连写批次大小', '1')
  105. await stage3(ctx)
  106. const r = await determineNextState(ctx)
  107. assert.equal(r.序, 3, JSON.stringify(r))
  108. assert.equal(r.dto.批次.停止.stop, true)
  109. assert.match(r.dto.批次.建议, /批量过稿/)
  110. } finally {
  111. await cleanup()
  112. }
  113. })