narraeon 0.5.6 → 0.6.0

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 (59) hide show
  1. package/README.md +3 -1
  2. package/README.zh-CN.md +3 -1
  3. package/dist/node/protocol/appPreferences.js +4 -2
  4. package/dist/node/protocol/gameplay.js +69 -0
  5. package/dist/node/protocol/playFailure.js +13 -0
  6. package/dist/node/protocol/protagonistTemplates.js +13 -0
  7. package/dist/node/protocol/resolution.js +274 -0
  8. package/dist/node/protocol/v1.js +40 -19
  9. package/dist/node/protocol/worldArchives.js +7 -0
  10. package/dist/node/runtime/RuntimeErrorLog.js +95 -0
  11. package/dist/node/runtime/V1Runtime.js +103 -8
  12. package/dist/node/runtime/archive/WorldArchiveZip.js +202 -0
  13. package/dist/node/runtime/archive/WorldArchives.js +389 -0
  14. package/dist/node/runtime/config/AppPreferencesStore.js +23 -10
  15. package/dist/node/runtime/config/ProtagonistTemplateStore.js +134 -0
  16. package/dist/node/runtime/content/ContentWorkspace.js +15 -2
  17. package/dist/node/runtime/content/CurrentTreeContentLibrary.js +43 -2
  18. package/dist/node/runtime/content/FileNativeContentTree.js +8 -1
  19. package/dist/node/runtime/history/StoryExport.js +33 -0
  20. package/dist/node/runtime/model/FileNativeModelAdapters.js +34 -2
  21. package/dist/node/runtime/model/ModelHost.js +12 -1
  22. package/dist/node/runtime/model/ModelHostStream.js +11 -3
  23. package/dist/node/runtime/play/FileNativePlayAdvanceStore.js +37 -1
  24. package/dist/node/runtime/play/FileNativePlayPresetStore.js +48 -3
  25. package/dist/node/runtime/play/FileNativePlayTimelineStore.js +87 -4
  26. package/dist/node/runtime/play/LegacyModelBindingFailure.js +10 -0
  27. package/dist/node/runtime/play/OrderedPlayPrompts.js +68 -6
  28. package/dist/node/runtime/play/PlayCallChain.js +177 -57
  29. package/dist/node/runtime/play/PlayCallChainError.js +3 -1
  30. package/dist/node/runtime/play/PlayContinuity.js +3 -20
  31. package/dist/node/runtime/play/PlayFailure.js +20 -0
  32. package/dist/node/runtime/play/PlayTraceRetention.js +3 -11
  33. package/dist/node/runtime/play/TabletopResolution.js +372 -0
  34. package/dist/node/runtime/play/TabletopRules.js +141 -0
  35. package/dist/node/runtime/prompt/FileNativePromptCompiler.js +49 -32
  36. package/dist/node/runtime/prompt/FileNativeToolRegistry.js +37 -4
  37. package/dist/node/runtime/setting/FileNativeSettingImprovementStore.js +4 -1
  38. package/dist/node/runtime/setting/SettingAuthoringTransaction.js +56 -13
  39. package/dist/node/runtime/setting/SettingImprovementSession.js +6 -4
  40. package/dist/node/runtime/world/FileNativeWorldStore.js +207 -40
  41. package/dist/node/runtime/world/WorldActivity.js +143 -0
  42. package/dist/node/runtime/world-revision/FileNativeWorldRevisionStore.js +2 -0
  43. package/dist/node/runtime/world-revision/WorldRevisionAuthoringTransaction.js +35 -6
  44. package/dist/node/runtime/world-revision/WorldRevisionSession.js +9 -5
  45. package/dist/node/server/ConversationStream.js +2 -0
  46. package/dist/node/server/createServer.js +48 -0
  47. package/dist/node/shared/default-preset-host.js +10 -6
  48. package/dist/node/shared/ordered-author-prompts.js +8 -0
  49. package/dist/node/shared/ordered-play-prompts.js +25 -2
  50. package/dist/node/shared/sample-packages/index.js +10 -0
  51. package/dist/node/shared/sample-packages/rainy-inn-en.js +194 -0
  52. package/dist/node/shared/sample-packages/rainy-inn-zh.js +194 -0
  53. package/dist/node/shared/tabletop-guidance.js +100 -0
  54. package/dist/web/assets/index-BJ-1Mb0e.css +1 -0
  55. package/dist/web/assets/index-BgBL8G-A.js +1323 -0
  56. package/dist/web/index.html +2 -2
  57. package/package.json +6 -2
  58. package/dist/web/assets/index-BH8NyuE4.js +0 -1233
  59. package/dist/web/assets/index-CVN48xrw.css +0 -1
@@ -1,5 +1,5 @@
1
1
  import { createHash } from "node:crypto";
2
- import { parseDocument } from "yaml";
2
+ import { isMap, isSeq, parseDocument } from "yaml";
3
3
  import { builtinPlayPrompts, isPromptMessageRole, } from "../../shared/ordered-play-prompts.js";
4
4
  /** The same strict permission gate is used by portable imports and structured saves. */
