research-copilot 0.2.17 → 0.2.21

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 (83) hide show
  1. package/README.md +7 -1
  2. package/app/out/main/index.mjs +2842 -188
  3. package/app/out/preload/index.js +2 -0
  4. package/app/out/renderer/assets/{MilkdownMarkdownEditor-tTNRIB2K.css → MilkdownMarkdownEditor-BW0Pt28W.css} +103 -15
  5. package/app/out/renderer/assets/{MilkdownMarkdownEditor-CuTa5j4S.js → MilkdownMarkdownEditor-OhCrq3X0.js} +99 -52
  6. package/app/out/renderer/assets/{arc-BAWS3N-F.js → arc-DLr0RP8F.js} +1 -1
  7. package/app/out/renderer/assets/{blockDiagram-c4efeb88-BHadwPqY.js → blockDiagram-c4efeb88-XhKChw2n.js} +8 -8
  8. package/app/out/renderer/assets/{c4Diagram-c83219d4-B3kOxRad.js → c4Diagram-c83219d4-DDoJmoIQ.js} +3 -3
  9. package/app/out/renderer/assets/{channel-Bll9CBqI.js → channel-CJCgJSqV.js} +1 -1
  10. package/app/out/renderer/assets/{classDiagram-beda092f-Dv7owGyx.js → classDiagram-beda092f-CAmimZpz.js} +6 -6
  11. package/app/out/renderer/assets/{classDiagram-v2-2358418a-cWrqk5tQ.js → classDiagram-v2-2358418a-Bma4E_Eg.js} +10 -10
  12. package/app/out/renderer/assets/{clone-D-DQ4nnY.js → clone-C338dmoI.js} +1 -1
  13. package/app/out/renderer/assets/{createText-1719965b-ciE8YuqI.js → createText-1719965b-_up4NJqB.js} +2 -2
  14. package/app/out/renderer/assets/{edges-96097737-DycnAYk_.js → edges-96097737-Bpp6hVLn.js} +3 -3
  15. package/app/out/renderer/assets/{erDiagram-0228fc6a-Sv78YNMY.js → erDiagram-0228fc6a-bjTh_7ap.js} +5 -5
  16. package/app/out/renderer/assets/{flowDb-c6c81e3f-BiOarg9b.js → flowDb-c6c81e3f-BjVV4DVk.js} +1 -1
  17. package/app/out/renderer/assets/{flowDiagram-50d868cf-19J80nxU.js → flowDiagram-50d868cf-gmeaaZ6z.js} +12 -12
  18. package/app/out/renderer/assets/{flowDiagram-v2-4f6560a1-c-kGsubV.js → flowDiagram-v2-4f6560a1-nem5zs2M.js} +12 -12
  19. package/app/out/renderer/assets/{flowchart-elk-definition-6af322e1-DRrYbiSC.js → flowchart-elk-definition-6af322e1-DPaGAYRw.js} +6 -6
  20. package/app/out/renderer/assets/{ganttDiagram-a2739b55-BadmpvMy.js → ganttDiagram-a2739b55-CnAti19E.js} +3 -3
  21. package/app/out/renderer/assets/{gitGraphDiagram-82fe8481-BdVoj60Q.js → gitGraphDiagram-82fe8481-DQWHD3SJ.js} +2 -2
  22. package/app/out/renderer/assets/{graph-jZhookGR.js → graph-DKiKgH8m.js} +1 -1
  23. package/app/out/renderer/assets/{index-B8fh500_.js → index-4s-c5d65.js} +3 -3
  24. package/app/out/renderer/assets/{index-5325376f-CbxmatXv.js → index-5325376f-G-0aO-2i.js} +6 -6
  25. package/app/out/renderer/assets/{index-CAlpJ3-o.js → index-9q_P5ULR.js} +4 -4
  26. package/app/out/renderer/assets/{index-cavFRVgM.js → index-B1A3JxQj.js} +3 -3
  27. package/app/out/renderer/assets/{index-B9kkJj3J.js → index-BBUrmGmY.js} +6 -6
  28. package/app/out/renderer/assets/{index-CMGDsC_t.js → index-BQho5LH-.js} +6 -6
  29. package/app/out/renderer/assets/{index-CirXkIv2.js → index-BUVlmsgO.js} +3 -3
  30. package/app/out/renderer/assets/{index-BWCwSkxb.js → index-BzEthrJ4.js} +3 -3
  31. package/app/out/renderer/assets/{index-B2UUF9y9.js → index-C1YzkB4z.js} +1289 -419
  32. package/app/out/renderer/assets/{index-D-ZMmLhv.js → index-CGo665vD.js} +3 -3
  33. package/app/out/renderer/assets/{index-DQwFQR1s.js → index-CPZaxR35.js} +3 -3
  34. package/app/out/renderer/assets/{index-DOUTte7i.js → index-CSyD1mbL.js} +3 -3
  35. package/app/out/renderer/assets/{index-BUcSHPha.js → index-Cf7vlFSn.js} +3 -3
  36. package/app/out/renderer/assets/{index-CZX0435B.js → index-CluH1o2q.js} +6 -6
  37. package/app/out/renderer/assets/{index-lAZsmnj1.css → index-CogwQwDN.css} +185 -32
  38. package/app/out/renderer/assets/{index-DEO9Jh2Y.js → index-Cw1n3klA.js} +5 -5
  39. package/app/out/renderer/assets/{index-BBUnWjLe.js → index-DFzvntIw.js} +3 -3
  40. package/app/out/renderer/assets/{index-g91Iwgxa.js → index-DHzyAhWM.js} +4 -4
  41. package/app/out/renderer/assets/{index-47oNNEnx.js → index-DhliHfCM.js} +6 -6
  42. package/app/out/renderer/assets/{index-DF_C6DjR.js → index-DkVFbCxC.js} +3 -3
  43. package/app/out/renderer/assets/{index-HCRA2-Q6.js → index-DpZJP5MT.js} +6 -6
  44. package/app/out/renderer/assets/{index-BXpNbFhG.js → index-Gfd_DiMG.js} +3 -3
  45. package/app/out/renderer/assets/{index-B110aKST.js → index-jOvNAYyP.js} +3 -3
  46. package/app/out/renderer/assets/{index-BTE0dEKO.js → index-rrJkk8KV.js} +6 -6
  47. package/app/out/renderer/assets/{index-DO5LsHlM.js → index-vfSerSmF.js} +1 -1
  48. package/app/out/renderer/assets/{infoDiagram-8eee0895-DpVt3Scv.js → infoDiagram-8eee0895-BCnBkXXS.js} +2 -2
  49. package/app/out/renderer/assets/{journeyDiagram-c64418c1-RYKX5mcV.js → journeyDiagram-c64418c1-Bq2wSX3k.js} +4 -4
  50. package/app/out/renderer/assets/{layout-BsbNXXgR.js → layout-BvkumzoT.js} +2 -2
  51. package/app/out/renderer/assets/{line-OzQTpJsh.js → line-eU4el-G4.js} +1 -1
  52. package/app/out/renderer/assets/{linear-DO5pdnqi.js → linear-DlBjMBEa.js} +1 -1
  53. package/app/out/renderer/assets/{mindmap-definition-8da855dc-D3zWs3h1.js → mindmap-definition-8da855dc-CzLBu7ao.js} +3 -3
  54. package/app/out/renderer/assets/{pieDiagram-a8764435-DDoNhSgQ.js → pieDiagram-a8764435--olrXFr_.js} +3 -3
  55. package/app/out/renderer/assets/{quadrantDiagram-1e28029f-ZO85SsRM.js → quadrantDiagram-1e28029f-BnpnBBgc.js} +3 -3
  56. package/app/out/renderer/assets/{requirementDiagram-08caed73-C-vKE6g8.js → requirementDiagram-08caed73-6O9WS7hn.js} +5 -5
  57. package/app/out/renderer/assets/{sankeyDiagram-a04cb91d-Cbqb2K-X.js → sankeyDiagram-a04cb91d-D-iJnK91.js} +2 -2
  58. package/app/out/renderer/assets/{sequenceDiagram-c5b8d532-BK4uvpEA.js → sequenceDiagram-c5b8d532-DBlK15cV.js} +3 -3
  59. package/app/out/renderer/assets/{stateDiagram-1ecb1508-DXa_YqNi.js → stateDiagram-1ecb1508-DKXKPYuk.js} +6 -6
  60. package/app/out/renderer/assets/{stateDiagram-v2-c2b004d7-Dm203Z8l.js → stateDiagram-v2-c2b004d7-DY288Eo5.js} +10 -10
  61. package/app/out/renderer/assets/{styles-b4e223ce-BV4b1eAh.js → styles-b4e223ce-CRJ_xgJ-.js} +1 -1
  62. package/app/out/renderer/assets/{styles-ca3715f6-CKhYSe7r.js → styles-ca3715f6-Bp_k5KLD.js} +1 -1
  63. package/app/out/renderer/assets/{styles-d45a18b0-DTCMfE-4.js → styles-d45a18b0-DLA8Gg6D.js} +4 -4
  64. package/app/out/renderer/assets/{svgDrawCommon-b86b1483-DK4i-dfJ.js → svgDrawCommon-b86b1483-Dm5CK2gQ.js} +1 -1
  65. package/app/out/renderer/assets/{timeline-definition-faaaa080-CE2LmuDH.js → timeline-definition-faaaa080-D-m9BHUg.js} +3 -3
  66. package/app/out/renderer/assets/{xychartDiagram-f5964ef8-Bd8KT9X9.js → xychartDiagram-f5964ef8-Drn4Rqev.js} +5 -5
  67. package/app/out/renderer/index.html +2 -2
  68. package/lib/skills/builtin/academic-marp-slides/SKILL.md +933 -0
  69. package/lib/skills/builtin/research-grants/SKILL.md +15 -11
  70. package/lib/skills/builtin/scholar-evaluation/SKILL.md +12 -11
  71. package/lib/skills/builtin/scientific-schematics/SKILL.md +463 -560
  72. package/lib/skills/builtin/teaching-marp-slides/SKILL.md +1218 -0
  73. package/package.json +1 -1
  74. package/scripts/audit-diagram-prompts.mjs +67 -0
  75. package/scripts/test-skill-routing.mjs +238 -0
  76. package/lib/skills/builtin/marp-slides/SKILL.md +0 -642
  77. package/lib/skills/builtin/scientific-schematics/references/QUICK_REFERENCE.md +0 -182
  78. package/lib/skills/builtin/scientific-schematics/references/README.md +0 -292
  79. package/lib/skills/builtin/scientific-schematics/scripts/__pycache__/generate_schematic.cpython-312.pyc +0 -0
  80. package/lib/skills/builtin/scientific-schematics/scripts/__pycache__/generate_schematic_ai.cpython-312.pyc +0 -0
  81. package/lib/skills/builtin/scientific-schematics/scripts/example_usage.sh +0 -85
  82. package/lib/skills/builtin/scientific-schematics/scripts/generate_schematic.py +0 -141
  83. package/lib/skills/builtin/scientific-schematics/scripts/generate_schematic_ai.py +0 -910
@@ -1,4 +1,4 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./MilkdownMarkdownEditor-CuTa5j4S.js","./MilkdownMarkdownEditor-tTNRIB2K.css"])))=>i.map(i=>d[i]);
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./MilkdownMarkdownEditor-OhCrq3X0.js","./MilkdownMarkdownEditor-BW0Pt28W.css"])))=>i.map(i=>d[i]);
2
2
  var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
