research-copilot 0.2.17 → 0.2.20

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 (68) hide show
  1. package/README.md +6 -0
  2. package/app/out/main/index.mjs +124 -7
  3. package/app/out/preload/index.js +2 -0
  4. package/app/out/renderer/assets/{MilkdownMarkdownEditor-CuTa5j4S.js → MilkdownMarkdownEditor-Bj7JSjF5.js} +93 -51
  5. package/app/out/renderer/assets/{MilkdownMarkdownEditor-tTNRIB2K.css → MilkdownMarkdownEditor-CCdZ2mtg.css} +88 -15
  6. package/app/out/renderer/assets/{arc-BAWS3N-F.js → arc-CPL9nDFE.js} +1 -1
  7. package/app/out/renderer/assets/{blockDiagram-c4efeb88-BHadwPqY.js → blockDiagram-c4efeb88-BFOajDNs.js} +8 -8
  8. package/app/out/renderer/assets/{c4Diagram-c83219d4-B3kOxRad.js → c4Diagram-c83219d4-LeqnQ2-5.js} +3 -3
  9. package/app/out/renderer/assets/{channel-Bll9CBqI.js → channel-jk5Np8ud.js} +1 -1
  10. package/app/out/renderer/assets/{classDiagram-beda092f-Dv7owGyx.js → classDiagram-beda092f-CxOqB6OU.js} +6 -6
  11. package/app/out/renderer/assets/{classDiagram-v2-2358418a-cWrqk5tQ.js → classDiagram-v2-2358418a-CyP_5qLa.js} +10 -10
  12. package/app/out/renderer/assets/{clone-D-DQ4nnY.js → clone-PHFwh58n.js} +1 -1
  13. package/app/out/renderer/assets/{createText-1719965b-ciE8YuqI.js → createText-1719965b-CE_0jsfj.js} +2 -2
  14. package/app/out/renderer/assets/{edges-96097737-DycnAYk_.js → edges-96097737-DBk1JhZS.js} +3 -3
  15. package/app/out/renderer/assets/{erDiagram-0228fc6a-Sv78YNMY.js → erDiagram-0228fc6a-DnR_LkSB.js} +5 -5
  16. package/app/out/renderer/assets/{flowDb-c6c81e3f-BiOarg9b.js → flowDb-c6c81e3f-CJrZUKlS.js} +1 -1
  17. package/app/out/renderer/assets/{flowDiagram-50d868cf-19J80nxU.js → flowDiagram-50d868cf-CfNfrt17.js} +12 -12
  18. package/app/out/renderer/assets/{flowDiagram-v2-4f6560a1-c-kGsubV.js → flowDiagram-v2-4f6560a1-BGQtiK3j.js} +12 -12
  19. package/app/out/renderer/assets/{flowchart-elk-definition-6af322e1-DRrYbiSC.js → flowchart-elk-definition-6af322e1-BXLraghz.js} +6 -6
  20. package/app/out/renderer/assets/{ganttDiagram-a2739b55-BadmpvMy.js → ganttDiagram-a2739b55-CAwaEMMm.js} +3 -3
  21. package/app/out/renderer/assets/{gitGraphDiagram-82fe8481-BdVoj60Q.js → gitGraphDiagram-82fe8481-vuSEC6ny.js} +2 -2
  22. package/app/out/renderer/assets/{graph-jZhookGR.js → graph-CZfltE7S.js} +1 -1
  23. package/app/out/renderer/assets/{index-5325376f-CbxmatXv.js → index-5325376f-DWTrHDEo.js} +6 -6
  24. package/app/out/renderer/assets/{index-DEO9Jh2Y.js → index-7dcVwInU.js} +5 -5
  25. package/app/out/renderer/assets/{index-BTE0dEKO.js → index-B4V7cFWJ.js} +6 -6
  26. package/app/out/renderer/assets/{index-DQwFQR1s.js → index-B5Mkpo9f.js} +3 -3
  27. package/app/out/renderer/assets/{index-CirXkIv2.js → index-B6f2bVW_.js} +3 -3
  28. package/app/out/renderer/assets/{index-DO5LsHlM.js → index-BgAs-p8D.js} +1 -1
  29. package/app/out/renderer/assets/{index-DOUTte7i.js → index-BpdWQuss.js} +3 -3
  30. package/app/out/renderer/assets/{index-B9kkJj3J.js → index-C2tqvXjC.js} +6 -6
  31. package/app/out/renderer/assets/{index-D-ZMmLhv.js → index-CMfKxpBP.js} +3 -3
  32. package/app/out/renderer/assets/{index-B2UUF9y9.js → index-CUsEKU8Q.js} +1199 -386
  33. package/app/out/renderer/assets/{index-BXpNbFhG.js → index-CaYWMBXT.js} +3 -3
  34. package/app/out/renderer/assets/{index-47oNNEnx.js → index-Cc9coKGN.js} +6 -6
  35. package/app/out/renderer/assets/{index-lAZsmnj1.css → index-CogwQwDN.css} +185 -32
  36. package/app/out/renderer/assets/{index-CAlpJ3-o.js → index-CwPfquqm.js} +4 -4
  37. package/app/out/renderer/assets/{index-CZX0435B.js → index-CyDfvefg.js} +6 -6
  38. package/app/out/renderer/assets/{index-BUcSHPha.js → index-DB8ImtMy.js} +3 -3
  39. package/app/out/renderer/assets/{index-B8fh500_.js → index-DIZJXKQ6.js} +3 -3
  40. package/app/out/renderer/assets/{index-CMGDsC_t.js → index-D_7yOLk3.js} +6 -6
  41. package/app/out/renderer/assets/{index-B110aKST.js → index-Di3HmXc-.js} +3 -3
  42. package/app/out/renderer/assets/{index-HCRA2-Q6.js → index-DiCqe1UR.js} +6 -6
  43. package/app/out/renderer/assets/{index-BWCwSkxb.js → index-DpXI4mHb.js} +3 -3
  44. package/app/out/renderer/assets/{index-cavFRVgM.js → index-EaGZvaBp.js} +3 -3
  45. package/app/out/renderer/assets/{index-DF_C6DjR.js → index-K0o5fHYG.js} +3 -3
  46. package/app/out/renderer/assets/{index-BBUnWjLe.js → index-Ul-Kq9b2.js} +3 -3
  47. package/app/out/renderer/assets/{index-g91Iwgxa.js → index-t0-md-MG.js} +4 -4
  48. package/app/out/renderer/assets/{infoDiagram-8eee0895-DpVt3Scv.js → infoDiagram-8eee0895-BmPESCfj.js} +2 -2
  49. package/app/out/renderer/assets/{journeyDiagram-c64418c1-RYKX5mcV.js → journeyDiagram-c64418c1-BGsCbfr_.js} +4 -4
  50. package/app/out/renderer/assets/{layout-BsbNXXgR.js → layout-5MwFTPs7.js} +2 -2
  51. package/app/out/renderer/assets/{line-OzQTpJsh.js → line-D0U74KO0.js} +1 -1
  52. package/app/out/renderer/assets/{linear-DO5pdnqi.js → linear-BclyBoiT.js} +1 -1
  53. package/app/out/renderer/assets/{mindmap-definition-8da855dc-D3zWs3h1.js → mindmap-definition-8da855dc-un1bPKBj.js} +3 -3
  54. package/app/out/renderer/assets/{pieDiagram-a8764435-DDoNhSgQ.js → pieDiagram-a8764435-B7KM3duv.js} +3 -3
  55. package/app/out/renderer/assets/{quadrantDiagram-1e28029f-ZO85SsRM.js → quadrantDiagram-1e28029f-C8i5m3Os.js} +3 -3
  56. package/app/out/renderer/assets/{requirementDiagram-08caed73-C-vKE6g8.js → requirementDiagram-08caed73-FjqENNN5.js} +5 -5
  57. package/app/out/renderer/assets/{sankeyDiagram-a04cb91d-Cbqb2K-X.js → sankeyDiagram-a04cb91d-BKV22yuJ.js} +2 -2
  58. package/app/out/renderer/assets/{sequenceDiagram-c5b8d532-BK4uvpEA.js → sequenceDiagram-c5b8d532-DWO-Z2i3.js} +3 -3
  59. package/app/out/renderer/assets/{stateDiagram-1ecb1508-DXa_YqNi.js → stateDiagram-1ecb1508-BqohgALA.js} +6 -6
  60. package/app/out/renderer/assets/{stateDiagram-v2-c2b004d7-Dm203Z8l.js → stateDiagram-v2-c2b004d7-B3sEkrB8.js} +10 -10
  61. package/app/out/renderer/assets/{styles-b4e223ce-BV4b1eAh.js → styles-b4e223ce-BGytHk8n.js} +1 -1
  62. package/app/out/renderer/assets/{styles-ca3715f6-CKhYSe7r.js → styles-ca3715f6-B0PvBknL.js} +1 -1
  63. package/app/out/renderer/assets/{styles-d45a18b0-DTCMfE-4.js → styles-d45a18b0-C6F384ai.js} +4 -4
  64. package/app/out/renderer/assets/{svgDrawCommon-b86b1483-DK4i-dfJ.js → svgDrawCommon-b86b1483-BXgThwM_.js} +1 -1
  65. package/app/out/renderer/assets/{timeline-definition-faaaa080-CE2LmuDH.js → timeline-definition-faaaa080-iNn5igPR.js} +3 -3
  66. package/app/out/renderer/assets/{xychartDiagram-f5964ef8-Bd8KT9X9.js → xychartDiagram-f5964ef8-oF_gxlk1.js} +5 -5
  67. package/app/out/renderer/index.html +2 -2
  68. package/package.json +1 -1