5
5
  export function parseOrderedPlayPrompts(value, catalog = builtinPlayPrompts("en"), worldRequired = true) {
@@ -24,20 +24,23 @@ export function parseOrderedPlayPrompts(value, catalog = builtinPlayPrompts("en"
24
24
  !isPromptMessageRole(item.messageRole))
25
25
  return fail();
26
26
  const messageRole = item.messageRole === undefined ? {} : { messageRole: item.messageRole };
27
- const exact = (keys) => Object.keys(item).length ===
28
- keys.length + (item.messageRole === undefined ? 0 : 1) &&
29
- keys.every((key) => Object.hasOwn(item, key));
27
+ const exact = (keys, optional = []) => Object.keys(item).every((key) => keys.includes(key) ||
28
+ optional.includes(key) ||
29
+ key === "messageRole" ||
30
+ key === "id" ||
31
+ key === "kind") && keys.every((key) => Object.hasOwn(item, key));
30
32
  if (item.kind === "world" && exact(["id", "kind"])) {
31
33
  worlds++;
32
34
  return { id: item.id, kind: "world", ...messageRole };
33
35
  }
34
36
  if (item.kind === "user" &&
35
- exact(["id", "kind", "name", "enabled", "body"]) &&
37
+ exact(["id", "kind", "name", "enabled", "body"], ["gameplay"]) &&
36
38
  typeof item.name === "string" &&
37
39
  item.name.trim().length > 0 &&
38
40
  /^[^\r\n\0]{1,160}$/u.test(item.name) &&
39
41
  typeof item.body === "string" &&
40
- typeof item.enabled === "boolean")
42
+ typeof item.enabled === "boolean" &&
43
+ (item.gameplay === undefined || item.gameplay === "tabletop"))
41
44
  return {
42
45
  id: item.id,
43
46
  kind: "user",
@@ -45,6 +48,9 @@ export function parseOrderedPlayPrompts(value, catalog = builtinPlayPrompts("en"
45
48
  enabled: item.enabled,
46
49
  body: item.body,
47
50
  ...messageRole,
51
+ ...(item.gameplay === "tabletop"
52
+ ? { gameplay: "tabletop" }
53
+ : {}),
48
54
  };
49
55
  const builtin = catalog.find((entry) => entry.id === item.builtin);
50
56
  if (item.kind !== "builtin" ||
@@ -70,6 +76,54 @@ export function parseOrderedPlayPrompts(value, catalog = builtinPlayPrompts("en"
70
76
  return fail();
71
77
  return entries;
72
78
  }
79
+ /**
80
+ * Insert the tabletop builtins that an ordered preset does not list yet.
81
+ * play.tabletop goes just before the world placeholder and author.tabletop just
82
+ * after author.guidance. Files that are not ordered v2 or do not parse come back
83
+ * unchanged, and nothing else in them is rewritten. The same object is returned
84
+ * when nothing needs inserting, so callers can detect a change by identity.
85
+ */
86
+ export function withTabletopPromptBuiltins(files) {
87
+ const source = files["preset.yaml"];
88
+ if (source === undefined)
89
+ return files;
90
+ const document = parseDocument(source, { uniqueKeys: true });
91
+ if (document.errors.length > 0 ||
92
+ document.warnings.length > 0 ||
93
+ !isMap(document.contents) ||
94
+ document.get("format") !== "narraeon.play-preset/v2")
95
+ return files;
96
+ let changed = false;
97
+ const playPrompts = document.get("playPrompts", true);
98
+ if (isSeq(playPrompts) && !hasEntry(playPrompts, "play.tabletop")) {
99
+ const world = playPrompts.items.findIndex((item) => entryField(item, "kind") === "world");
100
+ playPrompts.items.splice(world < 0 ? playPrompts.items.length : world, 0, document.createNode({
101
+ id: "play.tabletop",
102
+ kind: "builtin",
103
+ builtin: "play.tabletop",
104
+ enabled: true,
105
+ }));
106
+ changed = true;
107
+ }
108
+ const authorPrompts = document.get("authorPrompts", true);
109
+ if (isSeq(authorPrompts) && !hasEntry(authorPrompts, "author.tabletop")) {
110
+ const guidance = authorPrompts.items.findIndex((item) => entryField(item, "id") === "author.guidance");
111
+ authorPrompts.items.splice(guidance < 0 ? authorPrompts.items.length : guidance + 1, 0, document.createNode({
112
+ id: "author.tabletop",
113
+ kind: "builtin",
114
+ builtin: "author.tabletop",
115
+ enabled: true,
116
+ }));
117
+ changed = true;
118
+ }
119
+ return changed ? { ...files, "preset.yaml": document.toString() } : files;
120
+ }
121
+ function hasEntry(sequence, id) {
122
+ return sequence.items.some((item) => entryField(item, "id") === id);
123
+ }
124
+ function entryField(item, key) {
125
+ return isMap(item) ? item.get(key) : undefined;
126
+ }
73
127
  /** Recognized v1 content becomes user text, never a locked builtin inferred from a path. */
74
128
  export function migrateLegacyPlayPrompts(files, narrative, excludedPaths = []) {
75
129
  const document = parseDocument(files["frame.yaml"] ?? "", {
@@ -185,5 +239,13 @@ export function migrateLegacyPlayPrompts(files, narrative, excludedPaths = []) {
185
239
  if ((path.startsWith("blocks/") || path.startsWith("prompts/")) &&
186
240
  path.endsWith(".md"))
187
241
  add(path, false);
242
+ // The tabletop builtin joins converted presets just before the world placeholder.
243
+ const worldIndex = entries.findIndex((entry) => entry.kind === "world");
244
+ entries.splice(worldIndex, 0, {
245
+ id: "play.tabletop",
246
+ kind: "builtin",
247
+ builtin: "play.tabletop",
248
+ enabled: true,
249
+ });
188
250
  return entries;
189
251
  }