3
3
  function getDefaultExportFromCjs(x) {
4
4
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
@@ -12704,6 +12704,26 @@ const CircleDot = createLucideIcon("CircleDot", [
12704
12704
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
12705
12705
  ["circle", { cx: "12", cy: "12", r: "1", key: "41hilf" }]
12706
12706
  ]);
12707
+ /**
12708
+ * @license lucide-react v0.469.0 - ISC
12709
+ *
12710
+ * This source code is licensed under the ISC license.
12711
+ * See the LICENSE file in the root directory of this source tree.
12712
+ */
12713
+ const ClipboardPaste = createLucideIcon("ClipboardPaste", [
12714
+ [
12715
+ "path",
12716
+ { d: "M15 2H9a1 1 0 0 0-1 1v2c0 .6.4 1 1 1h6c.6 0 1-.4 1-1V3c0-.6-.4-1-1-1Z", key: "1pp7kr" }
12717
+ ],
12718
+ [
12719
+ "path",
12720
+ {
12721
+ d: "M8 4H6a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2M16 4h2a2 2 0 0 1 2 2v2M11 14h10",
12722
+ key: "2ik1ml"
12723
+ }
12724
+ ],
12725
+ ["path", { d: "m17 10 4 4-4 4", key: "vp2hj1" }]
12726
+ ]);
12707
12727
  /**
12708
12728
  * @license lucide-react v0.469.0 - ISC
12709
12729
  *
@@ -12754,6 +12774,17 @@ const Database = createLucideIcon("Database", [
12754
12774
  ["path", { d: "M3 5V19A9 3 0 0 0 21 19V5", key: "1wlel7" }],
12755
12775
  ["path", { d: "M3 12A9 3 0 0 0 21 12", key: "mv7ke4" }]
12756
12776
  ]);
12777
+ /**
12778
+ * @license lucide-react v0.469.0 - ISC
12779
+ *
12780
+ * This source code is licensed under the ISC license.
12781
+ * See the LICENSE file in the root directory of this source tree.
12782
+ */
12783
+ const Ellipsis = createLucideIcon("Ellipsis", [
12784
+ ["circle", { cx: "12", cy: "12", r: "1", key: "41hilf" }],
12785
+ ["circle", { cx: "19", cy: "12", r: "1", key: "1wjl8i" }],
12786
+ ["circle", { cx: "5", cy: "12", r: "1", key: "1pcz8c" }]
12787
+ ]);
12757
12788
  /**
12758
12789
  * @license lucide-react v0.469.0 - ISC
12759
12790
  *
@@ -12950,6 +12981,29 @@ const Globe = createLucideIcon("Globe", [
12950
12981
  ["path", { d: "M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20", key: "13o1zl" }],
12951
12982
  ["path", { d: "M2 12h20", key: "9i4pu4" }]
12952
12983
  ]);
12984
+ /**
12985
+ * @license lucide-react v0.469.0 - ISC
12986
+ *
12987
+ * This source code is licensed under the ISC license.
12988
+ * See the LICENSE file in the root directory of this source tree.
12989
+ */
12990
+ const Hash = createLucideIcon("Hash", [
12991
+ ["line", { x1: "4", x2: "20", y1: "9", y2: "9", key: "4lhtct" }],
12992
+ ["line", { x1: "4", x2: "20", y1: "15", y2: "15", key: "vyu0kd" }],
12993
+ ["line", { x1: "10", x2: "8", y1: "3", y2: "21", key: "1ggp8o" }],
12994
+ ["line", { x1: "16", x2: "14", y1: "3", y2: "21", key: "weycgp" }]
12995
+ ]);
12996
+ /**
12997
+ * @license lucide-react v0.469.0 - ISC
12998
+ *
12999
+ * This source code is licensed under the ISC license.
13000
+ * See the LICENSE file in the root directory of this source tree.
13001
+ */
13002
+ const Image = createLucideIcon("Image", [
13003
+ ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", ry: "2", key: "1m3agn" }],
13004
+ ["circle", { cx: "9", cy: "9", r: "2", key: "af1f0g" }],
13005
+ ["path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21", key: "1xmnt7" }]
13006
+ ]);
12953
13007
  /**
12954
13008
  * @license lucide-react v0.469.0 - ISC
12955
13009
  *
@@ -12989,6 +13043,17 @@ const Lightbulb = createLucideIcon("Lightbulb", [
12989
13043
  ["path", { d: "M9 18h6", key: "x1upvd" }],
12990
13044
  ["path", { d: "M10 22h4", key: "ceow96" }]
12991
13045
  ]);
13046
+ /**
13047
+ * @license lucide-react v0.469.0 - ISC
13048
+ *
13049
+ * This source code is licensed under the ISC license.
13050
+ * See the LICENSE file in the root directory of this source tree.
13051
+ */
13052
+ const Link2 = createLucideIcon("Link2", [
13053
+ ["path", { d: "M9 17H7A5 5 0 0 1 7 7h2", key: "8i5ue5" }],
13054
+ ["path", { d: "M15 7h2a5 5 0 1 1 0 10h-2", key: "1b9ql8" }],
13055
+ ["line", { x1: "8", x2: "16", y1: "12", y2: "12", key: "1jonct" }]
13056
+ ]);
12992
13057
  /**
12993
13058
  * @license lucide-react v0.469.0 - ISC
12994
13059
  *
@@ -13104,6 +13169,17 @@ const Plus = createLucideIcon("Plus", [
13104
13169
  ["path", { d: "M5 12h14", key: "1ays0h" }],
13105
13170
  ["path", { d: "M12 5v14", key: "s699le" }]
13106
13171
  ]);
13172
+ /**
13173
+ * @license lucide-react v0.469.0 - ISC
13174
+ *
13175
+ * This source code is licensed under the ISC license.
13176
+ * See the LICENSE file in the root directory of this source tree.
13177
+ */
13178
+ const Presentation = createLucideIcon("Presentation", [
13179
+ ["path", { d: "M2 3h20", key: "91anmk" }],
13180
+ ["path", { d: "M21 3v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V3", key: "2k9sn8" }],
13181
+ ["path", { d: "m7 21 5-5 5 5", key: "bip4we" }]
13182
+ ]);
13107
13183
  /**
13108
13184
  * @license lucide-react v0.469.0 - ISC
13109
13185
  *
@@ -13419,7 +13495,7 @@ const KEY_FIELDS = [
13419
13495
  name: "OPENAI_API_KEY",
13420
13496
  label: "OpenAI",
13421
13497
  placeholder: "sk-...",
13422
- hint: "Powers GPT / o-series models. Get a key at platform.openai.com",
13498
+ hint: "Powers GPT / o-series models AND publication-quality diagram generation (gpt-image-2 + PNG-anchored SVG transcription). Without this key, diagrams fall back to a chat-model-only path with reduced quality. Get a key at platform.openai.com",
13423
13499
  url: "https://platform.openai.com/api-keys",
13424
13500
  required: true
13425
13501
  },
@@ -13932,6 +14008,42 @@ function formatRelativeTime(isoString) {
13932
14008
  if (hours < 24) return `${hours} hour${hours > 1 ? "s" : ""} ago`;
13933
14009
  return new Date(isoString).toLocaleDateString();
13934
14010
  }
14011
+ function DiagramSettings({ reviewProvider, onChangeReviewProvider }) {
14012
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-6", children: [
14013
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
14014
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "text-xs font-semibold t-text mb-1.5", children: "Generation Provider" }),
14015
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[11px] t-text-muted", children: [
14016
+ "Diagram images are generated via OpenAI ",
14017
+ /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "font-mono", children: "gpt-image-2" }),
14018
+ " and require ",
14019
+ /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "font-mono", children: "OPENAI_API_KEY" }),
14020
+ ". Claude cannot generate images, so this is fixed for now."
14021
+ ] })
14022
+ ] }),
14023
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
14024
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "text-xs font-semibold t-text mb-1.5", children: "Review Provider" }),
14025
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] t-text-muted mb-2.5", children: "Which model evaluates each draft and decides whether to accept, edit, or regenerate." }),
14026
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
14027
+ SegmentedControl,
14028
+ {
14029
+ options: [
14030
+ { label: "Auto", value: "auto" },
14031
+ { label: "OpenAI", value: "openai" },
14032
+ { label: "Anthropic", value: "anthropic" }
14033
+ ],
14034
+ value: reviewProvider,
14035
+ onChange: onChangeReviewProvider
14036
+ }
14037
+ ),
14038
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[10px] t-text-muted mt-1.5", children: [
14039
+ reviewProvider === "auto" && "Prefer heterogeneous review (Anthropic when available, so the generator does not grade its own family).",
14040
+ reviewProvider === "openai" && "GPT-4o vision with JSON-schema output. Requires OPENAI_API_KEY.",
14041
+ reviewProvider === "anthropic" && "Claude Opus vision with tool-use constrained output. Requires ANTHROPIC_API_KEY."
14042
+ ] }),
14043
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] t-text-muted mt-2 leading-relaxed", children: "Score thresholds are calibrated per reviewer and are not directly comparable across providers. An 8.0 from OpenAI and an 8.0 from Claude represent similar quality targets, but the underlying numbers are not interchangeable." })
14044
+ ] })
14045
+ ] });
14046
+ }
13935
14047
  const DEFAULT_SETTINGS = {
13936
14048
  research: {
13937
14049
  researchIntensity: "medium",
@@ -13944,6 +14056,9 @@ const DEFAULT_SETTINGS = {
13944
14056
  wikiAgent: {
13945
14057
  model: "none",
13946
14058
  speed: "medium"
14059
+ },
14060
+ diagram: {
14061
+ reviewProvider: "auto"
13947
14062
  }
13948
14063
  };
13949
14064
  const api$e = window.api;
@@ -13951,7 +14066,8 @@ const TABS = [
13951
14066
  { id: "api-keys", label: "API Keys", icon: Key },
13952
14067
  { id: "research", label: "Research", icon: BookOpen },
13953
14068
  { id: "data-analysis", label: "Data Analysis", icon: ChartNoAxesColumn },
13954
- { id: "paper-wiki", label: "Paper Wiki", icon: BookMarked }
14069
+ { id: "paper-wiki", label: "Paper Wiki", icon: BookMarked },
14070
+ { id: "diagram", label: "Diagrams", icon: Image }
13955
14071
  ];
13956
14072
  const FOCUSABLE_SELECTOR = [
13957
14073
  "button:not([disabled])",
@@ -14043,6 +14159,7 @@ function SettingsModal({ open, onClose, initialTab }) {
14043
14159
  if (patch2.research) next.research = { ...prev.research, ...patch2.research };
14044
14160
  if (patch2.dataAnalysis) next.dataAnalysis = { ...prev.dataAnalysis, ...patch2.dataAnalysis };
14045
14161
  if (patch2.wikiAgent) next.wikiAgent = { ...prev.wikiAgent, ...patch2.wikiAgent };
14162
+ if (patch2.diagram) next.diagram = { ...prev.diagram, ...patch2.diagram };
14046
14163
  return next;
14047
14164
  });
14048
14165
  setDirty(true);
@@ -14126,7 +14243,7 @@ function SettingsModal({ open, onClose, initialTab }) {
14126
14243
  )
14127
14244
  ] }),
14128
14245
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 overflow-y-auto px-6 pb-4", children: [
14129
- activeTab === "api-keys" && /* @__PURE__ */ jsxRuntimeExports.jsx(ApiKeysSettings, {}),
14246
+ activeTab === "api-keys" && /* @__PURE__ */ jsxRuntimeExports.jsx(ApiKeysSettings, { showSaveButton: true }),
14130
14247
  activeTab === "research" && loaded && /* @__PURE__ */ jsxRuntimeExports.jsx(
14131
14248
  ResearchSettings,
14132
14249
  {
@@ -14153,6 +14270,13 @@ function SettingsModal({ open, onClose, initialTab }) {
14153
14270
  onChangeModel: (v3) => updateSettings({ wikiAgent: { ...settings.wikiAgent, model: v3 } }),
14154
14271
  onChangeSpeed: (v3) => updateSettings({ wikiAgent: { ...settings.wikiAgent, speed: v3 } })
14155
14272
  }
14273
+ ),
14274
+ activeTab === "diagram" && loaded && /* @__PURE__ */ jsxRuntimeExports.jsx(
14275
+ DiagramSettings,
14276
+ {
14277
+ reviewProvider: settings.diagram?.reviewProvider ?? "auto",
14278
+ onChangeReviewProvider: (v3) => updateSettings({ diagram: { reviewProvider: v3 } })
14279
+ }
14156
14280
  )
14157
14281
  ] }),
14158
14282
  activeTab !== "api-keys" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-6 py-2.5 border-t t-border-subtle", children: /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] t-text-muted", children: "Settings are saved automatically. Changes to research and analysis settings take effect for new agent sessions. Existing sessions require an app restart." }) })
@@ -14235,6 +14359,21 @@ function bootTheme() {
14235
14359
  applyThemeClass(theme);
14236
14360
  return theme;
14237
14361
  }
14362
+ const DRAWER_WIDTH_MIN = 360;
14363
+ const DRAWER_WIDTH_MAX = 720;
14364
+ const DRAWER_WIDTH_DEFAULT = 540;
14365
+ const clampDrawerWidth = (px) => Math.max(DRAWER_WIDTH_MIN, Math.min(DRAWER_WIDTH_MAX, Math.round(px)));
14366
+ const LEFT_WIDTH_MIN = 260;
14367
+ const LEFT_WIDTH_MAX = 480;
14368
+ const LEFT_WIDTH_DEFAULT = 320;
14369
+ const LEFT_WIDTH_KEY = "ui.leftSidebarWidth";
14370
+ const clampLeftWidth = (px) => Math.max(LEFT_WIDTH_MIN, Math.min(LEFT_WIDTH_MAX, Math.round(px)));
14371
+ const readLeftWidth = () => {
14372
+ if (typeof window === "undefined") return LEFT_WIDTH_DEFAULT;
14373
+ const raw = window.localStorage?.getItem(LEFT_WIDTH_KEY);
14374
+ const n = raw ? Number.parseInt(raw, 10) : NaN;
14375
+ return Number.isFinite(n) ? clampLeftWidth(n) : LEFT_WIDTH_DEFAULT;
14376
+ };
14238
14377
  const useUIStore = create$1((set) => ({
14239
14378
  // Theme hydrates from localStorage (or OS preference) at module init so
14240
14379
  // the zustand state matches the <html> class applied by bootTheme() in
@@ -14253,6 +14392,8 @@ const useUIStore = create$1((set) => ({
14253
14392
  previewEntity: null,
14254
14393
  previewSourceTab: null,
14255
14394
  previewEditorFocused: false,
14395
+ drawerWidth: DRAWER_WIDTH_DEFAULT,
14396
+ leftSidebarWidth: readLeftWidth(),
14256
14397
  literatureFilter: {
14257
14398
  search: "",
14258
14399
  subTopic: null,
@@ -14348,13 +14489,33 @@ const useUIStore = create$1((set) => ({
14348
14489
  previewEntity: null,
14349
14490
  previewSourceTab: null,
14350
14491
  previewEditorFocused: false,
14492
+ drawerWidth: DRAWER_WIDTH_DEFAULT,
14493
+ leftSidebarWidth: readLeftWidth(),
14351
14494
  literatureFilter: { search: "", subTopic: null, sortBy: "year", sortDir: "desc", minScore: 0, source: null, round: null },
14352
14495
  wikiReaderSlug: null,
14353
14496
  wikiReaderHistory: []
14354
14497
  }),
14355
- openPreview: (entity) => set((s15) => ({ previewEntity: entity, previewSourceTab: s15.leftTab, leftSidebarCollapsed: true, previewEditorFocused: false })),
14356
- closePreview: () => set({ previewEntity: null, previewSourceTab: null, leftSidebarCollapsed: false, previewEditorFocused: false }),
14357
- setPreviewEditorFocused: (previewEditorFocused) => set({ previewEditorFocused })
14498
+ // Opening a preview routes the user to chat view the drawer is mounted
14499
+ // inside the chat-body host, so it only renders there. Researchers expect
14500
+ // clicking a file to show them the file; forcing the view switch is the
14501
+ // honest implementation of that expectation.
14502
+ openPreview: (entity) => set((s15) => ({
14503
+ previewEntity: entity,
14504
+ previewSourceTab: s15.leftTab,
14505
+ previewEditorFocused: false,
14506
+ centerView: "chat"
14507
+ })),
14508
+ closePreview: () => set({ previewEntity: null, previewSourceTab: null, previewEditorFocused: false }),
14509
+ setPreviewEditorFocused: (previewEditorFocused) => set({ previewEditorFocused }),
14510
+ setDrawerWidth: (drawerWidth) => set({ drawerWidth: clampDrawerWidth(drawerWidth) }),
14511
+ setLeftSidebarWidth: (width) => {
14512
+ const clamped = clampLeftWidth(width);
14513
+ set({ leftSidebarWidth: clamped });
14514
+ try {
14515
+ window.localStorage?.setItem(LEFT_WIDTH_KEY, String(clamped));
14516
+ } catch {
14517
+ }
14518
+ }
14358
14519
  }));
14359
14520
  async function hydratePreferences() {
14360
14521
  const api2 = window.api;
@@ -27548,7 +27709,6 @@ const TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
27548
27709
  "ts",
27549
27710
  "js",
27550
27711
  "css",
27551
- "html",
27552
27712
  "yml",
27553
27713
  "yaml",
27554
27714
  "toml",
@@ -27578,6 +27738,8 @@ function WorkspaceTree() {
27578
27738
  const { projectPath } = useSessionStore();
27579
27739
  const openPreview = useUIStore((s15) => s15.openPreview);
27580
27740
  const previewEntity = useUIStore((s15) => s15.previewEntity);
27741
+ const leftTab = useUIStore((s15) => s15.leftTab);
27742
+ const centerView = useUIStore((s15) => s15.centerView);
27581
27743
  const data = useEntityStore((s15) => s15.data);
27582
27744
  const refreshEntities = useEntityStore((s15) => s15.refreshAll);
27583
27745
  const [query, setQuery] = reactExports.useState("");
@@ -27599,6 +27761,7 @@ function WorkspaceTree() {
27599
27761
  const [dropTargetPath, setDropTargetPath] = reactExports.useState(null);
27600
27762
  const [confirmTrashPath, setConfirmTrashPath] = reactExports.useState(null);
27601
27763
  const [contextMenu, setContextMenu] = reactExports.useState(null);
27764
+ const [clipboardNode, setClipboardNode] = reactExports.useState(null);
27602
27765
  const [renaming, setRenaming] = reactExports.useState(null);
27603
27766
  const [renameValue, setRenameValue] = reactExports.useState("");
27604
27767
  const [creating, setCreating] = reactExports.useState(null);
@@ -27613,6 +27776,9 @@ function WorkspaceTree() {
27613
27776
  window.addEventListener("click", handleClick);
27614
27777
  return () => window.removeEventListener("click", handleClick);
27615
27778
  }, [contextMenu]);
27779
+ reactExports.useEffect(() => {
27780
+ setContextMenu(null);
27781
+ }, [leftTab, centerView]);
27616
27782
  reactExports.useEffect(() => {
27617
27783
  if (renaming && renameInputRef.current) {
27618
27784
  renameInputRef.current.focus();
@@ -27795,6 +27961,35 @@ function WorkspaceTree() {
27795
27961
  if (node2.type === "directory") return node2.relativePath;
27796
27962
  return node2.relativePath.includes("/") ? node2.relativePath.slice(0, node2.relativePath.lastIndexOf("/")) : "";
27797
27963
  }, []);
27964
+ const handleRevealInFinder = reactExports.useCallback((node2) => {
27965
+ void api$9.revealInFinder(node2.path);
27966
+ setContextMenu(null);
27967
+ }, []);
27968
+ const handleOpenInDefaultApp = reactExports.useCallback((node2) => {
27969
+ void api$9.openFile(node2.path);
27970
+ setContextMenu(null);
27971
+ }, []);
27972
+ const handleCopyFile = reactExports.useCallback((node2) => {
27973
+ setClipboardNode(node2);
27974
+ setContextMenu(null);
27975
+ }, []);
27976
+ const handlePasteFile = reactExports.useCallback(async (targetNode) => {
27977
+ if (!clipboardNode) return;
27978
+ const destDir = targetNode.type === "directory" ? targetNode.relativePath : getParentDir(targetNode);
27979
+ setContextMenu(null);
27980
+ const result = await api$9.copyItem(clipboardNode.relativePath, destDir);
27981
+ if (result.success) {
27982
+ await loadChildren(destDir);
27983
+ }
27984
+ }, [clipboardNode, getParentDir, loadChildren]);
27985
+ const handleCopyPath = reactExports.useCallback((node2) => {
27986
+ void navigator.clipboard.writeText(node2.path);
27987
+ setContextMenu(null);
27988
+ }, []);
27989
+ const handleCopyRelativePath = reactExports.useCallback((node2) => {
27990
+ void navigator.clipboard.writeText(node2.relativePath);
27991
+ setContextMenu(null);
27992
+ }, []);
27798
27993
  const handleNewFile = reactExports.useCallback((parentRelPath) => {
27799
27994
  setCreating({ parentDir: parentRelPath, type: "file" });
27800
27995
  setCreateValue("");
@@ -28057,7 +28252,7 @@ function WorkspaceTree() {
28057
28252
  onClick: (e) => e.stopPropagation(),
28058
28253
  className: "flex-1 bg-transparent outline-none t-focus-ring border-b border-[var(--color-accent-soft)] text-xs t-text"
28059
28254
  }
28060
- ) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate flex-1", children: node2.name }),
28255
+ ) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate flex-1", title: node2.name, children: node2.name }),
28061
28256
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "hidden group-hover:flex items-center gap-0.5", children: [
28062
28257
  node2.type === "file" && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
28063
28258
  /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -28168,6 +28363,7 @@ function WorkspaceTree() {
28168
28363
  {
28169
28364
  ref: viewportRef,
28170
28365
  className: `flex-1 min-h-0 overflow-y-auto px-1 py-1 ${dropTargetPath === "__root__" ? "ring-2 ring-inset ring-[var(--color-accent)]/60 bg-[var(--color-accent)]/5" : ""}`,
28366
+ style: { overflowAnchor: "none" },
28171
28367
  onScroll: (e) => setScrollTop(e.currentTarget.scrollTop),
28172
28368
  onDragOver: handleViewportDragOver,
28173
28369
  onDragLeave: handleViewportDragLeave,
@@ -28181,16 +28377,16 @@ function WorkspaceTree() {
28181
28377
  '".'
28182
28378
  ] }) : !query.trim() && rootNodes.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "px-2 py-2 text-xs t-text-muted", children: "No visible files in workspace root." }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
28183
28379
  creating && creating.parentDir === "" && renderCreateInput(0),
28184
- topSpacerHeight > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { height: `${topSpacerHeight}px` } }),
28380
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { height: `${topSpacerHeight}px` } }),
28185
28381
  visibleRows.map((row) => renderVisibleRow(row)),
28186
- bottomSpacerHeight > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { height: `${bottomSpacerHeight}px` } })
28382
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { height: `${bottomSpacerHeight}px` } })
28187
28383
  ] })