@@ -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-Bj7JSjF5.js","./MilkdownMarkdownEditor-CCdZ2mtg.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,18 @@ 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
+ ]);
12953
12996
  /**
12954
12997
  * @license lucide-react v0.469.0 - ISC
12955
12998
  *
@@ -12989,6 +13032,17 @@ const Lightbulb = createLucideIcon("Lightbulb", [
12989
13032
  ["path", { d: "M9 18h6", key: "x1upvd" }],
12990
13033
  ["path", { d: "M10 22h4", key: "ceow96" }]
12991
13034
  ]);
13035
+ /**
13036
+ * @license lucide-react v0.469.0 - ISC
13037
+ *
13038
+ * This source code is licensed under the ISC license.
13039
+ * See the LICENSE file in the root directory of this source tree.
13040
+ */
13041
+ const Link2 = createLucideIcon("Link2", [
13042
+ ["path", { d: "M9 17H7A5 5 0 0 1 7 7h2", key: "8i5ue5" }],
13043
+ ["path", { d: "M15 7h2a5 5 0 1 1 0 10h-2", key: "1b9ql8" }],
13044
+ ["line", { x1: "8", x2: "16", y1: "12", y2: "12", key: "1jonct" }]
13045
+ ]);
12992
13046
  /**
12993
13047
  * @license lucide-react v0.469.0 - ISC
12994
13048
  *
@@ -13104,6 +13158,17 @@ const Plus = createLucideIcon("Plus", [
13104
13158
  ["path", { d: "M5 12h14", key: "1ays0h" }],
13105
13159
  ["path", { d: "M12 5v14", key: "s699le" }]
13106
13160
  ]);
13161
+ /**
13162
+ * @license lucide-react v0.469.0 - ISC
13163
+ *
13164
+ * This source code is licensed under the ISC license.
13165
+ * See the LICENSE file in the root directory of this source tree.
13166
+ */
13167
+ const Presentation = createLucideIcon("Presentation", [
13168
+ ["path", { d: "M2 3h20", key: "91anmk" }],
13169
+ ["path", { d: "M21 3v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V3", key: "2k9sn8" }],
13170
+ ["path", { d: "m7 21 5-5 5 5", key: "bip4we" }]
13171
+ ]);
13107
13172
  /**
13108
13173
  * @license lucide-react v0.469.0 - ISC
13109
13174
  *
@@ -14126,7 +14191,7 @@ function SettingsModal({ open, onClose, initialTab }) {
14126
14191
  )
14127
14192
  ] }),
14128
14193
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 overflow-y-auto px-6 pb-4", children: [
14129
- activeTab === "api-keys" && /* @__PURE__ */ jsxRuntimeExports.jsx(ApiKeysSettings, {}),
14194
+ activeTab === "api-keys" && /* @__PURE__ */ jsxRuntimeExports.jsx(ApiKeysSettings, { showSaveButton: true }),
14130
14195
  activeTab === "research" && loaded && /* @__PURE__ */ jsxRuntimeExports.jsx(
14131
14196
  ResearchSettings,
14132
14197
  {
@@ -14235,6 +14300,21 @@ function bootTheme() {
14235
14300
  applyThemeClass(theme);
14236
14301
  return theme;
14237
14302
  }
14303
+ const DRAWER_WIDTH_MIN = 360;
14304
+ const DRAWER_WIDTH_MAX = 720;
14305
+ const DRAWER_WIDTH_DEFAULT = 540;
14306
+ const clampDrawerWidth = (px) => Math.max(DRAWER_WIDTH_MIN, Math.min(DRAWER_WIDTH_MAX, Math.round(px)));
14307
+ const LEFT_WIDTH_MIN = 260;
14308
+ const LEFT_WIDTH_MAX = 480;
14309
+ const LEFT_WIDTH_DEFAULT = 320;
14310
+ const LEFT_WIDTH_KEY = "ui.leftSidebarWidth";
14311
+ const clampLeftWidth = (px) => Math.max(LEFT_WIDTH_MIN, Math.min(LEFT_WIDTH_MAX, Math.round(px)));
14312
+ const readLeftWidth = () => {
14313
+ if (typeof window === "undefined") return LEFT_WIDTH_DEFAULT;
14314
+ const raw = window.localStorage?.getItem(LEFT_WIDTH_KEY);
14315
+ const n = raw ? Number.parseInt(raw, 10) : NaN;
14316
+ return Number.isFinite(n) ? clampLeftWidth(n) : LEFT_WIDTH_DEFAULT;
14317
+ };
14238
14318
  const useUIStore = create$1((set) => ({
14239
14319
  // Theme hydrates from localStorage (or OS preference) at module init so
14240
14320
  // the zustand state matches the <html> class applied by bootTheme() in
@@ -14253,6 +14333,8 @@ const useUIStore = create$1((set) => ({
14253
14333
  previewEntity: null,
14254
14334
  previewSourceTab: null,
14255
14335
  previewEditorFocused: false,
14336
+ drawerWidth: DRAWER_WIDTH_DEFAULT,
14337
+ leftSidebarWidth: readLeftWidth(),
14256
14338
  literatureFilter: {
14257
14339
  search: "",
14258
14340
  subTopic: null,
@@ -14348,13 +14430,33 @@ const useUIStore = create$1((set) => ({
14348
14430
  previewEntity: null,
14349
14431
  previewSourceTab: null,
14350
14432
  previewEditorFocused: false,
14433
+ drawerWidth: DRAWER_WIDTH_DEFAULT,
14434
+ leftSidebarWidth: readLeftWidth(),
14351
14435
  literatureFilter: { search: "", subTopic: null, sortBy: "year", sortDir: "desc", minScore: 0, source: null, round: null },
14352
14436
  wikiReaderSlug: null,
14353
14437
  wikiReaderHistory: []
14354
14438
  }),
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 })
14439
+ // Opening a preview routes the user to chat view the drawer is mounted
14440
+ // inside the chat-body host, so it only renders there. Researchers expect
14441
+ // clicking a file to show them the file; forcing the view switch is the
14442
+ // honest implementation of that expectation.
14443
+ openPreview: (entity) => set((s15) => ({
14444
+ previewEntity: entity,
14445
+ previewSourceTab: s15.leftTab,
14446
+ previewEditorFocused: false,
14447
+ centerView: "chat"
14448
+ })),
14449
+ closePreview: () => set({ previewEntity: null, previewSourceTab: null, previewEditorFocused: false }),
14450
+ setPreviewEditorFocused: (previewEditorFocused) => set({ previewEditorFocused }),
14451
+ setDrawerWidth: (drawerWidth) => set({ drawerWidth: clampDrawerWidth(drawerWidth) }),
14452
+ setLeftSidebarWidth: (width) => {
14453
+ const clamped = clampLeftWidth(width);
14454
+ set({ leftSidebarWidth: clamped });
14455
+ try {
14456
+ window.localStorage?.setItem(LEFT_WIDTH_KEY, String(clamped));
14457
+ } catch {
14458
+ }
14459
+ }
14358
14460
  }));
14359
14461
  async function hydratePreferences() {
14360
14462
  const api2 = window.api;
@@ -27578,6 +27680,8 @@ function WorkspaceTree() {
27578
27680
  const { projectPath } = useSessionStore();
27579
27681
  const openPreview = useUIStore((s15) => s15.openPreview);
27580
27682
  const previewEntity = useUIStore((s15) => s15.previewEntity);
27683
+ const leftTab = useUIStore((s15) => s15.leftTab);
27684
+ const centerView = useUIStore((s15) => s15.centerView);
27581
27685
  const data = useEntityStore((s15) => s15.data);
27582
27686
  const refreshEntities = useEntityStore((s15) => s15.refreshAll);
27583
27687
  const [query, setQuery] = reactExports.useState("");
@@ -27599,6 +27703,7 @@ function WorkspaceTree() {
27599
27703
  const [dropTargetPath, setDropTargetPath] = reactExports.useState(null);
27600
27704
  const [confirmTrashPath, setConfirmTrashPath] = reactExports.useState(null);
27601
27705
  const [contextMenu, setContextMenu] = reactExports.useState(null);
27706
+ const [clipboardNode, setClipboardNode] = reactExports.useState(null);
27602
27707
  const [renaming, setRenaming] = reactExports.useState(null);
27603
27708
  const [renameValue, setRenameValue] = reactExports.useState("");
27604
27709
  const [creating, setCreating] = reactExports.useState(null);
@@ -27613,6 +27718,9 @@ function WorkspaceTree() {
27613
27718
  window.addEventListener("click", handleClick);
27614
27719
  return () => window.removeEventListener("click", handleClick);
27615
27720
  }, [contextMenu]);
27721
+ reactExports.useEffect(() => {
27722
+ setContextMenu(null);
27723
+ }, [leftTab, centerView]);
27616
27724
  reactExports.useEffect(() => {
27617
27725
  if (renaming && renameInputRef.current) {
27618
27726
  renameInputRef.current.focus();
@@ -27795,6 +27903,35 @@ function WorkspaceTree() {
27795
27903
  if (node2.type === "directory") return node2.relativePath;
27796
27904
  return node2.relativePath.includes("/") ? node2.relativePath.slice(0, node2.relativePath.lastIndexOf("/")) : "";
27797
27905
  }, []);
27906
+ const handleRevealInFinder = reactExports.useCallback((node2) => {
27907
+ void api$9.revealInFinder(node2.path);
27908
+ setContextMenu(null);
27909
+ }, []);
27910
+ const handleOpenInDefaultApp = reactExports.useCallback((node2) => {
27911
+ void api$9.openFile(node2.path);
27912
+ setContextMenu(null);
27913
+ }, []);
27914
+ const handleCopyFile = reactExports.useCallback((node2) => {
27915
+ setClipboardNode(node2);
27916
+ setContextMenu(null);
27917
+ }, []);
27918
+ const handlePasteFile = reactExports.useCallback(async (targetNode) => {
27919
+ if (!clipboardNode) return;
27920
+ const destDir = targetNode.type === "directory" ? targetNode.relativePath : getParentDir(targetNode);
27921
+ setContextMenu(null);
27922
+ const result = await api$9.copyItem(clipboardNode.relativePath, destDir);
27923
+ if (result.success) {
27924
+ await loadChildren(destDir);
27925
+ }
27926
+ }, [clipboardNode, getParentDir, loadChildren]);
27927
+ const handleCopyPath = reactExports.useCallback((node2) => {
27928
+ void navigator.clipboard.writeText(node2.path);
27929
+ setContextMenu(null);
27930
+ }, []);
27931
+ const handleCopyRelativePath = reactExports.useCallback((node2) => {
27932
+ void navigator.clipboard.writeText(node2.relativePath);
27933
+ setContextMenu(null);
27934
+ }, []);
27798
27935
  const handleNewFile = reactExports.useCallback((parentRelPath) => {
27799
27936
  setCreating({ parentDir: parentRelPath, type: "file" });
27800
27937
  setCreateValue("");
@@ -28057,7 +28194,7 @@ function WorkspaceTree() {
28057
28194
  onClick: (e) => e.stopPropagation(),
28058
28195
  className: "flex-1 bg-transparent outline-none t-focus-ring border-b border-[var(--color-accent-soft)] text-xs t-text"
28059
28196
  }
28060
- ) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate flex-1", children: node2.name }),
28197
+ ) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate flex-1", title: node2.name, children: node2.name }),
28061
28198
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "hidden group-hover:flex items-center gap-0.5", children: [
28062
28199
  node2.type === "file" && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
28063
28200
  /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -28168,6 +28305,7 @@ function WorkspaceTree() {
28168
28305
  {
28169
28306
  ref: viewportRef,
28170
28307
  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" : ""}`,
28308
+ style: { overflowAnchor: "none" },
28171
28309
  onScroll: (e) => setScrollTop(e.currentTarget.scrollTop),
28172
28310
  onDragOver: handleViewportDragOver,
28173
28311
  onDragLeave: handleViewportDragLeave,
@@ -28181,16 +28319,16 @@ function WorkspaceTree() {
28181
28319
  '".'
28182
28320
  ] }) : !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
28321
  creating && creating.parentDir === "" && renderCreateInput(0),
28184
- topSpacerHeight > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { height: `${topSpacerHeight}px` } }),
28322
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { height: `${topSpacerHeight}px` } }),
28185
28323
  visibleRows.map((row) => renderVisibleRow(row)),
28186
- bottomSpacerHeight > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { height: `${bottomSpacerHeight}px` } })
28324
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { height: `${bottomSpacerHeight}px` } })
28187
28325
  ] })
