Add Prompt Builder sequence section order.

Copied scene text and the scene editor follow a persisted sectionOrder, with legacy saves keeping the default style/settings/set/characters/prompt order.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Towsty
2026-10-04 07:07:43 -05:00
co-authored by Cursor
parent b6eef6a511
commit 45e97cc1c3
6 changed files with 1113 additions and 878 deletions
+82
View File
@@ -26,6 +26,8 @@ const {
emptyFraming,
cloneSceneForNext,
normalizePromptSequence,
normalizeSectionOrder,
DEFAULT_PROMPT_SEQUENCE_SECTION_ORDER,
ensureSceneStatesForCharacters
} = await import(pathToFileURL(tmp).href)
unlinkSync(tmp)
@@ -204,3 +206,83 @@ test('ensureSceneStatesForCharacters turns new character on only for current sce
assert.equal(scenes[0].characterStates.find(s => s.characterId === b.id).on, false)
assert.equal(scenes[1].characterStates.find(s => s.characterId === b.id).on, true)
})
test('sectionOrder settings then prompt then characters; empty style and set omitted', () => {
const ada = {
...emptyCharacter(),
id: 'c1',
name: 'Ada',
description: 'tall',
outfits: []
}
const set = {
...emptySet(),
id: 's1',
name: 'Courtyard',
framings: [{ ...emptyFraming('wide'), id: 'f1', text: 'open yard' }]
}
const scene = {
style: '',
settings: 'soft light',
setStates: [{ setId: 's1', on: true, framingId: null }],
characterStates: [{ characterId: 'c1', on: true, outfitId: null }],
prompt: 'looks up'
}
const order = ['settings', 'prompt', 'characters']
const text = assembleSceneText(scene, [ada], [set], order)
assert.equal(text, 'soft light\n\nlooks up\n\nAda: tall')
assert.ok(!text.includes('open yard'))
assert.ok(!text.includes('Courtyard'))
assert.ok(!text.includes('wide'))
})
test('legacy sequence without sectionOrder keeps default order and \\n\\n\\n join', () => {
const legacy = normalizePromptSequence({
id: 'seq1',
name: 'Old order',
characters: [{ id: 'c1', name: 'Ada', description: 'tall', outfits: [] }],
sets: [{
id: 's1',
name: 'Hall',
framings: [{ id: 'f1', label: 'wide', text: 'stone hall' }]
}],
scenes: [
{
id: 'sc1',
title: 'One',
style: 'oil',
settings: 'day',
setStates: [{ setId: 's1', on: true, framingId: 'f1' }],
characterStates: [{ characterId: 'c1', on: true, outfitId: null }],
prompt: 'walk'
},
{
id: 'sc2',
title: 'Two',
style: 'ink',
settings: '',
setStates: [{ setId: 's1', on: false, framingId: 'f1' }],
characterStates: [{ characterId: 'c1', on: true, outfitId: null }],
prompt: 'stop'
}
],
createdAt: 1,
updatedAt: 1
})
assert.deepEqual(legacy.sectionOrder, [...DEFAULT_PROMPT_SEQUENCE_SECTION_ORDER])
assert.deepEqual(normalizeSectionOrder(undefined), [...DEFAULT_PROMPT_SEQUENCE_SECTION_ORDER])
assert.deepEqual(normalizeSectionOrder(['prompt', 'prompt', 'bogus', 'settings']), [
'prompt',
'settings',
'style',
'set',
'characters'
])
const full = assembleSequenceText(legacy)
assert.equal(
full,
'oil\n\nday\n\nstone hall\n\nAda: tall\n\nwalk\n\n\nink\n\nAda: tall\n\nstop'
)
assert.ok(!full.includes('Hall'))
assert.ok(!full.includes('wide'))
})