28188
28384
  }
28189
28385
  ),
28190
28386
  contextMenu && /* @__PURE__ */ jsxRuntimeExports.jsxs(
28191
28387
  "div",
28192
28388
  {
28193
- className: "fixed z-50 min-w-[160px] rounded-lg border t-border t-bg-surface shadow-xl py-1",
28389
+ className: "fixed z-50 min-w-[180px] rounded-lg border t-border t-bg-surface shadow-xl py-1",
28194
28390
  style: { left: contextMenu.x, top: contextMenu.y },
28195
28391
  onClick: (e) => e.stopPropagation(),
28196
28392
  children: [
@@ -28208,6 +28404,75 @@ function WorkspaceTree() {
28208
28404
  ]
28209
28405
  }
28210
28406
  ),
28407
+ contextMenu.node.type === "file" && /* @__PURE__ */ jsxRuntimeExports.jsxs(
28408
+ "button",
28409
+ {
28410
+ className: "w-full text-left px-3 py-1.5 text-xs t-text-secondary hover:t-bg-hover flex items-center gap-2",
28411
+ onClick: () => handleOpenInDefaultApp(contextMenu.node),
28412
+ children: [
28413
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ExternalLink, { size: 11 }),
28414
+ " Open in Default App"
28415
+ ]
28416
+ }
28417
+ ),
28418
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
28419
+ "button",
28420
+ {
28421
+ className: "w-full text-left px-3 py-1.5 text-xs t-text-secondary hover:t-bg-hover flex items-center gap-2",
28422
+ onClick: () => handleRevealInFinder(contextMenu.node),
28423
+ children: [
28424
+ /* @__PURE__ */ jsxRuntimeExports.jsx(FolderOpen, { size: 11 }),
28425
+ " Reveal in Finder"
28426
+ ]
28427
+ }
28428
+ ),
28429
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "border-t t-border my-1" }),
28430
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
28431
+ "button",
28432
+ {
28433
+ className: "w-full text-left px-3 py-1.5 text-xs t-text-secondary hover:t-bg-hover flex items-center gap-2",
28434
+ onClick: () => handleCopyFile(contextMenu.node),
28435
+ children: [
28436
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { size: 11 }),
28437
+ " Copy"
28438
+ ]
28439
+ }
28440
+ ),
28441
+ clipboardNode && /* @__PURE__ */ jsxRuntimeExports.jsxs(
28442
+ "button",
28443
+ {
28444
+ className: "w-full text-left px-3 py-1.5 text-xs t-text-secondary hover:t-bg-hover flex items-center gap-2",
28445
+ onClick: () => void handlePasteFile(contextMenu.node),
28446
+ children: [
28447
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ClipboardPaste, { size: 11 }),
28448
+ " Paste"
28449
+ ]
28450
+ }
28451
+ ),
28452
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "border-t t-border my-1" }),
28453
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
28454
+ "button",
28455
+ {
28456
+ className: "w-full text-left px-3 py-1.5 text-xs t-text-secondary hover:t-bg-hover flex items-center gap-2",
28457
+ onClick: () => handleCopyPath(contextMenu.node),
28458
+ children: [
28459
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Hash, { size: 11 }),
28460
+ " Copy Path"
28461
+ ]
28462
+ }
28463
+ ),
28464
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
28465
+ "button",
28466
+ {
28467
+ className: "w-full text-left px-3 py-1.5 text-xs t-text-secondary hover:t-bg-hover flex items-center gap-2",
28468
+ onClick: () => handleCopyRelativePath(contextMenu.node),
28469
+ children: [
28470
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Link2, { size: 11 }),
28471
+ " Copy Relative Path"
28472
+ ]
28473
+ }
28474
+ ),
28475
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "border-t t-border my-1" }),
28211
28476
  /* @__PURE__ */ jsxRuntimeExports.jsxs(
28212
28477
  "button",
28213
28478
  {
@@ -28318,7 +28583,7 @@ const useSkillStore = create$1((set, get) => ({
28318
28583
  return result;
28319
28584
  }
28320
28585
  }));
28321
- const remarkPlugins$3 = [remarkGfm];
28586
+ const remarkPlugins$4 = [remarkGfm];
28322
28587
  function HoverPreview({
28323
28588
  entity,
28324
28589
  anchorRect,
@@ -28360,7 +28625,7 @@ function HoverPreview({
28360
28625
  }
28361
28626
  ) })
28362
28627
  ] }),
28363
- content2 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-3 py-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "md-prose text-xs", style: { color: "var(--color-text-secondary)" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Markdown, { remarkPlugins: remarkPlugins$3, children: content2.length > 600 ? content2.slice(0, 600) + "..." : content2 }) }) })
28628
+ content2 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-3 py-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "md-prose text-xs", style: { color: "var(--color-text-secondary)" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Markdown, { remarkPlugins: remarkPlugins$4, children: content2.length > 600 ? content2.slice(0, 600) + "..." : content2 }) }) })
28364
28629
  ]
28365
28630
  }
28366
28631
  );
@@ -28447,7 +28712,7 @@ const EntityRow = React$2.memo(function EntityRow2({ entity }) {
28447
28712
  }
28448
28713
  ),
28449
28714
  isEnriching ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { size: 10, className: "shrink-0 t-text-accent-soft animate-spin" }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-1 h-1 rounded-full shrink-0 t-bg-elevated" }),
28450
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs t-text truncate", children: entity.title })
28715
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs t-text truncate", title: entity.title, children: entity.title })
28451
28716
  ]
28452
28717
  }
28453
28718
  ),
@@ -28508,10 +28773,18 @@ function DataTreeView({ items }) {
28508
28773
  }
28509
28774
  ),
28510
28775
  /* @__PURE__ */ jsxRuntimeExports.jsx(FlaskConical, { size: 13, className: "shrink-0 t-text-accent" }),
28511
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs t-text truncate", onClick: () => openPreview(children[0]), children: [
28512
- "Analysis: ",
28513
- label
28514
- ] })
28776
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
28777
+ "span",
28778
+ {
28779
+ className: "text-xs t-text truncate",
28780
+ title: `Analysis: ${label}`,
28781
+ onClick: () => openPreview(children[0]),
28782
+ children: [
28783
+ "Analysis: ",
28784
+ label
28785
+ ]
28786
+ }
28787
+ )
28515
28788
  ] }),
28516
28789
  isOpen && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "pl-4", children: children.map((e) => /* @__PURE__ */ jsxRuntimeExports.jsx(EntityRow, { entity: e }, e.id)) })
28517
28790
  ] }, runId);
@@ -28720,7 +28993,7 @@ function SkillsContent() {
28720
28993
  ),
28721
28994
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0 flex-1", children: [
28722
28995
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5", children: [
28723
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs t-text font-medium truncate", children: skill.name }),
28996
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs t-text font-medium truncate", title: skill.name, children: skill.name }),
28724
28997
  skill.source !== "builtin" && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0 px-1 py-px text-[9px] rounded t-bg-elevated t-text-muted", children: skill.source })
28725
28998
  ] }),
28726
28999
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] t-text-muted leading-tight line-clamp-2 mt-0.5", children: skill.description }),
@@ -28761,21 +29034,6 @@ function EntityTabs() {
28761
29034
  const notes = useEntityStore((s15) => s15.notes);
28762
29035
  const data = useEntityStore((s15) => s15.data);
28763
29036
  const refreshAll = useEntityStore((s15) => s15.refreshAll);
28764
- reactExports.useEffect(() => {
28765
- refreshAll();
28766
- }, []);
28767
- const renderContent = () => {
28768
- switch (leftTab) {
28769
- case "library":
28770
- return /* @__PURE__ */ jsxRuntimeExports.jsx(LibraryContent, { notes, data, refreshAll });
28771
- case "files":
28772
- return /* @__PURE__ */ jsxRuntimeExports.jsx(WorkspaceTree, {});
28773
- case "skills":
28774
- return /* @__PURE__ */ jsxRuntimeExports.jsx(SkillsContent, {});
28775
- default:
28776
- return null;
28777
- }
28778
- };
28779
29037
  const handleTabKeyDown = (e) => {
28780
29038
  const tabKeys = tabs.map((t) => t.key);
28781
29039
  const idx = tabKeys.indexOf(leftTab);
@@ -28809,16 +29067,44 @@ function EntityTabs() {
28809
29067
  },
28810
29068
  key
28811
29069
  )) }),
28812
- /* @__PURE__ */ jsxRuntimeExports.jsx(
28813
- "div",
28814
- {
28815
- role: "tabpanel",
28816
- id: `tabpanel-${leftTab}`,
28817
- "aria-labelledby": `tab-${leftTab}`,
28818
- className: "flex-1 min-h-0 overflow-hidden flex flex-col",
28819
- children: renderContent()
28820
- }
28821
- )
29070
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 min-h-0 overflow-hidden", children: [
29071
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
29072
+ "div",
29073
+ {
29074
+ role: "tabpanel",
29075
+ id: "tabpanel-library",
29076
+ "aria-labelledby": "tab-library",
29077
+ className: `h-full flex flex-col min-h-0 ${leftTab === "library" ? "" : "hidden"}`,
29078
+ "aria-hidden": leftTab !== "library",
29079
+ inert: leftTab !== "library",
29080
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(LibraryContent, { notes, data, refreshAll })
29081
+ }
29082
+ ),
29083
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
29084
+ "div",
29085
+ {
29086
+ role: "tabpanel",
29087
+ id: "tabpanel-files",
29088
+ "aria-labelledby": "tab-files",
29089
+ className: `h-full flex flex-col min-h-0 ${leftTab === "files" ? "" : "hidden"}`,
29090
+ "aria-hidden": leftTab !== "files",
29091
+ inert: leftTab !== "files",
29092
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(WorkspaceTree, {})
29093
+ }
29094
+ ),
29095
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
29096
+ "div",
29097
+ {
29098
+ role: "tabpanel",
29099
+ id: "tabpanel-skills",
29100
+ "aria-labelledby": "tab-skills",
29101
+ className: `h-full flex flex-col min-h-0 ${leftTab === "skills" ? "" : "hidden"}`,
29102
+ "aria-hidden": leftTab !== "skills",
29103
+ inert: leftTab !== "skills",
29104
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(SkillsContent, {})
29105
+ }
29106
+ )
29107
+ ] })
28822
29108
  ] });
28823
29109
  }
28824
29110
  const api$8 = window.api;
@@ -28899,7 +29185,7 @@ function GapAlerts({ papers }) {
28899
29185
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] t-text-muted uppercase tracking-wider font-medium", children: "Coverage Gaps" }),
28900
29186
  gaps.map((topic) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5 px-1", children: [
28901
29187
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-1.5 h-1.5 rounded-full bg-amber-400 shrink-0" }),
28902
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[11px] t-text-secondary truncate", children: topic })
29188
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[11px] t-text-secondary truncate", title: topic, children: topic })
28903
29189
  ] }, topic))
28904
29190
  ] });
28905
29191
  }