28188
28326
  }
28189
28327
  ),
28190
28328
  contextMenu && /* @__PURE__ */ jsxRuntimeExports.jsxs(
28191
28329
  "div",
28192
28330
  {
28193
- className: "fixed z-50 min-w-[160px] rounded-lg border t-border t-bg-surface shadow-xl py-1",
28331
+ className: "fixed z-50 min-w-[180px] rounded-lg border t-border t-bg-surface shadow-xl py-1",
28194
28332
  style: { left: contextMenu.x, top: contextMenu.y },
28195
28333
  onClick: (e) => e.stopPropagation(),
28196
28334
  children: [
@@ -28208,6 +28346,75 @@ function WorkspaceTree() {
28208
28346
  ]
28209
28347
  }
28210
28348
  ),
28349
+ contextMenu.node.type === "file" && /* @__PURE__ */ jsxRuntimeExports.jsxs(
28350
+ "button",
28351
+ {
28352
+ className: "w-full text-left px-3 py-1.5 text-xs t-text-secondary hover:t-bg-hover flex items-center gap-2",
28353
+ onClick: () => handleOpenInDefaultApp(contextMenu.node),
28354
+ children: [
28355
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ExternalLink, { size: 11 }),
28356
+ " Open in Default App"
28357
+ ]
28358
+ }
28359
+ ),
28360
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
28361
+ "button",
28362
+ {
28363
+ className: "w-full text-left px-3 py-1.5 text-xs t-text-secondary hover:t-bg-hover flex items-center gap-2",
28364
+ onClick: () => handleRevealInFinder(contextMenu.node),
28365
+ children: [
28366
+ /* @__PURE__ */ jsxRuntimeExports.jsx(FolderOpen, { size: 11 }),
28367
+ " Reveal in Finder"
28368
+ ]
28369
+ }
28370
+ ),
28371
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "border-t t-border my-1" }),
28372
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
28373
+ "button",
28374
+ {
28375
+ className: "w-full text-left px-3 py-1.5 text-xs t-text-secondary hover:t-bg-hover flex items-center gap-2",
28376
+ onClick: () => handleCopyFile(contextMenu.node),
28377
+ children: [
28378
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { size: 11 }),
28379
+ " Copy"
28380
+ ]
28381
+ }
28382
+ ),
28383
+ clipboardNode && /* @__PURE__ */ jsxRuntimeExports.jsxs(
28384
+ "button",
28385
+ {
28386
+ className: "w-full text-left px-3 py-1.5 text-xs t-text-secondary hover:t-bg-hover flex items-center gap-2",
28387
+ onClick: () => void handlePasteFile(contextMenu.node),
28388
+ children: [
28389
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ClipboardPaste, { size: 11 }),
28390
+ " Paste"
28391
+ ]
28392
+ }
28393
+ ),
28394
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "border-t t-border my-1" }),
28395
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
28396
+ "button",
28397
+ {
28398
+ className: "w-full text-left px-3 py-1.5 text-xs t-text-secondary hover:t-bg-hover flex items-center gap-2",
28399
+ onClick: () => handleCopyPath(contextMenu.node),
28400
+ children: [
28401
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Hash, { size: 11 }),
28402
+ " Copy Path"
28403
+ ]
28404
+ }
28405
+ ),
28406
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
28407
+ "button",
28408
+ {
28409
+ className: "w-full text-left px-3 py-1.5 text-xs t-text-secondary hover:t-bg-hover flex items-center gap-2",
28410
+ onClick: () => handleCopyRelativePath(contextMenu.node),
28411
+ children: [
28412
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Link2, { size: 11 }),
28413
+ " Copy Relative Path"
28414
+ ]
28415
+ }
28416
+ ),
28417
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "border-t t-border my-1" }),
28211
28418
  /* @__PURE__ */ jsxRuntimeExports.jsxs(
28212
28419
  "button",
28213
28420
  {
@@ -28318,7 +28525,7 @@ const useSkillStore = create$1((set, get) => ({
28318
28525
  return result;
28319
28526
  }
28320
28527
  }));
28321
- const remarkPlugins$3 = [remarkGfm];
28528
+ const remarkPlugins$4 = [remarkGfm];
28322
28529
  function HoverPreview({
28323
28530
  entity,
28324
28531
  anchorRect,
@@ -28360,7 +28567,7 @@ function HoverPreview({
28360
28567
  }
28361
28568
  ) })
28362
28569
  ] }),
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 }) }) })
28570
+ 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
28571
  ]
28365
28572
  }
28366
28573
  );
@@ -28447,7 +28654,7 @@ const EntityRow = React$2.memo(function EntityRow2({ entity }) {
28447
28654
  }
28448
28655
  ),
28449
28656
  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 })
28657
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs t-text truncate", title: entity.title, children: entity.title })
28451
28658
  ]
28452
28659
  }
28453
28660
  ),
@@ -28508,10 +28715,18 @@ function DataTreeView({ items }) {
28508
28715
  }
28509
28716
  ),
28510
28717
  /* @__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
- ] })
28718
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
28719
+ "span",
28720
+ {
28721
+ className: "text-xs t-text truncate",
28722
+ title: `Analysis: ${label}`,
28723
+ onClick: () => openPreview(children[0]),
28724
+ children: [
28725
+ "Analysis: ",
28726
+ label
28727
+ ]
28728
+ }
28729
+ )
28515
28730
  ] }),
28516
28731
  isOpen && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "pl-4", children: children.map((e) => /* @__PURE__ */ jsxRuntimeExports.jsx(EntityRow, { entity: e }, e.id)) })
28517
28732
  ] }, runId);
@@ -28720,7 +28935,7 @@ function SkillsContent() {
28720
28935
  ),
28721
28936
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0 flex-1", children: [
28722
28937
  /* @__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 }),
28938
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs t-text font-medium truncate", title: skill.name, children: skill.name }),
28724
28939
  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
28940
  ] }),
28726
28941
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] t-text-muted leading-tight line-clamp-2 mt-0.5", children: skill.description }),
@@ -28764,18 +28979,6 @@ function EntityTabs() {
28764
28979
  reactExports.useEffect(() => {
28765
28980
  refreshAll();
28766
28981
  }, []);
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
28982
  const handleTabKeyDown = (e) => {
28780
28983
  const tabKeys = tabs.map((t) => t.key);
28781
28984
  const idx = tabKeys.indexOf(leftTab);
@@ -28809,16 +29012,44 @@ function EntityTabs() {
28809
29012
  },
28810
29013
  key
28811
29014
  )) }),
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
- )
29015
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 min-h-0 overflow-hidden", children: [
29016
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
29017
+ "div",
29018
+ {
29019
+ role: "tabpanel",
29020
+ id: "tabpanel-library",
29021
+ "aria-labelledby": "tab-library",
29022
+ className: `h-full flex flex-col min-h-0 ${leftTab === "library" ? "" : "hidden"}`,
29023
+ "aria-hidden": leftTab !== "library",
29024
+ inert: leftTab !== "library",
29025
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(LibraryContent, { notes, data, refreshAll })
29026
+ }
29027
+ ),
29028
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
29029
+ "div",
29030
+ {
29031
+ role: "tabpanel",
29032
+ id: "tabpanel-files",
29033
+ "aria-labelledby": "tab-files",
29034
+ className: `h-full flex flex-col min-h-0 ${leftTab === "files" ? "" : "hidden"}`,
29035
+ "aria-hidden": leftTab !== "files",
29036
+ inert: leftTab !== "files",
29037
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(WorkspaceTree, {})
29038
+ }
29039
+ ),
29040
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
29041
+ "div",
29042
+ {
29043
+ role: "tabpanel",
29044
+ id: "tabpanel-skills",
29045
+ "aria-labelledby": "tab-skills",
29046
+ className: `h-full flex flex-col min-h-0 ${leftTab === "skills" ? "" : "hidden"}`,
29047
+ "aria-hidden": leftTab !== "skills",
29048
+ inert: leftTab !== "skills",
29049
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(SkillsContent, {})
29050
+ }
29051
+ )
29052
+ ] })
28822
29053
  ] });
28823
29054
  }
28824
29055
  const api$8 = window.api;
@@ -28899,7 +29130,7 @@ function GapAlerts({ papers }) {
28899
29130
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] t-text-muted uppercase tracking-wider font-medium", children: "Coverage Gaps" }),
28900
29131
  gaps.map((topic) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5 px-1", children: [
28901
29132
  /* @__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 })
29133
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[11px] t-text-secondary truncate", title: topic, children: topic })
28903
29134
  ] }, topic))
28904
29135
  ] });
28905
29136
  }
@@ -29167,6 +29398,7 @@ function UserProfile() {
29167
29398
  "button",
29168
29399
  {
29169
29400
  onClick: handlePickFolder,
29401
+ title: displayPath,
29170
29402
  className: "no-drag flex items-center gap-2 w-full text-left text-sm t-text-secondary hover:t-text transition-colors",
29171
29403
  children: [
29172
29404
  /* @__PURE__ */ jsxRuntimeExports.jsx(Folder, { size: 16, className: "shrink-0" }),
@@ -29711,12 +29943,13 @@ function ReasoningToggle() {
29711
29943
  }
29712
29944
  );
29713
29945
  }
