feat: ship v0.5.0 with auto and wizard writing modes

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-06 20:57:31 +08:00
parent 86b66a311a
commit 6a949b54ba
38 changed files with 2581 additions and 184 deletions
@@ -0,0 +1,73 @@
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
import { DatabaseSync } from 'node:sqlite'
import { migrate } from '../../src/main/db/migrate'
import { VolumeRepository } from '../../src/main/db/repositories/volume.repo'
import { AiSessionRepository } from '../../src/main/db/repositories/ai-session.repo'
import { InteractiveRepository } from '../../src/main/db/repositories/interactive.repo'
import { SnapshotRepository } from '../../src/main/db/repositories/snapshot.repo'
import { ChapterRepository } from '../../src/main/db/repositories/chapter.repo'
import { ChapterFinishService } from '../../src/main/services/chapter-finish.service'
import { AutoWritingService } from '../../src/main/services/auto-writing.service'
import { handoffToInteractive } from '../../src/main/services/writing-flow-handoff.service'
import type { SqliteDb } from '../../src/main/db/types'
describe('ChapterFinishService', () => {
let db: SqliteDb
let volId: string
let flowId: string
beforeEach(() => {
db = new DatabaseSync(':memory:')
migrate(db)
volId = new VolumeRepository(db).create('卷一', 0).id
const session = new AiSessionRepository(db).create('t', 'm')
flowId = new InteractiveRepository(db).create(session.id).id
new InteractiveRepository(db).addScene(flowId, '<p>场景</p>', 'A')
})
afterEach(() => db.close())
it('IT-FIN-02: creates ai snapshot on interactive finish', () => {
const service = new ChapterFinishService(db)
const { chapterId } = service.finishFromFlow(flowId, volId, '交互初稿', 'interactive', '交互写作成章')
const snaps = new SnapshotRepository(db).list(chapterId)
expect(snaps.some((s) => s.type === 'ai' && s.name.includes('交互'))).toBe(true)
})
it('IT-FIN-01: auto origin and snapshot label', () => {
const service = new ChapterFinishService(db)
const { chapterId } = service.finishFromFlow(flowId, volId, '自动初稿', 'auto', '自动写作成章')
const ch = new ChapterRepository(db).get(chapterId)!
expect(ch.origin).toBe('auto')
const snaps = new SnapshotRepository(db).list(chapterId)
expect(snaps.some((s) => s.name.includes('自动'))).toBe(true)
})
})
describe('auto handoff', () => {
it('IT-AUTO-04: handoff sets flow_mode interactive', () => {
const db = new DatabaseSync(':memory:')
migrate(db)
const session = new AiSessionRepository(db).create('t', 'm')
const repo = new InteractiveRepository(db)
const flow = repo.create(session.id, 'auto', 'auto_generate')
repo.addScene(flow.id, '<p>已生成</p>', '场景1')
const result = handoffToInteractive(repo, flow.id)
expect(result.flowMode).toBe('interactive')
expect(result.step).toBe('plot_suggest')
db.close()
})
})
describe('AutoWritingService.setGoal', () => {
it('advances to scene_plan', () => {
const db = new DatabaseSync(':memory:')
migrate(db)
const session = new AiSessionRepository(db).create('t', 'm')
const service = new AutoWritingService(db, { chat: async () => '' } as never)
const flow = service.start(session.id)
const updated = service.setGoal(flow.id, { chapterGoal: '林远通过入门考核', wordMin: 2000, wordMax: 4000 })
expect(updated.step).toBe('scene_plan')
db.close()
})
})