@@ -29167,6 +29453,7 @@ function UserProfile() {
29167
29453
  "button",
29168
29454
  {
29169
29455
  onClick: handlePickFolder,
29456
+ title: displayPath,
29170
29457
  className: "no-drag flex items-center gap-2 w-full text-left text-sm t-text-secondary hover:t-text transition-colors",
29171
29458
  children: [
29172
29459
  /* @__PURE__ */ jsxRuntimeExports.jsx(Folder, { size: 16, className: "shrink-0" }),
@@ -29711,12 +29998,13 @@ function ReasoningToggle() {
29711
29998
  }
29712
29999
  );
29713
30000
  }
29714
- function ToolbarButton({ onClick, tooltip, children }) {
30001
+ function ToolbarButton({ onClick, tooltip, children, ariaExpanded }) {
29715
30002
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(
29716
30003
  "button",
29717
30004
  {
29718
30005
  onClick,
29719
30006
  "aria-label": tooltip,
30007
+ "aria-expanded": ariaExpanded,
29720
30008
  className: "no-drag group relative p-2.5 rounded-lg t-text-muted t-bg-hover transition-colors",
29721
30009
  children: [
29722
30010
  children,
@@ -29733,10 +30021,99 @@ function ToolbarButton({ onClick, tooltip, children }) {
29733
30021
  }
29734
30022
  );
29735
30023
  }
30024
+ function OverflowMenu({
30025
+ theme,
30026
+ onToggleTheme,
30027
+ onResetContext,
30028
+ onToggleTerminal
30029
+ }) {
30030
+ const [open, setOpen] = React$2.useState(false);
30031
+ const ref = reactExports.useRef(null);
30032
+ reactExports.useEffect(() => {
30033
+ if (!open) return;
30034
+ const handler = (e) => {
30035
+ if (!ref.current?.contains(e.target)) setOpen(false);
30036
+ };
30037
+ const escHandler = (e) => {
30038
+ if (e.key === "Escape") setOpen(false);
30039
+ };
30040
+ document.addEventListener("mousedown", handler);
30041
+ document.addEventListener("keydown", escHandler);
30042
+ return () => {
30043
+ document.removeEventListener("mousedown", handler);
30044
+ document.removeEventListener("keydown", escHandler);
30045
+ };
30046
+ }, [open]);
30047
+ const run = (fn2) => () => {
30048
+ fn2();
30049
+ setOpen(false);
30050
+ };
30051
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { ref, className: "relative", children: [
30052
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
30053
+ ToolbarButton,
30054
+ {
30055
+ onClick: () => setOpen((v3) => !v3),
30056
+ tooltip: "More",
30057
+ ariaExpanded: open,
30058
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(Ellipsis, { size: 16 })
30059
+ }
30060
+ ),
30061
+ open && /* @__PURE__ */ jsxRuntimeExports.jsxs(
30062
+ "div",
30063
+ {
30064
+ role: "menu",
30065
+ className: "absolute right-0 top-full mt-1 min-w-[180px] rounded-lg border t-border t-bg-surface shadow-xl z-50 py-1",
30066
+ children: [
30067
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
30068
+ "button",
30069
+ {
30070
+ role: "menuitem",
30071
+ onClick: run(onResetContext),
30072
+ className: "w-full flex items-center gap-2 px-3 py-1.5 text-xs t-text t-bg-hover transition-colors",
30073
+ children: [
30074
+ /* @__PURE__ */ jsxRuntimeExports.jsx(RotateCcw, { size: 14, className: "t-text-muted" }),
30075
+ "Reset AI context"
30076
+ ]
30077
+ }
30078
+ ),
30079
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
30080
+ "button",
30081
+ {
30082
+ role: "menuitem",
30083
+ onClick: run(onToggleTheme),
30084
+ className: "w-full flex items-center gap-2 px-3 py-1.5 text-xs t-text t-bg-hover transition-colors",
30085
+ children: [
30086
+ theme === "dark" ? /* @__PURE__ */ jsxRuntimeExports.jsx(Sun, { size: 14, className: "t-text-muted" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Moon, { size: 14, className: "t-text-muted" }),
30087
+ theme === "dark" ? "Light mode" : "Dark mode"
30088
+ ]
30089
+ }
30090
+ ),
30091
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
30092
+ "button",
30093
+ {
30094
+ role: "menuitem",
30095
+ onClick: run(onToggleTerminal),
30096
+ className: "w-full flex items-center justify-between gap-2 px-3 py-1.5 text-xs t-text t-bg-hover transition-colors",
30097
+ children: [
30098
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-2", children: [
30099
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Terminal, { size: 14, className: "t-text-muted" }),
30100
+ "Terminal"
30101
+ ] }),
30102
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-muted font-mono text-[10px]", children: "⌘`" })
30103
+ ]
30104
+ }
30105
+ )
30106
+ ]
30107
+ }
30108
+ )
30109
+ ] });
30110
+ }
29736
30111
  function LeftSidebar({ onOpenSettings }) {
29737
30112
  const theme = useUIStore((s15) => s15.theme);
29738
30113
  const toggleTheme = useUIStore((s15) => s15.toggleTheme);
29739
30114
  const centerView = useUIStore((s15) => s15.centerView);
30115
+ const leftSidebarWidth = useUIStore((s15) => s15.leftSidebarWidth);
30116
+ const setLeftSidebarWidth = useUIStore((s15) => s15.setLeftSidebarWidth);
29740
30117
  const noContextShownRef = reactExports.useRef(false);
29741
30118
  const handleResetContext = reactExports.useCallback(async () => {
29742
30119
  const messages = useChatStore.getState().messages;
@@ -29760,49 +30137,84 @@ function LeftSidebar({ onOpenSettings }) {
29760
30137
  useChatStore.getState().insertContextReset();
29761
30138
  noContextShownRef.current = false;
29762
30139
  }, []);
29763
- return (
29764
- // Narrow windows (≤1279px) get w-80 (320px) so the center panel keeps
29765
- // room to breathe; wider windows (≥1280px) get w-[22rem] (352px) so the
29766
- // toolbar has comfortable slack. Below ~1024px the ModelSelector label
29767
- // is the first thing to truncate — see ModelSelector for the shrink
29768
- // pattern introduced in commit 95312df.
29769
- /* @__PURE__ */ jsxRuntimeExports.jsxs("aside", { className: "w-80 xl:w-[22rem] flex flex-col border-r t-border t-bg-base pt-10", children: [
29770
- /* @__PURE__ */ jsxRuntimeExports.jsxs("nav", { "aria-label": "Sidebar tools", className: "px-4 pb-3 flex items-center justify-between", children: [
29771
- /* @__PURE__ */ jsxRuntimeExports.jsx(ModelSelector, {}),
29772
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1", children: [
29773
- /* @__PURE__ */ jsxRuntimeExports.jsx(ReasoningToggle, {}),
29774
- /* @__PURE__ */ jsxRuntimeExports.jsx(
29775
- ToolbarButton,
29776
- {
29777
- onClick: handleResetContext,
29778
- tooltip: "Reset AI context",
29779
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(RotateCcw, { size: 16 })
29780
- }
29781
- ),
29782
- /* @__PURE__ */ jsxRuntimeExports.jsx(
29783
- ToolbarButton,
29784
- {
29785
- onClick: toggleTheme,
29786
- tooltip: `${theme === "dark" ? "Light" : "Dark"} mode`,
29787
- children: theme === "dark" ? /* @__PURE__ */ jsxRuntimeExports.jsx(Sun, { size: 16 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Moon, { size: 16 })
29788
- }
29789
- ),
29790
- /* @__PURE__ */ jsxRuntimeExports.jsx(
29791
- ToolbarButton,
29792
- {
29793
- onClick: () => useUIStore.getState().toggleTerminal(),
29794
- tooltip: "Terminal ⌘`",
29795
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(Terminal, { size: 16 })
29796
- }
29797
- )
29798
- ] })
29799
- ] }),
29800
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-h-0", children: centerView === "literature" ? /* @__PURE__ */ jsxRuntimeExports.jsx(LiteratureSidebar, {}) : centerView === "compute" && window.api?.isComputeEnabled?.() ? /* @__PURE__ */ jsxRuntimeExports.jsx(ComputeSidebar, {}) : /* @__PURE__ */ jsxRuntimeExports.jsx(EntityTabs, {}) }),
29801
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-t t-border p-4 flex items-center justify-between", children: [
29802
- /* @__PURE__ */ jsxRuntimeExports.jsx(UserProfile, {}),
29803
- /* @__PURE__ */ jsxRuntimeExports.jsx(ToolbarButton, { onClick: onOpenSettings, tooltip: "Settings ⌘,", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Settings, { size: 16 }) })
29804
- ] })
29805
- ] })
30140
+ const dragStateRef = reactExports.useRef(null);
30141
+ const handleEdgeMouseDown = reactExports.useCallback((e) => {
30142
+ dragStateRef.current = { startX: e.clientX, startWidth: leftSidebarWidth };
30143
+ document.body.style.cursor = "ew-resize";
30144
+ e.preventDefault();
30145
+ }, [leftSidebarWidth]);
30146
+ reactExports.useEffect(() => {
30147
+ const onMove = (e) => {
30148
+ if (!dragStateRef.current) return;
30149
+ const dx = e.clientX - dragStateRef.current.startX;
30150
+ setLeftSidebarWidth(dragStateRef.current.startWidth + dx);
30151
+ };
30152
+ const onUp = () => {
30153
+ if (dragStateRef.current) document.body.style.cursor = "";
30154
+ dragStateRef.current = null;
30155
+ };
30156
+ window.addEventListener("mousemove", onMove);
30157
+ window.addEventListener("mouseup", onUp);
30158
+ return () => {
30159
+ window.removeEventListener("mousemove", onMove);
30160
+ window.removeEventListener("mouseup", onUp);
30161
+ };
30162
+ }, [setLeftSidebarWidth]);
30163
+ const handleEdgeDoubleClick = reactExports.useCallback(() => {
30164
+ setLeftSidebarWidth(320);
30165
+ }, [setLeftSidebarWidth]);
30166
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
30167
+ "aside",
30168
+ {
30169
+ className: "relative flex flex-col border-r t-border t-bg-base pt-10 shrink-0",
30170
+ style: { width: `${leftSidebarWidth}px` },
30171
+ children: [
30172
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("nav", { "aria-label": "Sidebar tools", className: "px-4 pb-3 flex items-center justify-between gap-2", children: [
30173
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ModelSelector, {}),
30174
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1", children: [
30175
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ReasoningToggle, {}),
30176
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
30177
+ OverflowMenu,
30178
+ {
30179
+ theme,
30180
+ onToggleTheme: toggleTheme,
30181
+ onResetContext: handleResetContext,
30182
+ onToggleTerminal: () => useUIStore.getState().toggleTerminal()
30183
+ }
30184
+ )
30185
+ ] })
30186
+ ] }),
30187
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-h-0 overflow-hidden", children: (() => {
30188
+ const computeEnabled2 = !!window.api?.isComputeEnabled?.();
30189
+ const showLit = centerView === "literature";
30190
+ const showCompute = centerView === "compute" && computeEnabled2;
30191
+ const showEntity = !showLit && !showCompute;
30192
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
30193
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `h-full ${showLit ? "" : "hidden"}`, "aria-hidden": !showLit, inert: !showLit, children: /* @__PURE__ */ jsxRuntimeExports.jsx(LiteratureSidebar, {}) }),
30194
+ computeEnabled2 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `h-full ${showCompute ? "" : "hidden"}`, "aria-hidden": !showCompute, inert: !showCompute, children: /* @__PURE__ */ jsxRuntimeExports.jsx(ComputeSidebar, {}) }),
30195
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `h-full ${showEntity ? "" : "hidden"}`, "aria-hidden": !showEntity, inert: !showEntity, children: /* @__PURE__ */ jsxRuntimeExports.jsx(EntityTabs, {}) })
30196
+ ] });
30197
+ })() }),
30198
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-t t-border p-4 flex items-center justify-between", children: [
30199
+ /* @__PURE__ */ jsxRuntimeExports.jsx(UserProfile, {}),
30200
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ToolbarButton, { onClick: onOpenSettings, tooltip: "Settings ⌘,", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Settings, { size: 16 }) })
30201
+ ] }),
30202
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
30203
+ "div",
30204
+ {
30205
+ role: "separator",
30206
+ "aria-orientation": "vertical",
30207
+ "aria-label": "Resize sidebar (drag to resize, double-click to reset)",
30208
+ tabIndex: -1,
30209
+ className: "absolute right-0 top-0 bottom-0 w-[6px] cursor-ew-resize group z-[6]",
30210
+ style: { marginRight: -3 },
30211
+ onMouseDown: handleEdgeMouseDown,
30212
+ onDoubleClick: handleEdgeDoubleClick,
30213
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute right-[3px] top-1/2 -translate-y-1/2 w-[2px] h-9 rounded bg-transparent group-hover:t-bg-accent transition-colors" })
30214
+ }
30215
+ )
30216
+ ]
30217
+ }
29806
30218
  );
29807
30219
  }
29808
30220
  const STARTERS = [
@@ -30502,8 +30914,53 @@ function ToolUseStream({ events: propEvents }) {
30502
30914
  running.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-1 mt-1", children: running.map((event) => /* @__PURE__ */ jsxRuntimeExports.jsx(ToolUseCard, { event }, event.id)) })
30503
30915
  ] });
30504
30916
  }
30917
+ function ImageLightbox({ src, onClose }) {
30918
+ reactExports.useEffect(() => {
30919
+ const onKey = (e) => {
30920
+ if (e.key === "Escape") onClose();
30921
+ };
30922
+ document.addEventListener("keydown", onKey);
30923
+ const prevOverflow = document.body.style.overflow;
30924
+ document.body.style.overflow = "hidden";
30925
+ return () => {
30926
+ document.removeEventListener("keydown", onKey);
30927
+ document.body.style.overflow = prevOverflow;
30928
+ };
30929
+ }, [onClose]);
30930
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
30931
+ "div",
30932
+ {
30933
+ role: "dialog",
30934
+ "aria-modal": "true",
30935
+ "aria-label": "Image preview",
30936
+ onClick: onClose,
30937
+ className: "fixed inset-0 z-[100] flex items-center justify-center p-8",
30938
+ style: { background: "rgba(0,0,0,0.82)" },
30939
+ children: [
30940
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
30941
+ "img",
30942
+ {
30943
+ src,
30944
+ alt: "",
30945
+ onClick: (e) => e.stopPropagation(),
30946
+ className: "max-w-full max-h-full object-contain rounded-lg shadow-2xl"
30947
+ }
30948
+ ),
30949
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
30950
+ "button",
30951
+ {
30952
+ onClick: onClose,
30953
+ "aria-label": "Close preview",
30954
+ className: "absolute top-4 right-4 p-2 rounded-full text-white/80 hover:text-white hover:bg-white/10 transition-colors",
30955
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(X$1, { size: 22 })
30956
+ }
30957
+ )
30958
+ ]
30959
+ }
30960
+ );
30961
+ }
30505
30962
  const api$7 = window.api;
30506
- const remarkPlugins$2 = [remarkGfm];
30963
+ const remarkPlugins$3 = [remarkGfm];
30507
30964
  function formatMessageTime(ts2) {
30508
30965
  const d = new Date(ts2);
30509
30966
  const now2 = /* @__PURE__ */ new Date();
@@ -30663,59 +31120,63 @@ const MessageBubble = React$2.memo(function MessageBubble2({ msg, isSaved }) {
30663
31120
  }
30664
31121
  };
30665
31122
  const [copied, setCopied] = reactExports.useState(false);
31123
+ const [lightboxSrc, setLightboxSrc] = reactExports.useState(null);
30666
31124
  const handleCopy = async () => {
30667
31125
  await navigator.clipboard.writeText(msg.content);
30668
31126
  setCopied(true);
30669
31127
  setTimeout(() => setCopied(false), 1500);
30670
31128
  };
30671
- return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `flex ${isUser ? "justify-end" : "justify-start"} group`, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
30672
- "div",
30673
- {
30674
- className: `relative max-w-[90%] rounded-2xl px-4 py-3 text-sm t-text ${!isUser ? "assistant-bubble" : ""}${!isUser && isSaved ? " border-l-2 border-[var(--color-status-success)]" : ""}`,
30675
- style: {
30676
- background: isUser ? "var(--color-bubble-user)" : "var(--color-bubble-assistant)"
30677
- },
30678
- "data-msg-id": msg.id,
30679
- children: [
30680
- msg.images && msg.images.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex gap-2 mb-2 flex-wrap", children: msg.images.map((src, i) => /* @__PURE__ */ jsxRuntimeExports.jsx(
30681
- "img",
30682
- {
30683
- src,
30684
- alt: "",
30685
- loading: "lazy",
30686
- className: `rounded-lg border t-border cursor-pointer hover:opacity-90 transition-opacity ${isUser ? "max-h-48" : "max-h-80"}`,
30687
- onClick: () => window.open(src, "_blank")
30688
- },
30689
- i
30690
- )) }),
30691
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "md-prose", style: { color: "var(--color-text)" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Markdown, { remarkPlugins: remarkPlugins$2, children: msg.content }) }),
30692
- msg.timestamp > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `mt-1.5 text-[10px] t-text-muted select-none ${isUser ? "text-right" : "text-left"}`, children: formatMessageTime(msg.timestamp) }),
30693
- !isUser && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "absolute -right-8 top-2 flex flex-col gap-1.5", children: [
30694
- /* @__PURE__ */ jsxRuntimeExports.jsx(
30695
- "button",
30696
- {
30697
- onClick: handleSaveNote,
30698
- disabled: saveState !== "idle",
30699
- className: `transition-opacity ${saveState === "saved" ? "opacity-100 t-text-success" : saveState === "saving" ? "opacity-100 t-text-muted" : "opacity-0 group-hover:opacity-100 t-text-muted hover:t-text-accent-soft"}`,
30700
- title: saveState === "saved" ? "Saved as note" : "Save entire message as note",
30701
- "aria-label": saveState === "saved" ? "Message saved as note" : "Save entire message as note",
30702
- children: saveState === "saving" ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { size: 14, className: "animate-spin" }) : saveState === "saved" ? /* @__PURE__ */ jsxRuntimeExports.jsx(BookmarkCheck, { size: 14 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Bookmark, { size: 14 })
30703
- }
30704
- ),
30705
- /* @__PURE__ */ jsxRuntimeExports.jsx(
30706
- "button",
31129
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `flex ${isUser ? "justify-end" : "justify-start"} group`, children: [
31130
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
31131
+ "div",
31132
+ {
31133
+ className: `relative max-w-[90%] rounded-2xl px-4 py-3 text-sm t-text ${!isUser ? "assistant-bubble" : ""}${!isUser && isSaved ? " border-l-2 border-[var(--color-status-success)]" : ""}`,
31134
+ style: {
31135
+ background: isUser ? "var(--color-bubble-user)" : "var(--color-bubble-assistant)"
31136
+ },
31137
+ "data-msg-id": msg.id,
31138
+ children: [
31139
+ msg.images && msg.images.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex gap-2 mb-2 flex-wrap", children: msg.images.map((src, i) => /* @__PURE__ */ jsxRuntimeExports.jsx(
31140
+ "img",
30707
31141
  {
30708
- onClick: handleCopy,
30709
- className: `transition-opacity ${copied ? "opacity-100 t-text-success" : "opacity-0 group-hover:opacity-100 t-text-muted hover:t-text-accent-soft"}`,
30710
- title: copied ? "Copied!" : "Copy message",
30711
- "aria-label": copied ? "Message copied" : "Copy message to clipboard",
30712
- children: copied ? /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { size: 14 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { size: 14 })
30713
- }
30714
- )
30715
- ] })
30716
- ]
30717
- }
30718
- ) });
31142
+ src,
31143
+ alt: "",
31144
+ loading: "lazy",
31145
+ className: `rounded-lg border t-border cursor-pointer hover:opacity-90 transition-opacity ${isUser ? "max-h-48" : "max-h-80"}`,
31146
+ onClick: () => setLightboxSrc(src)
31147
+ },
31148
+ i
31149
+ )) }),
31150
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "md-prose", style: { color: "var(--color-text)" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Markdown, { remarkPlugins: remarkPlugins$3, children: msg.content }) }),
31151
+ msg.timestamp > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `mt-1.5 text-[10px] t-text-muted select-none ${isUser ? "text-right" : "text-left"}`, children: formatMessageTime(msg.timestamp) }),
31152
+ !isUser && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "absolute -right-8 top-2 flex flex-col gap-1.5", children: [
31153
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
31154
+ "button",
31155
+ {
31156
+ onClick: handleSaveNote,
31157
+ disabled: saveState !== "idle",
31158
+ className: `transition-opacity ${saveState === "saved" ? "opacity-100 t-text-success" : saveState === "saving" ? "opacity-100 t-text-muted" : "opacity-0 group-hover:opacity-100 t-text-muted hover:t-text-accent-soft"}`,
31159
+ title: saveState === "saved" ? "Saved as note" : "Save entire message as note",
31160
+ "aria-label": saveState === "saved" ? "Message saved as note" : "Save entire message as note",
31161
+ children: saveState === "saving" ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { size: 14, className: "animate-spin" }) : saveState === "saved" ? /* @__PURE__ */ jsxRuntimeExports.jsx(BookmarkCheck, { size: 14 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Bookmark, { size: 14 })
31162
+ }
31163
+ ),
31164
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
31165
+ "button",
31166
+ {
31167
+ onClick: handleCopy,
31168
+ className: `transition-opacity ${copied ? "opacity-100 t-text-success" : "opacity-0 group-hover:opacity-100 t-text-muted hover:t-text-accent-soft"}`,
31169
+ title: copied ? "Copied!" : "Copy message",
31170
+ "aria-label": copied ? "Message copied" : "Copy message to clipboard",
31171
+ children: copied ? /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { size: 14 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { size: 14 })
31172
+ }
31173
+ )
31174
+ ] })
31175
+ ]
31176
+ }
31177
+ ),
31178
+ lightboxSrc && /* @__PURE__ */ jsxRuntimeExports.jsx(ImageLightbox, { src: lightboxSrc, onClose: () => setLightboxSrc(null) })
31179
+ ] });
30719
31180
  });
