@oh-story/dsh 0.1.6 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +10 -8
  2. package/lib/client.js +298 -87
  3. package/lib/client.js.map +4 -4
  4. package/lib/drama/manifest.json +34 -34
  5. package/lib/drama/skills/short-drama/SKILL.md +4 -1
  6. package/lib/drama/skills/short-drama/references/contract-and-ownership.md +2 -0
  7. package/lib/drama/skills/short-drama/references/creator-documents.md +30 -4
  8. package/lib/drama/skills/short-drama/references/creator-workflow.md +8 -2
  9. package/lib/drama/skills/short-drama/references/reference-roles.md +16 -2
  10. package/lib/drama/skills/short-drama/scripts/creator_markdown_check.py +328 -48
  11. package/lib/drama/skills/short-drama-produce/SKILL.md +4 -1
  12. package/lib/drama/skills/short-drama-produce/scripts/production_tool.py +34 -2
  13. package/lib/drama/skills/short-drama-storyboard/SKILL.md +27 -5
  14. package/lib/drama/skills/short-drama-storyboard/references/review-and-fixtures.md +2 -1
  15. package/lib/drama/skills/short-drama-storyboard/references/stage-contract.md +2 -2
  16. package/lib/drama/skills/short-drama-video-prompts/SKILL.md +11 -2
  17. package/lib/drama/skills/short-drama-video-prompts/assets/video-prompts.md +6 -1
  18. package/lib/drama/skills/short-drama-video-prompts/references/minimax-h3.md +19 -3
  19. package/lib/drama/skills/short-drama-video-prompts/references/stage-contract.md +8 -2
  20. package/lib/drama/skills/short-drama-video-prompts/references/target-model-profile.md +1 -0
  21. package/lib/index.js +194 -62
  22. package/lib/index.js.map +4 -4
  23. package/lib/types/client/drama-production-view.d.ts +1 -0
  24. package/lib/types/client/drama-production-view.d.ts.map +1 -1
  25. package/lib/types/client/drama-production.d.ts +3 -0
  26. package/lib/types/client/drama-production.d.ts.map +1 -1
  27. package/lib/types/client/index.d.ts.map +1 -1
  28. package/lib/types/client/video-studio.d.ts +2 -1
  29. package/lib/types/client/video-studio.d.ts.map +1 -1
  30. package/lib/types/client/workbench-presence.d.ts +29 -0
  31. package/lib/types/client/workbench-presence.d.ts.map +1 -0
  32. package/lib/types/drama-adapters.d.ts +65 -0
  33. package/lib/types/drama-adapters.d.ts.map +1 -0
  34. package/lib/types/host-python.d.ts +19 -0
  35. package/lib/types/host-python.d.ts.map +1 -0
  36. package/lib/types/index.d.ts +1 -0
  37. package/lib/types/index.d.ts.map +1 -1
  38. package/lib/types/skill-provider.d.ts +1 -1
  39. package/lib/types/skill-provider.d.ts.map +1 -1
  40. package/lib/types/workspace-route.d.ts.map +1 -1
  41. package/package.json +41 -41
