narraeon 0.4.0 → 0.5.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 (76) hide show
  1. package/dist/node/protocol/appPreferences.js +25 -0
  2. package/dist/node/protocol/conversationObservation.js +67 -0
  3. package/dist/node/protocol/v1.js +186 -34
  4. package/dist/node/protocol/worldExtensions.js +16 -0
  5. package/dist/node/protocol/worldMaintenance.js +77 -0
  6. package/dist/node/protocol/worldPromptDiagnostics.js +1 -0
  7. package/dist/node/runtime/ConversationChanges.js +24 -0
  8. package/dist/node/runtime/V1Runtime.js +445 -121
  9. package/dist/node/runtime/artifact/FileNativeArtifactStore.js +326 -12
  10. package/dist/node/runtime/authoring/AuthoringRequestSnapshot.js +63 -0
  11. package/dist/node/runtime/authoring/ModelToolConversation.js +218 -0
  12. package/dist/node/runtime/config/AppPreferencesStore.js +46 -17
  13. package/dist/node/runtime/content/ContentTreeFingerprint.js +13 -0
  14. package/dist/node/runtime/content/ContentWorkspace.js +43 -13
  15. package/dist/node/runtime/content/CurrentTreeContentLibrary.js +128 -46
  16. package/dist/node/runtime/content/FileNativeContentTree.js +28 -10
  17. package/dist/node/runtime/content/PackageFollowups.js +80 -0
  18. package/dist/node/runtime/extension/FrontendExtensionBundle.js +19 -14
  19. package/dist/node/runtime/extension/PackageScriptPermissions.js +70 -0
  20. package/dist/node/runtime/extension/WorldExtensionControls.js +205 -0
  21. package/dist/node/runtime/extension/WorldExtensionRequests.js +64 -0
  22. package/dist/node/runtime/model/FileNativeModelAdapters.js +21 -466
  23. package/dist/node/runtime/model/ModelConnectionStore.js +13 -0
  24. package/dist/node/runtime/model/ModelHost.js +31 -1
  25. package/dist/node/runtime/model/ModelHostStream.js +51 -5
  26. package/dist/node/runtime/play/FileNativeContinuityCorrection.js +55 -45
  27. package/dist/node/runtime/play/FileNativePlayPresetStore.js +256 -238
  28. package/dist/node/runtime/play/FileNativePlayTimelineStore.js +118 -9
  29. package/dist/node/runtime/play/OrderedFollowups.js +71 -0
  30. package/dist/node/runtime/play/OrderedPlayPrompts.js +180 -0
  31. package/dist/node/runtime/play/PlayCallChain.js +814 -61
  32. package/dist/node/runtime/play/PlayContinuity.js +88 -0
  33. package/dist/node/runtime/play/PlayDocumentTools.js +205 -287
  34. package/dist/node/runtime/play/PlayFollowupRequests.js +34 -3
  35. package/dist/node/runtime/play/PlayPresetWorkbench.js +45 -54
  36. package/dist/node/runtime/play/PlayPromptRun.js +86 -0
  37. package/dist/node/runtime/prompt/FileNativePromptCompiler.js +670 -93
  38. package/dist/node/runtime/prompt/FileNativeToolRegistry.js +37 -21
  39. package/dist/node/runtime/prompt/PromptCompilationCodec.js +322 -0
  40. package/dist/node/runtime/prompt/WorldMaintenanceReport.js +251 -0
  41. package/dist/node/runtime/prompt/WorldMaterialCoverage.js +83 -0
  42. package/dist/node/runtime/prompt/WorldPromptDiagnostics.js +185 -0
  43. package/dist/node/runtime/setting/FileNativeSettingImprovementStore.js +1027 -0
  44. package/dist/node/runtime/setting/SettingAuthoringTransaction.js +1339 -0
  45. package/dist/node/runtime/setting/SettingImprovementSession.js +714 -0
  46. package/dist/node/runtime/world/FileNativeAuthorityV3.js +88 -1
  47. package/dist/node/runtime/world/FileNativeWorldStore.js +292 -27
  48. package/dist/node/runtime/world/PlayerViewBindings.js +30 -0
  49. package/dist/node/runtime/world/PlayerViewRenderer.js +27 -34
  50. package/dist/node/runtime/world/WorldDocumentMaintenance.js +174 -0
  51. package/dist/node/runtime/world/WorldDocumentStore.js +166 -96
  52. package/dist/node/runtime/world/WorldOperationCoordinator.js +103 -2
  53. package/dist/node/runtime/world-revision/FileNativeWorldRevisionStore.js +696 -0
  54. package/dist/node/runtime/world-revision/WorldRevisionAuthoringTransaction.js +380 -0
  55. package/dist/node/runtime/world-revision/WorldRevisionSession.js +709 -0
  56. package/dist/node/runtime/world-revision/WorldRevisionWorkspace.js +494 -0
  57. package/dist/node/server/ConversationStream.js +109 -0
  58. package/dist/node/server/createServer.js +5 -1
  59. package/dist/node/shared/artifact-payload-contract.js +123 -0
  60. package/dist/node/shared/default-play-prompts.js +25 -45
  61. package/dist/node/shared/default-preset-host.js +114 -138
  62. package/dist/node/shared/default-setting-improvement-prompt.js +52 -38
  63. package/dist/node/shared/display-regex.js +114 -0
  64. package/dist/node/shared/first-party-action-choices.js +1 -6
  65. package/dist/node/shared/first-party-player-view.js +1 -6
  66. package/dist/node/shared/ordered-author-prompts.js +64 -0
  67. package/dist/node/shared/ordered-followups.js +42 -0
  68. package/dist/node/shared/ordered-play-prompts.js +73 -0
  69. package/dist/web/assets/index-BXfelCi9.js +1207 -0
  70. package/dist/web/assets/index-BYnhUxlk.css +1 -0
  71. package/dist/web/index.html +2 -2
  72. package/package.json +1 -1
  73. package/dist/node/runtime/model/SettingAuthorStream.js +0 -21
  74. package/dist/node/runtime/setting/DocumentCandidateSettingImprovement.js +0 -1731
  75. package/dist/web/assets/index-D8YKfmNG.js +0 -1192
  76. package/dist/web/assets/index-Xa0s35CJ.css +0 -1