30720
31181
  function ThinkingIndicator() {
30721
31182
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(
@@ -30740,7 +31201,7 @@ function StreamingBubble() {
30740
31201
  className: "max-w-[90%] rounded-2xl px-4 py-3 text-sm t-text assistant-bubble",
30741
31202
  style: { background: "var(--color-bubble-assistant)" },
30742
31203
  children: [
30743
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "md-prose", style: { color: "var(--color-text)" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Markdown, { remarkPlugins: remarkPlugins$2, children: text2 }) }),
31204
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "md-prose", style: { color: "var(--color-text)" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Markdown, { remarkPlugins: remarkPlugins$3, children: text2 }) }),
30744
31205
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "inline-block w-1.5 h-4 t-bg-accent-soft animate-pulse ml-0.5 align-text-bottom" })
30745
31206
  ]
30746
31207
  }
@@ -31349,6 +31810,7 @@ function ChatInput() {
31349
31810
  const [pendingImages, setPendingImages] = reactExports.useState([]);
31350
31811
  const [pendingFiles, setPendingFiles] = reactExports.useState([]);
31351
31812
  const [isDragOver, setIsDragOver] = reactExports.useState(false);
31813
+ const [lightboxSrc, setLightboxSrc] = reactExports.useState(null);
31352
31814
  const textareaRef = reactExports.useRef(null);
31353
31815
  const fileInputRef = reactExports.useRef(null);
31354
31816
  const send = useChatStore((s15) => s15.send);
@@ -31366,23 +31828,17 @@ function ChatInput() {
31366
31828
  const addImageFiles = reactExports.useCallback((files) => {
31367
31829
  const imageFiles = files.filter((f) => ACCEPTED_IMAGE_TYPES.includes(f.type));
31368
31830
  if (imageFiles.length === 0) return;
31369
- setPendingImages((prev) => {
31370
- const remaining = MAX_IMAGES - prev.length;
31371
- if (remaining <= 0) return prev;
31372
- const toAdd = imageFiles.slice(0, remaining);
31373
- toAdd.forEach((file) => {
31374
- const reader = new FileReader();
31375
- reader.onload = () => {
31376
- const dataUrl = reader.result;
31377
- const base64 = dataUrl.split(",")[1];
31378
- setPendingImages((p) => {
31379
- if (p.length >= MAX_IMAGES) return p;
31380
- return [...p, { base64, mimeType: file.type, dataUrl }];
31381
- });
31382
- };
31383
- reader.readAsDataURL(file);
31384
- });
31385
- return prev;
31831
+ imageFiles.forEach((file) => {
31832
+ const reader = new FileReader();
31833
+ reader.onload = () => {
31834
+ const dataUrl = reader.result;
31835
+ const base64 = dataUrl.split(",")[1];
31836
+ setPendingImages((p) => {
31837
+ if (p.length >= MAX_IMAGES) return p;
31838
+ return [...p, { base64, mimeType: file.type, dataUrl }];
31839
+ });
31840
+ };
31841
+ reader.readAsDataURL(file);
31386
31842
  });
31387
31843
  }, []);
31388
31844
  const isDocFile = reactExports.useCallback((file) => {
@@ -31744,6 +32200,7 @@ ${s15.openQuestions.map((q2) => `- ${q2}`).join("\n")}`;
31744
32200
  }
31745
32201
  }, [text2]);
31746
32202
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative", children: [
32203
+ lightboxSrc && /* @__PURE__ */ jsxRuntimeExports.jsx(ImageLightbox, { src: lightboxSrc, onClose: () => setLightboxSrc(null) }),
31747
32204
  showMention && /* @__PURE__ */ jsxRuntimeExports.jsx(
31748
32205
  MentionPopover,
31749
32206
  {
@@ -31790,13 +32247,17 @@ ${s15.openQuestions.map((q2) => `- ${q2}`).join("\n")}`;
31790
32247
  {
31791
32248
  src: img.dataUrl,
31792
32249
  alt: "",
31793
- className: "h-16 w-16 object-cover rounded-lg border t-border"
32250
+ onClick: () => setLightboxSrc(img.dataUrl),
32251
+ className: "h-16 w-16 object-cover rounded-lg border t-border cursor-pointer hover:opacity-90 transition-opacity"
31794
32252
  }
31795
32253
  ),
31796
32254
  /* @__PURE__ */ jsxRuntimeExports.jsx(
31797
32255
  "button",
31798
32256
  {
31799
- onClick: () => setPendingImages((prev) => prev.filter((_2, j2) => j2 !== i)),
32257
+ onClick: (e) => {
32258
+ e.stopPropagation();
32259
+ setPendingImages((prev) => prev.filter((_2, j2) => j2 !== i));
32260
+ },
31800
32261
  className: "absolute -top-1.5 -right-1.5 w-4 h-4 rounded-full t-bg-error text-white text-[10px]\n leading-none flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity",
31801
32262
  "aria-label": "Remove image",
31802
32263
  children: "×"
@@ -31879,7 +32340,7 @@ ${s15.openQuestions.map((q2) => `- ${q2}`).join("\n")}`;
31879
32340
  ] });
31880
32341
  }
31881
32342
  const api$4 = window.api;
31882
- const remarkPlugins$1 = [remarkGfm];
32343
+ const remarkPlugins$2 = [remarkGfm];
31883
32344
  function PaperFallback({ paper }) {
31884
32345
  const authors = paper.authors || [];
31885
32346
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [
@@ -32014,7 +32475,7 @@ ${body.trim()}
32014
32475
  }
32015
32476
  )
32016
32477
  ] }),
32017
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 overflow-y-auto px-4 py-3", onClick: handleLinkClick, children: loading ? /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs t-text-muted animate-pulse", children: "Loading..." }) : isPaperFallback && fallbackPaper ? /* @__PURE__ */ jsxRuntimeExports.jsx(PaperFallback, { paper: fallbackPaper }) : processedContent ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "md-prose text-sm", style: { color: "var(--color-text)" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Markdown, { remarkPlugins: remarkPlugins$1, children: processedContent }) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs t-text-muted", children: "No wiki page found for this slug." }) })
32478
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 overflow-y-auto px-4 py-3", onClick: handleLinkClick, children: loading ? /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs t-text-muted animate-pulse", children: "Loading..." }) : isPaperFallback && fallbackPaper ? /* @__PURE__ */ jsxRuntimeExports.jsx(PaperFallback, { paper: fallbackPaper }) : processedContent ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "md-prose text-sm", style: { color: "var(--color-text)" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Markdown, { remarkPlugins: remarkPlugins$2, children: processedContent }) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs t-text-muted", children: "No wiki page found for this slug." }) })
32018
32479
  ] });
32019
32480
  }
32020
32481
  function normalize(raw) {
@@ -32146,14 +32607,13 @@ function SortHeader({
32146
32607
  }
32147
32608
  );
32148
32609
  }
32149
- function PaperRow({
32150
- paper,
32610
+ const PaperRow = React$2.memo(function PaperRow2({
32611
+ row,
32151
32612
  expanded,
32152
- onToggle,
32153
- wikiSlug,
32154
32613
  isActive,
32155
- source = "project"
32614
+ onToggle
32156
32615
  }) {
32616
+ const { paper, source, wikiSlug } = row;
32157
32617
  const setWikiSlug = useUIStore((s15) => s15.setWikiReaderSlug);
32158
32618
  const authors = paper.authors || [];
32159
32619
  const authorStr = authors.length <= 3 ? authors.join(", ") : `${authors.slice(0, 2).join(", ")} et al.`;
@@ -32164,7 +32624,7 @@ function PaperRow({
32164
32624
  "div",
32165
32625
  {
32166
32626
  className: `flex items-center gap-3 px-3 py-2 transition-colors cursor-pointer ${isActive ? "bg-[var(--color-accent-soft)]/10" : "hover:bg-[var(--color-accent-soft)]/5"}`,
32167
- onClick: onToggle,
32627
+ onClick: () => onToggle(row),
32168
32628
  children: [
32169
32629
  /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "shrink-0 t-text-muted", children: expanded ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { size: 14 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { size: 14 }) }),
32170
32630
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [
@@ -32245,7 +32705,7 @@ function PaperRow({
32245
32705
  ] })
32246
32706
  ] })
32247
32707
  ] });
32248
- }
32708
+ });
32249
32709
  function WikiStatusPill() {
32250
32710
  const [status, setStatus] = reactExports.useState(null);
32251
32711
  reactExports.useEffect(() => {
@@ -32424,6 +32884,14 @@ function LiteratureView() {
32424
32884
  const wikiReaderSlug = useUIStore((s15) => s15.wikiReaderSlug);
32425
32885
  const setWikiSlug = useUIStore((s15) => s15.setWikiReaderSlug);
32426
32886
  const [expandedKey, setExpandedKey] = reactExports.useState(null);
32887
+ const handleRowToggle = reactExports.useCallback((row) => {
32888
+ setExpandedKey((prev) => prev === row.key ? null : row.key);
32889
+ if (row.source === "wiki") {
32890
+ setWikiSlug(row.wikiSlug);
32891
+ } else {
32892
+ setWikiSlug(row.wikiSlug || `paper:${row.paper.id}`);
32893
+ }
32894
+ }, [setWikiSlug]);
32427
32895
  const [wikiSlugs, setWikiSlugs] = reactExports.useState({});
32428
32896
  const [wikiMeta, setWikiMeta] = reactExports.useState([]);
32429
32897
  reactExports.useEffect(() => {
@@ -32615,19 +33083,10 @@ function LiteratureView() {
32615
33083
  ] }) : filteredRows.map((row) => /* @__PURE__ */ jsxRuntimeExports.jsx(
32616
33084
  PaperRow,
32617
33085
  {
32618
- paper: row.paper,
32619
- source: row.source,
33086
+ row,
32620
33087
  expanded: expandedKey === row.key,
32621
33088
  isActive: activeRowKey === row.key,
32622
- onToggle: () => {
32623
- setExpandedKey(expandedKey === row.key ? null : row.key);
32624
- if (row.source === "wiki") {
32625
- setWikiSlug(row.wikiSlug);
32626
- } else {
32627
- setWikiSlug(row.wikiSlug || `paper:${row.paper.id}`);
32628
- }
32629
- },
32630
- wikiSlug: row.wikiSlug
33089
+ onToggle: handleRowToggle
32631
33090
  },
32632
33091
  row.key
32633
33092
  )) })
@@ -32986,95 +33445,135 @@ function ComputeView() {
32986
33445
  !isEmpty && /* @__PURE__ */ jsxRuntimeExports.jsx(CoverageBar, { runs: allRuns })
32987
33446
  ] });
32988
33447
  }
32989
- const api$2 = window.api;
32990
- const computeEnabled = api$2?.isComputeEnabled?.() ?? false;
32991
- const viewTabs = [
32992
- { key: "chat", label: "Chat", icon: MessageSquare, shortcut: "⌘1" },
32993
- { key: "literature", label: "Literature", icon: BookOpen, shortcut: "⌘2" },
32994
- ...computeEnabled ? [{ key: "compute", label: "Compute", icon: Cpu, shortcut: "⌘3" }] : []
32995
- ];
32996
- function ViewSwitcher() {
32997
- const centerView = useUIStore((s15) => s15.centerView);
32998
- const setCenterView = useUIStore((s15) => s15.setCenterView);
32999
- const paperCount = useEntityStore((s15) => s15.papers.length);
33000
- const activeComputeRuns = useActiveRunCount();
33001
- return (
33002
- // Bottom hairline gives the nav a real anchor — without it, the tabs
33003
- // float in a gray area between the drag region and the content.
33004
- /* @__PURE__ */ jsxRuntimeExports.jsx(
33005
- "nav",
33006
- {
33007
- "aria-label": "View switcher",
33008
- className: "flex items-stretch gap-1 px-4 pt-10 border-b t-border",
33009
- children: viewTabs.map(({ key, label, icon: Icon2, shortcut }) => {
33010
- const isActive = centerView === key;
33011
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(
33012
- "button",
33013
- {
33014
- onClick: () => setCenterView(key),
33015
- "aria-current": isActive ? "page" : void 0,
33016
- title: `${label} (${shortcut})`,
33017
- className: `no-drag relative group flex items-center gap-2 px-3 pt-1.5 pb-2 text-[13px] font-medium transition-colors ${isActive ? "t-text" : "t-text-muted hover:t-text-secondary"}`,
33018
- children: [
33019
- /* @__PURE__ */ jsxRuntimeExports.jsx(Icon2, { size: 14, className: isActive ? "t-text-accent" : "" }),
33020
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: label }),
33021
- key === "literature" && paperCount > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(
33022
- "span",
33023
- {
33024
- className: `px-1.5 py-px text-[10px] rounded-full tabular-nums ${isActive ? "t-bg-accent/15 t-text-accent" : "t-bg-elevated t-text-muted"}`,
33025
- children: paperCount
33026
- }
33027
- ),
33028
- key === "compute" && activeComputeRuns > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "px-1.5 py-px text-[10px] rounded-full tabular-nums t-bg-accent/15 t-text-accent", children: activeComputeRuns }),
33029
- /* @__PURE__ */ jsxRuntimeExports.jsx(
33030
- "kbd",
33031
- {
33032
- className: `inline-flex items-center px-1 py-0 rounded border text-[9.5px] font-mono leading-[1.4] transition-colors ${isActive ? "t-border-accent-soft t-text-accent-soft bg-transparent" : "t-border-subtle t-bg-elevated t-text-muted group-hover:t-text-secondary"}`,
33033
- children: shortcut
33034
- }
33035
- ),
33036
- /* @__PURE__ */ jsxRuntimeExports.jsx(
33037
- "span",
33038
- {
33039
- "aria-hidden": true,
33040
- className: `pointer-events-none absolute left-0 right-0 -bottom-px h-[2px] transition-colors ${isActive ? "t-bg-accent" : "bg-transparent"}`
33041
- }
33042
- )
33043
- ]
33044
- },
33045
- key
33046
- );
33047
- })
33048
- }
33049
- )
33050
- );
33051
- }
33052
- function CenterPanel() {
33053
- const centerView = useUIStore((s15) => s15.centerView);
33054
- const isIdle = useUIStore((s15) => s15.isIdle);
33055
- const messages = useChatStore((s15) => s15.messages);
33056
- const showHero = isIdle && messages.length === 0;
33057
- if (centerView === "literature") {
33058
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("main", { id: "main-content", className: "flex-1 flex flex-col min-w-0", children: [
33059
- /* @__PURE__ */ jsxRuntimeExports.jsx(ViewSwitcher, {}),
33060
- /* @__PURE__ */ jsxRuntimeExports.jsx(LiteratureView, {})
33061
- ] });
33448
+ function resolveMarkdownImageUrl(src, baseDir) {
33449
+ if (!src) return "";
33450
+ if (/^(?:https?:|data:|blob:|workspace-asset:|file:)/i.test(src)) return src;
33451
+ let absPath = null;
33452
+ if (src.startsWith("/")) {
33453
+ absPath = src;
33454
+ } else if (baseDir) {
33455
+ try {
33456
+ const normalizedBase = baseDir.endsWith("/") ? baseDir : baseDir + "/";
33457
+ const resolved = new URL(src, `file://${normalizedBase}`);
33458
+ absPath = decodeURIComponent(resolved.pathname);
33459
+ } catch {
33460
+ absPath = null;
33461
+ }
33462
+ }
33463
+ if (!absPath) return src;
33464
+ return `workspace-asset://asset${encodeURI(absPath)}`;
33465
+ }
33466
+ function dirnameOf(filePath) {
33467
+ if (!filePath) return void 0;
33468
+ const normalized = filePath.replace(/\\/g, "/");
33469
+ const idx = normalized.lastIndexOf("/");
33470
+ if (idx < 0) return void 0;
33471
+ return normalized.slice(0, idx);
33472
+ }
33473
+ const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
33474
+ function splitFrontmatter(markdown) {
33475
+ if (!markdown) return { frontmatterBlock: null, body: markdown ?? "" };
33476
+ const match = markdown.match(FRONTMATTER_RE);
33477
+ if (!match) return { frontmatterBlock: null, body: markdown };
33478
+ return { frontmatterBlock: match[0], body: markdown.slice(match[0].length) };
33479
+ }
33480
+ function parseFrontmatterPairs(block) {
33481
+ const out = {};
33482
+ if (!block) return out;
33483
+ const inner = block.match(FRONTMATTER_RE)?.[1] ?? "";
33484
+ for (const rawLine of inner.split("\n")) {
33485
+ const line = rawLine.trim();
33486
+ if (!line || line.startsWith("#")) continue;
33487
+ const colonIdx = line.indexOf(":");
33488
+ if (colonIdx < 0) continue;
33489
+ const key = line.slice(0, colonIdx).trim();
33490
+ if (key) out[key] = line.slice(colonIdx + 1).trim();
33062
33491
  }
33063
- if (centerView === "compute") {
33064
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("main", { id: "main-content", className: "flex-1 flex flex-col min-w-0", children: [
33065
- /* @__PURE__ */ jsxRuntimeExports.jsx(ViewSwitcher, {}),
33066
- /* @__PURE__ */ jsxRuntimeExports.jsx(ComputeView, {})
33067
- ] });
33492
+ return out;
33493
+ }
33494
+ function isMarpFrontmatter(block) {
33495
+ const pairs = parseFrontmatterPairs(block);
33496
+ return /^(?:true|yes|on)$/i.test(pairs.marp || "");
33497
+ }
33498
+ const THEMATIC_BREAK_RE = /^[ \t]{0,3}(?:-{3,}|\*{3,}|_{3,})[ \t]*\r?$/m;
33499
+ function splitSlides(body) {
33500
+ return body.split(THEMATIC_BREAK_RE).map((chunk) => chunk.trim()).filter((chunk) => chunk.length > 0);
33501
+ }
33502
+ const remarkPlugins$1 = [remarkGfm];
33503
+ function MarpSlideView({ slides, baseDir }) {
33504
+ if (slides.length === 0) {
33505
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs t-text-muted", children: "No slides detected. Switch to source view to inspect the markdown." });
33068
33506
  }
33069
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("main", { id: "main-content", className: "flex-1 flex flex-col min-w-0", children: [
33070
- /* @__PURE__ */ jsxRuntimeExports.jsx(ViewSwitcher, {}),
33071
- showHero ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntimeExports.jsx(HeroIdle, {}) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-h-0 px-6 pt-4 pb-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mx-auto h-full", style: { maxWidth: "64rem" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChatMessages, {}) }) }),
33072
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-6 pb-5", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mx-auto", style: { maxWidth: "64rem" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChatInput, {}) }) })
33073
- ] });
33507
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-col gap-4", children: slides.map((slide, index2) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
33508
+ "article",
33509
+ {
33510
+ className: "relative t-bg-surface border t-border rounded-lg shadow-sm overflow-hidden",
33511
+ style: { aspectRatio: "16 / 9", minHeight: 200 },
33512
+ "aria-label": `Slide ${index2 + 1} of ${slides.length}`,
33513
+ children: [
33514
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "absolute top-2 right-3 text-[10px] font-mono tabular-nums t-text-muted z-10", children: [
33515
+ index2 + 1,
33516
+ " / ",
33517
+ slides.length
33518
+ ] }),
33519
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
33520
+ "div",
33521
+ {
33522
+ className: "md-prose h-full overflow-auto px-6 py-5",
33523
+ style: { color: "var(--color-text)", fontSize: "14px", lineHeight: 1.5 },
33524
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
33525
+ Markdown,
33526
+ {
33527
+ remarkPlugins: remarkPlugins$1,
33528
+ components: {
33529
+ img: ({ src, alt, ...rest }) => /* @__PURE__ */ jsxRuntimeExports.jsx(
33530
+ "img",
33531
+ {
33532
+ src: resolveMarkdownImageUrl(src, baseDir),
33533
+ alt,
33534
+ ...rest
33535
+ }
33536
+ )
33537
+ },
33538
+ children: slide
33539
+ }
33540
+ )
33541
+ }
33542
+ )
33543
+ ]
33544
+ },
33545
+ index2
33546
+ )) });
33074
33547
  }