package/lib/client.js CHANGED
@@ -560,10 +560,11 @@ function parseEpisodeProduction(documents, episodeDirectory) {
560
560
  let storyboardPath = `${episodeDirectory}/\u5206\u955C.md`, imagePromptPath = `${episodeDirectory}/\u56FE\u7247\u63D0\u793A\u8BCD.md`, videoPromptPath = `${episodeDirectory}/\u89C6\u9891\u63D0\u793A\u8BCD.md`, visualPath = `${episodeDirectory}/\u89C6\u89C9\u8BBE\u5B9A.md`, shots = parseStoryboard(storyboardPath, documents[storyboardPath] ?? ""), assets = parseImagePrompts(imagePromptPath, documents[imagePromptPath] ?? ""), motions = parseVideoPrompts(videoPromptPath, documents[videoPromptPath] ?? ""), visualAssets = parseVisualAssets(visualPath, documents[visualPath] ?? ""), motionByShot = new Map(motions.flatMap((motion) => motion.shotId === void 0 ? [] : [[motion.shotId, motion]])), linkedShots = shots.map((shot) => ({ ...shot, motion: motionByShot.get(shot.id) })), targets = /* @__PURE__ */ new Map();
561
561
  for (let item of [...linkedShots, ...assets, ...motions, ...visualAssets])
562
562
  targets.set(item.id, { path: item.path, offset: item.offset, id: item.id });
563
+ let screenplayPath = `${episodeDirectory}/\u5267\u672C.md`;
563
564
  for (let shot of linkedShots)
564
- if (shot.source !== void 0) {
565
- let screenplayPath = `${episodeDirectory}/\u5267\u672C.md`, target = sectionTarget(screenplayPath, documents[screenplayPath] ?? "", shot.source);
566
- target !== void 0 && targets.set(shot.source, target);
565
+ for (let id of sourceKeys(shot)) {
566
+ let target = sectionTarget(screenplayPath, documents[screenplayPath] ?? "", id);
567
+ target !== void 0 && targets.set(id, target);
567
568
  }
568
569
  let diagnostics = validateProductionProtocol({
569
570
  documents,
@@ -589,13 +590,14 @@ function parseStoryboard(path, content) {
589
590
  return levelTwoSections(content).flatMap((section) => {
590
591
  let match = /^(SHOT-[A-Z0-9-]+)\s*(?:[·||]\s*)?(.*)$/iu.exec(section.heading.trim());
591
592
  if (match === null || match[1] === void 0) return [];
592
- let fields = bulletFields(section.body), id = match[1].toLocaleUpperCase();
593
+ let fields = bulletFields(section.body), id = match[1].toLocaleUpperCase(), source = firstField(fields, "\u6765\u6E90", "\u573A\u6B21");
593
594
  return [{
594
595
  id,
595
596
  title: match[2]?.trim() || id,
596
597
  path,
597
598
  offset: section.offset,
598
- source: firstField(fields, "\u6765\u6E90", "\u573A\u6B21"),
599
+ source,
600
+ sceneIds: sourceSceneIds(source),
599
601
  durationSeconds: seconds(firstField(fields, "\u65F6\u957F")),
600
602
  purpose: firstField(fields, "\u76EE\u7684", "\u955C\u5934\u76EE\u7684"),
601
603
  shotSpec: firstField(fields, "\u666F\u522B/\u673A\u4F4D", "\u666F\u522B", "\u955C\u5934\u89C4\u683C"),
@@ -663,7 +665,8 @@ function validateProductionProtocol(input) {
663
665
  for (let shot of input.shots) {
664
666
  for (let reference of shot.references)
665
667
  knownReferences.has(reference) || add({ severity: "warning", code: "unknown_reference", path: shot.path, offset: shot.offset, targetId: shot.id, message: `${shot.id} \u5F15\u7528\u4E86\u672A\u89E3\u6790\u7684 ${reference}\u3002` });
666
- shot.source !== void 0 && sectionTarget(screenplayPath, input.documents[screenplayPath] ?? "", shot.source) === void 0 && add({ severity: "warning", code: "unknown_source", path: shot.path, offset: shot.offset, targetId: shot.id, message: `${shot.id} \u7684\u6765\u6E90 ${shot.source} \u5728\u5267\u672C\u4E2D\u4E0D\u5B58\u5728\u3002` });
668
+ for (let id of sourceKeys(shot))
669
+ sectionTarget(screenplayPath, input.documents[screenplayPath] ?? "", id) === void 0 && add({ severity: "warning", code: "unknown_source", path: shot.path, offset: shot.offset, targetId: shot.id, message: `${shot.id} \u7684\u6765\u6E90 ${id} \u5728\u5267\u672C\u4E2D\u4E0D\u5B58\u5728\u3002` });
667
670
  }
668
671
  let shots = new Set(input.shots.map((shot) => shot.id)), motionsByShot = /* @__PURE__ */ new Map();
669
672
  for (let motion of input.motions) {
@@ -739,6 +742,12 @@ function slug(value) {
739
742
  function lineAt(content, offset) {
740
743
  return content.slice(0, Math.max(0, offset)).split(/\r?\n/u).length;
741
744
  }
745
+ function sourceSceneIds(source) {
746
+ return source === void 0 ? [] : [...new Set([...source.matchAll(/(?:[A-Za-z0-9]+-)+SC[0-9]+/gu)].map((match) => match[0]))];
747
+ }
748
+ function sourceKeys(shot) {
749
+ return shot.sceneIds.length > 0 ? shot.sceneIds : shot.source === void 0 ? [] : [shot.source];
750
+ }
742
751
  function sectionTarget(path, content, id) {
743
752
  let offset = content.search(new RegExp(`^##\\s+${id.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&")}(?:\\s|$)`, "imu"));
744
753
  return offset < 0 ? void 0 : { path, offset, id };
@@ -751,6 +760,19 @@ function creatorDocumentOrder(path) {
751
760
  // src/client/drama-production-view.tsx
752
761
  var import_react = require("react");
753
762
 
763
+ // src/client/workbench-ui.ts
764
+ function handleTabKey(event, values, current, select) {
765
+ let index;
766
+ if (event.key === "Home" ? index = 0 : event.key === "End" ? index = values.length - 1 : event.key === "ArrowRight" ? index = (values.indexOf(current) + 1) % values.length : event.key === "ArrowLeft" && (index = (values.indexOf(current) - 1 + values.length) % values.length), index === void 0) return;
767
+ event.preventDefault();
768
+ let value = values[index];
769
+ value !== void 0 && (select(value), event.currentTarget.parentElement?.querySelectorAll("[role='tab']")[index]?.focus());
770
+ }
771
+ function endpoint(path, sessionId, file) {
772
+ let url = new URL(`/oh-story/${path}`, globalThis.location.origin);
773
+ return url.searchParams.set("sessionId", sessionId), file !== void 0 && url.searchParams.set("path", file), url.toString();
774
+ }
775
+
754
776
  // src/client/production-prompts.ts
755
777
  var authorityBoundary = "\u53EA\u4F7F\u7528\u5F53\u524D DSH Preset \u53EF\u89C1\u7684\u5DE5\u5177\uFF1B\u6240\u6709\u6587\u4EF6\u3001\u7F51\u7EDC\u3001\u751F\u6210\u548C\u547D\u4EE4\u64CD\u4F5C\u7EE7\u7EED\u9075\u5B88 DSH \u6743\u9650\u4E0E\u5BA1\u6279\u3002";
756
778
  function nativeProductionPrompt(production, job, references) {
@@ -905,7 +927,53 @@ function reorderSequence(sequence, source, target) {
905
927
  }
906
928
 
907
929
  // src/client/drama-production-view.tsx
908
- var import_jsx_runtime3 = require("react/jsx-runtime"), SECTION_LABELS = { shots: "\u955C\u5934", assets: "\u7D20\u6750", tasks: "\u4EFB\u52A1", sequence: "\u6210\u7247", canvas: "\u753B\u5E03" }, SECTION_ORDER = Object.keys(SECTION_LABELS), STATUS_LABELS = { awaiting_confirmation: "\u7B49\u5F85\u786E\u8BA4", pending: "\u5DF2\u63D0\u4EA4", running: "DSH \u6267\u884C\u4E2D", dispatched_unknown: "\u5F85\u6838\u5BF9", succeeded: "\u5DF2\u5B8C\u6210", failed: "\u5931\u8D25", canceled: "\u5DF2\u53D6\u6D88" }, ASSET_KIND_LABEL = { character: "\u4EBA\u7269", scene: "\u573A\u666F", prop: "\u9053\u5177", state: "\u72B6\u6001", unknown: "\u8BBE\u5B9A" }, JOB_KIND_LABEL = { image: "\u56FE\u7247", video: "\u89C6\u9891", composition: "\u6210\u7247" };
930
+ var import_jsx_runtime3 = require("react/jsx-runtime"), SECTION_LABELS = { shots: "\u955C\u5934", assets: "\u7D20\u6750", tasks: "\u4EFB\u52A1", sequence: "\u6210\u7247", canvas: "\u753B\u5E03" }, SECTION_ORDER = Object.keys(SECTION_LABELS), STATUS_LABELS = { awaiting_confirmation: "\u7B49\u5F85\u786E\u8BA4", pending: "\u5DF2\u63D0\u4EA4", running: "DSH \u6267\u884C\u4E2D", dispatched_unknown: "\u5F85\u6838\u5BF9", succeeded: "\u5DF2\u5B8C\u6210", failed: "\u5931\u8D25", canceled: "\u5DF2\u53D6\u6D88" }, ASSET_KIND_LABEL = { character: "\u4EBA\u7269", scene: "\u573A\u666F", prop: "\u9053\u5177", state: "\u72B6\u6001", unknown: "\u8BBE\u5B9A" }, JOB_KIND_LABEL = { image: "\u56FE\u7247", video: "\u89C6\u9891", composition: "\u6210\u7247" }, MODALITY_LABEL = { image: "\u56FE\u7247", video: "\u89C6\u9891", music: "\u97F3\u4E50" };
931
+ function ProductionEnvironment({ sessionId }) {
932
+ let [preflight, setPreflight] = (0, import_react.useState)(), [attempt, setAttempt] = (0, import_react.useState)(0);
933
+ (0, import_react.useEffect)(() => {
934
+ let controller = new AbortController();
935
+ return fetch(endpoint("drama-preflight", sessionId), { signal: controller.signal }).then(async (response) => {
936
+ if (!response.ok) throw new Error(`HTTP ${String(response.status)}`);
937
+ let summary = await response.json();
938
+ controller.signal.aborted || setPreflight(summary);
939
+ }).catch(() => {
940
+ controller.signal.aborted || setPreflight("failed");
941
+ }), () => {
942
+ controller.abort();
943
+ };
944
+ }, [attempt, sessionId]);
945
+ let unconfigured = typeof preflight == "object" ? preflight.adapters.filter((adapter) => !adapter.configured) : [];
946
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "oh-story-production-environment", role: "status", "aria-label": "\u5A92\u4F53\u751F\u6210\u73AF\u5883", children: [
947
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: "\u751F\u6210\u73AF\u5883" }),
948
+ preflight === void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { "data-pending": !0, children: "\u68C0\u67E5\u4E2D\u2026" }),
949
+ preflight === "failed" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", onClick: () => {
950
+ setPreflight(void 0), setAttempt((value) => value + 1);
951
+ }, children: "\u73AF\u5883\u68C0\u67E5\u5931\u8D25 \xB7 \u91CD\u8BD5" }),
952
+ typeof preflight == "object" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
953
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { "data-ready": preflight.python.ok || void 0, children: [
954
+ "Python ",
955
+ preflight.python.version ?? "\u672A\u627E\u5230"
956
+ ] }),
957
+ preflight.adapters.map((adapter) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { "data-ready": adapter.configured || void 0, title: adapter.configured ? `${adapter.name} \u5DF2\u914D\u7F6E` : `\u7F3A\u5C11\u73AF\u5883\u53D8\u91CF ${adapter.missing.join("\u3001")}`, children: [
958
+ MODALITY_LABEL[adapter.modality],
959
+ " ",
960
+ adapter.label,
961
+ adapter.configured ? "" : ` \xB7 \u7F3A ${adapter.missing.join("\u3001")}`
962
+ ] }, adapter.name)),
963
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("em", { children: [
964
+ "DeepSeek \u53EA\u8D1F\u8D23\u5199\u63D0\u793A\u8BCD\uFF1B\u56FE\u7247\u3001\u89C6\u9891\u3001\u97F3\u4E50\u7531\u4E0A\u9762\u7684\u4F9B\u5E94\u5546 API \u751F\u6210\uFF0CKey \u5728\u542F\u52A8 DSH \u524D\u5199\u5165\u5BBF\u4E3B\u673A\u73AF\u5883\u53D8\u91CF\u3002",
965
+ unconfigured.length === preflight.adapters.length && " \u5F53\u524D\u4E00\u4E2A\u90FD\u6CA1\u914D\u7F6E\uFF0C\u751F\u4EA7\u4EFB\u52A1\u4F1A\u505C\u5728 adapter \u4E4B\u524D\u3002",
966
+ " ",
967
+ "Adapter \u914D\u7F6E",
968
+ preflight.adapterConfig.generated ? "\u5DF2\u81EA\u52A8\u767B\u8BB0" : "\u4F7F\u7528\u81EA\u5B9A\u4E49\u6587\u4EF6",
969
+ preflight.adapterConfig.ok ? "" : "\uFF08\u5199\u5165\u5931\u8D25\uFF09",
970
+ "\uFF1A",
971
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("code", { children: preflight.adapterConfig.path }),
972
+ "\u3002\u8BE6\u89C1 README\u300C\u5A92\u4F53\u751F\u6210 API\u300D\u3002"
973
+ ] })
974
+ ] })
975
+ ] });
976
+ }
909
977
  function handleSectionKey(event, current, onChange) {
910
978
  let index = SECTION_ORDER.indexOf(current), next = event.key === "Home" ? 0 : event.key === "End" ? SECTION_ORDER.length - 1 : event.key === "ArrowRight" ? (index + 1) % SECTION_ORDER.length : event.key === "ArrowLeft" ? (index - 1 + SECTION_ORDER.length) % SECTION_ORDER.length : void 0;
911
979
  next !== void 0 && (event.preventDefault(), onChange(SECTION_ORDER[next]), event.currentTarget.parentElement?.querySelectorAll("[role='tab']")[next]?.focus());
@@ -1006,6 +1074,7 @@ ${item.prompt}`).join(`
1006
1074
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", onClick: props.onRefresh, children: "\u5237\u65B0" })
1007
1075
  ] })
1008
1076
  ] }),
1077
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ProductionEnvironment, { sessionId: props.sessionId }),
1009
1078
  notice !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "oh-story-production-notice", role: "status", children: [
1010
1079
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: notice }),
1011
1080
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", "aria-label": "\u5173\u95ED\u63D0\u793A", onClick: () => {
@@ -1083,7 +1152,7 @@ function ShotBoard(props) {
1083
1152
  ] })
1084
1153
  ] }),
