@researai/deepscientist 1.5.12 → 1.5.14

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 (99) hide show
  1. package/bin/ds.js +20 -3
  2. package/docs/en/00_QUICK_START.md +24 -5
  3. package/docs/en/01_SETTINGS_REFERENCE.md +4 -0
  4. package/docs/en/05_TUI_GUIDE.md +466 -96
  5. package/docs/en/09_DOCTOR.md +24 -5
  6. package/docs/en/15_CODEX_PROVIDER_SETUP.md +113 -15
  7. package/docs/en/README.md +2 -0
  8. package/docs/zh/00_QUICK_START.md +24 -5
  9. package/docs/zh/01_SETTINGS_REFERENCE.md +4 -0
  10. package/docs/zh/05_TUI_GUIDE.md +465 -82
  11. package/docs/zh/09_DOCTOR.md +24 -5
  12. package/docs/zh/15_CODEX_PROVIDER_SETUP.md +113 -15
  13. package/docs/zh/README.md +2 -0
  14. package/package.json +2 -1
  15. package/pyproject.toml +1 -1
  16. package/src/deepscientist/__init__.py +1 -1
  17. package/src/deepscientist/artifact/service.py +125 -2
  18. package/src/deepscientist/cli.py +3 -0
  19. package/src/deepscientist/codex_cli_compat.py +117 -0
  20. package/src/deepscientist/config/service.py +53 -6
  21. package/src/deepscientist/connector/lingzhu_support.py +23 -4
  22. package/src/deepscientist/daemon/app.py +111 -30
  23. package/src/deepscientist/mcp/server.py +161 -19
  24. package/src/deepscientist/prompts/builder.py +13 -54
  25. package/src/deepscientist/quest/service.py +99 -0
  26. package/src/deepscientist/quest/stage_views.py +134 -29
  27. package/src/deepscientist/runners/codex.py +11 -2
  28. package/src/deepscientist/runners/runtime_overrides.py +3 -0
  29. package/src/deepscientist/shared.py +6 -1
  30. package/src/prompts/system.md +220 -2065
  31. package/src/skills/baseline/SKILL.md +265 -994
  32. package/src/skills/baseline/references/artifact-payload-examples.md +39 -0
  33. package/src/skills/baseline/references/baseline-checklist-template.md +21 -32
  34. package/src/skills/baseline/references/baseline-plan-template.md +41 -57
  35. package/src/tui/dist/app/AppContainer.js +1442 -52
  36. package/src/tui/dist/components/Composer.js +1 -1
  37. package/src/tui/dist/components/ConfigScreen.js +190 -36
  38. package/src/tui/dist/components/GradientStatusText.js +1 -20
  39. package/src/tui/dist/components/InputPrompt.js +41 -32
  40. package/src/tui/dist/components/LoadingIndicator.js +1 -1
  41. package/src/tui/dist/components/Logo.js +61 -38
  42. package/src/tui/dist/components/MainContent.js +10 -3
  43. package/src/tui/dist/components/WelcomePanel.js +4 -12
  44. package/src/tui/dist/components/messages/AssistantMessage.js +1 -1
  45. package/src/tui/dist/components/messages/BashExecOperationMessage.js +3 -3
  46. package/src/tui/dist/components/messages/OperationMessage.js +1 -1
  47. package/src/tui/dist/index.js +28 -1
  48. package/src/tui/dist/layouts/DefaultAppLayout.js +3 -3
  49. package/src/tui/dist/lib/api.js +17 -0
  50. package/src/tui/dist/lib/connectorConfig.js +90 -0
  51. package/src/tui/dist/lib/connectors.js +261 -0
  52. package/src/tui/dist/lib/qr.js +21 -0
  53. package/src/tui/dist/semantic-colors.js +29 -19
  54. package/src/tui/package.json +2 -1
  55. package/src/ui/dist/assets/{AiManusChatView-CnJcXynW.js → AiManusChatView-DaF9Nge_.js} +12 -12
  56. package/src/ui/dist/assets/{AnalysisPlugin-DeyzPEhV.js → AnalysisPlugin-BSVx6dXE.js} +1 -1
  57. package/src/ui/dist/assets/{CliPlugin-CB1YODQn.js → CliPlugin-C9gzJX41.js} +9 -9
  58. package/src/ui/dist/assets/{CodeEditorPlugin-B-xicq1e.js → CodeEditorPlugin-DU9G0Tox.js} +8 -8
  59. package/src/ui/dist/assets/{CodeViewerPlugin-DT54ysXa.js → CodeViewerPlugin-DoX_fI9l.js} +5 -5
  60. package/src/ui/dist/assets/{DocViewerPlugin-DQtKT-VD.js → DocViewerPlugin-C4FWIXuU.js} +3 -3
  61. package/src/ui/dist/assets/{GitDiffViewerPlugin-hqHbCfnv.js → GitDiffViewerPlugin-BgfFMgtf.js} +20 -20
  62. package/src/ui/dist/assets/{ImageViewerPlugin-OcVo33jV.js → ImageViewerPlugin-tcPkfY_x.js} +5 -5
  63. package/src/ui/dist/assets/{LabCopilotPanel-DdGwhEUV.js → LabCopilotPanel-_dKV60Bf.js} +11 -11
  64. package/src/ui/dist/assets/{LabPlugin-Ciz1gDaX.js → LabPlugin-Bje0ayoC.js} +2 -2
  65. package/src/ui/dist/assets/{LatexPlugin-BhmjNQRC.js → LatexPlugin-CVsBzAln.js} +7 -7
  66. package/src/ui/dist/assets/{MarkdownViewerPlugin-BzdVH9Bx.js → MarkdownViewerPlugin-xjmrqv_8.js} +4 -4
  67. package/src/ui/dist/assets/{MarketplacePlugin-DmyHspXt.js → MarketplacePlugin-mMM2A8wP.js} +3 -3
  68. package/src/ui/dist/assets/{NotebookEditor-BTVYRGkm.js → NotebookEditor-3kVDSOBo.js} +11 -11
  69. package/src/ui/dist/assets/{NotebookEditor-BMXKrDRk.js → NotebookEditor-SoJ8X-MO.js} +1 -1
  70. package/src/ui/dist/assets/{PdfLoader-CvcjJHXv.js → PdfLoader-DElVuHl9.js} +1 -1
  71. package/src/ui/dist/assets/{PdfMarkdownPlugin-DW2ej8Vk.js → PdfMarkdownPlugin-Bq88XT4G.js} +2 -2
  72. package/src/ui/dist/assets/{PdfViewerPlugin-CmlDxbhU.js → PdfViewerPlugin-CsCXMo9S.js} +10 -10
  73. package/src/ui/dist/assets/{SearchPlugin-DAjQZPSv.js → SearchPlugin-oUPvy19k.js} +1 -1
  74. package/src/ui/dist/assets/{TextViewerPlugin-C-nVAZb_.js → TextViewerPlugin-CRkT9yNy.js} +5 -5
  75. package/src/ui/dist/assets/{VNCViewer-D7-dIYon.js → VNCViewer-BgbuvWhR.js} +10 -10
  76. package/src/ui/dist/assets/{bot-C_G4WtNI.js → bot-v_RASACv.js} +1 -1
  77. package/src/ui/dist/assets/{code-Cd7WfiWq.js → code-5hC9d0VH.js} +1 -1
  78. package/src/ui/dist/assets/{file-content-B57zsL9y.js → file-content-D1PxfOrp.js} +1 -1
  79. package/src/ui/dist/assets/{file-diff-panel-DVoheLFq.js → file-diff-panel-DG1oT_Hj.js} +1 -1
  80. package/src/ui/dist/assets/{file-socket-B5kXFxZP.js → file-socket-BmdFYQlk.js} +1 -1
  81. package/src/ui/dist/assets/{image-LLOjkMHF.js → image-Dqe2X2tW.js} +1 -1
  82. package/src/ui/dist/assets/{index-Dxa2eYMY.js → index-DVsMKK_y.js} +1 -1
  83. package/src/ui/dist/assets/{index-C3r2iGrp.js → index-Duvz8Ip0.js} +12 -12
  84. package/src/ui/dist/assets/{index-CLQauncb.js → index-Nt9hS4ck.js} +470 -165
  85. package/src/ui/dist/assets/{index-hOUOWbW2.js → index-RDlNXXx1.js} +2 -2
  86. package/src/ui/dist/assets/{monaco-BGGAEii3.js → monaco-DIXge1CP.js} +1 -1
  87. package/src/ui/dist/assets/{pdf-effect-queue-DlEr1_y5.js → pdf-effect-queue-BBTTQaO-.js} +1 -1
  88. package/src/ui/dist/assets/{popover-CWJbJuYY.js → popover-BWlolyxo.js} +1 -1
  89. package/src/ui/dist/assets/{project-sync-CRJiucYO.js → project-sync-BM5PkFH4.js} +1 -1
  90. package/src/ui/dist/assets/{select-CoHB7pvH.js → select-D4dAtrA8.js} +2 -2
  91. package/src/ui/dist/assets/{sigma-D5aJWR8J.js → sigma-CKbE5jJT.js} +1 -1
  92. package/src/ui/dist/assets/{square-check-big-DUK_mnkS.js → square-check-big-CZNGMgiB.js} +1 -1
  93. package/src/ui/dist/assets/{trash-ChU3SEE3.js → trash-DaB37xAz.js} +1 -1
  94. package/src/ui/dist/assets/{useCliAccess-BrJBV3tY.js → useCliAccess-C2OmAcWe.js} +1 -1
  95. package/src/ui/dist/assets/{useFileDiffOverlay-C2OQaVWc.js → useFileDiffOverlay-Dowd1Ij4.js} +1 -1
  96. package/src/ui/dist/assets/{wrap-text-C7Qqh-om.js → wrap-text-BGjAhAUq.js} +1 -1
  97. package/src/ui/dist/assets/{zoom-out-rtX0FKya.js → zoom-out-dMZQMXzc.js} +1 -1
  98. package/src/ui/dist/index.html +1 -1
  99. package/uv.lock +1 -1