33075
33548
  const remarkPlugins = [remarkGfm];
33549
+ const NAVIGABLE_FILE_EXTS = /* @__PURE__ */ new Set([
33550
+ "md",
33551
+ "txt",
33552
+ "json",
33553
+ "ts",
33554
+ "js",
33555
+ "css",
33556
+ "yml",
33557
+ "yaml",
33558
+ "toml",
33559
+ "env",
33560
+ "sh",
33561
+ "py",
33562
+ "cfg",
33563
+ "ini",
33564
+ "log",
33565
+ "csv",
33566
+ "xml",
33567
+ "rst",
33568
+ "jsx",
33569
+ "tsx",
33570
+ "mjs",
33571
+ "cjs",
33572
+ "markdown",
33573
+ "gitignore"
33574
+ ]);
33076
33575
  const LazyMilkdownMarkdownEditor = reactExports.lazy(async () => {
33077
- const mod = await __vitePreload(() => import("./MilkdownMarkdownEditor-CuTa5j4S.js").then((n) => n.bL), true ? __vite__mapDeps([0,1]) : void 0, import.meta.url);
33576
+ const mod = await __vitePreload(() => import("./MilkdownMarkdownEditor-OhCrq3X0.js").then((n) => n.bL), true ? __vite__mapDeps([0,1]) : void 0, import.meta.url);
33078
33577
  return { default: mod.MilkdownMarkdownEditor };
33079
33578
  });
33080
33579
  const typeIcons = {
@@ -33185,6 +33684,9 @@ function CsvPreview({ content: content2, separator }) {
33185
33684
  ] })
33186
33685
  ] });
33187
33686
  }