1085
1154
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "oh-story-reference-links", children: [
1086
- shot.source !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ReferenceButton, { id: shot.source, production: props.production, onNavigate: props.onNavigate }),
1155
+ shot.sceneIds.length > 0 ? shot.sceneIds.map((sceneId) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ReferenceButton, { id: sceneId, production: props.production, onNavigate: props.onNavigate }, sceneId)) : shot.source !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ReferenceButton, { id: shot.source, production: props.production, onNavigate: props.onNavigate }),
1087
1156
  shot.references.map((id) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ReferenceButton, { id, production: props.production, onNavigate: props.onNavigate }, id))
1088
1157
  ] }),
1089
1158
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "oh-story-card-actions", children: [
@@ -1419,21 +1488,6 @@ function settledProductionIntents(chat) {
1419
1488
 
1420
1489
  // src/client/video-studio.tsx
1421
1490
  var import_react2 = require("react");
1422
-
1423
- // src/client/workbench-ui.ts
1424
- function handleTabKey(event, values, current, select) {
1425
- let index;
1426
- if (event.key === "Home" ? index = 0 : event.key === "End" ? index = values.length - 1 : event.key === "ArrowRight" ? index = (values.indexOf(current) + 1) % values.length : event.key === "ArrowLeft" && (index = (values.indexOf(current) - 1 + values.length) % values.length), index === void 0) return;
1427
- event.preventDefault();
1428
- let value = values[index];
1429
- value !== void 0 && (select(value), event.currentTarget.parentElement?.querySelectorAll("[role='tab']")[index]?.focus());
1430
- }
1431
- function endpoint(path, sessionId, file) {
1432
- let url = new URL(`/oh-story/${path}`, globalThis.location.origin);
1433
- return url.searchParams.set("sessionId", sessionId), file !== void 0 && url.searchParams.set("path", file), url.toString();
1434
- }
1435
-
1436
- // src/client/video-studio.tsx
1437
1491
  var import_jsx_runtime4 = require("react/jsx-runtime");
1438
1492
  function preferredPreview(project) {
1439
1493
  return project.previews.find((item) => item.role === "final") ?? project.previews.find((item) => item.role === "edited") ?? project.previews.find((item) => item.role === "source");
@@ -1644,7 +1698,8 @@ function VideoStudio({
1644
1698
  labelledBy,
1645
1699
  onProject,
1646
1700
  onTab,
1647
- onWorkbench
1701
+ onWorkbench,
1702
+ onCollapse
1648
1703
  }) {
1649
1704
  let project = projects.find((item) => item.id === projectId) ?? projects[0], tabsId = (0, import_react2.useId)();
1650
1705
  (0, import_react2.useEffect)(() => {
@@ -1653,23 +1708,26 @@ function VideoStudio({
1653
1708
  let tabs = ["preview", "artifacts"];
1654
1709
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("main", { id: paneId, className: "oh-video-studio", role: "tabpanel", "aria-labelledby": labelledBy, hidden, children: [
1655
1710
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("header", { className: "oh-video-toolbar", children: [
1656
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "oh-video-mode-tabs", role: "tablist", "aria-label": "\u521B\u4F5C\u5DE5\u4F5C\u53F0", children: workbenches.map((mode) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1657
- "button",
1658
- {
1659
- type: "button",
1660
- role: "tab",
1661
- "aria-selected": mode === "video",
1662
- tabIndex: mode === "video" ? 0 : -1,
1663
- onKeyDown: (event) => {
1664
- handleTabKey(event, workbenches, "video", onWorkbench);
1665
- },
1666
- onClick: () => {
1667
- onWorkbench(mode);
1711
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "oh-workbench-cluster", children: [
1712
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "oh-video-mode-tabs", role: "tablist", "aria-label": "\u521B\u4F5C\u5DE5\u4F5C\u53F0", children: workbenches.map((mode) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1713
+ "button",
1714
+ {
1715
+ type: "button",
1716
+ role: "tab",
1717
+ "aria-selected": mode === "video",
1718
+ tabIndex: mode === "video" ? 0 : -1,
1719
+ onKeyDown: (event) => {
1720
+ handleTabKey(event, workbenches, "video", onWorkbench);
1721
+ },
1722
+ onClick: () => {
1723
+ onWorkbench(mode);
1724
+ },
1725
+ children: workbenchLabel(mode)
1668
1726
  },
1669
- children: workbenchLabel(mode)
1670
- },
1671
- mode
1672
- )) }),
1727
+ mode
1728
+ )) }),
1729
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { className: "oh-workbench-collapse", type: "button", title: "\u6536\u8D77\u521B\u4F5C\u5DE5\u4F5C\u53F0", "aria-label": "\u6536\u8D77\u521B\u4F5C\u5DE5\u4F5C\u53F0", onClick: onCollapse, children: "\xD7" })
1730
+ ] }),
1673
1731
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "oh-video-project", children: [
1674
1732
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "\u89C6\u9891\u9879\u76EE" }),
1675
1733
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("select", { "aria-label": "\u89C6\u9891\u9879\u76EE", value: project?.id ?? "", disabled: project === void 0, onChange: (event) => {
@@ -1715,14 +1773,77 @@ function VideoStudio({
1715
1773
  ] });
1716
1774
  }
1717
1775
 
1776
+ // src/client/workbench-presence.ts
1777
+ function hasCreativeProject(workspace) {
1778
+ return workspace === void 0 ? !1 : workspace.files.length > 0 || workspace.videos.length > 0 || workspace.games.some((game) => game.source === "workspace");
1779
+ }
1780
+ function resolveWorkbenchOpen(preference, creativeProject) {
1781
+ return preference === void 0 ? creativeProject : preference === "open";
1782
+ }
1783
+ function workbenchPreferenceKey(cwd) {
1784
+ return `oh-story.workbench.${cwd}`;
1785
+ }
1786
+ function readWorkbenchPreference(storage, cwd) {
1787
+ if (storage === void 0 || cwd === void 0) return;
1788
+ let value;
1789
+ try {
1790
+ value = storage.getItem(workbenchPreferenceKey(cwd));
1791
+ } catch {
1792
+ return;
1793
+ }
1794
+ return value === "open" || value === "closed" ? value : void 0;
1795
+ }
1796
+ function writeWorkbenchPreference(storage, cwd, preference) {
1797
+ if (!(storage === void 0 || cwd === void 0))
1798
+ try {
1799
+ storage.setItem(workbenchPreferenceKey(cwd), preference);
1800
+ } catch {
1801
+ }
1802
+ }
1803
+ function workbenchPreferenceStorage() {
1804
+ try {
1805
+ return globalThis.localStorage;
1806
+ } catch {
1807
+ return;
1808
+ }
1809
+ }
1810
+
1718
1811
  // inline-css:/home/runner/work/oh-story-dsh/oh-story-dsh/packages/dsh-plugin/src/client/plugin.css
1719
1812
  var plugin_default = `.oh-story-bridge-marker { display: none; }
1720
1813
  .oh-story-split-surface { display: contents; font-family: var(--dsw-font-family); }
1721
1814
 
1815
+ /* Collapsed, the plugin owns nothing but this control: DSH renders the
1816
+ conversation exactly as it does without the plugin installed. The launcher is
1817
+ fixed to the conversation column's own corner, which the bridge publishes,
1818
+ because the surrounding shell is not ours to place things in. */
1819
+ .oh-story-launcher {
1820
+ box-sizing: border-box;
1821
+ display: flex;
1822
+ position: fixed;
1823
+ z-index: 9;
1824
+ top: calc(var(--oh-story-seam-top, 0px) + 10px);
1825
+ right: calc(var(--oh-story-seam-right, 0px) + 14px);
1826
+ min-height: 28px;
1827
+ align-items: center;
1828
+ gap: 6px;
1829
+ border: 1px solid var(--dsw-alias-border-l2);
1830
+ border-radius: 999px;
1831
+ color: var(--dsw-alias-label-secondary);
1832
+ background: var(--dsw-alias-bg-base);
1833
+ padding: 3px 11px;
1834
+ cursor: pointer;
1835
+ font-family: var(--dsw-font-family);
1836
+ font-size: 12px;
1837
+ line-height: 20px;
1838
+ }
1839
+ .oh-story-launcher b { font-weight: 500; }
1840
+ .oh-story-launcher:hover { color: var(--dsw-alias-label-primary); background: var(--dsw-alias-interactive-bg-hover); }
1841
+ .oh-story-launcher:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary); outline-offset: 2px; }
1842
+
1722
1843
  /* DSH documents every [data-slot] wrapper as a stable addressable styling
1723
1844
  seam. The official Session body and composer stay mounted; this only turns
1724
1845
  their scroll host into a three-column writing surface. */
1725
- [data-conversation-scroll]:has(> [data-slot="conversation.session"] > .oh-story-split-surface) {
1846
+ [data-conversation-scroll]:has(> [data-slot="conversation.session"] > .oh-story-split-surface[data-open="true"]) {
1726
1847
  --os-border: var(--dsw-alias-border-l2);
1727
1848
  --os-muted: var(--dsw-alias-label-secondary);
1728
1849
  display: grid;
@@ -1737,7 +1858,7 @@ var plugin_default = `.oh-story-bridge-marker { display: none; }
1737
1858
  }
1738
1859
 
1739
1860
  /* Keep the final Chat flow above the overlapping official Composer. */
1740
- [data-conversation-scroll]:has(> [data-slot="conversation.session"] > .oh-story-split-surface)
1861
+ [data-conversation-scroll]:has(> [data-slot="conversation.session"] > .oh-story-split-surface[data-open="true"])
1741
1862
  > [data-slot="conversation.session"] > :not(.oh-story-split-surface) {
1742
1863
  grid-column: 3;
1743
1864
  grid-row: 1;
@@ -1746,12 +1867,12 @@ var plugin_default = `.oh-story-bridge-marker { display: none; }
1746
1867
  border-left: 1px solid var(--os-border);
1747
1868
  }
1748
1869
 
1749
- [data-conversation-scroll]:has(> [data-slot="conversation.session"] > .oh-story-split-surface)
1870
+ [data-conversation-scroll]:has(> [data-slot="conversation.session"] > .oh-story-split-surface[data-open="true"])
1750
1871
  [data-chat-flow] {
1751
1872
  padding-bottom: calc(max(var(--dsh-composer-height, 152px), var(--oh-story-composer-height, 0px)) + 16px);
1752
1873
  }
1753
1874
 
1754
- [data-conversation-scroll]:has(> [data-slot="conversation.session"] > .oh-story-split-surface)
1875
+ [data-conversation-scroll]:has(> [data-slot="conversation.session"] > .oh-story-split-surface[data-open="true"])
1755
1876
  > [data-composer-seat] {
1756
1877
  grid-column: 3;
1757
1878
  grid-row: 1;
@@ -1765,7 +1886,7 @@ var plugin_default = `.oh-story-bridge-marker { display: none; }
1765
1886
 
1766
1887
  /* Game mode keeps the official Conversation on the right but merges the two
1767
1888
  creator columns into one playable Studio. */
1768
- [data-conversation-scroll][data-oh-story-workbench="game"]:has(> [data-slot="conversation.session"] > .oh-story-split-surface) {
1889
+ [data-conversation-scroll][data-oh-story-workbench="game"]:has(> [data-slot="conversation.session"] > .oh-story-split-surface[data-open="true"]) {
1769
1890
  --game-stage: #0d100e;
1770
1891
  --game-stage-raised: #161a17;
1771
1892
  --game-accent: var(--dsw-alias-state-business-primary);
@@ -1775,9 +1896,9 @@ var plugin_default = `.oh-story-bridge-marker { display: none; }
1775
1896
  overflow: hidden;
1776
1897
  }
1777
1898
 
1778
- [data-conversation-scroll][data-oh-story-workbench="game"]:has(> [data-slot="conversation.session"] > .oh-story-split-surface)
1899
+ [data-conversation-scroll][data-oh-story-workbench="game"]:has(> [data-slot="conversation.session"] > .oh-story-split-surface[data-open="true"])
1779
1900
  > [data-slot="conversation.session"] > :not(.oh-story-split-surface),
1780
- [data-conversation-scroll][data-oh-story-workbench="game"]:has(> [data-slot="conversation.session"] > .oh-story-split-surface)
1901
+ [data-conversation-scroll][data-oh-story-workbench="game"]:has(> [data-slot="conversation.session"] > .oh-story-split-surface[data-open="true"])
1781
1902
  > [data-composer-seat] { grid-column: 2; }
1782
1903
 
1783
1904
  /* DSH 0.1.2 lays two 40px column-resize strips (z-index 8) over the whole
@@ -2053,6 +2174,27 @@ var plugin_default = `.oh-story-bridge-marker { display: none; }
2053
2174
  .oh-story-role button:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary); outline-offset: -2px; }
2054
2175
  .oh-story-save:disabled { opacity: .48; cursor: default; }
2055
2176
 
2177
+ .oh-story-brand-actions { display: flex; flex: none; align-items: center; gap: 2px; }
2178
+
2179
+ .oh-workbench-cluster { display: flex; min-width: 0; align-items: center; gap: 6px; }
2180
+ .oh-workbench-collapse {
2181
+ display: grid;
2182
+ width: 28px;
2183
+ height: 28px;
2184
+ flex: none;
2185
+ place-items: center;
2186
+ border: 0;
2187
+ border-radius: 5px;
2188
+ color: var(--os-muted);
2189
+ background: transparent;
2190
+ padding: 0;
2191
+ cursor: pointer;
2192
+ font: inherit;
2193
+ font-size: 16px;
2194
+ }
2195
+ .oh-workbench-collapse:hover { color: var(--dsw-alias-label-primary); background: var(--dsw-alias-interactive-bg-hover); }
2196
+ .oh-workbench-collapse:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary); outline-offset: -2px; }
2197
+
2056
2198
  .oh-story-mode-tabs { display: flex; margin: 0 4px 8px; padding: 2px; border: 1px solid var(--os-border); border-radius: 7px; background: var(--dsw-alias-bg-layer-1); }
2057
2199
 
2058
2200
  .oh-story-mode-tabs button,
@@ -2313,6 +2455,16 @@ var plugin_default = `.oh-story-bridge-marker { display: none; }
2313
2455
  .oh-story-production-summary { color: var(--os-muted); white-space: nowrap; }
2314
2456
  .oh-story-production-notice { justify-content: space-between; margin: 8px 12px 0; padding: 7px 9px; border: 1px solid var(--os-border); border-radius: 7px; color: var(--dsw-alias-label-secondary); background: var(--dsw-alias-bg-layer-1); }
2315
2457
  .oh-story-production-notice button { border: 0; background: transparent; }
2458
+ .oh-story-production-environment { display: flex; min-width: 0; flex-wrap: wrap; align-items: center; gap: 5px 10px; margin: 8px 12px 0; padding: 7px 9px; border: 1px solid var(--os-border); border-radius: 7px; color: var(--os-muted); background: var(--dsw-alias-bg-layer-1); font-size: 10px; }
2459
+ /* Environment names such as MINIMAX_VIDEO_RESOLUTIONS and the temp-dir path are longer than the 500 px editor column; let them break rather than widen the view. */
2460
+ .oh-story-production-environment > * { min-width: 0; max-width: 100%; overflow-wrap: anywhere; }
2461
+ .oh-story-production-environment strong { color: var(--dsw-alias-label-secondary); font-size: 11px; }
2462
+ .oh-story-production-environment span::before { content: "\u25CF"; margin-right: 4px; color: var(--video-danger, #d9534f); }
2463
+ .oh-story-production-environment span[data-ready]::before { color: var(--dsw-alias-state-success-primary, #45b96f); }
2464
+ .oh-story-production-environment span[data-pending]::before { color: var(--os-muted); }
2465
+ .oh-story-production-environment em { flex-basis: 100%; font-style: normal; line-height: 1.5; }
2466
+ .oh-story-production-environment code { font-size: 10px; overflow-wrap: anywhere; }
2467
+ .oh-story-production-environment button { min-height: 24px; border: 1px solid var(--os-border); border-radius: 6px; padding: 0 8px; color: inherit; background: var(--dsw-alias-bg-base); cursor: pointer; font: inherit; }
2316
2468
  .oh-story-production-diagnostics { margin: 8px 12px 0; padding: 7px 9px; border: 1px solid var(--dsw-alias-state-warn-label); border-radius: 7px; background: var(--dsw-specific-tip); }
2317
2469
  .oh-story-production-diagnostics summary { color: var(--dsw-alias-state-warn-label); cursor: pointer; }
2318
2470
  .oh-story-production-diagnostics ul { display: grid; gap: 4px; margin: 8px 0 0; padding: 0; list-style: none; }
@@ -2436,11 +2588,11 @@ var plugin_default = `.oh-story-bridge-marker { display: none; }
2436
2588
  .oh-story-canvas article span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
2437
2589
  .oh-story-canvas article span { color: var(--os-muted); font-size: 10px; }
2438
2590
 
2439
- [data-conversation-scroll][data-oh-story-layout="medium"]:has(> [data-slot="conversation.session"] > .oh-story-split-surface) {
2591
+ [data-conversation-scroll][data-oh-story-layout="medium"]:has(> [data-slot="conversation.session"] > .oh-story-split-surface[data-open="true"]) {
2440
2592
  grid-template-columns: clamp(104px, 18%, 184px) minmax(200px, 1fr) clamp(300px, 45%, 408px);
2441
2593
  }
2442
2594
 
2443
- [data-conversation-scroll][data-oh-story-layout="compact"]:has(> [data-slot="conversation.session"] > .oh-story-split-surface) {
2595
+ [data-conversation-scroll][data-oh-story-layout="compact"]:has(> [data-slot="conversation.session"] > .oh-story-split-surface[data-open="true"]) {
2444
2596
  grid-template-columns: clamp(80px, 16%, 104px) minmax(0, 1fr) clamp(228px, 48%, 300px);
2445
2597
  }
2446
2598
 
@@ -2483,12 +2635,12 @@ var plugin_default = `.oh-story-bridge-marker { display: none; }
2483
2635
  [data-oh-story-layout="compact"] .oh-story-jsonl summary > code,
2484
2636
  [data-oh-story-layout="compact"] .oh-story-jsonl summary > em { display: none; }
2485
2637
 
2486
- [data-conversation-scroll][data-oh-story-workbench="game"][data-oh-story-layout="medium"]:has(> [data-slot="conversation.session"] > .oh-story-split-surface) {
2638
+ [data-conversation-scroll][data-oh-story-workbench="game"][data-oh-story-layout="medium"]:has(> [data-slot="conversation.session"] > .oh-story-split-surface[data-open="true"]) {
2487
2639
  grid-template-columns: minmax(0, 1fr) clamp(360px, 42%, 440px);
2488
2640
  }
2489
2641
  [data-oh-story-workbench="game"][data-oh-story-layout="medium"] .oh-game-toolbar { grid-template-columns: auto minmax(140px, 1fr) auto; }
2490
2642
 
2491
- [data-conversation-scroll][data-oh-story-workbench="game"][data-oh-story-layout="compact"]:has(> [data-slot="conversation.session"] > .oh-story-split-surface) {
2643
+ [data-conversation-scroll][data-oh-story-workbench="game"][data-oh-story-layout="compact"]:has(> [data-slot="conversation.session"] > .oh-story-split-surface[data-open="true"]) {
2492
2644
  display: grid;
2493
2645
  grid-template-columns: minmax(0, 1fr);
2494
2646
  overflow: hidden;
@@ -2523,7 +2675,7 @@ var plugin_default = `.oh-story-bridge-marker { display: none; }
2523
2675
  gap: 5px;
2524
2676
  padding: 4px 8px;
2525
2677
  }
2526
- [data-conversation-scroll][data-oh-story-workbench="game"][data-oh-story-layout="compact"] .oh-game-mode-tabs { grid-column: 1; grid-row: 1; width: fit-content; }
2678
+ [data-conversation-scroll][data-oh-story-workbench="game"][data-oh-story-layout="compact"] .oh-game-toolbar > .oh-workbench-cluster { grid-column: 1; grid-row: 1; width: fit-content; }
2527
2679
  [data-conversation-scroll][data-oh-story-workbench="game"][data-oh-story-layout="compact"] .oh-game-project > span { display: none; }
2528
2680
  [data-conversation-scroll][data-oh-story-workbench="game"][data-oh-story-layout="compact"] .oh-game-project { grid-column: 1 / -1; grid-row: 2; }
2529
2681
  [data-conversation-scroll][data-oh-story-workbench="game"][data-oh-story-layout="compact"] .oh-game-project select { max-width: none; width: 100%; min-height: 44px; }
@@ -2549,7 +2701,7 @@ var plugin_default = `.oh-story-bridge-marker { display: none; }
2549
2701
  align-content: center;
2550
2702
  padding: 4px 8px;
2551
2703
  }
2552
- [data-conversation-scroll][data-oh-story-workbench="game"][data-oh-story-layout="compact"] .oh-game-studio[data-oh-game-narrow] .oh-game-mode-tabs {
2704
+ [data-conversation-scroll][data-oh-story-workbench="game"][data-oh-story-layout="compact"] .oh-game-studio[data-oh-game-narrow] .oh-game-toolbar > .oh-workbench-cluster {
2553
2705
  grid-column: 1;
2554
2706
  grid-row: 2;
2555
2707
  justify-self: start;
@@ -2607,7 +2759,7 @@ var plugin_default = `.oh-story-bridge-marker { display: none; }
2607
2759
 
2608
2760
  /* Video mode intentionally stays a preview surface: one player, a read-only artifact view,
2609
2761
  and the official DSH Conversation. It shares no nonlinear-editor or timeline runtime. */
2610
- [data-conversation-scroll][data-oh-story-workbench="video"]:has(> [data-slot="conversation.session"] > .oh-story-split-surface) {
2762
+ [data-conversation-scroll][data-oh-story-workbench="video"]:has(> [data-slot="conversation.session"] > .oh-story-split-surface[data-open="true"]) {
2611
2763
  --video-stage: #0b0d10;
2612
2764
  --video-stage-raised: #15181d;
2613
2765
  --video-accent: var(--dsw-alias-state-business-primary);
@@ -2616,9 +2768,9 @@ var plugin_default = `.oh-story-bridge-marker { display: none; }
2616
2768
  grid-template-columns: minmax(0, 1fr) clamp(400px, 34%, 520px);
2617
2769
  overflow: hidden;
2618
2770
  }
2619
- [data-conversation-scroll][data-oh-story-workbench="video"]:has(> [data-slot="conversation.session"] > .oh-story-split-surface)
2771
+ [data-conversation-scroll][data-oh-story-workbench="video"]:has(> [data-slot="conversation.session"] > .oh-story-split-surface[data-open="true"])
2620
2772
  > [data-slot="conversation.session"] > :not(.oh-story-split-surface),
2621
- [data-conversation-scroll][data-oh-story-workbench="video"]:has(> [data-slot="conversation.session"] > .oh-story-split-surface)
2773
+ [data-conversation-scroll][data-oh-story-workbench="video"]:has(> [data-slot="conversation.session"] > .oh-story-split-surface[data-open="true"])
2622
2774
  > [data-composer-seat] { grid-column: 2; }
2623
2775
 
2624
2776
  .oh-video-studio {
@@ -2762,10 +2914,10 @@ var plugin_default = `.oh-story-bridge-marker { display: none; }
2762
2914
  .oh-video-artifact-content { min-width: 0; min-height: 0; flex: 1; overflow: auto; }
2763
2915
  .oh-video-artifact-content pre { min-width: 0; min-height: 100%; box-sizing: border-box; margin: 0; padding: 20px; color: inherit; background: var(--dsw-alias-bg-base); white-space: pre-wrap; overflow-wrap: anywhere; font: 12px/1.65 var(--dsw-font-family-mono, ui-monospace, monospace); }
2764
2916
 
2765
- [data-conversation-scroll][data-oh-story-workbench="video"][data-oh-story-layout="medium"]:has(> [data-slot="conversation.session"] > .oh-story-split-surface) { grid-template-columns: minmax(0, 1fr) clamp(360px, 42%, 440px); }
2917
+ [data-conversation-scroll][data-oh-story-workbench="video"][data-oh-story-layout="medium"]:has(> [data-slot="conversation.session"] > .oh-story-split-surface[data-open="true"]) { grid-template-columns: minmax(0, 1fr) clamp(360px, 42%, 440px); }
2766
2918
  [data-oh-story-workbench="video"][data-oh-story-layout="medium"] .oh-video-project select { width: 100%; }
2767
2919
 
2768
- [data-conversation-scroll][data-oh-story-workbench="video"][data-oh-story-layout="compact"]:has(> [data-slot="conversation.session"] > .oh-story-split-surface) { display: grid; grid-template-columns: minmax(0, 1fr); overflow: hidden; }
2920
+ [data-conversation-scroll][data-oh-story-workbench="video"][data-oh-story-layout="compact"]:has(> [data-slot="conversation.session"] > .oh-story-split-surface[data-open="true"]) { display: grid; grid-template-columns: minmax(0, 1fr); overflow: hidden; }
2769
2921
  [data-conversation-scroll][data-oh-story-workbench="video"][data-oh-story-layout="compact"]
2770
2922
  > [data-slot="conversation.session"] > :not(.oh-story-split-surface),
2771
2923
  [data-conversation-scroll][data-oh-story-workbench="video"][data-oh-story-layout="compact"]
@@ -2778,7 +2930,7 @@ var plugin_default = `.oh-story-bridge-marker { display: none; }
2778
2930
  [data-conversation-scroll][data-oh-story-workbench="video"][data-oh-story-layout="compact"][data-oh-studio-pane="chat"] .oh-video-studio { display: none; }
2779
2931
  [data-conversation-scroll][data-oh-story-workbench="video"][data-oh-story-layout="compact"] .oh-game-mobile-switcher { display: flex; position: absolute; top: 8px; right: 8px; z-index: 20; border-color: var(--dsw-alias-border-l1); box-shadow: 0 4px 14px rgb(0 0 0 / 12%); }
2780
2932
  [data-conversation-scroll][data-oh-story-workbench="video"][data-oh-story-layout="compact"] .oh-video-toolbar { min-height: 142px; grid-template-columns: minmax(0, 1fr) auto; grid-template-rows: 44px 44px 38px; align-content: center; gap: 2px 6px; padding: 4px 8px; }
2781
- [data-conversation-scroll][data-oh-story-workbench="video"][data-oh-story-layout="compact"] .oh-video-mode-tabs { grid-column: 1 / -1; grid-row: 1; width: fit-content; }
2933
+ [data-conversation-scroll][data-oh-story-workbench="video"][data-oh-story-layout="compact"] .oh-video-toolbar > .oh-workbench-cluster { grid-column: 1 / -1; grid-row: 1; width: fit-content; }
2782
2934
  [data-conversation-scroll][data-oh-story-workbench="video"][data-oh-story-layout="compact"] .oh-video-tabs { grid-column: 2; grid-row: 2; justify-self: end; }
2783
2935
  [data-conversation-scroll][data-oh-story-workbench="video"][data-oh-story-layout="compact"] .oh-video-project { grid-column: 1; grid-row: 2; }
2784
2936
  [data-conversation-scroll][data-oh-story-workbench="video"][data-oh-story-layout="compact"] .oh-video-project > span { display: none; }
@@ -2801,6 +2953,7 @@ function createWorkbenchStore() {
2801
2953
  return (0, import_dsh_client_store.defineStore)({
2802
2954
  init: () => ({
2803
2955
  buffers: {},
2956
+ workbenchPreference: void 0,
2804
2957
  editorMode: "preview",
2805
2958
  expanded: {},
2806
2959
  selected: void 0,
@@ -2825,6 +2978,9 @@ function createWorkbenchStore() {
2825
2978
  setBuffers: (draft, update) => {
2826
2979
  draft.buffers = applyUpdate(draft.buffers, update);
2827
2980
  },
2981
+ setWorkbenchPreference: (draft, update) => {
2982
+ draft.workbenchPreference = applyUpdate(draft.workbenchPreference, update);
2983
+ },
2828
2984
  setEditorMode: (draft, update) => {
2829
2985
  draft.editorMode = applyUpdate(draft.editorMode, update);
2830
2986
  },
@@ -3126,6 +3282,7 @@ function GameStudio({
3126
3282
  paneId,
3127
3283
  labelledBy,
3128
3284
  onWorkbench,
3285
+ onCollapse,
3129
3286
  onSelect
3130
3287
  }) {
3131
3288
  let project = workspace.games.find((value) => value.id === gameProjectId) ?? workspace.games[0], studioRef = (0, import_react3.useRef)(null), tabsId = (0, import_react3.useId)();
@@ -3146,23 +3303,26 @@ function GameStudio({
3146
3303
  let tabs = ["preview", "design"];
3147
3304
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("main", { ref: studioRef, id: paneId, className: "oh-game-studio", "data-source": project.source, role: "tabpanel", "aria-labelledby": labelledBy, hidden, children: [
3148
3305
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("header", { className: "oh-game-toolbar", children: [
3149
- workbenches.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "oh-game-mode-tabs", role: "tablist", "aria-label": "\u521B\u4F5C\u5DE5\u4F5C\u53F0", children: workbenches.map((mode) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3150
- "button",
3151
- {
3152
- type: "button",
3153
- role: "tab",
3154
- "aria-selected": mode === "game",
3155
- tabIndex: mode === "game" ? 0 : -1,
3156
- onKeyDown: (event) => {
3157
- handleTabKey(event, workbenches, "game", onWorkbench);
3158
- },
3159
- onClick: () => {
3160
- onWorkbench(mode);
3306
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "oh-workbench-cluster", children: [
3307
+ workbenches.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "oh-game-mode-tabs", role: "tablist", "aria-label": "\u521B\u4F5C\u5DE5\u4F5C\u53F0", children: workbenches.map((mode) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3308
+ "button",
3309
+ {
3310
+ type: "button",
3311
+ role: "tab",
3312
+ "aria-selected": mode === "game",
3313
+ tabIndex: mode === "game" ? 0 : -1,
3314
+ onKeyDown: (event) => {
3315
+ handleTabKey(event, workbenches, "game", onWorkbench);
3316
+ },
3317
+ onClick: () => {
3318
+ onWorkbench(mode);
3319
+ },
3320
+ children: workbenchLabel(mode)
3161
3321
  },
3162
- children: workbenchLabel(mode)
3163
- },
3164
- mode
3165
- )) }),
3322
+ mode
3323
+ )) }),
3324
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { className: "oh-workbench-collapse", type: "button", title: "\u6536\u8D77\u521B\u4F5C\u5DE5\u4F5C\u53F0", "aria-label": "\u6536\u8D77\u521B\u4F5C\u5DE5\u4F5C\u53F0", onClick: onCollapse, children: "\xD7" })
3325
+ ] }),
3166
3326
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "oh-game-project", title: "\u5207\u6362\u9879\u76EE\u5C06\u91CD\u65B0\u8F7D\u5165\u8BD5\u73A9", children: [
3167
3327
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "\u6E38\u620F\u9879\u76EE" }),
3168
3328
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("select", { "aria-label": "\u6E38\u620F\u9879\u76EE\uFF1B\u5207\u6362\u5C06\u91CD\u65B0\u8F7D\u5165\u8BD5\u73A9", value: project.id, onChange: (event) => {
@@ -3209,16 +3369,24 @@ function CreativeWorkbench({
3209
3369
  sendProductionPrompt,
3210
3370
  cancelProduction,
3211
3371
  removeQueuedProduction,
3372
+ workspace,
3373
+ error,
3374
+ workspaceLoading,
3375
+ reload,
3376
+ open,
3377
+ creativeProject,
3212
3378
  useStore,
3213
3379
  actions
3214
3380
  }) {
3215
- let { workspace, error, loading: workspaceLoading, reload } = useWorkspace(sessionId), activities = (0, import_react3.useMemo)(
3381
+ let activities = (0, import_react3.useMemo)(
3216
3382
  () => fileMutations(runningCalls, partial),
3217
3383
  [partial, runningCalls]
3218
3384
  ), normalizedActivities = (0, import_react3.useMemo)(() => activities.flatMap((activity2) => {
3219
3385
  let path = creativeRelativePath(activity2.path, workspace?.cwd);
3220
3386
  return path === void 0 ? [] : [{ activity: activity2, path }];
3221
- }), [activities, workspace?.cwd]), primaryActivity = normalizedActivities.at(-1), activityPaths = (0, import_react3.useMemo)(() => new Set(normalizedActivities.map((value) => value.path)), [normalizedActivities]), activity = primaryActivity?.activity, activityPath = primaryActivity?.path, workbench = useStore((memory) => memory.workbench), setWorkbench = actions.setWorkbench, gameTab = useStore((memory) => memory.gameTab), setGameTab = actions.setGameTab, gameProjectId = useStore((memory) => memory.gameProjectId), setGameProjectId = actions.setGameProjectId, gamePane = useStore((memory) => memory.gamePane), setGamePane = actions.setGamePane, videoTab = useStore((memory) => memory.videoTab), setVideoTab = actions.setVideoTab, videoProjectId = useStore((memory) => memory.videoProjectId), setVideoProjectId = actions.setVideoProjectId, videoPane = useStore((memory) => memory.videoPane), setVideoPane = actions.setVideoPane, selected = useStore((memory) => memory.selected), setSelected = actions.setSelected, buffers = useStore((memory) => memory.buffers), setBuffers = actions.setBuffers, buffersRef = (0, import_react3.useRef)({}), expanded = useStore((memory) => memory.expanded), setExpanded = actions.setExpanded, productionSection = useStore((memory) => memory.productionSection), setProductionSection = actions.setProductionSection, productionSelectedIds = useStore((memory) => memory.productionSelectedIds), productionJobsByEpisode = useStore((memory) => memory.productionJobs), productionSelectionsByEpisode = useStore((memory) => memory.productionSelections), productionReferencesByEpisode = useStore((memory) => memory.productionReferences), productionSequenceByEpisode = useStore((memory) => memory.productionSequence), productionCanvasByEpisode = useStore((memory) => memory.productionCanvas), productionZoomByEpisode = useStore((memory) => memory.productionZoom), productionIntentCalls = useStore((memory) => memory.productionIntentCalls), surfaceRef = (0, import_react3.useRef)(null), compactTabsId = (0, import_react3.useId)(), compactStudioId = `${compactTabsId}-studio-panel`, compactVideoStudioId = `${compactTabsId}-video-studio-panel`, compactChatId = `${compactTabsId}-chat-panel`, navRef = (0, import_react3.useRef)(null), activityBases = (0, import_react3.useRef)(/* @__PURE__ */ new Map()), previousSignals = (0, import_react3.useRef)(/* @__PURE__ */ new Set()), previousSettledMutation = (0, import_react3.useRef)(settledMutation), saveLocks = (0, import_react3.useRef)(/* @__PURE__ */ new Set()), buffer = selected === void 0 ? void 0 : buffers[selected], selectedFile = workspace?.files.find((file) => file.path === selected), selectedMedia = selectedFile?.kind === "media", dirty = buffer?.source === "human" && buffer.content !== buffer.saved, saving = buffer?.saving === !0, fileError = buffer?.error, conflict = buffer?.conflict, selectedLower = selected?.toLocaleLowerCase(), markdown = selectedLower?.endsWith(".md") === !0, jsonl = selectedLower?.endsWith(".jsonl") === !0, structured = jsonl || selectedLower?.endsWith(".json") === !0, previewable = markdown || jsonl, episodeDirectory = episodeDirectoryForPath(selected), productionAvailable = selected !== void 0 && isCreatorDocumentPath(selected) && episodeDirectory !== void 0, editorModes = productionAvailable ? EDITOR_MODES : EDITOR_MODES.filter((mode) => mode !== "production"), episodeDocumentPaths = (0, import_react3.useMemo)(
3387
+ }), [activities, workspace?.cwd]), primaryActivity = normalizedActivities.at(-1), activityPaths = (0, import_react3.useMemo)(() => new Set(normalizedActivities.map((value) => value.path)), [normalizedActivities]), activity = primaryActivity?.activity, activityPath = primaryActivity?.path, workbench = useStore((memory) => memory.workbench), setWorkbench = actions.setWorkbench, gameTab = useStore((memory) => memory.gameTab), setGameTab = actions.setGameTab, gameProjectId = useStore((memory) => memory.gameProjectId), setGameProjectId = actions.setGameProjectId, gamePane = useStore((memory) => memory.gamePane), setGamePane = actions.setGamePane, videoTab = useStore((memory) => memory.videoTab), setVideoTab = actions.setVideoTab, videoProjectId = useStore((memory) => memory.videoProjectId), setVideoProjectId = actions.setVideoProjectId, videoPane = useStore((memory) => memory.videoPane), setVideoPane = actions.setVideoPane, selected = useStore((memory) => memory.selected), setSelected = actions.setSelected, buffers = useStore((memory) => memory.buffers), setBuffers = actions.setBuffers, buffersRef = (0, import_react3.useRef)({}), expanded = useStore((memory) => memory.expanded), setExpanded = actions.setExpanded, productionSection = useStore((memory) => memory.productionSection), setProductionSection = actions.setProductionSection, productionSelectedIds = useStore((memory) => memory.productionSelectedIds), productionJobsByEpisode = useStore((memory) => memory.productionJobs), productionSelectionsByEpisode = useStore((memory) => memory.productionSelections), productionReferencesByEpisode = useStore((memory) => memory.productionReferences), productionSequenceByEpisode = useStore((memory) => memory.productionSequence), productionCanvasByEpisode = useStore((memory) => memory.productionCanvas), productionZoomByEpisode = useStore((memory) => memory.productionZoom), productionIntentCalls = useStore((memory) => memory.productionIntentCalls), surfaceRef = (0, import_react3.useRef)(null), setWorkbenchPreference = actions.setWorkbenchPreference, applyWorkbenchPreference = (0, import_react3.useCallback)((preference) => {
3388
+ setWorkbenchPreference(preference), writeWorkbenchPreference(workbenchPreferenceStorage(), workspace?.cwd, preference);
3389
+ }, [setWorkbenchPreference, workspace?.cwd]), compactTabsId = (0, import_react3.useId)(), compactStudioId = `${compactTabsId}-studio-panel`, compactVideoStudioId = `${compactTabsId}-video-studio-panel`, compactChatId = `${compactTabsId}-chat-panel`, navRef = (0, import_react3.useRef)(null), activityBases = (0, import_react3.useRef)(/* @__PURE__ */ new Map()), previousSignals = (0, import_react3.useRef)(/* @__PURE__ */ new Set()), previousSettledMutation = (0, import_react3.useRef)(settledMutation), saveLocks = (0, import_react3.useRef)(/* @__PURE__ */ new Set()), buffer = selected === void 0 ? void 0 : buffers[selected], selectedFile = workspace?.files.find((file) => file.path === selected), selectedMedia = selectedFile?.kind === "media", dirty = buffer?.source === "human" && buffer.content !== buffer.saved, saving = buffer?.saving === !0, fileError = buffer?.error, conflict = buffer?.conflict, selectedLower = selected?.toLocaleLowerCase(), markdown = selectedLower?.endsWith(".md") === !0, jsonl = selectedLower?.endsWith(".jsonl") === !0, structured = jsonl || selectedLower?.endsWith(".json") === !0, previewable = markdown || jsonl, episodeDirectory = episodeDirectoryForPath(selected), productionAvailable = selected !== void 0 && isCreatorDocumentPath(selected) && episodeDirectory !== void 0, editorModes = productionAvailable ? EDITOR_MODES : EDITOR_MODES.filter((mode) => mode !== "production"), episodeDocumentPaths = (0, import_react3.useMemo)(
3222
3390
  () => episodeDirectory === void 0 ? [] : creatorDocumentPaths(workspace?.files.filter((file) => file.kind === "text") ?? [], episodeDirectory),
3223
3391
  [episodeDirectory, workspace?.files]
3224
3392
  ), episodeDocuments = (0, import_react3.useMemo)(() => Object.fromEntries(episodeDocumentPaths.flatMap((path) => {
@@ -3506,7 +3674,7 @@ function CreativeWorkbench({
3506
3674
  }
3507
3675
  }
3508
3676
  }, [selected]), (0, import_react3.useEffect)(() => {
3509
- if (normalizedActivities.length > 0 || workspace === void 0) return;
3677
+ if (!open || normalizedActivities.length > 0 || workspace === void 0) return;
3510
3678
  let sessionSurface = surfaceRef.current?.parentElement;
3511
3679
  if (sessionSurface == null) return;
3512
3680
  let knownPaths = new Set(workspace.files.map((file) => file.path)), followOfficialFileLink = (event) => {
@@ -3526,7 +3694,7 @@ function CreativeWorkbench({
3526
3694
  return sessionSurface.addEventListener("click", followOfficialFileLink, !0), () => {
3527
3695
  sessionSurface.removeEventListener("click", followOfficialFileLink, !0);
3528
3696
  };
3529
- }, [normalizedActivities.length, revealPath, workspace]), (0, import_react3.useEffect)(() => {
3697
+ }, [normalizedActivities.length, open, revealPath, workspace]), (0, import_react3.useEffect)(() => {
3530
3698
  if (workbench !== "game" && workbench !== "video") return;
3531
3699
  let surface = surfaceRef.current, sessionSurface = surface?.parentElement, chat = Array.from(sessionSurface?.children ?? []).find((child) => child !== surface && child instanceof HTMLElement);
3532
3700
  if (!(chat instanceof HTMLElement)) return;
@@ -3610,13 +3778,14 @@ function CreativeWorkbench({
3610
3778
  }
3611
3779
  }, [reload, sessionId]);
3612
3780
  (0, import_react3.useEffect)(() => {
3781
+ if (!open) return;
3613
3782
  let saveShortcut = (event) => {
3614
3783
  !(event.metaKey || event.ctrlKey) || event.key.toLocaleLowerCase() !== "s" || (event.preventDefault(), selected !== void 0 && savePath(selected));
3615
3784
  };
3616
3785
  return globalThis.addEventListener("keydown", saveShortcut), () => {
3617
3786
  globalThis.removeEventListener("keydown", saveShortcut);
3618
3787
  };
3619
- }, [savePath, selected]);
3788
+ }, [open, savePath, selected]);
3620
3789
  let groups = (0, import_react3.useMemo)(() => {
3621
3790
  let value = /* @__PURE__ */ new Map(), all = [...workspace?.files ?? []].filter((file) => workbenchModeForPath(file.path) === workbench);
3622
3791
  activityPath !== void 0 && !all.some((file) => file.path === activityPath) && all.push({ path: activityPath, bytes: 0, version: "", kind: "text" }), all.sort((left, right) => left.path.localeCompare(right.path, "zh-Hans-CN"));
@@ -3641,8 +3810,8 @@ function CreativeWorkbench({
3641
3810
  }, navigateProductionTarget = (target) => {
3642
3811
  let before = (buffersRef.current[target.path]?.content ?? "").slice(0, target.offset), approximateScrollTop = Math.max(0, before.split(/\r?\n/u).length * 28 - 96);
3643
3812
  editorPositions.current.set(target.path, { scrollTop: approximateScrollTop, selectionStart: target.offset, selectionEnd: target.offset }), modeSelection.current = target.path, revealPath(target.path), setEditorMode("source");
3644
- }, selectedLabel = selected ?? `\u5728\u5F53\u524D DSH workspace \u4E2D\u9009\u62E9${workbenchLabel(workbench)}\u6587\u4EF6`, selectedBasename = selected?.split("/").at(-1) ?? selectedLabel, selectedGroup = selected === void 0 ? void 0 : groupForPath(selected), toggleGroup = (key, open) => {
3645
- setExpanded((current) => ({ ...current, [key]: open }));
3813
+ }, selectedLabel = selected ?? `\u5728\u5F53\u524D DSH workspace \u4E2D\u9009\u62E9${workbenchLabel(workbench)}\u6587\u4EF6`, selectedBasename = selected?.split("/").at(-1) ?? selectedLabel, selectedGroup = selected === void 0 ? void 0 : groupForPath(selected), toggleGroup = (key, open2) => {
3814
+ setExpanded((current) => ({ ...current, [key]: open2 }));
3646
3815
  }, resolveConflict = (keepLocal) => {
3647
3816
  if (selected === void 0 || conflict?.theirs === void 0 || conflict.theirsVersion === void 0) return;
3648
3817
  let theirs = conflict.theirs, theirsVersion = conflict.theirsVersion;
@@ -3654,7 +3823,7 @@ function CreativeWorkbench({
3654
3823
  };
3655
3824
  });
3656
3825
  };
3657
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { ref: surfaceRef, className: "oh-story-split-surface", "data-workbench": workbench, children: [
3826
+ return open ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { ref: surfaceRef, className: "oh-story-split-surface", "data-open": "true", "data-workbench": workbench, children: [
3658
3827
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("style", { children: plugin_default }),
3659
3828
  (workbench === "game" || workbench === "video") && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "oh-game-mobile-switcher", role: "tablist", "aria-label": workbench === "game" ? "\u7A84\u5C4F\u6E38\u620F\u5DE5\u4F5C\u53F0" : "\u7A84\u5C4F\u89C6\u9891\u5DE5\u4F5C\u53F0", children: ["studio", "chat"].map((pane) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3660
3829
  "button",
@@ -3692,6 +3861,9 @@ function CreativeWorkbench({
3692
3861
  paneId: compactStudioId,
3693
3862
  labelledBy: `${compactTabsId}-studio-tab`,
3694
3863
  onWorkbench: selectWorkbench,
3864
+ onCollapse: () => {
3865
+ applyWorkbenchPreference("closed");
3866
+ },
3695
3867
  onSelect: revealPath
3696
3868
  }
3697
3869
  ),
@@ -3710,7 +3882,10 @@ function CreativeWorkbench({
3710
3882
  labelledBy: `${compactTabsId}-studio-tab`,
3711
3883
  onProject: setVideoProjectId,
3712
3884
  onTab: setVideoTab,
3713
- onWorkbench: selectWorkbench
3885
+ onWorkbench: selectWorkbench,
3886
+ onCollapse: () => {
3887
+ applyWorkbenchPreference("closed");
3888
+ }
3714
3889
  }
3715
3890
  ),
3716
3891
  workbench !== "game" && workbench !== "video" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
@@ -3723,7 +3898,12 @@ function CreativeWorkbench({
3723
3898
  ] }),
3724
3899
  workspaceKind !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "oh-story-kind", children: workspaceKind === "story" ? "\u5C0F\u8BF4" : "\u77ED\u5267" })
3725
3900
  ] }),
3726
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", onClick: reload, title: "\u5237\u65B0", "aria-label": "\u5237\u65B0\u9879\u76EE\u6587\u4EF6", children: "\u21BB" })
3901
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "oh-story-brand-actions", children: [
3902
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", onClick: reload, title: "\u5237\u65B0", "aria-label": "\u5237\u65B0\u9879\u76EE\u6587\u4EF6", children: "\u21BB" }),
3903
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", onClick: () => {
3904
+ applyWorkbenchPreference("closed");
3905
+ }, title: "\u6536\u8D77\u521B\u4F5C\u5DE5\u4F5C\u53F0", "aria-label": "\u6536\u8D77\u521B\u4F5C\u5DE5\u4F5C\u53F0", children: "\xD7" })
3906
+ ] })
3727
3907
  ] }),
3728
3908
  workspace !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "oh-story-mode-tabs", role: "tablist", "aria-label": "\u521B\u4F5C\u5DE5\u4F5C\u53F0", children: WORKBENCH_MODES.map((mode) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3729
3909
  "button",
@@ -3836,6 +4016,7 @@ function CreativeWorkbench({
3836
4016
  ] }) : editorMode === "production" && productionAvailable && episodeProduction !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3837
4017
  DramaProductionView,
3838
4018
  {
4019
+ sessionId,
3839
4020
  production: episodeProduction,
3840
4021
  sessionRunning,
3841
4022
  queue: productionQueue,
@@ -3895,10 +4076,21 @@ function CreativeWorkbench({
3895
4076
  )
3896
4077
  ] })
3897
4078
  ] })
4079
+ ] }) : !creativeProject && error === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { ref: surfaceRef, className: "oh-story-split-surface", "data-open": "false", children: [
4080
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("style", { children: plugin_default }),
4081
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("button", { className: "oh-story-launcher", type: "button", title: error ?? "\u6253\u5F00\u521B\u4F5C\u5DE5\u4F5C\u53F0", "aria-label": "\u6253\u5F00\u521B\u4F5C\u5DE5\u4F5C\u53F0", onClick: () => {
4082
+ applyWorkbenchPreference("open");
4083
+ }, children: [
4084
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { "aria-hidden": !0, children: "\u2726" }),
4085
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("b", { children: "\u521B\u4F5C\u5DE5\u4F5C\u53F0" })
4086
+ ] })
3898
4087
  ] });
3899
4088
  }
3900
4089
  function CreativeSplitBridge({ sessionId, useSession, useChat, useStore, actions, sendProductionPrompt, cancelProduction, removeQueuedProduction }) {
3901
- let marker = (0, import_react3.useRef)(null), [target, setTarget] = (0, import_react3.useState)(), runningCalls = useChat((snapshot) => snapshot.legacy.runningCalls), partial = useChat((snapshot) => streamingAssistant(snapshot.timeline)), settledMutation = useChat((snapshot) => latestSettledMutation(snapshot)), workbench = useStore((memory) => memory.workbench), gamePane = useStore((memory) => memory.gamePane), videoPane = useStore((memory) => memory.videoPane), sessionRunning = useSession((snapshot) => snapshot.running), productionQueue = useSession((snapshot) => snapshot.queue.map((item) => ({ id: item.id, preview: item.preview }))), chat = useChat((snapshot) => snapshot), productionIntents = (0, import_react3.useMemo)(() => settledProductionIntents(chat), [chat]);
4090
+ let marker = (0, import_react3.useRef)(null), [target, setTarget] = (0, import_react3.useState)(), runningCalls = useChat((snapshot) => snapshot.legacy.runningCalls), partial = useChat((snapshot) => streamingAssistant(snapshot.timeline)), settledMutation = useChat((snapshot) => latestSettledMutation(snapshot)), workbench = useStore((memory) => memory.workbench), gamePane = useStore((memory) => memory.gamePane), videoPane = useStore((memory) => memory.videoPane), sessionRunning = useSession((snapshot) => snapshot.running), productionQueue = useSession((snapshot) => snapshot.queue.map((item) => ({ id: item.id, preview: item.preview }))), chat = useChat((snapshot) => snapshot), productionIntents = (0, import_react3.useMemo)(() => settledProductionIntents(chat), [chat]), { workspace, error, loading: workspaceLoading, reload } = useWorkspace(sessionId), chosenPreference = useStore((memory) => memory.workbenchPreference), creativeProject = hasCreativeProject(workspace), storedPreference = (0, import_react3.useMemo)(
4091
+ () => readWorkbenchPreference(workbenchPreferenceStorage(), workspace?.cwd),
4092
+ [workspace?.cwd]
4093
+ ), open = resolveWorkbenchOpen(chosenPreference ?? storedPreference, creativeProject);
3902
4094
  return (0, import_react3.useLayoutEffect)(() => {
3903
4095
  let document = marker.current?.ownerDocument;
3904
4096
  if (document === void 0) return;
@@ -3914,6 +4106,19 @@ function CreativeSplitBridge({ sessionId, useSession, useChat, useStore, actions
3914
4106
  }, [sessionId]), (0, import_react3.useLayoutEffect)(() => {
3915
4107
  let scroller = target?.parentElement;
3916
4108
  if (scroller == null) return;
4109
+ if (!open) {
4110
+ let publishSeam = () => {
4111
+ let box = scroller.getBoundingClientRect();
4112
+ scroller.style.setProperty("--oh-story-seam-top", `${String(box.top)}px`), scroller.style.setProperty("--oh-story-seam-right", `${String(scroller.ownerDocument.documentElement.clientWidth - box.right)}px`);
4113
+ };
4114
+ publishSeam();
4115
+ let seams = new ResizeObserver(publishSeam);
4116
+ seams.observe(scroller);
4117
+ let view = scroller.ownerDocument.defaultView;
4118
+ return view?.addEventListener("resize", publishSeam), () => {
4119
+ seams.disconnect(), view?.removeEventListener("resize", publishSeam), scroller.style.removeProperty("--oh-story-seam-top"), scroller.style.removeProperty("--oh-story-seam-right");
4120
+ };
4121
+ }
3917
4122
  let composerSeat = () => scroller.querySelector(":scope > [data-composer-seat]"), parkedAtTail = () => scroller.scrollHeight - scroller.scrollTop - scroller.clientHeight <= 8, parked = parkedAtTail(), drivenAt = 0, markDriven = (event) => {
3918
4123
  event.target instanceof Node && composerSeat()?.contains(event.target) === !0 || (drivenAt = performance.now());
3919
4124
  }, trackParked = () => {
@@ -3947,7 +4152,7 @@ function CreativeSplitBridge({ sessionId, useSession, useChat, useStore, actions
3947
4152
  scroller.removeEventListener(driven, markDriven);
3948
4153
  observer.disconnect(), seats.disconnect(), scroller.style.removeProperty("--oh-story-scroll-height"), scroller.style.removeProperty("--oh-story-composer-height"), delete scroller.dataset.ohStoryLayout, delete scroller.dataset.ohStoryWorkbench, delete scroller.dataset.ohStudioPane;
3949
4154
  };
3950
- }, [gamePane, target, videoPane, workbench]), /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
4155
+ }, [gamePane, open, target, videoPane, workbench]), /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
3951
4156
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { ref: marker, className: "oh-story-bridge-marker", "aria-hidden": !0 }),
3952
4157
  target === void 0 ? null : (0, import_react_dom.createPortal)(/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3953
4158
  CreativeWorkbench,
@@ -3959,6 +4164,12 @@ function CreativeSplitBridge({ sessionId, useSession, useChat, useStore, actions
3959
4164
  sessionRunning,
3960
4165
  productionQueue,
3961
4166
  productionIntents,
4167
+ workspace,
4168
+ error,
4169
+ workspaceLoading,
4170
+ reload,
4171
+ open,
4172
+ creativeProject,
3962
4173
  sendProductionPrompt,
3963
4174
  cancelProduction,
3964
4175
  removeQueuedProduction,