probe-followup.mjs 3.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. // 补充探针:P-4b 重号章文件(序 0 拦不住的静默截断)、P-7b finalize 清理目录(正确相对路径)
  2. import { promises as fs } from 'node:fs'
  3. import os from 'node:os'
  4. import path from 'node:path'
  5. import { fileURLToPath } from 'node:url'
  6. const V7 = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', '..', '..', 'v7')
  7. const m = (p) => import(`file:///${path.join(V7, p).replace(/\\/g, '/')}`)
  8. const { persistCreateBook } = await m('src/state-machine/persist.js')
  9. const { finalizeChapter } = await m('src/finalize/index.js')
  10. const { determineNextState } = await m('src/state-machine/index.js')
  11. const { CacheManager } = await m('src/cache/index.js')
  12. const { createGit } = await m('src/finalize/git.js')
  13. const tmpRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'wnw-probe2-'))
  14. let n = 0
  15. async function makeBook() {
  16. const repo = path.join(tmpRoot, `book-${++n}`)
  17. await fs.mkdir(repo, { recursive: true })
  18. const r = await persistCreateBook({ repoPath: repo, cache: null }, {
  19. book: { spec_version: '7.0', 书名: `补探${n}`, 类型: '玄幻', 每章目标字数: 3000, 卷规模: 40 },
  20. 总纲: '# 总纲\n\n## 结局\nx\n', 卷纲: '# 第1卷\ny\n',
  21. })
  22. if (!r.ok) throw new Error(r.error)
  23. const cache = new CacheManager(path.join(repo, '.cache', 'index.db'))
  24. await cache.ensureReady(repo)
  25. return { repoPath: repo, cache }
  26. }
  27. const payloadOf = (num, extra = {}) => ({
  28. chapterNum: num,
  29. frontMatter: { 章号: num, 标题: `第${num}章题`, 卷: 1, 书内时间: `夏月初${num}`, 字数: 100, 章定位: '推进', 钩子: '危机钩-强', 情绪定位: '铺垫' },
  30. body: `第${num}章正文。`, summary: `摘${num}`, commitLines: {}, workspaceFiles: [], ...extra,
  31. })
  32. // P-4b: 同章号两个合法文件 → 序 0 不拦 → INSERT 撞主键被吞 → MAX 偏小 → next 重抄
  33. try {
  34. const ctx = await makeBook()
  35. for (const c of [1, 2, 3]) await finalizeChapter(ctx, payloadOf(c))
  36. const chDir = path.join(ctx.repoPath, '定稿', '正文')
  37. // 手改场景:作者复制了一份第 3 章改标题(两文件 front matter 均合法、同章号)
  38. const f3 = (await fs.readdir(chDir)).find((f) => f.startsWith('0003-'))
  39. await fs.copyFile(path.join(chDir, f3), path.join(chDir, '0003-旧稿备份.md'))
  40. const rb = await ctx.cache.rebuildFromSource(ctx.repoPath)
  41. const max = (await ctx.cache.query('SELECT MAX(chapter_num) AS m FROM chapters', []))[0].m
  42. const next = await determineNextState(ctx)
  43. console.log(`P-4b 重号章: rebuild.ok=${rb.ok} warnings=${JSON.stringify(rb.warnings || [])} MAX=${max} next序=${next.序} nextChapter=${next.dto?.nextChapter}`)
  44. console.log(max === 2 && next.dto?.nextChapter === 3 ? '【CONFIRMED】静默丢章+指向重抄已存在的第3章' : `【部分/REFUTED】看上行`)
  45. await ctx.cache.close()
  46. } catch (e) { console.log(`P-4b 异常: ${e.message}`) }
  47. // P-7b: workspaceFiles 含目录(正确相对路径)→ rm 无 recursive
  48. try {
  49. const ctx = await makeBook()
  50. await fs.mkdir(path.join(ctx.repoPath, '工作区', '评审报告'), { recursive: true })
  51. await fs.writeFile(path.join(ctx.repoPath, '工作区', '评审报告', 'a.md'), 'x', 'utf8')
  52. const r = await finalizeChapter(ctx, payloadOf(1, { workspaceFiles: ['评审报告'] }))
  53. const committed = await createGit(ctx.repoPath).findChapterCommit(1)
  54. const dirLeft = await fs.access(path.join(ctx.repoPath, '工作区', '评审报告')).then(() => true, () => false)
  55. console.log(`P-7b 清理目录: finalize.ok=${r.ok} err=${(r.error || '').slice(0, 60)} ch(1)commit=${committed ? '在' : '无'} 目录残留=${dirLeft}`)
  56. console.log(!r.ok && committed ? '【CONFIRMED】已 commit 却报失败(C1 成立)' : r.ok && dirLeft ? '【部分】ok 但目录静默残留(清理漏,弱化版 C1)' : '【REFUTED】')
  57. await ctx.cache.close()
  58. } catch (e) { console.log(`P-7b 异常: ${e.message}`) }
  59. await fs.rm(tmpRoot, { recursive: true, force: true })