narraeon 0.3.1 → 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.
- package/dist/node/protocol/appPreferences.js +25 -0
- package/dist/node/protocol/conversationObservation.js +67 -0
- package/dist/node/protocol/v1.js +188 -34
- package/dist/node/protocol/worldExtensions.js +16 -0
- package/dist/node/protocol/worldMaintenance.js +77 -0
- package/dist/node/protocol/worldPromptDiagnostics.js +1 -0
- package/dist/node/runtime/ConversationChanges.js +24 -0
- package/dist/node/runtime/V1Runtime.js +447 -121
- package/dist/node/runtime/artifact/FileNativeArtifactStore.js +326 -12
- package/dist/node/runtime/authoring/AuthoringRequestSnapshot.js +63 -0
- package/dist/node/runtime/authoring/ModelToolConversation.js +218 -0
- package/dist/node/runtime/config/AppPreferencesStore.js +46 -17
- package/dist/node/runtime/content/ContentTreeFingerprint.js +13 -0
- package/dist/node/runtime/content/ContentWorkspace.js +43 -13
- package/dist/node/runtime/content/CurrentTreeContentLibrary.js +128 -46
- package/dist/node/runtime/content/FileNativeContentTree.js +28 -10
- package/dist/node/runtime/content/PackageFollowups.js +80 -0
- package/dist/node/runtime/extension/FrontendExtensionBundle.js +19 -14
- package/dist/node/runtime/extension/PackageScriptPermissions.js +70 -0
- package/dist/node/runtime/extension/WorldExtensionControls.js +205 -0
- package/dist/node/runtime/extension/WorldExtensionRequests.js +64 -0
- package/dist/node/runtime/model/FileNativeModelAdapters.js +21 -466
- package/dist/node/runtime/model/ModelConnectionStore.js +44 -10
- package/dist/node/runtime/model/ModelHost.js +31 -1
- package/dist/node/runtime/model/ModelHostStream.js +51 -5
- package/dist/node/runtime/play/FileNativeContinuityCorrection.js +55 -45
- package/dist/node/runtime/play/FileNativePlayPresetStore.js +256 -238
- package/dist/node/runtime/play/FileNativePlayTimelineStore.js +118 -9
- package/dist/node/runtime/play/OrderedFollowups.js +71 -0
- package/dist/node/runtime/play/OrderedPlayPrompts.js +180 -0
- package/dist/node/runtime/play/PlayCallChain.js +814 -61
- package/dist/node/runtime/play/PlayContinuity.js +88 -0
- package/dist/node/runtime/play/PlayDocumentTools.js +205 -287
- package/dist/node/runtime/play/PlayFollowupRequests.js +34 -3
- package/dist/node/runtime/play/PlayPresetWorkbench.js +45 -54
- package/dist/node/runtime/play/PlayPromptRun.js +86 -0
- package/dist/node/runtime/prompt/FileNativePromptCompiler.js +670 -93
- package/dist/node/runtime/prompt/FileNativeToolRegistry.js +37 -21
- package/dist/node/runtime/prompt/PromptCompilationCodec.js +322 -0
- package/dist/node/runtime/prompt/WorldMaintenanceReport.js +251 -0
- package/dist/node/runtime/prompt/WorldMaterialCoverage.js +83 -0
- package/dist/node/runtime/prompt/WorldPromptDiagnostics.js +185 -0
- package/dist/node/runtime/setting/FileNativeSettingImprovementStore.js +1027 -0
- package/dist/node/runtime/setting/SettingAuthoringTransaction.js +1339 -0
- package/dist/node/runtime/setting/SettingImprovementSession.js +714 -0
- package/dist/node/runtime/world/FileNativeAuthorityV3.js +88 -1
- package/dist/node/runtime/world/FileNativeWorldStore.js +292 -27
- package/dist/node/runtime/world/PlayerViewBindings.js +30 -0
- package/dist/node/runtime/world/PlayerViewRenderer.js +27 -34
- package/dist/node/runtime/world/WorldDocumentMaintenance.js +174 -0
- package/dist/node/runtime/world/WorldDocumentStore.js +166 -96
- package/dist/node/runtime/world/WorldOperationCoordinator.js +103 -2
- package/dist/node/runtime/world-revision/FileNativeWorldRevisionStore.js +696 -0
- package/dist/node/runtime/world-revision/WorldRevisionAuthoringTransaction.js +380 -0
- package/dist/node/runtime/world-revision/WorldRevisionSession.js +709 -0
- package/dist/node/runtime/world-revision/WorldRevisionWorkspace.js +494 -0
- package/dist/node/server/ConversationStream.js +109 -0
- package/dist/node/server/createServer.js +5 -1
- package/dist/node/shared/artifact-payload-contract.js +123 -0
- package/dist/node/shared/default-play-prompts.js +25 -45
- package/dist/node/shared/default-preset-host.js +114 -138
- package/dist/node/shared/default-setting-improvement-prompt.js +52 -38
- package/dist/node/shared/display-regex.js +114 -0
- package/dist/node/shared/first-party-action-choices.js +1 -6
- package/dist/node/shared/first-party-player-view.js +1 -6
- package/dist/node/shared/ordered-author-prompts.js +64 -0
- package/dist/node/shared/ordered-followups.js +42 -0
- package/dist/node/shared/ordered-play-prompts.js +73 -0
- package/dist/web/assets/index-BXfelCi9.js +1207 -0
- package/dist/web/assets/index-BYnhUxlk.css +1 -0
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/dist/node/runtime/model/SettingAuthorStream.js +0 -21
- package/dist/node/runtime/setting/DocumentCandidateSettingImprovement.js +0 -1731
- package/dist/web/assets/index-D5VqDvjY.js +0 -1192
- package/dist/web/assets/index-Xa0s35CJ.css +0 -1
|
@@ -1,26 +1,36 @@
|
|
|
1
|
+
import { PackageScriptPermissions } from "./extension/PackageScriptPermissions.js";
|
|
2
|
+
import { comparePromptPrefixes } from "./prompt/WorldPromptDiagnostics.js";
|
|
1
3
|
import { join } from "node:path";
|
|
2
4
|
import { maxPortableContentArchiveBase64Characters, maxPortableContentArchiveBytes, } from "../protocol/contentTree.js";
|
|
3
5
|
import { V1ProtocolError, v1Protocol, } from "../protocol/v1.js";
|
|
4
6
|
import { defaultAppLocale, } from "../protocol/appPreferences.js";
|
|
5
7
|
import { ContentPackageImportError, ContentWorkspace, InvalidContentTreeError, } from "./content/ContentWorkspace.js";
|
|
8
|
+
import { contentTreeFingerprint } from "./content/ContentTreeFingerprint.js";
|
|
6
9
|
import { inspectContentPackageCurrentTree } from "./content/FileNativeContentTree.js";
|
|
7
|
-
import { FileNativeModelHost
|
|
8
|
-
import {} from "./model/ModelHost.js";
|
|
10
|
+
import { FileNativeModelHost } from "./model/FileNativeModelAdapters.js";
|
|
11
|
+
import { equalModelHostBinding, } from "./model/ModelHost.js";
|
|
9
12
|
import { ModelConnectionStore } from "./model/ModelConnectionStore.js";
|
|
10
13
|
import { FileNativeContinuityCorrection } from "./play/FileNativeContinuityCorrection.js";
|
|
14
|
+
import { fingerprintControl } from "./play/PlayDocumentTools.js";
|
|
11
15
|
import { PlayCallChain, PlayCallChainError, } from "./play/PlayCallChain.js";
|
|
12
|
-
import { FileNativePlayPresetError, FileNativePlayPresetStore, presetHostBinding,
|
|
16
|
+
import { FileNativePlayPresetError, FileNativePlayPresetStore, presetHostBinding, } from "./play/FileNativePlayPresetStore.js";
|
|
13
17
|
import { buildPlayPresetWorkbenchSnapshot } from "./play/PlayPresetWorkbench.js";
|
|
14
18
|
import { FileNativeArtifactStore } from "./artifact/FileNativeArtifactStore.js";
|
|
15
19
|
import { projectArtifactForFrontend, projectDebugArtifactForFrontend, } from "./extension/FrontendExtensionBundle.js";
|
|
16
20
|
import { projectPlayerViewPanels, } from "./extension/PlayerViewPanelProjector.js";
|
|
17
21
|
import { FileNativePromptCompiler } from "./prompt/FileNativePromptCompiler.js";
|
|
18
|
-
import {
|
|
22
|
+
import { FileNativeSettingImprovementStore } from "./setting/FileNativeSettingImprovementStore.js";
|
|
23
|
+
import { SettingImprovementRollbackError, SettingImprovementSession, } from "./setting/SettingImprovementSession.js";
|
|
19
24
|
import { FileNativeWorldStore } from "./world/FileNativeWorldStore.js";
|
|
20
25
|
import { WorldDocumentStore } from "./world/WorldDocumentStore.js";
|
|
21
26
|
import { FileNativeAiFailureLog } from "./model/AiFailureLog.js";
|
|
22
27
|
import { AppPreferencesStore } from "./config/AppPreferencesStore.js";
|
|
28
|
+
import { FileNativeWorldRevisionStore } from "./world-revision/FileNativeWorldRevisionStore.js";
|
|
29
|
+
import { WorldRevisionSession } from "./world-revision/WorldRevisionSession.js";
|
|
30
|
+
import { WorldRevisionWorkspace, WorldRevisionWorkspaceError, } from "./world-revision/WorldRevisionWorkspace.js";
|
|
31
|
+
import { ConversationChanges } from "./ConversationChanges.js";
|
|
23
32
|
export class V1Runtime {
|
|
33
|
+
#conversationChanges = new ConversationChanges();
|
|
24
34
|
#content;
|
|
25
35
|
#playPresets;
|
|
26
36
|
#worlds;
|
|
@@ -30,7 +40,8 @@ export class V1Runtime {
|
|
|
30
40
|
#playCallChains;
|
|
31
41
|
#failureLog;
|
|
32
42
|
#preferences;
|
|
33
|
-
#settingImprovements
|
|
43
|
+
#settingImprovements;
|
|
44
|
+
#worldRevisions;
|
|
34
45
|
#compiler = new FileNativePromptCompiler();
|
|
35
46
|
#locale = defaultAppLocale;
|
|
36
47
|
constructor(input) {
|
|
@@ -47,9 +58,75 @@ export class V1Runtime {
|
|
|
47
58
|
input.logRoot === undefined
|
|
48
59
|
? undefined
|
|
49
60
|
: new FileNativeAiFailureLog(join(input.logRoot, "ai-failures"));
|
|
50
|
-
this.#playCallChains = new PlayCallChain(this.#worlds, this.#compiler, this.#artifacts, this.#failureLog);
|
|
61
|
+
this.#playCallChains = new PlayCallChain(this.#worlds, this.#compiler, this.#artifacts, this.#failureLog, (id) => this.#conversationChanges.publish(`play:${id}`));
|
|
51
62
|
this.#models = new ModelConnectionStore(input.configRoot);
|
|
52
|
-
this.#corrections = new FileNativeContinuityCorrection(this.#worlds
|
|
63
|
+
this.#corrections = new FileNativeContinuityCorrection(this.#worlds, {
|
|
64
|
+
compiler: this.#compiler,
|
|
65
|
+
});
|
|
66
|
+
this.#settingImprovements = new SettingImprovementSession({
|
|
67
|
+
changed: (id, durable) => this.#conversationChanges.publish(`setting:${id}`, durable),
|
|
68
|
+
store: new FileNativeSettingImprovementStore(input.dataRoot, {
|
|
69
|
+
content: this.#content,
|
|
70
|
+
}),
|
|
71
|
+
content: this.#content,
|
|
72
|
+
compiler: this.#compiler,
|
|
73
|
+
locale: () => this.#locale,
|
|
74
|
+
bindModelHost: () => this.#modelHost(),
|
|
75
|
+
bindExistingModelHost: (binding) => this.#matchingModelHost(binding),
|
|
76
|
+
bindPlayPreset: () => this.#playPresets.freeze(),
|
|
77
|
+
preview: (snapshot, modelBinding, playPreset) => this.#compiler.preview({
|
|
78
|
+
endpoint: { id: "setting-authoring", commit: "current-tree" },
|
|
79
|
+
hostBinding: playPreset === undefined
|
|
80
|
+
? {
|
|
81
|
+
hostPresetId: "legacy-setting-authoring",
|
|
82
|
+
files: defaultSettingPreviewHost(),
|
|
83
|
+
}
|
|
84
|
+
: presetHostBinding(playPreset),
|
|
85
|
+
world: previewWorld(snapshot, "setting-authoring.message.genesis.narrator", "setting-authoring"),
|
|
86
|
+
playerInputPlacement: "append",
|
|
87
|
+
playerInput: this.#locale === "zh-CN"
|
|
88
|
+
? "检查内容包当前树。"
|
|
89
|
+
: "Inspect the content package current tree.",
|
|
90
|
+
modelBinding,
|
|
91
|
+
}, playPreset),
|
|
92
|
+
});
|
|
93
|
+
const worldRevisionStore = new FileNativeWorldRevisionStore(input.dataRoot);
|
|
94
|
+
const worldRevisionWorkspace = new WorldRevisionWorkspace({
|
|
95
|
+
store: worldRevisionStore,
|
|
96
|
+
worlds: this.#worlds,
|
|
97
|
+
});
|
|
98
|
+
this.#worldRevisions = new WorldRevisionSession({
|
|
99
|
+
changed: (id, durable) => this.#conversationChanges.publish(`revision:${id}`, durable),
|
|
100
|
+
store: worldRevisionStore,
|
|
101
|
+
workspace: worldRevisionWorkspace,
|
|
102
|
+
worlds: this.#worlds,
|
|
103
|
+
compiler: this.#compiler,
|
|
104
|
+
locale: () => this.#locale,
|
|
105
|
+
bindModelHost: () => this.#modelHost(),
|
|
106
|
+
bindExistingModelHost: (binding) => this.#matchingModelHost(binding),
|
|
107
|
+
bindPlayPreset: () => this.#playPresets.freeze(),
|
|
108
|
+
preview: ({ snapshot, modelBinding, playPreset, binding, epoch, maintenance, }) => this.#compiler.preview({
|
|
109
|
+
endpoint: {
|
|
110
|
+
id: `${epoch.worldId}:${epoch.baseHead}:revision`,
|
|
111
|
+
commit: `worktree:${contentTreeFingerprint(snapshot.files)}`,
|
|
112
|
+
operationId: epoch.epochId,
|
|
113
|
+
},
|
|
114
|
+
hostBinding: presetHostBinding(playPreset),
|
|
115
|
+
world: {
|
|
116
|
+
controlFingerprint: fingerprintControl(Object.fromEntries(snapshot.files.map(({ path, contents }) => [path, contents]))),
|
|
117
|
+
documentSnapshot: snapshot,
|
|
118
|
+
history: structuredClone(binding.history),
|
|
119
|
+
narrativeCheckpoint: binding.narrativeCheckpoint,
|
|
120
|
+
...maintenance,
|
|
121
|
+
additionalMaterials: structuredClone(binding.additionalMaterials),
|
|
122
|
+
},
|
|
123
|
+
playerInputPlacement: "append",
|
|
124
|
+
playerInput: this.#locale === "zh-CN"
|
|
125
|
+
? "检查世界修订工作树。"
|
|
126
|
+
: "Inspect the world-revision worktree.",
|
|
127
|
+
modelBinding,
|
|
128
|
+
}, playPreset),
|
|
129
|
+
});
|
|
53
130
|
}
|
|
54
131
|
async initialize() {
|
|
55
132
|
this.#locale = (await this.#preferences.view()).locale;
|
|
@@ -57,8 +134,58 @@ export class V1Runtime {
|
|
|
57
134
|
await this.#playPresets.initialize();
|
|
58
135
|
}
|
|
59
136
|
async handle(request, playCallChainObserver) {
|
|
60
|
-
|
|
61
|
-
|
|
137
|
+
try {
|
|
138
|
+
const result = await this.#dispatch(request, playCallChainObserver);
|
|
139
|
+
return { protocol: v1Protocol, result };
|
|
140
|
+
}
|
|
141
|
+
finally {
|
|
142
|
+
// Explicit commands may partially settle before failing. Readers recover
|
|
143
|
+
// through the same Runtime projection, never infer success from this signal.
|
|
144
|
+
if (!/\.(read|status|overview|inspect|page|detail|list|preview)$/.test(request.type)) {
|
|
145
|
+
if ("packageId" in request)
|
|
146
|
+
this.#conversationChanges.publish(`setting:${request.packageId}`);
|
|
147
|
+
if ("worldId" in request) {
|
|
148
|
+
this.#conversationChanges.publish(`play:${request.worldId}`);
|
|
149
|
+
this.#conversationChanges.publish(`revision:${request.worldId}`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
subscribeConversation(target, changed) {
|
|
155
|
+
return this.#conversationChanges.subscribe(`${target.kind}:${target.id}`, changed);
|
|
156
|
+
}
|
|
157
|
+
async readConversation(target, previous) {
|
|
158
|
+
switch (target.kind) {
|
|
159
|
+
case "play":
|
|
160
|
+
return {
|
|
161
|
+
kind: "play",
|
|
162
|
+
value: await this.#playCallChains.observeWorld(target.id),
|
|
163
|
+
extensionsRevision: await this.#worlds.extensionControlsRevision(target.id),
|
|
164
|
+
};
|
|
165
|
+
case "setting": {
|
|
166
|
+
if (previous?.kind === "setting")
|
|
167
|
+
return {
|
|
168
|
+
kind: "setting",
|
|
169
|
+
value: this.#settingImprovements.observeProgress(previous.value),
|
|
170
|
+
};
|
|
171
|
+
const status = await this.#settingImprovements.status(target.id, target.sessionId);
|
|
172
|
+
const content = await this.#content.readCurrentTreeContentPackage(target.id);
|
|
173
|
+
return {
|
|
174
|
+
kind: "setting",
|
|
175
|
+
value: {
|
|
176
|
+
...status,
|
|
177
|
+
revision: `${status.revision}:${contentTreeFingerprint(content.files)}`,
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
case "revision":
|
|
182
|
+
return {
|
|
183
|
+
kind: "revision",
|
|
184
|
+
value: previous?.kind === "revision"
|
|
185
|
+
? this.#worldRevisions.observeProgress(previous.value)
|
|
186
|
+
: await this.#worldRevisions.status(target.id, target.sessionId),
|
|
187
|
+
};
|
|
188
|
+
}
|
|
62
189
|
}
|
|
63
190
|
async #dispatch(request, playCallChainObserver) {
|
|
64
191
|
switch (request.type) {
|
|
@@ -74,7 +201,12 @@ export class V1Runtime {
|
|
|
74
201
|
case "preferences.read":
|
|
75
202
|
return this.#preferences.view();
|
|
76
203
|
case "preferences.save": {
|
|
77
|
-
const preferences = await this.#preferences.save(
|
|
204
|
+
const preferences = await this.#preferences.save({
|
|
205
|
+
...(request.locale === undefined ? {} : { locale: request.locale }),
|
|
206
|
+
...(request.reading === undefined
|
|
207
|
+
? {}
|
|
208
|
+
: { reading: request.reading }),
|
|
209
|
+
});
|
|
78
210
|
this.#locale = preferences.locale;
|
|
79
211
|
this.#compiler.setLocale(this.#locale);
|
|
80
212
|
await this.#playPresets.syncBuiltinDefaultLocale();
|
|
@@ -84,6 +216,8 @@ export class V1Runtime {
|
|
|
84
216
|
return this.#models.view();
|
|
85
217
|
case "model.save":
|
|
86
218
|
return this.#models.save(request.connection);
|
|
219
|
+
case "model.copy":
|
|
220
|
+
return this.#models.copy(request.connectionId, request.name);
|
|
87
221
|
case "model.select":
|
|
88
222
|
return this.#models.select(request.connectionId);
|
|
89
223
|
case "model.delete":
|
|
@@ -92,6 +226,14 @@ export class V1Runtime {
|
|
|
92
226
|
return this.#models.listModels(request);
|
|
93
227
|
case "content.create":
|
|
94
228
|
return this.#content.createCurrentTreeContentPackage();
|
|
229
|
+
case "content.scripts.read":
|
|
230
|
+
return this.#content.packageScriptPermissions(request.packageId);
|
|
231
|
+
case "content.scripts.set":
|
|
232
|
+
return this.#content.packageScriptPermissions(request.packageId, request.enabled);
|
|
233
|
+
case "world.package-scripts.read":
|
|
234
|
+
return this.#worlds.packageScriptPermissions(request.worldId);
|
|
235
|
+
case "world.package-scripts.set":
|
|
236
|
+
return this.#worlds.packageScriptPermissions(request.worldId, request.enabled);
|
|
95
237
|
case "content.read":
|
|
96
238
|
return this.#content.readCurrentTreeContentPackage(request.packageId);
|
|
97
239
|
case "content.replace":
|
|
@@ -106,7 +248,7 @@ export class V1Runtime {
|
|
|
106
248
|
case "content.import": {
|
|
107
249
|
const archive = decodePortableContentArchive(request.archiveBase64);
|
|
108
250
|
try {
|
|
109
|
-
return await this.#content.importPortableContentPackageArchive(archive);
|
|
251
|
+
return await this.#content.importPortableContentPackageArchive(archive, request.title === undefined ? {} : { title: request.title });
|
|
110
252
|
}
|
|
111
253
|
catch (error) {
|
|
112
254
|
if (error instanceof ContentPackageImportError ||
|
|
@@ -124,82 +266,33 @@ export class V1Runtime {
|
|
|
124
266
|
base64: exported.archive.toString("base64"),
|
|
125
267
|
};
|
|
126
268
|
}
|
|
127
|
-
case "setting-improvement.
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
: { failureLog: this.#failureLog }),
|
|
141
|
-
operationId: request.improvementId,
|
|
142
|
-
locale: this.#locale,
|
|
143
|
-
}),
|
|
144
|
-
authorPrompt: settingImprovementPromptForBinding(preset, this.#locale),
|
|
145
|
-
locale: this.#locale,
|
|
146
|
-
...(this.#failureLog === undefined
|
|
147
|
-
? {}
|
|
148
|
-
: { failureLog: this.#failureLog }),
|
|
149
|
-
preview: (snapshot) => this.#compiler.preview({
|
|
150
|
-
endpoint: { id: "setting-candidate", commit: "candidate" },
|
|
151
|
-
hostBinding: {
|
|
152
|
-
hostPresetId: "setting-candidate",
|
|
153
|
-
files: defaultSettingPreviewHost(),
|
|
154
|
-
},
|
|
155
|
-
world: previewWorld(snapshot, "setting-candidate.message.genesis.narrator", "setting-candidate"),
|
|
156
|
-
playerInputPlacement: "bootstrap",
|
|
157
|
-
playerInput: this.#locale === "zh-CN"
|
|
158
|
-
? "预览设定候选。"
|
|
159
|
-
: "Preview the setting candidate.",
|
|
160
|
-
modelBinding: new FileNativeModelHost(connection).binding(),
|
|
161
|
-
}),
|
|
162
|
-
});
|
|
163
|
-
if (this.#settingImprovements.has(request.improvementId))
|
|
164
|
-
throw new Error("Setting-improvement ID already exists");
|
|
165
|
-
this.#settingImprovements.set(request.improvementId, {
|
|
166
|
-
packageId: request.packageId,
|
|
167
|
-
improvement,
|
|
168
|
-
});
|
|
269
|
+
case "setting-improvement.preview":
|
|
270
|
+
return this.#settingImprovements.preview(request.packageId, request.sessionId);
|
|
271
|
+
case "setting-improvement.read":
|
|
272
|
+
return this.#settingImprovements.read(request.packageId);
|
|
273
|
+
case "setting-improvement.status":
|
|
274
|
+
return this.#settingImprovements.status(request.packageId, request.sessionId);
|
|
275
|
+
case "setting-improvement.overview":
|
|
276
|
+
return this.#settingImprovements.overview(request.packageId);
|
|
277
|
+
case "setting-improvement.session.read":
|
|
278
|
+
return this.#settingImprovements.readSession(request.packageId, request.sessionId);
|
|
279
|
+
case "setting-improvement.session.delete":
|
|
280
|
+
return this.#settingImprovements.deleteSession(request.packageId, request.sessionId);
|
|
281
|
+
case "setting-improvement.rollback":
|
|
169
282
|
try {
|
|
170
|
-
return await
|
|
171
|
-
goal: request.goal,
|
|
172
|
-
contextPaths: request.contextPaths,
|
|
173
|
-
mode: request.mode,
|
|
174
|
-
});
|
|
283
|
+
return await this.#settingImprovements.rollback(request);
|
|
175
284
|
}
|
|
176
285
|
catch (error) {
|
|
177
|
-
|
|
286
|
+
if (error instanceof SettingImprovementRollbackError)
|
|
287
|
+
throw new V1ProtocolError("invalid_request", error.message, {
|
|
288
|
+
cause: error,
|
|
289
|
+
});
|
|
178
290
|
throw error;
|
|
179
291
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
// yield the event loop, so this read observes the run in flight.
|
|
185
|
-
case "setting-improvement.progress":
|
|
186
|
-
return this.#settingImprovement(request.improvementId).improvement.progress();
|
|
187
|
-
case "setting-improvement.revise-plan":
|
|
188
|
-
return this.#settingImprovement(request.improvementId).improvement.revisePlan(request.feedback);
|
|
189
|
-
case "setting-improvement.revise-candidate":
|
|
190
|
-
return this.#settingImprovement(request.improvementId).improvement.reviseCandidate(request.feedback);
|
|
191
|
-
case "setting-improvement.apply": {
|
|
192
|
-
const active = this.#settingImprovement(request.improvementId);
|
|
193
|
-
await active.improvement.apply(async (files) => {
|
|
194
|
-
await this.#content.replaceCurrentTreeContentPackage(active.packageId, files);
|
|
195
|
-
});
|
|
196
|
-
this.#settingImprovements.delete(request.improvementId);
|
|
197
|
-
return { applied: true };
|
|
198
|
-
}
|
|
199
|
-
case "setting-improvement.discard":
|
|
200
|
-
this.#settingImprovement(request.improvementId).improvement.discard();
|
|
201
|
-
this.#settingImprovements.delete(request.improvementId);
|
|
202
|
-
return { discarded: true };
|
|
292
|
+
case "setting-improvement.message":
|
|
293
|
+
return this.#settingImprovements.send(request);
|
|
294
|
+
case "setting-improvement.cancel":
|
|
295
|
+
return this.#settingImprovements.cancel(request.sessionId);
|
|
203
296
|
case "play.read":
|
|
204
297
|
return this.#playPresets.list();
|
|
205
298
|
case "play.create":
|
|
@@ -228,7 +321,11 @@ export class V1Runtime {
|
|
|
228
321
|
const binding = request.presetId === undefined
|
|
229
322
|
? await this.#playPresets.bindCurrent()
|
|
230
323
|
: await this.#playPresets.bindRevision(request.presetId, request.revision);
|
|
231
|
-
|
|
324
|
+
if (request.worldId === undefined)
|
|
325
|
+
return buildPlayPresetWorkbenchSnapshot(binding, undefined, request.draft);
|
|
326
|
+
const head = await this.#worlds.currentHead(request.worldId);
|
|
327
|
+
const playerViews = await this.#worlds.renderPlayerViewsAtHead(request.worldId, head);
|
|
328
|
+
return buildPlayPresetWorkbenchSnapshot(binding, { worldId: request.worldId, head, playerViews }, request.draft);
|
|
232
329
|
}
|
|
233
330
|
case "prompt.preview": {
|
|
234
331
|
const [package_, connection, playPreset] = await Promise.all([
|
|
@@ -266,6 +363,9 @@ export class V1Runtime {
|
|
|
266
363
|
appended: preview.initialAppend === undefined
|
|
267
364
|
? []
|
|
268
365
|
: [
|
|
366
|
+
...(preview.initialAppend.beforePlayer === undefined
|
|
367
|
+
? []
|
|
368
|
+
: [preview.initialAppend.beforePlayer.logical]),
|
|
269
369
|
{
|
|
270
370
|
kind: "player",
|
|
271
371
|
text: preview.initialAppend.logical.text,
|
|
@@ -288,6 +388,8 @@ export class V1Runtime {
|
|
|
288
388
|
return this.#worlds.createFromContentPackage({
|
|
289
389
|
operationId: request.operationId,
|
|
290
390
|
sourcePackageId: request.packageId,
|
|
391
|
+
sourcePackageTitle: package_.title,
|
|
392
|
+
packageScriptGrants: await this.#content.readPackageScriptGrants(request.packageId),
|
|
291
393
|
packageFiles: package_.files,
|
|
292
394
|
prompt: {
|
|
293
395
|
hostBinding: presetHostBinding(preset),
|
|
@@ -301,15 +403,18 @@ export class V1Runtime {
|
|
|
301
403
|
return this.#worlds.renameWorld(request.worldId, request.name);
|
|
302
404
|
case "world.delete":
|
|
303
405
|
return playCall(async () => {
|
|
406
|
+
await this.#worlds.assertWorldRevisionUnlocked(request.worldId);
|
|
304
407
|
this.#playCallChains.forgetWorld(request.worldId);
|
|
305
408
|
return this.#worlds.deleteWorld(request.worldId);
|
|
306
409
|
});
|
|
307
410
|
case "world.read": {
|
|
308
411
|
const head = await this.#worlds.currentHead(request.worldId);
|
|
309
412
|
const playerViews = await this.#worlds.renderPlayerViewsAtHead(request.worldId, head);
|
|
310
|
-
const
|
|
311
|
-
|
|
413
|
+
const extensionControls = await this.#currentExtensionControls(request.worldId);
|
|
414
|
+
const [playerViewPanels, playTimeline, revisionEpoch] = await Promise.all([
|
|
415
|
+
this.#frontendPlayerViewPanels(request.worldId, head, playerViews, extensionControls),
|
|
312
416
|
this.#worlds.playTimeline.readPage(request.worldId, 40),
|
|
417
|
+
this.#worldRevisions.activeEpoch(request.worldId),
|
|
313
418
|
]);
|
|
314
419
|
return {
|
|
315
420
|
worldId: request.worldId,
|
|
@@ -323,27 +428,54 @@ export class V1Runtime {
|
|
|
323
428
|
artifacts: [],
|
|
324
429
|
extensions: [],
|
|
325
430
|
playerViewPanels,
|
|
431
|
+
extensionControls,
|
|
432
|
+
suppressedPlayerViewIds: await this.#suppressedPlayerViewIds(extensionControls),
|
|
326
433
|
artifactDebug: [],
|
|
327
434
|
playCallChain: null,
|
|
328
435
|
playTimeline,
|
|
436
|
+
worldRevision: revisionEpoch,
|
|
329
437
|
};
|
|
330
438
|
}
|
|
331
439
|
case "world.surface.read":
|
|
332
440
|
return request.surface === "runtime"
|
|
333
441
|
? this.#worlds.readSurface(request.worldId, "runtime")
|
|
334
442
|
: this.#worlds.readSurface(request.worldId, request.surface);
|
|
443
|
+
case "world.extensions.read":
|
|
444
|
+
return this.#worlds.extensionControls(request.worldId, await this.#playPresets.bindCurrent(), this.#locale);
|
|
445
|
+
case "world.extensions.set": {
|
|
446
|
+
const result = await this.#worlds.extensionControls(request.worldId, await this.#playPresets.bindCurrent(), this.#locale, request);
|
|
447
|
+
return result;
|
|
448
|
+
}
|
|
335
449
|
case "world.play-decorations.read": {
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
this.#
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
450
|
+
for (;;) {
|
|
451
|
+
const extensionControls = await this.#currentExtensionControls(request.worldId);
|
|
452
|
+
const head = await this.#reconcileArtifacts(request.worldId);
|
|
453
|
+
const [projection, artifactDebug] = await Promise.all([
|
|
454
|
+
this.#frontendDecorations(request.worldId),
|
|
455
|
+
this.#frontendDebug(request.worldId),
|
|
456
|
+
]);
|
|
457
|
+
const playerViews = await this.#worlds.renderPlayerViewsAtHead(request.worldId, head);
|
|
458
|
+
const playerViewPanels = await this.#frontendPlayerViewPanels(request.worldId, head, playerViews, extensionControls);
|
|
459
|
+
const suppressedPlayerViewIds = await this.#suppressedPlayerViewIds(extensionControls);
|
|
460
|
+
// Never attach a newer controls revision to a projection read before
|
|
461
|
+
// that choice was accepted. Concurrent toggles restart this read.
|
|
462
|
+
if ((await this.#worlds.extensionControlsRevision(request.worldId)) !==
|
|
463
|
+
extensionControls.revision)
|
|
464
|
+
continue;
|
|
465
|
+
return {
|
|
466
|
+
head,
|
|
467
|
+
...projection,
|
|
468
|
+
artifactDebug,
|
|
469
|
+
playerViews,
|
|
470
|
+
playerViewPanels,
|
|
471
|
+
extensionControls,
|
|
472
|
+
suppressedPlayerViewIds,
|
|
473
|
+
};
|
|
474
|
+
}
|
|
343
475
|
}
|
|
344
476
|
case "artifacts.read":
|
|
345
477
|
await this.#reconcileArtifacts(request.worldId);
|
|
346
|
-
return this.#
|
|
478
|
+
return (await this.#frontendDecorations(request.worldId, request.channel)).artifacts;
|
|
347
479
|
case "artifacts.debug":
|
|
348
480
|
await this.#reconcileArtifacts(request.worldId);
|
|
349
481
|
return this.#frontendDebug(request.worldId, request.operationId);
|
|
@@ -353,6 +485,7 @@ export class V1Runtime {
|
|
|
353
485
|
return result;
|
|
354
486
|
}
|
|
355
487
|
case "world.control-draft.save":
|
|
488
|
+
await this.#worlds.assertWorldRevisionUnlocked(request.worldId);
|
|
356
489
|
return this.#worlds.saveControlDraft(request.worldId, request.files);
|
|
357
490
|
case "world.control-draft.preview": {
|
|
358
491
|
const prompt = {
|
|
@@ -372,6 +505,33 @@ export class V1Runtime {
|
|
|
372
505
|
};
|
|
373
506
|
return this.#worlds.applyControlDraft(request.worldId, prompt);
|
|
374
507
|
}
|
|
508
|
+
case "world.revision.open":
|
|
509
|
+
return this.#worldRevisionCall(() => this.#worldRevisions.open(request.worldId));
|
|
510
|
+
case "world.revision.overview":
|
|
511
|
+
return this.#worldRevisionCall(() => this.#worldRevisions.overview(request.worldId));
|
|
512
|
+
case "world.revision.preview":
|
|
513
|
+
return this.#worldRevisions.preview(request.worldId, request.sessionId);
|
|
514
|
+
case "world.revision.status":
|
|
515
|
+
return this.#worldRevisionCall(() => this.#worldRevisions.status(request.worldId, request.sessionId));
|
|
516
|
+
case "world.revision.session.read":
|
|
517
|
+
return this.#worldRevisionCall(() => this.#worldRevisions.readSession(request.worldId, request.sessionId));
|
|
518
|
+
case "world.revision.session.delete":
|
|
519
|
+
return this.#worldRevisionCall(() => this.#worldRevisions.deleteSession(request.worldId, request.sessionId));
|
|
520
|
+
case "world.revision.message":
|
|
521
|
+
return this.#worldRevisionCall(() => this.#worldRevisions.send(request));
|
|
522
|
+
case "world.revision.cancel":
|
|
523
|
+
return this.#worldRevisionCall(() => this.#worldRevisions.cancel(request.sessionId));
|
|
524
|
+
case "world.revision.files.replace":
|
|
525
|
+
return this.#worldRevisionCall(() => this.#worldRevisions.replaceFiles(request));
|
|
526
|
+
case "world.revision.rollback":
|
|
527
|
+
return this.#worldRevisionCall(() => this.#worldRevisions.rollback(request));
|
|
528
|
+
case "world.revision.apply": {
|
|
529
|
+
const result = await this.#worldRevisionCall(() => this.#worldRevisions.apply(request));
|
|
530
|
+
await this.#reconcileArtifacts(request.worldId);
|
|
531
|
+
return result;
|
|
532
|
+
}
|
|
533
|
+
case "world.revision.discard":
|
|
534
|
+
return this.#worldRevisionCall(() => this.#worldRevisions.discard(request));
|
|
375
535
|
case "world.derive": {
|
|
376
536
|
const preset = await this.#playPresets.bindCurrent();
|
|
377
537
|
const result = await this.#playCallChains.deriveWorld({
|
|
@@ -384,18 +544,33 @@ export class V1Runtime {
|
|
|
384
544
|
return result;
|
|
385
545
|
}
|
|
386
546
|
case "play.chain.revise-player": {
|
|
387
|
-
const
|
|
547
|
+
const base = {
|
|
388
548
|
operationId: request.operationId,
|
|
389
549
|
worldId: request.worldId,
|
|
390
550
|
chainId: request.chainId,
|
|
391
551
|
eventId: request.eventId,
|
|
392
552
|
replacementExchangeId: request.replacementExchangeId,
|
|
393
553
|
replacementText: request.replacementText,
|
|
394
|
-
}
|
|
554
|
+
};
|
|
555
|
+
const result = await playCall(async () => {
|
|
556
|
+
await this.#worlds.assertWorldRevisionUnlocked(request.worldId);
|
|
557
|
+
if (request.continuation === "continue_context")
|
|
558
|
+
return this.#playCallChains.revisePlayer({
|
|
559
|
+
...base,
|
|
560
|
+
continuation: request.continuation,
|
|
561
|
+
});
|
|
562
|
+
const { hostBinding, playPreset, modelBinding } = await this.#continuousBinding();
|
|
563
|
+
return this.#playCallChains.revisePlayer({
|
|
564
|
+
...base,
|
|
565
|
+
continuation: request.continuation,
|
|
566
|
+
freshContext: { hostBinding, playPreset, modelBinding },
|
|
567
|
+
});
|
|
568
|
+
});
|
|
395
569
|
await this.#reconcileArtifacts(request.worldId);
|
|
396
570
|
return result;
|
|
397
571
|
}
|
|
398
572
|
case "play.chain.start": {
|
|
573
|
+
await this.#worlds.assertWorldRevisionUnlocked(request.worldId);
|
|
399
574
|
const { modelHost, hostBinding, playPreset, modelBinding } = await this.#continuousBinding();
|
|
400
575
|
return playCall(() => this.#playCallChains.start({
|
|
401
576
|
worldId: request.worldId,
|
|
@@ -412,16 +587,20 @@ export class V1Runtime {
|
|
|
412
587
|
}));
|
|
413
588
|
}
|
|
414
589
|
case "play.chain.append":
|
|
415
|
-
return playCall(async () =>
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
:
|
|
424
|
-
|
|
590
|
+
return playCall(async () => {
|
|
591
|
+
await this.#worlds.assertWorldRevisionUnlocked(request.worldId);
|
|
592
|
+
return this.#playCallChains.append({
|
|
593
|
+
worldId: request.worldId,
|
|
594
|
+
chainId: request.chainId,
|
|
595
|
+
exchangeId: request.exchangeId,
|
|
596
|
+
playerText: request.playerText,
|
|
597
|
+
modelHost: await this.#modelHost(),
|
|
598
|
+
resolvePrompt: () => this.#continuousBinding(),
|
|
599
|
+
...(playCallChainObserver === undefined
|
|
600
|
+
? {}
|
|
601
|
+
: { observer: playCallChainObserver }),
|
|
602
|
+
});
|
|
603
|
+
});
|
|
425
604
|
case "play.chain.cancel":
|
|
426
605
|
return playCall(() => this.#playCallChains.cancel({
|
|
427
606
|
worldId: request.worldId,
|
|
@@ -436,6 +615,88 @@ export class V1Runtime {
|
|
|
436
615
|
case "play.timeline.detail":
|
|
437
616
|
await this.#worlds.ensureCurrentStorage(request.worldId);
|
|
438
617
|
return this.#worlds.playTimeline.readDetail(request.worldId, request.chainId, request.eventId);
|
|
618
|
+
case "world.play-context.read": {
|
|
619
|
+
const binding = await this.#worlds.bindPlayCallChain(request.worldId);
|
|
620
|
+
const currentContext = await this.#playCallChains.inspectReading(request.worldId, binding.parentHead);
|
|
621
|
+
const model = await this.#models.view();
|
|
622
|
+
if (!model.configured)
|
|
623
|
+
return {
|
|
624
|
+
worldId: request.worldId,
|
|
625
|
+
worldHead: binding.parentHead,
|
|
626
|
+
currentContext,
|
|
627
|
+
nextFreshContext: null,
|
|
628
|
+
};
|
|
629
|
+
const { modelHost, hostBinding, playPreset, modelBinding } = await this.#continuousBinding();
|
|
630
|
+
const persisted = currentContext === null
|
|
631
|
+
? null
|
|
632
|
+
: await this.#worlds.playTimeline.readCurrent(request.worldId);
|
|
633
|
+
const frozenBinding = persisted?.value.modelBinding;
|
|
634
|
+
const continueContext = currentContext !== null &&
|
|
635
|
+
!currentContext.stale &&
|
|
636
|
+
frozenBinding !== undefined &&
|
|
637
|
+
equalModelHostBinding(frozenBinding, modelBinding);
|
|
638
|
+
const baseline = continueContext
|
|
639
|
+
? await this.#worlds.bindPlayCallChainAt(request.worldId, currentContext.baselineHead)
|
|
640
|
+
: binding;
|
|
641
|
+
const preview = this.#compiler.preview({
|
|
642
|
+
extensionControls: await this.#worlds.extensionControls(request.worldId, playPreset, this.#locale),
|
|
643
|
+
endpoint: {
|
|
644
|
+
id: `${request.worldId}:${binding.parentHead}`,
|
|
645
|
+
commit: binding.parentHead,
|
|
646
|
+
},
|
|
647
|
+
hostBinding,
|
|
648
|
+
world: {
|
|
649
|
+
controlFingerprint: fingerprintControl(binding.files),
|
|
650
|
+
documentSnapshot: WorldDocumentStore.open({
|
|
651
|
+
layout: "world_state",
|
|
652
|
+
files: Object.entries(binding.files).map(([path, contents]) => ({ path, contents })),
|
|
653
|
+
}),
|
|
654
|
+
additionalMaterials: structuredClone(binding.additionalMaterials),
|
|
655
|
+
history: structuredClone(binding.history),
|
|
656
|
+
narrativeCheckpoint: baseline.narrativeCheckpoint,
|
|
657
|
+
historyAlreadyAppended: Object.keys(binding.history).filter((key) => !(key in baseline.history)),
|
|
658
|
+
...(await this.#worlds.inspectDocumentMaintenance(request.worldId, binding.parentHead)),
|
|
659
|
+
},
|
|
660
|
+
playerInputPlacement: "append",
|
|
661
|
+
playerInput: "",
|
|
662
|
+
modelBinding,
|
|
663
|
+
}, playPreset);
|
|
664
|
+
const tools = preview.compilation.toolUniverse;
|
|
665
|
+
const nextEncoding = modelHost.previewRequest({
|
|
666
|
+
bootstrap: preview.compilation,
|
|
667
|
+
tools,
|
|
668
|
+
toolUniverse: tools,
|
|
669
|
+
allowedTools: tools.map(({ name }) => name),
|
|
670
|
+
toolStrategy: preview.compilation.toolStrategy,
|
|
671
|
+
appended: continueContext ? (persisted?.value.transcript ?? []) : [],
|
|
672
|
+
operationId: continueContext
|
|
673
|
+
? currentContext.chainId
|
|
674
|
+
: "next-fresh-context-preview",
|
|
675
|
+
maxOutputTokens: modelBinding.maxOutputTokens,
|
|
676
|
+
});
|
|
677
|
+
const currentEncoding = currentContext === null
|
|
678
|
+
? null
|
|
679
|
+
: await this.#worlds.playTimeline
|
|
680
|
+
.readInitialEncoding(request.worldId, currentContext.chainId, currentContext.requestExchange)
|
|
681
|
+
.catch(() => null);
|
|
682
|
+
const prefixDiagnostics = comparePromptPrefixes(currentContext === null
|
|
683
|
+
? null
|
|
684
|
+
: {
|
|
685
|
+
bootstrap: currentContext.bootstrap,
|
|
686
|
+
encoding: currentEncoding,
|
|
687
|
+
}, { bootstrap: preview.compilation, encoding: nextEncoding });
|
|
688
|
+
return {
|
|
689
|
+
worldId: request.worldId,
|
|
690
|
+
worldHead: binding.parentHead,
|
|
691
|
+
currentContext,
|
|
692
|
+
nextFreshContext: {
|
|
693
|
+
contextMode: continueContext ? "append" : "fresh",
|
|
694
|
+
head: binding.parentHead,
|
|
695
|
+
preview,
|
|
696
|
+
prefixDiagnostics,
|
|
697
|
+
},
|
|
698
|
+
};
|
|
699
|
+
}
|
|
439
700
|
case "correction.begin":
|
|
440
701
|
return this.#corrections.begin({
|
|
441
702
|
worldId: request.worldId,
|
|
@@ -448,12 +709,14 @@ export class V1Runtime {
|
|
|
448
709
|
return this.#corrections.patchDocument(request);
|
|
449
710
|
case "correction.replace":
|
|
450
711
|
return this.#corrections.replaceDocument(request);
|
|
451
|
-
case "correction.preview":
|
|
712
|
+
case "correction.preview": {
|
|
713
|
+
const { hostBinding, modelBinding, playPreset } = await this.#continuousBinding();
|
|
452
714
|
return this.#corrections.preview({
|
|
453
715
|
candidateId: request.candidateId,
|
|
454
716
|
expectedVersion: request.expectedVersion,
|
|
455
|
-
prompt:
|
|
717
|
+
prompt: { hostBinding, modelBinding, playPreset },
|
|
456
718
|
});
|
|
719
|
+
}
|
|
457
720
|
case "correction.apply": {
|
|
458
721
|
const result = await this.#corrections.apply(request);
|
|
459
722
|
await this.#reconcileResultArtifacts(result);
|
|
@@ -467,6 +730,21 @@ export class V1Runtime {
|
|
|
467
730
|
async #modelHost() {
|
|
468
731
|
return new FileNativeModelHost(await this.#models.bind(), fetch, this.#failureLog);
|
|
469
732
|
}
|
|
733
|
+
async #worldRevisionCall(operation) {
|
|
734
|
+
try {
|
|
735
|
+
return await operation();
|
|
736
|
+
}
|
|
737
|
+
catch (error) {
|
|
738
|
+
if (error instanceof WorldRevisionWorkspaceError)
|
|
739
|
+
throw new V1ProtocolError("invalid_request", error.message, {
|
|
740
|
+
cause: error,
|
|
741
|
+
});
|
|
742
|
+
throw error;
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
async #matchingModelHost(binding) {
|
|
746
|
+
return new FileNativeModelHost(await this.#models.bindMatching(binding), fetch, this.#failureLog);
|
|
747
|
+
}
|
|
470
748
|
async #reconcileArtifacts(worldId) {
|
|
471
749
|
const [head, currentOperationId] = await Promise.all([
|
|
472
750
|
this.#worlds.currentHead(worldId),
|
|
@@ -475,19 +753,71 @@ export class V1Runtime {
|
|
|
475
753
|
await this.#artifacts.reconcileHead(worldId, head, currentOperationId ?? undefined);
|
|
476
754
|
return head;
|
|
477
755
|
}
|
|
478
|
-
async #
|
|
479
|
-
|
|
480
|
-
|
|
756
|
+
async #frontendDecorations(worldId, channel) {
|
|
757
|
+
await this.#currentExtensionControls(worldId);
|
|
758
|
+
const summaries = await this.#artifacts.readExtensionSummaries(worldId);
|
|
759
|
+
const targets = await this.#worlds.playTimeline.resolveReplies(worldId, summaries.flatMap((item) => item.attachment === undefined ? [] : [item.attachment]));
|
|
760
|
+
const matches = (attachment) => targets.find((target) => target.contextId === attachment.contextId &&
|
|
761
|
+
target.eventId === attachment.eventId &&
|
|
762
|
+
target.head === attachment.head);
|
|
763
|
+
const extensions = summaries
|
|
764
|
+
.filter((item) => item.attachment === undefined ||
|
|
765
|
+
matches(item.attachment) !== undefined)
|
|
766
|
+
.sort((left, right) => Number(left.head?.replace("commit:", "") ?? 0) -
|
|
767
|
+
Number(right.head?.replace("commit:", "") ?? 0));
|
|
768
|
+
const artifacts = await this.#artifacts.readActiveProjection(worldId, channel, targets);
|
|
769
|
+
const projected = (await Promise.all(artifacts.map(async (artifact) => {
|
|
481
770
|
const { renderer, ...safeArtifact } = artifact;
|
|
482
771
|
void renderer;
|
|
483
772
|
const resolved = await this.#frontendBinding(artifact.playPresetId, artifact.playPresetRevision);
|
|
484
773
|
return {
|
|
485
774
|
...safeArtifact,
|
|
486
|
-
|
|
775
|
+
...(artifact.attachment === undefined
|
|
776
|
+
? {}
|
|
777
|
+
: {
|
|
778
|
+
reply: matches(artifact.attachment),
|
|
779
|
+
}),
|
|
780
|
+
frontend: projectArtifactForFrontend(artifact, resolved.binding, resolved.failure, artifact.requestId.startsWith("package:") &&
|
|
781
|
+
artifact.frozenPresentation !== undefined &&
|
|
782
|
+
(await this.#worlds.readPackageScriptGrants(worldId)).includes(PackageScriptPermissions.fingerprint(artifact.frozenPresentation.files))),
|
|
487
783
|
};
|
|
488
|
-
}));
|
|
784
|
+
}))).filter((artifact) => artifact.frontend.mount !== "story" || artifact.reply !== undefined);
|
|
785
|
+
return { artifacts: projected, extensions };
|
|
786
|
+
}
|
|
787
|
+
async #currentExtensionControls(worldId) {
|
|
788
|
+
try {
|
|
789
|
+
return await this.#worlds.extensionControls(worldId, await this.#playPresets.bindCurrent(), this.#locale);
|
|
790
|
+
}
|
|
791
|
+
catch (error) {
|
|
792
|
+
if (!(error instanceof FileNativePlayPresetError))
|
|
793
|
+
throw error;
|
|
794
|
+
return {
|
|
795
|
+
revision: await this.#worlds.extensionControlsRevision(worldId),
|
|
796
|
+
items: [],
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
async #suppressedPlayerViewIds(controls) {
|
|
801
|
+
let binding;
|
|
802
|
+
try {
|
|
803
|
+
binding = await this.#playPresets.bindCurrent();
|
|
804
|
+
}
|
|
805
|
+
catch (error) {
|
|
806
|
+
if (error instanceof FileNativePlayPresetError)
|
|
807
|
+
return [];
|
|
808
|
+
throw error;
|
|
809
|
+
}
|
|
810
|
+
// Every declared panel owns its view's fallback even while hidden.
|
|
811
|
+
return [
|
|
812
|
+
...new Set([
|
|
813
|
+
...binding.definition.playerViewPanels.map((panel) => panel.source.view),
|
|
814
|
+
...controls.items
|
|
815
|
+
.filter((item) => item.kind === "view" && !item.enabled)
|
|
816
|
+
.map((item) => item.id),
|
|
817
|
+
]),
|
|
818
|
+
];
|
|
489
819
|
}
|
|
490
|
-
async #frontendPlayerViewPanels(worldId, head, playerViews) {
|
|
820
|
+
async #frontendPlayerViewPanels(worldId, head, playerViews, controls) {
|
|
491
821
|
try {
|
|
492
822
|
const binding = await this.#playPresets.bindCurrent();
|
|
493
823
|
return projectPlayerViewPanels({
|
|
@@ -495,7 +825,7 @@ export class V1Runtime {
|
|
|
495
825
|
head,
|
|
496
826
|
playerViews,
|
|
497
827
|
binding,
|
|
498
|
-
});
|
|
828
|
+
}).filter((panel) => controls.items.some((item) => item.kind === "panel" && item.id === panel.panelId && item.enabled));
|
|
499
829
|
}
|
|
500
830
|
catch (error) {
|
|
501
831
|
// Panels are decoration on top of a world read. Any unusable preset —
|
|
@@ -514,7 +844,9 @@ export class V1Runtime {
|
|
|
514
844
|
const resolved = await this.#frontendBinding(record.playPresetId, record.playPresetRevision);
|
|
515
845
|
return {
|
|
516
846
|
...safeRecord,
|
|
517
|
-
frontend: projectDebugArtifactForFrontend(record, resolved.binding, resolved.failure)
|
|
847
|
+
frontend: projectDebugArtifactForFrontend(record, resolved.binding, resolved.failure, record.requestId.startsWith("package:") &&
|
|
848
|
+
record.frozenPresentation !== undefined &&
|
|
849
|
+
(await this.#worlds.readPackageScriptGrants(worldId)).includes(PackageScriptPermissions.fingerprint(record.frozenPresentation.files))),
|
|
518
850
|
};
|
|
519
851
|
}));
|
|
520
852
|
}
|
|
@@ -554,12 +886,6 @@ export class V1Runtime {
|
|
|
554
886
|
return;
|
|
555
887
|
await this.#reconcileArtifacts(worldId);
|
|
556
888
|
}
|
|
557
|
-
#settingImprovement(improvementId) {
|
|
558
|
-
const active = this.#settingImprovements.get(improvementId);
|
|
559
|
-
if (active === undefined)
|
|
560
|
-
throw new Error("Setting-improvement session does not exist");
|
|
561
|
-
return active;
|
|
562
|
-
}
|
|
563
889
|
async #promptBinding() {
|
|
564
890
|
const [preset, connection] = await Promise.all([
|
|
565
891
|
this.#playPresets.bindCurrent(),
|