research-copilot 0.2.8 → 0.2.10
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.
- package/README.md +42 -34
- package/app/out/main/index.mjs +6167 -2491
- package/app/out/preload/index.js +31 -0
- package/app/out/renderer/assets/{MilkdownMarkdownEditor-wtbKgEbm.js → MilkdownMarkdownEditor-De2Q1dek.js} +50 -50
- package/app/out/renderer/assets/{arc-BqLtjO5D.js → arc-C6EUFV_N.js} +1 -1
- package/app/out/renderer/assets/{blockDiagram-c4efeb88-CHtvWbUe.js → blockDiagram-c4efeb88-DPxImKGD.js} +8 -8
- package/app/out/renderer/assets/{c4Diagram-c83219d4-CGorl4p_.js → c4Diagram-c83219d4-VnazgZ1X.js} +3 -3
- package/app/out/renderer/assets/{channel-C4dnKIdE.js → channel-DC2lk7Hf.js} +1 -1
- package/app/out/renderer/assets/{classDiagram-beda092f-CcVq8zgL.js → classDiagram-beda092f-CH4Xea-4.js} +6 -6
- package/app/out/renderer/assets/{classDiagram-v2-2358418a-C1T7WzEm.js → classDiagram-v2-2358418a-DQAT-8KP.js} +10 -10
- package/app/out/renderer/assets/{clone-DxlJpy1a.js → clone-DmzuvEez.js} +1 -1
- package/app/out/renderer/assets/{createText-1719965b-C0d2kD0r.js → createText-1719965b-DipiQz-3.js} +2 -2
- package/app/out/renderer/assets/{edges-96097737-CLaP5xIP.js → edges-96097737-DMCNYzh0.js} +3 -3
- package/app/out/renderer/assets/{erDiagram-0228fc6a-MUP9rxkZ.js → erDiagram-0228fc6a-BCYmzg3a.js} +5 -5
- package/app/out/renderer/assets/{flowDb-c6c81e3f-BPAie9_m.js → flowDb-c6c81e3f-Dd2eD_J_.js} +1 -1
- package/app/out/renderer/assets/{flowDiagram-50d868cf-wPPnXbEC.js → flowDiagram-50d868cf-Cm_pVS1l.js} +12 -12
- package/app/out/renderer/assets/{flowDiagram-v2-4f6560a1-Bla11wXJ.js → flowDiagram-v2-4f6560a1-DmnPUt4m.js} +12 -12
- package/app/out/renderer/assets/{flowchart-elk-definition-6af322e1-D05H4IzP.js → flowchart-elk-definition-6af322e1-CWmjyrNl.js} +6 -6
- package/app/out/renderer/assets/{ganttDiagram-a2739b55-_HXvgcdj.js → ganttDiagram-a2739b55-zezz97ZG.js} +3 -3
- package/app/out/renderer/assets/{gitGraphDiagram-82fe8481-qK3Q1wq5.js → gitGraphDiagram-82fe8481-B8AuyyHK.js} +2 -2
- package/app/out/renderer/assets/{graph-C5ywDmPQ.js → graph-CeW0ZYF_.js} +1 -1
- package/app/out/renderer/assets/{index-5325376f-D3a5ZZZz.js → index-5325376f-ytL7PjAX.js} +6 -6
- package/app/out/renderer/assets/{index-Cvn9cLQy.js → index-Ay1x5fGf.js} +5 -5
- package/app/out/renderer/assets/{index-Bnopm9R6.js → index-B0IaCM06.js} +2162 -659
- package/app/out/renderer/assets/{index-0RdJfTuz.js → index-B0uWkIRD.js} +4 -4
- package/app/out/renderer/assets/{index-DkxwQySh.js → index-B75z0HLs.js} +3 -3
- package/app/out/renderer/assets/{index-CsIY4rv7.js → index-BKsFANZc.js} +3 -3
- package/app/out/renderer/assets/{index-Ct5-4eln.js → index-Bvn-V7yR.js} +6 -6
- package/app/out/renderer/assets/{index-CAV5KrKz.js → index-BvnI1484.js} +3 -3
- package/app/out/renderer/assets/{index-BD3NNxzl.js → index-C-qLsVVB.js} +3 -3
- package/app/out/renderer/assets/{index-CUhOSCxv.js → index-C6pCLMcd.js} +6 -6
- package/app/out/renderer/assets/{index-CJfHLqJM.js → index-C776N_wX.js} +1 -1
- package/app/out/renderer/assets/{index-BWngX05Q.js → index-C7QDCbIv.js} +3 -3
- package/app/out/renderer/assets/{index-CsvJ1nbq.js → index-C9i71nBq.js} +6 -6
- package/app/out/renderer/assets/{index-CviTrzVQ.js → index-CH0Tw6y0.js} +3 -3
- package/app/out/renderer/assets/{index-CTYjTyUA.js → index-CtSJ0GcR.js} +3 -3
- package/app/out/renderer/assets/{index-eO4trtHi.js → index-CwqgQS0P.js} +3 -3
- package/app/out/renderer/assets/{index-BPbilNff.js → index-CxruKWgd.js} +3 -3
- package/app/out/renderer/assets/{index-BcyuyYWv.css → index-D4U0VRks.css} +330 -75
- package/app/out/renderer/assets/{index-ByTHdZ7D.js → index-DCzv5EHR.js} +4 -4
- package/app/out/renderer/assets/{index-MnlXVp99.js → index-DO8xKLcA.js} +3 -3
- package/app/out/renderer/assets/{index-NTc0rY_G.js → index-DfC33JyY.js} +3 -3
- package/app/out/renderer/assets/{index-DXSYlARx.js → index-Dqp-JFMN.js} +3 -3
- package/app/out/renderer/assets/{index-UKpTDcKF.js → index-ETc6uiKn.js} +6 -6
- package/app/out/renderer/assets/{index-BlphXQkB.js → index-qA_Cm2qi.js} +6 -6
- package/app/out/renderer/assets/{index-DD3Ny6Vp.js → index-rCpjMSg4.js} +6 -6
- package/app/out/renderer/assets/{infoDiagram-8eee0895-Y5yOIBzh.js → infoDiagram-8eee0895-C7ulMekA.js} +2 -2
- package/app/out/renderer/assets/{journeyDiagram-c64418c1-nxv9KGN2.js → journeyDiagram-c64418c1-B6EiRrRb.js} +4 -4
- package/app/out/renderer/assets/{layout-QkNm3OqP.js → layout-BQe3Guvd.js} +2 -2
- package/app/out/renderer/assets/{line-CcMLwlNB.js → line-DKt3MOVb.js} +1 -1
- package/app/out/renderer/assets/{linear-DZFvfKB-.js → linear-BkgDruk7.js} +1 -1
- package/app/out/renderer/assets/{mindmap-definition-8da855dc-BLROjqLP.js → mindmap-definition-8da855dc-B_OxB2wg.js} +3 -3
- package/app/out/renderer/assets/{pieDiagram-a8764435-CEwkf3-w.js → pieDiagram-a8764435-Cs6G_wWV.js} +3 -3
- package/app/out/renderer/assets/{quadrantDiagram-1e28029f-Wtu-X7yj.js → quadrantDiagram-1e28029f-CBOijGWr.js} +3 -3
- package/app/out/renderer/assets/{requirementDiagram-08caed73-BmHzmnoA.js → requirementDiagram-08caed73-BWmZFvbN.js} +5 -5
- package/app/out/renderer/assets/{sankeyDiagram-a04cb91d-DR-ZBDLL.js → sankeyDiagram-a04cb91d-Dz86q9nr.js} +2 -2
- package/app/out/renderer/assets/{sequenceDiagram-c5b8d532-CvKwzJJS.js → sequenceDiagram-c5b8d532-rgC0xuyv.js} +3 -3
- package/app/out/renderer/assets/{stateDiagram-1ecb1508-D9DTeGP_.js → stateDiagram-1ecb1508-CUEUbsGu.js} +6 -6
- package/app/out/renderer/assets/{stateDiagram-v2-c2b004d7-CFD8lymK.js → stateDiagram-v2-c2b004d7-CnX14ipk.js} +10 -10
- package/app/out/renderer/assets/{styles-b4e223ce-rY8jQLYQ.js → styles-b4e223ce-DoXfPoT8.js} +1 -1
- package/app/out/renderer/assets/{styles-ca3715f6-DkM1AvDm.js → styles-ca3715f6-C9YwWiKc.js} +1 -1
- package/app/out/renderer/assets/{styles-d45a18b0-Cg53i9fc.js → styles-d45a18b0-BnKt7kQ1.js} +4 -4
- package/app/out/renderer/assets/{svgDrawCommon-b86b1483-Dcml1adX.js → svgDrawCommon-b86b1483-Bz6F-KWS.js} +1 -1
- package/app/out/renderer/assets/{timeline-definition-faaaa080-Dn53tAu-.js → timeline-definition-faaaa080-Dc1X0wkq.js} +3 -3
- package/app/out/renderer/assets/{xychartDiagram-f5964ef8-Dur19n8N.js → xychartDiagram-f5964ef8-DOBthtKy.js} +5 -5
- package/app/out/renderer/index.html +2 -2
- package/app/package.json +3 -1
- package/lib/skills/builtin/marp-slides/SKILL.md +642 -0
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./MilkdownMarkdownEditor-
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./MilkdownMarkdownEditor-De2Q1dek.js","./MilkdownMarkdownEditor-tTNRIB2K.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;
|
|
@@ -12524,6 +12524,16 @@ const createLucideIcon = (iconName, iconNode) => {
|
|
|
12524
12524
|
Component2.displayName = `${iconName}`;
|
|
12525
12525
|
return Component2;
|
|
12526
12526
|
};
|
|
12527
|
+
/**
|
|
12528
|
+
* @license lucide-react v0.469.0 - ISC
|
|
12529
|
+
*
|
|
12530
|
+
* This source code is licensed under the ISC license.
|
|
12531
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
12532
|
+
*/
|
|
12533
|
+
const ArrowLeft = createLucideIcon("ArrowLeft", [
|
|
12534
|
+
["path", { d: "m12 19-7-7 7-7", key: "1l729n" }],
|
|
12535
|
+
["path", { d: "M19 12H5", key: "x3x0zl" }]
|
|
12536
|
+
]);
|
|
12527
12537
|
/**
|
|
12528
12538
|
* @license lucide-react v0.469.0 - ISC
|
|
12529
12539
|
*
|
|
@@ -12609,6 +12619,17 @@ const ChartColumn = createLucideIcon("ChartColumn", [
|
|
|
12609
12619
|
["path", { d: "M13 17V5", key: "1frdt8" }],
|
|
12610
12620
|
["path", { d: "M8 17v-3", key: "17ska0" }]
|
|
12611
12621
|
]);
|
|
12622
|
+
/**
|
|
12623
|
+
* @license lucide-react v0.469.0 - ISC
|
|
12624
|
+
*
|
|
12625
|
+
* This source code is licensed under the ISC license.
|
|
12626
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
12627
|
+
*/
|
|
12628
|
+
const ChartNoAxesColumn = createLucideIcon("ChartNoAxesColumn", [
|
|
12629
|
+
["line", { x1: "18", x2: "18", y1: "20", y2: "10", key: "1xfpm4" }],
|
|
12630
|
+
["line", { x1: "12", x2: "12", y1: "20", y2: "4", key: "be30l9" }],
|
|
12631
|
+
["line", { x1: "6", x2: "6", y1: "20", y2: "14", key: "1r4le6" }]
|
|
12632
|
+
]);
|
|
12612
12633
|
/**
|
|
12613
12634
|
* @license lucide-react v0.469.0 - ISC
|
|
12614
12635
|
*
|
|
@@ -12673,6 +12694,16 @@ const CircleCheck = createLucideIcon("CircleCheck", [
|
|
|
12673
12694
|
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
|
|
12674
12695
|
["path", { d: "m9 12 2 2 4-4", key: "dzmm74" }]
|
|
12675
12696
|
]);
|
|
12697
|
+
/**
|
|
12698
|
+
* @license lucide-react v0.469.0 - ISC
|
|
12699
|
+
*
|
|
12700
|
+
* This source code is licensed under the ISC license.
|
|
12701
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
12702
|
+
*/
|
|
12703
|
+
const CircleDot = createLucideIcon("CircleDot", [
|
|
12704
|
+
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
|
|
12705
|
+
["circle", { cx: "12", cy: "12", r: "1", key: "41hilf" }]
|
|
12706
|
+
]);
|
|
12676
12707
|
/**
|
|
12677
12708
|
* @license lucide-react v0.469.0 - ISC
|
|
12678
12709
|
*
|
|
@@ -13018,6 +13049,19 @@ const Monitor = createLucideIcon("Monitor", [
|
|
|
13018
13049
|
const Moon = createLucideIcon("Moon", [
|
|
13019
13050
|
["path", { d: "M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z", key: "a7tn18" }]
|
|
13020
13051
|
]);
|
|
13052
|
+
/**
|
|
13053
|
+
* @license lucide-react v0.469.0 - ISC
|
|
13054
|
+
*
|
|
13055
|
+
* This source code is licensed under the ISC license.
|
|
13056
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
13057
|
+
*/
|
|
13058
|
+
const Network = createLucideIcon("Network", [
|
|
13059
|
+
["rect", { x: "16", y: "16", width: "6", height: "6", rx: "1", key: "4q2zg0" }],
|
|
13060
|
+
["rect", { x: "2", y: "16", width: "6", height: "6", rx: "1", key: "8cvhb9" }],
|
|
13061
|
+
["rect", { x: "9", y: "2", width: "6", height: "6", rx: "1", key: "1egb70" }],
|
|
13062
|
+
["path", { d: "M5 16v-3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v3", key: "1jsf9p" }],
|
|
13063
|
+
["path", { d: "M12 12V8", key: "2874zd" }]
|
|
13064
|
+
]);
|
|
13021
13065
|
/**
|
|
13022
13066
|
* @license lucide-react v0.469.0 - ISC
|
|
13023
13067
|
*
|
|
@@ -13125,22 +13169,6 @@ const Send = createLucideIcon("Send", [
|
|
|
13125
13169
|
],
|
|
13126
13170
|
["path", { d: "m21.854 2.147-10.94 10.939", key: "12cjpa" }]
|
|
13127
13171
|
]);
|
|
13128
|
-
/**
|
|
13129
|
-
* @license lucide-react v0.469.0 - ISC
|
|
13130
|
-
*
|
|
13131
|
-
* This source code is licensed under the ISC license.
|
|
13132
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
13133
|
-
*/
|
|
13134
|
-
const Settings = createLucideIcon("Settings", [
|
|
13135
|
-
[
|
|
13136
|
-
"path",
|
|
13137
|
-
{
|
|
13138
|
-
d: "M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z",
|
|
13139
|
-
key: "1qme2f"
|
|
13140
|
-
}
|
|
13141
|
-
],
|
|
13142
|
-
["circle", { cx: "12", cy: "12", r: "3", key: "1v7zrd" }]
|
|
13143
|
-
]);
|
|
13144
13172
|
/**
|
|
13145
13173
|
* @license lucide-react v0.469.0 - ISC
|
|
13146
13174
|
*
|
|
@@ -13302,7 +13330,7 @@ const Zap = createLucideIcon("Zap", [
|
|
|
13302
13330
|
}
|
|
13303
13331
|
]
|
|
13304
13332
|
]);
|
|
13305
|
-
const api$
|
|
13333
|
+
const api$g = window.api;
|
|
13306
13334
|
const KEY_FIELDS = [
|
|
13307
13335
|
{
|
|
13308
13336
|
name: "ANTHROPIC_API_KEY",
|
|
@@ -13337,7 +13365,62 @@ const KEY_FIELDS = [
|
|
|
13337
13365
|
required: false
|
|
13338
13366
|
}
|
|
13339
13367
|
];
|
|
13340
|
-
function
|
|
13368
|
+
function UpdateBanner() {
|
|
13369
|
+
const [update, setUpdate] = reactExports.useState(null);
|
|
13370
|
+
const [dismissed, setDismissed] = reactExports.useState(false);
|
|
13371
|
+
const [copied, setCopied] = reactExports.useState(false);
|
|
13372
|
+
reactExports.useEffect(() => {
|
|
13373
|
+
api$g.checkForUpdate().then((info) => {
|
|
13374
|
+
if (info.hasUpdate) setUpdate(info);
|
|
13375
|
+
}).catch(() => {
|
|
13376
|
+
});
|
|
13377
|
+
}, []);
|
|
13378
|
+
if (!update || dismissed) return null;
|
|
13379
|
+
const command = "npm update -g research-copilot";
|
|
13380
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-4 relative rounded-lg border t-border-subtle t-bg-elevated overflow-hidden", children: [
|
|
13381
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { "aria-hidden": true, className: "absolute left-0 top-0 bottom-0 w-[2px] t-bg-accent-soft" }),
|
|
13382
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-3 py-2.5 flex items-start gap-2.5", children: [
|
|
13383
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(CircleArrowUp, { size: 15, className: "t-text-accent-soft mt-0.5 shrink-0" }),
|
|
13384
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
13385
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs font-medium t-text", children: [
|
|
13386
|
+
"v",
|
|
13387
|
+
update.latest,
|
|
13388
|
+
" available",
|
|
13389
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "t-text-secondary font-normal ml-1.5", children: [
|
|
13390
|
+
"(current: v",
|
|
13391
|
+
update.current,
|
|
13392
|
+
")"
|
|
13393
|
+
] })
|
|
13394
|
+
] }),
|
|
13395
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-1.5 flex items-center gap-1.5", children: [
|
|
13396
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "flex-1 text-[10px] font-mono px-2 py-1 rounded t-bg-surface t-text select-all", children: command }),
|
|
13397
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
13398
|
+
"button",
|
|
13399
|
+
{
|
|
13400
|
+
onClick: () => {
|
|
13401
|
+
navigator.clipboard.writeText(command);
|
|
13402
|
+
setCopied(true);
|
|
13403
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
13404
|
+
},
|
|
13405
|
+
className: "shrink-0 p-1 rounded t-bg-surface hover:opacity-80 transition-opacity",
|
|
13406
|
+
title: "Copy command",
|
|
13407
|
+
children: copied ? /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { size: 12, className: "t-text-success" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { size: 12, className: "t-text-secondary" })
|
|
13408
|
+
}
|
|
13409
|
+
)
|
|
13410
|
+
] })
|
|
13411
|
+
] }),
|
|
13412
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
13413
|
+
"button",
|
|
13414
|
+
{
|
|
13415
|
+
onClick: () => setDismissed(true),
|
|
13416
|
+
className: "shrink-0 p-0.5 rounded hover:t-bg-surface transition-colors t-text-secondary hover:t-text",
|
|
13417
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(X$1, { size: 12 })
|
|
13418
|
+
}
|
|
13419
|
+
)
|
|
13420
|
+
] })
|
|
13421
|
+
] });
|
|
13422
|
+
}
|
|
13423
|
+
function ApiKeysSettings({ showSaveButton, onSaved }) {
|
|
13341
13424
|
const [values, setValues] = reactExports.useState({});
|
|
13342
13425
|
const [status, setStatus] = reactExports.useState({});
|
|
13343
13426
|
const [visible, setVisible] = reactExports.useState({});
|
|
@@ -13346,14 +13429,14 @@ function ApiKeySetup({ onComplete }) {
|
|
|
13346
13429
|
const [codexStatus, setCodexStatus] = reactExports.useState(null);
|
|
13347
13430
|
const [codexLoggingIn, setCodexLoggingIn] = reactExports.useState(false);
|
|
13348
13431
|
reactExports.useEffect(() => {
|
|
13349
|
-
api$
|
|
13350
|
-
api$
|
|
13432
|
+
api$g.getApiKeyStatus().then((s15) => setStatus(s15));
|
|
13433
|
+
api$g.getOpenAICodexStatus?.().then((s15) => setCodexStatus(s15)).catch(() => {
|
|
13351
13434
|
});
|
|
13352
13435
|
}, []);
|
|
13353
13436
|
const handleCodexLogin = async () => {
|
|
13354
13437
|
setCodexLoggingIn(true);
|
|
13355
13438
|
try {
|
|
13356
|
-
const result = await api$
|
|
13439
|
+
const result = await api$g.openaiCodexLogin?.();
|
|
13357
13440
|
if (result?.success) {
|
|
13358
13441
|
setCodexStatus({ isLoggedIn: true });
|
|
13359
13442
|
} else {
|
|
@@ -13365,148 +13448,698 @@ function ApiKeySetup({ onComplete }) {
|
|
|
13365
13448
|
setCodexLoggingIn(false);
|
|
13366
13449
|
}
|
|
13367
13450
|
};
|
|
13368
|
-
const hasAnyLlmKey = status.ANTHROPIC_API_KEY || status.OPENAI_API_KEY || codexStatus?.isLoggedIn || !!(values.ANTHROPIC_API_KEY || "").trim() || !!(values.OPENAI_API_KEY || "").trim();
|
|
13369
13451
|
const handleSave = async () => {
|
|
13370
13452
|
const entries = Object.entries(values).filter(([, v3]) => v3.trim());
|
|
13371
13453
|
if (entries.length === 0 && !status.ANTHROPIC_API_KEY && !status.OPENAI_API_KEY && !codexStatus?.isLoggedIn) {
|
|
13372
|
-
setError("Please enter at least one API key or sign in with ChatGPT
|
|
13454
|
+
setError("Please enter at least one LLM API key or sign in with ChatGPT.");
|
|
13373
13455
|
return;
|
|
13374
13456
|
}
|
|
13375
13457
|
setSaving(true);
|
|
13376
13458
|
setError(null);
|
|
13377
13459
|
try {
|
|
13378
13460
|
for (const [key, val] of entries) {
|
|
13379
|
-
await api$
|
|
13461
|
+
await api$g.saveApiKey(key, val);
|
|
13380
13462
|
}
|
|
13381
|
-
|
|
13463
|
+
const newStatus = await api$g.getApiKeyStatus();
|
|
13464
|
+
setStatus(newStatus);
|
|
13465
|
+
setValues({});
|
|
13466
|
+
onSaved?.();
|
|
13382
13467
|
} catch (err) {
|
|
13383
13468
|
setError(err.message || "Failed to save keys");
|
|
13384
13469
|
} finally {
|
|
13385
13470
|
setSaving(false);
|
|
13386
13471
|
}
|
|
13387
13472
|
};
|
|
13388
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", {
|
|
13389
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
13390
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
13391
|
-
|
|
13392
|
-
|
|
13393
|
-
|
|
13394
|
-
{
|
|
13395
|
-
|
|
13396
|
-
|
|
13397
|
-
|
|
13398
|
-
|
|
13399
|
-
|
|
13400
|
-
|
|
13401
|
-
|
|
13402
|
-
|
|
13403
|
-
|
|
13404
|
-
|
|
13473
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
13474
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(UpdateBanner, {}),
|
|
13475
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-3", children: KEY_FIELDS.map((field) => {
|
|
13476
|
+
const alreadySet = status[field.name];
|
|
13477
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded-lg border t-border t-bg-surface/50 p-3", children: [
|
|
13478
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between mb-1.5", children: [
|
|
13479
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-xs font-medium t-text flex items-center gap-1.5", children: [
|
|
13480
|
+
field.label,
|
|
13481
|
+
field.required && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] t-text-muted", children: "(required*)" }),
|
|
13482
|
+
!field.required && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] t-text-muted", children: "(optional)" }),
|
|
13483
|
+
alreadySet && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-0.5 text-[10px] text-green-500", children: [
|
|
13484
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Check, { size: 10 }),
|
|
13485
|
+
" configured"
|
|
13486
|
+
] })
|
|
13487
|
+
] }),
|
|
13488
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
13489
|
+
"a",
|
|
13490
|
+
{
|
|
13491
|
+
href: field.url,
|
|
13492
|
+
target: "_blank",
|
|
13493
|
+
rel: "noreferrer",
|
|
13494
|
+
className: "text-[10px] t-text-muted hover:t-text flex items-center gap-0.5",
|
|
13495
|
+
onClick: (e) => {
|
|
13496
|
+
e.preventDefault();
|
|
13497
|
+
window.open(field.url, "_blank");
|
|
13498
|
+
},
|
|
13499
|
+
children: [
|
|
13500
|
+
"Get key ",
|
|
13501
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(ExternalLink, { size: 9 })
|
|
13502
|
+
]
|
|
13503
|
+
}
|
|
13504
|
+
)
|
|
13505
|
+
] }),
|
|
13506
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative", children: [
|
|
13507
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
13508
|
+
"input",
|
|
13509
|
+
{
|
|
13510
|
+
type: visible[field.name] ? "text" : "password",
|
|
13511
|
+
className: "w-full text-xs px-2.5 py-1.5 rounded-md border t-border t-bg-base t-text font-mono pr-8\n focus:outline-none focus:ring-1 focus:ring-[var(--color-accent)]",
|
|
13512
|
+
placeholder: alreadySet ? "•••••••• (already set — leave blank to keep)" : field.placeholder,
|
|
13513
|
+
value: values[field.name] || "",
|
|
13514
|
+
onChange: (e) => setValues((prev) => ({ ...prev, [field.name]: e.target.value })),
|
|
13515
|
+
"aria-label": `${field.label} API key`
|
|
13516
|
+
}
|
|
13517
|
+
),
|
|
13518
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
13519
|
+
"button",
|
|
13520
|
+
{
|
|
13521
|
+
type: "button",
|
|
13522
|
+
className: "absolute right-2 top-1/2 -translate-y-1/2 t-text-muted hover:t-text",
|
|
13523
|
+
onClick: () => setVisible((prev) => ({ ...prev, [field.name]: !prev[field.name] })),
|
|
13524
|
+
tabIndex: -1,
|
|
13525
|
+
children: visible[field.name] ? /* @__PURE__ */ jsxRuntimeExports.jsx(EyeOff, { size: 13 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Eye, { size: 13 })
|
|
13526
|
+
}
|
|
13527
|
+
)
|
|
13528
|
+
] }),
|
|
13529
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] t-text-muted mt-1", children: field.hint })
|
|
13530
|
+
] }, field.name);
|
|
13531
|
+
}) }),
|
|
13532
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded-lg border t-border t-bg-surface/50 p-3 mt-3", children: [
|
|
13533
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-between mb-1.5", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-xs font-medium t-text flex items-center gap-1.5", children: [
|
|
13534
|
+
"ChatGPT Subscription",
|
|
13535
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] t-text-muted", children: "(alternative to OpenAI API key)" }),
|
|
13536
|
+
codexStatus?.isLoggedIn && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-0.5 text-[10px] text-green-500", children: [
|
|
13537
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Check, { size: 10 }),
|
|
13538
|
+
" signed in"
|
|
13539
|
+
] })
|
|
13540
|
+
] }) }),
|
|
13541
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
13542
|
+
"button",
|
|
13543
|
+
{
|
|
13544
|
+
onClick: handleCodexLogin,
|
|
13545
|
+
disabled: codexLoggingIn || codexStatus?.isLoggedIn,
|
|
13546
|
+
className: "flex items-center gap-1.5 px-3 py-1.5 rounded-md border t-border text-xs t-text-secondary hover:t-text t-bg-hover disabled:opacity-50",
|
|
13547
|
+
children: [
|
|
13548
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(LogIn, { size: 12 }),
|
|
13549
|
+
codexLoggingIn ? "Signing in..." : codexStatus?.isLoggedIn ? "Already signed in" : "Sign in with ChatGPT"
|
|
13550
|
+
]
|
|
13551
|
+
}
|
|
13552
|
+
),
|
|
13553
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] t-text-muted mt-1", children: "Use your ChatGPT Plus/Pro subscription instead of an API key. No per-token billing." })
|
|
13554
|
+
] }),
|
|
13555
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] t-text-muted mt-2", children: "* At least one of Anthropic or OpenAI (API key or ChatGPT subscription) is required." }),
|
|
13556
|
+
error && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-red-400 mt-2", role: "alert", children: error }),
|
|
13557
|
+
showSaveButton && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-4 flex justify-end", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
13558
|
+
"button",
|
|
13559
|
+
{
|
|
13560
|
+
onClick: handleSave,
|
|
13561
|
+
disabled: saving,
|
|
13562
|
+
className: "px-4 py-1.5 rounded-md text-white text-[13px] font-medium hover:brightness-110 transition-[filter] duration-150 disabled:opacity-50 bg-[var(--color-accent)]",
|
|
13563
|
+
children: saving ? "Saving…" : "Save & Continue"
|
|
13564
|
+
}
|
|
13565
|
+
) })
|
|
13566
|
+
] });
|
|
13567
|
+
}
|
|
13568
|
+
function SegmentedControl({ options, value, onChange }) {
|
|
13569
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex rounded-lg border t-border overflow-hidden", children: options.map((opt) => {
|
|
13570
|
+
const active = opt.value === value;
|
|
13571
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
13572
|
+
"button",
|
|
13573
|
+
{
|
|
13574
|
+
onClick: () => onChange(opt.value),
|
|
13575
|
+
className: `flex-1 px-3 py-1.5 text-xs font-medium transition-colors
|
|
13576
|
+
${active ? "t-text-accent bg-[var(--color-accent)]/10" : "t-text-secondary hover:t-text hover:t-bg-hover"}
|
|
13577
|
+
`,
|
|
13578
|
+
children: opt.label
|
|
13579
|
+
},
|
|
13580
|
+
opt.value
|
|
13581
|
+
);
|
|
13582
|
+
}) });
|
|
13583
|
+
}
|
|
13584
|
+
function ResearchSettings({
|
|
13585
|
+
researchIntensity,
|
|
13586
|
+
webSearchDepth,
|
|
13587
|
+
autoSaveSensitivity,
|
|
13588
|
+
onChangeIntensity,
|
|
13589
|
+
onChangeWebDepth,
|
|
13590
|
+
onChangeAutoSave
|
|
13591
|
+
}) {
|
|
13592
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-6", children: [
|
|
13593
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
13594
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "text-xs font-semibold t-text mb-1.5", children: "Literature Search Intensity" }),
|
|
13595
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] t-text-muted mb-2.5", children: "Controls how many papers are fetched per source and how thoroughly results are reviewed." }),
|
|
13596
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
13597
|
+
SegmentedControl,
|
|
13598
|
+
{
|
|
13599
|
+
options: [
|
|
13600
|
+
{ label: "Low", value: "low" },
|
|
13601
|
+
{ label: "Medium", value: "medium" },
|
|
13602
|
+
{ label: "High", value: "high" }
|
|
13603
|
+
],
|
|
13604
|
+
value: researchIntensity,
|
|
13605
|
+
onChange: onChangeIntensity
|
|
13606
|
+
}
|
|
13607
|
+
),
|
|
13608
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[10px] t-text-muted mt-1.5", children: [
|
|
13609
|
+
researchIntensity === "low" && "Faster searches, fewer papers. Good for quick checks.",
|
|
13610
|
+
researchIntensity === "medium" && "Balanced coverage. Suitable for most research tasks.",
|
|
13611
|
+
researchIntensity === "high" && "Thorough searches with more papers per source. Best for comprehensive reviews."
|
|
13612
|
+
] })
|
|
13613
|
+
] }),
|
|
13614
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
13615
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "text-xs font-semibold t-text mb-1.5", children: "Web Search Depth" }),
|
|
13616
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] t-text-muted mb-2.5", children: "Controls the number of results and how much content is fetched from each page." }),
|
|
13617
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
13618
|
+
SegmentedControl,
|
|
13619
|
+
{
|
|
13620
|
+
options: [
|
|
13621
|
+
{ label: "Quick", value: "quick" },
|
|
13622
|
+
{ label: "Standard", value: "standard" },
|
|
13623
|
+
{ label: "Thorough", value: "thorough" }
|
|
13624
|
+
],
|
|
13625
|
+
value: webSearchDepth,
|
|
13626
|
+
onChange: onChangeWebDepth
|
|
13627
|
+
}
|
|
13628
|
+
),
|
|
13629
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[10px] t-text-muted mt-1.5", children: [
|
|
13630
|
+
webSearchDepth === "quick" && "Fewer results, smaller page fetches. Good for simple lookups.",
|
|
13631
|
+
webSearchDepth === "standard" && "Balanced results. Suitable for most searches.",
|
|
13632
|
+
webSearchDepth === "thorough" && "More results and larger page fetches. Best for deep research."
|
|
13633
|
+
] })
|
|
13634
|
+
] }),
|
|
13635
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
13636
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "text-xs font-semibold t-text mb-1.5", children: "Auto-Save Sensitivity" }),
|
|
13637
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] t-text-muted mb-2.5", children: "How aggressively papers are auto-saved to your library based on relevance scores." }),
|
|
13638
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
13639
|
+
SegmentedControl,
|
|
13640
|
+
{
|
|
13641
|
+
options: [
|
|
13642
|
+
{ label: "Conservative", value: "conservative" },
|
|
13643
|
+
{ label: "Balanced", value: "balanced" },
|
|
13644
|
+
{ label: "Aggressive", value: "aggressive" }
|
|
13645
|
+
],
|
|
13646
|
+
value: autoSaveSensitivity,
|
|
13647
|
+
onChange: onChangeAutoSave
|
|
13648
|
+
}
|
|
13649
|
+
),
|
|
13650
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[10px] t-text-muted mt-1.5", children: [
|
|
13651
|
+
autoSaveSensitivity === "conservative" && "Only saves highly relevant papers. Keeps your library focused.",
|
|
13652
|
+
autoSaveSensitivity === "balanced" && "Saves papers with good relevance. A sensible default.",
|
|
13653
|
+
autoSaveSensitivity === "aggressive" && "Saves more papers for broader coverage. May include tangential results."
|
|
13654
|
+
] })
|
|
13655
|
+
] })
|
|
13656
|
+
] });
|
|
13657
|
+
}
|
|
13658
|
+
function DataAnalysisSettings({ executionTimeLimit, onChange }) {
|
|
13659
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-6", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
13660
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "text-xs font-semibold t-text mb-1.5", children: "Execution Time Limit" }),
|
|
13661
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] t-text-muted mb-2.5", children: "Maximum time allowed for Python data analysis scripts to run before timeout." }),
|
|
13662
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
13663
|
+
SegmentedControl,
|
|
13664
|
+
{
|
|
13665
|
+
options: [
|
|
13666
|
+
{ label: "1 min", value: "short" },
|
|
13667
|
+
{ label: "2 min", value: "standard" },
|
|
13668
|
+
{ label: "5 min", value: "extended" },
|
|
13669
|
+
{ label: "10 min", value: "long" }
|
|
13670
|
+
],
|
|
13671
|
+
value: executionTimeLimit,
|
|
13672
|
+
onChange
|
|
13673
|
+
}
|
|
13674
|
+
),
|
|
13675
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[10px] t-text-muted mt-1.5", children: [
|
|
13676
|
+
executionTimeLimit === "short" && "Quick timeout for simple analyses.",
|
|
13677
|
+
executionTimeLimit === "standard" && "Suitable for most data analysis tasks.",
|
|
13678
|
+
executionTimeLimit === "extended" && "For larger datasets or complex computations.",
|
|
13679
|
+
executionTimeLimit === "long" && "For very large datasets or intensive modeling tasks."
|
|
13680
|
+
] })
|
|
13681
|
+
] }) });
|
|
13682
|
+
}
|
|
13683
|
+
const REASONING_MODELS = [
|
|
13684
|
+
"openai:gpt-5.4",
|
|
13685
|
+
"openai:gpt-5.4-mini",
|
|
13686
|
+
"openai:gpt-5.4-nano",
|
|
13687
|
+
"openai:gpt-5.4-pro",
|
|
13688
|
+
"openai-codex:gpt-5.4",
|
|
13689
|
+
"openai-codex:gpt-5.4-mini",
|
|
13690
|
+
"anthropic:claude-opus-4-6",
|
|
13691
|
+
"anthropic-sub:claude-opus-4-6"
|
|
13692
|
+
];
|
|
13693
|
+
const SUPPORTED_MODELS = [
|
|
13694
|
+
// OpenAI (API key)
|
|
13695
|
+
{ id: "openai:gpt-5.4", label: "GPT-5.4", provider: "OpenAI" },
|
|
13696
|
+
{ id: "openai:gpt-5.4-mini", label: "GPT-5.4 Mini", provider: "OpenAI" },
|
|
13697
|
+
{ id: "openai:gpt-5.4-nano", label: "GPT-5.4 Nano", provider: "OpenAI" },
|
|
13698
|
+
{ id: "openai:gpt-4o", label: "GPT-4o", provider: "OpenAI" },
|
|
13699
|
+
{ id: "openai:gpt-5.4-pro", label: "GPT-5.4 Pro", provider: "OpenAI" },
|
|
13700
|
+
// ChatGPT Subscription (OAuth) — only models registered in pi-ai's openai-codex provider
|
|
13701
|
+
{ id: "openai-codex:gpt-5.4", label: "GPT-5.4", provider: "ChatGPT Subscription" },
|
|
13702
|
+
{ id: "openai-codex:gpt-5.4-mini", label: "GPT-5.4 Mini", provider: "ChatGPT Subscription" },
|
|
13703
|
+
// Anthropic (API key)
|
|
13704
|
+
{ id: "anthropic:claude-opus-4-6", label: "Claude Opus 4.6", provider: "Anthropic" },
|
|
13705
|
+
{ id: "anthropic:claude-opus-4-5-20251101", label: "Claude Opus 4.5", provider: "Anthropic" },
|
|
13706
|
+
{ id: "anthropic:claude-sonnet-4-5-20250929", label: "Claude Sonnet 4.5", provider: "Anthropic" },
|
|
13707
|
+
{ id: "anthropic:claude-haiku-4-5-20251001", label: "Claude Haiku 4.5", provider: "Anthropic" },
|
|
13708
|
+
// Claude Subscription (OAuth) — enabled by default alongside ChatGPT Subscription
|
|
13709
|
+
{ id: "anthropic-sub:claude-opus-4-6", label: "Claude Opus 4.6", provider: "Claude Subscription" },
|
|
13710
|
+
{ id: "anthropic-sub:claude-opus-4-5-20251101", label: "Claude Opus 4.5", provider: "Claude Subscription" },
|
|
13711
|
+
{ id: "anthropic-sub:claude-sonnet-4-5-20250929", label: "Claude Sonnet 4.5", provider: "Claude Subscription" },
|
|
13712
|
+
{ id: "anthropic-sub:claude-haiku-4-5-20251001", label: "Claude Haiku 4.5", provider: "Claude Subscription" }
|
|
13713
|
+
];
|
|
13714
|
+
const DEFAULT_MODEL = "openai:gpt-5.4";
|
|
13715
|
+
const api$f = window.api;
|
|
13716
|
+
const SPEED_OPTIONS = [
|
|
13717
|
+
{ label: "Slow", value: "slow", desc: "Minimal resource usage. Best for subscription plans with tight limits." },
|
|
13718
|
+
{ label: "Medium", value: "medium", desc: "Balanced processing. Suitable for most users." },
|
|
13719
|
+
{ label: "Fast", value: "fast", desc: "Processes papers quickly when idle. Uses more API calls." }
|
|
13720
|
+
];
|
|
13721
|
+
const PROVIDER_ORDER$1 = [
|
|
13722
|
+
"ChatGPT Subscription",
|
|
13723
|
+
"Claude Subscription",
|
|
13724
|
+
"OpenAI",
|
|
13725
|
+
"Anthropic"
|
|
13726
|
+
];
|
|
13727
|
+
const MODEL_GROUPS = PROVIDER_ORDER$1.map((p) => [p, SUPPORTED_MODELS.filter((m) => m.provider === p)]).filter(([, models]) => models.length > 0);
|
|
13728
|
+
function isSubProvider(providerId) {
|
|
13729
|
+
return providerId === "anthropic-sub" || providerId === "openai-codex";
|
|
13730
|
+
}
|
|
13731
|
+
function providerOf(modelId) {
|
|
13732
|
+
const i = modelId.indexOf(":");
|
|
13733
|
+
return i > 0 ? modelId.slice(0, i) : "";
|
|
13734
|
+
}
|
|
13735
|
+
function labelFor(modelId) {
|
|
13736
|
+
const m = SUPPORTED_MODELS.find((x) => x.id === modelId);
|
|
13737
|
+
if (!m) return modelId;
|
|
13738
|
+
const suffix2 = isSubProvider(providerOf(modelId)) ? " (sub)" : " (api)";
|
|
13739
|
+
return m.label + suffix2;
|
|
13740
|
+
}
|
|
13741
|
+
function WikiAgentSettings({ model, speed, onChangeModel, onChangeSpeed }) {
|
|
13742
|
+
const [status, setStatus] = reactExports.useState(null);
|
|
13743
|
+
const [stats, setStats] = reactExports.useState(null);
|
|
13744
|
+
const [recentLog, setRecentLog] = reactExports.useState([]);
|
|
13745
|
+
const [autoResolved, setAutoResolved] = reactExports.useState(null);
|
|
13746
|
+
reactExports.useEffect(() => {
|
|
13747
|
+
api$f.wikiGetStatus?.().then((s15) => setStatus(s15)).catch(() => {
|
|
13748
|
+
});
|
|
13749
|
+
api$f.wikiGetStats?.().then((s15) => setStats(s15)).catch(() => {
|
|
13750
|
+
});
|
|
13751
|
+
api$f.wikiGetLog?.().then((l2) => setRecentLog(l2 || [])).catch(() => {
|
|
13752
|
+
});
|
|
13753
|
+
const unsub = api$f.onWikiStatus?.((s15) => setStatus(s15));
|
|
13754
|
+
return () => unsub?.();
|
|
13755
|
+
}, []);
|
|
13756
|
+
reactExports.useEffect(() => {
|
|
13757
|
+
if (model !== "auto") {
|
|
13758
|
+
setAutoResolved(null);
|
|
13759
|
+
return;
|
|
13760
|
+
}
|
|
13761
|
+
let cancelled = false;
|
|
13762
|
+
api$f.pickPreferredModel?.().then((m) => {
|
|
13763
|
+
if (!cancelled) setAutoResolved(m);
|
|
13764
|
+
}).catch(() => {
|
|
13765
|
+
if (!cancelled) setAutoResolved(null);
|
|
13766
|
+
});
|
|
13767
|
+
return () => {
|
|
13768
|
+
cancelled = true;
|
|
13769
|
+
};
|
|
13770
|
+
}, [model]);
|
|
13771
|
+
const enabled = model !== "none";
|
|
13772
|
+
const speedDesc = SPEED_OPTIONS.find((o2) => o2.value === speed)?.desc || "";
|
|
13773
|
+
const runningModelLabel = reactExports.useMemo(() => {
|
|
13774
|
+
if (model === "auto") {
|
|
13775
|
+
return autoResolved ? `Auto → ${labelFor(autoResolved)}` : "Auto (no auth configured)";
|
|
13776
|
+
}
|
|
13777
|
+
return labelFor(model);
|
|
13778
|
+
}, [model, autoResolved]);
|
|
13779
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-6", children: [
|
|
13780
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded-lg border border-amber-500/40 bg-amber-500/10 p-3 flex gap-2.5", children: [
|
|
13781
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TriangleAlert, { size: 14, className: "shrink-0 mt-0.5 text-amber-500" }),
|
|
13782
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [
|
|
13783
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] font-semibold t-text", children: "Heads up: background token usage" }),
|
|
13784
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[11px] t-text-muted leading-relaxed", children: [
|
|
13785
|
+
"The Paper Wiki runs in the background and sends every new paper through an LLM (intro + abstract + full text if available). A typical paper consumes roughly",
|
|
13786
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text", children: " 8K–25K input tokens" }),
|
|
13787
|
+
" and produces",
|
|
13788
|
+
" ",
|
|
13789
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text", children: "2K–4K output tokens" }),
|
|
13790
|
+
", plus concept-page updates. Across a full library this can add up to ",
|
|
13791
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text", children: "several dollars per day" }),
|
|
13792
|
+
" on API-key billing. ",
|
|
13793
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "It is disabled by default" }),
|
|
13794
|
+
" — enable it below only after you've picked a model you're comfortable paying for, and prefer a subscription plan or a smaller/cheaper model for background work."
|
|
13405
13795
|
] })
|
|
13796
|
+
] })
|
|
13797
|
+
] }),
|
|
13798
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
13799
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "text-xs font-semibold t-text mb-1.5", children: "Wiki Agent Model" }),
|
|
13800
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[11px] t-text-muted mb-2.5", children: [
|
|
13801
|
+
"Select a model to power the background Paper Wiki agent. The wiki accumulates LLM-generated summaries of papers across all your projects. A smaller model is recommended for background processing. Pick ",
|
|
13802
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("em", { children: "Auto" }),
|
|
13803
|
+
" to follow the system-wide model priority (subscription before API key)."
|
|
13406
13804
|
] }),
|
|
13407
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
13408
|
-
|
|
13409
|
-
|
|
13410
|
-
|
|
13411
|
-
|
|
13412
|
-
|
|
13413
|
-
|
|
13414
|
-
|
|
13415
|
-
|
|
13416
|
-
|
|
13417
|
-
|
|
13418
|
-
|
|
13419
|
-
|
|
13420
|
-
|
|
13421
|
-
|
|
13422
|
-
|
|
13423
|
-
|
|
13424
|
-
|
|
13425
|
-
|
|
13426
|
-
|
|
13427
|
-
|
|
13428
|
-
|
|
13429
|
-
window.open(field.url, "_blank");
|
|
13430
|
-
},
|
|
13431
|
-
children: [
|
|
13432
|
-
"Get key ",
|
|
13433
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(ExternalLink, { size: 9 })
|
|
13434
|
-
]
|
|
13435
|
-
}
|
|
13436
|
-
)
|
|
13437
|
-
] }),
|
|
13438
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative", children: [
|
|
13439
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
13440
|
-
"input",
|
|
13441
|
-
{
|
|
13442
|
-
type: visible[field.name] ? "text" : "password",
|
|
13443
|
-
className: "w-full text-xs px-2.5 py-1.5 rounded-md border t-border t-bg-base t-text font-mono pr-8\n focus:outline-none focus:ring-1 focus:ring-[var(--color-accent)]",
|
|
13444
|
-
placeholder: alreadySet ? "•••••••• (already set — leave blank to keep)" : field.placeholder,
|
|
13445
|
-
value: values[field.name] || "",
|
|
13446
|
-
onChange: (e) => setValues((prev) => ({ ...prev, [field.name]: e.target.value })),
|
|
13447
|
-
"aria-label": `${field.label} API key`
|
|
13448
|
-
}
|
|
13449
|
-
),
|
|
13450
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
13451
|
-
"button",
|
|
13452
|
-
{
|
|
13453
|
-
type: "button",
|
|
13454
|
-
className: "absolute right-2 top-1/2 -translate-y-1/2 t-text-muted hover:t-text",
|
|
13455
|
-
onClick: () => setVisible((prev) => ({ ...prev, [field.name]: !prev[field.name] })),
|
|
13456
|
-
tabIndex: -1,
|
|
13457
|
-
children: visible[field.name] ? /* @__PURE__ */ jsxRuntimeExports.jsx(EyeOff, { size: 13 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Eye, { size: 13 })
|
|
13458
|
-
}
|
|
13459
|
-
)
|
|
13460
|
-
] }),
|
|
13461
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] t-text-muted mt-1", children: field.hint })
|
|
13462
|
-
] }, field.name);
|
|
13463
|
-
}) }),
|
|
13464
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded-lg border t-border t-bg-surface/50 p-3", children: [
|
|
13465
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-between mb-1.5", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-xs font-medium t-text flex items-center gap-1.5", children: [
|
|
13466
|
-
"ChatGPT Subscription",
|
|
13467
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] t-text-muted", children: "(alternative to OpenAI API key)" }),
|
|
13468
|
-
codexStatus?.isLoggedIn && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-0.5 text-[10px] text-green-500", children: [
|
|
13469
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Check, { size: 10 }),
|
|
13470
|
-
" signed in"
|
|
13471
|
-
] })
|
|
13472
|
-
] }) }),
|
|
13473
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
13474
|
-
"button",
|
|
13475
|
-
{
|
|
13476
|
-
onClick: handleCodexLogin,
|
|
13477
|
-
disabled: codexLoggingIn || codexStatus?.isLoggedIn,
|
|
13478
|
-
className: "flex items-center gap-1.5 px-3 py-1.5 rounded-md border t-border text-xs t-text-secondary hover:t-text t-bg-hover disabled:opacity-50",
|
|
13479
|
-
children: [
|
|
13480
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(LogIn, { size: 12 }),
|
|
13481
|
-
codexLoggingIn ? "Signing in..." : codexStatus?.isLoggedIn ? "Already signed in" : "Sign in with ChatGPT"
|
|
13482
|
-
]
|
|
13483
|
-
}
|
|
13484
|
-
),
|
|
13485
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] t-text-muted mt-1", children: "Use your ChatGPT Plus/Pro subscription instead of an API key. No per-token billing." })
|
|
13805
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
13806
|
+
"select",
|
|
13807
|
+
{
|
|
13808
|
+
value: model,
|
|
13809
|
+
onChange: (e) => onChangeModel(e.target.value),
|
|
13810
|
+
className: "w-full px-3 py-1.5 rounded-lg border t-border t-bg-base t-text text-xs",
|
|
13811
|
+
children: [
|
|
13812
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "none", children: "None (disabled — default)" }),
|
|
13813
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "auto", children: "Auto (match main model priority)" }),
|
|
13814
|
+
MODEL_GROUPS.map(([provider, models]) => /* @__PURE__ */ jsxRuntimeExports.jsx("optgroup", { label: provider, children: models.map((m) => {
|
|
13815
|
+
const suffix2 = isSubProvider(providerOf(m.id)) ? " (sub)" : " (api)";
|
|
13816
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("option", { value: m.id, children: [
|
|
13817
|
+
m.label,
|
|
13818
|
+
suffix2
|
|
13819
|
+
] }, m.id);
|
|
13820
|
+
}) }, provider))
|
|
13821
|
+
]
|
|
13822
|
+
}
|
|
13823
|
+
),
|
|
13824
|
+
enabled && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[10px] t-text-muted mt-1.5", children: [
|
|
13825
|
+
"Running: ",
|
|
13826
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text", children: runningModelLabel })
|
|
13486
13827
|
] }),
|
|
13487
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[
|
|
13488
|
-
|
|
13828
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] t-text-muted mt-1.5 italic", children: "Changes take effect after app restart." })
|
|
13829
|
+
] }),
|
|
13830
|
+
enabled && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
13831
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "text-xs font-semibold t-text mb-1.5", children: "Processing Speed" }),
|
|
13832
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
13833
|
+
SegmentedControl,
|
|
13834
|
+
{
|
|
13835
|
+
options: SPEED_OPTIONS,
|
|
13836
|
+
value: speed,
|
|
13837
|
+
onChange: onChangeSpeed
|
|
13838
|
+
}
|
|
13839
|
+
),
|
|
13840
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] t-text-muted mt-2", children: speedDesc })
|
|
13841
|
+
] }),
|
|
13842
|
+
enabled && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded-lg border t-border t-bg-surface/50 p-3 space-y-3", children: [
|
|
13489
13843
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
13490
|
-
|
|
13844
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "text-xs font-semibold t-text", children: "Status" }),
|
|
13845
|
+
status?.state && status.state !== "disabled" && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
13491
13846
|
"button",
|
|
13492
13847
|
{
|
|
13493
|
-
onClick:
|
|
13494
|
-
|
|
13495
|
-
|
|
13496
|
-
|
|
13497
|
-
|
|
13498
|
-
|
|
13499
|
-
|
|
13500
|
-
|
|
13501
|
-
|
|
13502
|
-
onClick: handleSave,
|
|
13503
|
-
disabled: saving,
|
|
13504
|
-
className: "px-5 py-2 rounded-lg text-white text-sm font-medium hover:opacity-90 transition-all duration-200 disabled:opacity-50 t-gradient-accent t-gradient-accent-shadow",
|
|
13505
|
-
children: saving ? "Saving..." : hasAnyLlmKey ? "Save & Continue" : "Save & Continue"
|
|
13848
|
+
onClick: () => {
|
|
13849
|
+
if (status.state === "paused") {
|
|
13850
|
+
api$f.wikiResume?.();
|
|
13851
|
+
} else {
|
|
13852
|
+
api$f.wikiPause?.();
|
|
13853
|
+
}
|
|
13854
|
+
},
|
|
13855
|
+
className: "px-2.5 py-1 rounded-md border t-border t-bg-base t-text text-[11px] font-medium hover:t-bg-hover transition-colors",
|
|
13856
|
+
children: status.state === "paused" ? "Resume" : "Pause"
|
|
13506
13857
|
}
|
|
13507
13858
|
)
|
|
13859
|
+
] }),
|
|
13860
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-[auto_1fr] gap-x-4 gap-y-1 text-[11px]", children: [
|
|
13861
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-muted", children: "State:" }),
|
|
13862
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "t-text flex items-center gap-1.5", children: [
|
|
13863
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `inline-block w-1.5 h-1.5 rounded-full ${status?.state === "processing" ? "bg-blue-500" : status?.state === "idle" ? "bg-green-500" : status?.state === "paused" ? "bg-yellow-500" : "bg-gray-400"}` }),
|
|
13864
|
+
status?.state === "processing" ? `Processing (${status?.pending ?? 0} pending)` : status?.state ?? "Disabled"
|
|
13865
|
+
] }),
|
|
13866
|
+
stats && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
13867
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-muted", children: "Papers:" }),
|
|
13868
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "t-text", children: [
|
|
13869
|
+
stats.papers,
|
|
13870
|
+
" in wiki (",
|
|
13871
|
+
stats.fulltext,
|
|
13872
|
+
" fulltext, ",
|
|
13873
|
+
stats.abstractOnly,
|
|
13874
|
+
" abstract)"
|
|
13875
|
+
] }),
|
|
13876
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-muted", children: "Concepts:" }),
|
|
13877
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "t-text", children: [
|
|
13878
|
+
stats.concepts,
|
|
13879
|
+
" pages"
|
|
13880
|
+
] })
|
|
13881
|
+
] }),
|
|
13882
|
+
status?.lastRunAt && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
13883
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-muted", children: "Last run:" }),
|
|
13884
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text", children: formatRelativeTime(status.lastRunAt) })
|
|
13885
|
+
] })
|
|
13886
|
+
] }),
|
|
13887
|
+
recentLog.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
13888
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h5", { className: "text-[11px] font-medium t-text-muted mb-1", children: "Recent Activity" }),
|
|
13889
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-0.5 max-h-32 overflow-y-auto", children: recentLog.slice(0, 10).map((entry, i) => /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] t-text-muted font-mono leading-relaxed truncate", children: entry }, i)) })
|
|
13508
13890
|
] })
|
|
13509
|
-
] })
|
|
13891
|
+
] }),
|
|
13892
|
+
!enabled && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "rounded-lg border t-border t-bg-surface/50 p-3", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[11px] t-text-muted", children: [
|
|
13893
|
+
"The wiki agent is disabled. Select a model above to enable cross-project paper memory. Papers from all your projects are accumulated into a searchable local memory accessible via ",
|
|
13894
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "font-mono", children: "wiki_search" }),
|
|
13895
|
+
",",
|
|
13896
|
+
" ",
|
|
13897
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "font-mono", children: "wiki_get" }),
|
|
13898
|
+
", ",
|
|
13899
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "font-mono", children: "wiki_coverage" }),
|
|
13900
|
+
", and ",
|
|
13901
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "font-mono", children: "wiki_source" }),
|
|
13902
|
+
" — the wiki is a research memory layer, not a fact oracle."
|
|
13903
|
+
] }) })
|
|
13904
|
+
] });
|
|
13905
|
+
}
|
|
13906
|
+
function formatRelativeTime(isoString) {
|
|
13907
|
+
const diff = Date.now() - new Date(isoString).getTime();
|
|
13908
|
+
const mins = Math.floor(diff / 6e4);
|
|
13909
|
+
if (mins < 1) return "just now";
|
|
13910
|
+
if (mins < 60) return `${mins} minute${mins > 1 ? "s" : ""} ago`;
|
|
13911
|
+
const hours = Math.floor(mins / 60);
|
|
13912
|
+
if (hours < 24) return `${hours} hour${hours > 1 ? "s" : ""} ago`;
|
|
13913
|
+
return new Date(isoString).toLocaleDateString();
|
|
13914
|
+
}
|
|
13915
|
+
const DEFAULT_SETTINGS = {
|
|
13916
|
+
research: {
|
|
13917
|
+
researchIntensity: "medium",
|
|
13918
|
+
webSearchDepth: "standard",
|
|
13919
|
+
autoSaveSensitivity: "balanced"
|
|
13920
|
+
},
|
|
13921
|
+
dataAnalysis: {
|
|
13922
|
+
executionTimeLimit: "standard"
|
|
13923
|
+
},
|
|
13924
|
+
wikiAgent: {
|
|
13925
|
+
model: "none",
|
|
13926
|
+
speed: "medium"
|
|
13927
|
+
}
|
|
13928
|
+
};
|
|
13929
|
+
const api$e = window.api;
|
|
13930
|
+
const TABS = [
|
|
13931
|
+
{ id: "api-keys", label: "API Keys", icon: Key },
|
|
13932
|
+
{ id: "research", label: "Research", icon: BookOpen },
|
|
13933
|
+
{ id: "data-analysis", label: "Data Analysis", icon: ChartNoAxesColumn },
|
|
13934
|
+
{ id: "paper-wiki", label: "Paper Wiki", icon: BookMarked }
|
|
13935
|
+
];
|
|
13936
|
+
const FOCUSABLE_SELECTOR = [
|
|
13937
|
+
"button:not([disabled])",
|
|
13938
|
+
"[href]",
|
|
13939
|
+
"input:not([disabled])",
|
|
13940
|
+
"select:not([disabled])",
|
|
13941
|
+
"textarea:not([disabled])",
|
|
13942
|
+
'[tabindex]:not([tabindex="-1"])'
|
|
13943
|
+
].join(",");
|
|
13944
|
+
function getVisibleFocusable(root2) {
|
|
13945
|
+
return Array.from(root2.querySelectorAll(FOCUSABLE_SELECTOR)).filter((el2) => el2.offsetParent !== null);
|
|
13946
|
+
}
|
|
13947
|
+
function SettingsModal({ open, onClose, initialTab }) {
|
|
13948
|
+
const [activeTab, setActiveTab] = reactExports.useState(initialTab ?? "api-keys");
|
|
13949
|
+
const [settings, setSettings] = reactExports.useState(DEFAULT_SETTINGS);
|
|
13950
|
+
const [loaded, setLoaded] = reactExports.useState(false);
|
|
13951
|
+
const [dirty, setDirty] = reactExports.useState(false);
|
|
13952
|
+
const panelRef = reactExports.useRef(null);
|
|
13953
|
+
reactExports.useEffect(() => {
|
|
13954
|
+
if (open && initialTab) {
|
|
13955
|
+
setActiveTab(initialTab);
|
|
13956
|
+
}
|
|
13957
|
+
}, [open, initialTab]);
|
|
13958
|
+
reactExports.useEffect(() => {
|
|
13959
|
+
if (!open) return;
|
|
13960
|
+
api$e.loadSettings?.().then((s15) => {
|
|
13961
|
+
if (s15) setSettings(s15);
|
|
13962
|
+
setLoaded(true);
|
|
13963
|
+
setDirty(false);
|
|
13964
|
+
}).catch(() => setLoaded(true));
|
|
13965
|
+
}, [open]);
|
|
13966
|
+
reactExports.useEffect(() => {
|
|
13967
|
+
if (!open) return;
|
|
13968
|
+
const trigger = document.activeElement;
|
|
13969
|
+
const frame = requestAnimationFrame(() => {
|
|
13970
|
+
const panel = panelRef.current;
|
|
13971
|
+
if (!panel) return;
|
|
13972
|
+
const focusable = getVisibleFocusable(panel);
|
|
13973
|
+
const first = focusable[0] ?? panel;
|
|
13974
|
+
first.focus();
|
|
13975
|
+
});
|
|
13976
|
+
return () => {
|
|
13977
|
+
cancelAnimationFrame(frame);
|
|
13978
|
+
if (trigger && document.contains(trigger)) {
|
|
13979
|
+
trigger.focus?.();
|
|
13980
|
+
}
|
|
13981
|
+
};
|
|
13982
|
+
}, [open]);
|
|
13983
|
+
reactExports.useEffect(() => {
|
|
13984
|
+
if (!open) return;
|
|
13985
|
+
const handleKey = (e) => {
|
|
13986
|
+
if (e.key === "Escape") {
|
|
13987
|
+
e.preventDefault();
|
|
13988
|
+
e.stopPropagation();
|
|
13989
|
+
onClose();
|
|
13990
|
+
return;
|
|
13991
|
+
}
|
|
13992
|
+
if (e.key !== "Tab") return;
|
|
13993
|
+
const panel = panelRef.current;
|
|
13994
|
+
if (!panel) return;
|
|
13995
|
+
const focusable = getVisibleFocusable(panel);
|
|
13996
|
+
if (focusable.length === 0) {
|
|
13997
|
+
e.preventDefault();
|
|
13998
|
+
panel.focus();
|
|
13999
|
+
return;
|
|
14000
|
+
}
|
|
14001
|
+
const first = focusable[0];
|
|
14002
|
+
const last = focusable[focusable.length - 1];
|
|
14003
|
+
const active = document.activeElement;
|
|
14004
|
+
if (!active || !panel.contains(active)) {
|
|
14005
|
+
e.preventDefault();
|
|
14006
|
+
first.focus();
|
|
14007
|
+
return;
|
|
14008
|
+
}
|
|
14009
|
+
if (e.shiftKey && active === first) {
|
|
14010
|
+
e.preventDefault();
|
|
14011
|
+
last.focus();
|
|
14012
|
+
} else if (!e.shiftKey && active === last) {
|
|
14013
|
+
e.preventDefault();
|
|
14014
|
+
first.focus();
|
|
14015
|
+
}
|
|
14016
|
+
};
|
|
14017
|
+
window.addEventListener("keydown", handleKey, true);
|
|
14018
|
+
return () => window.removeEventListener("keydown", handleKey, true);
|
|
14019
|
+
}, [open, onClose]);
|
|
14020
|
+
const updateSettings = (patch2) => {
|
|
14021
|
+
setSettings((prev) => {
|
|
14022
|
+
const next = { ...prev, ...patch2 };
|
|
14023
|
+
if (patch2.research) next.research = { ...prev.research, ...patch2.research };
|
|
14024
|
+
if (patch2.dataAnalysis) next.dataAnalysis = { ...prev.dataAnalysis, ...patch2.dataAnalysis };
|
|
14025
|
+
if (patch2.wikiAgent) next.wikiAgent = { ...prev.wikiAgent, ...patch2.wikiAgent };
|
|
14026
|
+
return next;
|
|
14027
|
+
});
|
|
14028
|
+
setDirty(true);
|
|
14029
|
+
};
|
|
14030
|
+
reactExports.useEffect(() => {
|
|
14031
|
+
if (!dirty || !loaded) return;
|
|
14032
|
+
const timer = setTimeout(() => {
|
|
14033
|
+
api$e.saveSettings?.(settings).catch(() => {
|
|
14034
|
+
});
|
|
14035
|
+
setDirty(false);
|
|
14036
|
+
}, 300);
|
|
14037
|
+
return () => clearTimeout(timer);
|
|
14038
|
+
}, [settings, dirty, loaded]);
|
|
14039
|
+
if (!open) return null;
|
|
14040
|
+
const activeLabel = TABS.find((t) => t.id === activeTab)?.label ?? "Settings";
|
|
14041
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "fixed inset-0 z-[60] flex items-center justify-center", children: [
|
|
14042
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute inset-0 bg-black/40", "aria-hidden": "true" }),
|
|
14043
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
14044
|
+
"div",
|
|
14045
|
+
{
|
|
14046
|
+
ref: panelRef,
|
|
14047
|
+
role: "dialog",
|
|
14048
|
+
"aria-modal": "true",
|
|
14049
|
+
"aria-labelledby": "settings-dialog-title",
|
|
14050
|
+
tabIndex: -1,
|
|
14051
|
+
className: "relative w-full max-w-2xl h-[520px] rounded-xl border t-border t-bg-surface shadow-xl flex overflow-hidden outline-none",
|
|
14052
|
+
children: [
|
|
14053
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
14054
|
+
"nav",
|
|
14055
|
+
{
|
|
14056
|
+
"aria-label": "Settings categories",
|
|
14057
|
+
className: "w-48 shrink-0 border-r t-border t-bg-base flex flex-col py-4 px-2",
|
|
14058
|
+
children: [
|
|
14059
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14060
|
+
"h1",
|
|
14061
|
+
{
|
|
14062
|
+
id: "settings-dialog-title",
|
|
14063
|
+
className: "px-3 mb-3 text-sm font-semibold t-text tracking-tight",
|
|
14064
|
+
children: "Settings"
|
|
14065
|
+
}
|
|
14066
|
+
),
|
|
14067
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-0.5", children: TABS.map((tab2) => {
|
|
14068
|
+
const Icon2 = tab2.icon;
|
|
14069
|
+
const active = activeTab === tab2.id;
|
|
14070
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
14071
|
+
"button",
|
|
14072
|
+
{
|
|
14073
|
+
onClick: () => setActiveTab(tab2.id),
|
|
14074
|
+
"aria-current": active ? "page" : void 0,
|
|
14075
|
+
className: `w-full flex items-center gap-2 px-3 py-1.5 rounded-lg text-xs font-medium transition-colors
|
|
14076
|
+
${active ? "t-text-accent bg-[var(--color-accent)]/10" : "t-text-secondary hover:t-text hover:t-bg-hover"}
|
|
14077
|
+
`,
|
|
14078
|
+
children: [
|
|
14079
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Icon2, { size: 14 }),
|
|
14080
|
+
tab2.label
|
|
14081
|
+
]
|
|
14082
|
+
},
|
|
14083
|
+
tab2.id
|
|
14084
|
+
);
|
|
14085
|
+
}) }),
|
|
14086
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1" }),
|
|
14087
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "px-3 text-[10px] t-text-muted leading-relaxed", children: [
|
|
14088
|
+
"Keys are stored in",
|
|
14089
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("br", {}),
|
|
14090
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "font-mono", children: "~/.research-copilot/" })
|
|
14091
|
+
] })
|
|
14092
|
+
]
|
|
14093
|
+
}
|
|
14094
|
+
),
|
|
14095
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex flex-col min-w-0", children: [
|
|
14096
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between px-6 pt-4 pb-2", children: [
|
|
14097
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-sm font-semibold t-text", children: activeLabel }),
|
|
14098
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14099
|
+
"button",
|
|
14100
|
+
{
|
|
14101
|
+
onClick: onClose,
|
|
14102
|
+
className: "p-1.5 rounded-lg t-text-muted hover:t-text hover:t-bg-hover transition-colors",
|
|
14103
|
+
"aria-label": "Close settings",
|
|
14104
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(X$1, { size: 16 })
|
|
14105
|
+
}
|
|
14106
|
+
)
|
|
14107
|
+
] }),
|
|
14108
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 overflow-y-auto px-6 pb-4", children: [
|
|
14109
|
+
activeTab === "api-keys" && /* @__PURE__ */ jsxRuntimeExports.jsx(ApiKeysSettings, {}),
|
|
14110
|
+
activeTab === "research" && loaded && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14111
|
+
ResearchSettings,
|
|
14112
|
+
{
|
|
14113
|
+
researchIntensity: settings.research.researchIntensity,
|
|
14114
|
+
webSearchDepth: settings.research.webSearchDepth,
|
|
14115
|
+
autoSaveSensitivity: settings.research.autoSaveSensitivity,
|
|
14116
|
+
onChangeIntensity: (v3) => updateSettings({ research: { ...settings.research, researchIntensity: v3 } }),
|
|
14117
|
+
onChangeWebDepth: (v3) => updateSettings({ research: { ...settings.research, webSearchDepth: v3 } }),
|
|
14118
|
+
onChangeAutoSave: (v3) => updateSettings({ research: { ...settings.research, autoSaveSensitivity: v3 } })
|
|
14119
|
+
}
|
|
14120
|
+
),
|
|
14121
|
+
activeTab === "data-analysis" && loaded && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14122
|
+
DataAnalysisSettings,
|
|
14123
|
+
{
|
|
14124
|
+
executionTimeLimit: settings.dataAnalysis.executionTimeLimit,
|
|
14125
|
+
onChange: (v3) => updateSettings({ dataAnalysis: { executionTimeLimit: v3 } })
|
|
14126
|
+
}
|
|
14127
|
+
),
|
|
14128
|
+
activeTab === "paper-wiki" && loaded && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14129
|
+
WikiAgentSettings,
|
|
14130
|
+
{
|
|
14131
|
+
model: settings.wikiAgent?.model ?? "none",
|
|
14132
|
+
speed: settings.wikiAgent?.speed ?? "medium",
|
|
14133
|
+
onChangeModel: (v3) => updateSettings({ wikiAgent: { ...settings.wikiAgent, model: v3 } }),
|
|
14134
|
+
onChangeSpeed: (v3) => updateSettings({ wikiAgent: { ...settings.wikiAgent, speed: v3 } })
|
|
14135
|
+
}
|
|
14136
|
+
)
|
|
14137
|
+
] }),
|
|
14138
|
+
activeTab !== "api-keys" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-6 py-2.5 border-t t-border-subtle", children: /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] t-text-muted", children: "Settings are saved automatically. Changes to research and analysis settings take effect for new agent sessions. Existing sessions require an app restart." }) })
|
|
14139
|
+
] })
|
|
14140
|
+
]
|
|
14141
|
+
}
|
|
14142
|
+
)
|
|
13510
14143
|
] });
|
|
13511
14144
|
}
|
|
13512
14145
|
const createStoreImpl = (createState2) => {
|
|
@@ -13548,32 +14181,6 @@ const createImpl = (createState2) => {
|
|
|
13548
14181
|
return useBoundStore;
|
|
13549
14182
|
};
|
|
13550
14183
|
const create$1 = (createState2) => createState2 ? createImpl(createState2) : createImpl;
|
|
13551
|
-
const REASONING_MODELS = [
|
|
13552
|
-
"openai:gpt-5.4",
|
|
13553
|
-
"openai:gpt-5.4-mini",
|
|
13554
|
-
"openai:gpt-5.4-nano",
|
|
13555
|
-
"openai:gpt-5.4-pro",
|
|
13556
|
-
"openai-codex:gpt-5.4",
|
|
13557
|
-
"openai-codex:gpt-5.4-mini",
|
|
13558
|
-
"anthropic:claude-opus-4-6"
|
|
13559
|
-
];
|
|
13560
|
-
const SUPPORTED_MODELS = [
|
|
13561
|
-
// OpenAI (API key)
|
|
13562
|
-
{ id: "openai:gpt-5.4", label: "GPT-5.4", provider: "OpenAI" },
|
|
13563
|
-
{ id: "openai:gpt-5.4-mini", label: "GPT-5.4 Mini", provider: "OpenAI" },
|
|
13564
|
-
{ id: "openai:gpt-5.4-nano", label: "GPT-5.4 Nano", provider: "OpenAI" },
|
|
13565
|
-
{ id: "openai:gpt-4o", label: "GPT-4o", provider: "OpenAI" },
|
|
13566
|
-
{ id: "openai:gpt-5.4-pro", label: "GPT-5.4 Pro", provider: "OpenAI" },
|
|
13567
|
-
// ChatGPT Subscription (OAuth) — only models registered in pi-ai's openai-codex provider
|
|
13568
|
-
{ id: "openai-codex:gpt-5.4", label: "GPT-5.4", provider: "ChatGPT Subscription" },
|
|
13569
|
-
{ id: "openai-codex:gpt-5.4-mini", label: "GPT-5.4 Mini", provider: "ChatGPT Subscription" },
|
|
13570
|
-
// Anthropic (API key)
|
|
13571
|
-
{ id: "anthropic:claude-opus-4-6", label: "Claude Opus 4.6", provider: "Anthropic" },
|
|
13572
|
-
{ id: "anthropic:claude-opus-4-5-20251101", label: "Claude Opus 4.5", provider: "Anthropic" },
|
|
13573
|
-
{ id: "anthropic:claude-sonnet-4-5-20250929", label: "Claude Sonnet 4.5", provider: "Anthropic" },
|
|
13574
|
-
{ id: "anthropic:claude-haiku-4-5-20251001", label: "Claude Haiku 4.5", provider: "Anthropic" }
|
|
13575
|
-
];
|
|
13576
|
-
const DEFAULT_MODEL = "openai:gpt-5.4";
|
|
13577
14184
|
function parseModelKey(key) {
|
|
13578
14185
|
const i = key.indexOf(":");
|
|
13579
14186
|
if (i > 0) return { provider: key.slice(0, i), modelId: key.slice(i + 1) };
|
|
@@ -13581,8 +14188,38 @@ function parseModelKey(key) {
|
|
|
13581
14188
|
if (key.startsWith("gemini-")) return { provider: "google", modelId: key };
|
|
13582
14189
|
return { provider: "openai", modelId: key };
|
|
13583
14190
|
}
|
|
14191
|
+
const STORAGE_KEY = "rp-theme";
|
|
14192
|
+
function getInitialTheme() {
|
|
14193
|
+
if (typeof window === "undefined") return "dark";
|
|
14194
|
+
try {
|
|
14195
|
+
const stored = window.localStorage.getItem(STORAGE_KEY);
|
|
14196
|
+
if (stored === "light" || stored === "dark") return stored;
|
|
14197
|
+
} catch {
|
|
14198
|
+
}
|
|
14199
|
+
return "dark";
|
|
14200
|
+
}
|
|
14201
|
+
function persistTheme(theme) {
|
|
14202
|
+
if (typeof window === "undefined") return;
|
|
14203
|
+
try {
|
|
14204
|
+
window.localStorage.setItem(STORAGE_KEY, theme);
|
|
14205
|
+
} catch {
|
|
14206
|
+
}
|
|
14207
|
+
}
|
|
14208
|
+
function applyThemeClass(theme) {
|
|
14209
|
+
if (typeof document === "undefined") return;
|
|
14210
|
+
document.documentElement.classList.remove("dark", "light");
|
|
14211
|
+
document.documentElement.classList.add(theme);
|
|
14212
|
+
}
|
|
14213
|
+
function bootTheme() {
|
|
14214
|
+
const theme = getInitialTheme();
|
|
14215
|
+
applyThemeClass(theme);
|
|
14216
|
+
return theme;
|
|
14217
|
+
}
|
|
13584
14218
|
const useUIStore = create$1((set) => ({
|
|
13585
|
-
|
|
14219
|
+
// Theme hydrates from localStorage (or OS preference) at module init so
|
|
14220
|
+
// the zustand state matches the <html> class applied by bootTheme() in
|
|
14221
|
+
// main.tsx. Both ends derive from getInitialTheme() — they stay in sync.
|
|
14222
|
+
theme: getInitialTheme(),
|
|
13586
14223
|
leftTab: "files",
|
|
13587
14224
|
centerView: "chat",
|
|
13588
14225
|
selectedModel: DEFAULT_MODEL,
|
|
@@ -13605,6 +14242,17 @@ const useUIStore = create$1((set) => ({
|
|
|
13605
14242
|
source: null,
|
|
13606
14243
|
round: null
|
|
13607
14244
|
},
|
|
14245
|
+
wikiReaderSlug: null,
|
|
14246
|
+
wikiReaderHistory: [],
|
|
14247
|
+
setWikiReaderSlug: (slug) => set((s15) => ({
|
|
14248
|
+
wikiReaderHistory: s15.wikiReaderSlug ? [...s15.wikiReaderHistory, s15.wikiReaderSlug] : s15.wikiReaderHistory,
|
|
14249
|
+
wikiReaderSlug: slug
|
|
14250
|
+
})),
|
|
14251
|
+
wikiReaderBack: () => set((s15) => {
|
|
14252
|
+
const history = [...s15.wikiReaderHistory];
|
|
14253
|
+
const prev = history.pop() ?? null;
|
|
14254
|
+
return { wikiReaderSlug: prev, wikiReaderHistory: history };
|
|
14255
|
+
}),
|
|
13608
14256
|
setReasoningEffort: (reasoningEffort) => {
|
|
13609
14257
|
set({ reasoningEffort });
|
|
13610
14258
|
const api2 = window.api;
|
|
@@ -13613,8 +14261,8 @@ const useUIStore = create$1((set) => ({
|
|
|
13613
14261
|
},
|
|
13614
14262
|
setTheme: (theme) => {
|
|
13615
14263
|
set({ theme });
|
|
13616
|
-
|
|
13617
|
-
|
|
14264
|
+
persistTheme(theme);
|
|
14265
|
+
applyThemeClass(theme);
|
|
13618
14266
|
},
|
|
13619
14267
|
toggleTheme: () => {
|
|
13620
14268
|
const newTheme = useUIStore.getState().theme === "dark" ? "light" : "dark";
|
|
@@ -13680,7 +14328,9 @@ const useUIStore = create$1((set) => ({
|
|
|
13680
14328
|
previewEntity: null,
|
|
13681
14329
|
previewSourceTab: null,
|
|
13682
14330
|
previewEditorFocused: false,
|
|
13683
|
-
literatureFilter: { search: "", subTopic: null, sortBy: "year", sortDir: "desc", minScore: 0, source: null, round: null }
|
|
14331
|
+
literatureFilter: { search: "", subTopic: null, sortBy: "year", sortDir: "desc", minScore: 0, source: null, round: null },
|
|
14332
|
+
wikiReaderSlug: null,
|
|
14333
|
+
wikiReaderHistory: []
|
|
13684
14334
|
}),
|
|
13685
14335
|
openPreview: (entity) => set((s15) => ({ previewEntity: entity, previewSourceTab: s15.leftTab, leftSidebarCollapsed: true, previewEditorFocused: false })),
|
|
13686
14336
|
closePreview: () => set({ previewEntity: null, previewSourceTab: null, leftSidebarCollapsed: false, previewEditorFocused: false }),
|
|
@@ -13689,9 +14339,8 @@ const useUIStore = create$1((set) => ({
|
|
|
13689
14339
|
async function hydratePreferences() {
|
|
13690
14340
|
const api2 = window.api;
|
|
13691
14341
|
const prefs = await api2?.loadPreferences?.();
|
|
13692
|
-
if (!prefs) return;
|
|
13693
14342
|
const updates = {};
|
|
13694
|
-
if (prefs
|
|
14343
|
+
if (prefs?.selectedModel) {
|
|
13695
14344
|
const m = prefs.selectedModel;
|
|
13696
14345
|
if (!m.includes(":")) {
|
|
13697
14346
|
const { provider, modelId } = parseModelKey(m);
|
|
@@ -13699,9 +14348,14 @@ async function hydratePreferences() {
|
|
|
13699
14348
|
} else {
|
|
13700
14349
|
updates.selectedModel = m;
|
|
13701
14350
|
}
|
|
14351
|
+
} else {
|
|
14352
|
+
try {
|
|
14353
|
+
const preferred = await api2?.pickPreferredModel?.();
|
|
14354
|
+
if (preferred) updates.selectedModel = preferred;
|
|
14355
|
+
} catch {
|
|
14356
|
+
}
|
|
13702
14357
|
}
|
|
13703
|
-
if (prefs
|
|
13704
|
-
if (prefs.theme) updates.theme = prefs.theme;
|
|
14358
|
+
if (prefs?.reasoningEffort) updates.reasoningEffort = prefs.reasoningEffort;
|
|
13705
14359
|
if (Object.keys(updates).length > 0) useUIStore.setState(updates);
|
|
13706
14360
|
}
|
|
13707
14361
|
const uiStore = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
@@ -13846,7 +14500,7 @@ const useToolEventsStore = create$1((set, get) => ({
|
|
|
13846
14500
|
clearRun: () => set({ currentRunEvents: [] })
|
|
13847
14501
|
}));
|
|
13848
14502
|
const PAGE_SIZE = 20;
|
|
13849
|
-
const api$
|
|
14503
|
+
const api$d = window.api;
|
|
13850
14504
|
let _sessionId = "";
|
|
13851
14505
|
const useChatStore = create$1((set, get) => ({
|
|
13852
14506
|
messages: [],
|
|
@@ -13874,7 +14528,7 @@ const useChatStore = create$1((set, get) => ({
|
|
|
13874
14528
|
isStreaming: true
|
|
13875
14529
|
}));
|
|
13876
14530
|
if (_sessionId) {
|
|
13877
|
-
api$
|
|
14531
|
+
api$d.saveMessage(_sessionId, userMsg).catch(() => {
|
|
13878
14532
|
});
|
|
13879
14533
|
}
|
|
13880
14534
|
const { useUsageStore: useUsageStore2 } = await __vitePreload(async () => {
|
|
@@ -13888,12 +14542,12 @@ const useChatStore = create$1((set, get) => ({
|
|
|
13888
14542
|
return { useUIStore: useUIStore3 };
|
|
13889
14543
|
}, true ? void 0 : void 0, import.meta.url);
|
|
13890
14544
|
const model = useUIStore2.getState().selectedModel;
|
|
13891
|
-
await api$
|
|
14545
|
+
await api$d.sendMessage(text2, void 0, model, images);
|
|
13892
14546
|
} catch {
|
|
13893
14547
|
}
|
|
13894
14548
|
},
|
|
13895
14549
|
stop: async () => {
|
|
13896
|
-
await api$
|
|
14550
|
+
await api$d.stopAgent();
|
|
13897
14551
|
},
|
|
13898
14552
|
appendChunk: (chunk) => {
|
|
13899
14553
|
set((s15) => ({ streamingText: s15.streamingText + chunk }));
|
|
@@ -13922,7 +14576,7 @@ const useChatStore = create$1((set, get) => ({
|
|
|
13922
14576
|
};
|
|
13923
14577
|
});
|
|
13924
14578
|
if (_sessionId) {
|
|
13925
|
-
api$
|
|
14579
|
+
api$d.saveMessage(_sessionId, assistantMsg).catch(() => {
|
|
13926
14580
|
});
|
|
13927
14581
|
}
|
|
13928
14582
|
},
|
|
@@ -13948,7 +14602,7 @@ const useChatStore = create$1((set, get) => ({
|
|
|
13948
14602
|
return { savedMessageIds: next };
|
|
13949
14603
|
});
|
|
13950
14604
|
if (_sessionId) {
|
|
13951
|
-
api$
|
|
14605
|
+
api$d.markMessageSaved(_sessionId, messageId).catch(() => {
|
|
13952
14606
|
});
|
|
13953
14607
|
}
|
|
13954
14608
|
},
|
|
@@ -13965,9 +14619,9 @@ const useChatStore = create$1((set, get) => ({
|
|
|
13965
14619
|
_sessionId = sessionId;
|
|
13966
14620
|
try {
|
|
13967
14621
|
const [count, messages, savedIds] = await Promise.all([
|
|
13968
|
-
api$
|
|
13969
|
-
api$
|
|
13970
|
-
api$
|
|
14622
|
+
api$d.getMessageCount(sessionId),
|
|
14623
|
+
api$d.loadMessages(sessionId, 0, PAGE_SIZE),
|
|
14624
|
+
api$d.loadSavedMessageIds(sessionId)
|
|
13971
14625
|
]);
|
|
13972
14626
|
set({
|
|
13973
14627
|
messages,
|
|
@@ -13984,8 +14638,8 @@ const useChatStore = create$1((set, get) => ({
|
|
|
13984
14638
|
set({ isLoadingHistory: true });
|
|
13985
14639
|
try {
|
|
13986
14640
|
const [count, older] = await Promise.all([
|
|
13987
|
-
api$
|
|
13988
|
-
api$
|
|
14641
|
+
api$d.getMessageCount(_sessionId),
|
|
14642
|
+
api$d.loadMessages(_sessionId, _offset, PAGE_SIZE)
|
|
13989
14643
|
]);
|
|
13990
14644
|
if (older.length > 0) {
|
|
13991
14645
|
set((s15) => ({
|
|
@@ -14063,7 +14717,7 @@ function merge(definitions, space2) {
|
|
|
14063
14717
|
}
|
|
14064
14718
|
return new Schema(property, normal, space2);
|
|
14065
14719
|
}
|
|
14066
|
-
function normalize$
|
|
14720
|
+
function normalize$2(value) {
|
|
14067
14721
|
return value.toLowerCase();
|
|
14068
14722
|
}
|
|
14069
14723
|
class Info {
|
|
@@ -14163,8 +14817,8 @@ function create(definition2) {
|
|
|
14163
14817
|
info.mustUseProperty = true;
|
|
14164
14818
|
}
|
|
14165
14819
|
properties[property] = info;
|
|
14166
|
-
normals[normalize$
|
|
14167
|
-
normals[normalize$
|
|
14820
|
+
normals[normalize$2(property)] = property;
|
|
14821
|
+
normals[normalize$2(info.attribute)] = property;
|
|
14168
14822
|
}
|
|
14169
14823
|
return new Schema(properties, normals, definition2.space);
|
|
14170
14824
|
}
|
|
@@ -15203,7 +15857,7 @@ const cap$1 = /[A-Z]/g;
|
|
|
15203
15857
|
const dash = /-[a-z]/g;
|
|
15204
15858
|
const valid = /^data[-\w.:]+$/i;
|
|
15205
15859
|
function find(schema, value) {
|
|
15206
|
-
const normal = normalize$
|
|
15860
|
+
const normal = normalize$2(value);
|
|
15207
15861
|
let property = value;
|
|
15208
15862
|
let Type = Info;
|
|
15209
15863
|
if (normal in schema.normal) {
|
|
@@ -22223,9 +22877,9 @@ function join(...segments) {
|
|
|
22223
22877
|
joined = joined === void 0 ? segments[index2] : joined + "/" + segments[index2];
|
|
22224
22878
|
}
|
|
22225
22879
|
}
|
|
22226
|
-
return joined === void 0 ? "." : normalize(joined);
|
|
22880
|
+
return joined === void 0 ? "." : normalize$1(joined);
|
|
22227
22881
|
}
|
|
22228
|
-
function normalize(path2) {
|
|
22882
|
+
function normalize$1(path2) {
|
|
22229
22883
|
assertPath$1(path2);
|
|
22230
22884
|
const absolute = path2.codePointAt(0) === 47;
|
|
22231
22885
|
let value = normalizeString(path2, !absolute);
|
|
@@ -26549,7 +27203,7 @@ function remarkGfm(options) {
|
|
|
26549
27203
|
fromMarkdownExtensions.push(gfmFromMarkdown());
|
|
26550
27204
|
toMarkdownExtensions.push(gfmToMarkdown(settings));
|
|
26551
27205
|
}
|
|
26552
|
-
const api$
|
|
27206
|
+
const api$c = window.api;
|
|
26553
27207
|
function stamp(items, type) {
|
|
26554
27208
|
return (items || []).map((i) => ({
|
|
26555
27209
|
...i,
|
|
@@ -26589,9 +27243,9 @@ const useEntityStore = create$1((set, get) => ({
|
|
|
26589
27243
|
}),
|
|
26590
27244
|
refreshAll: async () => {
|
|
26591
27245
|
const [notesRaw, papersRaw, dataRaw] = await Promise.all([
|
|
26592
|
-
api$
|
|
26593
|
-
api$
|
|
26594
|
-
api$
|
|
27246
|
+
api$c.listNotes(),
|
|
27247
|
+
api$c.listLiterature(),
|
|
27248
|
+
api$c.listData()
|
|
26595
27249
|
]);
|
|
26596
27250
|
const notes = stamp(notesRaw, "note");
|
|
26597
27251
|
notes.sort((a, b2) => a.id === "agent-md" ? -1 : b2.id === "agent-md" ? 1 : 0);
|
|
@@ -26604,7 +27258,7 @@ const useEntityStore = create$1((set, get) => ({
|
|
|
26604
27258
|
});
|
|
26605
27259
|
},
|
|
26606
27260
|
deleteEntity: async (id) => {
|
|
26607
|
-
await api$
|
|
27261
|
+
await api$c.deleteEntity(id);
|
|
26608
27262
|
await get().refreshAll();
|
|
26609
27263
|
}
|
|
26610
27264
|
}));
|
|
@@ -26660,10 +27314,10 @@ function findLastIndex(arr, pred) {
|
|
|
26660
27314
|
}
|
|
26661
27315
|
return -1;
|
|
26662
27316
|
}
|
|
26663
|
-
const api$
|
|
27317
|
+
const api$b = window.api;
|
|
26664
27318
|
async function loadFromFramework() {
|
|
26665
27319
|
try {
|
|
26666
|
-
const data = await api$
|
|
27320
|
+
const data = await api$b?.getUsageTotals?.();
|
|
26667
27321
|
return data ?? null;
|
|
26668
27322
|
} catch (e) {
|
|
26669
27323
|
console.warn("[usage-store] Failed to load persisted totals:", e);
|
|
@@ -26779,7 +27433,7 @@ const useUsageStore = create$1((set, get) => {
|
|
|
26779
27433
|
},
|
|
26780
27434
|
// Reset all-time totals (user-initiated)
|
|
26781
27435
|
resetAllTime: () => {
|
|
26782
|
-
api$
|
|
27436
|
+
api$b?.resetUsageTotals?.().catch?.(() => {
|
|
26783
27437
|
});
|
|
26784
27438
|
set({
|
|
26785
27439
|
runPromptTokens: 0,
|
|
@@ -26810,13 +27464,31 @@ const usageStore = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePr
|
|
|
26810
27464
|
__proto__: null,
|
|
26811
27465
|
useUsageStore
|
|
26812
27466
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
26813
|
-
const api$
|
|
27467
|
+
const api$a = window.api;
|
|
27468
|
+
async function applyOpenResult(set, result) {
|
|
27469
|
+
if (!result) return false;
|
|
27470
|
+
useChatStore.getState().clear();
|
|
27471
|
+
useProgressStore.getState().clear();
|
|
27472
|
+
useActivityStore.getState().clear();
|
|
27473
|
+
useUIStore.getState().reset();
|
|
27474
|
+
useEntityStore.getState().reset();
|
|
27475
|
+
useUsageStore.getState().resetSession();
|
|
27476
|
+
set({ hasProject: false, sessionId: "", projectPath: "" });
|
|
27477
|
+
await new Promise((r) => setTimeout(r, 0));
|
|
27478
|
+
set({
|
|
27479
|
+
sessionId: result.sessionId,
|
|
27480
|
+
projectPath: result.projectPath,
|
|
27481
|
+
hasProject: true
|
|
27482
|
+
});
|
|
27483
|
+
await hydratePreferences();
|
|
27484
|
+
return true;
|
|
27485
|
+
}
|
|
26814
27486
|
const useSessionStore = create$1((set) => ({
|
|
26815
27487
|
sessionId: "",
|
|
26816
27488
|
projectPath: "",
|
|
26817
27489
|
hasProject: false,
|
|
26818
27490
|
init: async () => {
|
|
26819
|
-
const session = await api$
|
|
27491
|
+
const session = await api$a.getCurrentSession();
|
|
26820
27492
|
set({
|
|
26821
27493
|
sessionId: session.sessionId,
|
|
26822
27494
|
projectPath: session.projectPath,
|
|
@@ -26827,28 +27499,15 @@ const useSessionStore = create$1((set) => ({
|
|
|
26827
27499
|
}
|
|
26828
27500
|
},
|
|
26829
27501
|
pickFolder: async () => {
|
|
26830
|
-
const result = await api$
|
|
26831
|
-
|
|
26832
|
-
|
|
26833
|
-
|
|
26834
|
-
|
|
26835
|
-
|
|
26836
|
-
useEntityStore.getState().reset();
|
|
26837
|
-
useUsageStore.getState().resetSession();
|
|
26838
|
-
set({ hasProject: false, sessionId: "", projectPath: "" });
|
|
26839
|
-
await new Promise((r) => setTimeout(r, 0));
|
|
26840
|
-
set({
|
|
26841
|
-
sessionId: result.sessionId,
|
|
26842
|
-
projectPath: result.projectPath,
|
|
26843
|
-
hasProject: true
|
|
26844
|
-
});
|
|
26845
|
-
await hydratePreferences();
|
|
26846
|
-
return true;
|
|
26847
|
-
}
|
|
26848
|
-
return false;
|
|
27502
|
+
const result = await api$a.pickFolder();
|
|
27503
|
+
return applyOpenResult(set, result);
|
|
27504
|
+
},
|
|
27505
|
+
openPath: async (projectPath) => {
|
|
27506
|
+
const result = await api$a.openProjectPath(projectPath);
|
|
27507
|
+
return applyOpenResult(set, result);
|
|
26849
27508
|
},
|
|
26850
27509
|
closeProject: async () => {
|
|
26851
|
-
await api$
|
|
27510
|
+
await api$a.closeProject();
|
|
26852
27511
|
useChatStore.getState().clear();
|
|
26853
27512
|
useProgressStore.getState().clear();
|
|
26854
27513
|
useActivityStore.getState().clear();
|
|
@@ -26858,7 +27517,7 @@ const useSessionStore = create$1((set) => ({
|
|
|
26858
27517
|
set({ sessionId: "", projectPath: "", hasProject: false });
|
|
26859
27518
|
}
|
|
26860
27519
|
}));
|
|
26861
|
-
const api$
|
|
27520
|
+
const api$9 = window.api;
|
|
26862
27521
|
const ROW_HEIGHT = 28;
|
|
26863
27522
|
const OVERSCAN_ROWS = 10;
|
|
26864
27523
|
const MAX_DROP_FILE_SIZE = 100 * 1024 * 1024;
|
|
@@ -26957,7 +27616,7 @@ function WorkspaceTree() {
|
|
|
26957
27616
|
const parentKey = toKey(relativePath);
|
|
26958
27617
|
setParentLoading(parentKey, true);
|
|
26959
27618
|
try {
|
|
26960
|
-
const children = await api$
|
|
27619
|
+
const children = await api$9.listTree({
|
|
26961
27620
|
relativePath,
|
|
26962
27621
|
showIgnored,
|
|
26963
27622
|
limit: 2e3
|
|
@@ -26982,8 +27641,8 @@ function WorkspaceTree() {
|
|
|
26982
27641
|
void Promise.all(dirs.map((dir) => loadChildren(dir)));
|
|
26983
27642
|
}, 500);
|
|
26984
27643
|
};
|
|
26985
|
-
const unsubFileCreated = api$
|
|
26986
|
-
const unsubAgentDone = api$
|
|
27644
|
+
const unsubFileCreated = api$9.onFileCreated(scheduleRefresh);
|
|
27645
|
+
const unsubAgentDone = api$9.onAgentDone(scheduleRefresh);
|
|
26987
27646
|
return () => {
|
|
26988
27647
|
if (debounceTimer) clearTimeout(debounceTimer);
|
|
26989
27648
|
unsubFileCreated();
|
|
@@ -27023,7 +27682,7 @@ function WorkspaceTree() {
|
|
|
27023
27682
|
}
|
|
27024
27683
|
setSearching(true);
|
|
27025
27684
|
try {
|
|
27026
|
-
const results = await api$
|
|
27685
|
+
const results = await api$9.searchTree(query.trim(), { showIgnored, maxResults: 4e3 });
|
|
27027
27686
|
setSearchResults(results);
|
|
27028
27687
|
} finally {
|
|
27029
27688
|
setSearching(false);
|
|
@@ -27067,7 +27726,7 @@ function WorkspaceTree() {
|
|
|
27067
27726
|
if (node2.type !== "file") return;
|
|
27068
27727
|
const ext = (node2.name.split(".").pop() || "").toLowerCase();
|
|
27069
27728
|
if (!TEXT_EXTENSIONS.has(ext)) {
|
|
27070
|
-
api$
|
|
27729
|
+
api$9.openFile(node2.path);
|
|
27071
27730
|
return;
|
|
27072
27731
|
}
|
|
27073
27732
|
const normalizedNodePath = normalizePath(node2.path);
|
|
@@ -27092,14 +27751,14 @@ function WorkspaceTree() {
|
|
|
27092
27751
|
});
|
|
27093
27752
|
}, [data, openPreview]);
|
|
27094
27753
|
const createArtifact = reactExports.useCallback(async (node2) => {
|
|
27095
|
-
await api$
|
|
27754
|
+
await api$9.createArtifactFromFile(node2.path);
|
|
27096
27755
|
await refreshEntities();
|
|
27097
27756
|
}, [refreshEntities]);
|
|
27098
27757
|
const handleTrashClick = reactExports.useCallback(async (node2) => {
|
|
27099
27758
|
if (confirmTrashPath === node2.relativePath) {
|
|
27100
27759
|
if (confirmTimerRef.current) clearTimeout(confirmTimerRef.current);
|
|
27101
27760
|
setConfirmTrashPath(null);
|
|
27102
|
-
const result = await api$
|
|
27761
|
+
const result = await api$9.trashFile(node2.path);
|
|
27103
27762
|
if (result.success) {
|
|
27104
27763
|
const parentRelPath = node2.relativePath.includes("/") ? node2.relativePath.slice(0, node2.relativePath.lastIndexOf("/")) : "";
|
|
27105
27764
|
await loadChildren(parentRelPath);
|
|
@@ -27148,7 +27807,7 @@ function WorkspaceTree() {
|
|
|
27148
27807
|
return;
|
|
27149
27808
|
}
|
|
27150
27809
|
const relPath = creating.parentDir ? `${creating.parentDir}/${createValue.trim()}` : createValue.trim();
|
|
27151
|
-
const result = creating.type === "file" ? await api$
|
|
27810
|
+
const result = creating.type === "file" ? await api$9.createFile(relPath) : await api$9.createDir(relPath);
|
|
27152
27811
|
if (result.success) {
|
|
27153
27812
|
await loadChildren(creating.parentDir);
|
|
27154
27813
|
}
|
|
@@ -27175,7 +27834,7 @@ function WorkspaceTree() {
|
|
|
27175
27834
|
const parentDir = renaming.includes("/") ? renaming.slice(0, renaming.lastIndexOf("/")) : "";
|
|
27176
27835
|
const newRelPath = parentDir ? `${parentDir}/${renameValue.trim()}` : renameValue.trim();
|
|
27177
27836
|
if (newRelPath !== renaming) {
|
|
27178
|
-
await api$
|
|
27837
|
+
await api$9.renameFile(renaming, newRelPath);
|
|
27179
27838
|
await loadChildren(parentDir);
|
|
27180
27839
|
}
|
|
27181
27840
|
setRenaming(null);
|
|
@@ -27217,7 +27876,7 @@ function WorkspaceTree() {
|
|
|
27217
27876
|
const base64 = btoa(
|
|
27218
27877
|
new Uint8Array(buffer).reduce((data2, byte) => data2 + String.fromCharCode(byte), "")
|
|
27219
27878
|
);
|
|
27220
|
-
await api$
|
|
27879
|
+
await api$9.dropToDir(file.name, base64, targetRelPath);
|
|
27221
27880
|
}
|
|
27222
27881
|
await loadChildren(targetRelPath);
|
|
27223
27882
|
}, [getDropDir, loadChildren]);
|
|
@@ -27243,7 +27902,7 @@ function WorkspaceTree() {
|
|
|
27243
27902
|
const base64 = btoa(
|
|
27244
27903
|
new Uint8Array(buffer).reduce((data2, byte) => data2 + String.fromCharCode(byte), "")
|
|
27245
27904
|
);
|
|
27246
|
-
await api$
|
|
27905
|
+
await api$9.dropToDir(file.name, base64, "");
|
|
27247
27906
|
}
|
|
27248
27907
|
await loadChildren("");
|
|
27249
27908
|
}, [loadChildren]);
|
|
@@ -27318,7 +27977,7 @@ function WorkspaceTree() {
|
|
|
27318
27977
|
onKeyDown: handleCreateKeyDown,
|
|
27319
27978
|
onBlur: () => void commitCreate(),
|
|
27320
27979
|
placeholder: creating.type === "file" ? "filename.ext" : "folder name",
|
|
27321
|
-
className: "flex-1 bg-transparent outline-none border-b border-[var(--color-accent-soft)] text-xs t-text"
|
|
27980
|
+
className: "flex-1 bg-transparent outline-none t-focus-ring border-b border-[var(--color-accent-soft)] text-xs t-text"
|
|
27322
27981
|
}
|
|
27323
27982
|
)
|
|
27324
27983
|
]
|
|
@@ -27637,7 +28296,7 @@ const useSkillStore = create$1((set, get) => ({
|
|
|
27637
28296
|
return result;
|
|
27638
28297
|
}
|
|
27639
28298
|
}));
|
|
27640
|
-
const remarkPlugins$
|
|
28299
|
+
const remarkPlugins$3 = [remarkGfm];
|
|
27641
28300
|
function HoverPreview({
|
|
27642
28301
|
entity,
|
|
27643
28302
|
anchorRect,
|
|
@@ -27679,7 +28338,7 @@ function HoverPreview({
|
|
|
27679
28338
|
}
|
|
27680
28339
|
) })
|
|
27681
28340
|
] }),
|
|
27682
|
-
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$
|
|
28341
|
+
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 }) }) })
|
|
27683
28342
|
]
|
|
27684
28343
|
}
|
|
27685
28344
|
);
|
|
@@ -28140,6 +28799,35 @@ function EntityTabs() {
|
|
|
28140
28799
|
)
|
|
28141
28800
|
] });
|
|
28142
28801
|
}
|
|
28802
|
+
const api$8 = window.api;
|
|
28803
|
+
function ConceptsList() {
|
|
28804
|
+
const [concepts, setConcepts] = reactExports.useState([]);
|
|
28805
|
+
const setSlug = useUIStore((s15) => s15.setWikiReaderSlug);
|
|
28806
|
+
const activeSlug = useUIStore((s15) => s15.wikiReaderSlug);
|
|
28807
|
+
reactExports.useEffect(() => {
|
|
28808
|
+
api$8.wikiListPages?.().then((result) => {
|
|
28809
|
+
if (result?.concepts) setConcepts(result.concepts);
|
|
28810
|
+
}).catch(() => {
|
|
28811
|
+
});
|
|
28812
|
+
}, []);
|
|
28813
|
+
if (concepts.length === 0) return null;
|
|
28814
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [
|
|
28815
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[10px] t-text-accent-soft uppercase tracking-wider font-medium flex items-center gap-1.5", children: [
|
|
28816
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Network, { size: 10 }),
|
|
28817
|
+
"Concepts"
|
|
28818
|
+
] }),
|
|
28819
|
+
concepts.map((c) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
28820
|
+
"button",
|
|
28821
|
+
{
|
|
28822
|
+
onClick: () => setSlug(c.slug),
|
|
28823
|
+
className: `w-full text-left flex items-center justify-between px-1 py-0.5 rounded transition-colors ${activeSlug === c.slug ? "bg-[var(--color-accent-soft)]/10 t-text-accent" : "t-text-secondary hover:t-bg-hover"}`,
|
|
28824
|
+
title: c.title,
|
|
28825
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[11px] truncate", children: c.title })
|
|
28826
|
+
},
|
|
28827
|
+
c.slug
|
|
28828
|
+
))
|
|
28829
|
+
] });
|
|
28830
|
+
}
|
|
28143
28831
|
function QuickAction({
|
|
28144
28832
|
icon: Icon2,
|
|
28145
28833
|
label,
|
|
@@ -28163,45 +28851,6 @@ function QuickAction({
|
|
|
28163
28851
|
}
|
|
28164
28852
|
);
|
|
28165
28853
|
}
|
|
28166
|
-
function SourceBreakdown({ papers }) {
|
|
28167
|
-
const sources = reactExports.useMemo(() => {
|
|
28168
|
-
const counts = /* @__PURE__ */ new Map();
|
|
28169
|
-
for (const p of papers) {
|
|
28170
|
-
const src = p.externalSource || "unknown";
|
|
28171
|
-
counts.set(src, (counts.get(src) || 0) + 1);
|
|
28172
|
-
}
|
|
28173
|
-
return Array.from(counts.entries()).sort((a, b2) => b2[1] - a[1]);
|
|
28174
|
-
}, [papers]);
|
|
28175
|
-
if (sources.length === 0) return null;
|
|
28176
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [
|
|
28177
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] t-text-muted uppercase tracking-wider font-medium", children: "Sources" }),
|
|
28178
|
-
sources.map(([src, count]) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between px-1", children: [
|
|
28179
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[11px] t-text-secondary capitalize", children: src.replace(/_/g, " ") }),
|
|
28180
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] t-text-muted tabular-nums", children: count })
|
|
28181
|
-
] }, src))
|
|
28182
|
-
] });
|
|
28183
|
-
}
|
|
28184
|
-
function RoundHistory({ papers }) {
|
|
28185
|
-
const rounds = reactExports.useMemo(() => {
|
|
28186
|
-
const map2 = /* @__PURE__ */ new Map();
|
|
28187
|
-
for (const p of papers) {
|
|
28188
|
-
const round = p.addedInRound || "";
|
|
28189
|
-
if (round) map2.set(round, (map2.get(round) || 0) + 1);
|
|
28190
|
-
}
|
|
28191
|
-
return Array.from(map2.entries()).sort();
|
|
28192
|
-
}, [papers]);
|
|
28193
|
-
if (rounds.length === 0) return null;
|
|
28194
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [
|
|
28195
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] t-text-muted uppercase tracking-wider font-medium", children: "Search Rounds" }),
|
|
28196
|
-
rounds.map(([round, count]) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between px-1", children: [
|
|
28197
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[11px] t-text-secondary", children: round }),
|
|
28198
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] t-text-muted tabular-nums", children: [
|
|
28199
|
-
count,
|
|
28200
|
-
" papers"
|
|
28201
|
-
] })
|
|
28202
|
-
] }, round))
|
|
28203
|
-
] });
|
|
28204
|
-
}
|
|
28205
28854
|
function GapAlerts({ papers }) {
|
|
28206
28855
|
const gaps = reactExports.useMemo(() => {
|
|
28207
28856
|
const topicScores = /* @__PURE__ */ new Map();
|
|
@@ -28312,8 +28961,7 @@ function LiteratureSidebar() {
|
|
|
28312
28961
|
] }),
|
|
28313
28962
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mx-3 border-t t-border" }),
|
|
28314
28963
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 overflow-y-auto px-3 py-3 space-y-4", children: [
|
|
28315
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
28316
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(RoundHistory, { papers }),
|
|
28964
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(ConceptsList, {}),
|
|
28317
28965
|
/* @__PURE__ */ jsxRuntimeExports.jsx(GapAlerts, { papers }),
|
|
28318
28966
|
papers.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center py-6", children: [
|
|
28319
28967
|
/* @__PURE__ */ jsxRuntimeExports.jsx(ChartColumn, { size: 24, className: "mx-auto mb-2 t-text-muted opacity-30" }),
|
|
@@ -28505,20 +29153,32 @@ function UserProfile() {
|
|
|
28505
29153
|
}
|
|
28506
29154
|
);
|
|
28507
29155
|
}
|
|
28508
|
-
const
|
|
28509
|
-
|
|
28510
|
-
|
|
28511
|
-
|
|
29156
|
+
const PROVIDER_ORDER = [
|
|
29157
|
+
"ChatGPT Subscription",
|
|
29158
|
+
"Claude Subscription",
|
|
29159
|
+
"OpenAI",
|
|
29160
|
+
"Anthropic"
|
|
29161
|
+
];
|
|
29162
|
+
const allProviders = PROVIDER_ORDER.filter(
|
|
29163
|
+
(p) => SUPPORTED_MODELS.some((m) => m.provider === p)
|
|
29164
|
+
);
|
|
29165
|
+
const allGroupedModels = {};
|
|
29166
|
+
for (const p of allProviders) {
|
|
29167
|
+
allGroupedModels[p] = SUPPORTED_MODELS.filter((m) => m.provider === p);
|
|
28512
29168
|
}
|
|
28513
29169
|
function ModelSelector$1({ selectedModel, onSelectModel }) {
|
|
28514
29170
|
const [open, setOpen] = reactExports.useState(false);
|
|
28515
29171
|
const [anthropicStatus, setAnthropicStatus] = reactExports.useState(null);
|
|
28516
29172
|
const [codexStatus, setCodexStatus] = reactExports.useState(null);
|
|
28517
29173
|
const [codexLoggingIn, setCodexLoggingIn] = reactExports.useState(false);
|
|
29174
|
+
const [anthropicSubStatus, setAnthropicSubStatus] = reactExports.useState(null);
|
|
29175
|
+
const [anthropicSubLoggingIn, setAnthropicSubLoggingIn] = reactExports.useState(false);
|
|
28518
29176
|
const [showAnthropicDialog, setShowAnthropicDialog] = reactExports.useState(false);
|
|
28519
29177
|
const [showOpenAIDialog, setShowOpenAIDialog] = reactExports.useState(false);
|
|
28520
29178
|
const ref = reactExports.useRef(null);
|
|
28521
29179
|
const api2 = window.api;
|
|
29180
|
+
const providers = allProviders;
|
|
29181
|
+
const groupedModels = allGroupedModels;
|
|
28522
29182
|
const current = SUPPORTED_MODELS.find((m) => m.id === selectedModel);
|
|
28523
29183
|
const refreshAnthropicStatus = reactExports.useCallback(async () => {
|
|
28524
29184
|
try {
|
|
@@ -28536,6 +29196,14 @@ function ModelSelector$1({ selectedModel, onSelectModel }) {
|
|
|
28536
29196
|
setCodexStatus(null);
|
|
28537
29197
|
}
|
|
28538
29198
|
}, [api2]);
|
|
29199
|
+
const refreshAnthropicSubStatus = reactExports.useCallback(async () => {
|
|
29200
|
+
try {
|
|
29201
|
+
const status = await api2?.getAnthropicSubStatus?.();
|
|
29202
|
+
setAnthropicSubStatus(status ?? null);
|
|
29203
|
+
} catch {
|
|
29204
|
+
setAnthropicSubStatus(null);
|
|
29205
|
+
}
|
|
29206
|
+
}, [api2]);
|
|
28539
29207
|
reactExports.useEffect(() => {
|
|
28540
29208
|
if (!open) return;
|
|
28541
29209
|
const handler = (e) => {
|
|
@@ -28557,11 +29225,12 @@ function ModelSelector$1({ selectedModel, onSelectModel }) {
|
|
|
28557
29225
|
reactExports.useEffect(() => {
|
|
28558
29226
|
refreshAnthropicStatus();
|
|
28559
29227
|
refreshCodexStatus();
|
|
29228
|
+
refreshAnthropicSubStatus();
|
|
28560
29229
|
const unsub = api2?.onAnthropicAuthStatus?.((status) => setAnthropicStatus(status));
|
|
28561
29230
|
return () => {
|
|
28562
29231
|
if (typeof unsub === "function") unsub();
|
|
28563
29232
|
};
|
|
28564
|
-
}, [api2, refreshAnthropicStatus, refreshCodexStatus]);
|
|
29233
|
+
}, [api2, refreshAnthropicStatus, refreshCodexStatus, refreshAnthropicSubStatus]);
|
|
28565
29234
|
const handleCodexLogin = async () => {
|
|
28566
29235
|
setCodexLoggingIn(true);
|
|
28567
29236
|
try {
|
|
@@ -28581,6 +29250,25 @@ function ModelSelector$1({ selectedModel, onSelectModel }) {
|
|
|
28581
29250
|
await api2?.openaiCodexLogout?.();
|
|
28582
29251
|
await refreshCodexStatus();
|
|
28583
29252
|
};
|
|
29253
|
+
const handleAnthropicSubLogin = async () => {
|
|
29254
|
+
setAnthropicSubLoggingIn(true);
|
|
29255
|
+
try {
|
|
29256
|
+
const result = await api2?.anthropicSubLogin?.();
|
|
29257
|
+
if (result?.success) {
|
|
29258
|
+
await refreshAnthropicSubStatus();
|
|
29259
|
+
} else {
|
|
29260
|
+
console.error("[ModelSelector] Anthropic sub login failed:", result?.error);
|
|
29261
|
+
}
|
|
29262
|
+
} catch (err) {
|
|
29263
|
+
console.error("[ModelSelector] Anthropic sub login error:", err);
|
|
29264
|
+
} finally {
|
|
29265
|
+
setAnthropicSubLoggingIn(false);
|
|
29266
|
+
}
|
|
29267
|
+
};
|
|
29268
|
+
const handleAnthropicSubLogout = async () => {
|
|
29269
|
+
await api2?.anthropicSubLogout?.();
|
|
29270
|
+
await refreshAnthropicSubStatus();
|
|
29271
|
+
};
|
|
28584
29272
|
const handleModelSelect = async (model) => {
|
|
28585
29273
|
const { provider } = parseModelKey(model.id);
|
|
28586
29274
|
if (provider === "openai-codex") {
|
|
@@ -28596,6 +29284,19 @@ function ModelSelector$1({ selectedModel, onSelectModel }) {
|
|
|
28596
29284
|
setOpen(false);
|
|
28597
29285
|
return;
|
|
28598
29286
|
}
|
|
29287
|
+
if (provider === "anthropic-sub") {
|
|
29288
|
+
if (!anthropicSubStatus?.isLoggedIn) {
|
|
29289
|
+
await handleAnthropicSubLogin();
|
|
29290
|
+
const status = await api2?.getAnthropicSubStatus?.();
|
|
29291
|
+
if (!status?.isLoggedIn) {
|
|
29292
|
+
setOpen(false);
|
|
29293
|
+
return;
|
|
29294
|
+
}
|
|
29295
|
+
}
|
|
29296
|
+
onSelectModel(model.id);
|
|
29297
|
+
setOpen(false);
|
|
29298
|
+
return;
|
|
29299
|
+
}
|
|
28599
29300
|
if (provider === "openai") {
|
|
28600
29301
|
const status = await api2?.getOpenAIAuthStatus?.();
|
|
28601
29302
|
if (!status?.hasApiKey) {
|
|
@@ -28617,7 +29318,7 @@ function ModelSelector$1({ selectedModel, onSelectModel }) {
|
|
|
28617
29318
|
refreshAnthropicStatus();
|
|
28618
29319
|
};
|
|
28619
29320
|
const { provider: currentProvider } = current ? parseModelKey(current.id) : { provider: "" };
|
|
28620
|
-
const
|
|
29321
|
+
const authSuffix = currentProvider === "anthropic-sub" || currentProvider === "openai-codex" ? "sub" : currentProvider === "openai" || currentProvider === "anthropic" ? "api" : null;
|
|
28621
29322
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { ref, className: "relative", children: [
|
|
28622
29323
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
28623
29324
|
"button",
|
|
@@ -28638,8 +29339,14 @@ function ModelSelector$1({ selectedModel, onSelectModel }) {
|
|
|
28638
29339
|
}
|
|
28639
29340
|
),
|
|
28640
29341
|
/* @__PURE__ */ jsxRuntimeExports.jsx(Cpu, { size: 14 }),
|
|
28641
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
28642
|
-
|
|
29342
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "truncate max-w-[108px]", children: [
|
|
29343
|
+
current?.label || selectedModel,
|
|
29344
|
+
authSuffix && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "t-text-muted", children: [
|
|
29345
|
+
" (",
|
|
29346
|
+
authSuffix,
|
|
29347
|
+
")"
|
|
29348
|
+
] })
|
|
29349
|
+
] }),
|
|
28643
29350
|
/* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { size: 12, className: `transition-transform ${open ? "rotate-180" : ""}` })
|
|
28644
29351
|
]
|
|
28645
29352
|
}
|
|
@@ -28678,6 +29385,38 @@ function ModelSelector$1({ selectedModel, onSelectModel }) {
|
|
|
28678
29385
|
}
|
|
28679
29386
|
)
|
|
28680
29387
|
] }),
|
|
29388
|
+
provider === "Claude Subscription" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-3 pb-1 flex items-center justify-between", children: [
|
|
29389
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[11px] t-text-muted", children: anthropicSubStatus?.isLoggedIn ? "Signed in" : "OAuth required" }),
|
|
29390
|
+
anthropicSubStatus?.isLoggedIn ? /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
29391
|
+
"button",
|
|
29392
|
+
{
|
|
29393
|
+
onClick: (e) => {
|
|
29394
|
+
e.stopPropagation();
|
|
29395
|
+
handleAnthropicSubLogout();
|
|
29396
|
+
},
|
|
29397
|
+
className: "text-[10px] t-text-muted hover:t-text flex items-center gap-0.5",
|
|
29398
|
+
children: [
|
|
29399
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(LogOut, { size: 10 }),
|
|
29400
|
+
" Sign out"
|
|
29401
|
+
]
|
|
29402
|
+
}
|
|
29403
|
+
) : /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
29404
|
+
"button",
|
|
29405
|
+
{
|
|
29406
|
+
onClick: (e) => {
|
|
29407
|
+
e.stopPropagation();
|
|
29408
|
+
handleAnthropicSubLogin();
|
|
29409
|
+
},
|
|
29410
|
+
disabled: anthropicSubLoggingIn,
|
|
29411
|
+
className: "text-[10px] t-text-accent flex items-center gap-0.5 hover:opacity-80 disabled:opacity-50",
|
|
29412
|
+
children: [
|
|
29413
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(LogIn, { size: 10 }),
|
|
29414
|
+
" ",
|
|
29415
|
+
anthropicSubLoggingIn ? "Signing in..." : "Sign in"
|
|
29416
|
+
]
|
|
29417
|
+
}
|
|
29418
|
+
)
|
|
29419
|
+
] }),
|
|
28681
29420
|
(provider === "OpenAI" || provider === "Anthropic") && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-3 pb-1 text-[11px] t-text-muted", children: "API Key" }),
|
|
28682
29421
|
groupedModels[provider].map((model) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
28683
29422
|
"button",
|
|
@@ -28961,75 +29700,119 @@ function LeftSidebar() {
|
|
|
28961
29700
|
useChatStore.getState().insertContextReset();
|
|
28962
29701
|
noContextShownRef.current = false;
|
|
28963
29702
|
}, []);
|
|
28964
|
-
return
|
|
28965
|
-
|
|
28966
|
-
|
|
28967
|
-
|
|
28968
|
-
|
|
28969
|
-
|
|
28970
|
-
|
|
28971
|
-
|
|
28972
|
-
|
|
28973
|
-
|
|
28974
|
-
|
|
28975
|
-
|
|
28976
|
-
|
|
29703
|
+
return (
|
|
29704
|
+
// Narrow windows (≤1279px) get w-80 (320px) so the center panel keeps
|
|
29705
|
+
// room to breathe; wider windows (≥1280px) get w-[22rem] (352px) so the
|
|
29706
|
+
// toolbar has comfortable slack. Below ~1024px the ModelSelector label
|
|
29707
|
+
// is the first thing to truncate — see ModelSelector for the shrink
|
|
29708
|
+
// pattern introduced in commit 95312df.
|
|
29709
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("aside", { className: "w-80 xl:w-[22rem] flex flex-col border-r t-border t-bg-base pt-10", children: [
|
|
29710
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("nav", { "aria-label": "Sidebar tools", className: "px-4 pb-3 flex items-center justify-between", children: [
|
|
29711
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(ModelSelector, {}),
|
|
29712
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1", children: [
|
|
29713
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(ReasoningToggle, {}),
|
|
29714
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
29715
|
+
ToolbarButton,
|
|
29716
|
+
{
|
|
29717
|
+
onClick: handleResetContext,
|
|
29718
|
+
tooltip: "Reset AI context",
|
|
29719
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(RotateCcw, { size: 16 })
|
|
29720
|
+
}
|
|
29721
|
+
),
|
|
29722
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
29723
|
+
ToolbarButton,
|
|
29724
|
+
{
|
|
29725
|
+
onClick: toggleTheme,
|
|
29726
|
+
tooltip: `${theme === "dark" ? "Light" : "Dark"} mode`,
|
|
29727
|
+
children: theme === "dark" ? /* @__PURE__ */ jsxRuntimeExports.jsx(Sun, { size: 16 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Moon, { size: 16 })
|
|
29728
|
+
}
|
|
29729
|
+
),
|
|
29730
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
29731
|
+
ToolbarButton,
|
|
29732
|
+
{
|
|
29733
|
+
onClick: () => useUIStore.getState().toggleTerminal(),
|
|
29734
|
+
tooltip: "Terminal ⌘`",
|
|
29735
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Terminal, { size: 16 })
|
|
29736
|
+
}
|
|
29737
|
+
)
|
|
29738
|
+
] })
|
|
29739
|
+
] }),
|
|
29740
|
+
/* @__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, {}) }),
|
|
29741
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "border-t t-border p-4", children: /* @__PURE__ */ jsxRuntimeExports.jsx(UserProfile, {}) })
|
|
29742
|
+
] })
|
|
29743
|
+
);
|
|
29744
|
+
}
|
|
29745
|
+
const STARTERS = [
|
|
29746
|
+
{
|
|
29747
|
+
label: "Understand this folder",
|
|
29748
|
+
description: "Scan files, existing artifacts, and recent work to get oriented."
|
|
29749
|
+
},
|
|
29750
|
+
{
|
|
29751
|
+
label: "Start a literature review on …",
|
|
29752
|
+
description: "Plan sub-topics, search multiple sources, score and summarize."
|
|
29753
|
+
},
|
|
29754
|
+
{
|
|
29755
|
+
label: "Capture a research note about …",
|
|
29756
|
+
description: "Draft a note artifact from your description."
|
|
29757
|
+
}
|
|
29758
|
+
];
|
|
29759
|
+
function focusInput() {
|
|
29760
|
+
const input = document.querySelector("[data-chat-input]");
|
|
29761
|
+
if (!input) return;
|
|
29762
|
+
input.focus();
|
|
29763
|
+
const end = input.value.length;
|
|
29764
|
+
try {
|
|
29765
|
+
input.setSelectionRange(end, end);
|
|
29766
|
+
} catch {
|
|
29767
|
+
}
|
|
29768
|
+
}
|
|
29769
|
+
function prefillFromLabel(label) {
|
|
29770
|
+
return label.replace(/…\s*$/, "").replace(/\s+$/, "") + (label.endsWith("…") ? " " : "");
|
|
29771
|
+
}
|
|
29772
|
+
function StarterRow({ starter, onActivate }) {
|
|
29773
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
29774
|
+
"button",
|
|
29775
|
+
{
|
|
29776
|
+
type: "button",
|
|
29777
|
+
onClick: onActivate,
|
|
29778
|
+
className: "group relative w-full text-left flex flex-col gap-0.5 py-2.5 pl-4 pr-2 rounded-sm t-bg-hover transition-colors",
|
|
29779
|
+
children: [
|
|
28977
29780
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
28978
|
-
|
|
29781
|
+
"span",
|
|
28979
29782
|
{
|
|
28980
|
-
|
|
28981
|
-
|
|
28982
|
-
children: theme === "dark" ? /* @__PURE__ */ jsxRuntimeExports.jsx(Sun, { size: 16 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Moon, { size: 16 })
|
|
29783
|
+
"aria-hidden": true,
|
|
29784
|
+
className: "absolute left-0 top-1.5 bottom-1.5 w-[2px] rounded-full bg-transparent group-hover:t-bg-accent-soft transition-colors"
|
|
28983
29785
|
}
|
|
28984
29786
|
),
|
|
28985
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
28986
|
-
|
|
28987
|
-
|
|
28988
|
-
|
|
28989
|
-
|
|
28990
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Terminal, { size: 16 })
|
|
28991
|
-
}
|
|
28992
|
-
)
|
|
28993
|
-
] })
|
|
28994
|
-
] }),
|
|
28995
|
-
/* @__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, {}) }),
|
|
28996
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "border-t t-border p-4", children: /* @__PURE__ */ jsxRuntimeExports.jsx(UserProfile, {}) })
|
|
28997
|
-
] });
|
|
29787
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[13px] t-text-secondary group-hover:t-text transition-colors leading-snug", children: starter.label }),
|
|
29788
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[11px] t-text-muted leading-snug", children: starter.description })
|
|
29789
|
+
]
|
|
29790
|
+
}
|
|
29791
|
+
);
|
|
28998
29792
|
}
|
|
28999
|
-
const suggestions = [
|
|
29000
|
-
{ icon: FileText, label: "Draft a research note", prompt: "Help me draft a research note about " },
|
|
29001
|
-
{ icon: BookOpen, label: "Search literature", prompt: "Search for recent papers on " },
|
|
29002
|
-
{ icon: ChartColumn, label: "Analyze data", prompt: "Analyze the data in " },
|
|
29003
|
-
{ icon: Sparkles, label: "Brainstorm ideas", prompt: "Help me brainstorm ideas for " }
|
|
29004
|
-
];
|
|
29005
29793
|
function HeroIdle() {
|
|
29006
29794
|
const setDraftText = useChatStore((s15) => s15.setDraftText);
|
|
29007
|
-
const
|
|
29008
|
-
|
|
29009
|
-
|
|
29010
|
-
|
|
29795
|
+
const handleStarter = (label) => {
|
|
29796
|
+
const prefill = prefillFromLabel(label);
|
|
29797
|
+
setDraftText(prefill);
|
|
29798
|
+
requestAnimationFrame(focusInput);
|
|
29011
29799
|
};
|
|
29012
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "
|
|
29013
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-
|
|
29014
|
-
|
|
29015
|
-
|
|
29016
|
-
|
|
29017
|
-
|
|
29018
|
-
children: "
|
|
29019
|
-
}
|
|
29020
|
-
|
|
29021
|
-
|
|
29022
|
-
|
|
29023
|
-
|
|
29024
|
-
|
|
29025
|
-
|
|
29026
|
-
|
|
29027
|
-
|
|
29028
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-secondary group-hover:t-text font-medium transition-colors", style: { fontSize: "var(--text-sm)" }, children: label })
|
|
29029
|
-
]
|
|
29030
|
-
},
|
|
29031
|
-
label
|
|
29032
|
-
)) })
|
|
29800
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full max-w-lg px-8", children: [
|
|
29801
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "pl-4 mb-2 text-[10px] uppercase tracking-wider t-text-muted font-medium", children: "Start" }),
|
|
29802
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-col", children: STARTERS.map((s15) => /* @__PURE__ */ jsxRuntimeExports.jsx(StarterRow, { starter: s15, onActivate: () => handleStarter(s15.label) }, s15.label)) }),
|
|
29803
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-8 pl-4 flex flex-col gap-1.5 text-[10px] t-text-muted", children: [
|
|
29804
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
29805
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("kbd", { className: "inline-flex items-center px-1 py-0 rounded border t-border-subtle t-bg-elevated text-[9.5px] font-mono t-text-secondary leading-[1.4]", children: "@" }),
|
|
29806
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "mention a note, paper, or file" })
|
|
29807
|
+
] }),
|
|
29808
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
29809
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("kbd", { className: "inline-flex items-center px-1 py-0 rounded border t-border-subtle t-bg-elevated text-[9.5px] font-mono t-text-secondary leading-[1.4]", children: "↵" }),
|
|
29810
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "send" }),
|
|
29811
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "opacity-50", "aria-hidden": true, children: "·" }),
|
|
29812
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("kbd", { className: "inline-flex items-center px-1 py-0 rounded border t-border-subtle t-bg-elevated text-[9.5px] font-mono t-text-secondary leading-[1.4]", children: "⇧↵" }),
|
|
29813
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "newline" })
|
|
29814
|
+
] })
|
|
29815
|
+
] })
|
|
29033
29816
|
] });
|
|
29034
29817
|
}
|
|
29035
29818
|
function getFileName(path2) {
|
|
@@ -29656,8 +30439,8 @@ function ToolUseStream({ events: propEvents }) {
|
|
|
29656
30439
|
running.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-1 mt-1", children: running.map((event) => /* @__PURE__ */ jsxRuntimeExports.jsx(ToolUseCard, { event }, event.id)) })
|
|
29657
30440
|
] });
|
|
29658
30441
|
}
|
|
29659
|
-
const api$
|
|
29660
|
-
const remarkPlugins$
|
|
30442
|
+
const api$7 = window.api;
|
|
30443
|
+
const remarkPlugins$2 = [remarkGfm];
|
|
29661
30444
|
function formatMessageTime(ts2) {
|
|
29662
30445
|
const d = new Date(ts2);
|
|
29663
30446
|
const now2 = /* @__PURE__ */ new Date();
|
|
@@ -29731,7 +30514,7 @@ function SelectionBookmark() {
|
|
|
29731
30514
|
try {
|
|
29732
30515
|
const first = selectedText.split(/[.!?\n]/)[0].trim();
|
|
29733
30516
|
const title = first.length > 60 ? first.slice(0, 57) + "…" : first || "Untitled selection";
|
|
29734
|
-
const created = await api$
|
|
30517
|
+
const created = await api$7.artifactCreate({
|
|
29735
30518
|
type: "note",
|
|
29736
30519
|
title,
|
|
29737
30520
|
content: selectedText,
|
|
@@ -29796,7 +30579,7 @@ const MessageBubble = React$2.memo(function MessageBubble2({ msg, isSaved }) {
|
|
|
29796
30579
|
try {
|
|
29797
30580
|
const first = msg.content.replace(/^#+\s*/, "").split(/[.!?\n]/)[0].trim();
|
|
29798
30581
|
const title = first.length > 60 ? first.slice(0, 57) + "…" : first || "Untitled note";
|
|
29799
|
-
const created = await api$
|
|
30582
|
+
const created = await api$7.artifactCreate({
|
|
29800
30583
|
type: "note",
|
|
29801
30584
|
title,
|
|
29802
30585
|
content: msg.content,
|
|
@@ -29842,7 +30625,7 @@ const MessageBubble = React$2.memo(function MessageBubble2({ msg, isSaved }) {
|
|
|
29842
30625
|
},
|
|
29843
30626
|
i
|
|
29844
30627
|
)) }),
|
|
29845
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "md-prose", style: { color: "var(--color-text)" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Markdown, { remarkPlugins: remarkPlugins$
|
|
30628
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "md-prose", style: { color: "var(--color-text)" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Markdown, { remarkPlugins: remarkPlugins$2, children: msg.content }) }),
|
|
29846
30629
|
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) }),
|
|
29847
30630
|
!isUser && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "absolute -right-8 top-2 flex flex-col gap-1.5", children: [
|
|
29848
30631
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -29872,11 +30655,18 @@ const MessageBubble = React$2.memo(function MessageBubble2({ msg, isSaved }) {
|
|
|
29872
30655
|
) });
|
|
29873
30656
|
});
|
|
29874
30657
|
function ThinkingIndicator() {
|
|
29875
|
-
return /* @__PURE__ */ jsxRuntimeExports.
|
|
29876
|
-
|
|
29877
|
-
|
|
29878
|
-
|
|
29879
|
-
|
|
30658
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
30659
|
+
"div",
|
|
30660
|
+
{
|
|
30661
|
+
role: "status",
|
|
30662
|
+
"aria-live": "polite",
|
|
30663
|
+
className: "flex items-center gap-2 mt-3 ml-2 text-[11px] t-text-muted",
|
|
30664
|
+
children: [
|
|
30665
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { size: 11, className: "t-text-accent-soft animate-spin shrink-0", "aria-hidden": true }),
|
|
30666
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Thinking…" })
|
|
30667
|
+
]
|
|
30668
|
+
}
|
|
30669
|
+
);
|
|
29880
30670
|
}
|
|
29881
30671
|
function StreamingBubble() {
|
|
29882
30672
|
const text2 = useChatStore((s15) => s15.streamingText);
|
|
@@ -29887,7 +30677,7 @@ function StreamingBubble() {
|
|
|
29887
30677
|
className: "max-w-[90%] rounded-2xl px-4 py-3 text-sm t-text assistant-bubble",
|
|
29888
30678
|
style: { background: "var(--color-bubble-assistant)" },
|
|
29889
30679
|
children: [
|
|
29890
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "md-prose", style: { color: "var(--color-text)" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Markdown, { remarkPlugins: remarkPlugins$
|
|
30680
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "md-prose", style: { color: "var(--color-text)" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Markdown, { remarkPlugins: remarkPlugins$2, children: text2 }) }),
|
|
29891
30681
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "inline-block w-1.5 h-4 t-bg-accent-soft animate-pulse ml-0.5 align-text-bottom" })
|
|
29892
30682
|
]
|
|
29893
30683
|
}
|
|
@@ -30052,7 +30842,7 @@ function ChatTimeline({ messages, scrollContainerRef }) {
|
|
|
30052
30842
|
borderRadius: 1,
|
|
30053
30843
|
background: "var(--color-accent-soft)",
|
|
30054
30844
|
opacity: isActive ? 1 : 0.35,
|
|
30055
|
-
transition: "
|
|
30845
|
+
transition: "opacity 80ms"
|
|
30056
30846
|
}
|
|
30057
30847
|
},
|
|
30058
30848
|
node2.msgId
|
|
@@ -30196,7 +30986,7 @@ function ChatMessages() {
|
|
|
30196
30986
|
)
|
|
30197
30987
|
] });
|
|
30198
30988
|
}
|
|
30199
|
-
const api$
|
|
30989
|
+
const api$6 = window.api;
|
|
30200
30990
|
const typeIcons$1 = {
|
|
30201
30991
|
note: /* @__PURE__ */ jsxRuntimeExports.jsx(StickyNote, { size: 13, className: "t-text-warning" }),
|
|
30202
30992
|
paper: /* @__PURE__ */ jsxRuntimeExports.jsx(BookOpen, { size: 13, className: "t-text-info" }),
|
|
@@ -30255,7 +31045,7 @@ function MentionPopover({ query, onSelect, onClose }) {
|
|
|
30255
31045
|
}
|
|
30256
31046
|
}
|
|
30257
31047
|
debounceRef.current = setTimeout(() => {
|
|
30258
|
-
api$
|
|
31048
|
+
api$6.getCandidates(search2, type).then((result) => {
|
|
30259
31049
|
if (stale) return;
|
|
30260
31050
|
setCandidates(result || []);
|
|
30261
31051
|
setSelectedIdx(0);
|
|
@@ -30448,7 +31238,7 @@ const SLASH_COMMANDS = [
|
|
|
30448
31238
|
{ name: "/delete", description: "Delete an entity", args: "<id>" },
|
|
30449
31239
|
{ name: "/help", description: "Show available commands" }
|
|
30450
31240
|
];
|
|
30451
|
-
const api$
|
|
31241
|
+
const api$5 = window.api;
|
|
30452
31242
|
const ACCEPTED_IMAGE_TYPES = ["image/png", "image/jpeg", "image/gif", "image/webp"];
|
|
30453
31243
|
const MAX_IMAGES = 5;
|
|
30454
31244
|
const ACCEPTED_DOC_EXTENSIONS = [".pdf", ".csv", ".md", ".txt", ".json", ".xml", ".html", ".docx"];
|
|
@@ -30569,7 +31359,7 @@ function ChatInput() {
|
|
|
30569
31359
|
const dataUrl = reader.result;
|
|
30570
31360
|
const base64 = dataUrl.split(",")[1];
|
|
30571
31361
|
try {
|
|
30572
|
-
const result = await api$
|
|
31362
|
+
const result = await api$5.convertFileToText(file.name, base64);
|
|
30573
31363
|
if (result?.success && result.content) {
|
|
30574
31364
|
setPendingFiles((p) => p.map(
|
|
30575
31365
|
(f) => f.name === file.name ? { ...f, content: result.content, loading: false } : f
|
|
@@ -30686,19 +31476,19 @@ ${fileBlocks}`;
|
|
|
30686
31476
|
try {
|
|
30687
31477
|
switch (cmd) {
|
|
30688
31478
|
case "/notes": {
|
|
30689
|
-
const notes = await api$
|
|
31479
|
+
const notes = await api$5.listNotes();
|
|
30690
31480
|
result = notes?.length ? `**Notes (${notes.length}):**
|
|
30691
31481
|
` + notes.map((n) => `- ${n.title} \`${n.id.slice(0, 8)}\``).join("\n") : "No notes yet.";
|
|
30692
31482
|
break;
|
|
30693
31483
|
}
|
|
30694
31484
|
case "/papers": {
|
|
30695
|
-
const papers = await api$
|
|
31485
|
+
const papers = await api$5.listLiterature();
|
|
30696
31486
|
result = papers?.length ? `**Papers (${papers.length}):**
|
|
30697
31487
|
` + papers.map((p) => `- ${p.title} \`${p.citeKey}\``).join("\n") : "No papers yet.";
|
|
30698
31488
|
break;
|
|
30699
31489
|
}
|
|
30700
31490
|
case "/data": {
|
|
30701
|
-
const data = await api$
|
|
31491
|
+
const data = await api$5.listData();
|
|
30702
31492
|
result = data?.length ? `**Data (${data.length}):**
|
|
30703
31493
|
` + data.map((d) => `- ${d.name} \`${d.id.slice(0, 8)}\``).join("\n") : "No data attachments yet.";
|
|
30704
31494
|
break;
|
|
@@ -30708,7 +31498,7 @@ ${fileBlocks}`;
|
|
|
30708
31498
|
result = "Usage: `/search <query>`";
|
|
30709
31499
|
break;
|
|
30710
31500
|
}
|
|
30711
|
-
const results = await api$
|
|
31501
|
+
const results = await api$5.search(rest);
|
|
30712
31502
|
result = results?.length ? `**Search results for "${rest}":**
|
|
30713
31503
|
` + results.map((r) => `- [${r.type}] ${r.title} \`${r.id.slice(0, 8)}\``).join("\n") : `No results for "${rest}".`;
|
|
30714
31504
|
break;
|
|
@@ -30718,7 +31508,7 @@ ${fileBlocks}`;
|
|
|
30718
31508
|
result = "Usage: `/note <title>`";
|
|
30719
31509
|
break;
|
|
30720
31510
|
}
|
|
30721
|
-
const r = await api$
|
|
31511
|
+
const r = await api$5.artifactCreate({ type: "note", title: rest, content: "" });
|
|
30722
31512
|
result = r?.success ? `Note saved: **${rest}**` : `Failed: ${r?.error || "unknown error"}`;
|
|
30723
31513
|
refreshEntities();
|
|
30724
31514
|
break;
|
|
@@ -30741,7 +31531,7 @@ ${fileBlocks}`;
|
|
|
30741
31531
|
const bibtex = flags.bibtex || `@article{${citeKey},
|
|
30742
31532
|
title = {${cleaned}}
|
|
30743
31533
|
}`;
|
|
30744
|
-
const r = await api$
|
|
31534
|
+
const r = await api$5.artifactCreate({
|
|
30745
31535
|
type: "paper",
|
|
30746
31536
|
title: cleaned,
|
|
30747
31537
|
authors,
|
|
@@ -30768,7 +31558,7 @@ ${fileBlocks}`;
|
|
|
30768
31558
|
result = "Usage: `/save-data <name> --path <file>`";
|
|
30769
31559
|
break;
|
|
30770
31560
|
}
|
|
30771
|
-
const r = await api$
|
|
31561
|
+
const r = await api$5.artifactCreate({
|
|
30772
31562
|
type: "data",
|
|
30773
31563
|
title: cleaned,
|
|
30774
31564
|
filePath: flags.path,
|
|
@@ -30779,7 +31569,7 @@ ${fileBlocks}`;
|
|
|
30779
31569
|
break;
|
|
30780
31570
|
}
|
|
30781
31571
|
case "/summary": {
|
|
30782
|
-
const summaryResult = await api$
|
|
31572
|
+
const summaryResult = await api$5.sessionSummaryGet();
|
|
30783
31573
|
if (!summaryResult?.success || !summaryResult?.summary) {
|
|
30784
31574
|
result = "No session summary available yet.";
|
|
30785
31575
|
break;
|
|
@@ -30806,7 +31596,7 @@ ${s15.openQuestions.map((q2) => `- ${q2}`).join("\n")}`;
|
|
|
30806
31596
|
result = "Usage: `/delete <id>`";
|
|
30807
31597
|
break;
|
|
30808
31598
|
}
|
|
30809
|
-
const r = await api$
|
|
31599
|
+
const r = await api$5.deleteEntity(rest);
|
|
30810
31600
|
result = r?.success ? `Deleted \`${rest}\`` : `Failed: ${r?.error || "not found"}`;
|
|
30811
31601
|
refreshEntities();
|
|
30812
31602
|
break;
|
|
@@ -31025,49 +31815,245 @@ ${s15.openQuestions.map((q2) => `- ${q2}`).join("\n")}`;
|
|
|
31025
31815
|
)
|
|
31026
31816
|
] });
|
|
31027
31817
|
}
|
|
31028
|
-
|
|
31029
|
-
|
|
31030
|
-
|
|
31031
|
-
|
|
31032
|
-
|
|
31033
|
-
|
|
31034
|
-
|
|
31035
|
-
|
|
31036
|
-
|
|
31037
|
-
|
|
31818
|
+
const api$4 = window.api;
|
|
31819
|
+
const remarkPlugins$1 = [remarkGfm];
|
|
31820
|
+
function PaperFallback({ paper }) {
|
|
31821
|
+
const authors = paper.authors || [];
|
|
31822
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [
|
|
31823
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h1", { className: "text-base font-semibold t-text leading-tight", children: paper.title }),
|
|
31824
|
+
authors.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs t-text-muted", children: authors.join(", ") }),
|
|
31825
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap gap-1.5", children: [
|
|
31826
|
+
paper.year && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "px-1.5 py-0.5 text-[10px] rounded t-bg-elevated t-text-muted", children: paper.year }),
|
|
31827
|
+
paper.venue && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "px-1.5 py-0.5 text-[10px] rounded t-bg-elevated t-text-muted", children: paper.venue }),
|
|
31828
|
+
paper.doi && !paper.doi.startsWith("unknown:") && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
31829
|
+
"a",
|
|
31830
|
+
{
|
|
31831
|
+
href: `https://doi.org/${paper.doi}`,
|
|
31832
|
+
target: "_blank",
|
|
31833
|
+
rel: "noopener noreferrer",
|
|
31834
|
+
className: "inline-flex items-center gap-0.5 px-1.5 py-0.5 text-[10px] rounded t-bg-elevated t-text-accent hover:underline",
|
|
31835
|
+
children: [
|
|
31836
|
+
"DOI ",
|
|
31837
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(ExternalLink, { size: 8 })
|
|
31838
|
+
]
|
|
31839
|
+
}
|
|
31840
|
+
),
|
|
31841
|
+
paper.relevanceScore != null && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "px-1.5 py-0.5 text-[10px] rounded t-bg-elevated t-text-accent", children: [
|
|
31842
|
+
paper.relevanceScore,
|
|
31843
|
+
"/10"
|
|
31844
|
+
] })
|
|
31845
|
+
] }),
|
|
31846
|
+
paper.abstract && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
31847
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] t-text-muted uppercase tracking-wider mb-1 font-medium", children: "Abstract" }),
|
|
31848
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs t-text-secondary leading-relaxed", children: paper.abstract })
|
|
31849
|
+
] }),
|
|
31850
|
+
paper.relevanceJustification && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
31851
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] t-text-muted uppercase tracking-wider mb-1 font-medium", children: "Relevance" }),
|
|
31852
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs t-text-secondary italic leading-relaxed", children: paper.relevanceJustification })
|
|
31853
|
+
] }),
|
|
31854
|
+
(paper.keyFindings || []).length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
31855
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] t-text-muted uppercase tracking-wider mb-1 font-medium", children: "Key Findings" }),
|
|
31856
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("ul", { className: "space-y-0.5", children: paper.keyFindings.map((f, i) => /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { className: "text-xs t-text-secondary flex items-start gap-1.5", children: [
|
|
31857
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0 mt-1 w-1 h-1 rounded-full bg-[var(--color-accent-soft)]" }),
|
|
31858
|
+
f
|
|
31859
|
+
] }, i)) })
|
|
31860
|
+
] }),
|
|
31861
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] t-text-muted italic pt-2", children: "No wiki page available for this paper yet." })
|
|
31862
|
+
] });
|
|
31863
|
+
}
|
|
31864
|
+
function WikiReaderPanel() {
|
|
31865
|
+
const slug = useUIStore((s15) => s15.wikiReaderSlug);
|
|
31866
|
+
const setSlug = useUIStore((s15) => s15.setWikiReaderSlug);
|
|
31867
|
+
const goBack = useUIStore((s15) => s15.wikiReaderBack);
|
|
31868
|
+
const history = useUIStore((s15) => s15.wikiReaderHistory);
|
|
31869
|
+
const papers = useEntityStore((s15) => s15.papers);
|
|
31870
|
+
const [content2, setContent] = reactExports.useState(null);
|
|
31871
|
+
const [loading, setLoading] = reactExports.useState(false);
|
|
31872
|
+
const isPaperFallback = slug?.startsWith("paper:");
|
|
31873
|
+
const fallbackPaper = isPaperFallback ? papers.find((p) => p.id === slug.replace("paper:", "")) : null;
|
|
31874
|
+
reactExports.useEffect(() => {
|
|
31875
|
+
if (!slug || isPaperFallback) {
|
|
31876
|
+
setContent(null);
|
|
31877
|
+
return;
|
|
31038
31878
|
}
|
|
31039
|
-
|
|
31040
|
-
|
|
31041
|
-
|
|
31042
|
-
|
|
31043
|
-
|
|
31044
|
-
|
|
31045
|
-
onClick: () => onSelect(null),
|
|
31046
|
-
className: `w-full text-left px-3 py-1.5 text-xs transition-colors ${selectedTopic === null ? "t-text-accent font-medium bg-[var(--color-accent-soft)]/10" : "t-text-secondary hover:t-bg-hover"}`,
|
|
31047
|
-
children: [
|
|
31048
|
-
"All Topics (",
|
|
31049
|
-
papers.length,
|
|
31050
|
-
")"
|
|
31051
|
-
]
|
|
31879
|
+
let cancelled = false;
|
|
31880
|
+
setLoading(true);
|
|
31881
|
+
api$4.wikiReadPage?.(slug).then((md) => {
|
|
31882
|
+
if (!cancelled) {
|
|
31883
|
+
setContent(md);
|
|
31884
|
+
setLoading(false);
|
|
31052
31885
|
}
|
|
31053
|
-
)
|
|
31054
|
-
|
|
31055
|
-
|
|
31056
|
-
|
|
31057
|
-
|
|
31058
|
-
|
|
31059
|
-
|
|
31060
|
-
|
|
31061
|
-
|
|
31062
|
-
|
|
31063
|
-
|
|
31064
|
-
|
|
31065
|
-
|
|
31066
|
-
|
|
31067
|
-
|
|
31068
|
-
|
|
31886
|
+
}).catch(() => {
|
|
31887
|
+
if (!cancelled) {
|
|
31888
|
+
setContent(null);
|
|
31889
|
+
setLoading(false);
|
|
31890
|
+
}
|
|
31891
|
+
});
|
|
31892
|
+
return () => {
|
|
31893
|
+
cancelled = true;
|
|
31894
|
+
};
|
|
31895
|
+
}, [slug, isPaperFallback]);
|
|
31896
|
+
const processedContent = reactExports.useMemo(() => {
|
|
31897
|
+
if (!content2) return null;
|
|
31898
|
+
return content2.replace(
|
|
31899
|
+
/<!--\s*paper:(\S+)\s*-->([\s\S]*?)<!--\s*\/paper:\1\s*-->/g,
|
|
31900
|
+
(_match, paperSlug, body) => {
|
|
31901
|
+
const firstLine = body.trim().split("\n")[0] || "";
|
|
31902
|
+
const titleMatch = firstLine.match(/\*{1,2}([^*]+)\*{1,2}/) || firstLine.match(/"([^"]+)"/);
|
|
31903
|
+
const title = titleMatch ? titleMatch[1] : paperSlug;
|
|
31904
|
+
return `
|
|
31905
|
+
---
|
|
31906
|
+
### [${title}](#wiki:${paperSlug})
|
|
31907
|
+
${body.trim()}
|
|
31908
|
+
`;
|
|
31909
|
+
}
|
|
31910
|
+
).replace(/<!--[\s\S]*?-->/g, "").replace(
|
|
31911
|
+
/\[\[([^\]]+)\]\]/g,
|
|
31912
|
+
(_match, innerSlug) => `[${innerSlug}](#wiki:${innerSlug})`
|
|
31913
|
+
);
|
|
31914
|
+
}, [content2]);
|
|
31915
|
+
const handleLinkClick = reactExports.useCallback((e) => {
|
|
31916
|
+
const target = e.target;
|
|
31917
|
+
const anchor = target.closest("a");
|
|
31918
|
+
if (!anchor) return;
|
|
31919
|
+
const href = anchor.getAttribute("href");
|
|
31920
|
+
if (href?.startsWith("#wiki:")) {
|
|
31921
|
+
e.preventDefault();
|
|
31922
|
+
setSlug(href.replace("#wiki:", ""));
|
|
31923
|
+
}
|
|
31924
|
+
}, [setSlug]);
|
|
31925
|
+
if (!slug) {
|
|
31926
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-center justify-center h-full text-center px-6", children: [
|
|
31927
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(BookOpen, { size: 28, className: "t-text-muted mb-2.5 opacity-30" }),
|
|
31928
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs t-text-muted", children: "Select a paper or concept to view details." })
|
|
31929
|
+
] });
|
|
31930
|
+
}
|
|
31931
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col h-full min-h-0", children: [
|
|
31932
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5 px-3 py-1.5 border-b t-border t-bg-surface shrink-0", children: [
|
|
31933
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
31934
|
+
"button",
|
|
31935
|
+
{
|
|
31936
|
+
onClick: goBack,
|
|
31937
|
+
disabled: history.length === 0,
|
|
31938
|
+
className: "p-1 rounded t-text-muted hover:t-text transition-colors disabled:opacity-30",
|
|
31939
|
+
title: "Back",
|
|
31940
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(ArrowLeft, { size: 14 })
|
|
31941
|
+
}
|
|
31942
|
+
),
|
|
31943
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 text-[11px] t-text-muted truncate font-mono", children: isPaperFallback ? fallbackPaper?.title || slug : slug }),
|
|
31944
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
31945
|
+
"button",
|
|
31946
|
+
{
|
|
31947
|
+
onClick: () => setSlug(null),
|
|
31948
|
+
className: "p-1 rounded t-text-muted hover:t-text transition-colors",
|
|
31949
|
+
title: "Close",
|
|
31950
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(X$1, { size: 13 })
|
|
31951
|
+
}
|
|
31952
|
+
)
|
|
31953
|
+
] }),
|
|
31954
|
+
/* @__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." }) })
|
|
31069
31955
|
] });
|
|
31070
31956
|
}
|
|
31957
|
+
function normalize(raw) {
|
|
31958
|
+
return raw.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, " ").trim();
|
|
31959
|
+
}
|
|
31960
|
+
function splitWords(s15) {
|
|
31961
|
+
const out = [];
|
|
31962
|
+
for (const w2 of s15.split(" ")) if (w2) out.push(w2);
|
|
31963
|
+
return out;
|
|
31964
|
+
}
|
|
31965
|
+
function firstAndLastWords(s15) {
|
|
31966
|
+
const words = splitWords(s15);
|
|
31967
|
+
if (words.length === 0) return [];
|
|
31968
|
+
if (words.length === 1) return [words[0]];
|
|
31969
|
+
return words[0] === words[words.length - 1] ? [words[0]] : [words[0], words[words.length - 1]];
|
|
31970
|
+
}
|
|
31971
|
+
function makeSearchable(p) {
|
|
31972
|
+
const normTitle = normalize(p.title || "");
|
|
31973
|
+
const titleWords = splitWords(normTitle);
|
|
31974
|
+
const normAuthors = (p.authors || []).map((a) => normalize(a)).filter(Boolean);
|
|
31975
|
+
const prefixTokens = /* @__PURE__ */ new Set();
|
|
31976
|
+
for (const a of normAuthors) for (const t of firstAndLastWords(a)) prefixTokens.add(t);
|
|
31977
|
+
return {
|
|
31978
|
+
normTitle,
|
|
31979
|
+
titleWords,
|
|
31980
|
+
titleWordSet: new Set(titleWords),
|
|
31981
|
+
normAuthors,
|
|
31982
|
+
authorPrefixTokens: Array.from(prefixTokens),
|
|
31983
|
+
normVenue: p.venue ? normalize(p.venue) : void 0,
|
|
31984
|
+
normTldr: p.tldr ? normalize(p.tldr) : void 0,
|
|
31985
|
+
normAbstract: p.abstract ? normalize(p.abstract) : void 0
|
|
31986
|
+
};
|
|
31987
|
+
}
|
|
31988
|
+
function tokenizeQuery(query) {
|
|
31989
|
+
const seen2 = /* @__PURE__ */ new Set();
|
|
31990
|
+
const out = [];
|
|
31991
|
+
for (const w2 of normalize(query).split(" ")) {
|
|
31992
|
+
if (w2.length < 2) continue;
|
|
31993
|
+
if (seen2.has(w2)) continue;
|
|
31994
|
+
seen2.add(w2);
|
|
31995
|
+
out.push(w2);
|
|
31996
|
+
}
|
|
31997
|
+
return out;
|
|
31998
|
+
}
|
|
31999
|
+
function isSubsequence(needle, hay) {
|
|
32000
|
+
if (needle.length === 0) return true;
|
|
32001
|
+
if (needle.length > hay.length) return false;
|
|
32002
|
+
let i = 0;
|
|
32003
|
+
for (let j2 = 0; j2 < hay.length && i < needle.length; j2++) {
|
|
32004
|
+
if (hay.charCodeAt(j2) === needle.charCodeAt(i)) i++;
|
|
32005
|
+
}
|
|
32006
|
+
return i === needle.length;
|
|
32007
|
+
}
|
|
32008
|
+
function scoreToken(token, p) {
|
|
32009
|
+
let best = 0;
|
|
32010
|
+
if (p.titleWordSet.has(token)) {
|
|
32011
|
+
best = Math.max(best, 20);
|
|
32012
|
+
} else if (p.normTitle.includes(token)) {
|
|
32013
|
+
best = Math.max(best, 10);
|
|
32014
|
+
} else if (token.length >= 4) {
|
|
32015
|
+
for (const word of p.titleWords) {
|
|
32016
|
+
if (word.length >= token.length && isSubsequence(token, word)) {
|
|
32017
|
+
best = Math.max(best, 4);
|
|
32018
|
+
break;
|
|
32019
|
+
}
|
|
32020
|
+
}
|
|
32021
|
+
}
|
|
32022
|
+
for (const pref of p.authorPrefixTokens) {
|
|
32023
|
+
if (pref.startsWith(token)) {
|
|
32024
|
+
best = Math.max(best, 10);
|
|
32025
|
+
break;
|
|
32026
|
+
}
|
|
32027
|
+
}
|
|
32028
|
+
if (best < 8) {
|
|
32029
|
+
for (const full of p.normAuthors) {
|
|
32030
|
+
if (full.includes(token)) {
|
|
32031
|
+
best = Math.max(best, 8);
|
|
32032
|
+
break;
|
|
32033
|
+
}
|
|
32034
|
+
}
|
|
32035
|
+
}
|
|
32036
|
+
if (p.normVenue && p.normVenue.includes(token)) best = Math.max(best, 3);
|
|
32037
|
+
if (p.normTldr && p.normTldr.includes(token)) best = Math.max(best, 3);
|
|
32038
|
+
if (p.normAbstract && p.normAbstract.includes(token)) best = Math.max(best, 2);
|
|
32039
|
+
return best;
|
|
32040
|
+
}
|
|
32041
|
+
function scorePaper(tokens, p) {
|
|
32042
|
+
if (tokens.length === 0) return 0;
|
|
32043
|
+
let total = 0;
|
|
32044
|
+
let hits = 0;
|
|
32045
|
+
for (const t of tokens) {
|
|
32046
|
+
const s15 = scoreToken(t, p);
|
|
32047
|
+
if (s15 > 0) {
|
|
32048
|
+
hits++;
|
|
32049
|
+
total += s15;
|
|
32050
|
+
}
|
|
32051
|
+
}
|
|
32052
|
+
const required = tokens.length <= 3 ? tokens.length : Math.ceil(0.7 * tokens.length);
|
|
32053
|
+
if (hits < required) return null;
|
|
32054
|
+
return total;
|
|
32055
|
+
}
|
|
32056
|
+
const api$3 = window.api;
|
|
31071
32057
|
function ScoreBadge({ score }) {
|
|
31072
32058
|
if (score == null) return null;
|
|
31073
32059
|
const color2 = score >= 8 ? "text-emerald-500" : score >= 6 ? "text-amber-500" : "t-text-muted";
|
|
@@ -31101,36 +32087,49 @@ function PaperRow({
|
|
|
31101
32087
|
paper,
|
|
31102
32088
|
expanded,
|
|
31103
32089
|
onToggle,
|
|
31104
|
-
|
|
32090
|
+
wikiSlug,
|
|
32091
|
+
isActive,
|
|
32092
|
+
source = "project"
|
|
31105
32093
|
}) {
|
|
32094
|
+
const setWikiSlug = useUIStore((s15) => s15.setWikiReaderSlug);
|
|
31106
32095
|
const authors = paper.authors || [];
|
|
31107
32096
|
const authorStr = authors.length <= 3 ? authors.join(", ") : `${authors.slice(0, 2).join(", ")} et al.`;
|
|
31108
32097
|
const keyFindings = paper.keyFindings || [];
|
|
31109
|
-
|
|
32098
|
+
const isWiki = source === "wiki";
|
|
32099
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `border-b t-border last:border-b-0 ${isActive ? "bg-[var(--color-accent-soft)]/8" : ""} ${isWiki ? "border-l-2 border-l-[var(--color-accent-soft)]" : ""}`, children: [
|
|
31110
32100
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
31111
32101
|
"div",
|
|
31112
32102
|
{
|
|
31113
|
-
className:
|
|
32103
|
+
className: `flex items-center gap-3 px-3 py-2 transition-colors cursor-pointer ${isActive ? "bg-[var(--color-accent-soft)]/10" : "hover:bg-[var(--color-accent-soft)]/5"}`,
|
|
31114
32104
|
onClick: onToggle,
|
|
31115
32105
|
children: [
|
|
31116
32106
|
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "shrink-0 t-text-muted", children: expanded ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { size: 14 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { size: 14 }) }),
|
|
31117
32107
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
31118
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
32108
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5 min-w-0", children: [
|
|
32109
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[13px] t-text font-medium truncate leading-tight", children: paper.title }),
|
|
32110
|
+
isWiki && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
32111
|
+
"span",
|
|
32112
|
+
{
|
|
32113
|
+
className: "shrink-0 px-1.5 py-0 text-[9px] uppercase tracking-wider rounded t-text-accent bg-[var(--color-accent-soft)]/15 border border-[var(--color-accent-soft)]/30",
|
|
32114
|
+
title: "From paper wiki — not in this project",
|
|
32115
|
+
children: "Wiki"
|
|
32116
|
+
}
|
|
32117
|
+
)
|
|
32118
|
+
] }),
|
|
31119
32119
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] t-text-muted truncate mt-0.5", children: authorStr })
|
|
31120
32120
|
] }),
|
|
31121
32121
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0 text-[11px] t-text-muted tabular-nums w-10 text-right", children: paper.year || "—" }),
|
|
31122
32122
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "shrink-0 w-10 text-right", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ScoreBadge, { score: paper.relevanceScore }) }),
|
|
31123
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0 text-[11px] t-text-muted tabular-nums w-12 text-right", children: paper.citationCount != null ? paper.citationCount : "—" }),
|
|
31124
32123
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
31125
32124
|
"button",
|
|
31126
32125
|
{
|
|
31127
32126
|
onClick: (e) => {
|
|
31128
32127
|
e.stopPropagation();
|
|
31129
|
-
|
|
32128
|
+
setWikiSlug(wikiSlug || `paper:${paper.id}`);
|
|
31130
32129
|
},
|
|
31131
|
-
className:
|
|
31132
|
-
title: "
|
|
31133
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx(BookOpen, { size:
|
|
32130
|
+
className: `shrink-0 p-1 rounded transition-colors ${wikiSlug ? "t-text-accent-soft hover:t-text-accent" : "t-text-muted hover:t-text-accent-soft"}`,
|
|
32131
|
+
title: wikiSlug ? "View wiki page" : "View paper details",
|
|
32132
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(BookOpen, { size: 13 })
|
|
31134
32133
|
}
|
|
31135
32134
|
)
|
|
31136
32135
|
]
|
|
@@ -31140,8 +32139,6 @@ function PaperRow({
|
|
|
31140
32139
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap gap-1.5", children: [
|
|
31141
32140
|
paper.venue && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "px-1.5 py-0.5 text-[10px] rounded t-bg-elevated t-text-muted", children: paper.venue }),
|
|
31142
32141
|
paper.subTopic && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "px-1.5 py-0.5 text-[10px] rounded bg-[var(--color-accent-soft)]/10 t-text-accent", children: paper.subTopic }),
|
|
31143
|
-
paper.externalSource && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "px-1.5 py-0.5 text-[10px] rounded t-bg-elevated t-text-muted", children: paper.externalSource }),
|
|
31144
|
-
paper.addedInRound && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "px-1.5 py-0.5 text-[10px] rounded t-bg-elevated t-text-muted", children: paper.addedInRound }),
|
|
31145
32142
|
paper.doi && !paper.doi.startsWith("unknown:") && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
31146
32143
|
"a",
|
|
31147
32144
|
{
|
|
@@ -31186,6 +32183,46 @@ function PaperRow({
|
|
|
31186
32183
|
] })
|
|
31187
32184
|
] });
|
|
31188
32185
|
}
|
|
32186
|
+
function WikiStatusPill() {
|
|
32187
|
+
const [status, setStatus] = reactExports.useState(null);
|
|
32188
|
+
reactExports.useEffect(() => {
|
|
32189
|
+
let cancelled = false;
|
|
32190
|
+
api$3.wikiGetStatus?.().then((s15) => {
|
|
32191
|
+
if (!cancelled) setStatus(s15);
|
|
32192
|
+
}).catch(() => {
|
|
32193
|
+
});
|
|
32194
|
+
const unsub = api$3.onWikiStatus?.((s15) => setStatus(s15));
|
|
32195
|
+
return () => {
|
|
32196
|
+
cancelled = true;
|
|
32197
|
+
unsub?.();
|
|
32198
|
+
};
|
|
32199
|
+
}, []);
|
|
32200
|
+
if (!status || status.state === "disabled") return null;
|
|
32201
|
+
const isProcessing = status.state === "processing";
|
|
32202
|
+
const isPaused = status.state === "paused";
|
|
32203
|
+
const totalInBatch = status.processed + status.pending;
|
|
32204
|
+
const pct = totalInBatch > 0 ? Math.round(status.processed / totalInBatch * 100) : 0;
|
|
32205
|
+
const dotClass = isProcessing ? "bg-blue-500 animate-pulse" : isPaused ? "bg-yellow-500" : "bg-emerald-500";
|
|
32206
|
+
const label = isProcessing ? `Wiki · processing${totalInBatch > 0 ? ` ${status.processed}/${totalInBatch}` : ""}` : isPaused ? "Wiki · paused" : `Wiki · idle${status.totalInWiki > 0 ? ` · ${status.totalInWiki} pages` : ""}`;
|
|
32207
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
32208
|
+
"div",
|
|
32209
|
+
{
|
|
32210
|
+
className: "ml-auto flex items-center gap-2 shrink-0",
|
|
32211
|
+
title: status.lastRunAt ? `Last tick: ${new Date(status.lastRunAt).toLocaleString()}` : void 0,
|
|
32212
|
+
children: [
|
|
32213
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `inline-block w-1.5 h-1.5 rounded-full ${dotClass}` }),
|
|
32214
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-muted tabular-nums", children: label }),
|
|
32215
|
+
isProcessing && totalInBatch > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-16 h-1 rounded-full t-bg-elevated overflow-hidden", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
32216
|
+
"div",
|
|
32217
|
+
{
|
|
32218
|
+
className: "h-full bg-blue-500 transition-[width] duration-500 ease-out",
|
|
32219
|
+
style: { width: `${pct}%` }
|
|
32220
|
+
}
|
|
32221
|
+
) })
|
|
32222
|
+
]
|
|
32223
|
+
}
|
|
32224
|
+
);
|
|
32225
|
+
}
|
|
31189
32226
|
function CoverageBar$1({ papers }) {
|
|
31190
32227
|
const topicCounts = reactExports.useMemo(() => {
|
|
31191
32228
|
const counts = /* @__PURE__ */ new Map();
|
|
@@ -31215,7 +32252,7 @@ function CoverageBar$1({ papers }) {
|
|
|
31215
32252
|
highRelevance,
|
|
31216
32253
|
" highly relevant"
|
|
31217
32254
|
] }),
|
|
31218
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "
|
|
32255
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "max-w-48 w-48", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-1.5 rounded-full t-bg-elevated overflow-hidden", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
31219
32256
|
"div",
|
|
31220
32257
|
{
|
|
31221
32258
|
className: "h-full rounded-full t-gradient-accent-h",
|
|
@@ -31223,10 +32260,11 @@ function CoverageBar$1({ papers }) {
|
|
|
31223
32260
|
width: `${Math.min(100, highRelevance / Math.max(papers.length, 1) * 100)}%`
|
|
31224
32261
|
}
|
|
31225
32262
|
}
|
|
31226
|
-
) }) })
|
|
32263
|
+
) }) }),
|
|
32264
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(WikiStatusPill, {})
|
|
31227
32265
|
] });
|
|
31228
32266
|
}
|
|
31229
|
-
function FilterBar$1() {
|
|
32267
|
+
function FilterBar$1({ topics }) {
|
|
31230
32268
|
const filter = useUIStore((s15) => s15.literatureFilter);
|
|
31231
32269
|
const setFilter = useUIStore((s15) => s15.setLiteratureFilter);
|
|
31232
32270
|
const [showFilters, setShowFilters] = reactExports.useState(false);
|
|
@@ -31241,7 +32279,7 @@ function FilterBar$1() {
|
|
|
31241
32279
|
type: "text",
|
|
31242
32280
|
value: filter.search,
|
|
31243
32281
|
onChange: (e) => setFilter({ search: e.target.value }),
|
|
31244
|
-
placeholder: "Search papers
|
|
32282
|
+
placeholder: "Search papers...",
|
|
31245
32283
|
className: "w-full pl-8 pr-3 py-1.5 text-xs rounded-lg border t-border t-bg-surface t-text focus:outline-none focus:border-[var(--color-accent-soft)]"
|
|
31246
32284
|
}
|
|
31247
32285
|
),
|
|
@@ -31254,6 +32292,18 @@ function FilterBar$1() {
|
|
|
31254
32292
|
}
|
|
31255
32293
|
)
|
|
31256
32294
|
] }),
|
|
32295
|
+
topics.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
32296
|
+
"select",
|
|
32297
|
+
{
|
|
32298
|
+
value: filter.subTopic || "",
|
|
32299
|
+
onChange: (e) => setFilter({ subTopic: e.target.value || null }),
|
|
32300
|
+
className: "px-2 py-1.5 text-xs rounded-lg border t-border t-bg-surface t-text max-w-40",
|
|
32301
|
+
children: [
|
|
32302
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "", children: "All topics" }),
|
|
32303
|
+
topics.map((t) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: t, children: t }, t))
|
|
32304
|
+
]
|
|
32305
|
+
}
|
|
32306
|
+
),
|
|
31257
32307
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
31258
32308
|
"button",
|
|
31259
32309
|
{
|
|
@@ -31261,7 +32311,6 @@ function FilterBar$1() {
|
|
|
31261
32311
|
className: `flex items-center gap-1 px-2 py-1.5 text-xs rounded-lg border t-border transition-colors ${hasActiveFilters ? "border-[var(--color-accent-soft)] t-text-accent" : "t-text-muted hover:t-text-secondary"}`,
|
|
31262
32312
|
children: [
|
|
31263
32313
|
/* @__PURE__ */ jsxRuntimeExports.jsx(Filter, { size: 12 }),
|
|
31264
|
-
"Filters",
|
|
31265
32314
|
hasActiveFilters && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-1.5 h-1.5 rounded-full bg-[var(--color-accent-soft)]" })
|
|
31266
32315
|
]
|
|
31267
32316
|
}
|
|
@@ -31293,12 +32342,47 @@ function FilterBar$1() {
|
|
|
31293
32342
|
] })
|
|
31294
32343
|
] });
|
|
31295
32344
|
}
|
|
32345
|
+
function wikiMetaToEntityItem(meta) {
|
|
32346
|
+
return {
|
|
32347
|
+
id: `wiki:${meta.slug}`,
|
|
32348
|
+
type: "paper",
|
|
32349
|
+
title: meta.title,
|
|
32350
|
+
authors: meta.authors,
|
|
32351
|
+
year: meta.year,
|
|
32352
|
+
venue: meta.venue,
|
|
32353
|
+
abstract: meta.tldr
|
|
32354
|
+
// show tldr as abstract preview for wiki rows
|
|
32355
|
+
};
|
|
32356
|
+
}
|
|
31296
32357
|
function LiteratureView() {
|
|
31297
32358
|
const papers = useEntityStore((s15) => s15.papers);
|
|
31298
32359
|
const filter = useUIStore((s15) => s15.literatureFilter);
|
|
31299
32360
|
const setFilter = useUIStore((s15) => s15.setLiteratureFilter);
|
|
31300
|
-
const
|
|
31301
|
-
const
|
|
32361
|
+
const wikiReaderSlug = useUIStore((s15) => s15.wikiReaderSlug);
|
|
32362
|
+
const setWikiSlug = useUIStore((s15) => s15.setWikiReaderSlug);
|
|
32363
|
+
const [expandedKey, setExpandedKey] = reactExports.useState(null);
|
|
32364
|
+
const [wikiSlugs, setWikiSlugs] = reactExports.useState({});
|
|
32365
|
+
const [wikiMeta, setWikiMeta] = reactExports.useState([]);
|
|
32366
|
+
reactExports.useEffect(() => {
|
|
32367
|
+
let cancelled = false;
|
|
32368
|
+
api$3.wikiPaperSlugMap?.().then((map2) => {
|
|
32369
|
+
if (!cancelled && map2) setWikiSlugs(map2);
|
|
32370
|
+
}).catch(() => {
|
|
32371
|
+
});
|
|
32372
|
+
return () => {
|
|
32373
|
+
cancelled = true;
|
|
32374
|
+
};
|
|
32375
|
+
}, [papers]);
|
|
32376
|
+
reactExports.useEffect(() => {
|
|
32377
|
+
let cancelled = false;
|
|
32378
|
+
api$3.wikiListPaperMeta?.().then((list2) => {
|
|
32379
|
+
if (!cancelled && Array.isArray(list2)) setWikiMeta(list2);
|
|
32380
|
+
}).catch(() => {
|
|
32381
|
+
});
|
|
32382
|
+
return () => {
|
|
32383
|
+
cancelled = true;
|
|
32384
|
+
};
|
|
32385
|
+
}, []);
|
|
31302
32386
|
const handleSort = reactExports.useCallback(
|
|
31303
32387
|
(key) => {
|
|
31304
32388
|
if (filter.sortBy === key) {
|
|
@@ -31309,73 +32393,121 @@ function LiteratureView() {
|
|
|
31309
32393
|
},
|
|
31310
32394
|
[filter.sortBy, filter.sortDir, setFilter]
|
|
31311
32395
|
);
|
|
31312
|
-
const
|
|
31313
|
-
|
|
31314
|
-
|
|
31315
|
-
const
|
|
31316
|
-
|
|
31317
|
-
const title = (p.title || "").toLowerCase();
|
|
31318
|
-
const abstract = (p.abstract || "").toLowerCase();
|
|
31319
|
-
const authors = (p.authors || []).join(" ").toLowerCase();
|
|
31320
|
-
return title.includes(q2) || abstract.includes(q2) || authors.includes(q2);
|
|
31321
|
-
});
|
|
31322
|
-
}
|
|
31323
|
-
if (filter.subTopic) {
|
|
31324
|
-
result = result.filter(
|
|
31325
|
-
(p) => (p.subTopic || "Uncategorized") === filter.subTopic
|
|
31326
|
-
);
|
|
31327
|
-
}
|
|
31328
|
-
if (filter.minScore > 0) {
|
|
31329
|
-
result = result.filter((p) => (p.relevanceScore || 0) >= filter.minScore);
|
|
32396
|
+
const topics = reactExports.useMemo(() => {
|
|
32397
|
+
const counts = /* @__PURE__ */ new Map();
|
|
32398
|
+
for (const p of papers) {
|
|
32399
|
+
const topic = p.subTopic;
|
|
32400
|
+
if (topic) counts.set(topic, (counts.get(topic) || 0) + 1);
|
|
31330
32401
|
}
|
|
31331
|
-
|
|
31332
|
-
|
|
32402
|
+
return Array.from(counts.entries()).sort((a, b2) => b2[1] - a[1]).map(([t]) => t);
|
|
32403
|
+
}, [papers]);
|
|
32404
|
+
const projectRows = reactExports.useMemo(() => {
|
|
32405
|
+
return papers.map((p) => ({
|
|
32406
|
+
key: `project:${p.id}`,
|
|
32407
|
+
source: "project",
|
|
32408
|
+
paper: p,
|
|
32409
|
+
wikiSlug: wikiSlugs[p.id],
|
|
32410
|
+
searchable: makeSearchable({
|
|
32411
|
+
title: p.title || "",
|
|
32412
|
+
authors: p.authors || [],
|
|
32413
|
+
venue: p.venue,
|
|
32414
|
+
tldr: void 0,
|
|
32415
|
+
abstract: p.abstract
|
|
32416
|
+
})
|
|
32417
|
+
}));
|
|
32418
|
+
}, [papers, wikiSlugs]);
|
|
32419
|
+
const wikiOnlyRows = reactExports.useMemo(() => {
|
|
32420
|
+
const usedSlugs = new Set(Object.values(wikiSlugs));
|
|
32421
|
+
return wikiMeta.filter((m) => !usedSlugs.has(m.slug)).map((m) => ({
|
|
32422
|
+
key: `wiki:${m.slug}`,
|
|
32423
|
+
source: "wiki",
|
|
32424
|
+
paper: wikiMetaToEntityItem(m),
|
|
32425
|
+
wikiSlug: m.slug,
|
|
32426
|
+
searchable: makeSearchable({
|
|
32427
|
+
title: m.title,
|
|
32428
|
+
authors: m.authors,
|
|
32429
|
+
venue: m.venue,
|
|
32430
|
+
tldr: m.tldr
|
|
32431
|
+
})
|
|
32432
|
+
}));
|
|
32433
|
+
}, [wikiMeta, papers, wikiSlugs]);
|
|
32434
|
+
const filteredRows = reactExports.useMemo(() => {
|
|
32435
|
+
const query = filter.search.trim();
|
|
32436
|
+
const tokens = query ? tokenizeQuery(query) : [];
|
|
32437
|
+
const searching = tokens.length > 0;
|
|
32438
|
+
const passesProjectFilters = (p) => {
|
|
32439
|
+
if (filter.subTopic && (p.subTopic || "Uncategorized") !== filter.subTopic) return false;
|
|
32440
|
+
if (filter.minScore > 0 && (p.relevanceScore || 0) < filter.minScore) return false;
|
|
32441
|
+
if (filter.source && p.externalSource !== filter.source) return false;
|
|
32442
|
+
if (filter.round && p.addedInRound !== filter.round) return false;
|
|
32443
|
+
return true;
|
|
32444
|
+
};
|
|
32445
|
+
const scored = [];
|
|
32446
|
+
for (const row of projectRows) {
|
|
32447
|
+
if (!passesProjectFilters(row.paper)) continue;
|
|
32448
|
+
if (searching) {
|
|
32449
|
+
const s15 = scorePaper(tokens, row.searchable);
|
|
32450
|
+
if (s15 == null) continue;
|
|
32451
|
+
scored.push({ row, score: s15 });
|
|
32452
|
+
} else {
|
|
32453
|
+
scored.push({ row, score: 0 });
|
|
32454
|
+
}
|
|
31333
32455
|
}
|
|
31334
|
-
if (
|
|
31335
|
-
|
|
32456
|
+
if (searching) {
|
|
32457
|
+
for (const row of wikiOnlyRows) {
|
|
32458
|
+
const s15 = scorePaper(tokens, row.searchable);
|
|
32459
|
+
if (s15 == null) continue;
|
|
32460
|
+
scored.push({ row, score: s15 });
|
|
32461
|
+
}
|
|
31336
32462
|
}
|
|
31337
|
-
|
|
31338
|
-
|
|
32463
|
+
const dir = filter.sortDir === "desc" ? -1 : 1;
|
|
32464
|
+
const compareSortKey = (a, b2) => {
|
|
31339
32465
|
switch (filter.sortBy) {
|
|
31340
|
-
case "year":
|
|
31341
|
-
|
|
31342
|
-
|
|
31343
|
-
return (
|
|
31344
|
-
|
|
31345
|
-
|
|
31346
|
-
const as2 = a.relevanceScore || 0;
|
|
31347
|
-
const bs2 = b2.relevanceScore || 0;
|
|
31348
|
-
return (as2 - bs2) * dir;
|
|
31349
|
-
}
|
|
31350
|
-
case "citations": {
|
|
31351
|
-
const ac2 = a.citationCount || 0;
|
|
31352
|
-
const bc2 = b2.citationCount || 0;
|
|
31353
|
-
return (ac2 - bc2) * dir;
|
|
31354
|
-
}
|
|
32466
|
+
case "year":
|
|
32467
|
+
return ((a.year || 0) - (b2.year || 0)) * dir;
|
|
32468
|
+
case "relevance":
|
|
32469
|
+
return ((a.relevanceScore || 0) - (b2.relevanceScore || 0)) * dir;
|
|
32470
|
+
case "citations":
|
|
32471
|
+
return ((a.citationCount || 0) - (b2.citationCount || 0)) * dir;
|
|
31355
32472
|
case "title":
|
|
31356
32473
|
return a.title.localeCompare(b2.title) * dir;
|
|
31357
32474
|
default:
|
|
31358
32475
|
return 0;
|
|
31359
32476
|
}
|
|
32477
|
+
};
|
|
32478
|
+
scored.sort((a, b2) => {
|
|
32479
|
+
if (searching) {
|
|
32480
|
+
if (a.score !== b2.score) return b2.score - a.score;
|
|
32481
|
+
}
|
|
32482
|
+
return compareSortKey(a.row.paper, b2.row.paper);
|
|
31360
32483
|
});
|
|
31361
|
-
return
|
|
31362
|
-
}, [
|
|
31363
|
-
|
|
32484
|
+
return scored.map((s15) => s15.row);
|
|
32485
|
+
}, [projectRows, wikiOnlyRows, filter]);
|
|
32486
|
+
reactExports.useEffect(() => {
|
|
32487
|
+
if (wikiReaderSlug || filteredRows.length === 0) return;
|
|
32488
|
+
const first = filteredRows[0];
|
|
32489
|
+
if (first.source === "wiki") {
|
|
32490
|
+
setWikiSlug(first.wikiSlug);
|
|
32491
|
+
} else {
|
|
32492
|
+
setWikiSlug(first.wikiSlug || `paper:${first.paper.id}`);
|
|
32493
|
+
}
|
|
32494
|
+
}, [filteredRows, wikiReaderSlug, setWikiSlug]);
|
|
32495
|
+
const activeRowKey = reactExports.useMemo(() => {
|
|
32496
|
+
if (!wikiReaderSlug) return null;
|
|
32497
|
+
if (wikiReaderSlug.startsWith("paper:")) {
|
|
32498
|
+
return `project:${wikiReaderSlug.slice("paper:".length)}`;
|
|
32499
|
+
}
|
|
32500
|
+
for (const [paperId, slug] of Object.entries(wikiSlugs)) {
|
|
32501
|
+
if (slug === wikiReaderSlug) return `project:${paperId}`;
|
|
32502
|
+
}
|
|
32503
|
+
return `wiki:${wikiReaderSlug}`;
|
|
32504
|
+
}, [wikiReaderSlug, wikiSlugs]);
|
|
31364
32505
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex flex-col min-h-0", children: [
|
|
31365
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(FilterBar$1, {}),
|
|
32506
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(FilterBar$1, { topics }),
|
|
31366
32507
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex min-h-0", children: [
|
|
31367
|
-
|
|
31368
|
-
TopicTree,
|
|
31369
|
-
{
|
|
31370
|
-
papers,
|
|
31371
|
-
selectedTopic: filter.subTopic,
|
|
31372
|
-
onSelect: (topic) => setFilter({ subTopic: topic })
|
|
31373
|
-
}
|
|
31374
|
-
),
|
|
31375
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex flex-col min-w-0", children: [
|
|
32508
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-1/2 flex flex-col min-w-0 border-r t-border", children: [
|
|
31376
32509
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 px-3 py-1.5 border-b t-border t-bg-surface", children: [
|
|
31377
32510
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-5" }),
|
|
31378
|
-
" ",
|
|
31379
32511
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
31380
32512
|
SortHeader,
|
|
31381
32513
|
{
|
|
@@ -31408,36 +32540,34 @@ function LiteratureView() {
|
|
|
31408
32540
|
className: "w-10 justify-end"
|
|
31409
32541
|
}
|
|
31410
32542
|
),
|
|
31411
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
31412
|
-
SortHeader,
|
|
31413
|
-
{
|
|
31414
|
-
label: "Cites",
|
|
31415
|
-
sortKey: "citations",
|
|
31416
|
-
currentSort: filter.sortBy,
|
|
31417
|
-
currentDir: filter.sortDir,
|
|
31418
|
-
onSort: handleSort,
|
|
31419
|
-
className: "w-12 justify-end"
|
|
31420
|
-
}
|
|
31421
|
-
),
|
|
31422
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-8" }),
|
|
31423
|
-
" "
|
|
32543
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-8" })
|
|
31424
32544
|
] }),
|
|
31425
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 overflow-y-auto", children:
|
|
32545
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 overflow-y-auto", children: filteredRows.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-center justify-center h-full text-center px-8", children: [
|
|
31426
32546
|
/* @__PURE__ */ jsxRuntimeExports.jsx(BookOpen, { size: 32, className: "t-text-muted mb-3 opacity-40" }),
|
|
31427
32547
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm t-text-muted", children: papers.length === 0 ? "No papers yet. Use the chat to search for literature." : "No papers match your filters." })
|
|
31428
|
-
] }) :
|
|
32548
|
+
] }) : filteredRows.map((row) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
31429
32549
|
PaperRow,
|
|
31430
32550
|
{
|
|
31431
|
-
paper,
|
|
31432
|
-
|
|
31433
|
-
|
|
31434
|
-
|
|
32551
|
+
paper: row.paper,
|
|
32552
|
+
source: row.source,
|
|
32553
|
+
expanded: expandedKey === row.key,
|
|
32554
|
+
isActive: activeRowKey === row.key,
|
|
32555
|
+
onToggle: () => {
|
|
32556
|
+
setExpandedKey(expandedKey === row.key ? null : row.key);
|
|
32557
|
+
if (row.source === "wiki") {
|
|
32558
|
+
setWikiSlug(row.wikiSlug);
|
|
32559
|
+
} else {
|
|
32560
|
+
setWikiSlug(row.wikiSlug || `paper:${row.paper.id}`);
|
|
32561
|
+
}
|
|
32562
|
+
},
|
|
32563
|
+
wikiSlug: row.wikiSlug
|
|
31435
32564
|
},
|
|
31436
|
-
|
|
32565
|
+
row.key
|
|
31437
32566
|
)) })
|
|
31438
|
-
] })
|
|
32567
|
+
] }),
|
|
32568
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-1/2 min-w-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(WikiReaderPanel, {}) })
|
|
31439
32569
|
] }),
|
|
31440
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(CoverageBar$1, { papers:
|
|
32570
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(CoverageBar$1, { papers: filteredRows.filter((r) => r.source === "project").map((r) => r.paper) })
|
|
31441
32571
|
] });
|
|
31442
32572
|
}
|
|
31443
32573
|
function formatDuration(seconds) {
|
|
@@ -31514,7 +32644,16 @@ function RunRow({
|
|
|
31514
32644
|
className: "flex items-center gap-3 px-3 py-2 hover:bg-[var(--color-accent-soft)]/5 transition-colors cursor-pointer",
|
|
31515
32645
|
onClick: onToggle,
|
|
31516
32646
|
children: [
|
|
31517
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
32647
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
32648
|
+
"button",
|
|
32649
|
+
{
|
|
32650
|
+
type: "button",
|
|
32651
|
+
"aria-label": expanded ? "Collapse run details" : "Expand run details",
|
|
32652
|
+
"aria-expanded": expanded,
|
|
32653
|
+
className: "shrink-0 t-text-muted",
|
|
32654
|
+
children: expanded ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { size: 14 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { size: 14 })
|
|
32655
|
+
}
|
|
32656
|
+
),
|
|
31518
32657
|
/* @__PURE__ */ jsxRuntimeExports.jsx(StatusDot, { status: run.status }),
|
|
31519
32658
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
31520
32659
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[13px] t-text font-medium truncate leading-tight font-mono", children: run.command }),
|
|
@@ -31647,7 +32786,9 @@ function FilterBar({
|
|
|
31647
32786
|
search2 && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
31648
32787
|
"button",
|
|
31649
32788
|
{
|
|
32789
|
+
type: "button",
|
|
31650
32790
|
onClick: () => onSearchChange(""),
|
|
32791
|
+
"aria-label": "Clear search",
|
|
31651
32792
|
className: "absolute right-2 top-1/2 -translate-y-1/2 t-text-muted hover:t-text",
|
|
31652
32793
|
children: /* @__PURE__ */ jsxRuntimeExports.jsx(X$1, { size: 12 })
|
|
31653
32794
|
}
|
|
@@ -31790,22 +32931,56 @@ function ViewSwitcher() {
|
|
|
31790
32931
|
const setCenterView = useUIStore((s15) => s15.setCenterView);
|
|
31791
32932
|
const paperCount = useEntityStore((s15) => s15.papers.length);
|
|
31792
32933
|
const activeComputeRuns = useActiveRunCount();
|
|
31793
|
-
return
|
|
31794
|
-
|
|
31795
|
-
|
|
31796
|
-
|
|
31797
|
-
|
|
31798
|
-
|
|
31799
|
-
|
|
31800
|
-
|
|
31801
|
-
label,
|
|
31802
|
-
|
|
31803
|
-
|
|
31804
|
-
|
|
31805
|
-
|
|
31806
|
-
|
|
31807
|
-
|
|
31808
|
-
|
|
32934
|
+
return (
|
|
32935
|
+
// Bottom hairline gives the nav a real anchor — without it, the tabs
|
|
32936
|
+
// float in a gray area between the drag region and the content.
|
|
32937
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
32938
|
+
"nav",
|
|
32939
|
+
{
|
|
32940
|
+
"aria-label": "View switcher",
|
|
32941
|
+
className: "flex items-stretch gap-1 px-4 pt-10 border-b t-border",
|
|
32942
|
+
children: viewTabs.map(({ key, label, icon: Icon2, shortcut }) => {
|
|
32943
|
+
const isActive = centerView === key;
|
|
32944
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
32945
|
+
"button",
|
|
32946
|
+
{
|
|
32947
|
+
onClick: () => setCenterView(key),
|
|
32948
|
+
"aria-current": isActive ? "page" : void 0,
|
|
32949
|
+
title: `${label} (${shortcut})`,
|
|
32950
|
+
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"}`,
|
|
32951
|
+
children: [
|
|
32952
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Icon2, { size: 14, className: isActive ? "t-text-accent" : "" }),
|
|
32953
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: label }),
|
|
32954
|
+
key === "literature" && paperCount > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
32955
|
+
"span",
|
|
32956
|
+
{
|
|
32957
|
+
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"}`,
|
|
32958
|
+
children: paperCount
|
|
32959
|
+
}
|
|
32960
|
+
),
|
|
32961
|
+
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 }),
|
|
32962
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
32963
|
+
"kbd",
|
|
32964
|
+
{
|
|
32965
|
+
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"}`,
|
|
32966
|
+
children: shortcut
|
|
32967
|
+
}
|
|
32968
|
+
),
|
|
32969
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
32970
|
+
"span",
|
|
32971
|
+
{
|
|
32972
|
+
"aria-hidden": true,
|
|
32973
|
+
className: `pointer-events-none absolute left-0 right-0 -bottom-px h-[2px] transition-colors ${isActive ? "t-bg-accent" : "bg-transparent"}`
|
|
32974
|
+
}
|
|
32975
|
+
)
|
|
32976
|
+
]
|
|
32977
|
+
},
|
|
32978
|
+
key
|
|
32979
|
+
);
|
|
32980
|
+
})
|
|
32981
|
+
}
|
|
32982
|
+
)
|
|
32983
|
+
);
|
|
31809
32984
|
}
|
|
31810
32985
|
function CenterPanel() {
|
|
31811
32986
|
const centerView = useUIStore((s15) => s15.centerView);
|
|
@@ -31832,7 +33007,7 @@ function CenterPanel() {
|
|
|
31832
33007
|
}
|
|
31833
33008
|
const remarkPlugins = [remarkGfm];
|
|
31834
33009
|
const LazyMilkdownMarkdownEditor = reactExports.lazy(async () => {
|
|
31835
|
-
const mod = await __vitePreload(() => import("./MilkdownMarkdownEditor-
|
|
33010
|
+
const mod = await __vitePreload(() => import("./MilkdownMarkdownEditor-De2Q1dek.js").then((n) => n.bL), true ? __vite__mapDeps([0,1]) : void 0, import.meta.url);
|
|
31836
33011
|
return { default: mod.MilkdownMarkdownEditor };
|
|
31837
33012
|
});
|
|
31838
33013
|
const typeIcons = {
|
|
@@ -32458,14 +33633,21 @@ function StatusBar() {
|
|
|
32458
33633
|
const hasRunUsage = runTokens > 0;
|
|
32459
33634
|
const hasProjectUsage = allTimeTokens > 0;
|
|
32460
33635
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "h-7 flex items-center px-4 gap-5 border-t t-border t-bg-surface text-[11px] t-text-secondary select-none shrink-0", children: [
|
|
32461
|
-
hasSkills && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center gap-2 overflow-hidden", children: activeSkills.map((name2) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
32462
|
-
|
|
32463
|
-
|
|
32464
|
-
|
|
32465
|
-
|
|
32466
|
-
|
|
33636
|
+
hasSkills && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center gap-2 overflow-hidden", children: activeSkills.map((name2) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
33637
|
+
"span",
|
|
33638
|
+
{
|
|
33639
|
+
className: "flex items-center gap-1.5 px-1.5 py-0.5 rounded t-bg-accent/10 t-text-accent whitespace-nowrap",
|
|
33640
|
+
children: [
|
|
33641
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(CircleDot, { size: 10, className: "shrink-0", "aria-hidden": true }),
|
|
33642
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: name2 })
|
|
33643
|
+
]
|
|
33644
|
+
},
|
|
33645
|
+
name2
|
|
33646
|
+
)) }),
|
|
33647
|
+
hasActivity && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center gap-3 overflow-hidden", children: toolSummary.map((t) => /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1.5 whitespace-nowrap", children: [
|
|
33648
|
+
t.pending > 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { size: 11, className: "t-text-warning shrink-0 animate-spin", "aria-label": "In progress" }) : t.failed > 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx(X$1, { size: 11, className: "t-text-error shrink-0", "aria-label": "Failed" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { size: 11, className: "t-text-success shrink-0", "aria-label": "Done" }),
|
|
32467
33649
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "capitalize", children: t.name }),
|
|
32468
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "t-text-muted", children: [
|
|
33650
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "t-text-muted tabular-nums", children: [
|
|
32469
33651
|
"×",
|
|
32470
33652
|
t.total
|
|
32471
33653
|
] })
|
|
@@ -32483,7 +33665,7 @@ function StatusBar() {
|
|
|
32483
33665
|
"% cache"
|
|
32484
33666
|
] })
|
|
32485
33667
|
] }),
|
|
32486
|
-
hasRunUsage && hasProjectUsage && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-muted", children: "
|
|
33668
|
+
hasRunUsage && hasProjectUsage && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-muted opacity-50", "aria-hidden": true, children: "·" }),
|
|
32487
33669
|
hasProjectUsage && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "t-text-muted", title: "Project total", children: [
|
|
32488
33670
|
formatTokens(allTimeTokens),
|
|
32489
33671
|
" / ",
|
|
@@ -41277,134 +42459,437 @@ const useToolProgressStore = create$1((set) => ({
|
|
|
41277
42459
|
clearAll: () => set({ inFlight: /* @__PURE__ */ new Map() })
|
|
41278
42460
|
}));
|
|
41279
42461
|
const api = window.api;
|
|
41280
|
-
function
|
|
41281
|
-
const
|
|
41282
|
-
|
|
41283
|
-
const
|
|
41284
|
-
|
|
41285
|
-
|
|
41286
|
-
|
|
41287
|
-
|
|
41288
|
-
|
|
41289
|
-
|
|
41290
|
-
if (
|
|
41291
|
-
const
|
|
41292
|
-
|
|
41293
|
-
|
|
41294
|
-
|
|
41295
|
-
|
|
41296
|
-
|
|
41297
|
-
|
|
41298
|
-
|
|
42462
|
+
function relativeTime(iso) {
|
|
42463
|
+
const then = new Date(iso).getTime();
|
|
42464
|
+
if (!Number.isFinite(then)) return "";
|
|
42465
|
+
const diffMs = Date.now() - then;
|
|
42466
|
+
const mins = Math.floor(diffMs / 6e4);
|
|
42467
|
+
if (mins < 1) return "just now";
|
|
42468
|
+
if (mins < 60) return `${mins}m ago`;
|
|
42469
|
+
const hours = Math.floor(mins / 60);
|
|
42470
|
+
if (hours < 24) return `${hours}h ago`;
|
|
42471
|
+
const days = Math.floor(hours / 24);
|
|
42472
|
+
if (days < 7) return `${days}d ago`;
|
|
42473
|
+
const weeks = Math.floor(days / 7);
|
|
42474
|
+
if (weeks < 5) return `${weeks}w ago`;
|
|
42475
|
+
return new Date(iso).toLocaleDateString(void 0, { month: "short", day: "numeric" });
|
|
42476
|
+
}
|
|
42477
|
+
function splitPath(p) {
|
|
42478
|
+
const clean = p.replace(/\/+$/, "");
|
|
42479
|
+
const idx = clean.lastIndexOf("/");
|
|
42480
|
+
if (idx < 0) return { name: clean, parent: "" };
|
|
42481
|
+
return { name: clean.slice(idx + 1), parent: clean.slice(0, idx) };
|
|
42482
|
+
}
|
|
42483
|
+
function Kbd({ children }) {
|
|
42484
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("kbd", { className: "inline-flex items-center px-1 py-0 rounded border t-border-subtle t-bg-elevated text-[9.5px] font-mono t-text-secondary leading-[1.4]", children });
|
|
42485
|
+
}
|
|
42486
|
+
function RecentRow({
|
|
42487
|
+
entry,
|
|
42488
|
+
active,
|
|
42489
|
+
confirmRemove,
|
|
42490
|
+
stats,
|
|
42491
|
+
onActivate,
|
|
42492
|
+
onHover
|
|
42493
|
+
}) {
|
|
42494
|
+
const { name: name2, parent } = splitPath(entry.path);
|
|
42495
|
+
const totalArtifacts = stats ? stats.papers + stats.notes + stats.data : 0;
|
|
42496
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
42497
|
+
"button",
|
|
41299
42498
|
{
|
|
41300
|
-
|
|
41301
|
-
|
|
41302
|
-
|
|
41303
|
-
|
|
41304
|
-
|
|
41305
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[13px] font-medium t-text", children: [
|
|
41306
|
-
"v",
|
|
41307
|
-
update.latest,
|
|
41308
|
-
" available",
|
|
41309
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "t-text-secondary font-normal ml-1.5", children: [
|
|
41310
|
-
"(current: v",
|
|
41311
|
-
update.current,
|
|
41312
|
-
")"
|
|
41313
|
-
] })
|
|
41314
|
-
] }),
|
|
41315
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-2 flex items-center gap-2", children: [
|
|
41316
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "flex-1 text-xs font-mono px-2.5 py-1.5 rounded-md t-bg-surface t-text select-all", children: command }),
|
|
41317
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
41318
|
-
"button",
|
|
41319
|
-
{
|
|
41320
|
-
onClick: handleCopy,
|
|
41321
|
-
className: "shrink-0 p-1.5 rounded-md t-bg-surface hover:opacity-80 transition-opacity",
|
|
41322
|
-
title: "Copy command",
|
|
41323
|
-
children: copied ? /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { size: 14, className: "t-text-success" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { size: 14, className: "t-text-secondary" })
|
|
41324
|
-
}
|
|
41325
|
-
)
|
|
41326
|
-
] })
|
|
41327
|
-
] }),
|
|
42499
|
+
type: "button",
|
|
42500
|
+
onClick: onActivate,
|
|
42501
|
+
onMouseEnter: onHover,
|
|
42502
|
+
className: `group relative w-full text-left flex items-baseline gap-4 py-2 pl-4 pr-3 rounded-sm transition-colors ${active ? "t-bg-hover" : ""}`,
|
|
42503
|
+
children: [
|
|
41328
42504
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
41329
|
-
"
|
|
42505
|
+
"span",
|
|
41330
42506
|
{
|
|
41331
|
-
|
|
41332
|
-
className:
|
|
41333
|
-
title: "Dismiss",
|
|
41334
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx(X$1, { size: 14 })
|
|
42507
|
+
"aria-hidden": true,
|
|
42508
|
+
className: `absolute left-0 top-1 bottom-1 w-[2px] rounded-full transition-colors ${active ? "t-bg-accent" : "bg-transparent group-hover:t-bg-accent-soft"}`
|
|
41335
42509
|
}
|
|
41336
|
-
)
|
|
41337
|
-
|
|
42510
|
+
),
|
|
42511
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
42512
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
42513
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `text-[13px] font-medium truncate ${active ? "t-text" : "t-text-secondary group-hover:t-text"}`, children: name2 }),
|
|
42514
|
+
entry.pinned && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] uppercase tracking-wider t-text-muted", children: "pinned" }),
|
|
42515
|
+
stats && !stats.initialized && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] uppercase tracking-wider t-text-muted", title: "No .research-pilot directory yet", children: "new" })
|
|
42516
|
+
] }),
|
|
42517
|
+
parent && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[11px] t-text-muted truncate font-mono mt-0.5", children: parent })
|
|
42518
|
+
] }),
|
|
42519
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "shrink-0 flex flex-col items-end gap-0.5 tabular-nums text-[10px] t-text-muted", children: confirmRemove ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-error-soft", children: "press ⌫ again" }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
42520
|
+
stats && totalArtifacts > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-1.5 t-text-secondary", children: [
|
|
42521
|
+
stats.papers > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
|
|
42522
|
+
stats.papers,
|
|
42523
|
+
"p"
|
|
42524
|
+
] }),
|
|
42525
|
+
stats.notes > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
|
|
42526
|
+
stats.notes,
|
|
42527
|
+
"n"
|
|
42528
|
+
] }),
|
|
42529
|
+
stats.data > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
|
|
42530
|
+
stats.data,
|
|
42531
|
+
"d"
|
|
42532
|
+
] })
|
|
42533
|
+
] }),
|
|
42534
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: relativeTime(entry.openedAt) })
|
|
42535
|
+
] }) })
|
|
42536
|
+
]
|
|
41338
42537
|
}
|
|
41339
42538
|
);
|
|
41340
42539
|
}
|
|
42540
|
+
function WikiPanel({ onOpenSettings }) {
|
|
42541
|
+
const [stats, setStats] = reactExports.useState(null);
|
|
42542
|
+
const [recentPapers, setRecentPapers] = reactExports.useState([]);
|
|
42543
|
+
const [status, setStatus] = reactExports.useState(null);
|
|
42544
|
+
const [loaded, setLoaded] = reactExports.useState(false);
|
|
42545
|
+
reactExports.useEffect(() => {
|
|
42546
|
+
let cancelled = false;
|
|
42547
|
+
Promise.all([
|
|
42548
|
+
api.wikiGetStats?.().catch(() => null),
|
|
42549
|
+
api.wikiListPaperMeta?.().catch(() => null),
|
|
42550
|
+
api.wikiGetStatus?.().catch(() => null)
|
|
42551
|
+
]).then(([s15, list2, st2]) => {
|
|
42552
|
+
if (cancelled) return;
|
|
42553
|
+
if (s15) setStats(s15);
|
|
42554
|
+
if (Array.isArray(list2)) {
|
|
42555
|
+
const sorted = [...list2].sort((a, b2) => (b2.updatedAt || "").localeCompare(a.updatedAt || ""));
|
|
42556
|
+
setRecentPapers(sorted.slice(0, 3));
|
|
42557
|
+
}
|
|
42558
|
+
if (st2) setStatus(st2);
|
|
42559
|
+
setLoaded(true);
|
|
42560
|
+
});
|
|
42561
|
+
const unsub = api.onWikiStatus?.((s15) => setStatus(s15));
|
|
42562
|
+
return () => {
|
|
42563
|
+
cancelled = true;
|
|
42564
|
+
unsub?.();
|
|
42565
|
+
};
|
|
42566
|
+
}, []);
|
|
42567
|
+
if (!loaded) return null;
|
|
42568
|
+
const isDisabled = status?.state === "disabled";
|
|
42569
|
+
const isEmpty = (stats?.papers ?? 0) === 0;
|
|
42570
|
+
const header = /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-baseline justify-between mb-3", children: [
|
|
42571
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] uppercase tracking-wider t-text-muted font-medium", children: "Paper wiki" }),
|
|
42572
|
+
!isEmpty && stats && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] t-text-muted tabular-nums", children: stats.papers }),
|
|
42573
|
+
isDisabled && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] uppercase tracking-wider t-text-muted", children: "off" })
|
|
42574
|
+
] });
|
|
42575
|
+
if (isDisabled) {
|
|
42576
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("section", { "aria-labelledby": "wiki-panel-heading", children: [
|
|
42577
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h2", { id: "wiki-panel-heading", className: "sr-only", children: "Paper wiki" }),
|
|
42578
|
+
header,
|
|
42579
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[12px] t-text-secondary leading-relaxed", children: "Turn the wiki agent on in settings to build a cross-project summary of every paper you save. It runs quietly in the background." }),
|
|
42580
|
+
onOpenSettings && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
42581
|
+
"button",
|
|
42582
|
+
{
|
|
42583
|
+
onClick: onOpenSettings,
|
|
42584
|
+
className: "mt-3 inline-flex items-center gap-1.5 text-[11px] t-text-accent-soft hover:t-text-accent transition-colors",
|
|
42585
|
+
children: "Open settings →"
|
|
42586
|
+
}
|
|
42587
|
+
)
|
|
42588
|
+
] });
|
|
42589
|
+
}
|
|
42590
|
+
if (isEmpty) {
|
|
42591
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("section", { "aria-labelledby": "wiki-panel-heading", children: [
|
|
42592
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h2", { id: "wiki-panel-heading", className: "sr-only", children: "Paper wiki" }),
|
|
42593
|
+
header,
|
|
42594
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[12px] t-text-secondary leading-relaxed", children: "Your cross-project library. As you save papers in any project, the agent summarizes each one here — visible from every project afterwards." }),
|
|
42595
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "mt-3 text-[11px] t-text-muted leading-relaxed", children: "Nothing here yet. Open a project and add your first paper." })
|
|
42596
|
+
] });
|
|
42597
|
+
}
|
|
42598
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("section", { "aria-labelledby": "wiki-panel-heading", children: [
|
|
42599
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h2", { id: "wiki-panel-heading", className: "sr-only", children: "Paper wiki" }),
|
|
42600
|
+
header,
|
|
42601
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-baseline gap-3 text-[11px] t-text-secondary tabular-nums mb-6", children: [
|
|
42602
|
+
(stats?.fulltext ?? 0) > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
|
|
42603
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text font-medium", children: stats.fulltext }),
|
|
42604
|
+
" ",
|
|
42605
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-muted", children: "fulltext" })
|
|
42606
|
+
] }),
|
|
42607
|
+
(stats?.abstractOnly ?? 0) > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
42608
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-muted opacity-50", "aria-hidden": true, children: "·" }),
|
|
42609
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
|
|
42610
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text font-medium", children: stats.abstractOnly }),
|
|
42611
|
+
" ",
|
|
42612
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-muted", children: "abstract" })
|
|
42613
|
+
] })
|
|
42614
|
+
] }),
|
|
42615
|
+
(stats?.concepts ?? 0) > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
42616
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-muted opacity-50", "aria-hidden": true, children: "·" }),
|
|
42617
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
|
|
42618
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text font-medium", children: stats.concepts }),
|
|
42619
|
+
" ",
|
|
42620
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-muted", children: "concepts" })
|
|
42621
|
+
] })
|
|
42622
|
+
] })
|
|
42623
|
+
] }),
|
|
42624
|
+
recentPapers.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-6", children: [
|
|
42625
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] uppercase tracking-wider t-text-muted font-medium mb-2", children: "Recently added" }),
|
|
42626
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("ul", { className: "flex flex-col gap-1.5", children: recentPapers.map((p) => /* @__PURE__ */ jsxRuntimeExports.jsxs("li", { className: "flex items-baseline gap-2", children: [
|
|
42627
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0 text-[10px] t-text-muted mt-1", children: "·" }),
|
|
42628
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
42629
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[12px] t-text-secondary truncate leading-snug", children: p.title }),
|
|
42630
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-[10px] t-text-muted font-mono truncate", children: [
|
|
42631
|
+
p.slug,
|
|
42632
|
+
p.updatedAt && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
42633
|
+
" · ",
|
|
42634
|
+
relativeTime(p.updatedAt)
|
|
42635
|
+
] })
|
|
42636
|
+
] })
|
|
42637
|
+
] })
|
|
42638
|
+
] }, p.slug)) })
|
|
42639
|
+
] }),
|
|
42640
|
+
status && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5 text-[10px] t-text-muted", children: [
|
|
42641
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
42642
|
+
"span",
|
|
42643
|
+
{
|
|
42644
|
+
className: `inline-block w-1.5 h-1.5 rounded-full ${status.state === "processing" ? "bg-blue-500 animate-pulse" : status.state === "paused" ? "bg-yellow-500" : "bg-emerald-500"}`,
|
|
42645
|
+
"aria-hidden": true
|
|
42646
|
+
}
|
|
42647
|
+
),
|
|
42648
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "capitalize", children: status.state }),
|
|
42649
|
+
status.lastRunAt && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
42650
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "opacity-50", "aria-hidden": true, children: "·" }),
|
|
42651
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
|
|
42652
|
+
"last tick ",
|
|
42653
|
+
relativeTime(status.lastRunAt)
|
|
42654
|
+
] })
|
|
42655
|
+
] })
|
|
42656
|
+
] })
|
|
42657
|
+
] });
|
|
42658
|
+
}
|
|
42659
|
+
function TipsBlock() {
|
|
42660
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("section", { "aria-label": "Tips", children: [
|
|
42661
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] uppercase tracking-wider t-text-muted font-medium mb-2", children: "Tips" }),
|
|
42662
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("ul", { className: "flex flex-col gap-1.5 text-[11px] t-text-secondary", children: [
|
|
42663
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("li", { className: "flex items-center gap-2", children: [
|
|
42664
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Kbd, { children: "/" }),
|
|
42665
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-muted", children: "or" }),
|
|
42666
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Kbd, { children: "⌘K" }),
|
|
42667
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "open the command palette" })
|
|
42668
|
+
] }),
|
|
42669
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("li", { className: "flex items-center gap-2", children: [
|
|
42670
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Kbd, { children: "@" }),
|
|
42671
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "mention a note, paper, or file" })
|
|
42672
|
+
] }),
|
|
42673
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("li", { className: "flex items-center gap-2", children: [
|
|
42674
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Kbd, { children: "⌘1" }),
|
|
42675
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Kbd, { children: "⌘2" }),
|
|
42676
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "switch between chat and literature" })
|
|
42677
|
+
] })
|
|
42678
|
+
] })
|
|
42679
|
+
] });
|
|
42680
|
+
}
|
|
41341
42681
|
function FolderGate({ onOpenSettings }) {
|
|
41342
42682
|
const pickFolder = useSessionStore((s15) => s15.pickFolder);
|
|
42683
|
+
const openPath = useSessionStore((s15) => s15.openPath);
|
|
41343
42684
|
const refreshEntities = useEntityStore((s15) => s15.refreshAll);
|
|
41344
|
-
const
|
|
41345
|
-
|
|
41346
|
-
|
|
41347
|
-
|
|
42685
|
+
const [recents, setRecents] = reactExports.useState([]);
|
|
42686
|
+
const [projectStats, setProjectStats] = reactExports.useState({});
|
|
42687
|
+
const [activeIndex, setActiveIndex] = reactExports.useState(0);
|
|
42688
|
+
const [confirmRemove, setConfirmRemove] = reactExports.useState(null);
|
|
42689
|
+
const [opening, setOpening] = reactExports.useState(false);
|
|
42690
|
+
reactExports.useEffect(() => {
|
|
42691
|
+
let cancelled = false;
|
|
42692
|
+
api.listRecentProjects?.().then((list2) => {
|
|
42693
|
+
if (!cancelled && Array.isArray(list2)) setRecents(list2);
|
|
42694
|
+
}).catch(() => {
|
|
42695
|
+
});
|
|
42696
|
+
return () => {
|
|
42697
|
+
cancelled = true;
|
|
42698
|
+
};
|
|
42699
|
+
}, []);
|
|
42700
|
+
reactExports.useEffect(() => {
|
|
42701
|
+
if (recents.length === 0) {
|
|
42702
|
+
setProjectStats({});
|
|
42703
|
+
return;
|
|
41348
42704
|
}
|
|
41349
|
-
|
|
41350
|
-
|
|
41351
|
-
|
|
41352
|
-
|
|
41353
|
-
|
|
41354
|
-
|
|
41355
|
-
|
|
41356
|
-
|
|
41357
|
-
|
|
41358
|
-
|
|
41359
|
-
|
|
41360
|
-
|
|
41361
|
-
|
|
41362
|
-
|
|
41363
|
-
|
|
41364
|
-
|
|
41365
|
-
|
|
41366
|
-
|
|
41367
|
-
|
|
41368
|
-
|
|
41369
|
-
|
|
41370
|
-
|
|
41371
|
-
|
|
41372
|
-
|
|
41373
|
-
|
|
41374
|
-
|
|
41375
|
-
|
|
41376
|
-
|
|
41377
|
-
|
|
41378
|
-
|
|
41379
|
-
|
|
41380
|
-
|
|
41381
|
-
|
|
41382
|
-
|
|
41383
|
-
|
|
41384
|
-
|
|
41385
|
-
|
|
41386
|
-
|
|
41387
|
-
|
|
41388
|
-
|
|
41389
|
-
|
|
41390
|
-
|
|
41391
|
-
|
|
41392
|
-
|
|
41393
|
-
|
|
41394
|
-
|
|
41395
|
-
|
|
41396
|
-
|
|
41397
|
-
|
|
41398
|
-
|
|
41399
|
-
|
|
41400
|
-
|
|
41401
|
-
|
|
41402
|
-
|
|
41403
|
-
|
|
41404
|
-
|
|
42705
|
+
let cancelled = false;
|
|
42706
|
+
api.projectStatsBatch?.(recents.map((r) => r.path)).then(
|
|
42707
|
+
(map2) => {
|
|
42708
|
+
if (!cancelled && map2) setProjectStats(map2);
|
|
42709
|
+
}
|
|
42710
|
+
).catch(() => {
|
|
42711
|
+
});
|
|
42712
|
+
return () => {
|
|
42713
|
+
cancelled = true;
|
|
42714
|
+
};
|
|
42715
|
+
}, [recents]);
|
|
42716
|
+
const handleOpen = reactExports.useCallback(async (path2) => {
|
|
42717
|
+
if (opening) return;
|
|
42718
|
+
setOpening(true);
|
|
42719
|
+
try {
|
|
42720
|
+
const ok2 = await openPath(path2);
|
|
42721
|
+
if (ok2) await refreshEntities();
|
|
42722
|
+
} finally {
|
|
42723
|
+
setOpening(false);
|
|
42724
|
+
}
|
|
42725
|
+
}, [openPath, refreshEntities, opening]);
|
|
42726
|
+
const handlePickNew = reactExports.useCallback(async () => {
|
|
42727
|
+
if (opening) return;
|
|
42728
|
+
setOpening(true);
|
|
42729
|
+
try {
|
|
42730
|
+
const ok2 = await pickFolder();
|
|
42731
|
+
if (ok2) await refreshEntities();
|
|
42732
|
+
} finally {
|
|
42733
|
+
setOpening(false);
|
|
42734
|
+
}
|
|
42735
|
+
}, [pickFolder, refreshEntities, opening]);
|
|
42736
|
+
const handleRemove = reactExports.useCallback(async (path2) => {
|
|
42737
|
+
await api.removeRecentProject?.(path2);
|
|
42738
|
+
setRecents((prev) => {
|
|
42739
|
+
const next = prev.filter((e) => e.path !== path2);
|
|
42740
|
+
setActiveIndex((i) => Math.min(Math.max(0, i), Math.max(0, next.length - 1)));
|
|
42741
|
+
return next;
|
|
42742
|
+
});
|
|
42743
|
+
setConfirmRemove(null);
|
|
42744
|
+
}, []);
|
|
42745
|
+
reactExports.useEffect(() => {
|
|
42746
|
+
const handler = (e) => {
|
|
42747
|
+
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "o") {
|
|
42748
|
+
e.preventDefault();
|
|
42749
|
+
handlePickNew();
|
|
42750
|
+
return;
|
|
42751
|
+
}
|
|
42752
|
+
if (e.key === "ArrowDown") {
|
|
42753
|
+
if (recents.length === 0) return;
|
|
42754
|
+
e.preventDefault();
|
|
42755
|
+
setActiveIndex((i) => (i + 1) % recents.length);
|
|
42756
|
+
setConfirmRemove(null);
|
|
42757
|
+
} else if (e.key === "ArrowUp") {
|
|
42758
|
+
if (recents.length === 0) return;
|
|
42759
|
+
e.preventDefault();
|
|
42760
|
+
setActiveIndex((i) => (i - 1 + recents.length) % recents.length);
|
|
42761
|
+
setConfirmRemove(null);
|
|
42762
|
+
} else if (e.key === "Enter") {
|
|
42763
|
+
if (recents.length === 0) {
|
|
42764
|
+
e.preventDefault();
|
|
42765
|
+
handlePickNew();
|
|
42766
|
+
return;
|
|
42767
|
+
}
|
|
42768
|
+
const target = recents[activeIndex];
|
|
42769
|
+
if (target) {
|
|
42770
|
+
e.preventDefault();
|
|
42771
|
+
handleOpen(target.path);
|
|
42772
|
+
}
|
|
42773
|
+
} else if (e.key === "Backspace" || e.key === "Delete") {
|
|
42774
|
+
if (recents.length === 0) return;
|
|
42775
|
+
const target = recents[activeIndex];
|
|
42776
|
+
if (!target) return;
|
|
42777
|
+
e.preventDefault();
|
|
42778
|
+
if (confirmRemove === target.path) {
|
|
42779
|
+
handleRemove(target.path);
|
|
42780
|
+
} else {
|
|
42781
|
+
setConfirmRemove(target.path);
|
|
42782
|
+
}
|
|
42783
|
+
} else if (e.key === "Escape") {
|
|
42784
|
+
setConfirmRemove(null);
|
|
42785
|
+
}
|
|
42786
|
+
};
|
|
42787
|
+
window.addEventListener("keydown", handler);
|
|
42788
|
+
return () => window.removeEventListener("keydown", handler);
|
|
42789
|
+
}, [recents, activeIndex, confirmRemove, handleOpen, handlePickNew, handleRemove]);
|
|
42790
|
+
const hasRecents = recents.length > 0;
|
|
42791
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col h-screen w-screen t-bg-base t-text overflow-hidden", children: [
|
|
42792
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "drag-region fixed top-0 left-0 right-0 h-10 z-50" }),
|
|
42793
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
42794
|
+
"main",
|
|
42795
|
+
{
|
|
42796
|
+
id: "main-content",
|
|
42797
|
+
className: "flex-1 overflow-y-auto pt-[12vh] px-[8vw] pb-6",
|
|
42798
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mx-auto w-full max-w-6xl", children: [
|
|
42799
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-12 pl-1", children: [
|
|
42800
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h1", { className: "text-[16px] font-semibold t-text tracking-tight leading-none", children: "Research Pilot" }),
|
|
42801
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[11px] t-text-muted mt-1.5 leading-none", children: "A research workflow, not a chat window." })
|
|
42802
|
+
] }),
|
|
42803
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 xl:grid-cols-[minmax(0,1fr)_20rem] gap-12 xl:gap-16 items-start", children: [
|
|
42804
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("section", { "aria-labelledby": "recents-heading", children: [
|
|
42805
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h2", { id: "recents-heading", className: "sr-only", children: "Recent projects" }),
|
|
42806
|
+
hasRecents ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
42807
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-baseline justify-between mb-2 pl-4", children: [
|
|
42808
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] uppercase tracking-wider t-text-muted font-medium", children: "Recent projects" }),
|
|
42809
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] t-text-muted tabular-nums", children: recents.length })
|
|
42810
|
+
] }),
|
|
42811
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-col mb-6", children: recents.map((entry, i) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
42812
|
+
RecentRow,
|
|
42813
|
+
{
|
|
42814
|
+
entry,
|
|
42815
|
+
stats: projectStats[entry.path],
|
|
42816
|
+
active: i === activeIndex,
|
|
42817
|
+
confirmRemove: confirmRemove === entry.path,
|
|
42818
|
+
onActivate: () => handleOpen(entry.path),
|
|
42819
|
+
onHover: () => {
|
|
42820
|
+
setActiveIndex(i);
|
|
42821
|
+
if (confirmRemove !== entry.path) setConfirmRemove(null);
|
|
42822
|
+
}
|
|
42823
|
+
},
|
|
42824
|
+
entry.path
|
|
42825
|
+
)) })
|
|
42826
|
+
] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-6 pl-4", children: [
|
|
42827
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-baseline justify-between mb-3", children: [
|
|
42828
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] uppercase tracking-wider t-text-muted font-medium", children: "Recent projects" }),
|
|
42829
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] t-text-muted", children: "—" })
|
|
42830
|
+
] }),
|
|
42831
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[13px] t-text-secondary leading-relaxed mb-1", children: "No projects yet." }),
|
|
42832
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[12px] t-text-muted leading-relaxed max-w-md", children: [
|
|
42833
|
+
"Pick a folder to begin — we'll create a",
|
|
42834
|
+
" ",
|
|
42835
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "px-1 py-0.5 rounded t-bg-elevated text-[10.5px] font-mono t-text-secondary", children: ".research-pilot" }),
|
|
42836
|
+
" ",
|
|
42837
|
+
"directory beside it for your notes, papers, and data. Everything stays on disk; nothing goes to the cloud."
|
|
42838
|
+
] })
|
|
42839
|
+
] }),
|
|
42840
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "pl-4", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
42841
|
+
"button",
|
|
42842
|
+
{
|
|
42843
|
+
onClick: handlePickNew,
|
|
42844
|
+
disabled: opening,
|
|
42845
|
+
className: "inline-flex items-center gap-2.5 px-3 py-1.5 rounded-md border t-border t-text-secondary hover:t-text hover:t-border-accent-soft text-[12px] transition-colors disabled:opacity-50",
|
|
42846
|
+
children: [
|
|
42847
|
+
hasRecents ? "Open another folder…" : "Choose a folder to begin",
|
|
42848
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Kbd, { children: "⌘O" })
|
|
42849
|
+
]
|
|
42850
|
+
}
|
|
42851
|
+
) })
|
|
42852
|
+
] }),
|
|
42853
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("aside", { "aria-label": "Global status", className: "flex flex-col gap-10 xl:pl-4 xl:border-l t-border-subtle", children: [
|
|
42854
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "xl:pl-8", children: /* @__PURE__ */ jsxRuntimeExports.jsx(WikiPanel, { onOpenSettings }) }),
|
|
42855
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "xl:pl-8", children: /* @__PURE__ */ jsxRuntimeExports.jsx(TipsBlock, {}) })
|
|
42856
|
+
] })
|
|
42857
|
+
] }),
|
|
42858
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-16 pl-1 flex items-center gap-5 text-[10px] t-text-muted flex-wrap", children: [
|
|
42859
|
+
hasRecents && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
42860
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
42861
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Kbd, { children: "↑↓" }),
|
|
42862
|
+
" navigate"
|
|
42863
|
+
] }),
|
|
42864
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
42865
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Kbd, { children: "↵" }),
|
|
42866
|
+
" open"
|
|
42867
|
+
] }),
|
|
42868
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
42869
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Kbd, { children: "⌫" }),
|
|
42870
|
+
" remove"
|
|
42871
|
+
] })
|
|
42872
|
+
] }),
|
|
42873
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
42874
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Kbd, { children: "⌘O" }),
|
|
42875
|
+
" new folder"
|
|
42876
|
+
] }),
|
|
42877
|
+
onOpenSettings && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
42878
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Kbd, { children: "⌘," }),
|
|
42879
|
+
" settings"
|
|
42880
|
+
] }),
|
|
42881
|
+
onOpenSettings && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
42882
|
+
"button",
|
|
42883
|
+
{
|
|
42884
|
+
onClick: onOpenSettings,
|
|
42885
|
+
className: "ml-auto text-[11px] t-text-muted hover:t-text-secondary transition-colors",
|
|
42886
|
+
children: "API keys & settings →"
|
|
42887
|
+
}
|
|
42888
|
+
)
|
|
42889
|
+
] })
|
|
41405
42890
|
] })
|
|
41406
|
-
|
|
41407
|
-
|
|
42891
|
+
}
|
|
42892
|
+
)
|
|
41408
42893
|
] });
|
|
41409
42894
|
}
|
|
41410
42895
|
function App() {
|
|
@@ -41419,16 +42904,17 @@ function App() {
|
|
|
41419
42904
|
const terminalVisible = useUIStore((s15) => s15.terminalVisible);
|
|
41420
42905
|
const terminalAlive = useUIStore((s15) => s15.terminalAlive);
|
|
41421
42906
|
const theme = useUIStore((s15) => s15.theme);
|
|
41422
|
-
const [
|
|
41423
|
-
const [
|
|
41424
|
-
const [
|
|
42907
|
+
const [settingsOpen, setSettingsOpen] = reactExports.useState(false);
|
|
42908
|
+
const [settingsTab, setSettingsTab] = reactExports.useState("api-keys");
|
|
42909
|
+
const [authChecked, setAuthChecked] = reactExports.useState(false);
|
|
41425
42910
|
reactExports.useEffect(() => {
|
|
41426
|
-
api.
|
|
41427
|
-
|
|
41428
|
-
|
|
41429
|
-
|
|
41430
|
-
|
|
41431
|
-
|
|
42911
|
+
api.hasLlmAuth?.().then((hasAuth) => {
|
|
42912
|
+
if (!hasAuth) {
|
|
42913
|
+
setSettingsOpen(true);
|
|
42914
|
+
setSettingsTab("api-keys");
|
|
42915
|
+
}
|
|
42916
|
+
setAuthChecked(true);
|
|
42917
|
+
}).catch(() => setAuthChecked(true));
|
|
41432
42918
|
}, []);
|
|
41433
42919
|
reactExports.useEffect(() => {
|
|
41434
42920
|
document.documentElement.classList.remove("dark", "light");
|
|
@@ -41622,18 +43108,33 @@ function App() {
|
|
|
41622
43108
|
e.preventDefault();
|
|
41623
43109
|
useUIStore.getState().toggleTerminal();
|
|
41624
43110
|
}
|
|
43111
|
+
if ((e.metaKey || e.ctrlKey) && e.key === ",") {
|
|
43112
|
+
e.preventDefault();
|
|
43113
|
+
setSettingsOpen((prev) => !prev);
|
|
43114
|
+
}
|
|
41625
43115
|
};
|
|
41626
43116
|
window.addEventListener("keydown", handler);
|
|
41627
43117
|
return () => window.removeEventListener("keydown", handler);
|
|
41628
43118
|
}, [previewEntity, previewEditorFocused]);
|
|
41629
|
-
if (!
|
|
43119
|
+
if (!authChecked) {
|
|
41630
43120
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex h-screen w-screen t-bg-base t-text items-center justify-center", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "drag-region fixed top-0 left-0 right-0 h-8 z-50" }) });
|
|
41631
43121
|
}
|
|
41632
|
-
|
|
41633
|
-
|
|
41634
|
-
|
|
43122
|
+
const settingsModal = /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
43123
|
+
SettingsModal,
|
|
43124
|
+
{
|
|
43125
|
+
open: settingsOpen,
|
|
43126
|
+
onClose: () => setSettingsOpen(false),
|
|
43127
|
+
initialTab: settingsTab
|
|
43128
|
+
}
|
|
43129
|
+
);
|
|
41635
43130
|
if (!hasProject) {
|
|
41636
|
-
return /* @__PURE__ */ jsxRuntimeExports.
|
|
43131
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
43132
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(FolderGate, { onOpenSettings: () => {
|
|
43133
|
+
setSettingsTab("api-keys");
|
|
43134
|
+
setSettingsOpen(true);
|
|
43135
|
+
} }),
|
|
43136
|
+
settingsModal
|
|
43137
|
+
] });
|
|
41637
43138
|
}
|
|
41638
43139
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(ErrorBoundary, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col h-screen w-screen t-bg-base t-text", children: [
|
|
41639
43140
|
/* @__PURE__ */ jsxRuntimeExports.jsx("a", { href: "#main-content", className: "skip-link", children: "Skip to content" }),
|
|
@@ -41659,9 +43160,11 @@ function App() {
|
|
|
41659
43160
|
)
|
|
41660
43161
|
] })
|
|
41661
43162
|
] }),
|
|
41662
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(StatusBar, {})
|
|
43163
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(StatusBar, {}),
|
|
43164
|
+
settingsModal
|
|
41663
43165
|
] }) });
|
|
41664
43166
|
}
|
|
43167
|
+
bootTheme();
|
|
41665
43168
|
ReactDOM.createRoot(document.getElementById("root")).render(
|
|
41666
43169
|
/* @__PURE__ */ jsxRuntimeExports.jsx(React$2.StrictMode, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(App, {}) })
|
|
41667
43170
|
);
|