29714
- function ToolbarButton({ onClick, tooltip, children }) {
29946
+ function ToolbarButton({ onClick, tooltip, children, ariaExpanded }) {
29715
29947
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(
29716
29948
  "button",
29717
29949
  {
29718
29950
  onClick,
29719
29951
  "aria-label": tooltip,
29952
+ "aria-expanded": ariaExpanded,
29720
29953
  className: "no-drag group relative p-2.5 rounded-lg t-text-muted t-bg-hover transition-colors",
29721
29954
  children: [
29722
29955
  children,
@@ -29733,10 +29966,99 @@ function ToolbarButton({ onClick, tooltip, children }) {
29733
29966
  }
29734
29967
  );
29735
29968
  }
29969
+ function OverflowMenu({
29970
+ theme,
29971
+ onToggleTheme,
29972
+ onResetContext,
29973
+ onToggleTerminal
29974
+ }) {
29975
+ const [open, setOpen] = React$2.useState(false);
29976
+ const ref = reactExports.useRef(null);
29977
+ reactExports.useEffect(() => {
29978
+ if (!open) return;
29979
+ const handler = (e) => {
29980
+ if (!ref.current?.contains(e.target)) setOpen(false);
29981
+ };
29982
+ const escHandler = (e) => {
29983
+ if (e.key === "Escape") setOpen(false);
29984
+ };
29985
+ document.addEventListener("mousedown", handler);
29986
+ document.addEventListener("keydown", escHandler);
29987
+ return () => {
29988
+ document.removeEventListener("mousedown", handler);
29989
+ document.removeEventListener("keydown", escHandler);
29990
+ };
29991
+ }, [open]);
29992
+ const run = (fn2) => () => {
29993
+ fn2();
29994
+ setOpen(false);
29995
+ };
29996
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { ref, className: "relative", children: [
29997
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
29998
+ ToolbarButton,
29999
+ {
30000
+ onClick: () => setOpen((v3) => !v3),
30001
+ tooltip: "More",
30002
+ ariaExpanded: open,
30003
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(Ellipsis, { size: 16 })
30004
+ }
30005
+ ),
30006
+ open && /* @__PURE__ */ jsxRuntimeExports.jsxs(
30007
+ "div",
30008
+ {
30009
+ role: "menu",
30010
+ 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",
30011
+ children: [
30012
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
30013
+ "button",
30014
+ {
30015
+ role: "menuitem",
30016
+ onClick: run(onResetContext),
30017
+ className: "w-full flex items-center gap-2 px-3 py-1.5 text-xs t-text t-bg-hover transition-colors",
30018
+ children: [
30019
+ /* @__PURE__ */ jsxRuntimeExports.jsx(RotateCcw, { size: 14, className: "t-text-muted" }),
30020
+ "Reset AI context"
30021
+ ]
30022
+ }
30023
+ ),
30024
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
30025
+ "button",
30026
+ {
30027
+ role: "menuitem",
30028
+ onClick: run(onToggleTheme),
30029
+ className: "w-full flex items-center gap-2 px-3 py-1.5 text-xs t-text t-bg-hover transition-colors",
30030
+ children: [
30031
+ theme === "dark" ? /* @__PURE__ */ jsxRuntimeExports.jsx(Sun, { size: 14, className: "t-text-muted" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Moon, { size: 14, className: "t-text-muted" }),
30032
+ theme === "dark" ? "Light mode" : "Dark mode"
30033
+ ]
30034
+ }
30035
+ ),
30036
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
30037
+ "button",
30038
+ {
30039
+ role: "menuitem",
30040
+ onClick: run(onToggleTerminal),
30041
+ className: "w-full flex items-center justify-between gap-2 px-3 py-1.5 text-xs t-text t-bg-hover transition-colors",
30042
+ children: [
30043
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-2", children: [
30044
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Terminal, { size: 14, className: "t-text-muted" }),
30045
+ "Terminal"
30046
+ ] }),
30047
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-muted font-mono text-[10px]", children: "⌘`" })
30048
+ ]
30049
+ }
30050
+ )
30051
+ ]
30052
+ }
30053
+ )
30054
+ ] });
30055
+ }
29736
30056
  function LeftSidebar({ onOpenSettings }) {
29737
30057
  const theme = useUIStore((s15) => s15.theme);
29738
30058
  const toggleTheme = useUIStore((s15) => s15.toggleTheme);
29739
30059
  const centerView = useUIStore((s15) => s15.centerView);
30060
+ const leftSidebarWidth = useUIStore((s15) => s15.leftSidebarWidth);
30061
+ const setLeftSidebarWidth = useUIStore((s15) => s15.setLeftSidebarWidth);
29740
30062
  const noContextShownRef = reactExports.useRef(false);
29741
30063
  const handleResetContext = reactExports.useCallback(async () => {
29742
30064
  const messages = useChatStore.getState().messages;
@@ -29760,49 +30082,84 @@ function LeftSidebar({ onOpenSettings }) {
29760
30082
  useChatStore.getState().insertContextReset();
29761
30083
  noContextShownRef.current = false;
29762
30084
  }, []);
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
- ] })
30085
+ const dragStateRef = reactExports.useRef(null);
30086
+ const handleEdgeMouseDown = reactExports.useCallback((e) => {
30087
+ dragStateRef.current = { startX: e.clientX, startWidth: leftSidebarWidth };
30088
+ document.body.style.cursor = "ew-resize";
30089
+ e.preventDefault();
30090
+ }, [leftSidebarWidth]);
30091
+ reactExports.useEffect(() => {
30092
+ const onMove = (e) => {
30093
+ if (!dragStateRef.current) return;
30094
+ const dx = e.clientX - dragStateRef.current.startX;
30095
+ setLeftSidebarWidth(dragStateRef.current.startWidth + dx);
30096
+ };
30097
+ const onUp = () => {
30098
+ if (dragStateRef.current) document.body.style.cursor = "";
30099
+ dragStateRef.current = null;
30100
+ };
30101
+ window.addEventListener("mousemove", onMove);
30102
+ window.addEventListener("mouseup", onUp);
30103
+ return () => {
30104
+ window.removeEventListener("mousemove", onMove);
30105
+ window.removeEventListener("mouseup", onUp);
30106
+ };
30107
+ }, [setLeftSidebarWidth]);
30108
+ const handleEdgeDoubleClick = reactExports.useCallback(() => {
30109
+ setLeftSidebarWidth(320);
30110
+ }, [setLeftSidebarWidth]);
30111
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
30112
+ "aside",
30113
+ {
30114
+ className: "relative flex flex-col border-r t-border t-bg-base pt-10 shrink-0",
30115
+ style: { width: `${leftSidebarWidth}px` },
30116
+ children: [
30117
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("nav", { "aria-label": "Sidebar tools", className: "px-4 pb-3 flex items-center justify-between gap-2", children: [
30118
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ModelSelector, {}),
30119
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1", children: [
30120
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ReasoningToggle, {}),
30121
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
30122
+ OverflowMenu,
30123
+ {
30124
+ theme,
30125
+ onToggleTheme: toggleTheme,
30126
+ onResetContext: handleResetContext,
30127
+ onToggleTerminal: () => useUIStore.getState().toggleTerminal()
30128
+ }
30129
+ )
30130
+ ] })
30131
+ ] }),
30132
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-h-0 overflow-hidden", children: (() => {
30133
+ const computeEnabled2 = !!window.api?.isComputeEnabled?.();
30134
+ const showLit = centerView === "literature";
30135
+ const showCompute = centerView === "compute" && computeEnabled2;
30136
+ const showEntity = !showLit && !showCompute;
30137
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
30138
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `h-full ${showLit ? "" : "hidden"}`, "aria-hidden": !showLit, inert: !showLit, children: /* @__PURE__ */ jsxRuntimeExports.jsx(LiteratureSidebar, {}) }),
30139
+ computeEnabled2 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `h-full ${showCompute ? "" : "hidden"}`, "aria-hidden": !showCompute, inert: !showCompute, children: /* @__PURE__ */ jsxRuntimeExports.jsx(ComputeSidebar, {}) }),
30140
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `h-full ${showEntity ? "" : "hidden"}`, "aria-hidden": !showEntity, inert: !showEntity, children: /* @__PURE__ */ jsxRuntimeExports.jsx(EntityTabs, {}) })
30141
+ ] });
30142
+ })() }),
30143
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-t t-border p-4 flex items-center justify-between", children: [
30144
+ /* @__PURE__ */ jsxRuntimeExports.jsx(UserProfile, {}),
30145
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ToolbarButton, { onClick: onOpenSettings, tooltip: "Settings ⌘,", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Settings, { size: 16 }) })
30146
+ ] }),
30147
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
30148
+ "div",
30149
+ {
30150
+ role: "separator",
30151
+ "aria-orientation": "vertical",
30152
+ "aria-label": "Resize sidebar (drag to resize, double-click to reset)",
30153
+ tabIndex: -1,
30154
+ className: "absolute right-0 top-0 bottom-0 w-[6px] cursor-ew-resize group z-[6]",
30155
+ style: { marginRight: -3 },
30156
+ onMouseDown: handleEdgeMouseDown,
30157
+ onDoubleClick: handleEdgeDoubleClick,
30158
+ 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" })
30159
+ }
30160
+ )
30161
+ ]
30162
+ }
29806
30163
  );
29807
30164
  }
29808
30165
  const STARTERS = [
@@ -30502,8 +30859,53 @@ function ToolUseStream({ events: propEvents }) {
30502
30859
  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
30860
  ] });
30504
30861
  }
30862
+ function ImageLightbox({ src, onClose }) {
30863
+ reactExports.useEffect(() => {
30864
+ const onKey = (e) => {
30865
+ if (e.key === "Escape") onClose();
30866
+ };
30867
+ document.addEventListener("keydown", onKey);
30868
+ const prevOverflow = document.body.style.overflow;
30869
+ document.body.style.overflow = "hidden";
30870
+ return () => {
30871
+ document.removeEventListener("keydown", onKey);
30872
+ document.body.style.overflow = prevOverflow;
30873
+ };
30874
+ }, [onClose]);
30875
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
30876
+ "div",
30877
+ {
30878
+ role: "dialog",
30879
+ "aria-modal": "true",
30880
+ "aria-label": "Image preview",
30881
+ onClick: onClose,
30882
+ className: "fixed inset-0 z-[100] flex items-center justify-center p-8",
30883
+ style: { background: "rgba(0,0,0,0.82)" },
30884
+ children: [
30885
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
30886
+ "img",
30887
+ {
30888
+ src,
30889
+ alt: "",
30890
+ onClick: (e) => e.stopPropagation(),
30891
+ className: "max-w-full max-h-full object-contain rounded-lg shadow-2xl"
30892
+ }
30893
+ ),
30894
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
30895
+ "button",
30896
+ {
30897
+ onClick: onClose,
30898
+ "aria-label": "Close preview",
30899
+ className: "absolute top-4 right-4 p-2 rounded-full text-white/80 hover:text-white hover:bg-white/10 transition-colors",
30900
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(X$1, { size: 22 })
30901
+ }
30902
+ )
30903
+ ]
30904
+ }
30905
+ );
30906
+ }
30505
30907
  const api$7 = window.api;
30506
- const remarkPlugins$2 = [remarkGfm];
30908
+ const remarkPlugins$3 = [remarkGfm];
30507
30909
  function formatMessageTime(ts2) {
30508
30910
  const d = new Date(ts2);
30509
30911
  const now2 = /* @__PURE__ */ new Date();
@@ -30663,59 +31065,63 @@ const MessageBubble = React$2.memo(function MessageBubble2({ msg, isSaved }) {
30663
31065
  }
30664
31066
  };
30665
31067
  const [copied, setCopied] = reactExports.useState(false);
31068
+ const [lightboxSrc, setLightboxSrc] = reactExports.useState(null);
30666
31069
  const handleCopy = async () => {
30667
31070
  await navigator.clipboard.writeText(msg.content);
30668
31071
  setCopied(true);
30669
31072
  setTimeout(() => setCopied(false), 1500);
30670
31073
  };
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",
31074
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `flex ${isUser ? "justify-end" : "justify-start"} group`, children: [
31075
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
31076
+ "div",
31077
+ {
31078
+ 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)]" : ""}`,
31079
+ style: {
31080
+ background: isUser ? "var(--color-bubble-user)" : "var(--color-bubble-assistant)"
31081
+ },
31082
+ "data-msg-id": msg.id,
31083
+ children: [
31084
+ 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(
31085
+ "img",
30707
31086
  {
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
- ) });
31087
+ src,
31088
+ alt: "",
31089
+ loading: "lazy",
31090
+ className: `rounded-lg border t-border cursor-pointer hover:opacity-90 transition-opacity ${isUser ? "max-h-48" : "max-h-80"}`,
31091
+ onClick: () => setLightboxSrc(src)
31092
+ },
31093
+ i
31094
+ )) }),
31095
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "md-prose", style: { color: "var(--color-text)" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Markdown, { remarkPlugins: remarkPlugins$3, children: msg.content }) }),
31096
+ 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) }),
31097
+ !isUser && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "absolute -right-8 top-2 flex flex-col gap-1.5", children: [
31098
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
31099
+ "button",
31100
+ {
31101
+ onClick: handleSaveNote,
31102
+ disabled: saveState !== "idle",
31103
+ 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"}`,
31104
+ title: saveState === "saved" ? "Saved as note" : "Save entire message as note",
31105
+ "aria-label": saveState === "saved" ? "Message saved as note" : "Save entire message as note",
31106
+ 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 })
31107
+ }
31108
+ ),
31109
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
31110
+ "button",
31111
+ {
31112
+ onClick: handleCopy,
31113
+ className: `transition-opacity ${copied ? "opacity-100 t-text-success" : "opacity-0 group-hover:opacity-100 t-text-muted hover:t-text-accent-soft"}`,
31114
+ title: copied ? "Copied!" : "Copy message",
31115
+ "aria-label": copied ? "Message copied" : "Copy message to clipboard",
31116
+ children: copied ? /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { size: 14 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { size: 14 })
31117
+ }
31118
+ )
31119
+ ] })
31120
+ ]
31121
+ }
31122
+ ),
31123
+ lightboxSrc && /* @__PURE__ */ jsxRuntimeExports.jsx(ImageLightbox, { src: lightboxSrc, onClose: () => setLightboxSrc(null) })
31124
+ ] });
30719
31125
  });
