narraeon 0.5.6 → 0.5.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +1 -1
  2. package/README.zh-CN.md +1 -1
  3. package/dist/node/protocol/appPreferences.js +4 -2
  4. package/dist/node/protocol/playFailure.js +13 -0
  5. package/dist/node/protocol/protagonistTemplates.js +13 -0
  6. package/dist/node/protocol/v1.js +25 -19
  7. package/dist/node/protocol/worldArchives.js +7 -0
  8. package/dist/node/runtime/V1Runtime.js +46 -6
  9. package/dist/node/runtime/archive/WorldArchiveZip.js +202 -0
  10. package/dist/node/runtime/archive/WorldArchives.js +389 -0
  11. package/dist/node/runtime/config/AppPreferencesStore.js +23 -10
  12. package/dist/node/runtime/config/ProtagonistTemplateStore.js +134 -0
  13. package/dist/node/runtime/content/ContentWorkspace.js +5 -0
  14. package/dist/node/runtime/history/StoryExport.js +33 -0
  15. package/dist/node/runtime/model/FileNativeModelAdapters.js +34 -2
  16. package/dist/node/runtime/model/ModelHost.js +12 -1
  17. package/dist/node/runtime/model/ModelHostStream.js +11 -3
  18. package/dist/node/runtime/play/FileNativePlayTimelineStore.js +80 -4
  19. package/dist/node/runtime/play/LegacyModelBindingFailure.js +10 -0
  20. package/dist/node/runtime/play/PlayCallChain.js +144 -52
  21. package/dist/node/runtime/play/PlayCallChainError.js +3 -1
  22. package/dist/node/runtime/play/PlayContinuity.js +3 -20
  23. package/dist/node/runtime/play/PlayFailure.js +20 -0
  24. package/dist/node/runtime/play/PlayTraceRetention.js +3 -11
  25. package/dist/node/runtime/prompt/FileNativePromptCompiler.js +4 -22
  26. package/dist/node/runtime/prompt/FileNativeToolRegistry.js +2 -2
  27. package/dist/node/runtime/world/FileNativeWorldStore.js +172 -39
  28. package/dist/node/runtime/world/WorldActivity.js +143 -0
  29. package/dist/node/server/createServer.js +48 -0
  30. package/dist/node/shared/default-preset-host.js +10 -6
  31. package/dist/node/shared/ordered-play-prompts.js +2 -2
  32. package/dist/node/shared/sample-packages/index.js +10 -0
  33. package/dist/node/shared/sample-packages/rainy-inn-en.js +194 -0
  34. package/dist/node/shared/sample-packages/rainy-inn-zh.js +194 -0
  35. package/dist/web/assets/index-DxNtxzLR.js +1255 -0
  36. package/dist/web/assets/{index-CVN48xrw.css → index-DzOnu9uv.css} +1 -1
  37. package/dist/web/index.html +2 -2
  38. package/package.json +6 -2
  39. package/dist/web/assets/index-BH8NyuE4.js +0 -1233
@@ -234,7 +234,7 @@ NPC 可以按性格、认知、处境和目标继续做事、与别人交谈、
234
234
 
235
235
  summary 是目录简介,用于识别文档和判断是否需要读取。只写简短的身份、主题或稳定线索,不复述具体状态和事件经过;具体事实放在正文。仅在识别信息改变时更新标题与简介。
236
236
 
237
- ## 保存时机与整理检查点
237
+ ## 保存时机、整理与检查点
238
238
 
239
239
  先按玩家授权与互动需要确定本轮叙事范围和停笔位置,再保存该范围内的事实。保存进行中活动的实际进展、必要原话和待回应事项即可整理截至此刻的状态,不把尚未发生的完成结果提前写入。
240
240
 
@@ -243,9 +243,11 @@ summary 是目录简介,用于识别文档和判断是否需要读取。只写
243
243
  3. 需要保存但玩家原文和最终叙事没有记录的信息,当轮保存,包括重要场外进展、未表露的认知和隐蔽后果。工具中间文本不能替代持久记录。
244
244
  4. 其余可从玩家原文和最终叙事恢复的持续结果,允许事件收尾或合适的中间整理点归并。
245
245
 
