feat: ship v0.5.0 with auto and wizard writing modes
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -3,8 +3,9 @@ import schemaV1 from './schema-v1.sql?raw'
|
||||
import schemaV2 from './schema-v2.sql?raw'
|
||||
import schemaV3 from './schema-v3.sql?raw'
|
||||
import schemaV4 from './schema-v4.sql?raw'
|
||||
import schemaV5 from './schema-v5.sql?raw'
|
||||
|
||||
const CURRENT_VERSION = 4
|
||||
const CURRENT_VERSION = 5
|
||||
|
||||
function tryAlter(db: SqliteDb, sql: string): void {
|
||||
try {
|
||||
@@ -56,5 +57,12 @@ export function migrate(db: SqliteDb): void {
|
||||
tryAlter(db, "ALTER TABLE chapters ADD COLUMN origin TEXT NOT NULL DEFAULT 'manual'")
|
||||
db.exec(schemaV4)
|
||||
db.prepare('INSERT INTO schema_version (version, description) VALUES (?, ?)').run(4, 'P4 interactive schema')
|
||||
current = 4
|
||||
}
|
||||
|
||||
if (current < 5) {
|
||||
tryAlter(db, "ALTER TABLE interactive_flows ADD COLUMN flow_mode TEXT NOT NULL DEFAULT 'interactive'")
|
||||
tryAlter(db, "ALTER TABLE interactive_flows ADD COLUMN mode_config_json TEXT NOT NULL DEFAULT '{}'")
|
||||
db.prepare('INSERT INTO schema_version (version, description) VALUES (?, ?)').run(5, 'P4.1 auto/wizard schema')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE interactive_flows ADD COLUMN flow_mode TEXT NOT NULL DEFAULT 'interactive';
|
||||
ALTER TABLE interactive_flows ADD COLUMN mode_config_json TEXT NOT NULL DEFAULT '{}';
|
||||
Reference in New Issue
Block a user