30720
31126
  function ThinkingIndicator() {
30721
31127
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(
@@ -30740,7 +31146,7 @@ function StreamingBubble() {
30740
31146
  className: "max-w-[90%] rounded-2xl px-4 py-3 text-sm t-text assistant-bubble",
30741
31147
  style: { background: "var(--color-bubble-assistant)" },
30742
31148
  children: [
30743
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "md-prose", style: { color: "var(--color-text)" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Markdown, { remarkPlugins: remarkPlugins$2, children: text2 }) }),
31149
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "md-prose", style: { color: "var(--color-text)" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Markdown, { remarkPlugins: remarkPlugins$3, children: text2 }) }),
30744
31150
  /* @__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
31151
  ]
30746
31152
  }
@@ -31349,6 +31755,7 @@ function ChatInput() {
31349
31755
  const [pendingImages, setPendingImages] = reactExports.useState([]);
31350
31756
  const [pendingFiles, setPendingFiles] = reactExports.useState([]);
31351
31757
  const [isDragOver, setIsDragOver] = reactExports.useState(false);
31758
+ const [lightboxSrc, setLightboxSrc] = reactExports.useState(null);
31352
31759
  const textareaRef = reactExports.useRef(null);
31353
31760
  const fileInputRef = reactExports.useRef(null);
31354
31761
  const send = useChatStore((s15) => s15.send);
@@ -31366,23 +31773,17 @@ function ChatInput() {
31366
31773
  const addImageFiles = reactExports.useCallback((files) => {
31367
31774
  const imageFiles = files.filter((f) => ACCEPTED_IMAGE_TYPES.includes(f.type));
31368
31775
  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;
31776
+ imageFiles.forEach((file) => {
31777
+ const reader = new FileReader();
31778
+ reader.onload = () => {
31779
+ const dataUrl = reader.result;
31780
+ const base64 = dataUrl.split(",")[1];
31781
+ setPendingImages((p) => {
31782
+ if (p.length >= MAX_IMAGES) return p;
31783
+ return [...p, { base64, mimeType: file.type, dataUrl }];
31784
+ });
31785
+ };
31786
+ reader.readAsDataURL(file);
31386
31787
  });
31387
31788
  }, []);
31388
31789
  const isDocFile = reactExports.useCallback((file) => {
@@ -31744,6 +32145,7 @@ ${s15.openQuestions.map((q2) => `- ${q2}`).join("\n")}`;
31744
32145
  }
31745
32146
  }, [text2]);
31746
32147
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative", children: [
32148
+ lightboxSrc && /* @__PURE__ */ jsxRuntimeExports.jsx(ImageLightbox, { src: lightboxSrc, onClose: () => setLightboxSrc(null) }),
31747
32149
  showMention && /* @__PURE__ */ jsxRuntimeExports.jsx(
31748
32150
  MentionPopover,
31749
32151
  {
@@ -31790,13 +32192,17 @@ ${s15.openQuestions.map((q2) => `- ${q2}`).join("\n")}`;
31790
32192
  {
31791
32193
  src: img.dataUrl,
31792
32194
  alt: "",
31793
- className: "h-16 w-16 object-cover rounded-lg border t-border"
32195
+ onClick: () => setLightboxSrc(img.dataUrl),
32196
+ className: "h-16 w-16 object-cover rounded-lg border t-border cursor-pointer hover:opacity-90 transition-opacity"
31794
32197
  }
31795
32198
  ),
31796
32199
  /* @__PURE__ */ jsxRuntimeExports.jsx(
31797
32200
  "button",
31798
32201
  {
31799
- onClick: () => setPendingImages((prev) => prev.filter((_2, j2) => j2 !== i)),
32202
+ onClick: (e) => {
32203
+ e.stopPropagation();
32204
+ setPendingImages((prev) => prev.filter((_2, j2) => j2 !== i));
32205
+ },
31800
32206
  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
32207
  "aria-label": "Remove image",
31802
32208
  children: "×"
@@ -31879,7 +32285,7 @@ ${s15.openQuestions.map((q2) => `- ${q2}`).join("\n")}`;
31879
32285
  ] });
31880
32286
  }
31881
32287
  const api$4 = window.api;
31882
- const remarkPlugins$1 = [remarkGfm];
32288
+ const remarkPlugins$2 = [remarkGfm];
31883
32289
  function PaperFallback({ paper }) {
31884
32290
  const authors = paper.authors || [];
31885
32291
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [
@@ -32014,7 +32420,7 @@ ${body.trim()}
32014
32420
  }
32015
32421
  )
32016
32422
  ] }),
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." }) })
32423
+ /* @__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
32424
  ] });
32019
32425
  }
32020
32426
  function normalize(raw) {
@@ -32986,95 +33392,136 @@ function ComputeView() {
32986
33392
  !isEmpty && /* @__PURE__ */ jsxRuntimeExports.jsx(CoverageBar, { runs: allRuns })
32987
33393
  ] });
32988
33394
  }
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
- ] });
33395
+ function resolveMarkdownImageUrl(src, baseDir) {
33396
+ if (!src) return "";
33397
+ if (/^(?:https?:|data:|blob:|workspace-asset:|file:)/i.test(src)) return src;
33398
+ let absPath = null;
33399
+ if (src.startsWith("/")) {
33400
+ absPath = src;
33401
+ } else if (baseDir) {
33402
+ try {
33403
+ const normalizedBase = baseDir.endsWith("/") ? baseDir : baseDir + "/";
33404
+ const resolved = new URL(src, `file://${normalizedBase}`);
33405
+ absPath = decodeURIComponent(resolved.pathname);
33406
+ } catch {
33407
+ absPath = null;
33408
+ }
33409
+ }
33410
+ if (!absPath) return src;
33411
+ return `workspace-asset://asset${encodeURI(absPath)}`;
33412
+ }
33413
+ function dirnameOf(filePath) {
33414
+ if (!filePath) return void 0;
33415
+ const normalized = filePath.replace(/\\/g, "/");
33416
+ const idx = normalized.lastIndexOf("/");
33417
+ if (idx < 0) return void 0;
33418
+ return normalized.slice(0, idx);
33419
+ }
33420
+ const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
33421
+ function splitFrontmatter(markdown) {
33422
+ if (!markdown) return { frontmatterBlock: null, body: markdown ?? "" };
33423
+ const match = markdown.match(FRONTMATTER_RE);
33424
+ if (!match) return { frontmatterBlock: null, body: markdown };
33425
+ return { frontmatterBlock: match[0], body: markdown.slice(match[0].length) };
33426
+ }
33427
+ function parseFrontmatterPairs(block) {
33428
+ const out = {};
33429
+ if (!block) return out;
33430
+ const inner = block.match(FRONTMATTER_RE)?.[1] ?? "";
33431
+ for (const rawLine of inner.split("\n")) {
33432
+ const line = rawLine.trim();
33433
+ if (!line || line.startsWith("#")) continue;
33434
+ const colonIdx = line.indexOf(":");
33435
+ if (colonIdx < 0) continue;
33436
+ const key = line.slice(0, colonIdx).trim();
33437
+ if (key) out[key] = line.slice(colonIdx + 1).trim();
33062
33438
  }
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
- ] });
33439
+ return out;
33440
+ }
33441
+ function isMarpFrontmatter(block) {
33442
+ const pairs = parseFrontmatterPairs(block);
33443
+ return /^(?:true|yes|on)$/i.test(pairs.marp || "");
33444
+ }
33445
+ const THEMATIC_BREAK_RE = /^[ \t]{0,3}(?:-{3,}|\*{3,}|_{3,})[ \t]*\r?$/m;
33446
+ function splitSlides(body) {
33447
+ return body.split(THEMATIC_BREAK_RE).map((chunk) => chunk.trim()).filter((chunk) => chunk.length > 0);
33448
+ }
33449
+ const remarkPlugins$1 = [remarkGfm];
33450
+ function MarpSlideView({ slides, baseDir }) {
33451
+ if (slides.length === 0) {
33452
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs t-text-muted", children: "No slides detected. Switch to source view to inspect the markdown." });
33068
33453
  }
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
- ] });
33454
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-col gap-4", children: slides.map((slide, index2) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
33455
+ "article",
33456
+ {
33457
+ className: "relative t-bg-surface border t-border rounded-lg shadow-sm overflow-hidden",
33458
+ style: { aspectRatio: "16 / 9", minHeight: 200 },
33459
+ "aria-label": `Slide ${index2 + 1} of ${slides.length}`,
33460
+ children: [
33461
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "absolute top-2 right-3 text-[10px] font-mono tabular-nums t-text-muted z-10", children: [
33462
+ index2 + 1,
33463
+ " / ",
33464
+ slides.length
33465
+ ] }),
33466
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
33467
+ "div",
33468
+ {
33469
+ className: "md-prose h-full overflow-auto px-6 py-5",
33470
+ style: { color: "var(--color-text)", fontSize: "14px", lineHeight: 1.5 },
33471
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
33472
+ Markdown,
33473
+ {
33474
+ remarkPlugins: remarkPlugins$1,
33475
+ components: {
33476
+ img: ({ src, alt, ...rest }) => /* @__PURE__ */ jsxRuntimeExports.jsx(
33477
+ "img",
33478
+ {
33479
+ src: resolveMarkdownImageUrl(src, baseDir),
33480
+ alt,
33481
+ ...rest
33482
+ }
33483
+ )
33484
+ },
33485
+ children: slide
33486
+ }
33487
+ )
33488
+ }
33489
+ )
33490
+ ]
33491
+ },
33492
+ index2
33493
+ )) });
33074
33494
  }