@@ -0,0 +1,205 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { open, readFile, rename, rm } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { requestControlKey } from "../../protocol/worldExtensions.js";
5
+ import { builtinFollowupExample, defaultFollowupItems, } from "../../shared/ordered-followups.js";
6
+ import { readPackageFollowups } from "../content/PackageFollowups.js";
7
+ const fileName = "extension-controls.json";
8
+ /** Caller serializes mutations with the existing world lock; no Authority facts are changed. */
9
+ export class WorldExtensionControls {
10
+ static async read(root) {
11
+ try {
12
+ const state = JSON.parse(await readFile(join(root, fileName), "utf8"));
13
+ if (!isState(state))
14
+ throw new Error("Invalid world extension controls");
15
+ return state;
16
+ }
17
+ catch (error) {
18
+ if (error instanceof Error && "code" in error && error.code === "ENOENT")
19
+ return { schemaVersion: 1, revision: 0, entries: {} };
20
+ throw error;
21
+ }
22
+ }
23
+ static async write(root, state) {
24
+ const path = join(root, fileName);
25
+ const temporary = `${path}.${randomUUID()}.tmp`;
26
+ try {
27
+ const file = await open(temporary, "wx", 0o600);
28
+ try {
29
+ await file.writeFile(JSON.stringify(state));
30
+ await file.sync();
31
+ }
32
+ finally {
33
+ await file.close();
34
+ }
35
+ await rename(temporary, path);
36
+ const directory = await open(root, "r");
37
+ try {
38
+ await directory.sync();
39
+ }
40
+ finally {
41
+ await directory.close();
42
+ }
43
+ }
44
+ finally {
45
+ await rm(temporary, { force: true });
46
+ }
47
+ }
48
+ static async copy(sourceRoot, targetRoot) {
49
+ await this.write(targetRoot, await this.read(sourceRoot));
50
+ }
51
+ static async resolve(root, definitions, _presetId, change) {
52
+ const state = await this.read(root);
53
+ const before = JSON.stringify(state.entries);
54
+ for (const definition of definitions)
55
+ if (!Object.hasOwn(state.entries, definition.key)) {
56
+ const group = definitions.find((item) => item.key === definition.group);
57
+ const enabled = definition.defaultEnabled &&
58
+ (group === undefined ||
59
+ (state.entries[group.key]?.override ?? group.defaultEnabled));
60
+ state.entries[definition.key] = {
61
+ generation: enabled ? 0 : 1,
62
+ // Defaults select the next run; only world commands revoke frozen runs.
63
+ enabled: group === undefined || state.entries[group.key]?.enabled !== false,
64
+ };
65
+ }
66
+ if (change) {
67
+ if (!definitions.some((item) => item.key === change.key))
68
+ throw new Error("The extension definition no longer exists");
69
+ const entry = state.entries[change.key] ?? {
70
+ generation: 0,
71
+ enabled: false,
72
+ };
73
+ if (change.value === "default")
74
+ delete entry.override;
75
+ else
76
+ entry.override = change.value === "on";
77
+ state.entries[change.key] = entry;
78
+ }
79
+ const selected = (definition) => state.entries[definition.key]?.override ?? definition.defaultEnabled;
80
+ const items = definitions.map((definition) => {
81
+ const group = definitions.find((item) => item.key === definition.group);
82
+ const enabled = selected(definition) && (group === undefined || selected(group));
83
+ const previous = state.entries[definition.key];
84
+ const affected = change !== undefined &&
85
+ (definition.key === change.key || definition.group === change.key);
86
+ const gateEnabled = affected
87
+ ? enabled
88
+ : enabled || (previous?.enabled ?? true);
89
+ const entry = {
90
+ generation: (previous?.generation ?? 0) +
91
+ (previous?.enabled === true && !gateEnabled ? 1 : 0),
92
+ enabled: gateEnabled,
93
+ ...(previous?.override === undefined
94
+ ? {}
95
+ : { override: previous.override }),
96
+ };
97
+ state.entries[definition.key] = entry;
98
+ return {
99
+ ...definition,
100
+ selected: selected(definition),
101
+ enabled,
102
+ overridden: entry.override !== undefined,
103
+ generation: entry.generation,
104
+ };
105
+ });
106
+ // Removing a source definition also belongs to the next run. Retain its
107
+ // frozen generation; an explicit package-group close still revokes all children.
108
+ if (change?.key === "group:package" &&
109
+ state.entries[change.key]?.enabled === false)
110
+ for (const [key, entry] of Object.entries(state.entries))
111
+ if (key.startsWith("package:") && entry.enabled) {
112
+ entry.enabled = false;
113
+ entry.generation++;
114
+ }
115
+ if (before !== JSON.stringify(state.entries)) {
116
+ state.revision++;
117
+ await this.write(root, state);
118
+ }
119
+ return { revision: state.revision, items };
120
+ }
121
+ }
122
+ export function extensionDefinitions(binding, files, views, locale) {
123
+ const items = [];
124
+ for (const item of binding.definition.followupItems ??
125
+ defaultFollowupItems(binding.definition.followups)) {
126
+ const group = item.kind === "content-package";
127
+ const request = binding.definition.followups.find((def) => def.id === item.id);
128
+ items.push({
129
+ key: group ? "group:package" : requestControlKey(binding.id, item.id),
130
+ id: item.id,
131
+ name: group
132
+ ? locale === "zh-CN"
133
+ ? "内容包后置请求"
134
+ : "Content package requests"
135
+ : item.kind === "builtin"
136
+ ? builtinFollowupExample(locale).definition.displayName
137
+ : request.displayName,
138
+ kind: group ? "group" : "request",
139
+ source: group
140
+ ? "package"
141
+ : item.kind === "builtin"
142
+ ? "builtin"
143
+ : "preset",
144
+ defaultEnabled: item.enabled,
145
+ });
146
+ if (group)
147
+ for (const child of readPackageFollowups(files).followups)
148
+ items.push({
149
+ key: `package:${child.definition.id}`,
150
+ id: `package:${child.definition.id}`,
151
+ name: child.definition.displayName,
152
+ kind: "request",
153
+ source: "package",
154
+ group: "group:package",
155
+ defaultEnabled: child.enabled,
156
+ });
157
+ }
158
+ for (const panel of binding.definition.playerViewPanels)
159
+ items.push({
160
+ key: `preset:${binding.id}:panel:${panel.id}`,
161
+ id: panel.id,
162
+ name: panel.config.title ??
163
+ views.find((view) => view.id === panel.source.view)?.title ??
164
+ panel.source.view,
165
+ kind: "panel",
166
+ source: "preset",
167
+ defaultEnabled: true,
168
+ });
169
+ const covered = new Set(binding.definition.playerViewPanels.map((panel) => panel.source.view));
170
+ for (const view of views)
171
+ if (!covered.has(view.id))
172
+ items.push({
173
+ key: `view:${view.id}`,
174
+ id: view.id,
175
+ name: view.title,
176
+ kind: "view",
177
+ source: "world",
178
+ defaultEnabled: true,
179
+ });
180
+ return items;
181
+ }
182
+ function isState(value) {
183
+ if (typeof value !== "object" ||
184
+ value === null ||
185
+ !("schemaVersion" in value) ||
186
+ value.schemaVersion !== 1 ||
187
+ !("revision" in value) ||
188
+ !Number.isSafeInteger(value.revision) ||
189
+ Number(value.revision) < 0 ||
190
+ !("entries" in value) ||
191
+ typeof value.entries !== "object" ||
192
+ value.entries === null ||
193
+ Array.isArray(value.entries) ||
194
+ Object.keys(value).length !== 3)
195
+ return false;
196
+ return Object.values(value.entries).every((entry) => typeof entry === "object" &&
197
+ entry !== null &&
198
+ "generation" in entry &&
199
+ Number.isSafeInteger(entry.generation) &&
200
+ Number(entry.generation) >= 0 &&
201
+ "enabled" in entry &&
202
+ typeof entry.enabled === "boolean" &&
203
+ (!("override" in entry) || typeof entry.override === "boolean") &&
204
+ Object.keys(entry).every((key) => ["generation", "enabled", "override"].includes(key)));
205
+ }
@@ -0,0 +1,64 @@
1
+ import { join } from "node:path";
2
+ import { requestControlKey, } from "../../protocol/worldExtensions.js";
3
+ import { WorldExtensionControls } from "./WorldExtensionControls.js";
4
+ /** Cancellation is best effort; persisted generations remain the visibility authority. */
5
+ export class WorldExtensionRequests {
6
+ #root;
7
+ #active = new Set();
8
+ constructor(worldsRoot) {
9
+ this.#root = worldsRoot;
10
+ }
11
+ async visible(worldId, record) {
12
+ const control = record.extensionControl ?? {
13
+ key: requestControlKey(record.playPresetId, record.requestId),
14
+ generation: 0,
15
+ };
16
+ const state = await WorldExtensionControls.read(join(this.#root, worldId));
17
+ const current = state.entries[control.key];
18
+ return current === undefined
19
+ ? control.generation === 0
20
+ : current.enabled && current.generation === control.generation;
21
+ }
22
+ async changed(worldId) {
23
+ for (const active of this.#active) {
24
+ if (active.worldId !== worldId)
25
+ continue;
26
+ if (!(await this.visible(worldId, {
27
+ playPresetId: "",
28
+ requestId: "",
29
+ extensionControl: active.control,
30
+ })))
31
+ active.controller.abort();
32
+ }
33
+ }
34
+ async acquire(worldId, record, signal) {
35
+ const controller = new AbortController();
36
+ const entry = {
37
+ worldId,
38
+ control: record.extensionControl ?? {
39
+ key: requestControlKey(record.playPresetId, record.requestId),
40
+ generation: 0,
41
+ },
42
+ controller,
43
+ };
44
+ this.#active.add(entry);
45
+ // Register before reading, so a concurrent accepted change cannot slip between
46
+ // the persisted check and dispatch registration.
47
+ try {
48
+ if (!(await this.visible(worldId, record)))
49
+ controller.abort();
50
+ return {
51
+ signal: signal === undefined
52
+ ? controller.signal
53
+ : AbortSignal.any([signal, controller.signal]),
54
+ release: () => {
55
+ this.#active.delete(entry);
56
+ },
57
+ };
58
+ }
59
+ catch (error) {
60
+ this.#active.delete(entry);
61
+ throw error;
62
+ }
63
+ }
64
+ }