@momoyu-ink/kit 0.5.4 → 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.
- package/dist/{jsx-dev-runtime-BKsP0hXU.d.mts → jsx-dev-runtime-B5T-ZMWr.d.mts} +16 -0
- package/dist/{jsx-dev-runtime-BKsP0hXU.d.ts → jsx-dev-runtime-B5T-ZMWr.d.ts} +16 -0
- package/dist/jsx-dev-runtime.d.mts +1 -1
- package/dist/jsx-dev-runtime.d.ts +1 -1
- package/dist/jsx-runtime.d.mts +1 -1
- package/dist/jsx-runtime.d.ts +1 -1
- package/dist/lib.cjs +861 -48
- package/dist/lib.d.mts +149 -50
- package/dist/lib.d.ts +149 -50
- package/dist/lib.mjs +852 -28
- package/package.json +1 -1
package/dist/lib.mjs
CHANGED
|
@@ -33,23 +33,33 @@ __export(lib_exports, {
|
|
|
33
33
|
createStaticNavigation: () => createStaticNavigation,
|
|
34
34
|
executeNodeCommand: () => executeNodeCommand,
|
|
35
35
|
executePluginCommand: () => executePluginCommand,
|
|
36
|
+
fastForwardState: () => fastForwardState,
|
|
37
|
+
getAppStateAdapter: () => getAppStateAdapter,
|
|
36
38
|
getNavigator: () => getNavigator,
|
|
39
|
+
getSeekingType: () => getSeekingType,
|
|
37
40
|
getStageSize: () => getStageSize,
|
|
38
41
|
globalEventListeners: () => globalEventListeners,
|
|
39
42
|
globalRequestAnimationFrameListeners: () => globalRequestAnimationFrameListeners,
|
|
40
43
|
moyu: () => moyu_exports,
|
|
41
44
|
nextLine: () => nextLine,
|
|
45
|
+
registerAppStateAdapter: () => registerAppStateAdapter,
|
|
42
46
|
setDefaultAutoTailMs: () => setDefaultAutoTailMs,
|
|
43
47
|
setWaiting: () => setWaiting,
|
|
44
48
|
skipState: () => skipState,
|
|
49
|
+
startDebugSession: () => startDebugSession,
|
|
50
|
+
startRuntimeDebugSession: () => startRuntimeDebugSession,
|
|
51
|
+
stopDebugSession: () => stopDebugSession,
|
|
52
|
+
stopRuntimeDebugSession: () => stopRuntimeDebugSession,
|
|
45
53
|
useAutoBlocker: () => useAutoBlocker,
|
|
46
54
|
useAutoTicket: () => useAutoTicket,
|
|
47
55
|
useBeforeHandleCommandCallback: () => useBeforeHandleCommandCallback,
|
|
56
|
+
useDebugSession: () => useDebugSession,
|
|
48
57
|
useFadeIn: () => useFadeIn,
|
|
49
58
|
useFadeInOut: () => useFadeInOut,
|
|
50
59
|
useFadeOut: () => useFadeOut,
|
|
51
60
|
useInterruptCallback: () => useInterruptCallback,
|
|
52
61
|
useIsAutoing: () => useIsAutoing,
|
|
62
|
+
useIsSeeking: () => useIsSeeking,
|
|
53
63
|
useIsSkipping: () => useIsSkipping,
|
|
54
64
|
useNavigation: () => useNavigation,
|
|
55
65
|
useNavigationParams: () => useNavigationParams,
|
|
@@ -58,7 +68,8 @@ __export(lib_exports, {
|
|
|
58
68
|
useSkipBlocker: () => useSkipBlocker,
|
|
59
69
|
useSkipCallback: () => useSkipCallback,
|
|
60
70
|
useSoundEffect: () => useSoundEffect,
|
|
61
|
-
useStageContext: () => useStageContext
|
|
71
|
+
useStageContext: () => useStageContext,
|
|
72
|
+
warpState: () => warpState
|
|
62
73
|
});
|
|
63
74
|
|
|
64
75
|
// src/react.ts
|
|
@@ -199,7 +210,8 @@ var hostConfig = {
|
|
|
199
210
|
* @required
|
|
200
211
|
*/
|
|
201
212
|
createInstance(type, props, _root, _hostContext, _internalInstanceHandle) {
|
|
202
|
-
const
|
|
213
|
+
const { ref, ...restProps } = props;
|
|
214
|
+
const node = Node.create(props.label ?? "", type, restProps);
|
|
203
215
|
return node;
|
|
204
216
|
},
|
|
205
217
|
/**
|
|
@@ -269,7 +281,7 @@ var hostConfig = {
|
|
|
269
281
|
},
|
|
270
282
|
commitUpdate(instance, _type, prevProps, nextProps, _internalHandle) {
|
|
271
283
|
const { label: _oldLabel, children: _oldChildren, ...oldProps } = prevProps;
|
|
272
|
-
const { label, children, ...newProps } = nextProps;
|
|
284
|
+
const { label, children, ref, ...newProps } = nextProps;
|
|
273
285
|
const changedProps = {};
|
|
274
286
|
for (const key in newProps) {
|
|
275
287
|
if (newProps[key] !== oldProps[key]) {
|
|
@@ -436,7 +448,7 @@ var globalVariables = new Proxy(
|
|
|
436
448
|
}
|
|
437
449
|
);
|
|
438
450
|
function safeEval(code, sandbox) {
|
|
439
|
-
const
|
|
451
|
+
const proxy4 = new Proxy(sandbox, {
|
|
440
452
|
has(target, key) {
|
|
441
453
|
if (typeof key === "string" && JS_GLOBAL_KEYS.has(key)) {
|
|
442
454
|
return false;
|
|
@@ -444,7 +456,7 @@ function safeEval(code, sandbox) {
|
|
|
444
456
|
return key in target || key === "ARCHIVE" || key === "GLOBAL" || key === "window" || key === "globalThis";
|
|
445
457
|
},
|
|
446
458
|
get(target, key) {
|
|
447
|
-
if (key === "window" || key === "globalThis") return
|
|
459
|
+
if (key === "window" || key === "globalThis") return proxy4;
|
|
448
460
|
if (key === "ARCHIVE") return archiveVariables;
|
|
449
461
|
if (key === "GLOBAL") return globalVariables;
|
|
450
462
|
if (key === Symbol.unscopables) return void 0;
|
|
@@ -455,7 +467,7 @@ function safeEval(code, sandbox) {
|
|
|
455
467
|
return true;
|
|
456
468
|
}
|
|
457
469
|
});
|
|
458
|
-
return new Function("sandbox", `with(sandbox) { return (${code}) }`).bind(
|
|
470
|
+
return new Function("sandbox", `with(sandbox) { return (${code}) }`).bind(proxy4)(proxy4);
|
|
459
471
|
}
|
|
460
472
|
globalThis.__moyu_eval_sandbox = (code) => {
|
|
461
473
|
try {
|
|
@@ -638,9 +650,9 @@ function getStageSize() {
|
|
|
638
650
|
}
|
|
639
651
|
|
|
640
652
|
// src/components/navigation.tsx
|
|
641
|
-
import React2 from "react";
|
|
642
653
|
import { createContext, useContext } from "react";
|
|
643
654
|
import { proxy, useSnapshot } from "valtio";
|
|
655
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
644
656
|
var PageParamsContext = createContext(void 0);
|
|
645
657
|
var OverlayParamsContext = createContext(void 0);
|
|
646
658
|
var overlayIdCounter = 0;
|
|
@@ -696,6 +708,9 @@ function createStackNavigator(options) {
|
|
|
696
708
|
delete navigationState.pageParams[page];
|
|
697
709
|
}
|
|
698
710
|
},
|
|
711
|
+
hasPage: (page) => {
|
|
712
|
+
return normalizedPages[page] !== void 0;
|
|
713
|
+
},
|
|
699
714
|
goBack: () => {
|
|
700
715
|
console.warn("goBack() not implemented yet");
|
|
701
716
|
},
|
|
@@ -751,11 +766,14 @@ function createStaticNavigation(navigator) {
|
|
|
751
766
|
const { pages, overlays } = navigator._descriptors;
|
|
752
767
|
const pageDescriptor = pages[navState.currentPage];
|
|
753
768
|
const Page = pageDescriptor?.component || (() => null);
|
|
754
|
-
return /* @__PURE__ */
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
769
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
770
|
+
/* @__PURE__ */ jsx(PageParamsContext.Provider, { value: navState.pageParams[navState.currentPage], children: /* @__PURE__ */ jsx(Page, {}) }),
|
|
771
|
+
navState.overlayStack.map((overlay) => {
|
|
772
|
+
const overlayDescriptor = overlays[overlay.type];
|
|
773
|
+
const OverlayComponent = overlayDescriptor?.component || (() => null);
|
|
774
|
+
return /* @__PURE__ */ jsx(OverlayParamsContext.Provider, { value: navState.overlayParams[overlay.id], children: /* @__PURE__ */ jsx(OverlayComponent, {}) }, overlay.id);
|
|
775
|
+
})
|
|
776
|
+
] });
|
|
759
777
|
};
|
|
760
778
|
}
|
|
761
779
|
function getNavigator() {
|
|
@@ -774,6 +792,624 @@ function useNavigationParams() {
|
|
|
774
792
|
return overlayParams ?? pageParams ?? {};
|
|
775
793
|
}
|
|
776
794
|
|
|
795
|
+
// src/debug/session.ts
|
|
796
|
+
import { useSnapshot as useSnapshot2, proxy as proxy2 } from "valtio";
|
|
797
|
+
var debugState = proxy2({
|
|
798
|
+
active: false,
|
|
799
|
+
checkpoints: {},
|
|
800
|
+
currentCursor: null,
|
|
801
|
+
restoring: false,
|
|
802
|
+
lastError: null
|
|
803
|
+
});
|
|
804
|
+
var appStateAdapter = null;
|
|
805
|
+
var currentConfig = {
|
|
806
|
+
onMarkerEnter: () => {
|
|
807
|
+
},
|
|
808
|
+
onError: () => {
|
|
809
|
+
}
|
|
810
|
+
};
|
|
811
|
+
var disposeMarkerListener = null;
|
|
812
|
+
var disposeFinishedListener = null;
|
|
813
|
+
var disposeWarpFinishedListener = null;
|
|
814
|
+
var debugOperationQueue = Promise.resolve();
|
|
815
|
+
var activeFastForward = null;
|
|
816
|
+
var activeWarp = null;
|
|
817
|
+
function enqueueDebugOperation(task) {
|
|
818
|
+
const nextTask = debugOperationQueue.then(task, task);
|
|
819
|
+
debugOperationQueue = nextTask.then(
|
|
820
|
+
() => void 0,
|
|
821
|
+
() => void 0
|
|
822
|
+
);
|
|
823
|
+
return nextTask;
|
|
824
|
+
}
|
|
825
|
+
function executeScenarioCommand(payload) {
|
|
826
|
+
return Promise.resolve(executePluginCommand("scenario", payload));
|
|
827
|
+
}
|
|
828
|
+
function toErrorMessage(error) {
|
|
829
|
+
if (error instanceof Error) {
|
|
830
|
+
return error.message;
|
|
831
|
+
}
|
|
832
|
+
return String(error);
|
|
833
|
+
}
|
|
834
|
+
function isPromiseLike(value) {
|
|
835
|
+
return !!value && typeof value.then === "function";
|
|
836
|
+
}
|
|
837
|
+
function reportDebugSessionError(error) {
|
|
838
|
+
debugState.lastError = toErrorMessage(error);
|
|
839
|
+
void Promise.resolve(currentConfig.onError(error));
|
|
840
|
+
}
|
|
841
|
+
function clearLocalRuntimeState() {
|
|
842
|
+
debugState.checkpoints = {};
|
|
843
|
+
debugState.currentCursor = null;
|
|
844
|
+
debugState.restoring = false;
|
|
845
|
+
debugState.lastError = null;
|
|
846
|
+
}
|
|
847
|
+
async function doSettleActiveSeek(op, clearSlot, error) {
|
|
848
|
+
if (!op) {
|
|
849
|
+
return;
|
|
850
|
+
}
|
|
851
|
+
clearSlot();
|
|
852
|
+
try {
|
|
853
|
+
await appStateAdapter?.exitFastForwardMode?.();
|
|
854
|
+
} catch (exitError) {
|
|
855
|
+
if (error === void 0) {
|
|
856
|
+
error = exitError;
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
if (error === void 0) {
|
|
860
|
+
op.resolve();
|
|
861
|
+
return;
|
|
862
|
+
}
|
|
863
|
+
op.reject(error);
|
|
864
|
+
}
|
|
865
|
+
async function settleActiveFastForward(error) {
|
|
866
|
+
await doSettleActiveSeek(activeFastForward, () => {
|
|
867
|
+
activeFastForward = null;
|
|
868
|
+
}, error);
|
|
869
|
+
}
|
|
870
|
+
async function settleActiveWarp(error) {
|
|
871
|
+
await doSettleActiveSeek(activeWarp, () => {
|
|
872
|
+
activeWarp = null;
|
|
873
|
+
}, error);
|
|
874
|
+
}
|
|
875
|
+
async function clearRemoteCheckpoints() {
|
|
876
|
+
await executeScenarioCommand({ subCommand: "clearCheckpoints" });
|
|
877
|
+
}
|
|
878
|
+
async function syncLocalWarpCheckpoint(targetMarkerId) {
|
|
879
|
+
const cursor = await executeScenarioCommand({
|
|
880
|
+
subCommand: "getExecutionCursor"
|
|
881
|
+
});
|
|
882
|
+
const checkpointCursor = cursor ? {
|
|
883
|
+
story: cursor.story,
|
|
884
|
+
paragraph: cursor.paragraph,
|
|
885
|
+
markerId: targetMarkerId
|
|
886
|
+
} : debugState.currentCursor ? {
|
|
887
|
+
story: debugState.currentCursor.story,
|
|
888
|
+
paragraph: debugState.currentCursor.paragraph,
|
|
889
|
+
markerId: targetMarkerId
|
|
890
|
+
} : null;
|
|
891
|
+
if (!checkpointCursor) {
|
|
892
|
+
return;
|
|
893
|
+
}
|
|
894
|
+
const checkpoint = {
|
|
895
|
+
cursor: checkpointCursor,
|
|
896
|
+
appState: appStateAdapter ? await appStateAdapter.capture() : void 0
|
|
897
|
+
};
|
|
898
|
+
debugState.currentCursor = checkpointCursor;
|
|
899
|
+
debugState.checkpoints[targetMarkerId] = checkpoint;
|
|
900
|
+
await currentConfig.onMarkerEnter(checkpoint);
|
|
901
|
+
}
|
|
902
|
+
function captureCheckpointAppStateSync() {
|
|
903
|
+
if (!appStateAdapter) {
|
|
904
|
+
return void 0;
|
|
905
|
+
}
|
|
906
|
+
const appState = appStateAdapter.capture();
|
|
907
|
+
if (isPromiseLike(appState)) {
|
|
908
|
+
throw new Error("Async app state capture is not supported for debug checkpoints");
|
|
909
|
+
}
|
|
910
|
+
return appState;
|
|
911
|
+
}
|
|
912
|
+
function notifyMarkerEnter(checkpoint) {
|
|
913
|
+
try {
|
|
914
|
+
const result = currentConfig.onMarkerEnter(checkpoint);
|
|
915
|
+
if (isPromiseLike(result)) {
|
|
916
|
+
void result.catch(reportDebugSessionError);
|
|
917
|
+
}
|
|
918
|
+
} catch (error) {
|
|
919
|
+
reportDebugSessionError(error);
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
async function prepareJumpStart(markerId) {
|
|
923
|
+
const checkpoint = debugState.checkpoints[markerId];
|
|
924
|
+
if (checkpoint) {
|
|
925
|
+
const restored2 = await executeScenarioCommand({
|
|
926
|
+
subCommand: "restoreCheckpoint",
|
|
927
|
+
key: markerId
|
|
928
|
+
});
|
|
929
|
+
if (!restored2) {
|
|
930
|
+
throw new Error(`Failed to restore checkpoint ${markerId}`);
|
|
931
|
+
}
|
|
932
|
+
if (appStateAdapter) {
|
|
933
|
+
await appStateAdapter.restore(checkpoint.appState);
|
|
934
|
+
}
|
|
935
|
+
debugState.currentCursor = checkpoint.cursor;
|
|
936
|
+
return false;
|
|
937
|
+
}
|
|
938
|
+
const lookup = await executeScenarioCommand({
|
|
939
|
+
subCommand: "getFastForwardCheckpoint",
|
|
940
|
+
key: markerId
|
|
941
|
+
});
|
|
942
|
+
if (!lookup.markerExists) {
|
|
943
|
+
throw new Error(`Marker ${markerId} is not available in the current story`);
|
|
944
|
+
}
|
|
945
|
+
const startCheckpointKey = lookup.checkpointKey ?? null;
|
|
946
|
+
if (!startCheckpointKey) {
|
|
947
|
+
if (!appStateAdapter?.restartCurrentStoryFromHead) {
|
|
948
|
+
throw new Error("Restarting the current story from head is not supported by the app state adapter");
|
|
949
|
+
}
|
|
950
|
+
await appStateAdapter.restartCurrentStoryFromHead();
|
|
951
|
+
debugState.checkpoints = {};
|
|
952
|
+
debugState.currentCursor = null;
|
|
953
|
+
return true;
|
|
954
|
+
}
|
|
955
|
+
const startCheckpoint = debugState.checkpoints[startCheckpointKey];
|
|
956
|
+
if (!startCheckpoint) {
|
|
957
|
+
throw new Error(`Local checkpoint ${startCheckpointKey} not found`);
|
|
958
|
+
}
|
|
959
|
+
const restored = await executeScenarioCommand({
|
|
960
|
+
subCommand: "restoreCheckpoint",
|
|
961
|
+
key: startCheckpointKey
|
|
962
|
+
});
|
|
963
|
+
if (!restored) {
|
|
964
|
+
throw new Error(`Failed to restore checkpoint ${startCheckpointKey}`);
|
|
965
|
+
}
|
|
966
|
+
if (appStateAdapter) {
|
|
967
|
+
await appStateAdapter.restore(startCheckpoint.appState);
|
|
968
|
+
}
|
|
969
|
+
debugState.currentCursor = startCheckpoint.cursor;
|
|
970
|
+
return true;
|
|
971
|
+
}
|
|
972
|
+
function handleMarkerEnter(marker) {
|
|
973
|
+
const checkpoint = {
|
|
974
|
+
cursor: {
|
|
975
|
+
story: marker.story,
|
|
976
|
+
paragraph: marker.paragraph,
|
|
977
|
+
markerId: marker.markerId
|
|
978
|
+
},
|
|
979
|
+
appState: captureCheckpointAppStateSync()
|
|
980
|
+
};
|
|
981
|
+
debugState.currentCursor = checkpoint.cursor;
|
|
982
|
+
debugState.checkpoints[marker.markerId] = checkpoint;
|
|
983
|
+
notifyMarkerEnter(checkpoint);
|
|
984
|
+
if (activeFastForward?.targetMarkerId === marker.markerId) {
|
|
985
|
+
void settleActiveFastForward();
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
async function runFastForwardToMarker(markerId) {
|
|
989
|
+
if (!appStateAdapter?.enterFastForwardMode || !appStateAdapter?.exitFastForwardMode) {
|
|
990
|
+
throw new Error("Fast-forward mode is not supported by the app state adapter");
|
|
991
|
+
}
|
|
992
|
+
if (activeFastForward !== null || activeWarp !== null) {
|
|
993
|
+
throw new Error("A debug seek operation is already active");
|
|
994
|
+
}
|
|
995
|
+
await appStateAdapter.enterFastForwardMode({
|
|
996
|
+
onAbort: (error) => {
|
|
997
|
+
void settleActiveFastForward(error);
|
|
998
|
+
}
|
|
999
|
+
});
|
|
1000
|
+
const completion = new Promise((resolve, reject) => {
|
|
1001
|
+
activeFastForward = {
|
|
1002
|
+
targetMarkerId: markerId,
|
|
1003
|
+
resolve,
|
|
1004
|
+
reject
|
|
1005
|
+
};
|
|
1006
|
+
});
|
|
1007
|
+
try {
|
|
1008
|
+
await executeScenarioCommand({ subCommand: "nextLine" });
|
|
1009
|
+
} catch (error) {
|
|
1010
|
+
await settleActiveFastForward(error);
|
|
1011
|
+
}
|
|
1012
|
+
await completion;
|
|
1013
|
+
}
|
|
1014
|
+
async function runWarp(options) {
|
|
1015
|
+
if (!appStateAdapter?.enterFastForwardMode || !appStateAdapter?.exitFastForwardMode) {
|
|
1016
|
+
throw new Error("Warp mode is not supported by the app state adapter");
|
|
1017
|
+
}
|
|
1018
|
+
if (activeFastForward !== null || activeWarp !== null) {
|
|
1019
|
+
throw new Error("A debug seek operation is already active");
|
|
1020
|
+
}
|
|
1021
|
+
const boundary = options.boundary ?? "before";
|
|
1022
|
+
await appStateAdapter.enterFastForwardMode({ warp: true });
|
|
1023
|
+
const completion = new Promise((resolve, reject) => {
|
|
1024
|
+
activeWarp = {
|
|
1025
|
+
targetMarkerId: options.markerId,
|
|
1026
|
+
resolve,
|
|
1027
|
+
reject
|
|
1028
|
+
};
|
|
1029
|
+
});
|
|
1030
|
+
try {
|
|
1031
|
+
await executeScenarioCommand({
|
|
1032
|
+
subCommand: "warp",
|
|
1033
|
+
markerId: options.markerId,
|
|
1034
|
+
boundary
|
|
1035
|
+
});
|
|
1036
|
+
} catch (error) {
|
|
1037
|
+
await settleActiveWarp(error);
|
|
1038
|
+
}
|
|
1039
|
+
await completion;
|
|
1040
|
+
}
|
|
1041
|
+
var debugSessionController = {
|
|
1042
|
+
async restoreCheckpoint(markerId) {
|
|
1043
|
+
debugState.restoring = true;
|
|
1044
|
+
debugState.lastError = null;
|
|
1045
|
+
try {
|
|
1046
|
+
const needsFastForward = await enqueueDebugOperation(async () => prepareJumpStart(markerId));
|
|
1047
|
+
if (needsFastForward) {
|
|
1048
|
+
await runFastForwardToMarker(markerId);
|
|
1049
|
+
}
|
|
1050
|
+
return true;
|
|
1051
|
+
} catch (error) {
|
|
1052
|
+
debugState.lastError = toErrorMessage(error);
|
|
1053
|
+
throw error;
|
|
1054
|
+
} finally {
|
|
1055
|
+
debugState.restoring = false;
|
|
1056
|
+
}
|
|
1057
|
+
},
|
|
1058
|
+
async warp(options) {
|
|
1059
|
+
debugState.restoring = true;
|
|
1060
|
+
debugState.lastError = null;
|
|
1061
|
+
try {
|
|
1062
|
+
const needsWarp = await enqueueDebugOperation(async () => prepareJumpStart(options.markerId));
|
|
1063
|
+
if (needsWarp) {
|
|
1064
|
+
await runWarp(options);
|
|
1065
|
+
}
|
|
1066
|
+
} catch (error) {
|
|
1067
|
+
debugState.lastError = toErrorMessage(error);
|
|
1068
|
+
throw error;
|
|
1069
|
+
} finally {
|
|
1070
|
+
debugState.restoring = false;
|
|
1071
|
+
}
|
|
1072
|
+
},
|
|
1073
|
+
async switchPage(page, params) {
|
|
1074
|
+
return enqueueDebugOperation(async () => {
|
|
1075
|
+
debugState.lastError = null;
|
|
1076
|
+
try {
|
|
1077
|
+
if (!appStateAdapter?.switchPage) {
|
|
1078
|
+
throw new Error("Page switching is not supported by the app state adapter");
|
|
1079
|
+
}
|
|
1080
|
+
await appStateAdapter.switchPage(page, params);
|
|
1081
|
+
} catch (error) {
|
|
1082
|
+
debugState.lastError = toErrorMessage(error);
|
|
1083
|
+
throw error;
|
|
1084
|
+
}
|
|
1085
|
+
});
|
|
1086
|
+
}
|
|
1087
|
+
};
|
|
1088
|
+
function registerAppStateAdapter(adapter) {
|
|
1089
|
+
appStateAdapter = adapter;
|
|
1090
|
+
}
|
|
1091
|
+
function getAppStateAdapter() {
|
|
1092
|
+
return appStateAdapter;
|
|
1093
|
+
}
|
|
1094
|
+
async function startDebugSession(config = {}) {
|
|
1095
|
+
await stopDebugSession();
|
|
1096
|
+
currentConfig = {
|
|
1097
|
+
onMarkerEnter: config.onMarkerEnter ?? (() => {
|
|
1098
|
+
}),
|
|
1099
|
+
onError: config.onError ?? (() => {
|
|
1100
|
+
})
|
|
1101
|
+
};
|
|
1102
|
+
clearLocalRuntimeState();
|
|
1103
|
+
debugState.active = true;
|
|
1104
|
+
disposeMarkerListener = addEventListener("scenariomarkerenter", (event) => {
|
|
1105
|
+
const marker = event;
|
|
1106
|
+
try {
|
|
1107
|
+
handleMarkerEnter(marker);
|
|
1108
|
+
} catch (error) {
|
|
1109
|
+
reportDebugSessionError(error);
|
|
1110
|
+
}
|
|
1111
|
+
});
|
|
1112
|
+
disposeFinishedListener = addEventListener("scenariofinished", () => {
|
|
1113
|
+
debugState.currentCursor = null;
|
|
1114
|
+
if (activeFastForward) {
|
|
1115
|
+
void settleActiveFastForward(
|
|
1116
|
+
new Error(`Marker ${activeFastForward.targetMarkerId} was not reached before the scenario finished`)
|
|
1117
|
+
);
|
|
1118
|
+
}
|
|
1119
|
+
if (activeWarp) {
|
|
1120
|
+
const targetMarkerId = activeWarp.targetMarkerId;
|
|
1121
|
+
void settleActiveWarp(new Error(`Marker ${targetMarkerId} was not reached before the scenario finished`));
|
|
1122
|
+
}
|
|
1123
|
+
});
|
|
1124
|
+
disposeWarpFinishedListener = addEventListener("scenariowarpfinished", () => {
|
|
1125
|
+
const warp = activeWarp;
|
|
1126
|
+
if (!warp) {
|
|
1127
|
+
return;
|
|
1128
|
+
}
|
|
1129
|
+
void enqueueDebugOperation(async () => {
|
|
1130
|
+
try {
|
|
1131
|
+
await syncLocalWarpCheckpoint(warp.targetMarkerId);
|
|
1132
|
+
await settleActiveWarp();
|
|
1133
|
+
} catch (error) {
|
|
1134
|
+
debugState.lastError = toErrorMessage(error);
|
|
1135
|
+
await settleActiveWarp(error);
|
|
1136
|
+
await currentConfig.onError(error);
|
|
1137
|
+
}
|
|
1138
|
+
});
|
|
1139
|
+
});
|
|
1140
|
+
try {
|
|
1141
|
+
await clearRemoteCheckpoints();
|
|
1142
|
+
debugState.currentCursor = await executeScenarioCommand({
|
|
1143
|
+
subCommand: "getExecutionCursor"
|
|
1144
|
+
});
|
|
1145
|
+
} catch (error) {
|
|
1146
|
+
debugState.active = false;
|
|
1147
|
+
clearLocalRuntimeState();
|
|
1148
|
+
disposeMarkerListener?.();
|
|
1149
|
+
disposeFinishedListener?.();
|
|
1150
|
+
disposeWarpFinishedListener?.();
|
|
1151
|
+
disposeMarkerListener = null;
|
|
1152
|
+
disposeFinishedListener = null;
|
|
1153
|
+
disposeWarpFinishedListener = null;
|
|
1154
|
+
await currentConfig.onError(error);
|
|
1155
|
+
throw error;
|
|
1156
|
+
}
|
|
1157
|
+
return debugSessionController;
|
|
1158
|
+
}
|
|
1159
|
+
async function stopDebugSession() {
|
|
1160
|
+
disposeMarkerListener?.();
|
|
1161
|
+
disposeFinishedListener?.();
|
|
1162
|
+
disposeWarpFinishedListener?.();
|
|
1163
|
+
disposeMarkerListener = null;
|
|
1164
|
+
disposeFinishedListener = null;
|
|
1165
|
+
disposeWarpFinishedListener = null;
|
|
1166
|
+
await settleActiveFastForward(new Error("Debug session stopped"));
|
|
1167
|
+
await settleActiveWarp(new Error("Debug session stopped"));
|
|
1168
|
+
if (debugState.active) {
|
|
1169
|
+
await enqueueDebugOperation(async () => {
|
|
1170
|
+
try {
|
|
1171
|
+
await clearRemoteCheckpoints();
|
|
1172
|
+
} catch (error) {
|
|
1173
|
+
debugState.lastError = toErrorMessage(error);
|
|
1174
|
+
await currentConfig.onError(error);
|
|
1175
|
+
}
|
|
1176
|
+
});
|
|
1177
|
+
}
|
|
1178
|
+
debugState.active = false;
|
|
1179
|
+
clearLocalRuntimeState();
|
|
1180
|
+
}
|
|
1181
|
+
function clearDebugSessionRuntimeState() {
|
|
1182
|
+
clearLocalRuntimeState();
|
|
1183
|
+
void settleActiveFastForward(new Error("Debug session runtime state cleared"));
|
|
1184
|
+
void settleActiveWarp(new Error("Debug session runtime state cleared"));
|
|
1185
|
+
if (!debugState.active) {
|
|
1186
|
+
return;
|
|
1187
|
+
}
|
|
1188
|
+
void enqueueDebugOperation(async () => {
|
|
1189
|
+
try {
|
|
1190
|
+
await clearRemoteCheckpoints();
|
|
1191
|
+
} catch (error) {
|
|
1192
|
+
debugState.lastError = toErrorMessage(error);
|
|
1193
|
+
await currentConfig.onError(error);
|
|
1194
|
+
}
|
|
1195
|
+
});
|
|
1196
|
+
}
|
|
1197
|
+
function useDebugSession() {
|
|
1198
|
+
const snapshot = useSnapshot2(debugState);
|
|
1199
|
+
return {
|
|
1200
|
+
...snapshot,
|
|
1201
|
+
startDebugSession,
|
|
1202
|
+
stopDebugSession,
|
|
1203
|
+
restoreCheckpoint: debugSessionController.restoreCheckpoint,
|
|
1204
|
+
warp: debugSessionController.warp,
|
|
1205
|
+
switchPage: debugSessionController.switchPage
|
|
1206
|
+
};
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
// src/debug/runtime.ts
|
|
1210
|
+
var currentConnection = null;
|
|
1211
|
+
var currentController = null;
|
|
1212
|
+
var bufferedRequestMessages = [];
|
|
1213
|
+
function getRuntimeWebSocket() {
|
|
1214
|
+
return globalThis.WebSocket ?? null;
|
|
1215
|
+
}
|
|
1216
|
+
function isJumpRequestMessage(message) {
|
|
1217
|
+
return message.type === "jump:request" && typeof message.sessionId === "string" && typeof message.requestId === "number" && typeof message.markerId === "string" && (message.boundary === void 0 || message.boundary === "before" || message.boundary === "after") && (message.strategy === void 0 || message.strategy === "fast-forward" || message.strategy === "warp");
|
|
1218
|
+
}
|
|
1219
|
+
function isRouteRequestMessage(message) {
|
|
1220
|
+
return message.type === "route:request" && typeof message.sessionId === "string" && typeof message.requestId === "number" && typeof message.page === "string" && (message.params === void 0 || typeof message.params === "object" && message.params !== null && !Array.isArray(message.params));
|
|
1221
|
+
}
|
|
1222
|
+
function sendRuntimeDebugMessage(socket, message) {
|
|
1223
|
+
const RuntimeWebSocket = getRuntimeWebSocket();
|
|
1224
|
+
if (!RuntimeWebSocket || socket.readyState !== RuntimeWebSocket.OPEN) {
|
|
1225
|
+
return;
|
|
1226
|
+
}
|
|
1227
|
+
socket.send(JSON.stringify(message));
|
|
1228
|
+
}
|
|
1229
|
+
function clearBufferedRequestMessages() {
|
|
1230
|
+
bufferedRequestMessages = [];
|
|
1231
|
+
}
|
|
1232
|
+
function bufferRequestMessage(message) {
|
|
1233
|
+
bufferedRequestMessages.push(message);
|
|
1234
|
+
}
|
|
1235
|
+
function flushBufferedRequestMessages(socket, sessionId) {
|
|
1236
|
+
const messages = bufferedRequestMessages;
|
|
1237
|
+
bufferedRequestMessages = [];
|
|
1238
|
+
for (const message of messages) {
|
|
1239
|
+
handleRuntimeDebugRequest(socket, sessionId, message);
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
function handleRuntimeDebugRequest(socket, sessionId, message) {
|
|
1243
|
+
const controller = currentController;
|
|
1244
|
+
if (!controller) {
|
|
1245
|
+
bufferRequestMessage(message);
|
|
1246
|
+
return;
|
|
1247
|
+
}
|
|
1248
|
+
if (isJumpRequestMessage(message)) {
|
|
1249
|
+
const runJump = message.strategy === "warp" ? controller.warp({
|
|
1250
|
+
markerId: message.markerId,
|
|
1251
|
+
boundary: message.boundary
|
|
1252
|
+
}).then(() => true) : controller.restoreCheckpoint(message.markerId);
|
|
1253
|
+
void runJump.then((restored) => {
|
|
1254
|
+
if (!restored) {
|
|
1255
|
+
sendRuntimeDebugMessage(socket, {
|
|
1256
|
+
type: "jump:error",
|
|
1257
|
+
sessionId,
|
|
1258
|
+
requestId: message.requestId,
|
|
1259
|
+
markerId: message.markerId,
|
|
1260
|
+
error: "Checkpoint not found"
|
|
1261
|
+
});
|
|
1262
|
+
return;
|
|
1263
|
+
}
|
|
1264
|
+
sendRuntimeDebugMessage(socket, {
|
|
1265
|
+
type: "jump:done",
|
|
1266
|
+
sessionId,
|
|
1267
|
+
requestId: message.requestId,
|
|
1268
|
+
markerId: message.markerId
|
|
1269
|
+
});
|
|
1270
|
+
}).catch((error) => {
|
|
1271
|
+
sendRuntimeDebugMessage(socket, {
|
|
1272
|
+
type: "jump:error",
|
|
1273
|
+
sessionId,
|
|
1274
|
+
requestId: message.requestId,
|
|
1275
|
+
markerId: message.markerId,
|
|
1276
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1277
|
+
});
|
|
1278
|
+
});
|
|
1279
|
+
return;
|
|
1280
|
+
}
|
|
1281
|
+
void controller.switchPage(message.page, message.params).then(() => {
|
|
1282
|
+
sendRuntimeDebugMessage(socket, {
|
|
1283
|
+
type: "route:done",
|
|
1284
|
+
sessionId,
|
|
1285
|
+
requestId: message.requestId,
|
|
1286
|
+
page: message.page
|
|
1287
|
+
});
|
|
1288
|
+
}).catch((error) => {
|
|
1289
|
+
sendRuntimeDebugMessage(socket, {
|
|
1290
|
+
type: "route:error",
|
|
1291
|
+
sessionId,
|
|
1292
|
+
requestId: message.requestId,
|
|
1293
|
+
page: message.page,
|
|
1294
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1295
|
+
});
|
|
1296
|
+
});
|
|
1297
|
+
}
|
|
1298
|
+
async function readDebugParams() {
|
|
1299
|
+
const rawParams = await executePluginCommand("system", {
|
|
1300
|
+
subCommand: "getParams"
|
|
1301
|
+
});
|
|
1302
|
+
if (!rawParams) {
|
|
1303
|
+
return {};
|
|
1304
|
+
}
|
|
1305
|
+
try {
|
|
1306
|
+
const parsed = JSON.parse(rawParams);
|
|
1307
|
+
return {
|
|
1308
|
+
debug: parsed.debug === true,
|
|
1309
|
+
debugSessionId: typeof parsed.debugSessionId === "string" ? parsed.debugSessionId : void 0,
|
|
1310
|
+
debugWsUrl: typeof parsed.debugWsUrl === "string" ? parsed.debugWsUrl : void 0
|
|
1311
|
+
};
|
|
1312
|
+
} catch {
|
|
1313
|
+
return {};
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
async function stopRuntimeDebugSession() {
|
|
1317
|
+
const connection = currentConnection;
|
|
1318
|
+
currentConnection = null;
|
|
1319
|
+
currentController = null;
|
|
1320
|
+
clearBufferedRequestMessages();
|
|
1321
|
+
const RuntimeWebSocket = getRuntimeWebSocket();
|
|
1322
|
+
await stopDebugSession();
|
|
1323
|
+
if (!connection) {
|
|
1324
|
+
return;
|
|
1325
|
+
}
|
|
1326
|
+
if (RuntimeWebSocket && (connection.socket.readyState === RuntimeWebSocket.OPEN || connection.socket.readyState === RuntimeWebSocket.CONNECTING)) {
|
|
1327
|
+
connection.socket.close();
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
async function startRuntimeDebugSession() {
|
|
1331
|
+
await stopRuntimeDebugSession();
|
|
1332
|
+
const params = await readDebugParams();
|
|
1333
|
+
if (params.debug !== true || !params.debugSessionId || !params.debugWsUrl) {
|
|
1334
|
+
return;
|
|
1335
|
+
}
|
|
1336
|
+
const RuntimeWebSocket = getRuntimeWebSocket();
|
|
1337
|
+
if (!RuntimeWebSocket) {
|
|
1338
|
+
return;
|
|
1339
|
+
}
|
|
1340
|
+
const socket = new RuntimeWebSocket(params.debugWsUrl);
|
|
1341
|
+
const sessionId = params.debugSessionId;
|
|
1342
|
+
currentConnection = { sessionId, socket };
|
|
1343
|
+
socket.onopen = () => {
|
|
1344
|
+
if (currentConnection?.socket !== socket) {
|
|
1345
|
+
socket.close();
|
|
1346
|
+
return;
|
|
1347
|
+
}
|
|
1348
|
+
void startDebugSession({
|
|
1349
|
+
onMarkerEnter(checkpoint) {
|
|
1350
|
+
if (!checkpoint.cursor.markerId) {
|
|
1351
|
+
return;
|
|
1352
|
+
}
|
|
1353
|
+
sendRuntimeDebugMessage(socket, {
|
|
1354
|
+
type: "marker:enter",
|
|
1355
|
+
sessionId,
|
|
1356
|
+
markerId: checkpoint.cursor.markerId,
|
|
1357
|
+
story: checkpoint.cursor.story,
|
|
1358
|
+
paragraph: checkpoint.cursor.paragraph
|
|
1359
|
+
});
|
|
1360
|
+
},
|
|
1361
|
+
onError(error) {
|
|
1362
|
+
console.error("[debug] runtime debug session error:", error);
|
|
1363
|
+
}
|
|
1364
|
+
}).then((controller) => {
|
|
1365
|
+
currentController = controller;
|
|
1366
|
+
flushBufferedRequestMessages(socket, sessionId);
|
|
1367
|
+
}).catch((error) => {
|
|
1368
|
+
console.error("[debug] failed to start runtime debug session:", error);
|
|
1369
|
+
socket.close();
|
|
1370
|
+
});
|
|
1371
|
+
};
|
|
1372
|
+
socket.onclose = () => {
|
|
1373
|
+
if (currentConnection?.socket !== socket) {
|
|
1374
|
+
return;
|
|
1375
|
+
}
|
|
1376
|
+
currentConnection = null;
|
|
1377
|
+
currentController = null;
|
|
1378
|
+
clearBufferedRequestMessages();
|
|
1379
|
+
void stopDebugSession();
|
|
1380
|
+
};
|
|
1381
|
+
socket.onerror = (event) => {
|
|
1382
|
+
if (currentConnection?.socket !== socket) {
|
|
1383
|
+
return;
|
|
1384
|
+
}
|
|
1385
|
+
console.error("[debug] runtime websocket error:", event);
|
|
1386
|
+
};
|
|
1387
|
+
socket.onmessage = (event) => {
|
|
1388
|
+
if (currentConnection?.socket !== socket) {
|
|
1389
|
+
return;
|
|
1390
|
+
}
|
|
1391
|
+
try {
|
|
1392
|
+
const message = JSON.parse(String(event.data));
|
|
1393
|
+
if (message.sessionId && message.sessionId !== sessionId) {
|
|
1394
|
+
return;
|
|
1395
|
+
}
|
|
1396
|
+
if (isJumpRequestMessage(message)) {
|
|
1397
|
+
handleRuntimeDebugRequest(socket, sessionId, message);
|
|
1398
|
+
return;
|
|
1399
|
+
}
|
|
1400
|
+
if (isRouteRequestMessage(message)) {
|
|
1401
|
+
handleRuntimeDebugRequest(socket, sessionId, message);
|
|
1402
|
+
return;
|
|
1403
|
+
}
|
|
1404
|
+
if (message.type && message.type !== "session:init") {
|
|
1405
|
+
console.debug("[debug] runtime received message:", message);
|
|
1406
|
+
}
|
|
1407
|
+
} catch (error) {
|
|
1408
|
+
console.error("[debug] failed to parse runtime debug message:", error);
|
|
1409
|
+
}
|
|
1410
|
+
};
|
|
1411
|
+
}
|
|
1412
|
+
|
|
777
1413
|
// src/hooks/useFadeInOut.ts
|
|
778
1414
|
function useFadeInOut(inTime, _keepTime, _outTime, pause = false, onFinished) {
|
|
779
1415
|
const [style, api] = (0, spring_exports.useSpring)(
|
|
@@ -876,11 +1512,13 @@ async function terminateCurrentScenario() {
|
|
|
876
1512
|
await executePluginCommand("scenario", {
|
|
877
1513
|
subCommand: "terminateStory"
|
|
878
1514
|
});
|
|
1515
|
+
clearDebugSessionRuntimeState();
|
|
879
1516
|
} catch (error) {
|
|
880
1517
|
console.error("Failed to terminate scenario:", error);
|
|
881
1518
|
}
|
|
882
1519
|
}
|
|
883
1520
|
async function startScenarioSession(session, config) {
|
|
1521
|
+
clearDebugSessionRuntimeState();
|
|
884
1522
|
for (const story of config.stories) {
|
|
885
1523
|
if (!isCurrentScenarioSession(session)) return;
|
|
886
1524
|
try {
|
|
@@ -1047,18 +1685,30 @@ function useSoundEffect(src) {
|
|
|
1047
1685
|
|
|
1048
1686
|
// src/hooks/useStage.ts
|
|
1049
1687
|
import { createContext as createContext2, useContext as useContext2, useEffect as useEffect3, createElement, useCallback as useCallback2 } from "react";
|
|
1050
|
-
import { proxy as
|
|
1688
|
+
import { proxy as proxy3, useSnapshot as useSnapshot3 } from "valtio";
|
|
1051
1689
|
var SKIP_INTERVAL_MS = 80;
|
|
1690
|
+
var DEFAULT_FAST_FORWARD_STEP_LIMIT = 1e4;
|
|
1691
|
+
var DEFAULT_FAST_FORWARD_TIME_LIMIT_MS = 3e3;
|
|
1052
1692
|
var autoRuntime = {
|
|
1053
1693
|
defaultTailMs: 0
|
|
1054
1694
|
};
|
|
1055
|
-
var skipState =
|
|
1056
|
-
var autoState =
|
|
1695
|
+
var skipState = proxy3({ active: false });
|
|
1696
|
+
var autoState = proxy3({ active: false });
|
|
1697
|
+
var fastForwardState = proxy3({ active: false });
|
|
1698
|
+
var warpState = proxy3({ active: false });
|
|
1057
1699
|
function useIsSkipping() {
|
|
1058
|
-
return
|
|
1700
|
+
return useSnapshot3(skipState).active;
|
|
1059
1701
|
}
|
|
1060
1702
|
function useIsAutoing() {
|
|
1061
|
-
return
|
|
1703
|
+
return useSnapshot3(autoState).active;
|
|
1704
|
+
}
|
|
1705
|
+
function useIsSeeking() {
|
|
1706
|
+
return useSnapshot3(fastForwardState).active;
|
|
1707
|
+
}
|
|
1708
|
+
function getSeekingType() {
|
|
1709
|
+
if (warpState.active) return "warp";
|
|
1710
|
+
if (fastForwardState.active) return "fast-forward";
|
|
1711
|
+
return null;
|
|
1062
1712
|
}
|
|
1063
1713
|
function setDefaultAutoTailMs(ms) {
|
|
1064
1714
|
if (!Number.isFinite(ms)) {
|
|
@@ -1166,6 +1816,101 @@ function createStage() {
|
|
|
1166
1816
|
let _autoBarrierSeq = 0;
|
|
1167
1817
|
let _autoTicketSeq = 0;
|
|
1168
1818
|
const _pendingAutoTickets = /* @__PURE__ */ new Map();
|
|
1819
|
+
let _fastForwardRuntime = null;
|
|
1820
|
+
let _managedAdvanceInFlight = false;
|
|
1821
|
+
let _managedAdvancePending = false;
|
|
1822
|
+
function resetManagedAdvanceState() {
|
|
1823
|
+
_managedAdvanceInFlight = false;
|
|
1824
|
+
_managedAdvancePending = false;
|
|
1825
|
+
}
|
|
1826
|
+
function clearFastForwardRuntime() {
|
|
1827
|
+
_fastForwardRuntime = null;
|
|
1828
|
+
resetManagedAdvanceState();
|
|
1829
|
+
}
|
|
1830
|
+
function stopFastForwardInternal() {
|
|
1831
|
+
fastForwardState.active = false;
|
|
1832
|
+
warpState.active = false;
|
|
1833
|
+
clearFastForwardRuntime();
|
|
1834
|
+
}
|
|
1835
|
+
function abortFastForward(error) {
|
|
1836
|
+
const runtime = _fastForwardRuntime;
|
|
1837
|
+
stopFastForwardInternal();
|
|
1838
|
+
if (!runtime?.onAbort) {
|
|
1839
|
+
return;
|
|
1840
|
+
}
|
|
1841
|
+
try {
|
|
1842
|
+
runtime.onAbort(error);
|
|
1843
|
+
} catch (abortError) {
|
|
1844
|
+
console.error("Error in fast-forward abort callback:", abortError);
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1847
|
+
function canAdvanceFastForward() {
|
|
1848
|
+
if (!fastForwardState.active || _fastForwardRuntime === null) {
|
|
1849
|
+
return true;
|
|
1850
|
+
}
|
|
1851
|
+
const elapsedMs = Date.now() - _fastForwardRuntime.startedAt;
|
|
1852
|
+
if (elapsedMs > _fastForwardRuntime.timeLimitMs) {
|
|
1853
|
+
abortFastForward(new Error(`Fast forward exceeded time limit (${_fastForwardRuntime.timeLimitMs}ms)`));
|
|
1854
|
+
return false;
|
|
1855
|
+
}
|
|
1856
|
+
_fastForwardRuntime.stepCount += 1;
|
|
1857
|
+
if (_fastForwardRuntime.stepCount > _fastForwardRuntime.stepLimit) {
|
|
1858
|
+
abortFastForward(new Error(`Fast forward exceeded step limit (${_fastForwardRuntime.stepLimit})`));
|
|
1859
|
+
return false;
|
|
1860
|
+
}
|
|
1861
|
+
return true;
|
|
1862
|
+
}
|
|
1863
|
+
function normalizeAdvanceError(error) {
|
|
1864
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
1865
|
+
}
|
|
1866
|
+
function isManagedAdvanceActive() {
|
|
1867
|
+
return fastForwardState.active || skipState.active || autoState.active;
|
|
1868
|
+
}
|
|
1869
|
+
function canScheduleManagedAdvance() {
|
|
1870
|
+
if (fastForwardState.active) {
|
|
1871
|
+
return canAdvanceFastForward();
|
|
1872
|
+
}
|
|
1873
|
+
return true;
|
|
1874
|
+
}
|
|
1875
|
+
function handleManagedAdvanceError(error) {
|
|
1876
|
+
console.error("Failed to advance scenario:", error);
|
|
1877
|
+
if (fastForwardState.active) {
|
|
1878
|
+
abortFastForward(normalizeAdvanceError(error));
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
function scheduleManagedAdvance() {
|
|
1882
|
+
if (!isManagedAdvanceActive()) {
|
|
1883
|
+
_managedAdvancePending = false;
|
|
1884
|
+
return;
|
|
1885
|
+
}
|
|
1886
|
+
if (_managedAdvanceInFlight) {
|
|
1887
|
+
_managedAdvancePending = true;
|
|
1888
|
+
return;
|
|
1889
|
+
}
|
|
1890
|
+
if (!canScheduleManagedAdvance()) {
|
|
1891
|
+
_managedAdvancePending = false;
|
|
1892
|
+
return;
|
|
1893
|
+
}
|
|
1894
|
+
_managedAdvanceInFlight = true;
|
|
1895
|
+
_managedAdvancePending = false;
|
|
1896
|
+
void Promise.resolve(nextLine()).catch(handleManagedAdvanceError).finally(() => {
|
|
1897
|
+
_managedAdvanceInFlight = false;
|
|
1898
|
+
if (!isManagedAdvanceActive()) {
|
|
1899
|
+
_managedAdvancePending = false;
|
|
1900
|
+
return;
|
|
1901
|
+
}
|
|
1902
|
+
if (_managedAdvancePending) {
|
|
1903
|
+
scheduleManagedAdvance();
|
|
1904
|
+
}
|
|
1905
|
+
});
|
|
1906
|
+
}
|
|
1907
|
+
function requestNextLine() {
|
|
1908
|
+
if (isManagedAdvanceActive()) {
|
|
1909
|
+
scheduleManagedAdvance();
|
|
1910
|
+
return;
|
|
1911
|
+
}
|
|
1912
|
+
void Promise.resolve(nextLine()).catch(handleManagedAdvanceError);
|
|
1913
|
+
}
|
|
1169
1914
|
function clearAutoResumeTimer() {
|
|
1170
1915
|
if (_autoResumeTimer !== null) {
|
|
1171
1916
|
clearTimeout(_autoResumeTimer);
|
|
@@ -1200,7 +1945,7 @@ function createStage() {
|
|
|
1200
1945
|
if (!autoState.active) return;
|
|
1201
1946
|
if (_autoBarrier === null || _autoBarrier.id !== barrierId) return;
|
|
1202
1947
|
_autoBarrier = null;
|
|
1203
|
-
|
|
1948
|
+
requestNextLine();
|
|
1204
1949
|
}, safeDelayMs);
|
|
1205
1950
|
}
|
|
1206
1951
|
function trySettleAutoBarrier(barrier) {
|
|
@@ -1336,7 +2081,7 @@ function createStage() {
|
|
|
1336
2081
|
return;
|
|
1337
2082
|
}
|
|
1338
2083
|
if (_autoBarrier === null) {
|
|
1339
|
-
|
|
2084
|
+
requestNextLine();
|
|
1340
2085
|
}
|
|
1341
2086
|
}, autoRuntime.defaultTailMs);
|
|
1342
2087
|
}
|
|
@@ -1344,11 +2089,12 @@ function createStage() {
|
|
|
1344
2089
|
if (_skipTimer !== null) clearTimeout(_skipTimer);
|
|
1345
2090
|
_skipTimer = setTimeout(() => {
|
|
1346
2091
|
_skipTimer = null;
|
|
1347
|
-
if (skipState.active)
|
|
2092
|
+
if (skipState.active) requestNextLine();
|
|
1348
2093
|
}, SKIP_INTERVAL_MS);
|
|
1349
2094
|
}
|
|
1350
2095
|
function startSkip() {
|
|
1351
2096
|
if (skipState.active) return;
|
|
2097
|
+
if (fastForwardState.active) return;
|
|
1352
2098
|
if (isAnyBlockerActive()) return;
|
|
1353
2099
|
skipState.active = true;
|
|
1354
2100
|
invokeSkipCallbacks();
|
|
@@ -1360,7 +2106,7 @@ function createStage() {
|
|
|
1360
2106
|
if (_skipTimer !== null) {
|
|
1361
2107
|
clearTimeout(_skipTimer);
|
|
1362
2108
|
_skipTimer = null;
|
|
1363
|
-
|
|
2109
|
+
requestNextLine();
|
|
1364
2110
|
}
|
|
1365
2111
|
}
|
|
1366
2112
|
function isSkipping() {
|
|
@@ -1368,6 +2114,7 @@ function createStage() {
|
|
|
1368
2114
|
}
|
|
1369
2115
|
function startAuto() {
|
|
1370
2116
|
if (autoState.active) return;
|
|
2117
|
+
if (fastForwardState.active) return;
|
|
1371
2118
|
if (isAnyAutoBlockerActive()) return;
|
|
1372
2119
|
autoState.active = true;
|
|
1373
2120
|
tryInterrupt();
|
|
@@ -1385,12 +2132,58 @@ function createStage() {
|
|
|
1385
2132
|
function isAutoing() {
|
|
1386
2133
|
return autoState.active;
|
|
1387
2134
|
}
|
|
2135
|
+
function startFastForward(options) {
|
|
2136
|
+
if (fastForwardState.active) return;
|
|
2137
|
+
resetRuntimeState();
|
|
2138
|
+
_fastForwardRuntime = {
|
|
2139
|
+
stepLimit: Math.max(1, options?.stepLimit ?? DEFAULT_FAST_FORWARD_STEP_LIMIT),
|
|
2140
|
+
timeLimitMs: Math.max(1, options?.timeLimitMs ?? DEFAULT_FAST_FORWARD_TIME_LIMIT_MS),
|
|
2141
|
+
stepCount: 0,
|
|
2142
|
+
startedAt: Date.now(),
|
|
2143
|
+
onAbort: options?.onAbort,
|
|
2144
|
+
warp: options?.warp === true
|
|
2145
|
+
};
|
|
2146
|
+
fastForwardState.active = true;
|
|
2147
|
+
warpState.active = _fastForwardRuntime.warp;
|
|
2148
|
+
}
|
|
2149
|
+
function stopFastForward() {
|
|
2150
|
+
stopFastForwardInternal();
|
|
2151
|
+
}
|
|
2152
|
+
function isFastForwarding() {
|
|
2153
|
+
return fastForwardState.active;
|
|
2154
|
+
}
|
|
2155
|
+
function resetRuntimeState() {
|
|
2156
|
+
skipState.active = false;
|
|
2157
|
+
autoState.active = false;
|
|
2158
|
+
fastForwardState.active = false;
|
|
2159
|
+
warpState.active = false;
|
|
2160
|
+
clearFastForwardRuntime();
|
|
2161
|
+
if (_skipTimer !== null) {
|
|
2162
|
+
clearTimeout(_skipTimer);
|
|
2163
|
+
_skipTimer = null;
|
|
2164
|
+
}
|
|
2165
|
+
if (_autoTimer !== null) {
|
|
2166
|
+
clearTimeout(_autoTimer);
|
|
2167
|
+
_autoTimer = null;
|
|
2168
|
+
}
|
|
2169
|
+
clearAutoBarrier();
|
|
2170
|
+
clearPendingAutoTickets();
|
|
2171
|
+
}
|
|
1388
2172
|
function buildControl() {
|
|
1389
|
-
|
|
2173
|
+
const warpActive = warpState.active;
|
|
2174
|
+
let handled = warpActive;
|
|
1390
2175
|
let unskippableFlag = false;
|
|
2176
|
+
const inertRecordId = "__warp__";
|
|
1391
2177
|
const control = {
|
|
1392
2178
|
setWaiting(time, skippable) {
|
|
1393
2179
|
handled = true;
|
|
2180
|
+
if (warpActive) {
|
|
2181
|
+
return;
|
|
2182
|
+
}
|
|
2183
|
+
if (fastForwardState.active) {
|
|
2184
|
+
requestNextLine();
|
|
2185
|
+
return;
|
|
2186
|
+
}
|
|
1394
2187
|
if (skipState.active) {
|
|
1395
2188
|
invokeSkipCallbacks();
|
|
1396
2189
|
scheduleSkipNextLine();
|
|
@@ -1407,6 +2200,13 @@ function createStage() {
|
|
|
1407
2200
|
},
|
|
1408
2201
|
hold() {
|
|
1409
2202
|
handled = true;
|
|
2203
|
+
if (warpActive) {
|
|
2204
|
+
return;
|
|
2205
|
+
}
|
|
2206
|
+
if (fastForwardState.active) {
|
|
2207
|
+
requestNextLine();
|
|
2208
|
+
return;
|
|
2209
|
+
}
|
|
1410
2210
|
if (skipState.active && !unskippableFlag) {
|
|
1411
2211
|
if (isAnyBlockerActive()) {
|
|
1412
2212
|
stopSkip();
|
|
@@ -1425,12 +2225,21 @@ function createStage() {
|
|
|
1425
2225
|
},
|
|
1426
2226
|
nextLine() {
|
|
1427
2227
|
handled = true;
|
|
1428
|
-
|
|
2228
|
+
if (warpActive) {
|
|
2229
|
+
return;
|
|
2230
|
+
}
|
|
2231
|
+
requestNextLine();
|
|
1429
2232
|
},
|
|
1430
2233
|
unskippable() {
|
|
2234
|
+
if (warpActive) {
|
|
2235
|
+
return;
|
|
2236
|
+
}
|
|
1431
2237
|
unskippableFlag = true;
|
|
1432
2238
|
},
|
|
1433
2239
|
record(meta) {
|
|
2240
|
+
if (warpActive) {
|
|
2241
|
+
return inertRecordId;
|
|
2242
|
+
}
|
|
1434
2243
|
const result = executePluginCommand("scenario", {
|
|
1435
2244
|
subCommand: "record",
|
|
1436
2245
|
meta
|
|
@@ -1469,19 +2278,19 @@ function createStage() {
|
|
|
1469
2278
|
cmd = transformCommand(e);
|
|
1470
2279
|
} catch (err) {
|
|
1471
2280
|
console.error("Failed to transform scenario command:", err);
|
|
1472
|
-
|
|
2281
|
+
requestNextLine();
|
|
1473
2282
|
return;
|
|
1474
2283
|
}
|
|
1475
2284
|
const handler = commandHandlers.get(cmd.command);
|
|
1476
2285
|
if (!handler) {
|
|
1477
2286
|
console.warn(`[Stage] No handler registered for command "${cmd.command}". Auto-advancing.`);
|
|
1478
|
-
|
|
2287
|
+
requestNextLine();
|
|
1479
2288
|
return;
|
|
1480
2289
|
}
|
|
1481
2290
|
const { control, wasHandled } = buildControl();
|
|
1482
2291
|
handler(cmd, control);
|
|
1483
2292
|
if (!wasHandled()) {
|
|
1484
|
-
|
|
2293
|
+
requestNextLine();
|
|
1485
2294
|
}
|
|
1486
2295
|
}
|
|
1487
2296
|
function dispatchTextLine(e) {
|
|
@@ -1490,7 +2299,7 @@ function createStage() {
|
|
|
1490
2299
|
handler(e, control);
|
|
1491
2300
|
}
|
|
1492
2301
|
if (!wasHandled()) {
|
|
1493
|
-
|
|
2302
|
+
requestNextLine();
|
|
1494
2303
|
}
|
|
1495
2304
|
}
|
|
1496
2305
|
function invokeSkipCallbacks() {
|
|
@@ -1538,6 +2347,10 @@ function createStage() {
|
|
|
1538
2347
|
startAuto,
|
|
1539
2348
|
stopAuto,
|
|
1540
2349
|
isAutoing,
|
|
2350
|
+
startFastForward,
|
|
2351
|
+
stopFastForward,
|
|
2352
|
+
isFastForwarding,
|
|
2353
|
+
resetRuntimeState,
|
|
1541
2354
|
bindEvents
|
|
1542
2355
|
};
|
|
1543
2356
|
}
|
|
@@ -1610,23 +2423,33 @@ export {
|
|
|
1610
2423
|
createStaticNavigation,
|
|
1611
2424
|
executeNodeCommand,
|
|
1612
2425
|
executePluginCommand,
|
|
2426
|
+
fastForwardState,
|
|
2427
|
+
getAppStateAdapter,
|
|
1613
2428
|
getNavigator,
|
|
2429
|
+
getSeekingType,
|
|
1614
2430
|
getStageSize,
|
|
1615
2431
|
globalEventListeners,
|
|
1616
2432
|
globalRequestAnimationFrameListeners,
|
|
1617
2433
|
moyu_exports as moyu,
|
|
1618
2434
|
nextLine,
|
|
2435
|
+
registerAppStateAdapter,
|
|
1619
2436
|
setDefaultAutoTailMs,
|
|
1620
2437
|
setWaiting,
|
|
1621
2438
|
skipState,
|
|
2439
|
+
startDebugSession,
|
|
2440
|
+
startRuntimeDebugSession,
|
|
2441
|
+
stopDebugSession,
|
|
2442
|
+
stopRuntimeDebugSession,
|
|
1622
2443
|
useAutoBlocker,
|
|
1623
2444
|
useAutoTicket,
|
|
1624
2445
|
useBeforeHandleCommandCallback,
|
|
2446
|
+
useDebugSession,
|
|
1625
2447
|
useFadeIn,
|
|
1626
2448
|
useFadeInOut,
|
|
1627
2449
|
useFadeOut,
|
|
1628
2450
|
useInterruptCallback,
|
|
1629
2451
|
useIsAutoing,
|
|
2452
|
+
useIsSeeking,
|
|
1630
2453
|
useIsSkipping,
|
|
1631
2454
|
useNavigation,
|
|
1632
2455
|
useNavigationParams,
|
|
@@ -1635,5 +2458,6 @@ export {
|
|
|
1635
2458
|
useSkipBlocker,
|
|
1636
2459
|
useSkipCallback,
|
|
1637
2460
|
useSoundEffect,
|
|
1638
|
-
useStageContext
|
|
2461
|
+
useStageContext,
|
|
2462
|
+
warpState
|
|
1639
2463
|
};
|