33075
33495
  const remarkPlugins = [remarkGfm];
33496
+ const NAVIGABLE_FILE_EXTS = /* @__PURE__ */ new Set([
33497
+ "md",
33498
+ "txt",
33499
+ "json",
33500
+ "ts",
33501
+ "js",
33502
+ "css",
33503
+ "html",
33504
+ "yml",
33505
+ "yaml",
33506
+ "toml",
33507
+ "env",
33508
+ "sh",
33509
+ "py",
33510
+ "cfg",
33511
+ "ini",
33512
+ "log",
33513
+ "csv",
33514
+ "xml",
33515
+ "rst",
33516
+ "jsx",
33517
+ "tsx",
33518
+ "mjs",
33519
+ "cjs",
33520
+ "markdown",
33521
+ "gitignore"
33522
+ ]);
33076
33523
  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);
33524
+ const mod = await __vitePreload(() => import("./MilkdownMarkdownEditor-Bj7JSjF5.js").then((n) => n.bL), true ? __vite__mapDeps([0,1]) : void 0, import.meta.url);
33078
33525
  return { default: mod.MilkdownMarkdownEditor };
33079
33526
  });
33080
33527
  const typeIcons = {
@@ -33185,6 +33632,9 @@ function CsvPreview({ content: content2, separator }) {
33185
33632
  ] })
33186
33633
  ] });
33187
33634
  }