33687
+ function normalizePathSep(p) {
33688
+ return p.replace(/\\/g, "/");
33689
+ }
33188
33690
  function usePreviewNavigation() {
33189
33691
  const previewSourceTab = useUIStore((s15) => s15.previewSourceTab);
33190
33692
  const previewEntity = useUIStore((s15) => s15.previewEntity);
@@ -33192,6 +33694,71 @@ function usePreviewNavigation() {
33192
33694
  const notes = useEntityStore((s15) => s15.notes);
33193
33695
  const papers = useEntityStore((s15) => s15.papers);
33194
33696
  const data = useEntityStore((s15) => s15.data);
33697
+ const projectPath = useSessionStore((s15) => s15.projectPath);
33698
+ const [fileSiblings, setFileSiblings] = reactExports.useState([]);
33699
+ const currentFilePath = previewSourceTab === "files" ? previewEntity?.filePath : void 0;
33700
+ reactExports.useEffect(() => {
33701
+ if (!currentFilePath || !projectPath) {
33702
+ setFileSiblings([]);
33703
+ return;
33704
+ }
33705
+ const absFile = normalizePathSep(currentFilePath);
33706
+ const absProj = normalizePathSep(projectPath);
33707
+ let relParent;
33708
+ if (absFile === absProj) {
33709
+ relParent = "";
33710
+ } else if (absFile.startsWith(absProj + "/")) {
33711
+ const rel = absFile.slice(absProj.length + 1);
33712
+ relParent = rel.includes("/") ? rel.slice(0, rel.lastIndexOf("/")) : "";
33713
+ } else {
33714
+ setFileSiblings([]);
33715
+ return;
33716
+ }
33717
+ let cancelled = false;
33718
+ const api2 = window.api;
33719
+ Promise.resolve(api2.listTree({ relativePath: relParent, showIgnored: true, limit: 2e3 })).then((nodes) => {
33720
+ if (cancelled || !Array.isArray(nodes)) return;
33721
+ const siblings = [];
33722
+ for (const n of nodes) {
33723
+ if (n.type !== "file") continue;
33724
+ const ext = (n.name.split(".").pop() || "").toLowerCase();
33725
+ if (!NAVIGABLE_FILE_EXTS.has(ext)) continue;
33726
+ siblings.push({ name: n.name, path: n.path, modifiedAt: n.modifiedAt || Date.now() });
33727
+ }
33728
+ setFileSiblings(siblings);
33729
+ }).catch(() => {
33730
+ if (!cancelled) setFileSiblings([]);
33731
+ });
33732
+ return () => {
33733
+ cancelled = true;
33734
+ };
33735
+ }, [currentFilePath, projectPath]);
33736
+ const entityForFilePath = reactExports.useCallback((filePath, displayName, modifiedAt) => {
33737
+ const norm = normalizePathSep(filePath);
33738
+ const existing = data.find((item) => normalizePathSep(item.filePath || "") === norm);
33739
+ if (existing) {
33740
+ return {
33741
+ ...existing,
33742
+ type: "data",
33743
+ title: existing.title || existing.name || displayName,
33744
+ filePath
33745
+ };
33746
+ }
33747
+ const iso = new Date(modifiedAt || Date.now()).toISOString();
33748
+ return {
33749
+ id: filePath,
33750
+ type: "data",
33751
+ title: displayName,
33752
+ filePath,
33753
+ tags: [],
33754
+ createdAt: iso,
33755
+ updatedAt: iso
33756
+ };
33757
+ }, [data]);
33758
+ const fileSiblingEntities = reactExports.useMemo(
33759
+ () => fileSiblings.map((s15) => entityForFilePath(s15.path, s15.name, s15.modifiedAt)),
33760
+ [fileSiblings, entityForFilePath]
33761
+ );
33195
33762
  const list2 = (() => {
33196
33763
  switch (previewSourceTab) {
33197
33764
  case "library":
@@ -33199,11 +33766,19 @@ function usePreviewNavigation() {
33199
33766
  case "papers":
33200
33767
  return papers;
33201
33768
  case "files":
33769
+ return fileSiblingEntities;
33202
33770
  default:
33203
33771
  return [];
33204
33772
  }
33205
33773
  })();
33206
- const currentIndex = previewEntity ? list2.findIndex((item) => item.id === previewEntity.id) : -1;
33774
+ const currentIndex = (() => {
33775
+ if (!previewEntity) return -1;
33776
+ if (previewSourceTab === "files" && previewEntity.filePath) {
33777
+ const target = normalizePathSep(previewEntity.filePath);
33778
+ return list2.findIndex((item) => normalizePathSep(item.filePath || "") === target);
33779
+ }
33780
+ return list2.findIndex((item) => item.id === previewEntity.id);
33781
+ })();
33207
33782
  const total = list2.length;
33208
33783
  const canNavigate = total > 1 && currentIndex >= 0;
33209
33784
  const goNext = reactExports.useCallback(() => {
@@ -33222,12 +33797,35 @@ function EntityPreviewPanel() {
33222
33797
  const rawEntity = useUIStore((s15) => s15.previewEntity);
33223
33798
  const closePreview = useUIStore((s15) => s15.closePreview);
33224
33799
  const setPreviewEditorFocused = useUIStore((s15) => s15.setPreviewEditorFocused);
33225
- const deleteEntity = useEntityStore((s15) => s15.deleteEntity);
33800
+ const drawerWidth = useUIStore((s15) => s15.drawerWidth);
33801
+ const setDrawerWidth = useUIStore((s15) => s15.setDrawerWidth);
33226
33802
  const refreshAll = useEntityStore((s15) => s15.refreshAll);
33227
33803
  const previewEditorFocused = useUIStore((s15) => s15.previewEditorFocused);
33228
33804
  const nav = usePreviewNavigation();
33805
+ const dragStateRef = reactExports.useRef(null);
33806
+ const handleEdgeMouseDown = reactExports.useCallback((e) => {
33807
+ dragStateRef.current = { startX: e.clientX, startWidth: drawerWidth };
33808
+ document.body.style.cursor = "ew-resize";
33809
+ e.preventDefault();
33810
+ }, [drawerWidth]);
33811
+ reactExports.useEffect(() => {
33812
+ const onMove = (e) => {
33813
+ if (!dragStateRef.current) return;
33814
+ const dx = dragStateRef.current.startX - e.clientX;
33815
+ setDrawerWidth(dragStateRef.current.startWidth + dx);
33816
+ };
33817
+ const onUp = () => {
33818
+ if (dragStateRef.current) document.body.style.cursor = "";
33819
+ dragStateRef.current = null;
33820
+ };
33821
+ window.addEventListener("mousemove", onMove);
33822
+ window.addEventListener("mouseup", onUp);
33823
+ return () => {
33824
+ window.removeEventListener("mousemove", onMove);
33825
+ window.removeEventListener("mouseup", onUp);
33826
+ };
33827
+ }, [setDrawerWidth]);
33229
33828
  const entity = rawEntity ? { ...rawEntity } : null;
33230
- const [confirmDelete, setConfirmDelete] = reactExports.useState(false);
33231
33829
  const [draftMarkdown, setDraftMarkdown] = reactExports.useState("");
33232
33830
  const [baselineMarkdown, setBaselineMarkdown] = reactExports.useState("");
33233
33831
  const [editorSeedMarkdown, setEditorSeedMarkdown] = reactExports.useState("");
@@ -33237,6 +33835,7 @@ function EntityPreviewPanel() {
33237
33835
  const [fileType, setFileType] = reactExports.useState(null);
33238
33836
  const [loading, setLoading] = reactExports.useState(false);
33239
33837
  const [externalMarkdown, setExternalMarkdown] = reactExports.useState(void 0);
33838
+ const [viewModeOverride, setViewModeOverride] = reactExports.useState(null);
33240
33839
  const resolvedAbsPathRef = reactExports.useRef(null);
33241
33840
  const baselineRef = reactExports.useRef("");
33242
33841
  const getArtifactMarkdownContent = (artifactLike) => {
@@ -33259,6 +33858,7 @@ function EntityPreviewPanel() {
33259
33858
  setSaveError(null);
33260
33859
  setSaveSuccess(null);
33261
33860
  setPreviewEditorFocused(false);
33861
+ setViewModeOverride(null);
33262
33862
  }, [entity?.id]);
33263
33863
  reactExports.useEffect(() => {
33264
33864
  setFileContent(null);
@@ -33299,6 +33899,11 @@ function EntityPreviewPanel() {
33299
33899
  reactExports.useEffect(() => {
33300
33900
  baselineRef.current = baselineMarkdown;
33301
33901
  }, [baselineMarkdown]);
33902
+ const scrollContentRef = reactExports.useRef(null);
33903
+ const modeScrollRef = reactExports.useRef({ source: 0, slides: 0 });
33904
+ reactExports.useEffect(() => {
33905
+ modeScrollRef.current = { source: 0, slides: 0 };
33906
+ }, [entity?.id]);
33302
33907
  reactExports.useEffect(() => {
33303
33908
  if (!entity?.filePath) return;
33304
33909
  const ext = getExtension(entity.filePath);
@@ -33343,7 +33948,48 @@ function EntityPreviewPanel() {
33343
33948
  const isInlineEditable = !entity.filePath;
33344
33949
  const isEditable = isInlineEditable || isFileMarkdown;
33345
33950
  const isDirty = isEditable && normalizeMarkdown(draftMarkdown) !== normalizeMarkdown(baselineMarkdown);
33346
- const seedFp = buildFingerprint(editorSeedMarkdown);
33951
+ const { frontmatterBlock, body: baselineBody } = reactExports.useMemo(
33952
+ () => splitFrontmatter(baselineMarkdown),
33953
+ [baselineMarkdown]
33954
+ );
33955
+ const isMarpFile = reactExports.useMemo(() => isMarpFrontmatter(frontmatterBlock), [frontmatterBlock]);
33956
+ const draftBody = reactExports.useMemo(() => {
33957
+ if (!frontmatterBlock) return draftMarkdown;
33958
+ return draftMarkdown.startsWith(frontmatterBlock) ? draftMarkdown.slice(frontmatterBlock.length) : splitFrontmatter(draftMarkdown).body;
33959
+ }, [draftMarkdown, frontmatterBlock]);
33960
+ const editorSeedBody = reactExports.useMemo(() => splitFrontmatter(editorSeedMarkdown).body, [editorSeedMarkdown]);
33961
+ const externalBody = reactExports.useMemo(() => {
33962
+ if (externalMarkdown === void 0) return void 0;
33963
+ return splitFrontmatter(externalMarkdown).body;
33964
+ }, [externalMarkdown]);
33965
+ const slides = reactExports.useMemo(
33966
+ () => isMarpFile ? splitSlides(draftBody) : [],
33967
+ [isMarpFile, draftBody]
33968
+ );
33969
+ const effectiveViewMode = viewModeOverride ?? (isMarpFile ? "slides" : "source");
33970
+ const showSlideView = isMarpFile && effectiveViewMode === "slides";
33971
+ reactExports.useEffect(() => {
33972
+ const el2 = scrollContentRef.current;
33973
+ if (!el2) return;
33974
+ const onScroll = () => {
33975
+ modeScrollRef.current[effectiveViewMode] = el2.scrollTop;
33976
+ };
33977
+ el2.addEventListener("scroll", onScroll, { passive: true });
33978
+ return () => el2.removeEventListener("scroll", onScroll);
33979
+ }, [effectiveViewMode]);
33980
+ reactExports.useEffect(() => {
33981
+ const target = modeScrollRef.current[effectiveViewMode] ?? 0;
33982
+ const apply = () => {
33983
+ if (scrollContentRef.current) scrollContentRef.current.scrollTop = target;
33984
+ };
33985
+ const raf = requestAnimationFrame(apply);
33986
+ const retry = window.setTimeout(apply, 200);
33987
+ return () => {
33988
+ cancelAnimationFrame(raf);
33989
+ window.clearTimeout(retry);
33990
+ };
33991
+ }, [effectiveViewMode, entity?.id]);
33992
+ const seedFp = buildFingerprint(editorSeedBody);
33347
33993
  const editorKey = `${entity.id}:${entity.filePath ?? "inline"}:${seedFp.length}:${seedFp.codeFenceCount}:${seedFp.mermaidFenceCount}:${seedFp.mathBlockCount}:${seedFp.imageCount}`;
33348
33994
  const handleNavNext = reactExports.useCallback(() => {
33349
33995
  if (!nav.canNavigate) return;
@@ -33376,15 +34022,6 @@ function EntityPreviewPanel() {
33376
34022
  window.addEventListener("keydown", handler);
33377
34023
  return () => window.removeEventListener("keydown", handler);
33378
34024
  }, [nav.canNavigate, previewEditorFocused, handleNavPrev, handleNavNext]);
33379
- const handleDelete2 = async () => {
33380
- if (!confirmDelete) {
33381
- setConfirmDelete(true);
33382
- setTimeout(() => setConfirmDelete(false), 2e3);
33383
- return;
33384
- }
33385
- await deleteEntity(entity.id);
33386
- closePreview();
33387
- };
33388
34025
  const handleSave = async () => {
33389
34026
  if (!isEditable || !isDirty) return;
33390
34027
  const nextMarkdown = draftMarkdown;
@@ -33465,10 +34102,11 @@ Save anyway?`
33465
34102
  LazyMilkdownMarkdownEditor,
33466
34103
  {
33467
34104
  editorId: editorKey,
33468
- initialMarkdown: baselineMarkdown,
33469
- externalMarkdown,
34105
+ initialMarkdown: baselineBody,
34106
+ externalMarkdown: externalBody,
34107
+ baseDir: dirnameOf(entity.filePath),
33470
34108
  onChange: (markdown) => {
33471
- setDraftMarkdown(markdown);
34109
+ setDraftMarkdown((frontmatterBlock ?? "") + markdown);
33472
34110
  if (saveError) setSaveError(null);
33473
34111
  },
33474
34112
  onFocusChange: setPreviewEditorFocused,
@@ -33511,6 +34149,9 @@ Save anyway?`
33511
34149
  const ext = getExtension(entity.filePath);
33512
34150
  const isMarkdown = ext === "md" || ext === "markdown";
33513
34151
  if (isMarkdown) {
34152
+ if (showSlideView) {
34153
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(MarpSlideView, { slides, baseDir: dirnameOf(entity.filePath) });
34154
+ }
33514
34155
  return renderMarkdownEditor();
33515
34156
  }
33516
34157
  return /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "text-xs whitespace-pre-wrap break-words t-text font-mono leading-relaxed", children: fileContent });
@@ -33518,142 +34159,368 @@ Save anyway?`
33518
34159
  return /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs t-text-muted", children: entity.filePath });
33519
34160
  }
33520
34161
  if (isInlineEditable) {
34162
+ if (showSlideView) {
34163
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(MarpSlideView, { slides, baseDir: dirnameOf(entity.filePath) });
34164
+ }
33521
34165
  return renderMarkdownEditor();
33522
34166
  }
33523
34167
  const content2 = entity.content || entity.abstract || entity.valueText || "No content available.";
33524
- return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "md-prose", style: { color: "var(--color-text)" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Markdown, { remarkPlugins, children: typeof content2 === "string" ? content2 : JSON.stringify(content2, null, 2) }) });
33525
- };
33526
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex flex-col border-l t-border t-bg-base pt-10 min-w-0", children: [
33527
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 px-4 py-3 border-b t-border", children: [
33528
- typeIcons[entity.type] || null,
33529
- /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "flex-1 text-sm font-semibold t-text truncate", children: entity.title }),
33530
- isEditable && isDirty && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] px-1.5 py-0.5 rounded-full bg-[var(--color-status-warning)]/15 t-text-warning", children: "Unsaved" }),
33531
- nav.canNavigate && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-0.5", children: [
33532
- /* @__PURE__ */ jsxRuntimeExports.jsx(
33533
- "button",
33534
- {
33535
- onClick: handleNavPrev,
33536
- className: "p-1 rounded t-text-muted t-bg-hover transition-colors",
33537
- title: "Previous item (Alt+Up)",
33538
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronUp, { size: 14 })
33539
- }
33540
- ),
33541
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] t-text-muted tabular-nums min-w-[2.5rem] text-center", children: [
33542
- nav.currentIndex + 1,
33543
- " / ",
33544
- nav.total
33545
- ] }),
33546
- /* @__PURE__ */ jsxRuntimeExports.jsx(
33547
- "button",
34168
+ const mdBaseDir = dirnameOf(entity.filePath);
34169
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
34170
+ "div",
34171
+ {
34172
+ className: "md-prose",
34173
+ style: {
34174
+ color: "var(--color-text)",
34175
+ fontFamily: READING_FONT,
34176
+ fontSize: "14px",
34177
+ lineHeight: 1.55
34178
+ },
34179
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
34180
+ Markdown,
33548
34181
  {
33549
- onClick: handleNavNext,
33550
- className: "p-1 rounded t-text-muted t-bg-hover transition-colors",
33551
- title: "Next item (Alt+Down)",
33552
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { size: 14 })
34182
+ remarkPlugins,
34183
+ components: {
34184
+ // Rewrite relative / absolute disk paths to workspace-asset://
34185
+ // URLs so images actually load. Remote URLs pass through.
34186
+ img: ({ src, alt, ...rest }) => /* @__PURE__ */ jsxRuntimeExports.jsx(
34187
+ "img",
34188
+ {
34189
+ src: resolveMarkdownImageUrl(src, mdBaseDir),
34190
+ alt,
34191
+ ...rest
34192
+ }
34193
+ )
34194
+ },
34195
+ children: typeof content2 === "string" ? content2 : JSON.stringify(content2, null, 2)
33553
34196
  }
33554
34197
  )
33555
- ] }),
33556
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1", children: [
33557
- isEditable && /* @__PURE__ */ jsxRuntimeExports.jsx(
33558
- "button",
33559
- {
33560
- onClick: () => void handleSave(),
33561
- disabled: !isDirty,
33562
- className: `p-1 rounded transition-colors ${isDirty ? "t-text-accent-soft hover:t-text-accent" : "t-text-muted opacity-50"}`,
33563
- title: isDirty ? "Save markdown (Cmd/Ctrl+S)" : "No changes to save",
33564
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(Save, { size: 14 })
33565
- }
33566
- ),
33567
- entity.id !== "agent-md" && /* @__PURE__ */ jsxRuntimeExports.jsx(
33568
- "button",
33569
- {
33570
- onClick: handleDelete2,
33571
- className: `p-1 rounded transition-colors ${confirmDelete ? "t-text-error" : "t-text-muted t-bg-hover"}`,
33572
- title: confirmDelete ? "Click again to confirm delete" : "Delete",
33573
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { size: 14 })
33574
- }
33575
- ),
34198
+ }
34199
+ );
34200
+ };
34201
+ const drawerBoxShadow = "inset 3px 0 0 0 var(--color-accent), -12px 0 32px -14px rgba(0,0,0,0.18)";
34202
+ const crumb = entity.filePath ? `files · ${(getExtension(entity.filePath) || "file").toLowerCase()}` : `library · ${entity.type}`;
34203
+ const READING_FONT = '"Iowan Old Style", "Charter", "Sitka Text", Georgia, serif';
34204
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
34205
+ "div",
34206
+ {
34207
+ className: "absolute top-0 right-0 bottom-0 flex flex-col t-bg-base min-w-0 z-[5] pt-10 transition-[width,box-shadow] duration-500 ease-[cubic-bezier(0.32,0.72,0.24,1)]",
34208
+ style: { width: drawerWidth, boxShadow: drawerBoxShadow },
34209
+ "aria-label": `Preview: ${entity.title}`,
34210
+ children: [
33576
34211
  /* @__PURE__ */ jsxRuntimeExports.jsx(
33577
- "button",
34212
+ "div",
33578
34213
  {
33579
- onClick: handleClosePreview,
33580
- className: "p-1 rounded t-text-muted t-bg-hover transition-colors",
33581
- title: "Close preview",
33582
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(X$1, { size: 14 })
34214
+ className: "absolute left-0 top-0 bottom-0 w-[6px] cursor-ew-resize group z-[6]",
34215
+ style: { marginLeft: -3 },
34216
+ onMouseDown: handleEdgeMouseDown,
34217
+ title: "Drag to resize",
34218
+ "aria-hidden": "true",
34219
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute left-[3px] top-1/2 -translate-y-1/2 w-[2px] h-9 rounded bg-transparent group-hover:t-bg-accent transition-colors" })
33583
34220
  }
33584
- )
33585
- ] })
33586
- ] }),
33587
- entity.type === "paper" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 py-2 border-b t-border text-xs t-text-secondary space-y-1", children: [
33588
- entity.authors?.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
33589
- "Authors: ",
33590
- entity.authors.join(", ")
33591
- ] }),
33592
- entity.year && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
33593
- "Year: ",
33594
- entity.year
33595
- ] }),
33596
- entity.venue && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
33597
- "Venue: ",
33598
- entity.venue
33599
- ] }),
33600
- entity.doi && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
33601
- "DOI: ",
33602
- /* @__PURE__ */ jsxRuntimeExports.jsx("a", { href: `https://doi.org/${entity.doi}`, target: "_blank", rel: "noreferrer", className: "t-text-accent-soft hover:underline", children: entity.doi })
33603
- ] }),
33604
- entity.citationCount != null && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
33605
- "Citations: ",
33606
- entity.citationCount
33607
- ] }),
33608
- entity.url && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
33609
- "URL: ",
33610
- /* @__PURE__ */ jsxRuntimeExports.jsx("a", { href: entity.url, target: "_blank", rel: "noreferrer", className: "t-text-accent-soft hover:underline break-all", children: entity.url })
33611
- ] }),
33612
- entity.pdfUrl && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
33613
- "PDF: ",
33614
- /* @__PURE__ */ jsxRuntimeExports.jsx("a", { href: entity.pdfUrl, target: "_blank", rel: "noreferrer", className: "t-text-accent-soft hover:underline break-all", children: entity.pdfUrl })
33615
- ] }),
33616
- entity.citeKey && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
33617
- "Cite key: ",
33618
- /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "t-bg-surface px-1 rounded", children: entity.citeKey })
33619
- ] }),
33620
- entity.externalSource && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
33621
- "Source: ",
33622
- entity.externalSource
33623
- ] }),
33624
- entity.relevanceScore != null && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
33625
- "Relevance: ",
33626
- entity.relevanceScore,
33627
- "/10"
33628
- ] }),
33629
- entity.enrichmentSource && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
33630
- "Enriched via: ",
33631
- entity.enrichmentSource
33632
- ] }),
33633
- entity.enrichedAt && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
33634
- "Enriched at: ",
33635
- new Date(entity.enrichedAt).toLocaleDateString()
33636
- ] }),
33637
- entity.tags?.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "flex items-center gap-1 flex-wrap", children: [
33638
- "Tags: ",
33639
- entity.tags.map((t) => /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "inline-block t-bg-surface px-1.5 py-0.5 rounded", children: t }, t))
33640
- ] }),
33641
- entity.bibtex && /* @__PURE__ */ jsxRuntimeExports.jsxs("details", { className: "mt-1", children: [
33642
- /* @__PURE__ */ jsxRuntimeExports.jsx("summary", { className: "cursor-pointer hover:t-text-accent-soft", children: "BibTeX" }),
33643
- /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "mt-1 p-2 t-bg-surface rounded text-[11px] font-mono whitespace-pre-wrap break-all", children: entity.bibtex })
33644
- ] })
33645
- ] }),
33646
- entity.type === "data" && entity.schema && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 py-2 border-b t-border text-xs t-text-secondary", children: [
33647
- /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
33648
- "File: ",
33649
- entity.name
33650
- ] }),
33651
- entity.schema.rowCount != null && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
33652
- "Rows: ",
33653
- entity.schema.rowCount
33654
- ] })
33655
- ] }),
33656
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 overflow-y-auto px-4 py-4", children: renderContent() })
34221
+ ),
34222
+ /* @__PURE__ */ jsxRuntimeExports.jsx("header", { className: "px-5 pt-3.5 pb-3 border-b t-border", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-start justify-between gap-3", children: [
34223
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0 flex-1", children: [
34224
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-[10px] font-mono uppercase tracking-[0.14em] t-text-muted mb-1.5 flex items-center gap-2 flex-wrap", children: [
34225
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: crumb }),
34226
+ isEditable && isDirty && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "normal-case tracking-normal px-1.5 py-0.5 rounded-full bg-[var(--color-status-warning)]/15 t-text-warning", children: "Unsaved" })
34227
+ ] }),
34228
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [
34229
+ typeIcons[entity.type] || null,
34230
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
34231
+ "h2",
34232
+ {
34233
+ className: "min-w-0 truncate t-text",
34234
+ style: {
34235
+ fontFamily: READING_FONT,
34236
+ fontSize: "17px",
34237
+ lineHeight: 1.2,
34238
+ fontWeight: 500,
34239
+ letterSpacing: "-0.012em"
34240
+ },
34241
+ children: entity.title
34242
+ }
34243
+ )
34244
+ ] })
34245
+ ] }),
34246
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1 flex-shrink-0 pt-1", children: [
34247
+ nav.canNavigate && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-0.5 mr-1", children: [
34248
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
34249
+ "button",
34250
+ {
34251
+ onClick: handleNavPrev,
34252
+ className: "p-1 rounded t-text-muted t-bg-hover transition-colors",
34253
+ title: "Previous item (Alt+Up)",
34254
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronUp, { size: 14 })
34255
+ }
34256
+ ),
34257
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] t-text-muted tabular-nums min-w-[2.5rem] text-center", children: [
34258
+ nav.currentIndex + 1,
34259
+ " / ",
34260
+ nav.total
34261
+ ] }),
34262
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
34263
+ "button",
34264
+ {
34265
+ onClick: handleNavNext,
34266
+ className: "p-1 rounded t-text-muted t-bg-hover transition-colors",
34267
+ title: "Next item (Alt+Down)",
34268
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { size: 14 })
34269
+ }
34270
+ )
34271
+ ] }),
34272
+ isEditable && /* @__PURE__ */ jsxRuntimeExports.jsx(
34273
+ "button",
34274
+ {
34275
+ onClick: () => void handleSave(),
34276
+ disabled: !isDirty,
34277
+ className: `p-1 rounded transition-colors ${isDirty ? "t-text-accent-soft hover:t-text-accent" : "t-text-muted opacity-50"}`,
34278
+ title: isDirty ? "Save markdown (Cmd/Ctrl+S)" : "No changes to save",
34279
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(Save, { size: 14 })
34280
+ }
34281
+ ),
34282
+ isMarpFile && /* @__PURE__ */ jsxRuntimeExports.jsx(
34283
+ "button",
34284
+ {
34285
+ onClick: () => setViewModeOverride(showSlideView ? "source" : "slides"),
34286
+ className: "p-1 rounded t-text-muted t-bg-hover transition-colors",
34287
+ title: showSlideView ? "Edit source" : "View as slides",
34288
+ "aria-pressed": showSlideView,
34289
+ children: showSlideView ? /* @__PURE__ */ jsxRuntimeExports.jsx(FileText, { size: 14 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Presentation, { size: 14 })
34290
+ }
34291
+ ),
34292
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
34293
+ "button",
34294
+ {
34295
+ onClick: handleClosePreview,
34296
+ className: "p-1 rounded t-text-muted t-bg-hover transition-colors",
34297
+ title: "Close preview (Esc)",
34298
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(X$1, { size: 14 })
34299
+ }
34300
+ )
34301
+ ] })
34302
+ ] }) }),
34303
+ entity.type === "paper" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 py-2 border-b t-border text-xs t-text-secondary space-y-1", children: [
34304
+ entity.authors?.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
34305
+ "Authors: ",
34306
+ entity.authors.join(", ")
34307
+ ] }),
34308
+ entity.year && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
34309
+ "Year: ",
34310
+ entity.year
34311
+ ] }),
34312
+ entity.venue && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
34313
+ "Venue: ",
34314
+ entity.venue
34315
+ ] }),
34316
+ entity.doi && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
34317
+ "DOI: ",
34318
+ /* @__PURE__ */ jsxRuntimeExports.jsx("a", { href: `https://doi.org/${entity.doi}`, target: "_blank", rel: "noreferrer", className: "t-text-accent-soft hover:underline", children: entity.doi })
34319
+ ] }),
34320
+ entity.citationCount != null && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
34321
+ "Citations: ",
34322
+ entity.citationCount
34323
+ ] }),
34324
+ entity.url && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
34325
+ "URL: ",
34326
+ /* @__PURE__ */ jsxRuntimeExports.jsx("a", { href: entity.url, target: "_blank", rel: "noreferrer", className: "t-text-accent-soft hover:underline break-all", children: entity.url })
34327
+ ] }),
34328
+ entity.pdfUrl && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
34329
+ "PDF: ",
34330
+ /* @__PURE__ */ jsxRuntimeExports.jsx("a", { href: entity.pdfUrl, target: "_blank", rel: "noreferrer", className: "t-text-accent-soft hover:underline break-all", children: entity.pdfUrl })
34331
+ ] }),
34332
+ entity.citeKey && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
34333
+ "Cite key: ",
34334
+ /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "t-bg-surface px-1 rounded", children: entity.citeKey })
34335
+ ] }),
34336
+ entity.externalSource && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
34337
+ "Source: ",
34338
+ entity.externalSource
34339
+ ] }),
34340
+ entity.relevanceScore != null && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
34341
+ "Relevance: ",
34342
+ entity.relevanceScore,
34343
+ "/10"
34344
+ ] }),
34345
+ entity.enrichmentSource && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
34346
+ "Enriched via: ",
34347
+ entity.enrichmentSource
34348
+ ] }),
34349
+ entity.enrichedAt && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
34350
+ "Enriched at: ",
34351
+ new Date(entity.enrichedAt).toLocaleDateString()
34352
+ ] }),
34353
+ entity.tags?.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "flex items-center gap-1 flex-wrap", children: [
34354
+ "Tags: ",
34355
+ entity.tags.map((t) => /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "inline-block t-bg-surface px-1.5 py-0.5 rounded", children: t }, t))
34356
+ ] }),
34357
+ entity.bibtex && /* @__PURE__ */ jsxRuntimeExports.jsxs("details", { className: "mt-1", children: [
34358
+ /* @__PURE__ */ jsxRuntimeExports.jsx("summary", { className: "cursor-pointer hover:t-text-accent-soft", children: "BibTeX" }),
34359
+ /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "mt-1 p-2 t-bg-surface rounded text-[11px] font-mono whitespace-pre-wrap break-all", children: entity.bibtex })
34360
+ ] })
34361
+ ] }),
34362
+ entity.type === "data" && entity.schema && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 py-2 border-b t-border text-xs t-text-secondary", children: [
34363
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
34364
+ "File: ",
34365
+ entity.name
34366
+ ] }),
34367
+ entity.schema.rowCount != null && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
34368
+ "Rows: ",
34369
+ entity.schema.rowCount
34370
+ ] })
34371
+ ] }),
34372
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { ref: scrollContentRef, className: "flex-1 overflow-y-auto px-5 py-5 min-h-0", children: renderContent() }),
34373
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("footer", { className: "shrink-0 px-5 py-2.5 border-t t-border flex items-center justify-between gap-3 text-[10px] font-mono uppercase tracking-[0.12em] t-text-muted", children: [
34374
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-2 min-w-0 truncate", children: [
34375
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
34376
+ "span",
34377
+ {
34378
+ className: "inline-block w-[7px] h-[7px] rounded-full t-bg-accent animate-pulse shrink-0",
34379
+ "aria-hidden": "true"
34380
+ }
34381
+ ),
34382
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate", children: "Bound to chat" })
34383
+ ] }),
34384
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate shrink-0", children: "Drag edge · Esc to close" })
34385
+ ] })
34386
+ ]
34387
+ }
34388
+ );
34389
+ }
34390
+ const api$2 = window.api;
34391
+ const computeEnabled = api$2?.isComputeEnabled?.() ?? false;
34392
+ const viewTabs = [
34393
+ { key: "chat", label: "Chat", icon: MessageSquare, shortcut: "⌘1" },
34394
+ { key: "literature", label: "Literature", icon: BookOpen, shortcut: "⌘2" },
34395
+ ...computeEnabled ? [{ key: "compute", label: "Compute", icon: Cpu, shortcut: "⌘3" }] : []
34396
+ ];
34397
+ function ViewSwitcher() {
34398
+ const centerView = useUIStore((s15) => s15.centerView);
34399
+ const setCenterView = useUIStore((s15) => s15.setCenterView);
34400
+ const paperCount = useEntityStore((s15) => s15.papers.length);
34401
+ const activeComputeRuns = useActiveRunCount();
34402
+ return (
34403
+ // Bottom hairline gives the nav a real anchor — without it, the tabs
34404
+ // float in a gray area between the drag region and the content.
34405
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
34406
+ "nav",
34407
+ {
34408
+ "aria-label": "View switcher",
34409
+ className: "flex items-stretch gap-1 px-4 pt-10 border-b t-border",
34410
+ children: viewTabs.map(({ key, label, icon: Icon2, shortcut }) => {
34411
+ const isActive = centerView === key;
34412
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
34413
+ "button",
34414
+ {
34415
+ onClick: () => setCenterView(key),
34416
+ "aria-current": isActive ? "page" : void 0,
34417
+ title: `${label} (${shortcut})`,
34418
+ className: `no-drag relative group flex items-center gap-2 px-3 pt-1.5 pb-2 text-[13px] font-medium transition-colors ${isActive ? "t-text" : "t-text-muted hover:t-text-secondary"}`,
34419
+ children: [
34420
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Icon2, { size: 14, className: isActive ? "t-text-accent" : "" }),
34421
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: label }),
34422
+ key === "literature" && paperCount > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(
34423
+ "span",
34424
+ {
34425
+ className: `px-1.5 py-px text-[10px] rounded-full tabular-nums ${isActive ? "t-bg-accent/15 t-text-accent" : "t-bg-elevated t-text-muted"}`,
34426
+ children: paperCount
34427
+ }
34428
+ ),
34429
+ key === "compute" && activeComputeRuns > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "px-1.5 py-px text-[10px] rounded-full tabular-nums t-bg-accent/15 t-text-accent", children: activeComputeRuns }),
34430
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
34431
+ "kbd",
34432
+ {
34433
+ className: `inline-flex items-center px-1 py-0 rounded border text-[9.5px] font-mono leading-[1.4] transition-colors ${isActive ? "t-border-accent-soft t-text-accent-soft bg-transparent" : "t-border-subtle t-bg-elevated t-text-muted group-hover:t-text-secondary"}`,
34434
+ children: shortcut
34435
+ }
34436
+ ),
34437
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
34438
+ "span",
34439
+ {
34440
+ "aria-hidden": true,
34441
+ className: `pointer-events-none absolute left-0 right-0 -bottom-px h-[2px] transition-colors ${isActive ? "t-bg-accent" : "bg-transparent"}`
34442
+ }
34443
+ )
34444
+ ]
34445
+ },
34446
+ key
34447
+ );
34448
+ })
34449
+ }
34450
+ )
34451
+ );
34452
+ }
34453
+ function CenterPanel() {
34454
+ const centerView = useUIStore((s15) => s15.centerView);
34455
+ const isIdle = useUIStore((s15) => s15.isIdle);
34456
+ const messages = useChatStore((s15) => s15.messages);
34457
+ const previewEntity = useUIStore((s15) => s15.previewEntity);
34458
+ const drawerWidth = useUIStore((s15) => s15.drawerWidth);
34459
+ const showHero = isIdle && messages.length === 0;
34460
+ const drawerOpen = !!previewEntity;
34461
+ const rightGutter = drawerOpen ? drawerWidth : 0;
34462
+ const columnShiftStyle = { paddingRight: `${rightGutter}px` };
34463
+ const columnShiftClass = "transition-[padding] duration-500 ease-[cubic-bezier(0.32,0.72,0.24,1)]";
34464
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
34465
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
34466
+ "main",
34467
+ {
34468
+ id: centerView === "chat" ? "main-content" : void 0,
34469
+ hidden: centerView !== "chat",
34470
+ className: "flex-1 flex flex-col min-w-0 relative overflow-hidden",
34471
+ children: [
34472
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: columnShiftClass, style: columnShiftStyle, children: /* @__PURE__ */ jsxRuntimeExports.jsx(ViewSwitcher, {}) }),
34473
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-h-0", children: showHero ? /* @__PURE__ */ jsxRuntimeExports.jsx(
34474
+ "div",
34475
+ {
34476
+ className: `h-full flex items-center justify-center ${columnShiftClass}`,
34477
+ style: columnShiftStyle,
34478
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(HeroIdle, {})
34479
+ }
34480
+ ) : /* @__PURE__ */ jsxRuntimeExports.jsx(
34481
+ "div",
34482
+ {
34483
+ className: `h-full pl-6 pt-4 pb-2 ${columnShiftClass}`,
34484
+ style: { paddingRight: `${24 + rightGutter}px` },
34485
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mx-auto h-full", style: { maxWidth: "64rem" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChatMessages, {}) })
34486
+ }
34487
+ ) }),
34488
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
34489
+ "div",
34490
+ {
34491
+ className: `pl-6 pb-5 ${columnShiftClass}`,
34492
+ style: { paddingRight: `${24 + rightGutter}px` },
34493
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mx-auto", style: { maxWidth: "64rem" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChatInput, {}) })
34494
+ }
34495
+ ),
34496
+ drawerOpen && /* @__PURE__ */ jsxRuntimeExports.jsx(EntityPreviewPanel, {})
34497
+ ]
34498
+ }
34499
+ ),
34500
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
34501
+ "main",
34502
+ {
34503
+ id: centerView === "literature" ? "main-content" : void 0,
34504
+ hidden: centerView !== "literature",
34505
+ className: "flex-1 flex flex-col min-w-0",
34506
+ children: [
34507
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ViewSwitcher, {}),
34508
+ /* @__PURE__ */ jsxRuntimeExports.jsx(LiteratureView, {})
34509
+ ]
34510
+ }
34511
+ ),
34512
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
34513
+ "main",
34514
+ {
34515
+ id: centerView === "compute" ? "main-content" : void 0,
34516
+ hidden: centerView !== "compute",
34517
+ className: "flex-1 flex flex-col min-w-0",
34518
+ children: [
34519
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ViewSwitcher, {}),
34520
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ComputeView, {})
34521
+ ]
34522
+ }
34523
+ )
33657
34524
  ] });