246
- 按已确定的叙事范围完成本轮必须保存的写入。在本轮原定停笔位置判断整理时机:事件自然告一段落、实际转换场景,或持续活动经过多轮并积累了需要归并的进展时,主动集中整理,不等玩家要求,也不等整个活动完成。只有零散即时变化时,按上述保存时机继续互动;一次写入不等于一次检查点。
246
+ 按已确定的叙事范围完成本轮必须保存的写入。整理随时可以进行:持续活动跨多轮积累了需要归并的进展,或发现重复、过期的记录时,直接在当轮工具调用中归并,不需要等事件结束,也不需要登记检查点。整理不等于检查点。只有零散即时变化时,按上述保存时机继续互动。
247
247
 
248
- 整理时核对上次检查点后的交互和本轮范围内的结果,补齐必要记录,更新认知、进程、约定和界面值,结束实际已失效的待办并清理重复。此前已写回的事实核对后沿用,无需重复写入。准备好该停笔位置的记录后,调用 world_checkpoint,再输出最终叙事;进行中的活动和待回应事项按原状保存,整理不改变停笔位置。检查点覆盖该叙事,若其中又增加重要结果,继续工具调用补齐。登记回执不是语义完整性认证。
248
+ world_checkpoint 只用于事件之间的间隙:上一事件已在本轮停笔位置自然告一段落,或场景已实际转换,接下来从全新上下文开始也不会丢失仍然重要的细节。登记前核对上次检查点后的交互,把刚结束事件中后续仍需要的结果写入文档,包括当前状态、重要认知、承诺与待办和界面值,因为全新上下文只补入检查点之后的原文,上一事件的经过不会再出现。持续活动中途、对方刚给出需要玩家回应的反馈,或仍有待玩家决定的事项时,不登记检查点。此前已写回的事实核对后沿用,无需重复写入。登记后输出最终叙事;若叙事又增加重要结果,继续工具调用补齐。登记回执不是语义完整性认证。
249
+
250
+ 检查点只标记已经出现的间隙,不是本轮要达成的目标。不要为了到达间隙而加快节奏、压缩过程、替玩家完成尚未授权的步骤或提前结束事件;停笔位置仍按“哪些必须由玩家决定”与互动需要确定。一个事件持续很多轮、跨越多次回复都是正常的,期间不需要登记检查点。
249
251
 
250
252
  ## 整理与连续性
251
253
 
@@ -492,7 +494,7 @@ Prefer natural owners for durable information. Create a separate document for in
492
494
 
493
495
  summary is a catalog description for identifying a document and deciding whether to read it. Include only a brief identity, topic or stable clue, not detailed state or event accounts; put concrete facts in the body. Update titles and descriptions only when that identifying information changes.
494
496
 
495
- ## Save timing and consolidation checkpoints
497
+ ## Save timing, consolidation and checkpoints
496
498
 
497
499
  First choose this turn's narrative scope and stopping point from player authorization and interaction needs, then save facts within that scope. Recording actual progress in an ongoing activity, necessary exact wording and matters awaiting a response can complete maintenance through this moment without writing unrealized completion outcomes in advance.
498
500
 
@@ -501,9 +503,11 @@ First choose this turn's narrative scope and stopping point from player authoriz
501
503
  3. Save needed information absent from player originals and final narrative during this turn, including important offstage progress, unexpressed knowledge and hidden consequences. Intermediate tool text is not a durable substitute.
502
504
  4. Other durable outcomes recoverable from player originals and final narrative may be consolidated at event closure or a suitable intermediate point.
503
505
 
504
- Complete required writes within the chosen narrative scope. At this turn's already chosen stopping point, assess whether consolidation is due: proactively consolidate when an event naturally settles, the scene actually changes, or an ongoing activity has accumulated progress across several turns that needs consolidation. Do not wait for the player to request maintenance or for the whole activity to finish. With only isolated immediate changes, continue the interaction under the saving rules above; one write does not mean one checkpoint.
506
+ Complete required writes within the chosen narrative scope. Consolidation can happen at any time: when an ongoing activity has accumulated progress across several turns that needs consolidation, or records are duplicated or outdated, consolidate directly in this turn's tool calls without waiting for the event to end or registering a checkpoint. Consolidation is not a checkpoint. With only isolated immediate changes, continue the interaction under the saving rules above.
507
+
508
+ Use world_checkpoint only for gaps between events: the previous event has naturally settled at this turn's stopping point, or the scene has actually changed, and starting a fresh context next would not lose still-important details. Before registration, reconcile interactions since the previous checkpoint and save outcomes of the finished event that remain necessary, including current state, important knowledge, commitments, pending work and interface values. A fresh context replays only originals after the checkpoint; the previous event's account will no longer appear. Do not register during an ongoing activity, immediately after feedback needing the player's response, or while matters await the player's decision. Reuse already saved facts after checking them, without duplicate writes. After registration, produce final narrative; if it adds another important outcome, continue tool calls to save it. Registration is not certification of semantic completeness.
505
509
 
