feat: ship v1.2.0 Wave 1 foundation with book settings, chapter management, and focus mode
Deliver schema v9, book/chapter IPC extensions, BookSettingsTab, chapter meta/tags, AI session menu, focus mode and TTS, template context enrich, and Wave 1 E2E coverage. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
import type { ChapterTag } from '../../../shared/types'
|
||||
import type { SqliteDb } from '../types'
|
||||
|
||||
function mapRow(row: Record<string, unknown>): ChapterTag {
|
||||
return {
|
||||
chapterId: row.chapter_id as string,
|
||||
tag: row.tag as string,
|
||||
color: (row.color as string) ?? ''
|
||||
}
|
||||
}
|
||||
|
||||
export class ChapterTagRepository {
|
||||
constructor(private db: SqliteDb) {}
|
||||
|
||||
list(chapterId: string): ChapterTag[] {
|
||||
return (
|
||||
this.db
|
||||
.prepare('SELECT * FROM chapter_tags WHERE chapter_id = ? ORDER BY tag')
|
||||
.all(chapterId) as Record<string, unknown>[]
|
||||
).map(mapRow)
|
||||
}
|
||||
|
||||
listAll(): ChapterTag[] {
|
||||
return (
|
||||
this.db.prepare('SELECT * FROM chapter_tags ORDER BY chapter_id, tag').all() as Record<
|
||||
string,
|
||||
unknown
|
||||
>[]
|
||||
).map(mapRow)
|
||||
}
|
||||
|
||||
set(chapterId: string, tag: string, color = ''): void {
|
||||
this.db
|
||||
.prepare(
|
||||
`INSERT INTO chapter_tags (chapter_id, tag, color) VALUES (?, ?, ?)
|
||||
ON CONFLICT(chapter_id, tag) DO UPDATE SET color = excluded.color`
|
||||
)
|
||||
.run(chapterId, tag, color)
|
||||
}
|
||||
|
||||
remove(chapterId: string, tag: string): void {
|
||||
this.db.prepare('DELETE FROM chapter_tags WHERE chapter_id = ? AND tag = ?').run(chapterId, tag)
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,11 @@ function mapRow(row: Record<string, unknown>): Chapter {
|
||||
cursorOffset: (row.cursor_offset as number) ?? 0,
|
||||
origin: ((row.origin as ChapterOrigin) ?? 'manual') as ChapterOrigin,
|
||||
publishStatus: ((row.publish_status as PublishStatus) ?? 'draft') as PublishStatus,
|
||||
povCharacterId: (row.pov_character_id as string) || null
|
||||
povCharacterId: (row.pov_character_id as string) || null,
|
||||
summary: (row.summary as string) ?? '',
|
||||
storyTime: (row.story_time as string) ?? null,
|
||||
publishedAt: (row.published_at as string) ?? null,
|
||||
wordCountThreshold: (row.word_count_threshold as number) ?? null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +72,10 @@ export class ChapterRepository {
|
||||
cursorOffset: number
|
||||
publishStatus: PublishStatus
|
||||
povCharacterId: string | null
|
||||
summary: string
|
||||
storyTime: string | null
|
||||
publishedAt: string | null
|
||||
wordCountThreshold: number | null
|
||||
}>
|
||||
): Chapter {
|
||||
const existing = this.get(id)
|
||||
@@ -82,7 +90,9 @@ export class ChapterRepository {
|
||||
.prepare(
|
||||
`UPDATE chapters SET
|
||||
title = ?, content = ?, status = ?, cursor_offset = ?,
|
||||
publish_status = ?, pov_character_id = ?, word_count = ?, updated_at = datetime('now')
|
||||
publish_status = ?, pov_character_id = ?, word_count = ?,
|
||||
summary = ?, story_time = ?, published_at = ?, word_count_threshold = ?,
|
||||
updated_at = datetime('now')
|
||||
WHERE id = ?`
|
||||
)
|
||||
.run(
|
||||
@@ -93,13 +103,23 @@ export class ChapterRepository {
|
||||
patch.publishStatus ?? existing.publishStatus ?? 'draft',
|
||||
povCharacterId,
|
||||
wordCount,
|
||||
patch.summary ?? existing.summary ?? '',
|
||||
patch.storyTime !== undefined ? patch.storyTime : (existing.storyTime ?? null),
|
||||
patch.publishedAt !== undefined ? patch.publishedAt : (existing.publishedAt ?? null),
|
||||
patch.wordCountThreshold !== undefined
|
||||
? patch.wordCountThreshold
|
||||
: (existing.wordCountThreshold ?? null),
|
||||
id
|
||||
)
|
||||
return this.get(id)!
|
||||
}
|
||||
|
||||
setPublishStatus(id: string, publishStatus: PublishStatus): Chapter {
|
||||
return this.update(id, { publishStatus })
|
||||
const patch: Parameters<ChapterRepository['update']>[1] = { publishStatus }
|
||||
if (publishStatus === 'published') {
|
||||
patch.publishedAt = new Date().toISOString()
|
||||
}
|
||||
return this.update(id, patch)
|
||||
}
|
||||
|
||||
countByPublishStatus(status: PublishStatus): number {
|
||||
|
||||
Reference in New Issue
Block a user