33658
34525
  }
33659
34526
  function formatCost(cost) {
@@ -42748,7 +43615,6 @@ function TipsBlock() {
42748
43615
  function FolderGate({ onOpenSettings }) {
42749
43616
  const pickFolder = useSessionStore((s15) => s15.pickFolder);
42750
43617
  const openPath = useSessionStore((s15) => s15.openPath);
42751
- const refreshEntities = useEntityStore((s15) => s15.refreshAll);
42752
43618
  const [recents, setRecents] = reactExports.useState([]);
42753
43619
  const [projectStats, setProjectStats] = reactExports.useState({});
42754
43620
  const [activeIndex, setActiveIndex] = reactExports.useState(0);
@@ -42784,22 +43650,20 @@ function FolderGate({ onOpenSettings }) {
42784
43650
  if (opening) return;
42785
43651
  setOpening(true);
42786
43652
  try {
42787
- const ok2 = await openPath(path2);
42788
- if (ok2) await refreshEntities();
43653
+ await openPath(path2);
42789
43654
  } finally {
42790
43655
  setOpening(false);
42791
43656
  }
42792
- }, [openPath, refreshEntities, opening]);
43657
+ }, [openPath, opening]);
42793
43658
  const handlePickNew = reactExports.useCallback(async () => {
42794
43659
  if (opening) return;
42795
43660
  setOpening(true);
42796
43661
  try {
42797
- const ok2 = await pickFolder();
42798
- if (ok2) await refreshEntities();
43662
+ await pickFolder();
42799
43663
  } finally {
42800
43664
  setOpening(false);
42801
43665
  }
42802
- }, [pickFolder, refreshEntities, opening]);
43666
+ }, [pickFolder, opening]);
42803
43667
  const handleRemove = reactExports.useCallback(async (path2) => {
42804
43668
  await api.removeRecentProject?.(path2);
42805
43669
  setRecents((prev) => {
@@ -43065,10 +43929,17 @@ function App() {
43065
43929
  const unsubSkillLoaded = api.onSkillLoaded((skillName) => {
43066
43930
  useActivityStore.getState().addSkill(skillName);
43067
43931
  });
43932
+ let entityRefreshTimer = null;
43933
+ const scheduleEntityRefresh = () => {
43934
+ if (entityRefreshTimer) clearTimeout(entityRefreshTimer);
43935
+ entityRefreshTimer = setTimeout(() => {
43936
+ entityRefreshTimer = null;
43937
+ refreshEntities();
43938
+ }, 300);
43939
+ };
43068
43940
  const unsub1 = api.onStreamChunk((chunk) => appendChunk(chunk));
43069
43941
  const unsub2 = api.onAgentDone((result) => {
43070
43942
  finalize(result);
43071
- refreshEntities();
43072
43943
  const text2 = result.response || "";
43073
43944
  const projectRoot = useSessionStore.getState().projectPath;
43074
43945
  const filePathRegex = /(?:^|\s)((?:[\w.-]+\/)+[\w.-]+\.\w+|(?:\/[\w.-]+)+\.\w+)/gm;
@@ -43096,7 +43967,7 @@ function App() {
43096
43967
  useUIStore.getState().addWorkingFile(path2);
43097
43968
  });
43098
43969
  const unsub6 = api.onEntityCreated(() => {
43099
- refreshEntities();
43970
+ scheduleEntityRefresh();
43100
43971
  });
43101
43972
  if (api?.isComputeEnabled?.()) {
43102
43973
  api.probeComputeEnvironment?.().catch(() => {
@@ -43112,6 +43983,7 @@ function App() {
43112
43983
  useComputeStore.getState().setEnvironment(event);
43113
43984
  });
43114
43985
  return () => {
43986
+ if (entityRefreshTimer) clearTimeout(entityRefreshTimer);
43115
43987
  unsub1();
43116
43988
  unsub2();
43117
43989
  unsub3();
@@ -43212,12 +44084,9 @@ function App() {
43212
44084
  /* @__PURE__ */ jsxRuntimeExports.jsx("a", { href: "#main-content", className: "skip-link", children: "Skip to content" }),
43213
44085
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "drag-region fixed top-0 left-0 right-0 h-8 z-50" }),
43214
44086
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-1 min-h-0", children: [
43215
- !leftCollapsed && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: previewEntity ? "hidden" : "contents", children: /* @__PURE__ */ jsxRuntimeExports.jsx(LeftSidebar, { onOpenSettings: () => setSettingsOpen(true) }) }),
44087
+ !leftCollapsed && /* @__PURE__ */ jsxRuntimeExports.jsx(LeftSidebar, { onOpenSettings: () => setSettingsOpen(true) }),
43216
44088
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex flex-col min-w-0 min-h-0", children: [
43217
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `flex min-h-0 ${terminalVisible ? "flex-[2]" : "flex-1"}`, children: [
43218
- /* @__PURE__ */ jsxRuntimeExports.jsx(CenterPanel, {}),
43219
- previewEntity && /* @__PURE__ */ jsxRuntimeExports.jsx(EntityPreviewPanel, {})
43220
- ] }),
44089
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `flex min-h-0 ${terminalVisible ? "flex-[2]" : "flex-1"}`, children: /* @__PURE__ */ jsxRuntimeExports.jsx(CenterPanel, {}) }),
43221
44090
  terminalAlive && /* @__PURE__ */ jsxRuntimeExports.jsx(
43222
44091
  "div",
43223
44092
  {
@@ -43262,6 +44131,7 @@ export {
43262
44131
  patternInScope as p,
43263
44132
  jsxRuntimeExports as q,
43264
44133
  reactExports as r,
44134
+ resolveMarkdownImageUrl as s,
43265
44135
  unified as u,
43266
44136
  visit as v
43267
44137
  };