506
- When consolidating, reconcile interactions since the previous checkpoint and outcomes within this turn's scope: fill necessary records, update knowledge, processes, commitments and interface values, close actually expired pending work and remove duplicates. Reuse already saved facts after checking them, without duplicate writes. Once records for that stopping point are ready, call world_checkpoint, then produce final narrative. Preserve ongoing activities and matters awaiting a response as they stand; maintenance does not move the stopping point. The checkpoint covers that narrative; if it adds another important outcome, continue tool calls to save it. Registration is not certification of semantic completeness.
510
+ A checkpoint marks a gap that has already appeared, not a goal for this turn. Do not accelerate the pace, compress the process, complete unauthorized steps for the player or end an event early to reach a gap. Choose the stopping point from what the player must decide and the interaction's needs. One event may last many turns across multiple replies; no checkpoint is needed during it.
507
511
 
508
512
  ## Maintenance and continuity
509
513
 
@@ -22,7 +22,7 @@ export function builtinPlayPrompts(locale) {
22
22
 
23
23
  world_patch 的 YAML locator 可以包含 map key 和从零开始的数组下标;remove 删除一个精确位置。未提供的元数据保持原值。world_retire 从目录注入中退役文档,文档仍可读取、引用和恢复。工具响应的成功状态变化与后续最终叙事分别提交,后续失败不回滚已提交变化。成功写入回执表示当前值已改变;以真实回执的结算状态为准,模型文字不能提交世界。
24
24
 
25
- 包含工具调用的响应属于中间步,其中的文字尚未展示或提交为最终叙事。收到全部工具结果后,根据回执在最终正文中呈现本轮尚未展示的内容,并与已提交状态一致;没有工具调用的非空正文结束本次循环并由 Runtime 提交。world_checkpoint 仅登记整理声明与历史重放边界,在随后非空且无工具调用的最终正文成功提交后生效,边界包含该正文;登记后仍可继续工具调用。登记不结束世界内事件,也不自动切换上下文,玩家自行选择。全新上下文补入边界后的已提交玩家原文与最终叙事,排除开场白、工具和推理。
25
+ 包含工具调用的响应属于中间步,其中的文字尚未展示或提交为最终叙事。收到全部工具结果后,根据回执在最终正文中呈现本轮尚未展示的内容,并与已提交状态一致;没有工具调用的非空正文结束本次循环并由 Runtime 提交。world_checkpoint 只在事件间隙登记,表示建议从此开始全新上下文,并作为历史重放边界;整理本身不需要登记。在随后非空且无工具调用的最终正文成功提交后生效,边界包含该正文;登记后仍可继续工具调用。登记不结束世界内事件,也不自动切换上下文,玩家自行选择。全新上下文补入边界后的已提交玩家原文与最终叙事,排除开场白、工具和推理。
26
26
 
27
27
  ${historyUseGuidance(locale)}`
28
28
  : `# Tools and response settlement
@@ -31,7 +31,7 @@ Use only attached tools. Directories use @dir-* handles from the preload or tool
31
31
 
32
32
  YAML world_patch locators accept map keys and zero-based array indexes; remove deletes one exact location. Omitted metadata remains unchanged. world_retire removes a document from catalog injection while keeping it readable, referenceable and restorable. Successful tool-response state changes and later final narrative commit separately; later failure does not roll back committed changes. Successful write receipts change current values; the actual receipt determines settlement, not model prose.
33
33
 
34
- Responses containing tool calls are intermediate steps; their text has not yet been displayed or committed as final narrative. After all tool results, use the receipts to present this turn's still-unshown content in final prose consistent with committed state. A nonempty tool-free response ends this loop and Runtime commits it. world_checkpoint only registers a consolidation declaration and history-replay boundary; it takes effect after the subsequent nonempty tool-free final prose successfully commits, including that prose. Further tool calls may follow registration. Registration neither ends an in-world event nor switches context, which the player chooses. Fresh-context replay contains committed player originals and final narratives after the boundary, excluding the opening, tools and reasoning.
34
+ Responses containing tool calls are intermediate steps; their text has not yet been displayed or committed as final narrative. After all tool results, use the receipts to present this turn's still-unshown content in final prose consistent with committed state. A nonempty tool-free response ends this loop and Runtime commits it. world_checkpoint registers only at gaps between events, suggesting a fresh context from that point and defining the history-replay boundary; consolidation itself does not require registration. It takes effect after the subsequent nonempty tool-free final prose successfully commits, including that prose. Further tool calls may follow registration. Registration neither ends an in-world event nor switches context, which the player chooses. Fresh-context replay contains committed player originals and final narratives after the boundary, excluding the opening, tools and reasoning.
35
35
 
36
36
  ${historyUseGuidance(locale)}`,
37
37
  },
@@ -0,0 +1,10 @@
1
+ import { rainyInnEnglish } from "./rainy-inn-en.js";
2
+ import { rainyInnChinese } from "./rainy-inn-zh.js";
3
+ /** Each caller receives an ordinary, independent content-tree seed. */
4
+ export function sampleContentPackageForLocale(locale) {
5
+ const sample = locale === "zh-CN" ? rainyInnChinese : rainyInnEnglish;
6
+ return {
7
+ title: sample.title,
8
+ files: sample.files.map((file) => ({ ...file })),
9
+ };
10
+ }
@@ -0,0 +1,194 @@
1
+ export const rainyInnEnglish = {
2
+ title: "A Letter at the Rain Lantern Inn",
3
+ files: [
4
+ {
5
+ path: "opening.md",
6
+ contents: `Rain patters from the inn's eaves. The little brass bell above you is still swaying, and the lobby smells of ginger tea. A lamp casts a warm circle across the wooden counter.
7
+
8
+ Behind it, a woman in a green apron lifts an empty blue saucer, checks underneath, and sets it down again. “Well, it hasn't grown legs.”
9
+
10
+ A guest in a grey cardigan looks up from the window table. “A pale blue envelope. It's for my sister, and I haven't sealed it yet.” Beside the counter, a young postal runner pauses with a damp ledger tucked against his chest.
11
+
12
+ The woman offers you a dry towel. “Welcome in. We're having a small mystery with a letter. Would you mind lending us a fresh pair of eyes?” The counter, umbrella stand, and window table are all within the lamplight. She waits for your answer.
13
+ `,
14
+ },
15
+ {
16
+ path: "world/current-situation.yaml",
17
+ contents: `$document:
18
+ id: situation.rainy-inn
19
+ ref: current-situation
20
+ title: An empty saucer in the lamplight
21
+ summary: A small search in the Rain Lantern Inn's lobby.
22
+ aliases: []
23
+ 背景:
24
+ Time: An autumn evening, nine o'clock, steady rain
25
+ Place: Rain Lantern Inn lobby, Brookbridge
26
+ Present:
27
+ - $ref: character.nora
28
+ - $ref: character.evelyn
29
+ - $ref: character.kit
30
+ In progress:
31
+ Letter search: Evelyn's pale blue envelope is no longer on the counter's blue saucer. Nobody has begun a methodical search of the lobby.
32
+ Awaiting a response:
33
+ Speaker: { $ref: character.nora }
34
+ Invitation: Welcome in. We're having a small mystery with a letter. Would you mind lending us a fresh pair of eyes?
35
+ Immediate circumstances:
36
+ - You have just arrived at the doorway. Nora's offered towel has not been taken.
37
+ - Kit holds the ledger and has paused wiping its damp corner.
38
+ `,
39
+ },
40
+ {
41
+ path: "world/characters/nora.yaml",
42
+ contents: `$document:
43
+ id: character.nora
44
+ ref: nora
45
+ title: Nora
46
+ summary: The Rain Lantern's attentive innkeeper, quick to offer practical kindness.
47
+ aliases: []
48
+ Appearance: Short hair, soft features, a dusting of flour on one cuff.
49
+ Clothing: A cream shirt, forest-green apron, and soft indoor shoes.
50
+ Temperament: Patient; looks for a remedy before laying blame.
51
+ Relationships:
52
+ Evelyn:
53
+ Person: { $ref: character.evelyn }
54
+ View: A familiar guest whose plant stories brighten the lobby; hopes she can rest without worrying tonight.
55
+ Kit:
56
+ Person: { $ref: character.kit }
57
+ View: A neighbour's helpful son, sometimes distracted; willing to hear him out when something goes wrong.
58
+ Knowledge:
59
+ Letter: Remembers putting Evelyn's envelope on the blue saucer, then leaving to make tea. Did not watch the counter after that.
60
+ Basis: { $ref: event.letter-entrusted }
61
+ `,
62
+ },
63
+ {
64
+ path: "world/characters/evelyn.yaml",
65
+ contents: `$document:
66
+ id: character.evelyn
67
+ ref: evelyn
68
+ title: Evelyn
69
+ summary: A travelling botanical illustrator who shares discoveries in letters.
70
+ aliases: []
71
+ Appearance: Round glasses and a faint smudge of graphite on her fingertips.
72
+ Clothing: A grey cardigan and navy trousers; her brown rain cape hangs by the umbrellas.
73
+ Temperament: Observant and deliberate; double-checks small details when worried.
74
+ Relationships:
75
+ Nora:
76
+ Person: { $ref: character.nora }
77
+ View: A trusted innkeeper; the missing letter has not made her suspect deliberate concealment.
78
+ Kit:
79
+ Person: { $ref: character.kit }
80
+ View: Met him this evening; trusts his postal expertise but knows little about his habits.
81
+ Important belongings:
82
+ Letter for her sister: An unsealed pale blue envelope containing a page of news and a hand-drawn leaf study, intended for tomorrow's post.
83
+ Knowledge:
84
+ Letter: Knows she entrusted it to Nora and now sees an empty saucer; does not know where it went afterward.
85
+ Basis: { $ref: event.letter-entrusted }
86
+ `,
87
+ },
88
+ {
89
+ path: "world/characters/kit.yaml",
90
+ contents: `$document:
91
+ id: character.kit
92
+ ref: kit
93
+ title: Kit
94
+ summary: Brookbridge's young postal runner, always willing to help a neighbour.
95
+ aliases: []
96
+ Appearance: Rain-flattened hair and a small dimple when he smiles.
97
+ Clothing: An unbuttoned blue raincoat, striped shirt, and canvas shoes with wet toes.
98
+ Temperament: Eager and easily distracted; owns up to mistakes and tries to put them right.
99
+ Relationships:
100
+ Nora:
101
+ Person: { $ref: character.nora }
102
+ View: A neighbour he has known since childhood; trusts her and wants to be useful.
103
+ Evelyn:
104
+ Person: { $ref: character.evelyn }
105
+ View: A new acquaintance with intriguing drawings; hopes to ask about the leaves she sketches.
106
+ Knowledge:
107
+ Remembered action: Moved a pale blue envelope to make room for his wet ledger, slipping it inside the back cover. Assumed the envelope was empty.
108
+ Current understanding: Has not caught what Evelyn is looking for or connected her letter with the envelope he moved.
109
+ Belongings:
110
+ Ledger: Held against his chest; a corner of the back cover is damp.
111
+ `,
112
+ },
113
+ {
114
+ path: "world/locations/rain-lantern-inn.yaml",
115
+ contents: `$document:
116
+ id: location.rain-lantern-inn
117
+ ref: rain-lantern-inn
118
+ title: Rain Lantern Inn
119
+ summary: A small inn by Brookbridge's bridge, where neighbours shelter over tea.
120
+ aliases: []
121
+ Lobby: A wooden counter faces the entrance, with a blue saucer and brass lamp on top. A small table stands by the window; the umbrellas rest beside the door.
122
+ Daily life: Guests can rest over ginger tea; the innkeeper sometimes holds letters for familiar visitors until morning.
123
+ `,
124
+ },
125
+ {
126
+ path: "world/events/letter-entrusted.yaml",
127
+ contents: `$document:
128
+ id: event.letter-entrusted
129
+ ref: letter-entrusted
130
+ title: A letter left for safekeeping
131
+ summary: Evelyn's earlier arrangement with Nora to keep a letter at the counter.
132
+ aliases: []
133
+ When: About half an hour earlier this evening
134
+ Account: Evelyn gave Nora an unsealed pale blue envelope, explaining that it held a letter and leaf drawing for her sister. Nora put it on the blue saucer while Evelyn watched.
135
+ Words: Evelyn said, “I'll seal it in the morning. Could you keep it here until then?” Nora agreed.
136
+ Source: Both Evelyn and Nora were at the counter.
137
+ `,
138
+ },
139
+ {
140
+ path: "control/frame.yaml",
141
+ contents: `format: narraeon.world-frame/v1
142
+ bindings:
143
+ currentSituation: "@current-situation"
144
+ instructions:
145
+ - markdown: blocks/world.md
146
+ context:
147
+ - slot: { kind: catalog, directory: characters, maxEntries: 3 }
148
+ - slot: { kind: catalog, directory: locations, maxEntries: 4 }
149
+ - slot: { kind: catalog, directory: events, maxEntries: 12 }
150
+ - slot: { kind: document, document: "@rain-lantern-inn" }
151
+ - slot:
152
+ kind: reference_targets
153
+ from:
154
+ document: "@current-situation"
155
+ locator: { yaml: [Present] }
156
+ maxEntries: 3
157
+ - slot: { kind: current_situation }
158
+ - slot: { kind: additional_materials }
159
+ `,
160
+ },
161
+ {
162
+ path: "control/blocks/world.md",
163
+ contents: `<!-- opening.md is the visible opening; world/current-situation.yaml holds the background and pending response; characters/ holds each person's state, relationships, and knowledge; locations/ describes places; events/ records shared past events; frame.yaml selects play material; player-views.yaml selects status values. Adapt these files to write your own story. -->
164
+
165
+ # Genre and boundaries
166
+
167
+ Focus on small-town inn life, conversation, and gentle mysteries arising from objects, memories, and misunderstandings. Keep the tone warm and suitable for all ages, without violence, adult content, or life-threatening conspiracies. Sharing a letter's private contents is up to its writer and recipient.
168
+
169
+ ## Documents and where changes belong
170
+
171
+ Keep relationships, opinions, and knowledge in each person's own world/characters/ document, without a shared truth or secret field. Record events that need shared reference in world/events/; link to the account rather than copying it into each character. Lasting changes to places belong in world/locations/. Keep the letter among its owner's important belongings until independent transfer tracking warrants a separate document.
172
+ `,
173
+ },
174
+ {
175
+ path: "control/player-views.yaml",
176
+ contents: `format: narraeon.player-views/v1
177
+ views:
178
+ - id: scene-status
179
+ title: Right now
180
+ items:
181
+ - id: time
182
+ label: Time
183
+ select:
184
+ document: "@current-situation"
185
+ locator: { yaml: [背景, Time] }
186
+ - id: place
187
+ label: Place
188
+ select:
189
+ document: "@current-situation"
190
+ locator: { yaml: [背景, Place] }
191
+ `,
192
+ },
193
+ ],
194
+ };
@@ -0,0 +1,194 @@
1
+ export const rainyInnChinese = {
2
+ title: "雨灯旅店的一封信",
3
+ files: [
4
+ {
5
+ path: "opening.md",
6
+ contents: `雨水沿着旅店的檐角落下,门上的小铜铃还在轻轻晃动。你面前的柜台亮着一盏暖黄的灯,湿伞架旁飘来姜茶的香气。
7
+
8
+ 柜台后,一位系着墨绿围裙的女人把空的蓝瓷碟翻过来,又放回原处。「刚才还在这里的。」她低声说。
9
+
10
+ 窗边穿灰色针织衫的客人抬起头:「是一个浅蓝信封,明早要寄给我妹妹。还没有封口。」她看向柜台边抱着登记簿的年轻邮差。邮差停下擦拭书角的手,神情有些茫然。
11
+
12
+ 女人转向你,递来一条干毛巾:「先擦擦雨吧。我们正找一封信——你愿意帮忙看看吗?」柜台、伞架和窗边的小桌都在灯光里,她等着你的回答。
13
+ `,
14
+ },
15
+ {
16
+ path: "world/current-situation.yaml",
17
+ contents: `$document:
18
+ id: situation.rainy-inn
19
+ ref: current-situation
20
+ title: 灯下的空瓷碟
21
+ summary: 雨灯旅店大厅里的一次小小寻物。
22
+ aliases: []
23
+ 背景:
24
+ 时间: 秋日,雨夜,晚上九点
25
+ 地点: 溪桥镇,雨灯旅店大厅
26
+ 在场人物:
27
+ - $ref: character.shen-he
28
+ - $ref: character.lin-lan
29
+ - $ref: character.zhou-cheng
30
+ 进行中事件:
31
+ 寻信: 林岚发现寄给妹妹的浅蓝信封不在柜台蓝瓷碟上;大厅里尚未有人开始系统寻找。
32
+ 待回应:
33
+ 说话者: { $ref: character.shen-he }
34
+ 邀请: 先擦擦雨吧。我们正找一封信——你愿意帮忙看看吗?
35
+ 短期局面:
36
+ - 你刚抵达门口,沈禾递来的干毛巾尚未被接过。
37
+ - 周澄抱着登记簿,刚停下擦拭湿书角的动作。
38
+ `,
39
+ },
40
+ {
41
+ path: "world/characters/shen-he.yaml",
42
+ contents: `$document:
43
+ id: character.shen-he
44
+ ref: shen-he
45
+ title: 沈禾
46
+ summary: 雨灯旅店的店主,做事细致,待客温和。
47
+ aliases: [沈老板]
48
+ 外貌: 短发,眉眼柔和,袖口上有一点面粉。
49
+ 衣着: 米色衬衣,墨绿围裙,布鞋。
50
+ 性格: 耐心,遇到疏漏先寻找补救办法,不轻易责怪人。
51
+ 关系:
52
+ 林岚:
53
+ 对象: { $ref: character.lin-lan }
54
+ 看法: 常住的熟客,珍惜她带来的植物故事;希望她今晚能安心休息。
55
+ 周澄:
56
+ 对象: { $ref: character.zhou-cheng }
57
+ 看法: 邻居家的年轻邮差,热心但偶尔忙中出错;愿意让他说明情况。
58
+ 认知:
59
+ 信件: 记得把林岚的浅蓝信封放在蓝瓷碟上,此后忙着烧姜茶,没有留意柜台。
60
+ 依据: { $ref: event.letter-entrusted }
61
+ `,
62
+ },
63
+ {
64
+ path: "world/characters/lin-lan.yaml",
65
+ contents: `$document:
66
+ id: character.lin-lan
67
+ ref: lin-lan
68
+ title: 林岚
69
+ summary: 途经溪桥镇的植物绘图员,喜欢用信分享见闻。
70
+ aliases: []
71
+ 外貌: 戴圆框眼镜,指尖有淡淡的铅笔灰。
72
+ 衣着: 灰色针织衫,深蓝长裤,晾在伞架旁的棕色雨披。
73
+ 性格: 观察细致,说话慢,担心时会反复核对细节。
74
+ 关系:
75
+ 沈禾:
76
+ 对象: { $ref: character.shen-he }
77
+ 看法: 熟悉而可靠的店主,信不见了也不认为她会故意隐瞒。
78
+ 周澄:
79
+ 对象: { $ref: character.zhou-cheng }
80
+ 看法: 今晚才认识的邮差,相信他熟悉寄信流程,尚不了解他的习惯。
81
+ 重要物品:
82
+ 给妹妹的信: 浅蓝信封,未封口,内有一页见闻和一张手绘叶片图;原计划明早寄出。
83
+ 认知:
84
+ 信件: 知道自己把信交给了沈禾;只看到现在瓷碟空了,不知道它后来去了哪里。
85
+ 依据: { $ref: event.letter-entrusted }
86
+ `,
87
+ },
88
+ {
89
+ path: "world/characters/zhou-cheng.yaml",
90
+ contents: `$document:
91
+ id: character.zhou-cheng
92
+ ref: zhou-cheng
93
+ title: 周澄
94
+ summary: 镇上的年轻邮差,雨天也会顺路帮邻居跑腿。
95
+ aliases: [小周]
96
+ 外貌: 头发被雨压得贴在额前,笑起来有浅酒窝。
97
+ 衣着: 蓝色雨衣敞着扣子,条纹衬衣,湿了鞋尖的帆布鞋。
98
+ 性格: 热心,做事容易分心;一旦发现自己弄错,愿意承认并帮忙补救。
99
+ 关系:
100
+ 沈禾:
101
+ 对象: { $ref: character.shen-he }
102
+ 看法: 从小认识的邻居,信任她,也在意自己能否帮上忙。
103
+ 林岚:
104
+ 对象: { $ref: character.lin-lan }
105
+ 看法: 刚认识的客人,她的植物画很有趣,想请她解释画里的树叶。
106
+ 认知:
107
+ 自己记得的动作: 刚才挪开柜台上的浅蓝信封给湿登记簿腾地方,顺手把它夹进登记簿封底;以为那只是空信封。
108
+ 当前理解: 尚未听清林岚在找什么,没有把她的信与自己挪过的信封联系起来。
109
+ 随身物品:
110
+ 登记簿: 抱在手里,封底书角被雨打湿。
111
+ `,
112
+ },
113
+ {
114
+ path: "world/locations/rain-lantern-inn.yaml",
115
+ contents: `$document:
116
+ id: location.rain-lantern-inn
117
+ ref: rain-lantern-inn
118
+ title: 雨灯旅店
119
+ summary: 溪桥镇桥头的小旅店,邻里常来避雨喝茶。
120
+ aliases: []
121
+ 大厅: 木柜台正对入口,柜台上有蓝瓷碟和铜灯;窗边放着小桌,门旁是伞架。
122
+ 日常: 客人可在大厅休息、喝姜茶,店主替熟客暂存待寄信件。
123
+ `,
124
+ },
125
+ {
126
+ path: "world/events/letter-entrusted.yaml",
127
+ contents: `$document:
128
+ id: event.letter-entrusted
129
+ ref: letter-entrusted
130
+ title: 柜台上的托付
131
+ summary: 林岚把待寄信件交给沈禾暂存的一次托付。
132
+ aliases: []
133
+ 时间: 今晚约半小时前
134
+ 经过: 林岚将未封口的浅蓝信封交给沈禾,说明里面有给妹妹的信和叶片图;沈禾当着她的面放在柜台蓝瓷碟上。
135
+ 原话: 林岚说「明早我再来封口,麻烦先放这里」。沈禾答应替她暂存。
136
+ 来源: 林岚与沈禾当时都在柜台旁。
137
+ `,
138
+ },
139
+ {
140
+ path: "control/frame.yaml",
141
+ contents: `format: narraeon.world-frame/v1
142
+ bindings:
143
+ currentSituation: "@current-situation"
144
+ instructions:
145
+ - markdown: blocks/world.md
146
+ context:
147
+ - slot: { kind: catalog, directory: characters, maxEntries: 3 }
148
+ - slot: { kind: catalog, directory: locations, maxEntries: 4 }
149
+ - slot: { kind: catalog, directory: events, maxEntries: 12 }
150
+ - slot: { kind: document, document: "@rain-lantern-inn" }
151
+ - slot:
152
+ kind: reference_targets
153
+ from:
154
+ document: "@current-situation"
155
+ locator: { yaml: [在场人物] }
156
+ maxEntries: 3
157
+ - slot: { kind: current_situation }
158
+ - slot: { kind: additional_materials }
159
+ `,
160
+ },
161
+ {
162
+ path: "control/blocks/world.md",
163
+ contents: `<!-- opening.md 是玩家看到的开场;world/current-situation.yaml 记录背景与待回应局面;characters/ 各自保存人物状态、关系与认知;locations/ 保存地点;events/ 保存共同往事;frame.yaml 选择游玩材料;player-views.yaml 选择状态栏原值。可从这些文件改写自己的故事。 -->
164
+
165
+ # 本世界的题材与边界
166
+
167
+ 以小镇旅店的日常交谈和轻微悬疑为主,线索来自物件、记忆和误会。保持温暖、适合所有年龄;不引入暴力、成人内容或威胁生命的阴谋。信件的私人内容由收信人与写信人决定是否分享。
168
+
169
+ ## 本世界的文档与保存位置
170
+
171
+ 人物之间的关系、各自看法与认知写在各自的 world/characters/ 人物文档中,不设统一真相或秘密字段。需要共同引用的事件经过写在 world/events/,人物通过引用关联,不重复抄写经过。地点的持续变化写回 world/locations/。信件先作为所属人物的重要物品维护,需要独立转移追踪时再建文档。
172
+ `,
173
+ },
174
+ {
175
+ path: "control/player-views.yaml",
176
+ contents: `format: narraeon.player-views/v1
177
+ views:
178
+ - id: scene-status
179
+ title: 此刻
180
+ items:
181
+ - id: time
182
+ label: 时间
183
+ select:
184
+ document: "@current-situation"
185
+ locator: { yaml: [背景, 时间] }
186
+ - id: place
187
+ label: 地点
188
+ select:
189
+ document: "@current-situation"
190
+ locator: { yaml: [背景, 地点] }
191
+ `,
192
+ },
193
+ ],
194
+ };