Keep creation as a living DAG and archive playable products separately.
Opening accept no longer locks the graph; session.json stays creation-only while play starts from an instance snapshot. Sidebar products nest run saves, and play reading fills the feed at a denser type size. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -2292,7 +2292,23 @@ export function isCloserModule(
|
||||
name?: string,
|
||||
): boolean {
|
||||
if (module?.closer === true) return true;
|
||||
return (name ?? "").trim() === "开场白与开场变量";
|
||||
const t = (name ?? "").trim();
|
||||
return t === "开场白与开场变量" || t.startsWith("开场白与开场变量#") || t === "开场白";
|
||||
}
|
||||
|
||||
export function hasAcceptedCloserStep(
|
||||
flow: CreationFlow | null | undefined,
|
||||
acceptedStepIds: readonly string[],
|
||||
catalog?: ModuleCatalog | null,
|
||||
): boolean {
|
||||
if (flow?.steps.length) {
|
||||
return flow.steps.some(
|
||||
(s) =>
|
||||
isCloserModule(findModuleByName(catalog, s.name), s.name) &&
|
||||
isStepAccepted(s, acceptedStepIds),
|
||||
);
|
||||
}
|
||||
return acceptedStepIds.some((id) => isCloserModule(null, id));
|
||||
}
|
||||
|
||||
export function findCloserStepIndex(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* 开场白终节点:选定后落库、关 DAG。
|
||||
* 开场白终节点:选定后落库开场。不关 DAG;产物靠用户「保存」拆出。
|
||||
* 能力 `opening-setup` 与磁盘 worker `opening-generator` 共用这条收口。
|
||||
*/
|
||||
import {
|
||||
@@ -22,21 +22,34 @@ export const SLOT_CREATION_SEALED_BY_OPENING = "creationSealedByOpening";
|
||||
export const SLOT_OPENING_SELECTED_INDEX = "openingSelectedIndex";
|
||||
|
||||
export const CREATION_SEALED_WAITING_MESSAGE =
|
||||
"开场已选定,创作已收口并保存。可切换到「游玩」。";
|
||||
"开场已选定。可保存为产物后开玩,或继续补节点。";
|
||||
|
||||
export const INSTANCE_OPENING_SNAPSHOT_LABEL = "创作定稿(开场)";
|
||||
export const INSTANCE_OPENING_SNAPSHOT_LABEL = "定稿";
|
||||
|
||||
export function isOpeningLockTag(tag: string): boolean {
|
||||
const t = tag.trim();
|
||||
return t === OPENING_OUTPUT_TAG || t === OPENING_INITIAL_VARS_TAG;
|
||||
}
|
||||
|
||||
/** 收口步 id / name(含「开场白与开场变量#2」) */
|
||||
export function isCloserStepRef(id: string | undefined): boolean {
|
||||
const t = (id ?? "").trim();
|
||||
if (!t) return false;
|
||||
return (
|
||||
t === "开场白与开场变量" ||
|
||||
t.startsWith("开场白与开场变量#") ||
|
||||
t === "开场白"
|
||||
);
|
||||
}
|
||||
|
||||
export function isOpeningSealArtifact(artifact: {
|
||||
workerId?: string;
|
||||
stepId?: string;
|
||||
outputTags?: readonly string[];
|
||||
}): boolean {
|
||||
if ((artifact.workerId ?? "").trim() === "opening-generator") return true;
|
||||
return (artifact.outputTags ?? []).includes(OPENING_SETUP_ARTIFACT_TAG);
|
||||
if ((artifact.outputTags ?? []).includes(OPENING_SETUP_ARTIFACT_TAG)) return true;
|
||||
return isCloserStepRef(artifact.stepId);
|
||||
}
|
||||
|
||||
export type OpeningVariable = {
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
*/
|
||||
export const SLOT_PLAY_TURN_QUEUE = "playTurnQueue";
|
||||
export const SLOT_PLAY_LAYER_ACTIVE = "playLayerActive";
|
||||
/** 当前游玩线所依据的产物 snapshot id */
|
||||
export const SLOT_PLAY_INSTANCE_ID = "playInstanceId";
|
||||
|
||||
export const PLAY_WORKING_SNAPSHOT_ID = "play-working";
|
||||
export const PLAY_WORKING_SNAPSHOT_LABEL = "当前游玩";
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
import type { Blackboard } from "../blackboard/blackboard.js";
|
||||
import type { RuntimeSession } from "../types/runtime.js";
|
||||
import { isPlayLayerActive } from "./play-turn.js";
|
||||
import {
|
||||
SLOT_CREATION_ACCEPTED_UNITS,
|
||||
parseAcceptedUnits,
|
||||
} from "./creation-units.js";
|
||||
import {
|
||||
isCloserStepRef,
|
||||
SLOT_CREATION_SEALED_BY_OPENING,
|
||||
} from "./opening-seal.js";
|
||||
import {
|
||||
deriveDesignStageScope,
|
||||
deriveOnDemandWorkerScope,
|
||||
@@ -41,8 +49,14 @@ export function hasAcceptedWorkerSet(session: RuntimeSession): boolean {
|
||||
);
|
||||
}
|
||||
|
||||
function hasAcceptedCloser(session: RuntimeSession): boolean {
|
||||
if (Boolean(session.slots[SLOT_CREATION_SEALED_BY_OPENING])) return true;
|
||||
const accepted = parseAcceptedUnits(session.slots[SLOT_CREATION_ACCEPTED_UNITS]);
|
||||
return accepted.some((id) => isCloserStepRef(id));
|
||||
}
|
||||
|
||||
export function canEnterPlay(session: RuntimeSession): boolean {
|
||||
return hasAcceptedWorkerSet(session);
|
||||
return hasAcceptedWorkerSet(session) || hasAcceptedCloser(session);
|
||||
}
|
||||
|
||||
export function inferLifecycleStage(session: RuntimeSession): LifecycleStage {
|
||||
|
||||
Reference in New Issue
Block a user