33635
+ function normalizePathSep(p) {
33636
+ return p.replace(/\\/g, "/");
33637
+ }
33188
33638
  function usePreviewNavigation() {
33189
33639
  const previewSourceTab = useUIStore((s15) => s15.previewSourceTab);
33190
33640
  const previewEntity = useUIStore((s15) => s15.previewEntity);
@@ -33192,6 +33642,71 @@ function usePreviewNavigation() {
33192
33642
  const notes = useEntityStore((s15) => s15.notes);
33193
33643
  const papers = useEntityStore((s15) => s15.papers);
33194
33644
  const data = useEntityStore((s15) => s15.data);
33645
+ const projectPath = useSessionStore((s15) => s15.projectPath);
33646
+ const [fileSiblings, setFileSiblings] = reactExports.useState([]);
33647
+ const currentFilePath = previewSourceTab === "files" ? previewEntity?.filePath : void 0;
33648
+ reactExports.useEffect(() => {
33649
+ if (!currentFilePath || !projectPath) {
33650
+ setFileSiblings([]);
33651
+ return;
33652
+ }
33653
+ const absFile = normalizePathSep(currentFilePath);
33654
+ const absProj = normalizePathSep(projectPath);
33655
+ let relParent;
33656
+ if (absFile === absProj) {
33657
+ relParent = "";
33658
+ } else if (absFile.startsWith(absProj + "/")) {
33659
+ const rel = absFile.slice(absProj.length + 1);
33660
+ relParent = rel.includes("/") ? rel.slice(0, rel.lastIndexOf("/")) : "";
33661
+ } else {
33662
+ setFileSiblings([]);
33663
+ return;
33664
+ }
33665
+ let cancelled = false;
33666
+ const api2 = window.api;
33667
+ Promise.resolve(api2.listTree({ relativePath: relParent, showIgnored: true, limit: 2e3 })).then((nodes) => {
33668
+ if (cancelled || !Array.isArray(nodes)) return;
33669
+ const siblings = [];
33670
+ for (const n of nodes) {
33671
+ if (n.type !== "file") continue;
33672
+ const ext = (n.name.split(".").pop() || "").toLowerCase();
33673
+ if (!NAVIGABLE_FILE_EXTS.has(ext)) continue;
33674
+ siblings.push({ name: n.name, path: n.path, modifiedAt: n.modifiedAt || Date.now() });
33675
+ }
33676
+ setFileSiblings(siblings);
33677
+ }).catch(() => {
33678
+ if (!cancelled) setFileSiblings([]);
33679
+ });
33680
+ return () => {
33681
+ cancelled = true;
33682
+ };
33683
+ }, [currentFilePath, projectPath]);
33684
+ const entityForFilePath = reactExports.useCallback((filePath, displayName, modifiedAt) => {
33685
+ const norm = normalizePathSep(filePath);
33686
+ const existing = data.find((item) => normalizePathSep(item.filePath || "") === norm);
33687
+ if (existing) {
33688
+ return {
33689
+ ...existing,
33690
+ type: "data",
33691
+ title: existing.title || existing.name || displayName,
33692
+ filePath
33693
+ };
33694
+ }
33695
+ const iso = new Date(modifiedAt || Date.now()).toISOString();
33696
+ return {
33697
+ id: filePath,
33698
+ type: "data",
33699
+ title: displayName,
33700
+ filePath,
33701
+ tags: [],
33702
+ createdAt: iso,
33703
+ updatedAt: iso
33704
+ };
33705
+ }, [data]);
33706
+ const fileSiblingEntities = reactExports.useMemo(
33707
+ () => fileSiblings.map((s15) => entityForFilePath(s15.path, s15.name, s15.modifiedAt)),
33708
+ [fileSiblings, entityForFilePath]
33709
+ );
33195
33710
  const list2 = (() => {
33196
33711
  switch (previewSourceTab) {
33197
33712
  case "library":
@@ -33199,11 +33714,19 @@ function usePreviewNavigation() {
33199
33714
  case "papers":
33200
33715
  return papers;
33201
33716
  case "files":
33717
+ return fileSiblingEntities;
33202
33718
  default:
33203
33719
  return [];
33204
33720
  }
33205
33721
  })();
33206
- const currentIndex = previewEntity ? list2.findIndex((item) => item.id === previewEntity.id) : -1;
33722
+ const currentIndex = (() => {
33723
+ if (!previewEntity) return -1;
33724
+ if (previewSourceTab === "files" && previewEntity.filePath) {
33725
+ const target = normalizePathSep(previewEntity.filePath);
33726
+ return list2.findIndex((item) => normalizePathSep(item.filePath || "") === target);
33727
+ }
33728
+ return list2.findIndex((item) => item.id === previewEntity.id);
33729
+ })();
33207
33730
  const total = list2.length;
33208
33731
  const canNavigate = total > 1 && currentIndex >= 0;
33209
33732
  const goNext = reactExports.useCallback(() => {
@@ -33222,12 +33745,35 @@ function EntityPreviewPanel() {
33222
33745
  const rawEntity = useUIStore((s15) => s15.previewEntity);
33223
33746
  const closePreview = useUIStore((s15) => s15.closePreview);
33224
33747
  const setPreviewEditorFocused = useUIStore((s15) => s15.setPreviewEditorFocused);
33225
- const deleteEntity = useEntityStore((s15) => s15.deleteEntity);
33748
+ const drawerWidth = useUIStore((s15) => s15.drawerWidth);
33749
+ const setDrawerWidth = useUIStore((s15) => s15.setDrawerWidth);
33226
33750
  const refreshAll = useEntityStore((s15) => s15.refreshAll);
33227
33751
  const previewEditorFocused = useUIStore((s15) => s15.previewEditorFocused);
33228
33752
  const nav = usePreviewNavigation();
33753
+ const dragStateRef = reactExports.useRef(null);
33754
+ const handleEdgeMouseDown = reactExports.useCallback((e) => {
33755
+ dragStateRef.current = { startX: e.clientX, startWidth: drawerWidth };
33756
+ document.body.style.cursor = "ew-resize";
33757
+ e.preventDefault();
33758
+ }, [drawerWidth]);
33759
+ reactExports.useEffect(() => {
33760
+ const onMove = (e) => {
33761
+ if (!dragStateRef.current) return;
33762
+ const dx = dragStateRef.current.startX - e.clientX;
33763
+ setDrawerWidth(dragStateRef.current.startWidth + dx);
33764
+ };
33765
+ const onUp = () => {
33766
+ if (dragStateRef.current) document.body.style.cursor = "";
33767
+ dragStateRef.current = null;
33768
+ };
33769
+ window.addEventListener("mousemove", onMove);
33770
+ window.addEventListener("mouseup", onUp);
33771
+ return () => {
33772
+ window.removeEventListener("mousemove", onMove);
33773
+ window.removeEventListener("mouseup", onUp);
33774
+ };
33775
+ }, [setDrawerWidth]);
33229
33776
  const entity = rawEntity ? { ...rawEntity } : null;
33230
- const [confirmDelete, setConfirmDelete] = reactExports.useState(false);
33231
33777
  const [draftMarkdown, setDraftMarkdown] = reactExports.useState("");
33232
33778
  const [baselineMarkdown, setBaselineMarkdown] = reactExports.useState("");
33233
33779
  const [editorSeedMarkdown, setEditorSeedMarkdown] = reactExports.useState("");
@@ -33237,6 +33783,7 @@ function EntityPreviewPanel() {
33237
33783
  const [fileType, setFileType] = reactExports.useState(null);
33238
33784
  const [loading, setLoading] = reactExports.useState(false);
33239
33785
  const [externalMarkdown, setExternalMarkdown] = reactExports.useState(void 0);
33786
+ const [viewModeOverride, setViewModeOverride] = reactExports.useState(null);
33240
33787
  const resolvedAbsPathRef = reactExports.useRef(null);
33241
33788
  const baselineRef = reactExports.useRef("");
33242
33789
  const getArtifactMarkdownContent = (artifactLike) => {
@@ -33259,6 +33806,7 @@ function EntityPreviewPanel() {
33259
33806
  setSaveError(null);
33260
33807
  setSaveSuccess(null);
33261
33808
  setPreviewEditorFocused(false);
33809
+ setViewModeOverride(null);
33262
33810
  }, [entity?.id]);
33263
33811
  reactExports.useEffect(() => {
33264
33812
  setFileContent(null);
@@ -33299,6 +33847,11 @@ function EntityPreviewPanel() {
33299
33847
  reactExports.useEffect(() => {
33300
33848
  baselineRef.current = baselineMarkdown;
33301
33849
  }, [baselineMarkdown]);
33850
+ const scrollContentRef = reactExports.useRef(null);
33851
+ const modeScrollRef = reactExports.useRef({ source: 0, slides: 0 });
33852
+ reactExports.useEffect(() => {
33853
+ modeScrollRef.current = { source: 0, slides: 0 };
33854
+ }, [entity?.id]);
33302
33855
  reactExports.useEffect(() => {
33303
33856
  if (!entity?.filePath) return;
33304
33857
  const ext = getExtension(entity.filePath);
@@ -33343,7 +33896,48 @@ function EntityPreviewPanel() {
33343
33896
  const isInlineEditable = !entity.filePath;
33344
33897
  const isEditable = isInlineEditable || isFileMarkdown;
33345
33898
  const isDirty = isEditable && normalizeMarkdown(draftMarkdown) !== normalizeMarkdown(baselineMarkdown);
33346
- const seedFp = buildFingerprint(editorSeedMarkdown);
33899
+ const { frontmatterBlock, body: baselineBody } = reactExports.useMemo(
33900
+ () => splitFrontmatter(baselineMarkdown),
33901
+ [baselineMarkdown]
33902
+ );
33903
+ const isMarpFile = reactExports.useMemo(() => isMarpFrontmatter(frontmatterBlock), [frontmatterBlock]);
33904
+ const draftBody = reactExports.useMemo(() => {
33905
+ if (!frontmatterBlock) return draftMarkdown;
33906
+ return draftMarkdown.startsWith(frontmatterBlock) ? draftMarkdown.slice(frontmatterBlock.length) : splitFrontmatter(draftMarkdown).body;
33907
+ }, [draftMarkdown, frontmatterBlock]);
33908
+ const editorSeedBody = reactExports.useMemo(() => splitFrontmatter(editorSeedMarkdown).body, [editorSeedMarkdown]);
33909
+ const externalBody = reactExports.useMemo(() => {
33910
+ if (externalMarkdown === void 0) return void 0;
33911
+ return splitFrontmatter(externalMarkdown).body;
33912
+ }, [externalMarkdown]);
33913
+ const slides = reactExports.useMemo(
33914
+ () => isMarpFile ? splitSlides(draftBody) : [],
33915
+ [isMarpFile, draftBody]
33916
+ );
33917
+ const effectiveViewMode = viewModeOverride ?? (isMarpFile ? "slides" : "source");
33918
+ const showSlideView = isMarpFile && effectiveViewMode === "slides";
33919
+ reactExports.useEffect(() => {
33920
+ const el2 = scrollContentRef.current;
33921
+ if (!el2) return;
33922
+ const onScroll = () => {
33923
+ modeScrollRef.current[effectiveViewMode] = el2.scrollTop;
33924
+ };
33925
+ el2.addEventListener("scroll", onScroll, { passive: true });
33926
+ return () => el2.removeEventListener("scroll", onScroll);
33927
+ }, [effectiveViewMode]);
33928
+ reactExports.useEffect(() => {
33929
+ const target = modeScrollRef.current[effectiveViewMode] ?? 0;
33930
+ const apply = () => {
33931
+ if (scrollContentRef.current) scrollContentRef.current.scrollTop = target;
33932
+ };
33933
+ const raf = requestAnimationFrame(apply);
33934
+ const retry = window.setTimeout(apply, 200);
33935
+ return () => {
33936
+ cancelAnimationFrame(raf);
33937
+ window.clearTimeout(retry);
33938
+ };
33939
+ }, [effectiveViewMode, entity?.id]);
33940
+ const seedFp = buildFingerprint(editorSeedBody);
33347
33941
  const editorKey = `${entity.id}:${entity.filePath ?? "inline"}:${seedFp.length}:${seedFp.codeFenceCount}:${seedFp.mermaidFenceCount}:${seedFp.mathBlockCount}:${seedFp.imageCount}`;
33348
33942
  const handleNavNext = reactExports.useCallback(() => {
33349
33943
  if (!nav.canNavigate) return;
@@ -33376,15 +33970,6 @@ function EntityPreviewPanel() {
33376
33970
  window.addEventListener("keydown", handler);
33377
33971
  return () => window.removeEventListener("keydown", handler);
33378
33972
  }, [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
33973
  const handleSave = async () => {
33389
33974
  if (!isEditable || !isDirty) return;
33390
33975
  const nextMarkdown = draftMarkdown;
@@ -33465,10 +34050,11 @@ Save anyway?`
33465
34050
  LazyMilkdownMarkdownEditor,
33466
34051
  {
33467
34052
  editorId: editorKey,
33468
- initialMarkdown: baselineMarkdown,
33469
- externalMarkdown,
34053
+ initialMarkdown: baselineBody,
34054
+ externalMarkdown: externalBody,
34055
+ baseDir: dirnameOf(entity.filePath),
33470
34056
  onChange: (markdown) => {
33471
- setDraftMarkdown(markdown);
34057
+ setDraftMarkdown((frontmatterBlock ?? "") + markdown);
33472
34058
  if (saveError) setSaveError(null);
33473
34059
  },
33474
34060
  onFocusChange: setPreviewEditorFocused,
@@ -33511,6 +34097,9 @@ Save anyway?`
33511
34097
  const ext = getExtension(entity.filePath);
33512
34098
  const isMarkdown = ext === "md" || ext === "markdown";
33513
34099
  if (isMarkdown) {
34100
+ if (showSlideView) {
34101
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(MarpSlideView, { slides, baseDir: dirnameOf(entity.filePath) });
34102
+ }
33514
34103
  return renderMarkdownEditor();
33515
34104
  }
33516
34105
  return /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "text-xs whitespace-pre-wrap break-words t-text font-mono leading-relaxed", children: fileContent });
@@ -33518,142 +34107,368 @@ Save anyway?`
33518
34107
  return /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs t-text-muted", children: entity.filePath });
33519
34108
  }
33520
34109
  if (isInlineEditable) {
34110
+ if (showSlideView) {
34111
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(MarpSlideView, { slides, baseDir: dirnameOf(entity.filePath) });
34112
+ }
33521
34113
  return renderMarkdownEditor();
33522
34114
  }
33523
34115
  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",
34116
+ const mdBaseDir = dirnameOf(entity.filePath);
34117
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
34118
+ "div",
34119
+ {
34120
+ className: "md-prose",
34121
+ style: {
34122
+ color: "var(--color-text)",
34123
+ fontFamily: READING_FONT,
34124
+ fontSize: "14px",
34125
+ lineHeight: 1.55
34126
+ },
34127
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
34128
+ Markdown,
33548
34129
  {
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 })
34130
+ remarkPlugins,
34131
+ components: {
34132
+ // Rewrite relative / absolute disk paths to workspace-asset://
34133
+ // URLs so images actually load. Remote URLs pass through.
34134
+ img: ({ src, alt, ...rest }) => /* @__PURE__ */ jsxRuntimeExports.jsx(
34135
+ "img",
34136
+ {
34137
+ src: resolveMarkdownImageUrl(src, mdBaseDir),
34138
+ alt,
34139
+ ...rest
34140
+ }
34141
+ )
34142
+ },
34143
+ children: typeof content2 === "string" ? content2 : JSON.stringify(content2, null, 2)
33553
34144
  }
33554
34145
  )
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
- ),
34146
+ }
34147
+ );
34148
+ };
34149
+ const drawerBoxShadow = "inset 3px 0 0 0 var(--color-accent), -12px 0 32px -14px rgba(0,0,0,0.18)";
34150
+ const crumb = entity.filePath ? `files · ${(getExtension(entity.filePath) || "file").toLowerCase()}` : `library · ${entity.type}`;
34151
+ const READING_FONT = '"Iowan Old Style", "Charter", "Sitka Text", Georgia, serif';
34152
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
34153
+ "div",
34154
+ {
34155
+ 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)]",
34156
+ style: { width: drawerWidth, boxShadow: drawerBoxShadow },
34157
+ "aria-label": `Preview: ${entity.title}`,
34158
+ children: [
33576
34159
  /* @__PURE__ */ jsxRuntimeExports.jsx(
33577
- "button",
34160
+ "div",
33578
34161
  {
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 })
34162
+ className: "absolute left-0 top-0 bottom-0 w-[6px] cursor-ew-resize group z-[6]",
34163
+ style: { marginLeft: -3 },
34164
+ onMouseDown: handleEdgeMouseDown,
34165
+ title: "Drag to resize",
34166
+ "aria-hidden": "true",
34167
+ 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
34168
  }
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() })
34169
+ ),
34170
+ /* @__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: [
34171
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0 flex-1", children: [
34172
+ /* @__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: [
34173
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: crumb }),
34174
+ 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" })
34175
+ ] }),
34176
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [
34177
+ typeIcons[entity.type] || null,
34178
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
34179
+ "h2",
34180
+ {
34181
+ className: "min-w-0 truncate t-text",
34182
+ style: {
34183
+ fontFamily: READING_FONT,
34184
+ fontSize: "17px",
34185
+ lineHeight: 1.2,
34186
+ fontWeight: 500,
34187
+ letterSpacing: "-0.012em"
34188
+ },
34189
+ children: entity.title
34190
+ }
34191
+ )
34192
+ ] })
34193
+ ] }),
34194
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1 flex-shrink-0 pt-1", children: [
34195
+ nav.canNavigate && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-0.5 mr-1", children: [
34196
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
34197
+ "button",
34198
+ {
34199
+ onClick: handleNavPrev,
34200
+ className: "p-1 rounded t-text-muted t-bg-hover transition-colors",
34201
+ title: "Previous item (Alt+Up)",
34202
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronUp, { size: 14 })
34203
+ }
34204
+ ),
34205
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] t-text-muted tabular-nums min-w-[2.5rem] text-center", children: [
34206
+ nav.currentIndex + 1,
34207
+ " / ",
34208
+ nav.total
34209
+ ] }),
34210
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
34211
+ "button",
34212
+ {
34213
+ onClick: handleNavNext,
34214
+ className: "p-1 rounded t-text-muted t-bg-hover transition-colors",
34215
+ title: "Next item (Alt+Down)",
34216
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { size: 14 })
34217
+ }
34218
+ )
34219
+ ] }),
34220
+ isEditable && /* @__PURE__ */ jsxRuntimeExports.jsx(
34221
+ "button",
34222
+ {
34223
+ onClick: () => void handleSave(),
34224
+ disabled: !isDirty,
34225
+ className: `p-1 rounded transition-colors ${isDirty ? "t-text-accent-soft hover:t-text-accent" : "t-text-muted opacity-50"}`,
34226
+ title: isDirty ? "Save markdown (Cmd/Ctrl+S)" : "No changes to save",
34227
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(Save, { size: 14 })
34228
+ }
34229
+ ),
34230
+ isMarpFile && /* @__PURE__ */ jsxRuntimeExports.jsx(
34231
+ "button",
34232
+ {
34233
+ onClick: () => setViewModeOverride(showSlideView ? "source" : "slides"),
34234
+ className: "p-1 rounded t-text-muted t-bg-hover transition-colors",
34235
+ title: showSlideView ? "Edit source" : "View as slides",
34236
+ "aria-pressed": showSlideView,
34237
+ children: showSlideView ? /* @__PURE__ */ jsxRuntimeExports.jsx(FileText, { size: 14 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Presentation, { size: 14 })
34238
+ }
34239
+ ),
34240
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
34241
+ "button",
34242
+ {
34243
+ onClick: handleClosePreview,
34244
+ className: "p-1 rounded t-text-muted t-bg-hover transition-colors",
34245
+ title: "Close preview (Esc)",
34246
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(X$1, { size: 14 })
34247
+ }
34248
+ )
34249
+ ] })
34250
+ ] }) }),
34251
+ 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: [
34252
+ entity.authors?.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
34253
+ "Authors: ",
34254
+ entity.authors.join(", ")
34255
+ ] }),
34256
+ entity.year && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
34257
+ "Year: ",
34258
+ entity.year
34259
+ ] }),
34260
+ entity.venue && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
34261
+ "Venue: ",
34262
+ entity.venue
34263
+ ] }),
34264
+ entity.doi && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
34265
+ "DOI: ",
34266
+ /* @__PURE__ */ jsxRuntimeExports.jsx("a", { href: `https://doi.org/${entity.doi}`, target: "_blank", rel: "noreferrer", className: "t-text-accent-soft hover:underline", children: entity.doi })
34267
+ ] }),
34268
+ entity.citationCount != null && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
34269
+ "Citations: ",
34270
+ entity.citationCount
34271
+ ] }),
34272
+ entity.url && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
34273
+ "URL: ",
34274
+ /* @__PURE__ */ jsxRuntimeExports.jsx("a", { href: entity.url, target: "_blank", rel: "noreferrer", className: "t-text-accent-soft hover:underline break-all", children: entity.url })
34275
+ ] }),
34276
+ entity.pdfUrl && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
34277
+ "PDF: ",
34278
+ /* @__PURE__ */ jsxRuntimeExports.jsx("a", { href: entity.pdfUrl, target: "_blank", rel: "noreferrer", className: "t-text-accent-soft hover:underline break-all", children: entity.pdfUrl })
34279
+ ] }),
34280
+ entity.citeKey && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
34281
+ "Cite key: ",
34282
+ /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "t-bg-surface px-1 rounded", children: entity.citeKey })
34283
+ ] }),
34284
+ entity.externalSource && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
34285
+ "Source: ",
34286
+ entity.externalSource
34287
+ ] }),
34288
+ entity.relevanceScore != null && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
34289
+ "Relevance: ",
34290
+ entity.relevanceScore,
34291
+ "/10"
34292
+ ] }),
34293
+ entity.enrichmentSource && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
34294
+ "Enriched via: ",
34295
+ entity.enrichmentSource
34296
+ ] }),
34297
+ entity.enrichedAt && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
34298
+ "Enriched at: ",
34299
+ new Date(entity.enrichedAt).toLocaleDateString()
34300
+ ] }),
34301
+ entity.tags?.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "flex items-center gap-1 flex-wrap", children: [
34302
+ "Tags: ",
34303
+ entity.tags.map((t) => /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "inline-block t-bg-surface px-1.5 py-0.5 rounded", children: t }, t))
34304
+ ] }),
34305
+ entity.bibtex && /* @__PURE__ */ jsxRuntimeExports.jsxs("details", { className: "mt-1", children: [
34306
+ /* @__PURE__ */ jsxRuntimeExports.jsx("summary", { className: "cursor-pointer hover:t-text-accent-soft", children: "BibTeX" }),
34307
+ /* @__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 })
34308
+ ] })
34309
+ ] }),
34310
+ entity.type === "data" && entity.schema && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 py-2 border-b t-border text-xs t-text-secondary", children: [
34311
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
34312
+ "File: ",
34313
+ entity.name
34314
+ ] }),
34315
+ entity.schema.rowCount != null && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
34316
+ "Rows: ",
34317
+ entity.schema.rowCount
34318
+ ] })
34319
+ ] }),
34320
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { ref: scrollContentRef, className: "flex-1 overflow-y-auto px-5 py-5 min-h-0", children: renderContent() }),
34321
+ /* @__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: [
34322
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-2 min-w-0 truncate", children: [
34323
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
34324
+ "span",
34325
+ {
34326
+ className: "inline-block w-[7px] h-[7px] rounded-full t-bg-accent animate-pulse shrink-0",
34327
+ "aria-hidden": "true"
34328
+ }
34329
+ ),
34330
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate", children: "Bound to chat" })
34331
+ ] }),
34332
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate shrink-0", children: "Drag edge · Esc to close" })
34333
+ ] })
34334
+ ]
34335
+ }
34336
+ );
34337
+ }
34338
+ const api$2 = window.api;
34339
+ const computeEnabled = api$2?.isComputeEnabled?.() ?? false;
34340
+ const viewTabs = [
34341
+ { key: "chat", label: "Chat", icon: MessageSquare, shortcut: "⌘1" },
34342
+ { key: "literature", label: "Literature", icon: BookOpen, shortcut: "⌘2" },
34343
+ ...computeEnabled ? [{ key: "compute", label: "Compute", icon: Cpu, shortcut: "⌘3" }] : []
34344
+ ];
34345
+ function ViewSwitcher() {
34346
+ const centerView = useUIStore((s15) => s15.centerView);
34347
+ const setCenterView = useUIStore((s15) => s15.setCenterView);
34348
+ const paperCount = useEntityStore((s15) => s15.papers.length);
34349
+ const activeComputeRuns = useActiveRunCount();
34350
+ return (
34351
+ // Bottom hairline gives the nav a real anchor — without it, the tabs
34352
+ // float in a gray area between the drag region and the content.
34353
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
34354
+ "nav",
34355
+ {
34356
+ "aria-label": "View switcher",
34357
+ className: "flex items-stretch gap-1 px-4 pt-10 border-b t-border",
34358
+ children: viewTabs.map(({ key, label, icon: Icon2, shortcut }) => {
34359
+ const isActive = centerView === key;
34360
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
34361
+ "button",
34362
+ {
34363
+ onClick: () => setCenterView(key),
34364
+ "aria-current": isActive ? "page" : void 0,
34365
+ title: `${label} (${shortcut})`,
34366
+ 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"}`,
34367
+ children: [
34368
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Icon2, { size: 14, className: isActive ? "t-text-accent" : "" }),
34369
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: label }),
34370
+ key === "literature" && paperCount > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(
34371
+ "span",
34372
+ {
34373
+ 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"}`,
34374
+ children: paperCount
34375
+ }
34376
+ ),
34377
+ 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 }),
34378
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
34379
+ "kbd",
34380
+ {
34381
+ 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"}`,
34382
+ children: shortcut
34383
+ }
34384
+ ),
34385
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
34386
+ "span",
34387
+ {
34388
+ "aria-hidden": true,
34389
+ className: `pointer-events-none absolute left-0 right-0 -bottom-px h-[2px] transition-colors ${isActive ? "t-bg-accent" : "bg-transparent"}`
34390
+ }
34391
+ )
34392
+ ]
34393
+ },
34394
+ key
34395
+ );
34396
+ })
34397
+ }
34398
+ )
34399
+ );
34400
+ }
34401
+ function CenterPanel() {
34402
+ const centerView = useUIStore((s15) => s15.centerView);
34403
+ const isIdle = useUIStore((s15) => s15.isIdle);
34404
+ const messages = useChatStore((s15) => s15.messages);
34405
+ const previewEntity = useUIStore((s15) => s15.previewEntity);
34406
+ const drawerWidth = useUIStore((s15) => s15.drawerWidth);
34407
+ const showHero = isIdle && messages.length === 0;
34408
+ const drawerOpen = !!previewEntity;
34409
+ const rightGutter = drawerOpen ? drawerWidth : 0;
34410
+ const columnShiftStyle = { paddingRight: `${rightGutter}px` };
34411
+ const columnShiftClass = "transition-[padding] duration-500 ease-[cubic-bezier(0.32,0.72,0.24,1)]";
34412
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
34413
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
34414
+ "main",
34415
+ {
34416
+ id: centerView === "chat" ? "main-content" : void 0,
34417
+ hidden: centerView !== "chat",
34418
+ className: "flex-1 flex flex-col min-w-0 relative overflow-hidden",
34419
+ children: [
34420
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: columnShiftClass, style: columnShiftStyle, children: /* @__PURE__ */ jsxRuntimeExports.jsx(ViewSwitcher, {}) }),
34421
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-h-0", children: showHero ? /* @__PURE__ */ jsxRuntimeExports.jsx(
34422
+ "div",
34423
+ {
34424
+ className: `h-full flex items-center justify-center ${columnShiftClass}`,
34425
+ style: columnShiftStyle,
34426
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(HeroIdle, {})
34427
+ }
34428
+ ) : /* @__PURE__ */ jsxRuntimeExports.jsx(
34429
+ "div",
34430
+ {
34431
+ className: `h-full pl-6 pt-4 pb-2 ${columnShiftClass}`,
34432
+ style: { paddingRight: `${24 + rightGutter}px` },
34433
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mx-auto h-full", style: { maxWidth: "64rem" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChatMessages, {}) })
34434
+ }
34435
+ ) }),
34436
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
34437
+ "div",
34438
+ {
34439
+ className: `pl-6 pb-5 ${columnShiftClass}`,
34440
+ style: { paddingRight: `${24 + rightGutter}px` },
34441
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mx-auto", style: { maxWidth: "64rem" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChatInput, {}) })
34442
+ }
34443
+ ),
34444
+ drawerOpen && /* @__PURE__ */ jsxRuntimeExports.jsx(EntityPreviewPanel, {})
34445
+ ]
34446
+ }
34447
+ ),
34448
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
34449
+ "main",
34450
+ {
34451
+ id: centerView === "literature" ? "main-content" : void 0,
34452
+ hidden: centerView !== "literature",
34453
+ className: "flex-1 flex flex-col min-w-0",
34454
+ children: [
34455
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ViewSwitcher, {}),
34456
+ /* @__PURE__ */ jsxRuntimeExports.jsx(LiteratureView, {})
34457
+ ]
34458
+ }
34459
+ ),
34460
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
34461
+ "main",
34462
+ {
34463
+ id: centerView === "compute" ? "main-content" : void 0,
34464
+ hidden: centerView !== "compute",
34465
+ className: "flex-1 flex flex-col min-w-0",
34466
+ children: [
34467
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ViewSwitcher, {}),
34468
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ComputeView, {})
34469
+ ]
34470
+ }
34471
+ )
33657
34472
  ] });
