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
+63 -9
View File
@@ -1,10 +1,13 @@
import { randomUUID } from 'crypto'
import type {
AutoWritingConfig,
InteractiveFlow,
InteractiveFlowStatus,
InteractiveScene,
InteractiveStep,
NamingPause
NamingPause,
WizardWritingConfig,
WritingFlowMode,
WritingStep
} from '../../../shared/types'
import type { SqliteDb } from '../types'
@@ -27,33 +30,47 @@ export class InteractiveRepository {
return row ? this.mapFlow(row) : null
}
create(sessionId: string): InteractiveFlow {
create(
sessionId: string,
flowMode: WritingFlowMode = 'interactive',
initialStep?: WritingStep
): InteractiveFlow {
const id = randomUUID()
const step =
initialStep ??
(flowMode === 'auto'
? 'goal_setup'
: flowMode === 'wizard'
? 'wizard_goal'
: 'context_confirm')
this.db
.prepare(
`INSERT INTO interactive_flows (id, session_id, step, status, context_json) VALUES (?, ?, 'context_confirm', 'in_progress', '{}')`
`INSERT INTO interactive_flows (id, session_id, step, status, context_json, flow_mode, mode_config_json)
VALUES (?, ?, ?, 'in_progress', '{}', ?, '{}')`
)
.run(id, sessionId)
.run(id, sessionId, step, flowMode)
return this.get(id)!
}
resetInProgress(sessionId: string): InteractiveFlow {
resetInProgress(sessionId: string, flowMode: WritingFlowMode = 'interactive'): InteractiveFlow {
this.db
.prepare(
`UPDATE interactive_flows SET status = 'abandoned', updated_at = datetime('now') WHERE session_id = ? AND status = 'in_progress'`
)
.run(sessionId)
return this.create(sessionId)
return this.create(sessionId, flowMode)
}
updateStep(
flowId: string,
step: InteractiveStep,
step: WritingStep,
patch: {
contextJson?: string
plotSelectionJson?: string | null
namingPendingJson?: string | null
sceneDraftHtml?: string | null
modeConfigJson?: string
flowMode?: WritingFlowMode
status?: InteractiveFlowStatus
} = {}
): InteractiveFlow {
@@ -75,6 +92,14 @@ export class InteractiveRepository {
sets.push('scene_draft_html = ?')
vals.push(patch.sceneDraftHtml)
}
if (patch.modeConfigJson !== undefined) {
sets.push('mode_config_json = ?')
vals.push(patch.modeConfigJson)
}
if (patch.flowMode !== undefined) {
sets.push('flow_mode = ?')
vals.push(patch.flowMode)
}
if (patch.status !== undefined) {
sets.push('status = ?')
vals.push(patch.status)
@@ -84,6 +109,27 @@ export class InteractiveRepository {
return this.get(flowId)!
}
getModeConfig<T extends AutoWritingConfig | WizardWritingConfig>(
flowId: string
): T {
const row = this.db
.prepare('SELECT mode_config_json FROM interactive_flows WHERE id = ?')
.get(flowId) as { mode_config_json: string } | undefined
try {
return JSON.parse(row?.mode_config_json ?? '{}') as T
} catch {
return {} as T
}
}
setModeConfig(flowId: string, config: AutoWritingConfig | WizardWritingConfig): void {
this.db
.prepare(
`UPDATE interactive_flows SET mode_config_json = ?, updated_at = datetime('now') WHERE id = ?`
)
.run(JSON.stringify(config), flowId)
}
listScenes(flowId: string): InteractiveScene[] {
const rows = this.db
.prepare('SELECT * FROM interactive_scenes WHERE flow_id = ? ORDER BY sort_order')
@@ -156,11 +202,19 @@ export class InteractiveRepository {
namingPending = null
}
}
let modeConfig: AutoWritingConfig | WizardWritingConfig | Record<string, never> = {}
try {
modeConfig = JSON.parse((row.mode_config_json as string) ?? '{}')
} catch {
modeConfig = {}
}
return {
id: flowId,
sessionId: row.session_id as string,
step: row.step as InteractiveStep,
flowMode: (row.flow_mode as WritingFlowMode) ?? 'interactive',
step: row.step as WritingStep,
status: row.status as InteractiveFlowStatus,
modeConfig,
scenes: this.listScenes(flowId),
namingPending,
contextSummary: undefined