@@ -1,4 +1,4 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/CodeViewerPlugin-DT54ysXa.js","assets/file-jump-queue-r5XKgJEV.js","assets/code-Cd7WfiWq.js","assets/wrap-text-C7Qqh-om.js","assets/CodeEditorPlugin-B-xicq1e.js","assets/file-content-B57zsL9y.js","assets/file-socket-B5kXFxZP.js","assets/monaco-BGGAEii3.js","assets/useFileDiffOverlay-C2OQaVWc.js","assets/file-diff-panel-DVoheLFq.js","assets/TextViewerPlugin-C-nVAZb_.js","assets/index-Dxa2eYMY.js","assets/MarkdownViewerPlugin-BzdVH9Bx.js","assets/ImageViewerPlugin-OcVo33jV.js","assets/image-LLOjkMHF.js","assets/zoom-out-rtX0FKya.js","assets/PdfViewerPlugin-CmlDxbhU.js","assets/pdf-effect-queue-DlEr1_y5.js","assets/PdfLoader-CvcjJHXv.js","assets/PdfLoader-C-Y707R3.css","assets/square-check-big-DUK_mnkS.js","assets/PdfViewerPlugin-DQ11QcSf.css","assets/PdfMarkdownPlugin-DW2ej8Vk.js","assets/NotebookEditor-BMXKrDRk.js","assets/NotebookEditor-C3VQ7ylN.css","assets/CliPlugin-CB1YODQn.js","assets/select-CoHB7pvH.js","assets/useCliAccess-BrJBV3tY.js","assets/LabPlugin-Ciz1gDaX.js","assets/bot-C_G4WtNI.js","assets/index-C3r2iGrp.js","assets/NotebookEditor-BTVYRGkm.js","assets/function-B5QZkkHC.js","assets/yjs-DncrqiZ8.js","assets/project-sync-CRJiucYO.js","assets/popover-CWJbJuYY.js","assets/trash-ChU3SEE3.js","assets/sigma-D5aJWR8J.js","assets/NotebookEditor-CccQYZjX.css","assets/LatexPlugin-BhmjNQRC.js","assets/GitDiffViewerPlugin-hqHbCfnv.js","assets/SearchPlugin-DAjQZPSv.js","assets/SearchPlugin-DDMrGDkh.css","assets/MarketplacePlugin-DmyHspXt.js","assets/AiManusChatView-CnJcXynW.js","assets/LabCopilotPanel-DdGwhEUV.js"])))=>i.map(i=>d[i]);
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/CodeViewerPlugin-DoX_fI9l.js","assets/file-jump-queue-r5XKgJEV.js","assets/code-5hC9d0VH.js","assets/wrap-text-BGjAhAUq.js","assets/CodeEditorPlugin-DU9G0Tox.js","assets/file-content-D1PxfOrp.js","assets/file-socket-BmdFYQlk.js","assets/monaco-DIXge1CP.js","assets/useFileDiffOverlay-Dowd1Ij4.js","assets/file-diff-panel-DG1oT_Hj.js","assets/TextViewerPlugin-CRkT9yNy.js","assets/index-DVsMKK_y.js","assets/MarkdownViewerPlugin-xjmrqv_8.js","assets/ImageViewerPlugin-tcPkfY_x.js","assets/image-Dqe2X2tW.js","assets/zoom-out-dMZQMXzc.js","assets/PdfViewerPlugin-CsCXMo9S.js","assets/pdf-effect-queue-BBTTQaO-.js","assets/PdfLoader-DElVuHl9.js","assets/PdfLoader-C-Y707R3.css","assets/square-check-big-CZNGMgiB.js","assets/PdfViewerPlugin-DQ11QcSf.css","assets/PdfMarkdownPlugin-Bq88XT4G.js","assets/NotebookEditor-SoJ8X-MO.js","assets/NotebookEditor-C3VQ7ylN.css","assets/CliPlugin-C9gzJX41.js","assets/select-D4dAtrA8.js","assets/useCliAccess-C2OmAcWe.js","assets/LabPlugin-Bje0ayoC.js","assets/bot-v_RASACv.js","assets/index-Duvz8Ip0.js","assets/NotebookEditor-3kVDSOBo.js","assets/function-B5QZkkHC.js","assets/yjs-DncrqiZ8.js","assets/project-sync-BM5PkFH4.js","assets/popover-BWlolyxo.js","assets/trash-DaB37xAz.js","assets/sigma-CKbE5jJT.js","assets/NotebookEditor-CccQYZjX.css","assets/LatexPlugin-CVsBzAln.js","assets/GitDiffViewerPlugin-BgfFMgtf.js","assets/SearchPlugin-oUPvy19k.js","assets/SearchPlugin-DDMrGDkh.css","assets/MarketplacePlugin-mMM2A8wP.js","assets/AiManusChatView-DaF9Nge_.js","assets/LabCopilotPanel-_dKV60Bf.js"])))=>i.map(i=>d[i]);
2
2
  function _mergeNamespaces(n, m) {
3
3
  for (var i = 0; i < m.length; i++) {
4
4
  const e = m[i];
@@ -135668,7 +135668,7 @@ function EntryCoachDialog({
135668
135668
  "button",
135669
135669
  {
135670
135670
  type: "button",
135671
- onClick: () => onSetLanguage("zh"),
135671
+ onClick: () => onSetLanguage?.("zh"),
135672
135672
  className: cn$1(
135673
135673
  "rounded-full px-3 py-1.5 text-xs font-semibold transition",
135674
135674
  locale === "zh" ? "bg-[#2D2A26] text-white" : "text-[rgba(86,82,77,0.82)] hover:bg-white"
@@ -135680,7 +135680,7 @@ function EntryCoachDialog({
135680
135680
  "button",
135681
135681
  {
135682
135682
  type: "button",
135683
- onClick: () => onSetLanguage("en"),
135683
+ onClick: () => onSetLanguage?.("en"),
135684
135684
  className: cn$1(
135685
135685
  "rounded-full px-3 py-1.5 text-xs font-semibold transition",
135686
135686
  locale === "en" ? "bg-[#2D2A26] text-white" : "text-[rgba(86,82,77,0.82)] hover:bg-white"
@@ -136423,7 +136423,17 @@ function UpdateReminderDialog() {
136423
136423
  }
136424
136424
 
136425
136425
  const clamp$5 = (value, min, max) => Math.min(Math.max(value, min), max);
136426
- const FINAL_SCROLL_HOLD = 0.2;
136426
+ function readPageScrollTop() {
136427
+ if (typeof window === "undefined" || typeof document === "undefined") {
136428
+ return 0;
136429
+ }
136430
+ return Math.max(
136431
+ window.scrollY,
136432
+ window.pageYOffset,
136433
+ document.documentElement?.scrollTop || 0,
136434
+ document.body?.scrollTop || 0
136435
+ );
136436
+ }
136427
136437
  function sortQuests(items) {
136428
136438
  return [...items].sort((left, right) => {
136429
136439
  const leftTime = new Date(left.updated_at || 0).getTime();
@@ -136434,6 +136444,7 @@ function sortQuests(items) {
136434
136444
  function Hero() {
136435
136445
  const navigate = useNavigate();
136436
136446
  const { locale } = useI18n$1();
136447
+ const saveLanguagePreference = useUILanguageStore((state) => state.saveLanguagePreference);
136437
136448
  const {
136438
136449
  hydrated: onboardingHydrated,
136439
136450
  firstRunHandled,
@@ -136458,13 +136469,8 @@ function Hero() {
136458
136469
  const [showProgress, setShowProgress] = reactExports.useState(true);
136459
136470
  const progressRef = reactExports.useRef(0);
136460
136471
  const targetRef = reactExports.useRef(0);
136461
- const holdRef = reactExports.useRef(0);
136462
136472
  const rafRef = reactExports.useRef(null);
136463
- const allowScrollProgressRef = reactExports.useRef(true);
136464
136473
  const lastScrollYRef = reactExports.useRef(0);
136465
- const lockedScrollYRef = reactExports.useRef(null);
136466
- const scheduleTickRef = reactExports.useRef(() => {
136467
- });
136468
136474
  const [questDialogOpen, setQuestDialogOpen] = reactExports.useState(false);
136469
136475
  const [quests, setQuests] = reactExports.useState([]);
136470
136476
  const [questsLoading, setQuestsLoading] = reactExports.useState(false);
@@ -136477,6 +136483,7 @@ function Hero() {
136477
136483
  const [connectorAvailabilityResolved, setConnectorAvailabilityResolved] = reactExports.useState(false);
136478
136484
  const [entryCoachDismissed, setEntryCoachDismissed] = reactExports.useState(false);
136479
136485
  const currentVersion = reactExports.useMemo(() => runtimeVersion(), []);
136486
+ const landingModalOpen = questDialogOpen || createDialogOpen;
136480
136487
  reactExports.useEffect(() => {
136481
136488
  document.body.classList.add("font-project");
136482
136489
  return () => document.body.classList.remove("font-project");
@@ -136526,7 +136533,6 @@ function Hero() {
136526
136533
  if (isPortraitMode) {
136527
136534
  targetRef.current = 0;
136528
136535
  progressRef.current = 0;
136529
- holdRef.current = 0;
136530
136536
  setProgress(0);
136531
136537
  setShowProgress(false);
136532
136538
  return;
@@ -136534,7 +136540,7 @@ function Hero() {
136534
136540
  const element = heroRef.current;
136535
136541
  if (!element) return;
136536
136542
  const updateVisibility = (heroTop, heroHeight) => {
136537
- const viewportTop = window.scrollY;
136543
+ const viewportTop = readPageScrollTop();
136538
136544
  const viewportBottom = viewportTop + window.innerHeight;
136539
136545
  const heroBottom = heroTop + heroHeight;
136540
136546
  const isVisible = viewportBottom > heroTop && viewportTop < heroBottom;
@@ -136557,91 +136563,35 @@ function Hero() {
136557
136563
  rafRef.current = requestAnimationFrame(tick);
136558
136564
  }
136559
136565
  };
136560
- scheduleTickRef.current = scheduleTick;
136561
136566
  const updateTarget = () => {
136562
- const scrollY = window.scrollY;
136567
+ const scrollY = readPageScrollTop();
136563
136568
  const heroTop = element.getBoundingClientRect().top + scrollY;
136564
136569
  const heroHeight = element.offsetHeight;
136565
136570
  const travel = Math.max(1, heroHeight - window.innerHeight);
136566
136571
  updateVisibility(heroTop, heroHeight);
136567
- if (!allowScrollProgressRef.current) {
136568
- if (scrollY > heroTop + 2) {
136569
- allowScrollProgressRef.current = true;
136570
- lockedScrollYRef.current = null;
136571
- } else {
136572
- if (lockedScrollYRef.current === null) {
136573
- lockedScrollYRef.current = scrollY;
136574
- }
136575
- if (scrollY !== lockedScrollYRef.current) {
136576
- window.scrollTo({ top: lockedScrollYRef.current, behavior: "auto" });
136577
- }
136578
- lastScrollYRef.current = lockedScrollYRef.current;
136579
- return;
136580
- }
136581
- }
136582
136572
  const scrolled = clamp$5(scrollY - heroTop, 0, travel);
136583
136573
  const nextTarget = scrolled / travel;
136584
136574
  const lastScrollY = lastScrollYRef.current;
136585
136575
  lastScrollYRef.current = scrollY;
136586
136576
  targetRef.current = scrollY < lastScrollY ? nextTarget : Math.max(targetRef.current, nextTarget);
136587
- if (targetRef.current < 1) {
136588
- holdRef.current = 0;
136589
- }
136590
136577
  scheduleTick();
136591
136578
  };
136592
136579
  updateTarget();
136593
136580
  window.addEventListener("scroll", updateTarget, { passive: true });
136581
+ document.addEventListener("scroll", updateTarget, { passive: true });
136582
+ document.body.addEventListener("scroll", updateTarget, { passive: true });
136583
+ document.documentElement.addEventListener("scroll", updateTarget, { passive: true });
136594
136584
  window.addEventListener("resize", updateTarget);
136595
136585
  return () => {
136596
136586
  window.removeEventListener("scroll", updateTarget);
136587
+ document.removeEventListener("scroll", updateTarget);
136588
+ document.body.removeEventListener("scroll", updateTarget);
136589
+ document.documentElement.removeEventListener("scroll", updateTarget);
136597
136590
  window.removeEventListener("resize", updateTarget);
136598
136591
  if (rafRef.current) cancelAnimationFrame(rafRef.current);
136599
136592
  rafRef.current = null;
136600
136593
  };
136601
136594
  }, [reducedMotion, isPortraitMode]);
136602
- reactExports.useEffect(() => {
136603
- if (isMobile || isPortraitMode) {
136604
- allowScrollProgressRef.current = true;
136605
- lockedScrollYRef.current = null;
136606
- return;
136607
- }
136608
- const handleWheel = (event) => {
136609
- const element = heroRef.current;
136610
- if (!element) return;
136611
- const heroTop = element.getBoundingClientRect().top + window.scrollY;
136612
- const heroHeight = element.offsetHeight;
136613
- const heroBottom = heroTop + heroHeight;
136614
- const viewportTop = window.scrollY;
136615
- const viewportBottom = viewportTop + window.innerHeight;
136616
- const isVisible = viewportBottom > heroTop && viewportTop < heroBottom;
136617
- if (!isVisible) return;
136618
- const virtualProgress = clamp$5(targetRef.current + holdRef.current, 0, 1 + FINAL_SCROLL_HOLD);
136619
- const shouldLock = viewportTop <= heroTop + 2 && virtualProgress < 1 + FINAL_SCROLL_HOLD;
136620
- if (!shouldLock) {
136621
- if (!allowScrollProgressRef.current) {
136622
- allowScrollProgressRef.current = true;
136623
- lockedScrollYRef.current = null;
136624
- }
136625
- return;
136626
- }
136627
- event.preventDefault();
136628
- if (allowScrollProgressRef.current) {
136629
- lockedScrollYRef.current = window.scrollY;
136630
- }
136631
- allowScrollProgressRef.current = false;
136632
- if (lockedScrollYRef.current !== null && window.scrollY !== lockedScrollYRef.current) {
136633
- window.scrollTo({ top: lockedScrollYRef.current, behavior: "auto" });
136634
- lastScrollYRef.current = lockedScrollYRef.current;
136635
- }
136636
- const delta = event.deltaY / (window.innerHeight * 1.6);
136637
- const nextVirtual = clamp$5(virtualProgress + delta, 0, 1 + FINAL_SCROLL_HOLD);
136638
- targetRef.current = Math.min(1, nextVirtual);
136639
- holdRef.current = Math.max(0, nextVirtual - 1);
136640
- scheduleTickRef.current();
136641
- };
136642
- window.addEventListener("wheel", handleWheel, { passive: false });
136643
- return () => window.removeEventListener("wheel", handleWheel);
136644
- }, [isMobile, isPortraitMode]);
136645
136595
  reactExports.useEffect(() => {
136646
136596
  if (!questDialogOpen) {
136647
136597
  return;
@@ -136739,6 +136689,28 @@ function Hero() {
136739
136689
  const shouldShowConnectorCoach = connectorAvailabilityResolved && connectorCoachMode !== null;
136740
136690
  const shouldShowTutorialCoach = onboardingHydrated && !firstRunHandled && !neverRemind;
136741
136691
  const entryCoachOpen = !entryCoachDismissed && !createDialogOpen && !questDialogOpen && (shouldShowConnectorCoach || shouldShowTutorialCoach);
136692
+ reactExports.useEffect(() => {
136693
+ const htmlStyle = document.documentElement.style;
136694
+ const bodyStyle = document.body.style;
136695
+ const previousHtmlOverflowY = htmlStyle.overflowY;
136696
+ const previousHtmlOverflowX = htmlStyle.overflowX;
136697
+ const previousBodyOverflow = bodyStyle.overflow;
136698
+ const previousBodyOverflowX = bodyStyle.overflowX;
136699
+ const previousBodyOverflowY = bodyStyle.overflowY;
136700
+ const shouldLockBackground = landingModalOpen || entryCoachOpen;
136701
+ htmlStyle.overflowX = "hidden";
136702
+ htmlStyle.overflowY = shouldLockBackground ? "hidden" : "auto";
136703
+ bodyStyle.overflow = shouldLockBackground ? "hidden" : "auto";
136704
+ bodyStyle.overflowX = "hidden";
136705
+ bodyStyle.overflowY = shouldLockBackground ? "hidden" : "auto";
136706
+ return () => {
136707
+ htmlStyle.overflowY = previousHtmlOverflowY;
136708
+ htmlStyle.overflowX = previousHtmlOverflowX;
136709
+ bodyStyle.overflow = previousBodyOverflow;
136710
+ bodyStyle.overflowX = previousBodyOverflowX;
136711
+ bodyStyle.overflowY = previousBodyOverflowY;
136712
+ };
136713
+ }, [entryCoachOpen, landingModalOpen]);
136742
136714
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
136743
136715
  /* @__PURE__ */ jsxRuntimeExports.jsxs(
136744
136716
  "div",
@@ -136878,6 +136850,9 @@ function Hero() {
136878
136850
  showConnectorStep: shouldShowConnectorCoach,
136879
136851
  showTutorialStep: shouldShowTutorialCoach,
136880
136852
  onClose: () => setEntryCoachDismissed(true),
136853
+ onSetLanguage: (language) => {
136854
+ void saveLanguagePreference(language);
136855
+ },
136881
136856
  onOpenConnectorSettings: () => {
136882
136857
  setEntryCoachDismissed(true);
136883
136858
  navigate("/settings/connector", { state: { configName: "connectors" } });
@@ -137614,6 +137589,9 @@ function flattenQuestExplorerPayload(projectId, payload) {
137614
137589
  };
137615
137590
  }
137616
137591
  async function loadQuestTree(projectId, force = false) {
137592
+ if (force) {
137593
+ invalidateQuestFileTree(projectId);
137594
+ }
137617
137595
  const cached = treeCache.get(projectId);
137618
137596
  if (!force && cached && cached.expiresAt > Date.now()) {
137619
137597
  return cached.payload;
@@ -137626,6 +137604,21 @@ async function loadQuestTree(projectId, force = false) {
137626
137604
  });
137627
137605
  return payload;
137628
137606
  }
137607
+ function invalidateQuestFileTree(projectId) {
137608
+ const normalizedProjectId = typeof projectId === "string" ? projectId.trim() : "";
137609
+ if (!normalizedProjectId) {
137610
+ treeCache.clear();
137611
+ fileCache.clear();
137612
+ return;
137613
+ }
137614
+ treeCache.delete(normalizedProjectId);
137615
+ for (const key of Array.from(fileCache.keys())) {
137616
+ const ref = parseQuestNodeId(key);
137617
+ if (ref?.projectId === normalizedProjectId) {
137618
+ fileCache.delete(key);
137619
+ }
137620
+ }
137621
+ }
137629
137622
  function getCachedFile(fileId) {
137630
137623
  return fileCache.get(fileId) || null;
137631
137624
  }
@@ -137661,15 +137654,15 @@ function resolveQuestDocumentPath(document) {
137661
137654
  }
137662
137655
  return null;
137663
137656
  }
137664
- async function listQuestFiles(projectId, parentId) {
137665
- const tree = await loadQuestTree(projectId);
137657
+ async function listQuestFiles(projectId, parentId, options = {}) {
137658
+ const tree = await loadQuestTree(projectId, options.force === true);
137666
137659
  if (parentId === void 0 || parentId === null) {
137667
137660
  return tree.files.filter((item) => item.parent_id === null);
137668
137661
  }
137669
137662
  return tree.files.filter((item) => item.parent_id === parentId);
137670
137663
  }
137671
- async function getQuestFileTree(projectId) {
137672
- return await loadQuestTree(projectId);
137664
+ async function getQuestFileTree(projectId, options = {}) {
137665
+ return await loadQuestTree(projectId, options.force === true);
137673
137666
  }
137674
137667
  async function getQuestFile(fileId) {
137675
137668
  const cached = getCachedFile(fileId);
@@ -137814,12 +137807,12 @@ const FILES_BASE = "/api/v1/files";
137814
137807
  async function listFiles(projectId, parentId) {
137815
137808
  return await listQuestFiles(projectId, parentId);
137816
137809
  }
137817
- async function getFileTree(projectId) {
137810
+ async function getFileTree(projectId, options = {}) {
137818
137811
  const demoTree = buildDemoFileTree(projectId);
137819
137812
  if (demoTree) {
137820
137813
  return demoTree;
137821
137814
  }
137822
- return await getQuestFileTree(projectId);
137815
+ return await getQuestFileTree(projectId, options);
137823
137816
  }
137824
137817
  async function searchFiles(projectId, params) {
137825
137818
  const query = new URLSearchParams();
@@ -138391,10 +138384,10 @@ const useFileTreeStore = create$3(
138391
138384
  movedFileIds: /* @__PURE__ */ new Set(),
138392
138385
  renamedFileIds: /* @__PURE__ */ new Set(),
138393
138386
  // Load files for a project
138394
- loadFiles: async (projectId) => {
138387
+ loadFiles: async (projectId, options = {}) => {
138395
138388
  set({ isLoading: true, error: null, projectId });
138396
138389
  try {
138397
- const response = await getFileTree(projectId);
138390
+ const response = await getFileTree(projectId, options);
138398
138391
  const files = response?.files;
138399
138392
  const nodes = buildFileTree(files);
138400
138393
  set({ nodes, isLoading: false });
@@ -138408,7 +138401,7 @@ const useFileTreeStore = create$3(
138408
138401
  refresh: async () => {
138409
138402
  const { projectId } = get();
138410
138403
  if (projectId) {
138411
- await get().loadFiles(projectId);
138404
+ await get().loadFiles(projectId, { force: true });
138412
138405
  }
138413
138406
  },
138414
138407
  // Toggle folder expanded state
@@ -139608,11 +139601,16 @@ function useOpenFile() {
139608
139601
  );
139609
139602
  const openNotebook = reactExports.useCallback(
139610
139603
  (resourceId, resourceName, projectId, options = {}) => {
139604
+ const mergedCustomData = projectId || options.readonly || options.customData ? {
139605
+ ...options.customData || {},
139606
+ ...projectId ? { projectId } : {},
139607
+ ...options.readonly ? { readonly: Boolean(options.readonly) } : {}
139608
+ } : void 0;
139611
139609
  const context = {
139612
139610
  type: "notebook",
139613
139611
  resourceId,
139614
139612
  resourceName,
139615
- customData: projectId || options.readonly ? { projectId, readonly: Boolean(options.readonly) } : void 0
139613
+ customData: mergedCustomData
139616
139614
  };
139617
139615
  return openTab({
139618
139616
  pluginId: BUILTIN_PLUGINS.NOTEBOOK,
@@ -156019,71 +156017,71 @@ const BUILTIN_PLUGIN_IMPORTS = {
156019
156017
  // Implemented Plugins
156020
156018
  // ============================================================
156021
156019
  // Code Viewer Plugin
156022
- "@ds/plugin-code-viewer": () => __vitePreload(() => import('./CodeViewerPlugin-DT54ysXa.js'),true?__vite__mapDeps([0,1,2,3]):void 0).then((m) => ({
156020
+ "@ds/plugin-code-viewer": () => __vitePreload(() => import('./CodeViewerPlugin-DoX_fI9l.js'),true?__vite__mapDeps([0,1,2,3]):void 0).then((m) => ({
156023
156021
  default: m.default
156024
156022
  })),
156025
156023
  // Code Editor Plugin (Monaco)
156026
- "@ds/plugin-code-editor": () => __vitePreload(() => import('./CodeEditorPlugin-B-xicq1e.js'),true?__vite__mapDeps([4,5,6,7,8,9]):void 0).then((m) => ({
156024
+ "@ds/plugin-code-editor": () => __vitePreload(() => import('./CodeEditorPlugin-DU9G0Tox.js'),true?__vite__mapDeps([4,5,6,7,8,9]):void 0).then((m) => ({
156027
156025
  default: m.default
156028
156026
  })),
156029
156027
  // Text Viewer Plugin
156030
- "@ds/plugin-text-viewer": () => __vitePreload(() => import('./TextViewerPlugin-C-nVAZb_.js'),true?__vite__mapDeps([10,1,3,11]):void 0).then((m) => ({
156028
+ "@ds/plugin-text-viewer": () => __vitePreload(() => import('./TextViewerPlugin-CRkT9yNy.js'),true?__vite__mapDeps([10,1,3,11]):void 0).then((m) => ({
156031
156029
  default: m.default
156032
156030
  })),
156033
156031
  // Markdown Viewer Plugin
156034
- "@ds/plugin-markdown-viewer": () => __vitePreload(() => import('./MarkdownViewerPlugin-BzdVH9Bx.js'),true?__vite__mapDeps([12,2]):void 0).then((m) => ({
156032
+ "@ds/plugin-markdown-viewer": () => __vitePreload(() => import('./MarkdownViewerPlugin-xjmrqv_8.js'),true?__vite__mapDeps([12,2]):void 0).then((m) => ({
156035
156033
  default: m.default
156036
156034
  })),
156037
156035
  // Image Viewer Plugin
156038
- "@ds/plugin-image-viewer": () => __vitePreload(() => import('./ImageViewerPlugin-OcVo33jV.js'),true?__vite__mapDeps([13,14,15]):void 0).then((m) => ({
156036
+ "@ds/plugin-image-viewer": () => __vitePreload(() => import('./ImageViewerPlugin-tcPkfY_x.js'),true?__vite__mapDeps([13,14,15]):void 0).then((m) => ({
156039
156037
  default: m.default
156040
156038
  })),
156041
156039
  // Document Viewer Plugin (Office documents)
156042
- "@ds/plugin-doc-viewer": () => __vitePreload(() => import('./DocViewerPlugin-DQtKT-VD.js'),true?[]:void 0).then((m) => ({
156040
+ "@ds/plugin-doc-viewer": () => __vitePreload(() => import('./DocViewerPlugin-C4FWIXuU.js'),true?[]:void 0).then((m) => ({
156043
156041
  default: m.default
156044
156042
  })),
156045
156043
  // PDF Viewer Plugin (Stage 06)
156046
- "@ds/plugin-pdf-viewer": () => __vitePreload(() => import('./PdfViewerPlugin-CmlDxbhU.js'),true?__vite__mapDeps([16,6,17,18,19,15,11,20,21]):void 0).then((m) => ({
156044
+ "@ds/plugin-pdf-viewer": () => __vitePreload(() => import('./PdfViewerPlugin-CsCXMo9S.js'),true?__vite__mapDeps([16,6,17,18,19,15,11,20,21]):void 0).then((m) => ({
156047
156045
  default: m.default
156048
156046
  })),
156049
156047
  // PDF Markdown Plugin (MinerU)
156050
- "@ds/plugin-pdf-markdown": () => __vitePreload(() => import('./PdfMarkdownPlugin-DW2ej8Vk.js'),true?__vite__mapDeps([22,23,24]):void 0).then((m) => ({
156048
+ "@ds/plugin-pdf-markdown": () => __vitePreload(() => import('./PdfMarkdownPlugin-Bq88XT4G.js'),true?__vite__mapDeps([22,23,24]):void 0).then((m) => ({
156051
156049
  default: m.default
156052
156050
  })),
156053
156051
  // CLI Plugin
156054
- "@ds/plugin-cli": () => __vitePreload(() => import('./CliPlugin-CB1YODQn.js'),true?__vite__mapDeps([25,26,11,20,27]):void 0).then((m) => ({
156052
+ "@ds/plugin-cli": () => __vitePreload(() => import('./CliPlugin-C9gzJX41.js'),true?__vite__mapDeps([25,26,11,20,27]):void 0).then((m) => ({
156055
156053
  default: m.default
156056
156054
  })),
156057
156055
  // Lab Plugin (Home)
156058
- "@ds/plugin-lab": () => __vitePreload(() => import('./LabPlugin-Ciz1gDaX.js'),true?__vite__mapDeps([28,29]):void 0).then((m) => ({
156056
+ "@ds/plugin-lab": () => __vitePreload(() => import('./LabPlugin-Bje0ayoC.js'),true?__vite__mapDeps([28,29]):void 0).then((m) => ({
156059
156057
  default: m.default
156060
156058
  })),
156061
156059
  // ============================================================
156062
156060
  // Notebook Plugin (Novel Integration)
156063
156061
  // ============================================================
156064
156062
  // Notebook plugin with Novel editor
156065
- "@ds/plugin-notebook": () => __vitePreload(() => import('./index-C3r2iGrp.js'),true?__vite__mapDeps([30,31,23,24,32,33,34,20,2,14,35,36,37,8,9,38]):void 0).then((m) => ({
156063
+ "@ds/plugin-notebook": () => __vitePreload(() => import('./index-Duvz8Ip0.js'),true?__vite__mapDeps([30,31,23,24,32,33,34,20,2,14,35,36,37,8,9,38]):void 0).then((m) => ({
156066
156064
  default: m.default
156067
156065
  })),
156068
156066
  // ============================================================
156069
156067
  // LaTeX Plugin (Stage 11)
156070
156068
  // ============================================================
156071
- "@ds/plugin-latex": () => __vitePreload(() => import('./LatexPlugin-BhmjNQRC.js'),true?__vite__mapDeps([39,34,7,18,19,15]):void 0).then((m) => ({
156069
+ "@ds/plugin-latex": () => __vitePreload(() => import('./LatexPlugin-CVsBzAln.js'),true?__vite__mapDeps([39,34,7,18,19,15]):void 0).then((m) => ({
156072
156070
  default: m.default
156073
156071
  })),
156074
- "@ds/plugin-git-diff-viewer": () => __vitePreload(() => import('./GitDiffViewerPlugin-hqHbCfnv.js'),true?__vite__mapDeps([40,13,14,15,12,2,31,23,24,32,33,34,20,35,36,37,8,9,38,16,6,17,18,19,11,21]):void 0).then((m) => ({
156072
+ "@ds/plugin-git-diff-viewer": () => __vitePreload(() => import('./GitDiffViewerPlugin-BgfFMgtf.js'),true?__vite__mapDeps([40,13,14,15,12,2,31,23,24,32,33,34,20,35,36,37,8,9,38,16,6,17,18,19,11,21]):void 0).then((m) => ({
156075
156073
  default: m.default
156076
156074
  })),
156077
156075
  // ============================================================
156078
156076
  // Placeholder Plugins - to be implemented
156079
156077
  // ============================================================
156080
- "@ds/plugin-search": () => __vitePreload(() => import('./SearchPlugin-DAjQZPSv.js'),true?__vite__mapDeps([41,42]):void 0).then((m) => ({
156078
+ "@ds/plugin-search": () => __vitePreload(() => import('./SearchPlugin-oUPvy19k.js'),true?__vite__mapDeps([41,42]):void 0).then((m) => ({
156081
156079
  default: m.default
156082
156080
  })),
156083
- "@ds/plugin-analysis": () => __vitePreload(() => import('./AnalysisPlugin-DeyzPEhV.js'),true?[]:void 0).then((m) => ({
156081
+ "@ds/plugin-analysis": () => __vitePreload(() => import('./AnalysisPlugin-BSVx6dXE.js'),true?[]:void 0).then((m) => ({
156084
156082
  default: m.default
156085
156083
  })),
156086
- "@ds/plugin-marketplace": () => __vitePreload(() => import('./MarketplacePlugin-DmyHspXt.js'),true?__vite__mapDeps([43,37,14]):void 0).then((m) => ({
156084
+ "@ds/plugin-marketplace": () => __vitePreload(() => import('./MarketplacePlugin-mMM2A8wP.js'),true?__vite__mapDeps([43,37,14]):void 0).then((m) => ({
156087
156085
  default: m.default
156088
156086
  }))
156089
156087
  };
@@ -173607,7 +173605,7 @@ const CopilotDockHeaderPortalContext = reactExports.createContext(null);
173607
173605
  const useCopilotDockHeaderPortal = () => reactExports.useContext(CopilotDockHeaderPortalContext);
173608
173606
  const CopilotDockCallbacksContext = reactExports.createContext(null);
173609
173607
  const useCopilotDockCallbacks = () => reactExports.useContext(CopilotDockCallbacksContext);
173610
- const AiManusChatView$1 = dynamic(() => __vitePreload(() => import('./AiManusChatView-CnJcXynW.js').then(n => n.c),true?__vite__mapDeps([44,5,26,11,1,17,9,29,23,24,36]):void 0), {
173608
+ const AiManusChatView$1 = dynamic(() => __vitePreload(() => import('./AiManusChatView-DaF9Nge_.js').then(n => n.c),true?__vite__mapDeps([44,5,26,11,1,17,9,29,23,24,36]):void 0), {
173611
173609
  loading: () => /* @__PURE__ */ jsxRuntimeExports.jsx(CopilotDockLoading, {})
173612
173610
  });
173613
173611
  const SPRING = {
@@ -175199,7 +175197,7 @@ function WorkspaceTooltipLayer({ rootId = "workspace-root" }) {
175199
175197
  );
175200
175198
  }
175201
175199
 
175202
- const AiManusChatView = dynamic(() => __vitePreload(() => import('./AiManusChatView-CnJcXynW.js').then(n => n.c),true?__vite__mapDeps([44,5,26,11,1,17,9,29,23,24,36]):void 0), {
175200
+ const AiManusChatView = dynamic(() => __vitePreload(() => import('./AiManusChatView-DaF9Nge_.js').then(n => n.c),true?__vite__mapDeps([44,5,26,11,1,17,9,29,23,24,36]):void 0), {
175203
175201
  loading: () => /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex h-full items-center justify-center text-xs text-muted-foreground", children: "Loading Copilot…" })
175204
175202
  });
175205
175203
  function WelcomeCopilotView({
@@ -177156,7 +177154,7 @@ clamp$2 = function clamp(min, max, value) {
177156
177154
  toArray$1 = function toArray(value, scope, leaveStrings) {
177157
177155
  return _context && !scope && _context.selector ? _context.selector(value) : _isString(value) && !leaveStrings && (_coreInitted || !_wake()) ? _slice.call((scope || _doc$1).querySelectorAll(value), 0) : _isArray(value) ? _flatten(value, leaveStrings) : _isArrayLike(value) ? _slice.call(value, 0) : value ? [value] : [];
177158
177156
  },
177159
- selector$4 = function selector(value) {
177157
+ selector$5 = function selector(value) {
177160
177158
  value = toArray$1(value)[0] || _warn("Invalid scope") || {};
177161
177159
  return function (v) {
177162
177160
  var el = value.current || value.nativeElement || value;
@@ -180402,7 +180400,7 @@ var _media = [],
180402
180400
 
180403
180401
  var Context = /*#__PURE__*/function () {
180404
180402
  function Context(func, scope) {
180405
- this.selector = scope && selector$4(scope);
180403
+ this.selector = scope && selector$5(scope);
180406
180404
  this.data = [];
180407
180405
  this._r = []; // returned/cleanup functions
180408
180406
 
@@ -180432,7 +180430,7 @@ var Context = /*#__PURE__*/function () {
180432
180430
  prevSelector = self.selector,
180433
180431
  result;
180434
180432
  prev && prev !== self && prev.data.push(self);
180435
- scope && (self.selector = selector$4(scope));
180433
+ scope && (self.selector = selector$5(scope));
180436
180434
  _context = self;
180437
180435
  result = func.apply(self, arguments);
180438
180436
  _isFunction(result) && self._r.push(result);
@@ -180808,7 +180806,7 @@ var _gsap = {
180808
180806
  clamp: clamp$2,
180809
180807
  splitColor: splitColor,
180810
180808
  toArray: toArray$1,
180811
- selector: selector$4,
180809
+ selector: selector$5,
180812
180810
  mapRange: mapRange,
180813
180811
  pipe: pipe,
180814
180812
  unitize: unitize,
@@ -223165,6 +223163,26 @@ function useEdgesState(initialEdges) {
223165
223163
  const onEdgesChange = reactExports.useCallback((changes) => setEdges((eds) => applyEdgeChanges(changes, eds)), []);
223166
223164
  return [edges, setEdges, onEdgesChange];
223167
223165
  }
223166
+ const selector$4 = (options) => (s) => {
223167
+ if (!options.includeHiddenNodes) {
223168
+ return s.nodesInitialized;
223169
+ }
223170
+ if (s.nodeLookup.size === 0) {
223171
+ return false;
223172
+ }
223173
+ for (const [, { internals }] of s.nodeLookup) {
223174
+ if (internals.handleBounds === void 0 || !nodeHasDimensions(internals.userNode)) {
223175
+ return false;
223176
+ }
223177
+ }
223178
+ return true;
223179
+ };
223180
+ function useNodesInitialized(options = {
223181
+ includeHiddenNodes: false
223182
+ }) {
223183
+ const initialized = useStore(selector$4(options));
223184
+ return initialized;
223185
+ }
223168
223186
  function LinePattern({ dimensions, lineWidth, variant, className }) {
223169
223187
  return jsxRuntimeExports.jsx("path", { strokeWidth: lineWidth, d: `M${dimensions[0] / 2} 0 V${dimensions[1]} M0 ${dimensions[1] / 2} H${dimensions[0]}`, className: cc(["react-flow__background-pattern", variant, className]) });
223170
223188
  }
@@ -225082,8 +225100,21 @@ function resolveLabCanvasSelectionSemantic({
225082
225100
  return null;
225083
225101
  }
225084
225102
 
225085
- const DAGRE_NODE_WIDTH = 190;
225086
- const DAGRE_NODE_HEIGHT = 110;
225103
+ const DAGRE_NODE_WIDTH = 228;
225104
+ const DAGRE_NODE_HEIGHT = 144;
225105
+ const DAGRE_BRANCH_NODE_BASE_HEIGHT = 96;
225106
+ const DAGRE_BRANCH_NODE_MIN_HEIGHT = 160;
225107
+ const DAGRE_BRANCH_NODE_TEXT_ROW_HEIGHT = 16;
225108
+ const DAGRE_BRANCH_NODE_SUMMARY_HEIGHT = 36;
225109
+ const DAGRE_BRANCH_NODE_METRIC_HEIGHT = 84;
225110
+ const DAGRE_BRANCH_NODE_MEMORY_HEIGHT = 56;
225111
+ const DAGRE_BRANCH_NODE_TREND_HEIGHT = 48;
225112
+ const DAGRE_STAGE_NODE_HEIGHT = 132;
225113
+ const DAGRE_EVENT_NODE_HEIGHT = 140;
225114
+ const DAGRE_LAYOUT_BUFFER_HEIGHT = 16;
225115
+ const AUTO_LAYOUT_GAP_X = 36;
225116
+ const AUTO_LAYOUT_GAP_Y = 32;
225117
+ const AUTO_LAYOUT_MAX_PASSES = 8;
225087
225118
  const DAY_MS = 24 * 60 * 60 * 1e3;
225088
225119
  const STALE_BRANCH_MS = 3 * DAY_MS;
225089
225120
  const EMPTY_GRAPH_NODES = [];
@@ -226000,8 +226031,11 @@ const buildDagreLayout = (nodes, edges, options) => {
226000
226031
  nodesep: options?.nodesep ?? 70,
226001
226032
  ranksep: options?.ranksep ?? 120
226002
226033
  });
226034
+ const nodeSizes = /* @__PURE__ */ new Map();
226003
226035
  nodes.forEach((node) => {
226004
- graph.setNode(node.node_id, { width: DAGRE_NODE_WIDTH, height: DAGRE_NODE_HEIGHT });
226036
+ const size = options?.getNodeSize?.(node) ?? DEFAULT_DAGRE_NODE_SIZE;
226037
+ nodeSizes.set(node.node_id, size);
226038
+ graph.setNode(node.node_id, size);
226005
226039
  });
226006
226040
  edges.forEach((edge) => {
226007
226041
  graph.setEdge(edge.source, edge.target);
@@ -226014,23 +226048,35 @@ const buildDagreLayout = (nodes, edges, options) => {
226014
226048
  positions[node.node_id] = { x: 0, y: 0 };
226015
226049
  return;
226016
226050
  }
226051
+ const size = nodeSizes.get(node.node_id) ?? DEFAULT_DAGRE_NODE_SIZE;
226017
226052
  positions[node.node_id] = {
226018
- x: layoutNode.x - DAGRE_NODE_WIDTH / 2,
226019
- y: layoutNode.y - DAGRE_NODE_HEIGHT / 2
226053
+ x: layoutNode.x - size.width / 2,
226054
+ y: layoutNode.y - size.height / 2
226020
226055
  };
226021
226056
  });
226022
226057
  return positions;
226023
226058
  };
226024
- const buildBranchLayout = (nodes, edges) => {
226059
+ const buildBranchLayout = (nodes, edges, options) => {
226025
226060
  if (nodes.length === 0) return {};
226026
226061
  return buildDagreLayout(nodes, edges, {
226027
226062
  rankdir: "LR",
226028
226063
  nodesep: nodes.length > 60 ? 44 : nodes.length > 24 ? 56 : 78,
226029
- ranksep: nodes.length > 100 ? 96 : nodes.length > 60 ? 112 : 136
226064
+ ranksep: nodes.length > 100 ? 96 : nodes.length > 60 ? 112 : 136,
226065
+ getNodeSize: (node) => estimateBranchNodeSize(node, options)
226030
226066
  });
226031
226067
  };
226032
- const buildEventLayout = (nodes, edges) => buildDagreLayout(nodes, edges, { rankdir: "TB", nodesep: 60, ranksep: 110 });
226033
- const buildStageLayout = (nodes, edges) => buildDagreLayout(nodes, edges, { rankdir: "LR", nodesep: 120, ranksep: 160 });
226068
+ const buildEventLayout = (nodes, edges) => buildDagreLayout(nodes, edges, {
226069
+ rankdir: "TB",
226070
+ nodesep: 60,
226071
+ ranksep: 110,
226072
+ getNodeSize: () => ({ width: DAGRE_NODE_WIDTH, height: DAGRE_EVENT_NODE_HEIGHT })
226073
+ });
226074
+ const buildStageLayout = (nodes, edges) => buildDagreLayout(nodes, edges, {
226075
+ rankdir: "LR",
226076
+ nodesep: 120,
226077
+ ranksep: 160,
226078
+ getNodeSize: () => ({ width: DAGRE_NODE_WIDTH, height: DAGRE_STAGE_NODE_HEIGHT })
226079
+ });
226034
226080
  function resolveLayoutMap(layoutJson, viewMode) {
226035
226081
  if (!layoutJson) return {};
226036
226082
  const candidate = layoutJson[viewMode];
@@ -226242,6 +226288,123 @@ const shallowArrayEqual = (a, b) => {
226242
226288
  }
226243
226289
  return true;
226244
226290
  };
226291
+ const DEFAULT_DAGRE_NODE_SIZE = {
226292
+ width: DAGRE_NODE_WIDTH,
226293
+ height: DAGRE_NODE_HEIGHT
226294
+ };
226295
+ const estimateBranchNodeSize = (node, options) => {
226296
+ const isPlaceholder = Boolean(node.placeholder || node.node_kind === "placeholder");
226297
+ const isBaselineRoot = node.node_kind === "baseline_root";
226298
+ const branchInsight = node.branch_name ? options.branchInsights.get(node.branch_name) ?? null : null;
226299
+ const branchMemory = node.branch_name ? options.memoryByBranch.get(node.branch_name) ?? null : null;
226300
+ const fallbackSummary = clampCanvasText(node.node_summary?.last_error, 96) || clampCanvasText(node.node_summary?.last_reply, 96) || clampCanvasText(node.node_summary?.last_event_type, 96) || null;
226301
+ let height = DAGRE_BRANCH_NODE_BASE_HEIGHT;
226302
+ const hasPrimarySubtitle = isBaselineRoot ? Boolean(node.status) : Boolean(node.idea_title || branchInsight?.stageLabel || node.idea_id);
226303
+ if (hasPrimarySubtitle) {
226304
+ height += DAGRE_BRANCH_NODE_TEXT_ROW_HEIGHT;
226305
+ }
226306
+ if (node.parent_branch || node.foundation_label) {
226307
+ height += DAGRE_BRANCH_NODE_TEXT_ROW_HEIGHT;
226308
+ }
226309
+ if (options.nodeDisplayMode === "metric") {
226310
+ height += DAGRE_BRANCH_NODE_METRIC_HEIGHT;
226311
+ } else if (branchInsight?.nowDoing || node.idea_problem || fallbackSummary) {
226312
+ height += DAGRE_BRANCH_NODE_SUMMARY_HEIGHT;
226313
+ }
226314
+ if (!isPlaceholder && !isBaselineRoot && branchMemory) {
226315
+ height += DAGRE_BRANCH_NODE_MEMORY_HEIGHT;
226316
+ }
226317
+ if ((extractTrend(node, {
226318
+ metricKey: options.curveMetric || null,
226319
+ mode: options.curveMode
226320
+ }) || []).length > 0) {
226321
+ height += DAGRE_BRANCH_NODE_TREND_HEIGHT;
226322
+ }
226323
+ if (isBaselineRoot) {
226324
+ height += 10;
226325
+ }
226326
+ return {
226327
+ width: DAGRE_NODE_WIDTH,
226328
+ height: Math.max(DAGRE_BRANCH_NODE_MIN_HEIGHT, height + DAGRE_LAYOUT_BUFFER_HEIGHT)
226329
+ };
226330
+ };
226331
+ const resolveNodeMeasuredSize = (node, getMeasuredSize) => {
226332
+ const measured = getMeasuredSize?.(node.id);
226333
+ return {
226334
+ width: measured?.width ?? node.measured?.width ?? node.width ?? DAGRE_NODE_WIDTH,
226335
+ height: measured?.height ?? node.measured?.height ?? node.height ?? DAGRE_NODE_HEIGHT
226336
+ };
226337
+ };
226338
+ const resolveNodeSpacingCollisions = (nodes, options) => {
226339
+ if (nodes.length <= 1) return nodes;
226340
+ const gapX = options.gapX ?? AUTO_LAYOUT_GAP_X;
226341
+ const gapY = options.gapY ?? AUTO_LAYOUT_GAP_Y;
226342
+ const trackedNodes = nodes.filter((node) => !isAgentNode(node));
226343
+ if (trackedNodes.length <= 1) return nodes;
226344
+ const positions = new Map(
226345
+ nodes.map((node) => [node.id, { x: node.position.x, y: node.position.y }])
226346
+ );
226347
+ const sizeById = new Map(
226348
+ trackedNodes.map((node) => [node.id, resolveNodeMeasuredSize(node, options.getMeasuredSize)])
226349
+ );
226350
+ let moved = false;
226351
+ for (let pass = 0; pass < AUTO_LAYOUT_MAX_PASSES; pass += 1) {
226352
+ let passMoved = false;
226353
+ const ordered = [...trackedNodes].sort((left, right) => {
226354
+ const leftPos = positions.get(left.id) ?? left.position;
226355
+ const rightPos = positions.get(right.id) ?? right.position;
226356
+ if (options.viewMode === "event") {
226357
+ return leftPos.y - rightPos.y || leftPos.x - rightPos.x;
226358
+ }
226359
+ return leftPos.x - rightPos.x || leftPos.y - rightPos.y;
226360
+ });
226361
+ for (let index = 0; index < ordered.length; index += 1) {
226362
+ const current = ordered[index];
226363
+ const currentPos = positions.get(current.id) ?? current.position;
226364
+ const currentSize = sizeById.get(current.id) ?? resolveNodeMeasuredSize(current, options.getMeasuredSize);
226365
+ for (let nextIndex = index + 1; nextIndex < ordered.length; nextIndex += 1) {
226366
+ const target = ordered[nextIndex];
226367
+ const targetPos = positions.get(target.id) ?? target.position;
226368
+ const targetSize = sizeById.get(target.id) ?? resolveNodeMeasuredSize(target, options.getMeasuredSize);
226369
+ const overlapsHorizontally = currentPos.x < targetPos.x + targetSize.width + gapX && targetPos.x < currentPos.x + currentSize.width + gapX;
226370
+ const overlapsVertically = currentPos.y < targetPos.y + targetSize.height + gapY && targetPos.y < currentPos.y + currentSize.height + gapY;
226371
+ if (!overlapsHorizontally || !overlapsVertically) {
226372
+ continue;
226373
+ }
226374
+ const verticalShift = currentPos.y + currentSize.height + gapY - targetPos.y;
226375
+ const horizontalShift = currentPos.x + currentSize.width + gapX - targetPos.x;
226376
+ const preferVertical = options.viewMode !== "event";
226377
+ const verticalCost = verticalShift * (preferVertical ? 0.88 : 1.12);
226378
+ const horizontalCost = horizontalShift * (preferVertical ? 1.12 : 0.88);
226379
+ const targetPosition = positions.get(target.id) ?? { x: target.position.x, y: target.position.y };
226380
+ if (verticalCost <= horizontalCost) {
226381
+ targetPosition.y += Math.max(0, verticalShift);
226382
+ } else {
226383
+ targetPosition.x += Math.max(0, horizontalShift);
226384
+ }
226385
+ positions.set(target.id, targetPosition);
226386
+ passMoved = true;
226387
+ moved = true;
226388
+ }
226389
+ }
226390
+ if (!passMoved) {
226391
+ break;
226392
+ }
226393
+ }
226394
+ if (!moved) return nodes;
226395
+ const resolved = nodes.map((node) => {
226396
+ const nextPosition = positions.get(node.id);
226397
+ if (!nextPosition) return node;
226398
+ if (Math.abs(nextPosition.x - node.position.x) < 0.5 && Math.abs(nextPosition.y - node.position.y) < 0.5) {
226399
+ return node;
226400
+ }
226401
+ return {
226402
+ ...node,
226403
+ position: nextPosition
226404
+ };
226405
+ });
226406
+ return areNodesEquivalent(nodes, resolved) ? nodes : resolved;
226407
+ };
226245
226408
  const isAgentNode = (node) => {
226246
226409
  if (!node) return false;
226247
226410
  return node.type === "agentNode" || Boolean(node.data?.isAgent);
@@ -226579,6 +226742,7 @@ function LabQuestGraphCanvasInner({
226579
226742
  const interactionLocked = Boolean(readOnly || atEventId);
226580
226743
  const setSelectionStore = useLabGraphSelectionStore((state) => state.setSelection);
226581
226744
  const flow = useReactFlow();
226745
+ const nodesInitialized = useNodesInitialized();
226582
226746
  const boundsRef = reactExports.useRef(null);
226583
226747
  const fittedViewportRef = reactExports.useRef(/* @__PURE__ */ new Set());
226584
226748
  const [nodes, setNodes, onNodesChange] = useNodesState([]);
@@ -227261,8 +227425,14 @@ function LabQuestGraphCanvasInner({
227261
227425
  [branchEdgesRaw, branchNodeIdSet]
227262
227426
  );
227263
227427
  const branchLayoutFallback = reactExports.useMemo(
227264
- () => buildBranchLayout(branchNodes, branchEdges),
227265
- [branchEdges, branchNodes]
227428
+ () => buildBranchLayout(branchNodes, branchEdges, {
227429
+ nodeDisplayMode,
227430
+ curveMetric: curveMetric || null,
227431
+ curveMode,
227432
+ branchInsights,
227433
+ memoryByBranch
227434
+ }),
227435
+ [branchEdges, branchInsights, branchNodes, curveMetric, curveMode, memoryByBranch, nodeDisplayMode]
227266
227436
  );
227267
227437
  const branchLayoutExplicit = reactExports.useMemo(() => resolveLayoutMap(layoutJson, "branch"), [layoutJson]);
227268
227438
  const branchLayoutMap = reactExports.useMemo(
@@ -227299,8 +227469,14 @@ function LabQuestGraphCanvasInner({
227299
227469
  return edgesRaw.filter((edge) => viewNodeIds.has(edge.source) && viewNodeIds.has(edge.target));
227300
227470
  }, [edgesRaw, viewNodeIds]);
227301
227471
  const fallbackLayout = reactExports.useMemo(
227302
- () => viewMode === "event" ? buildEventLayout(viewNodes, viewEdges) : viewMode === "stage" ? buildStageLayout(viewNodes, viewEdges) : buildBranchLayout(viewNodes, viewEdges),
227303
- [viewMode, viewNodes, viewEdges]
227472
+ () => viewMode === "event" ? buildEventLayout(viewNodes, viewEdges) : viewMode === "stage" ? buildStageLayout(viewNodes, viewEdges) : buildBranchLayout(viewNodes, viewEdges, {
227473
+ nodeDisplayMode,
227474
+ curveMetric: curveMetric || null,
227475
+ curveMode,
227476
+ branchInsights,
227477
+ memoryByBranch
227478
+ }),
227479
+ [branchInsights, curveMetric, curveMode, memoryByBranch, nodeDisplayMode, viewEdges, viewMode, viewNodes]
227304
227480
  );
227305
227481
  const explicitLayout = reactExports.useMemo(
227306
227482
  () => ({
@@ -227558,6 +227734,25 @@ function LabQuestGraphCanvasInner({
227558
227734
  });
227559
227735
  setEdges((prev) => areEdgesEquivalent(prev, computedEdges) ? prev : computedEdges);
227560
227736
  }, [combinedNodes, computedEdges, explicitLayout, setEdges, setNodes, viewMode]);
227737
+ reactExports.useEffect(() => {
227738
+ if (!nodesInitialized) return;
227739
+ if (nodes.length <= 1) return;
227740
+ if (nodes.some((node) => node.dragging)) return;
227741
+ const resolved = resolveNodeSpacingCollisions(nodes, {
227742
+ viewMode,
227743
+ getMeasuredSize: (id) => {
227744
+ const internal = flow.getInternalNode(id);
227745
+ if (!internal) return null;
227746
+ return {
227747
+ width: internal.measured?.width ?? internal.width ?? DAGRE_NODE_WIDTH,
227748
+ height: internal.measured?.height ?? internal.height ?? DAGRE_NODE_HEIGHT
227749
+ };
227750
+ }
227751
+ });
227752
+ if (!areNodesEquivalent(nodes, resolved)) {
227753
+ setNodes(resolved);
227754
+ }
227755
+ }, [flow, nodes, nodesInitialized, setNodes, viewMode]);
227561
227756
  reactExports.useEffect(() => {
227562
227757
  viewModeRef.current = viewMode;
227563
227758
  }, [viewMode]);
@@ -227643,8 +227838,11 @@ function LabQuestGraphCanvasInner({
227643
227838
  if (!targetId) return;
227644
227839
  const target = nodes.find((node) => node.id === targetId);
227645
227840
  if (!target) return;
227646
- const centerX = target.position.x + 120;
227647
- const centerY = target.position.y + 60;
227841
+ const internal = flow.getInternalNode(targetId);
227842
+ const targetWidth = internal?.measured?.width ?? target.measured?.width ?? target.width ?? DAGRE_NODE_WIDTH;
227843
+ const targetHeight = internal?.measured?.height ?? target.measured?.height ?? target.height ?? DAGRE_NODE_HEIGHT;
227844
+ const centerX = target.position.x + targetWidth / 2;
227845
+ const centerY = target.position.y + targetHeight / 2;
227648
227846
  try {
227649
227847
  flow.setCenter(centerX, centerY, { duration: 500 });
227650
227848
  lastFocusedKeyRef.current = focusKey;
@@ -230400,11 +230598,12 @@ function QuestStageSurface({
230400
230598
  const node = await openQuestDocumentAsFileNode(questId, documentId);
230401
230599
  await openFileInTab(node, {
230402
230600
  customData: {
230403
- projectId: questId
230601
+ projectId: questId,
230602
+ quest_stage_selection: stageSelection || null
230404
230603
  }
230405
230604
  });
230406
230605
  },
230407
- [openFileInTab, questId]
230606
+ [openFileInTab, questId, stageSelection]
230408
230607
  );
230409
230608
  const downloadDocument = reactExports.useCallback(
230410
230609
  async (documentId, fallbackName) => {
@@ -230454,12 +230653,13 @@ function QuestStageSurface({
230454
230653
  customData: {
230455
230654
  projectId: questId,
230456
230655
  latexFolderId: folderId,
230457
- mainFileId: null
230656
+ mainFileId: null,
230657
+ quest_stage_selection: stageSelection || null
230458
230658
  }
230459
230659
  },
230460
230660
  title: folderName
230461
230661
  });
230462
- }, [latexRootPath, openTab, questId]);
230662
+ }, [latexRootPath, openTab, questId, stageSelection]);
230463
230663
  const downloadLatexArchive = reactExports.useCallback(async () => {
230464
230664
  if (!latexRootPath) return;
230465
230665
  setArchivePending(true);
@@ -240639,11 +240839,11 @@ function MobileQuestWorkspaceShell({
240639
240839
 
240640
240840
  const EXPLORER_REFRESH_EVENT = "ds:explorer:refresh";
240641
240841
 
240642
- const LabCopilotPanel = dynamic(() => __vitePreload(() => import('./LabCopilotPanel-DdGwhEUV.js'),true?__vite__mapDeps([45,35,26,11,44,5,1,17,9,29,23,24,36]):void 0), {
240842
+ const LabCopilotPanel = dynamic(() => __vitePreload(() => import('./LabCopilotPanel-_dKV60Bf.js'),true?__vite__mapDeps([45,35,26,11,44,5,1,17,9,29,23,24,36]):void 0), {
240643
240843
  loading: () => null
240644
240844
  });
240645
240845
  const LabCopilotHeader = dynamic(
240646
- () => __vitePreload(() => import('./LabCopilotPanel-DdGwhEUV.js'),true?__vite__mapDeps([45,35,26,11,44,5,1,17,9,29,23,24,36]):void 0).then((mod) => mod.LabCopilotHeader),
240846
+ () => __vitePreload(() => import('./LabCopilotPanel-_dKV60Bf.js'),true?__vite__mapDeps([45,35,26,11,44,5,1,17,9,29,23,24,36]):void 0).then((mod) => mod.LabCopilotHeader),
240647
240847
  { loading: () => null }
240648
240848
  );
240649
240849
  const getLabContextSessionId = (tab, projectId) => {
@@ -240757,6 +240957,29 @@ function getQuestWorkspaceStageSelection(tabOrContext) {
240757
240957
  baseline_gate: typeof record.baseline_gate === "string" ? record.baseline_gate : null
240758
240958
  };
240759
240959
  }
240960
+ function normalizeScopedExplorerSelection(selection) {
240961
+ if (!selection) return null;
240962
+ const selectionType = String(selection.selection_type || "").trim();
240963
+ const selectionRef = String(selection.selection_ref || selection.stage_key || "").trim() || null;
240964
+ if (!selectionRef) return null;
240965
+ if (!["branch_node", "stage_node", "baseline_node"].includes(selectionType)) {
240966
+ return null;
240967
+ }
240968
+ return {
240969
+ ...selection,
240970
+ selection_type: selectionType,
240971
+ selection_ref: selectionRef
240972
+ };
240973
+ }
240974
+ function sameScopedExplorerSelection(left, right) {
240975
+ const a = normalizeScopedExplorerSelection(left);
240976
+ const b = normalizeScopedExplorerSelection(right);
240977
+ if (!a && !b) return true;
240978
+ if (!a || !b) return false;
240979
+ const scopeA = (a.scope_paths || []).join("||");
240980
+ const scopeB = (b.scope_paths || []).join("||");
240981
+ return a.selection_ref === b.selection_ref && a.selection_type === b.selection_type && (a.branch_name || null) === (b.branch_name || null) && (a.stage_key || null) === (b.stage_key || null) && (a.worktree_rel_path || null) === (b.worktree_rel_path || null) && (a.compare_base || null) === (b.compare_base || null) && (a.compare_head || null) === (b.compare_head || null) && scopeA === scopeB;
240982
+ }
240760
240983
  function getQuestWorkspaceTitle(view, stageSelection) {
240761
240984
  if (view === "stage") {
240762
240985
  const label = String(stageSelection?.label || stageSelection?.stage_key || "Stage").trim() || "Stage";
@@ -241832,7 +242055,9 @@ function LeftPanel({
241832
242055
  onEnterLab,
241833
242056
  onExitHome,
241834
242057
  localQuestMode = false,
241835
- demoMode = false
242058
+ demoMode = false,
242059
+ workspaceTreeSyncKey = null,
242060
+ workspaceScopeContextKey = null
241836
242061
  }) {
241837
242062
  const { t } = useI18n("workspace");
241838
242063
  const { t: tCommon } = useI18n("common");
@@ -241840,18 +242065,20 @@ function LeftPanel({
241840
242065
  const { addToast } = useToast();
241841
242066
  const openTab = useTabsStore((state) => state.openTab);
241842
242067
  const graphSelection = useLabGraphSelectionStore((state) => state.selection);
241843
- const { createFolder, upload, refresh, isLoading } = useFileTreeStore();
242068
+ const { createFolder, upload, refresh, loadFiles, isLoading } = useFileTreeStore();
241844
242069
  const refreshArxivLibrary = useArxivStore((state) => state.refresh);
241845
242070
  const { openFileInTab, downloadFile, openNotebook } = useOpenFile();
241846
242071
  const fileInputRef = reactExports.useRef(null);
241847
242072
  const explorerBodyRef = reactExports.useRef(null);
241848
242073
  const [activeExplorer, setActiveExplorer] = reactExports.useState("files");
242074
+ const [explorerModePreference, setExplorerModePreference] = reactExports.useState("auto");
241849
242075
  const [hideDotfiles, setHideDotfiles] = reactExports.useState(true);
241850
242076
  const [createFileOpen, setCreateFileOpen] = reactExports.useState(false);
241851
242077
  const [isMenuOpen, setIsMenuOpen] = reactExports.useState(true);
241852
242078
  const [scopedExplorerLabel, setScopedExplorerLabel] = reactExports.useState(null);
241853
242079
  const [scopedExplorerNodes, setScopedExplorerNodes] = reactExports.useState([]);
241854
242080
  const [scopedExplorerLoading, setScopedExplorerLoading] = reactExports.useState(false);
242081
+ const [stickyScopedSelection, setStickyScopedSelection] = reactExports.useState(null);
241855
242082
  const [explorerLocation, setExplorerLocation] = reactExports.useState(DEFAULT_EXPLORER_LOCATION);
241856
242083
  const [diffFiles, setDiffFiles] = reactExports.useState([]);
241857
242084
  const [diffCompareBase, setDiffCompareBase] = reactExports.useState(null);
@@ -241871,31 +242098,68 @@ function LeftPanel({
241871
242098
  }
241872
242099
  return getQuestWorkspaceStageSelection(activeTab);
241873
242100
  }, [activeTab, projectId]);
241874
- const activeDiffScopedSelection = reactExports.useMemo(() => {
241875
- if (activeTab?.pluginId !== BUILTIN_PLUGINS.GIT_DIFF_VIEWER || !tabMatchesProject(activeTab, projectId)) {
242101
+ const activeTabStageSelection = reactExports.useMemo(() => {
242102
+ if (!tabMatchesProject(activeTab, projectId)) {
241876
242103
  return null;
241877
242104
  }
241878
242105
  return getQuestWorkspaceStageSelection(activeTab);
241879
242106
  }, [activeTab, projectId]);
242107
+ const explorerStageSelection = reactExports.useMemo(() => {
242108
+ if (activeQuestWorkspaceView === "stage" && activeQuestStageSelection) {
242109
+ return activeQuestStageSelection;
242110
+ }
242111
+ return activeTabStageSelection || graphSelection || null;
242112
+ }, [activeQuestStageSelection, activeQuestWorkspaceView, activeTabStageSelection, graphSelection]);
242113
+ const liveScopedExplorerSelection = reactExports.useMemo(
242114
+ () => normalizeScopedExplorerSelection(explorerStageSelection),
242115
+ [explorerStageSelection]
242116
+ );
242117
+ reactExports.useEffect(() => {
242118
+ setExplorerModePreference("auto");
242119
+ setStickyScopedSelection(null);
242120
+ }, [projectId]);
242121
+ reactExports.useEffect(() => {
242122
+ setStickyScopedSelection(null);
242123
+ }, [workspaceScopeContextKey]);
242124
+ reactExports.useEffect(() => {
242125
+ if (!liveScopedExplorerSelection) return;
242126
+ setStickyScopedSelection(
242127
+ (current) => sameScopedExplorerSelection(current, liveScopedExplorerSelection) ? current : liveScopedExplorerSelection
242128
+ );
242129
+ }, [liveScopedExplorerSelection]);
241880
242130
  reactExports.useEffect(() => {
241881
242131
  if (typeof window === "undefined") return;
241882
242132
  const handleRefresh2 = (event) => {
241883
242133
  const detail = event.detail;
241884
242134
  if (!detail?.target) return;
241885
242135
  if (detail.projectId && detail.projectId !== projectId) return;
241886
- detail.onComplete?.();
242136
+ void (async () => {
242137
+ try {
242138
+ invalidateQuestFileTree(projectId);
242139
+ await loadFiles(projectId, { force: true });
242140
+ if (localQuestMode) {
242141
+ setScopedExplorerReloadKey((value) => value + 1);
242142
+ }
242143
+ } finally {
242144
+ detail.onComplete?.();
242145
+ }
242146
+ })();
241887
242147
  };
241888
242148
  window.addEventListener(EXPLORER_REFRESH_EVENT, handleRefresh2);
241889
242149
  return () => {
241890
242150
  window.removeEventListener(EXPLORER_REFRESH_EVENT, handleRefresh2);
241891
242151
  };
241892
- }, [projectId]);
242152
+ }, [loadFiles, localQuestMode, projectId]);
241893
242153
  reactExports.useEffect(() => {
241894
- const effectiveSelection = activeQuestWorkspaceView === "stage" && activeQuestStageSelection ? {
241895
- ...activeQuestStageSelection,
241896
- selection_type: activeQuestStageSelection.selection_type || "stage_node",
241897
- selection_ref: activeQuestStageSelection.selection_ref || activeQuestStageSelection.stage_key || "stage"
241898
- } : graphSelection || activeDiffScopedSelection;
242154
+ if (!workspaceTreeSyncKey) return;
242155
+ invalidateQuestFileTree(projectId);
242156
+ void loadFiles(projectId, { force: true });
242157
+ if (localQuestMode) {
242158
+ setScopedExplorerReloadKey((value) => value + 1);
242159
+ }
242160
+ }, [loadFiles, localQuestMode, projectId, workspaceTreeSyncKey]);
242161
+ reactExports.useEffect(() => {
242162
+ const effectiveSelection = liveScopedExplorerSelection || ((activeExplorer === "scope" || explorerModePreference === "auto") && explorerModePreference !== "files" && explorerModePreference !== "arxiv" ? stickyScopedSelection : null);
241899
242163
  if (!localQuestMode || !effectiveSelection) {
241900
242164
  setScopedExplorerLabel(null);
241901
242165
  setScopedExplorerNodes([]);
@@ -241907,16 +242171,6 @@ function LeftPanel({
241907
242171
  setActiveExplorer((current) => current === "scope" ? "files" : current);
241908
242172
  return;
241909
242173
  }
241910
- if (!["branch_node", "stage_node", "baseline_node"].includes(String(effectiveSelection.selection_type || ""))) {
241911
- setScopedExplorerLabel(null);
241912
- setScopedExplorerNodes([]);
241913
- setExplorerLocation(DEFAULT_EXPLORER_LOCATION);
241914
- setDiffFiles([]);
241915
- setDiffCompareBase(null);
241916
- setDiffCompareHead(null);
241917
- setActiveExplorer((current) => current === "scope" ? "files" : current);
241918
- return;
241919
- }
241920
242174
  const snapshotRevision = resolveExplorerSnapshotRevision(effectiveSelection);
241921
242175
  const scopePaths = [
241922
242176
  ...effectiveSelection.scope_paths || [],
@@ -241993,7 +242247,13 @@ function LeftPanel({
241993
242247
  setDiffCompareBase(compareBase);
241994
242248
  setDiffCompareHead(compareHead);
241995
242249
  if (nextScopeNodes.length || nextDiffFiles.length) {
241996
- setActiveExplorer("scope");
242250
+ setActiveExplorer((current) => {
242251
+ if (current === "scope") return current;
242252
+ if (explorerModePreference === "files" || explorerModePreference === "arxiv") {
242253
+ return current;
242254
+ }
242255
+ return liveScopedExplorerSelection ? "scope" : current;
242256
+ });
241997
242257
  }
241998
242258
  } catch (error) {
241999
242259
  console.error("[WorkspaceLayout] Failed to build scoped explorer:", error);
@@ -242007,13 +242267,13 @@ function LeftPanel({
242007
242267
  cancelled = true;
242008
242268
  };
242009
242269
  }, [
242010
- activeQuestStageSelection,
242011
- activeDiffScopedSelection,
242012
- activeQuestWorkspaceView,
242013
- graphSelection,
242270
+ activeExplorer,
242271
+ explorerModePreference,
242272
+ liveScopedExplorerSelection,
242014
242273
  localQuestMode,
242015
242274
  projectId,
242016
- scopedExplorerReloadKey
242275
+ scopedExplorerReloadKey,
242276
+ stickyScopedSelection
242017
242277
  ]);
242018
242278
  const diffFileByPath = reactExports.useMemo(() => {
242019
242279
  const mapping = /* @__PURE__ */ new Map();
@@ -242039,14 +242299,14 @@ function LeftPanel({
242039
242299
  oldPath: item.oldPath || null,
242040
242300
  added: item.added ?? null,
242041
242301
  removed: item.removed ?? null,
242042
- quest_stage_selection: activeQuestStageSelection || graphSelection || null,
242302
+ quest_stage_selection: explorerStageSelection || null,
242043
242303
  scoped_selection_source: "diff-viewer"
242044
242304
  }
242045
242305
  },
242046
242306
  title: item.path
242047
242307
  });
242048
242308
  },
242049
- [activeQuestStageSelection, diffCompareBase, diffCompareHead, graphSelection, onExitHome, openTab, projectId]
242309
+ [diffCompareBase, diffCompareHead, explorerStageSelection, onExitHome, openTab, projectId]
242050
242310
  );
242051
242311
  const openPluginTab = reactExports.useCallback(
242052
242312
  (pluginId, title, customData) => {
@@ -242097,7 +242357,7 @@ function LeftPanel({
242097
242357
  removed: diffEntry?.removed ?? null,
242098
242358
  allowSnapshot: true,
242099
242359
  allowDiff: Boolean(diffEntry && diffCompareBase && diffCompareHead),
242100
- quest_stage_selection: activeQuestStageSelection || graphSelection || null,
242360
+ quest_stage_selection: explorerStageSelection || null,
242101
242361
  scoped_selection_source: "snapshot-viewer"
242102
242362
  }
242103
242363
  },
@@ -242120,7 +242380,8 @@ function LeftPanel({
242120
242380
  projectId,
242121
242381
  latexFolderId: file.id,
242122
242382
  mainFileId: file.latex?.mainFileId ?? null,
242123
- readOnly: readOnlyMode
242383
+ readOnly: readOnlyMode,
242384
+ quest_stage_selection: explorerStageSelection || null
242124
242385
  }
242125
242386
  },
242126
242387
  title: file.name
@@ -242128,12 +242389,18 @@ function LeftPanel({
242128
242389
  return;
242129
242390
  }
242130
242391
  if (file.type === "notebook") {
242131
- openNotebook(file.id, file.name, projectId, { readonly: readOnlyMode });
242392
+ openNotebook(file.id, file.name, projectId, {
242393
+ readonly: readOnlyMode,
242394
+ customData: {
242395
+ quest_stage_selection: explorerStageSelection || null
242396
+ }
242397
+ });
242132
242398
  return;
242133
242399
  }
242134
242400
  await openFileInTab(file, {
242135
242401
  customData: {
242136
242402
  projectId,
242403
+ quest_stage_selection: explorerStageSelection || null,
242137
242404
  fileMeta: {
242138
242405
  updatedAt: file.updatedAt,
242139
242406
  sizeBytes: file.size,
@@ -242144,13 +242411,12 @@ function LeftPanel({
242144
242411
  },
242145
242412
  [
242146
242413
  activeExplorer,
242147
- activeQuestStageSelection,
242148
242414
  diffCompareBase,
242149
242415
  diffCompareHead,
242150
242416
  diffFileByPath,
242417
+ explorerStageSelection,
242151
242418
  explorerLocation.revision,
242152
242419
  explorerLocation.sourceMode,
242153
- graphSelection,
242154
242420
  handleOpenDiffFile,
242155
242421
  onExitHome,
242156
242422
  openFileInTab,
@@ -242256,8 +242522,26 @@ function LeftPanel({
242256
242522
  if (showArxivExplorerPanel || activeExplorer !== "arxiv") {
242257
242523
  return;
242258
242524
  }
242525
+ setExplorerModePreference("auto");
242259
242526
  setActiveExplorer(hasScopedExplorer ? "scope" : "files");
242260
242527
  }, [activeExplorer, hasScopedExplorer, showArxivExplorerPanel]);
242528
+ const handleExplorerTabClick = reactExports.useCallback(
242529
+ (next) => {
242530
+ if (next === "files") {
242531
+ setExplorerModePreference("files");
242532
+ setActiveExplorer("files");
242533
+ return;
242534
+ }
242535
+ if (next === "arxiv") {
242536
+ setExplorerModePreference("arxiv");
242537
+ setActiveExplorer("arxiv");
242538
+ return;
242539
+ }
242540
+ setExplorerModePreference("auto");
242541
+ setActiveExplorer("scope");
242542
+ },
242543
+ []
242544
+ );
242261
242545
  const handleExplorerNewFile = reactExports.useCallback(() => {
242262
242546
  if (disableExplorerMutations) return;
242263
242547
  setCreateFileOpen(true);
@@ -242325,7 +242609,7 @@ function LeftPanel({
242325
242609
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#9b8352]/40",
242326
242610
  isArxivView ? "border-[#d0b08a] text-[var(--text-on-dark)]" : "text-[var(--text-muted-on-dark)] hover:text-[var(--text-on-dark)]"
242327
242611
  ),
242328
- onClick: () => setActiveExplorer("arxiv"),
242612
+ onClick: () => handleExplorerTabClick("arxiv"),
242329
242613
  role: "tab",
242330
242614
  "aria-selected": isArxivView,
242331
242615
  "aria-label": t("explorer_arxiv"),
@@ -242343,7 +242627,7 @@ function LeftPanel({
242343
242627
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#9b8352]/40",
242344
242628
  isFilesView ? "border-[#d0b08a] text-[var(--text-on-dark)]" : "text-[var(--text-muted-on-dark)] hover:text-[var(--text-on-dark)]"
242345
242629
  ),
242346
- onClick: () => setActiveExplorer("files"),
242630
+ onClick: () => handleExplorerTabClick("files"),
242347
242631
  role: "tab",
242348
242632
  "aria-selected": isFilesView,
242349
242633
  "aria-label": t("explorer_files"),
@@ -242361,7 +242645,7 @@ function LeftPanel({
242361
242645
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#9b8352]/40",
242362
242646
  isScopeView ? "border-[#d0b08a] text-[var(--text-on-dark)]" : "text-[var(--text-muted-on-dark)] hover:text-[var(--text-on-dark)]"
242363
242647
  ),
242364
- onClick: () => setActiveExplorer("scope"),
242648
+ onClick: () => handleExplorerTabClick("scope"),
242365
242649
  role: "tab",
242366
242650
  "aria-selected": isScopeView,
242367
242651
  "aria-label": t("explorer_snapshot"),
@@ -243136,6 +243420,25 @@ function WorkspaceLayout({
243136
243420
  const demoLocale = tutorialLanguage === "zh" ? "zh" : "en";
243137
243421
  const demoScenario = isDemoProject && demoScenarioId ? tutorialDemoScenarios[demoScenarioId] ?? null : null;
243138
243422
  const demoWorkspace = useDemoQuestWorkspace(projectId, demoScenario, demoLocale);
243423
+ const workspaceTreeSyncKey = reactExports.useMemo(() => {
243424
+ if (!isLocalQuestProject) return null;
243425
+ const snapshot = questWorkspace.snapshot;
243426
+ if (!snapshot) return null;
243427
+ const activeWorkspaceRoot = typeof snapshot.active_workspace_root === "string" ? snapshot.active_workspace_root : "";
243428
+ const currentWorkspaceBranch = typeof snapshot.current_workspace_branch === "string" ? snapshot.current_workspace_branch : typeof snapshot.branch === "string" ? snapshot.branch : "";
243429
+ const head = typeof snapshot.head === "string" ? snapshot.head : "";
243430
+ const key = [activeWorkspaceRoot, currentWorkspaceBranch, head].join("::");
243431
+ return key.trim() ? key : null;
243432
+ }, [isLocalQuestProject, questWorkspace.snapshot]);
243433
+ const workspaceScopeContextKey = reactExports.useMemo(() => {
243434
+ if (!isLocalQuestProject) return null;
243435
+ const snapshot = questWorkspace.snapshot;
243436
+ if (!snapshot) return null;
243437
+ const activeWorkspaceRoot = typeof snapshot.active_workspace_root === "string" ? snapshot.active_workspace_root : "";
243438
+ const currentWorkspaceBranch = typeof snapshot.current_workspace_branch === "string" ? snapshot.current_workspace_branch : typeof snapshot.branch === "string" ? snapshot.branch : "";
243439
+ const key = [activeWorkspaceRoot, currentWorkspaceBranch].join("::");
243440
+ return key.trim() ? key : null;
243441
+ }, [isLocalQuestProject, questWorkspace.snapshot]);
243139
243442
  const [isMobileQuestShell, setIsMobileQuestShell] = reactExports.useState(false);
243140
243443
  const workspaceProjectTitle = projectName ?? (projectId ? `Project ${projectId}` : "Project");
243141
243444
  const { addToast } = useToast();
@@ -244155,7 +244458,9 @@ function WorkspaceLayout({
244155
244458
  onEnterLab: enterLab,
244156
244459
  onExitHome: exitHome,
244157
244460
  localQuestMode: isQuestLikeProject,
244158
- demoMode: isDemoProject
244461
+ demoMode: isDemoProject,
244462
+ workspaceTreeSyncKey,
244463
+ workspaceScopeContextKey
244159
244464
  }
244160
244465
  ),
244161
244466
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "resizer", onMouseDown: startResize("left") })