33658
34473
  }
33659
34474
  function formatCost(cost) {
@@ -43212,12 +44027,9 @@ function App() {
43212
44027
  /* @__PURE__ */ jsxRuntimeExports.jsx("a", { href: "#main-content", className: "skip-link", children: "Skip to content" }),
43213
44028
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "drag-region fixed top-0 left-0 right-0 h-8 z-50" }),
43214
44029
  /* @__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) }) }),
44030
+ !leftCollapsed && /* @__PURE__ */ jsxRuntimeExports.jsx(LeftSidebar, { onOpenSettings: () => setSettingsOpen(true) }),
43216
44031
  /* @__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
- ] }),
44032
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `flex min-h-0 ${terminalVisible ? "flex-[2]" : "flex-1"}`, children: /* @__PURE__ */ jsxRuntimeExports.jsx(CenterPanel, {}) }),
43221
44033
  terminalAlive && /* @__PURE__ */ jsxRuntimeExports.jsx(
43222
44034
  "div",
43223
44035
  {
@@ -43262,6 +44074,7 @@ export {
43262
44074
  patternInScope as p,
43263
44075
  jsxRuntimeExports as q,
43264
44076
  reactExports as r,
44077
+ resolveMarkdownImageUrl as s,
43265
44078
  unified as u,
43266
44079
  visit as v
43267
44080
  };