research-copilot 0.2.6 → 0.2.9
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/app/out/main/index.mjs +6153 -2502
- package/app/out/preload/index.js +30 -0
- package/app/out/renderer/assets/{MilkdownMarkdownEditor-2wg63TSu.js → MilkdownMarkdownEditor-CK0d0F6d.js} +50 -50
- package/app/out/renderer/assets/{arc-Bpvizsn8.js → arc-CgrgxBD6.js} +1 -1
- package/app/out/renderer/assets/{blockDiagram-c4efeb88-BopVnbxX.js → blockDiagram-c4efeb88-BqZGW4Le.js} +8 -8
- package/app/out/renderer/assets/{c4Diagram-c83219d4-DYK03hOG.js → c4Diagram-c83219d4-gNbl9eSr.js} +3 -3
- package/app/out/renderer/assets/{channel-CmlMCRa3.js → channel-vUNI1iNi.js} +1 -1
- package/app/out/renderer/assets/{classDiagram-beda092f-oSGZIrY_.js → classDiagram-beda092f-jMkGJ9Ey.js} +6 -6
- package/app/out/renderer/assets/{classDiagram-v2-2358418a-BHM8844_.js → classDiagram-v2-2358418a-CNuFkLzW.js} +10 -10
- package/app/out/renderer/assets/{clone-PITMMgBv.js → clone-rSI1fs-P.js} +1 -1
- package/app/out/renderer/assets/{createText-1719965b-BN3FKtRi.js → createText-1719965b-BXIo6gGa.js} +2 -2
- package/app/out/renderer/assets/{edges-96097737-76OqZvY1.js → edges-96097737-nhmklBMU.js} +3 -3
- package/app/out/renderer/assets/{erDiagram-0228fc6a-CtXOkjA1.js → erDiagram-0228fc6a-DAEu9LLq.js} +5 -5
- package/app/out/renderer/assets/{flowDb-c6c81e3f-BCT1eQU9.js → flowDb-c6c81e3f-BCxc52Bt.js} +1 -1
- package/app/out/renderer/assets/{flowDiagram-50d868cf-BKR9gSZL.js → flowDiagram-50d868cf-DAeMm-oV.js} +12 -12
- package/app/out/renderer/assets/{flowDiagram-v2-4f6560a1-CBGrwW2p.js → flowDiagram-v2-4f6560a1-B3DiSW7H.js} +12 -12
- package/app/out/renderer/assets/{flowchart-elk-definition-6af322e1-CQxHOjqj.js → flowchart-elk-definition-6af322e1-C3U45hIj.js} +6 -6
- package/app/out/renderer/assets/{ganttDiagram-a2739b55-BVsEi_1s.js → ganttDiagram-a2739b55-DH_BJl1v.js} +3 -3
- package/app/out/renderer/assets/{gitGraphDiagram-82fe8481-BlGuagiw.js → gitGraphDiagram-82fe8481-BQYI6jwt.js} +2 -2
- package/app/out/renderer/assets/{graph-B-Uy9LVb.js → graph-Cbmv2S9S.js} +1 -1
- package/app/out/renderer/assets/{index-BrQ_Y-LE.js → index--rks7CK0.js} +3 -3
- package/app/out/renderer/assets/{index-5325376f-DFVM9bEE.js → index-5325376f-tk-JBjUy.js} +6 -6
- package/app/out/renderer/assets/{index-wvsLwV9F.js → index-B05MKQl-.js} +3 -3
- package/app/out/renderer/assets/{index-DlRaaYEU.js → index-BTNmK-qR.js} +3 -3
- package/app/out/renderer/assets/{index-jMygKcX_.js → index-BaHR_2Nj.js} +3 -3
- package/app/out/renderer/assets/{index-jJGUNJNs.js → index-BdSZkB2P.js} +4 -4
- package/app/out/renderer/assets/{index-Dt57Xb0R.js → index-Bg6-UTvh.js} +3 -3
- package/app/out/renderer/assets/{index-cLiUsMmu.js → index-BgoqHomD.js} +6 -6
- package/app/out/renderer/assets/{index-SoluVSbR.js → index-BkmP_G4w.js} +3 -3
- package/app/out/renderer/assets/{index-rMj6TAlT.js → index-ByH1hCUC.js} +4 -4
- package/app/out/renderer/assets/{index-9DibXU9f.js → index-C4WNjCL0.js} +6 -6
- package/app/out/renderer/assets/{index-PVPY9npp.js → index-CdhMP7aL.js} +3 -3
- package/app/out/renderer/assets/{index-DkVOuuVx.js → index-CqAzD5Mv.js} +6 -6
- package/app/out/renderer/assets/{index-C0Czl4Cv.js → index-DCdUaSNI.js} +3 -3
- package/app/out/renderer/assets/{index-B8_hOntP.js → index-DK2BzNnx.js} +3 -3
- package/app/out/renderer/assets/{index-BRtK-r6R.js → index-DU4yTtXH.js} +3 -3
- package/app/out/renderer/assets/{index-Dk7Wa0Je.js → index-DbWCHQ2E.js} +3 -3
- package/app/out/renderer/assets/{index-DFnA5GRw.js → index-DcOi0itd.js} +2275 -710
- package/app/out/renderer/assets/{index-CoEolmNf.js → index-Dk6CqgIG.js} +5 -5
- package/app/out/renderer/assets/{index-j9e1ML36.js → index-Do8kanBG.js} +1 -1
- package/app/out/renderer/assets/{index-BW7eNq5J.js → index-HX-NQu3g.js} +6 -6
- package/app/out/renderer/assets/{index-BllgkT3a.css → index-LbAr_1fx.css} +371 -121
- package/app/out/renderer/assets/{index-DlUgEE0Z.js → index-QjeQ3sgb.js} +3 -3
- package/app/out/renderer/assets/{index-i5J_uYOr.js → index-hDvDO954.js} +6 -6
- package/app/out/renderer/assets/{index-BcKf35dV.js → index-xqpIz9Nc.js} +6 -6
- package/app/out/renderer/assets/{infoDiagram-8eee0895-C6WcmMAB.js → infoDiagram-8eee0895-B7stNUSw.js} +2 -2
- package/app/out/renderer/assets/{journeyDiagram-c64418c1-wkVqZcQW.js → journeyDiagram-c64418c1-BmjjCYfG.js} +4 -4
- package/app/out/renderer/assets/{layout-C6Q0z3G5.js → layout-BwUXWB3n.js} +2 -2
- package/app/out/renderer/assets/{line-BDJIIoze.js → line-DAwxPIOb.js} +1 -1
- package/app/out/renderer/assets/{linear-95dGQxH4.js → linear-DF3tF_pi.js} +1 -1
- package/app/out/renderer/assets/{mindmap-definition-8da855dc-DWlj4Xm-.js → mindmap-definition-8da855dc-Dcm6UXzX.js} +3 -3
- package/app/out/renderer/assets/{pieDiagram-a8764435-CrdnVfOv.js → pieDiagram-a8764435-DkGcoK7i.js} +3 -3
- package/app/out/renderer/assets/{quadrantDiagram-1e28029f-M3YRJdbH.js → quadrantDiagram-1e28029f-C1Q8r814.js} +3 -3
- package/app/out/renderer/assets/{requirementDiagram-08caed73-C08ql71g.js → requirementDiagram-08caed73-C83u7Zho.js} +5 -5
- package/app/out/renderer/assets/{sankeyDiagram-a04cb91d-C8ADDrm7.js → sankeyDiagram-a04cb91d-CmjgGu4H.js} +2 -2
- package/app/out/renderer/assets/{sequenceDiagram-c5b8d532-gNfcaPex.js → sequenceDiagram-c5b8d532-B0tN0kuE.js} +3 -3
- package/app/out/renderer/assets/{stateDiagram-1ecb1508-CbYo7fPM.js → stateDiagram-1ecb1508-CvChhiL2.js} +6 -6
- package/app/out/renderer/assets/{stateDiagram-v2-c2b004d7-C9NIgZa5.js → stateDiagram-v2-c2b004d7-DuV4iLKk.js} +10 -10
- package/app/out/renderer/assets/{styles-b4e223ce-DgvzV6cM.js → styles-b4e223ce-CYC1lyng.js} +1 -1
- package/app/out/renderer/assets/{styles-ca3715f6-Dxd4UtQU.js → styles-ca3715f6-wbpEm70M.js} +1 -1
- package/app/out/renderer/assets/{styles-d45a18b0-C0jzXR3J.js → styles-d45a18b0-dtPSe0gc.js} +4 -4
- package/app/out/renderer/assets/{svgDrawCommon-b86b1483-CjGKGyYF.js → svgDrawCommon-b86b1483-DeFjfiKP.js} +1 -1
- package/app/out/renderer/assets/{timeline-definition-faaaa080-CRz7hPUx.js → timeline-definition-faaaa080-WkpCNoL6.js} +3 -3
- package/app/out/renderer/assets/{xychartDiagram-f5964ef8-BI-asLSS.js → xychartDiagram-f5964ef8-DhjmJVco.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-CK0d0F6d.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,632 @@ 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
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("br", {}),
|
|
13403
|
-
"Keys are stored locally in ",
|
|
13404
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "px-1 py-0.5 rounded t-bg-surface text-xs font-mono", children: "~/.research-copilot/config.json" })
|
|
13405
|
-
] })
|
|
13406
|
-
] }),
|
|
13407
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-3 mb-6", children: KEY_FIELDS.map((field) => {
|
|
13408
|
-
const alreadySet = status[field.name];
|
|
13409
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded-lg border t-border t-bg-surface/50 p-3", children: [
|
|
13410
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between mb-1.5", children: [
|
|
13411
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "text-xs font-medium t-text flex items-center gap-1.5", children: [
|
|
13412
|
-
field.label,
|
|
13413
|
-
field.required && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] t-text-muted", children: "(required*)" }),
|
|
13414
|
-
!field.required && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] t-text-muted", children: "(optional)" }),
|
|
13415
|
-
alreadySet && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-0.5 text-[10px] text-green-500", children: [
|
|
13416
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Check, { size: 10 }),
|
|
13417
|
-
" configured"
|
|
13418
|
-
] })
|
|
13419
|
-
] }),
|
|
13420
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
13421
|
-
"a",
|
|
13422
|
-
{
|
|
13423
|
-
href: field.url,
|
|
13424
|
-
target: "_blank",
|
|
13425
|
-
rel: "noreferrer",
|
|
13426
|
-
className: "text-[10px] t-text-muted hover:t-text flex items-center gap-0.5",
|
|
13427
|
-
onClick: (e) => {
|
|
13428
|
-
e.preventDefault();
|
|
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
|
-
)
|
|
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
|
+
] })
|
|
13460
13487
|
] }),
|
|
13461
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
13462
|
-
|
|
13463
|
-
|
|
13464
|
-
|
|
13465
|
-
|
|
13466
|
-
|
|
13467
|
-
|
|
13468
|
-
|
|
13469
|
-
|
|
13470
|
-
|
|
13471
|
-
|
|
13472
|
-
|
|
13473
|
-
|
|
13474
|
-
|
|
13475
|
-
|
|
13476
|
-
|
|
13477
|
-
|
|
13478
|
-
|
|
13479
|
-
|
|
13480
|
-
|
|
13481
|
-
|
|
13482
|
-
|
|
13483
|
-
|
|
13484
|
-
|
|
13485
|
-
|
|
13486
|
-
|
|
13487
|
-
|
|
13488
|
-
|
|
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) — gated behind ENABLE_CLAUDE_SUB=1
|
|
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 MODEL_GROUPS = (() => {
|
|
13722
|
+
const groups = /* @__PURE__ */ new Map();
|
|
13723
|
+
for (const m of SUPPORTED_MODELS) {
|
|
13724
|
+
const list2 = groups.get(m.provider) || [];
|
|
13725
|
+
list2.push(m);
|
|
13726
|
+
groups.set(m.provider, list2);
|
|
13727
|
+
}
|
|
13728
|
+
return groups;
|
|
13729
|
+
})();
|
|
13730
|
+
function WikiAgentSettings({ model, speed, onChangeModel, onChangeSpeed }) {
|
|
13731
|
+
const [status, setStatus] = reactExports.useState(null);
|
|
13732
|
+
const [stats, setStats] = reactExports.useState(null);
|
|
13733
|
+
const [recentLog, setRecentLog] = reactExports.useState([]);
|
|
13734
|
+
reactExports.useEffect(() => {
|
|
13735
|
+
api$f.wikiGetStatus?.().then((s15) => setStatus(s15)).catch(() => {
|
|
13736
|
+
});
|
|
13737
|
+
api$f.wikiGetStats?.().then((s15) => setStats(s15)).catch(() => {
|
|
13738
|
+
});
|
|
13739
|
+
api$f.wikiGetLog?.().then((l2) => setRecentLog(l2 || [])).catch(() => {
|
|
13740
|
+
});
|
|
13741
|
+
const unsub = api$f.onWikiStatus?.((s15) => setStatus(s15));
|
|
13742
|
+
return () => unsub?.();
|
|
13743
|
+
}, []);
|
|
13744
|
+
const enabled = model !== "none";
|
|
13745
|
+
const speedDesc = SPEED_OPTIONS.find((o2) => o2.value === speed)?.desc || "";
|
|
13746
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-6", children: [
|
|
13747
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
13748
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "text-xs font-semibold t-text mb-1.5", children: "Wiki Agent Model" }),
|
|
13749
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] t-text-muted mb-2.5", children: "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." }),
|
|
13750
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
13751
|
+
"select",
|
|
13752
|
+
{
|
|
13753
|
+
value: model,
|
|
13754
|
+
onChange: (e) => onChangeModel(e.target.value),
|
|
13755
|
+
className: "w-full px-3 py-1.5 rounded-lg border t-border t-bg-base t-text text-xs",
|
|
13756
|
+
children: [
|
|
13757
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "none", children: "None (disabled)" }),
|
|
13758
|
+
Array.from(MODEL_GROUPS.entries()).map(([provider, models]) => /* @__PURE__ */ jsxRuntimeExports.jsx("optgroup", { label: provider, children: models.map((m) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: m.id, children: m.label }, m.id)) }, provider))
|
|
13759
|
+
]
|
|
13760
|
+
}
|
|
13761
|
+
),
|
|
13762
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] t-text-muted mt-1.5 italic", children: "Changes take effect after app restart." })
|
|
13763
|
+
] }),
|
|
13764
|
+
enabled && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
13765
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "text-xs font-semibold t-text mb-1.5", children: "Processing Speed" }),
|
|
13766
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
13767
|
+
SegmentedControl,
|
|
13768
|
+
{
|
|
13769
|
+
options: SPEED_OPTIONS,
|
|
13770
|
+
value: speed,
|
|
13771
|
+
onChange: onChangeSpeed
|
|
13772
|
+
}
|
|
13773
|
+
),
|
|
13774
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] t-text-muted mt-2", children: speedDesc })
|
|
13775
|
+
] }),
|
|
13776
|
+
enabled && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded-lg border t-border t-bg-surface/50 p-3 space-y-3", children: [
|
|
13489
13777
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
13490
|
-
|
|
13491
|
-
|
|
13492
|
-
{
|
|
13493
|
-
onClick: onComplete,
|
|
13494
|
-
className: "text-xs t-text-secondary hover:t-text transition-colors",
|
|
13495
|
-
children: "Skip — keys already configured"
|
|
13496
|
-
}
|
|
13497
|
-
),
|
|
13498
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1" }),
|
|
13499
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
13778
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "text-xs font-semibold t-text", children: "Status" }),
|
|
13779
|
+
status?.state && status.state !== "disabled" && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
13500
13780
|
"button",
|
|
13501
13781
|
{
|
|
13502
|
-
onClick:
|
|
13503
|
-
|
|
13504
|
-
|
|
13505
|
-
|
|
13782
|
+
onClick: () => {
|
|
13783
|
+
if (status.state === "paused") {
|
|
13784
|
+
api$f.wikiResume?.();
|
|
13785
|
+
} else {
|
|
13786
|
+
api$f.wikiPause?.();
|
|
13787
|
+
}
|
|
13788
|
+
},
|
|
13789
|
+
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",
|
|
13790
|
+
children: status.state === "paused" ? "Resume" : "Pause"
|
|
13506
13791
|
}
|
|
13507
13792
|
)
|
|
13793
|
+
] }),
|
|
13794
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-[auto_1fr] gap-x-4 gap-y-1 text-[11px]", children: [
|
|
13795
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-muted", children: "State:" }),
|
|
13796
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "t-text flex items-center gap-1.5", children: [
|
|
13797
|
+
/* @__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"}` }),
|
|
13798
|
+
status?.state === "processing" ? `Processing (${status?.pending ?? 0} pending)` : status?.state ?? "Disabled"
|
|
13799
|
+
] }),
|
|
13800
|
+
stats && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
13801
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-muted", children: "Papers:" }),
|
|
13802
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "t-text", children: [
|
|
13803
|
+
stats.papers,
|
|
13804
|
+
" in wiki (",
|
|
13805
|
+
stats.fulltext,
|
|
13806
|
+
" fulltext, ",
|
|
13807
|
+
stats.abstractOnly,
|
|
13808
|
+
" abstract)"
|
|
13809
|
+
] }),
|
|
13810
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-muted", children: "Concepts:" }),
|
|
13811
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "t-text", children: [
|
|
13812
|
+
stats.concepts,
|
|
13813
|
+
" pages"
|
|
13814
|
+
] })
|
|
13815
|
+
] }),
|
|
13816
|
+
status?.lastRunAt && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
13817
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-muted", children: "Last run:" }),
|
|
13818
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text", children: formatRelativeTime(status.lastRunAt) })
|
|
13819
|
+
] })
|
|
13820
|
+
] }),
|
|
13821
|
+
recentLog.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
13822
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h5", { className: "text-[11px] font-medium t-text-muted mb-1", children: "Recent Activity" }),
|
|
13823
|
+
/* @__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
13824
|
] })
|
|
13509
|
-
] })
|
|
13825
|
+
] }),
|
|
13826
|
+
!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: [
|
|
13827
|
+
"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 ",
|
|
13828
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "font-mono", children: "wiki_search" }),
|
|
13829
|
+
",",
|
|
13830
|
+
" ",
|
|
13831
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "font-mono", children: "wiki_get" }),
|
|
13832
|
+
", ",
|
|
13833
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "font-mono", children: "wiki_coverage" }),
|
|
13834
|
+
", and ",
|
|
13835
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "font-mono", children: "wiki_source" }),
|
|
13836
|
+
" — the wiki is a research memory layer, not a fact oracle."
|
|
13837
|
+
] }) })
|
|
13838
|
+
] });
|
|
13839
|
+
}
|
|
13840
|
+
function formatRelativeTime(isoString) {
|
|
13841
|
+
const diff = Date.now() - new Date(isoString).getTime();
|
|
13842
|
+
const mins = Math.floor(diff / 6e4);
|
|
13843
|
+
if (mins < 1) return "just now";
|
|
13844
|
+
if (mins < 60) return `${mins} minute${mins > 1 ? "s" : ""} ago`;
|
|
13845
|
+
const hours = Math.floor(mins / 60);
|
|
13846
|
+
if (hours < 24) return `${hours} hour${hours > 1 ? "s" : ""} ago`;
|
|
13847
|
+
return new Date(isoString).toLocaleDateString();
|
|
13848
|
+
}
|
|
13849
|
+
const DEFAULT_SETTINGS = {
|
|
13850
|
+
research: {
|
|
13851
|
+
researchIntensity: "medium",
|
|
13852
|
+
webSearchDepth: "standard",
|
|
13853
|
+
autoSaveSensitivity: "balanced"
|
|
13854
|
+
},
|
|
13855
|
+
dataAnalysis: {
|
|
13856
|
+
executionTimeLimit: "standard"
|
|
13857
|
+
},
|
|
13858
|
+
wikiAgent: {
|
|
13859
|
+
model: "none",
|
|
13860
|
+
speed: "medium"
|
|
13861
|
+
}
|
|
13862
|
+
};
|
|
13863
|
+
const api$e = window.api;
|
|
13864
|
+
const TABS = [
|
|
13865
|
+
{ id: "api-keys", label: "API Keys", icon: Key },
|
|
13866
|
+
{ id: "research", label: "Research", icon: BookOpen },
|
|
13867
|
+
{ id: "data-analysis", label: "Data Analysis", icon: ChartNoAxesColumn },
|
|
13868
|
+
{ id: "paper-wiki", label: "Paper Wiki", icon: BookMarked }
|
|
13869
|
+
];
|
|
13870
|
+
const FOCUSABLE_SELECTOR = [
|
|
13871
|
+
"button:not([disabled])",
|
|
13872
|
+
"[href]",
|
|
13873
|
+
"input:not([disabled])",
|
|
13874
|
+
"select:not([disabled])",
|
|
13875
|
+
"textarea:not([disabled])",
|
|
13876
|
+
'[tabindex]:not([tabindex="-1"])'
|
|
13877
|
+
].join(",");
|
|
13878
|
+
function getVisibleFocusable(root2) {
|
|
13879
|
+
return Array.from(root2.querySelectorAll(FOCUSABLE_SELECTOR)).filter((el2) => el2.offsetParent !== null);
|
|
13880
|
+
}
|
|
13881
|
+
function SettingsModal({ open, onClose, initialTab }) {
|
|
13882
|
+
const [activeTab, setActiveTab] = reactExports.useState(initialTab ?? "api-keys");
|
|
13883
|
+
const [settings, setSettings] = reactExports.useState(DEFAULT_SETTINGS);
|
|
13884
|
+
const [loaded, setLoaded] = reactExports.useState(false);
|
|
13885
|
+
const [dirty, setDirty] = reactExports.useState(false);
|
|
13886
|
+
const panelRef = reactExports.useRef(null);
|
|
13887
|
+
reactExports.useEffect(() => {
|
|
13888
|
+
if (open && initialTab) {
|
|
13889
|
+
setActiveTab(initialTab);
|
|
13890
|
+
}
|
|
13891
|
+
}, [open, initialTab]);
|
|
13892
|
+
reactExports.useEffect(() => {
|
|
13893
|
+
if (!open) return;
|
|
13894
|
+
api$e.loadSettings?.().then((s15) => {
|
|
13895
|
+
if (s15) setSettings(s15);
|
|
13896
|
+
setLoaded(true);
|
|
13897
|
+
setDirty(false);
|
|
13898
|
+
}).catch(() => setLoaded(true));
|
|
13899
|
+
}, [open]);
|
|
13900
|
+
reactExports.useEffect(() => {
|
|
13901
|
+
if (!open) return;
|
|
13902
|
+
const trigger = document.activeElement;
|
|
13903
|
+
const frame = requestAnimationFrame(() => {
|
|
13904
|
+
const panel = panelRef.current;
|
|
13905
|
+
if (!panel) return;
|
|
13906
|
+
const focusable = getVisibleFocusable(panel);
|
|
13907
|
+
const first = focusable[0] ?? panel;
|
|
13908
|
+
first.focus();
|
|
13909
|
+
});
|
|
13910
|
+
return () => {
|
|
13911
|
+
cancelAnimationFrame(frame);
|
|
13912
|
+
if (trigger && document.contains(trigger)) {
|
|
13913
|
+
trigger.focus?.();
|
|
13914
|
+
}
|
|
13915
|
+
};
|
|
13916
|
+
}, [open]);
|
|
13917
|
+
reactExports.useEffect(() => {
|
|
13918
|
+
if (!open) return;
|
|
13919
|
+
const handleKey = (e) => {
|
|
13920
|
+
if (e.key === "Escape") {
|
|
13921
|
+
e.preventDefault();
|
|
13922
|
+
e.stopPropagation();
|
|
13923
|
+
onClose();
|
|
13924
|
+
return;
|
|
13925
|
+
}
|
|
13926
|
+
if (e.key !== "Tab") return;
|
|
13927
|
+
const panel = panelRef.current;
|
|
13928
|
+
if (!panel) return;
|
|
13929
|
+
const focusable = getVisibleFocusable(panel);
|
|
13930
|
+
if (focusable.length === 0) {
|
|
13931
|
+
e.preventDefault();
|
|
13932
|
+
panel.focus();
|
|
13933
|
+
return;
|
|
13934
|
+
}
|
|
13935
|
+
const first = focusable[0];
|
|
13936
|
+
const last = focusable[focusable.length - 1];
|
|
13937
|
+
const active = document.activeElement;
|
|
13938
|
+
if (!active || !panel.contains(active)) {
|
|
13939
|
+
e.preventDefault();
|
|
13940
|
+
first.focus();
|
|
13941
|
+
return;
|
|
13942
|
+
}
|
|
13943
|
+
if (e.shiftKey && active === first) {
|
|
13944
|
+
e.preventDefault();
|
|
13945
|
+
last.focus();
|
|
13946
|
+
} else if (!e.shiftKey && active === last) {
|
|
13947
|
+
e.preventDefault();
|
|
13948
|
+
first.focus();
|
|
13949
|
+
}
|
|
13950
|
+
};
|
|
13951
|
+
window.addEventListener("keydown", handleKey, true);
|
|
13952
|
+
return () => window.removeEventListener("keydown", handleKey, true);
|
|
13953
|
+
}, [open, onClose]);
|
|
13954
|
+
const updateSettings = (patch2) => {
|
|
13955
|
+
setSettings((prev) => {
|
|
13956
|
+
const next = { ...prev, ...patch2 };
|
|
13957
|
+
if (patch2.research) next.research = { ...prev.research, ...patch2.research };
|
|
13958
|
+
if (patch2.dataAnalysis) next.dataAnalysis = { ...prev.dataAnalysis, ...patch2.dataAnalysis };
|
|
13959
|
+
if (patch2.wikiAgent) next.wikiAgent = { ...prev.wikiAgent, ...patch2.wikiAgent };
|
|
13960
|
+
return next;
|
|
13961
|
+
});
|
|
13962
|
+
setDirty(true);
|
|
13963
|
+
};
|
|
13964
|
+
reactExports.useEffect(() => {
|
|
13965
|
+
if (!dirty || !loaded) return;
|
|
13966
|
+
const timer = setTimeout(() => {
|
|
13967
|
+
api$e.saveSettings?.(settings).catch(() => {
|
|
13968
|
+
});
|
|
13969
|
+
setDirty(false);
|
|
13970
|
+
}, 300);
|
|
13971
|
+
return () => clearTimeout(timer);
|
|
13972
|
+
}, [settings, dirty, loaded]);
|
|
13973
|
+
if (!open) return null;
|
|
13974
|
+
const activeLabel = TABS.find((t) => t.id === activeTab)?.label ?? "Settings";
|
|
13975
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "fixed inset-0 z-[60] flex items-center justify-center", children: [
|
|
13976
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute inset-0 bg-black/40", "aria-hidden": "true" }),
|
|
13977
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
13978
|
+
"div",
|
|
13979
|
+
{
|
|
13980
|
+
ref: panelRef,
|
|
13981
|
+
role: "dialog",
|
|
13982
|
+
"aria-modal": "true",
|
|
13983
|
+
"aria-labelledby": "settings-dialog-title",
|
|
13984
|
+
tabIndex: -1,
|
|
13985
|
+
className: "relative w-full max-w-2xl h-[520px] rounded-xl border t-border t-bg-surface shadow-xl flex overflow-hidden outline-none",
|
|
13986
|
+
children: [
|
|
13987
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
13988
|
+
"nav",
|
|
13989
|
+
{
|
|
13990
|
+
"aria-label": "Settings categories",
|
|
13991
|
+
className: "w-48 shrink-0 border-r t-border t-bg-base flex flex-col py-4 px-2",
|
|
13992
|
+
children: [
|
|
13993
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
13994
|
+
"h1",
|
|
13995
|
+
{
|
|
13996
|
+
id: "settings-dialog-title",
|
|
13997
|
+
className: "px-3 mb-3 text-sm font-semibold t-text tracking-tight",
|
|
13998
|
+
children: "Settings"
|
|
13999
|
+
}
|
|
14000
|
+
),
|
|
14001
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-0.5", children: TABS.map((tab2) => {
|
|
14002
|
+
const Icon2 = tab2.icon;
|
|
14003
|
+
const active = activeTab === tab2.id;
|
|
14004
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
14005
|
+
"button",
|
|
14006
|
+
{
|
|
14007
|
+
onClick: () => setActiveTab(tab2.id),
|
|
14008
|
+
"aria-current": active ? "page" : void 0,
|
|
14009
|
+
className: `w-full flex items-center gap-2 px-3 py-1.5 rounded-lg text-xs font-medium transition-colors
|
|
14010
|
+
${active ? "t-text-accent bg-[var(--color-accent)]/10" : "t-text-secondary hover:t-text hover:t-bg-hover"}
|
|
14011
|
+
`,
|
|
14012
|
+
children: [
|
|
14013
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Icon2, { size: 14 }),
|
|
14014
|
+
tab2.label
|
|
14015
|
+
]
|
|
14016
|
+
},
|
|
14017
|
+
tab2.id
|
|
14018
|
+
);
|
|
14019
|
+
}) }),
|
|
14020
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1" }),
|
|
14021
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "px-3 text-[10px] t-text-muted leading-relaxed", children: [
|
|
14022
|
+
"Keys are stored in",
|
|
14023
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("br", {}),
|
|
14024
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "font-mono", children: "~/.research-copilot/" })
|
|
14025
|
+
] })
|
|
14026
|
+
]
|
|
14027
|
+
}
|
|
14028
|
+
),
|
|
14029
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex flex-col min-w-0", children: [
|
|
14030
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between px-6 pt-4 pb-2", children: [
|
|
14031
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-sm font-semibold t-text", children: activeLabel }),
|
|
14032
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14033
|
+
"button",
|
|
14034
|
+
{
|
|
14035
|
+
onClick: onClose,
|
|
14036
|
+
className: "p-1.5 rounded-lg t-text-muted hover:t-text hover:t-bg-hover transition-colors",
|
|
14037
|
+
"aria-label": "Close settings",
|
|
14038
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(X$1, { size: 16 })
|
|
14039
|
+
}
|
|
14040
|
+
)
|
|
14041
|
+
] }),
|
|
14042
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 overflow-y-auto px-6 pb-4", children: [
|
|
14043
|
+
activeTab === "api-keys" && /* @__PURE__ */ jsxRuntimeExports.jsx(ApiKeysSettings, {}),
|
|
14044
|
+
activeTab === "research" && loaded && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14045
|
+
ResearchSettings,
|
|
14046
|
+
{
|
|
14047
|
+
researchIntensity: settings.research.researchIntensity,
|
|
14048
|
+
webSearchDepth: settings.research.webSearchDepth,
|
|
14049
|
+
autoSaveSensitivity: settings.research.autoSaveSensitivity,
|
|
14050
|
+
onChangeIntensity: (v3) => updateSettings({ research: { ...settings.research, researchIntensity: v3 } }),
|
|
14051
|
+
onChangeWebDepth: (v3) => updateSettings({ research: { ...settings.research, webSearchDepth: v3 } }),
|
|
14052
|
+
onChangeAutoSave: (v3) => updateSettings({ research: { ...settings.research, autoSaveSensitivity: v3 } })
|
|
14053
|
+
}
|
|
14054
|
+
),
|
|
14055
|
+
activeTab === "data-analysis" && loaded && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14056
|
+
DataAnalysisSettings,
|
|
14057
|
+
{
|
|
14058
|
+
executionTimeLimit: settings.dataAnalysis.executionTimeLimit,
|
|
14059
|
+
onChange: (v3) => updateSettings({ dataAnalysis: { executionTimeLimit: v3 } })
|
|
14060
|
+
}
|
|
14061
|
+
),
|
|
14062
|
+
activeTab === "paper-wiki" && loaded && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14063
|
+
WikiAgentSettings,
|
|
14064
|
+
{
|
|
14065
|
+
model: settings.wikiAgent?.model ?? "none",
|
|
14066
|
+
speed: settings.wikiAgent?.speed ?? "medium",
|
|
14067
|
+
onChangeModel: (v3) => updateSettings({ wikiAgent: { ...settings.wikiAgent, model: v3 } }),
|
|
14068
|
+
onChangeSpeed: (v3) => updateSettings({ wikiAgent: { ...settings.wikiAgent, speed: v3 } })
|
|
14069
|
+
}
|
|
14070
|
+
)
|
|
14071
|
+
] }),
|
|
14072
|
+
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." }) })
|
|
14073
|
+
] })
|
|
14074
|
+
]
|
|
14075
|
+
}
|
|
14076
|
+
)
|
|
13510
14077
|
] });
|
|
13511
14078
|
}
|
|
13512
14079
|
const createStoreImpl = (createState2) => {
|
|
@@ -13548,32 +14115,6 @@ const createImpl = (createState2) => {
|
|
|
13548
14115
|
return useBoundStore;
|
|
13549
14116
|
};
|
|
13550
14117
|
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
14118
|
function parseModelKey(key) {
|
|
13578
14119
|
const i = key.indexOf(":");
|
|
13579
14120
|
if (i > 0) return { provider: key.slice(0, i), modelId: key.slice(i + 1) };
|
|
@@ -13581,8 +14122,38 @@ function parseModelKey(key) {
|
|
|
13581
14122
|
if (key.startsWith("gemini-")) return { provider: "google", modelId: key };
|
|
13582
14123
|
return { provider: "openai", modelId: key };
|
|
13583
14124
|
}
|
|
14125
|
+
const STORAGE_KEY = "rp-theme";
|
|
14126
|
+
function getInitialTheme() {
|
|
14127
|
+
if (typeof window === "undefined") return "dark";
|
|
14128
|
+
try {
|
|
14129
|
+
const stored = window.localStorage.getItem(STORAGE_KEY);
|
|
14130
|
+
if (stored === "light" || stored === "dark") return stored;
|
|
14131
|
+
} catch {
|
|
14132
|
+
}
|
|
14133
|
+
return "dark";
|
|
14134
|
+
}
|
|
14135
|
+
function persistTheme(theme) {
|
|
14136
|
+
if (typeof window === "undefined") return;
|
|
14137
|
+
try {
|
|
14138
|
+
window.localStorage.setItem(STORAGE_KEY, theme);
|
|
14139
|
+
} catch {
|
|
14140
|
+
}
|
|
14141
|
+
}
|
|
14142
|
+
function applyThemeClass(theme) {
|
|
14143
|
+
if (typeof document === "undefined") return;
|
|
14144
|
+
document.documentElement.classList.remove("dark", "light");
|
|
14145
|
+
document.documentElement.classList.add(theme);
|
|
14146
|
+
}
|
|
14147
|
+
function bootTheme() {
|
|
14148
|
+
const theme = getInitialTheme();
|
|
14149
|
+
applyThemeClass(theme);
|
|
14150
|
+
return theme;
|
|
14151
|
+
}
|
|
13584
14152
|
const useUIStore = create$1((set) => ({
|
|
13585
|
-
|
|
14153
|
+
// Theme hydrates from localStorage (or OS preference) at module init so
|
|
14154
|
+
// the zustand state matches the <html> class applied by bootTheme() in
|
|
14155
|
+
// main.tsx. Both ends derive from getInitialTheme() — they stay in sync.
|
|
14156
|
+
theme: getInitialTheme(),
|
|
13586
14157
|
leftTab: "files",
|
|
13587
14158
|
centerView: "chat",
|
|
13588
14159
|
selectedModel: DEFAULT_MODEL,
|
|
@@ -13605,6 +14176,17 @@ const useUIStore = create$1((set) => ({
|
|
|
13605
14176
|
source: null,
|
|
13606
14177
|
round: null
|
|
13607
14178
|
},
|
|
14179
|
+
wikiReaderSlug: null,
|
|
14180
|
+
wikiReaderHistory: [],
|
|
14181
|
+
setWikiReaderSlug: (slug) => set((s15) => ({
|
|
14182
|
+
wikiReaderHistory: s15.wikiReaderSlug ? [...s15.wikiReaderHistory, s15.wikiReaderSlug] : s15.wikiReaderHistory,
|
|
14183
|
+
wikiReaderSlug: slug
|
|
14184
|
+
})),
|
|
14185
|
+
wikiReaderBack: () => set((s15) => {
|
|
14186
|
+
const history = [...s15.wikiReaderHistory];
|
|
14187
|
+
const prev = history.pop() ?? null;
|
|
14188
|
+
return { wikiReaderSlug: prev, wikiReaderHistory: history };
|
|
14189
|
+
}),
|
|
13608
14190
|
setReasoningEffort: (reasoningEffort) => {
|
|
13609
14191
|
set({ reasoningEffort });
|
|
13610
14192
|
const api2 = window.api;
|
|
@@ -13613,8 +14195,8 @@ const useUIStore = create$1((set) => ({
|
|
|
13613
14195
|
},
|
|
13614
14196
|
setTheme: (theme) => {
|
|
13615
14197
|
set({ theme });
|
|
13616
|
-
|
|
13617
|
-
|
|
14198
|
+
persistTheme(theme);
|
|
14199
|
+
applyThemeClass(theme);
|
|
13618
14200
|
},
|
|
13619
14201
|
toggleTheme: () => {
|
|
13620
14202
|
const newTheme = useUIStore.getState().theme === "dark" ? "light" : "dark";
|
|
@@ -13680,7 +14262,9 @@ const useUIStore = create$1((set) => ({
|
|
|
13680
14262
|
previewEntity: null,
|
|
13681
14263
|
previewSourceTab: null,
|
|
13682
14264
|
previewEditorFocused: false,
|
|
13683
|
-
literatureFilter: { search: "", subTopic: null, sortBy: "year", sortDir: "desc", minScore: 0, source: null, round: null }
|
|
14265
|
+
literatureFilter: { search: "", subTopic: null, sortBy: "year", sortDir: "desc", minScore: 0, source: null, round: null },
|
|
14266
|
+
wikiReaderSlug: null,
|
|
14267
|
+
wikiReaderHistory: []
|
|
13684
14268
|
}),
|
|
13685
14269
|
openPreview: (entity) => set((s15) => ({ previewEntity: entity, previewSourceTab: s15.leftTab, leftSidebarCollapsed: true, previewEditorFocused: false })),
|
|
13686
14270
|
closePreview: () => set({ previewEntity: null, previewSourceTab: null, leftSidebarCollapsed: false, previewEditorFocused: false }),
|
|
@@ -13701,7 +14285,6 @@ async function hydratePreferences() {
|
|
|
13701
14285
|
}
|
|
13702
14286
|
}
|
|
13703
14287
|
if (prefs.reasoningEffort) updates.reasoningEffort = prefs.reasoningEffort;
|
|
13704
|
-
if (prefs.theme) updates.theme = prefs.theme;
|
|
13705
14288
|
if (Object.keys(updates).length > 0) useUIStore.setState(updates);
|
|
13706
14289
|
}
|
|
13707
14290
|
const uiStore = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
@@ -13846,7 +14429,7 @@ const useToolEventsStore = create$1((set, get) => ({
|
|
|
13846
14429
|
clearRun: () => set({ currentRunEvents: [] })
|
|
13847
14430
|
}));
|
|
13848
14431
|
const PAGE_SIZE = 20;
|
|
13849
|
-
const api$
|
|
14432
|
+
const api$d = window.api;
|
|
13850
14433
|
let _sessionId = "";
|
|
13851
14434
|
const useChatStore = create$1((set, get) => ({
|
|
13852
14435
|
messages: [],
|
|
@@ -13874,7 +14457,7 @@ const useChatStore = create$1((set, get) => ({
|
|
|
13874
14457
|
isStreaming: true
|
|
13875
14458
|
}));
|
|
13876
14459
|
if (_sessionId) {
|
|
13877
|
-
api$
|
|
14460
|
+
api$d.saveMessage(_sessionId, userMsg).catch(() => {
|
|
13878
14461
|
});
|
|
13879
14462
|
}
|
|
13880
14463
|
const { useUsageStore: useUsageStore2 } = await __vitePreload(async () => {
|
|
@@ -13888,12 +14471,12 @@ const useChatStore = create$1((set, get) => ({
|
|
|
13888
14471
|
return { useUIStore: useUIStore3 };
|
|
13889
14472
|
}, true ? void 0 : void 0, import.meta.url);
|
|
13890
14473
|
const model = useUIStore2.getState().selectedModel;
|
|
13891
|
-
await api$
|
|
14474
|
+
await api$d.sendMessage(text2, void 0, model, images);
|
|
13892
14475
|
} catch {
|
|
13893
14476
|
}
|
|
13894
14477
|
},
|
|
13895
14478
|
stop: async () => {
|
|
13896
|
-
await api$
|
|
14479
|
+
await api$d.stopAgent();
|
|
13897
14480
|
},
|
|
13898
14481
|
appendChunk: (chunk) => {
|
|
13899
14482
|
set((s15) => ({ streamingText: s15.streamingText + chunk }));
|
|
@@ -13922,7 +14505,7 @@ const useChatStore = create$1((set, get) => ({
|
|
|
13922
14505
|
};
|
|
13923
14506
|
});
|
|
13924
14507
|
if (_sessionId) {
|
|
13925
|
-
api$
|
|
14508
|
+
api$d.saveMessage(_sessionId, assistantMsg).catch(() => {
|
|
13926
14509
|
});
|
|
13927
14510
|
}
|
|
13928
14511
|
},
|
|
@@ -13948,7 +14531,7 @@ const useChatStore = create$1((set, get) => ({
|
|
|
13948
14531
|
return { savedMessageIds: next };
|
|
13949
14532
|
});
|
|
13950
14533
|
if (_sessionId) {
|
|
13951
|
-
api$
|
|
14534
|
+
api$d.markMessageSaved(_sessionId, messageId).catch(() => {
|
|
13952
14535
|
});
|
|
13953
14536
|
}
|
|
13954
14537
|
},
|
|
@@ -13965,9 +14548,9 @@ const useChatStore = create$1((set, get) => ({
|
|
|
13965
14548
|
_sessionId = sessionId;
|
|
13966
14549
|
try {
|
|
13967
14550
|
const [count, messages, savedIds] = await Promise.all([
|
|
13968
|
-
api$
|
|
13969
|
-
api$
|
|
13970
|
-
api$
|
|
14551
|
+
api$d.getMessageCount(sessionId),
|
|
14552
|
+
api$d.loadMessages(sessionId, 0, PAGE_SIZE),
|
|
14553
|
+
api$d.loadSavedMessageIds(sessionId)
|
|
13971
14554
|
]);
|
|
13972
14555
|
set({
|
|
13973
14556
|
messages,
|
|
@@ -13984,8 +14567,8 @@ const useChatStore = create$1((set, get) => ({
|
|
|
13984
14567
|
set({ isLoadingHistory: true });
|
|
13985
14568
|
try {
|
|
13986
14569
|
const [count, older] = await Promise.all([
|
|
13987
|
-
api$
|
|
13988
|
-
api$
|
|
14570
|
+
api$d.getMessageCount(_sessionId),
|
|
14571
|
+
api$d.loadMessages(_sessionId, _offset, PAGE_SIZE)
|
|
13989
14572
|
]);
|
|
13990
14573
|
if (older.length > 0) {
|
|
13991
14574
|
set((s15) => ({
|
|
@@ -14063,7 +14646,7 @@ function merge(definitions, space2) {
|
|
|
14063
14646
|
}
|
|
14064
14647
|
return new Schema(property, normal, space2);
|
|
14065
14648
|
}
|
|
14066
|
-
function normalize$
|
|
14649
|
+
function normalize$2(value) {
|
|
14067
14650
|
return value.toLowerCase();
|
|
14068
14651
|
}
|
|
14069
14652
|
class Info {
|
|
@@ -14163,8 +14746,8 @@ function create(definition2) {
|
|
|
14163
14746
|
info.mustUseProperty = true;
|
|
14164
14747
|
}
|
|
14165
14748
|
properties[property] = info;
|
|
14166
|
-
normals[normalize$
|
|
14167
|
-
normals[normalize$
|
|
14749
|
+
normals[normalize$2(property)] = property;
|
|
14750
|
+
normals[normalize$2(info.attribute)] = property;
|
|
14168
14751
|
}
|
|
14169
14752
|
return new Schema(properties, normals, definition2.space);
|
|
14170
14753
|
}
|
|
@@ -15203,7 +15786,7 @@ const cap$1 = /[A-Z]/g;
|
|
|
15203
15786
|
const dash = /-[a-z]/g;
|
|
15204
15787
|
const valid = /^data[-\w.:]+$/i;
|
|
15205
15788
|
function find(schema, value) {
|
|
15206
|
-
const normal = normalize$
|
|
15789
|
+
const normal = normalize$2(value);
|
|
15207
15790
|
let property = value;
|
|
15208
15791
|
let Type = Info;
|
|
15209
15792
|
if (normal in schema.normal) {
|
|
@@ -22223,9 +22806,9 @@ function join(...segments) {
|
|
|
22223
22806
|
joined = joined === void 0 ? segments[index2] : joined + "/" + segments[index2];
|
|
22224
22807
|
}
|
|
22225
22808
|
}
|
|
22226
|
-
return joined === void 0 ? "." : normalize(joined);
|
|
22809
|
+
return joined === void 0 ? "." : normalize$1(joined);
|
|
22227
22810
|
}
|
|
22228
|
-
function normalize(path2) {
|
|
22811
|
+
function normalize$1(path2) {
|
|
22229
22812
|
assertPath$1(path2);
|
|
22230
22813
|
const absolute = path2.codePointAt(0) === 47;
|
|
22231
22814
|
let value = normalizeString(path2, !absolute);
|
|
@@ -26549,7 +27132,7 @@ function remarkGfm(options) {
|
|
|
26549
27132
|
fromMarkdownExtensions.push(gfmFromMarkdown());
|
|
26550
27133
|
toMarkdownExtensions.push(gfmToMarkdown(settings));
|
|
26551
27134
|
}
|
|
26552
|
-
const api$
|
|
27135
|
+
const api$c = window.api;
|
|
26553
27136
|
function stamp(items, type) {
|
|
26554
27137
|
return (items || []).map((i) => ({
|
|
26555
27138
|
...i,
|
|
@@ -26589,9 +27172,9 @@ const useEntityStore = create$1((set, get) => ({
|
|
|
26589
27172
|
}),
|
|
26590
27173
|
refreshAll: async () => {
|
|
26591
27174
|
const [notesRaw, papersRaw, dataRaw] = await Promise.all([
|
|
26592
|
-
api$
|
|
26593
|
-
api$
|
|
26594
|
-
api$
|
|
27175
|
+
api$c.listNotes(),
|
|
27176
|
+
api$c.listLiterature(),
|
|
27177
|
+
api$c.listData()
|
|
26595
27178
|
]);
|
|
26596
27179
|
const notes = stamp(notesRaw, "note");
|
|
26597
27180
|
notes.sort((a, b2) => a.id === "agent-md" ? -1 : b2.id === "agent-md" ? 1 : 0);
|
|
@@ -26604,7 +27187,7 @@ const useEntityStore = create$1((set, get) => ({
|
|
|
26604
27187
|
});
|
|
26605
27188
|
},
|
|
26606
27189
|
deleteEntity: async (id) => {
|
|
26607
|
-
await api$
|
|
27190
|
+
await api$c.deleteEntity(id);
|
|
26608
27191
|
await get().refreshAll();
|
|
26609
27192
|
}
|
|
26610
27193
|
}));
|
|
@@ -26660,10 +27243,10 @@ function findLastIndex(arr, pred) {
|
|
|
26660
27243
|
}
|
|
26661
27244
|
return -1;
|
|
26662
27245
|
}
|
|
26663
|
-
const api$
|
|
27246
|
+
const api$b = window.api;
|
|
26664
27247
|
async function loadFromFramework() {
|
|
26665
27248
|
try {
|
|
26666
|
-
const data = await api$
|
|
27249
|
+
const data = await api$b?.getUsageTotals?.();
|
|
26667
27250
|
return data ?? null;
|
|
26668
27251
|
} catch (e) {
|
|
26669
27252
|
console.warn("[usage-store] Failed to load persisted totals:", e);
|
|
@@ -26779,7 +27362,7 @@ const useUsageStore = create$1((set, get) => {
|
|
|
26779
27362
|
},
|
|
26780
27363
|
// Reset all-time totals (user-initiated)
|
|
26781
27364
|
resetAllTime: () => {
|
|
26782
|
-
api$
|
|
27365
|
+
api$b?.resetUsageTotals?.().catch?.(() => {
|
|
26783
27366
|
});
|
|
26784
27367
|
set({
|
|
26785
27368
|
runPromptTokens: 0,
|
|
@@ -26810,13 +27393,31 @@ const usageStore = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePr
|
|
|
26810
27393
|
__proto__: null,
|
|
26811
27394
|
useUsageStore
|
|
26812
27395
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
26813
|
-
const api$
|
|
27396
|
+
const api$a = window.api;
|
|
27397
|
+
async function applyOpenResult(set, result) {
|
|
27398
|
+
if (!result) return false;
|
|
27399
|
+
useChatStore.getState().clear();
|
|
27400
|
+
useProgressStore.getState().clear();
|
|
27401
|
+
useActivityStore.getState().clear();
|
|
27402
|
+
useUIStore.getState().reset();
|
|
27403
|
+
useEntityStore.getState().reset();
|
|
27404
|
+
useUsageStore.getState().resetSession();
|
|
27405
|
+
set({ hasProject: false, sessionId: "", projectPath: "" });
|
|
27406
|
+
await new Promise((r) => setTimeout(r, 0));
|
|
27407
|
+
set({
|
|
27408
|
+
sessionId: result.sessionId,
|
|
27409
|
+
projectPath: result.projectPath,
|
|
27410
|
+
hasProject: true
|
|
27411
|
+
});
|
|
27412
|
+
await hydratePreferences();
|
|
27413
|
+
return true;
|
|
27414
|
+
}
|
|
26814
27415
|
const useSessionStore = create$1((set) => ({
|
|
26815
27416
|
sessionId: "",
|
|
26816
27417
|
projectPath: "",
|
|
26817
27418
|
hasProject: false,
|
|
26818
27419
|
init: async () => {
|
|
26819
|
-
const session = await api$
|
|
27420
|
+
const session = await api$a.getCurrentSession();
|
|
26820
27421
|
set({
|
|
26821
27422
|
sessionId: session.sessionId,
|
|
26822
27423
|
projectPath: session.projectPath,
|
|
@@ -26827,28 +27428,15 @@ const useSessionStore = create$1((set) => ({
|
|
|
26827
27428
|
}
|
|
26828
27429
|
},
|
|
26829
27430
|
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;
|
|
27431
|
+
const result = await api$a.pickFolder();
|
|
27432
|
+
return applyOpenResult(set, result);
|
|
27433
|
+
},
|
|
27434
|
+
openPath: async (projectPath) => {
|
|
27435
|
+
const result = await api$a.openProjectPath(projectPath);
|
|
27436
|
+
return applyOpenResult(set, result);
|
|
26849
27437
|
},
|
|
26850
27438
|
closeProject: async () => {
|
|
26851
|
-
await api$
|
|
27439
|
+
await api$a.closeProject();
|
|
26852
27440
|
useChatStore.getState().clear();
|
|
26853
27441
|
useProgressStore.getState().clear();
|
|
26854
27442
|
useActivityStore.getState().clear();
|
|
@@ -26858,7 +27446,7 @@ const useSessionStore = create$1((set) => ({
|
|
|
26858
27446
|
set({ sessionId: "", projectPath: "", hasProject: false });
|
|
26859
27447
|
}
|
|
26860
27448
|
}));
|
|
26861
|
-
const api$
|
|
27449
|
+
const api$9 = window.api;
|
|
26862
27450
|
const ROW_HEIGHT = 28;
|
|
26863
27451
|
const OVERSCAN_ROWS = 10;
|
|
26864
27452
|
const MAX_DROP_FILE_SIZE = 100 * 1024 * 1024;
|
|
@@ -26957,7 +27545,7 @@ function WorkspaceTree() {
|
|
|
26957
27545
|
const parentKey = toKey(relativePath);
|
|
26958
27546
|
setParentLoading(parentKey, true);
|
|
26959
27547
|
try {
|
|
26960
|
-
const children = await api$
|
|
27548
|
+
const children = await api$9.listTree({
|
|
26961
27549
|
relativePath,
|
|
26962
27550
|
showIgnored,
|
|
26963
27551
|
limit: 2e3
|
|
@@ -26982,8 +27570,8 @@ function WorkspaceTree() {
|
|
|
26982
27570
|
void Promise.all(dirs.map((dir) => loadChildren(dir)));
|
|
26983
27571
|
}, 500);
|
|
26984
27572
|
};
|
|
26985
|
-
const unsubFileCreated = api$
|
|
26986
|
-
const unsubAgentDone = api$
|
|
27573
|
+
const unsubFileCreated = api$9.onFileCreated(scheduleRefresh);
|
|
27574
|
+
const unsubAgentDone = api$9.onAgentDone(scheduleRefresh);
|
|
26987
27575
|
return () => {
|
|
26988
27576
|
if (debounceTimer) clearTimeout(debounceTimer);
|
|
26989
27577
|
unsubFileCreated();
|
|
@@ -27023,7 +27611,7 @@ function WorkspaceTree() {
|
|
|
27023
27611
|
}
|
|
27024
27612
|
setSearching(true);
|
|
27025
27613
|
try {
|
|
27026
|
-
const results = await api$
|
|
27614
|
+
const results = await api$9.searchTree(query.trim(), { showIgnored, maxResults: 4e3 });
|
|
27027
27615
|
setSearchResults(results);
|
|
27028
27616
|
} finally {
|
|
27029
27617
|
setSearching(false);
|
|
@@ -27067,7 +27655,7 @@ function WorkspaceTree() {
|
|
|
27067
27655
|
if (node2.type !== "file") return;
|
|
27068
27656
|
const ext = (node2.name.split(".").pop() || "").toLowerCase();
|
|
27069
27657
|
if (!TEXT_EXTENSIONS.has(ext)) {
|
|
27070
|
-
api$
|
|
27658
|
+
api$9.openFile(node2.path);
|
|
27071
27659
|
return;
|
|
27072
27660
|
}
|
|
27073
27661
|
const normalizedNodePath = normalizePath(node2.path);
|
|
@@ -27092,14 +27680,14 @@ function WorkspaceTree() {
|
|
|
27092
27680
|
});
|
|
27093
27681
|
}, [data, openPreview]);
|
|
27094
27682
|
const createArtifact = reactExports.useCallback(async (node2) => {
|
|
27095
|
-
await api$
|
|
27683
|
+
await api$9.createArtifactFromFile(node2.path);
|
|
27096
27684
|
await refreshEntities();
|
|
27097
27685
|
}, [refreshEntities]);
|
|
27098
27686
|
const handleTrashClick = reactExports.useCallback(async (node2) => {
|
|
27099
27687
|
if (confirmTrashPath === node2.relativePath) {
|
|
27100
27688
|
if (confirmTimerRef.current) clearTimeout(confirmTimerRef.current);
|
|
27101
27689
|
setConfirmTrashPath(null);
|
|
27102
|
-
const result = await api$
|
|
27690
|
+
const result = await api$9.trashFile(node2.path);
|
|
27103
27691
|
if (result.success) {
|
|
27104
27692
|
const parentRelPath = node2.relativePath.includes("/") ? node2.relativePath.slice(0, node2.relativePath.lastIndexOf("/")) : "";
|
|
27105
27693
|
await loadChildren(parentRelPath);
|
|
@@ -27148,7 +27736,7 @@ function WorkspaceTree() {
|
|
|
27148
27736
|
return;
|
|
27149
27737
|
}
|
|
27150
27738
|
const relPath = creating.parentDir ? `${creating.parentDir}/${createValue.trim()}` : createValue.trim();
|
|
27151
|
-
const result = creating.type === "file" ? await api$
|
|
27739
|
+
const result = creating.type === "file" ? await api$9.createFile(relPath) : await api$9.createDir(relPath);
|
|
27152
27740
|
if (result.success) {
|
|
27153
27741
|
await loadChildren(creating.parentDir);
|
|
27154
27742
|
}
|
|
@@ -27175,7 +27763,7 @@ function WorkspaceTree() {
|
|
|
27175
27763
|
const parentDir = renaming.includes("/") ? renaming.slice(0, renaming.lastIndexOf("/")) : "";
|
|
27176
27764
|
const newRelPath = parentDir ? `${parentDir}/${renameValue.trim()}` : renameValue.trim();
|
|
27177
27765
|
if (newRelPath !== renaming) {
|
|
27178
|
-
await api$
|
|
27766
|
+
await api$9.renameFile(renaming, newRelPath);
|
|
27179
27767
|
await loadChildren(parentDir);
|
|
27180
27768
|
}
|
|
27181
27769
|
setRenaming(null);
|
|
@@ -27217,7 +27805,7 @@ function WorkspaceTree() {
|
|
|
27217
27805
|
const base64 = btoa(
|
|
27218
27806
|
new Uint8Array(buffer).reduce((data2, byte) => data2 + String.fromCharCode(byte), "")
|
|
27219
27807
|
);
|
|
27220
|
-
await api$
|
|
27808
|
+
await api$9.dropToDir(file.name, base64, targetRelPath);
|
|
27221
27809
|
}
|
|
27222
27810
|
await loadChildren(targetRelPath);
|
|
27223
27811
|
}, [getDropDir, loadChildren]);
|
|
@@ -27243,7 +27831,7 @@ function WorkspaceTree() {
|
|
|
27243
27831
|
const base64 = btoa(
|
|
27244
27832
|
new Uint8Array(buffer).reduce((data2, byte) => data2 + String.fromCharCode(byte), "")
|
|
27245
27833
|
);
|
|
27246
|
-
await api$
|
|
27834
|
+
await api$9.dropToDir(file.name, base64, "");
|
|
27247
27835
|
}
|
|
27248
27836
|
await loadChildren("");
|
|
27249
27837
|
}, [loadChildren]);
|
|
@@ -27318,7 +27906,7 @@ function WorkspaceTree() {
|
|
|
27318
27906
|
onKeyDown: handleCreateKeyDown,
|
|
27319
27907
|
onBlur: () => void commitCreate(),
|
|
27320
27908
|
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"
|
|
27909
|
+
className: "flex-1 bg-transparent outline-none t-focus-ring border-b border-[var(--color-accent-soft)] text-xs t-text"
|
|
27322
27910
|
}
|
|
27323
27911
|
)
|
|
27324
27912
|
]
|
|
@@ -27637,7 +28225,7 @@ const useSkillStore = create$1((set, get) => ({
|
|
|
27637
28225
|
return result;
|
|
27638
28226
|
}
|
|
27639
28227
|
}));
|
|
27640
|
-
const remarkPlugins$
|
|
28228
|
+
const remarkPlugins$3 = [remarkGfm];
|
|
27641
28229
|
function HoverPreview({
|
|
27642
28230
|
entity,
|
|
27643
28231
|
anchorRect,
|
|
@@ -27679,7 +28267,7 @@ function HoverPreview({
|
|
|
27679
28267
|
}
|
|
27680
28268
|
) })
|
|
27681
28269
|
] }),
|
|
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$
|
|
28270
|
+
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
28271
|
]
|
|
27684
28272
|
}
|
|
27685
28273
|
);
|
|
@@ -28140,6 +28728,35 @@ function EntityTabs() {
|
|
|
28140
28728
|
)
|
|
28141
28729
|
] });
|
|
28142
28730
|
}
|
|
28731
|
+
const api$8 = window.api;
|
|
28732
|
+
function ConceptsList() {
|
|
28733
|
+
const [concepts, setConcepts] = reactExports.useState([]);
|
|
28734
|
+
const setSlug = useUIStore((s15) => s15.setWikiReaderSlug);
|
|
28735
|
+
const activeSlug = useUIStore((s15) => s15.wikiReaderSlug);
|
|
28736
|
+
reactExports.useEffect(() => {
|
|
28737
|
+
api$8.wikiListPages?.().then((result) => {
|
|
28738
|
+
if (result?.concepts) setConcepts(result.concepts);
|
|
28739
|
+
}).catch(() => {
|
|
28740
|
+
});
|
|
28741
|
+
}, []);
|
|
28742
|
+
if (concepts.length === 0) return null;
|
|
28743
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [
|
|
28744
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[10px] t-text-accent-soft uppercase tracking-wider font-medium flex items-center gap-1.5", children: [
|
|
28745
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Network, { size: 10 }),
|
|
28746
|
+
"Concepts"
|
|
28747
|
+
] }),
|
|
28748
|
+
concepts.map((c) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
28749
|
+
"button",
|
|
28750
|
+
{
|
|
28751
|
+
onClick: () => setSlug(c.slug),
|
|
28752
|
+
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"}`,
|
|
28753
|
+
title: c.title,
|
|
28754
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[11px] truncate", children: c.title })
|
|
28755
|
+
},
|
|
28756
|
+
c.slug
|
|
28757
|
+
))
|
|
28758
|
+
] });
|
|
28759
|
+
}
|
|
28143
28760
|
function QuickAction({
|
|
28144
28761
|
icon: Icon2,
|
|
28145
28762
|
label,
|
|
@@ -28163,45 +28780,6 @@ function QuickAction({
|
|
|
28163
28780
|
}
|
|
28164
28781
|
);
|
|
28165
28782
|
}
|
|
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
28783
|
function GapAlerts({ papers }) {
|
|
28206
28784
|
const gaps = reactExports.useMemo(() => {
|
|
28207
28785
|
const topicScores = /* @__PURE__ */ new Map();
|
|
@@ -28312,8 +28890,7 @@ function LiteratureSidebar() {
|
|
|
28312
28890
|
] }),
|
|
28313
28891
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mx-3 border-t t-border" }),
|
|
28314
28892
|
/* @__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 }),
|
|
28893
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(ConceptsList, {}),
|
|
28317
28894
|
/* @__PURE__ */ jsxRuntimeExports.jsx(GapAlerts, { papers }),
|
|
28318
28895
|
papers.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center py-6", children: [
|
|
28319
28896
|
/* @__PURE__ */ jsxRuntimeExports.jsx(ChartColumn, { size: 24, className: "mx-auto mb-2 t-text-muted opacity-30" }),
|
|
@@ -28505,20 +29082,25 @@ function UserProfile() {
|
|
|
28505
29082
|
}
|
|
28506
29083
|
);
|
|
28507
29084
|
}
|
|
28508
|
-
const
|
|
28509
|
-
const
|
|
28510
|
-
for (const p of
|
|
28511
|
-
|
|
29085
|
+
const allProviders = [...new Set(SUPPORTED_MODELS.map((m) => m.provider))];
|
|
29086
|
+
const allGroupedModels = {};
|
|
29087
|
+
for (const p of allProviders) {
|
|
29088
|
+
allGroupedModels[p] = SUPPORTED_MODELS.filter((m) => m.provider === p);
|
|
28512
29089
|
}
|
|
28513
29090
|
function ModelSelector$1({ selectedModel, onSelectModel }) {
|
|
28514
29091
|
const [open, setOpen] = reactExports.useState(false);
|
|
28515
29092
|
const [anthropicStatus, setAnthropicStatus] = reactExports.useState(null);
|
|
28516
29093
|
const [codexStatus, setCodexStatus] = reactExports.useState(null);
|
|
28517
29094
|
const [codexLoggingIn, setCodexLoggingIn] = reactExports.useState(false);
|
|
29095
|
+
const [anthropicSubStatus, setAnthropicSubStatus] = reactExports.useState(null);
|
|
29096
|
+
const [anthropicSubLoggingIn, setAnthropicSubLoggingIn] = reactExports.useState(false);
|
|
28518
29097
|
const [showAnthropicDialog, setShowAnthropicDialog] = reactExports.useState(false);
|
|
28519
29098
|
const [showOpenAIDialog, setShowOpenAIDialog] = reactExports.useState(false);
|
|
28520
29099
|
const ref = reactExports.useRef(null);
|
|
28521
29100
|
const api2 = window.api;
|
|
29101
|
+
const claudeSubEnabled = api2?.isClaudeSubEnabled?.() ?? false;
|
|
29102
|
+
const providers = claudeSubEnabled ? allProviders : allProviders.filter((p) => p !== "Claude Subscription");
|
|
29103
|
+
const groupedModels = claudeSubEnabled ? allGroupedModels : Object.fromEntries(Object.entries(allGroupedModels).filter(([p]) => p !== "Claude Subscription"));
|
|
28522
29104
|
const current = SUPPORTED_MODELS.find((m) => m.id === selectedModel);
|
|
28523
29105
|
const refreshAnthropicStatus = reactExports.useCallback(async () => {
|
|
28524
29106
|
try {
|
|
@@ -28536,6 +29118,14 @@ function ModelSelector$1({ selectedModel, onSelectModel }) {
|
|
|
28536
29118
|
setCodexStatus(null);
|
|
28537
29119
|
}
|
|
28538
29120
|
}, [api2]);
|
|
29121
|
+
const refreshAnthropicSubStatus = reactExports.useCallback(async () => {
|
|
29122
|
+
try {
|
|
29123
|
+
const status = await api2?.getAnthropicSubStatus?.();
|
|
29124
|
+
setAnthropicSubStatus(status ?? null);
|
|
29125
|
+
} catch {
|
|
29126
|
+
setAnthropicSubStatus(null);
|
|
29127
|
+
}
|
|
29128
|
+
}, [api2]);
|
|
28539
29129
|
reactExports.useEffect(() => {
|
|
28540
29130
|
if (!open) return;
|
|
28541
29131
|
const handler = (e) => {
|
|
@@ -28557,11 +29147,12 @@ function ModelSelector$1({ selectedModel, onSelectModel }) {
|
|
|
28557
29147
|
reactExports.useEffect(() => {
|
|
28558
29148
|
refreshAnthropicStatus();
|
|
28559
29149
|
refreshCodexStatus();
|
|
29150
|
+
if (claudeSubEnabled) refreshAnthropicSubStatus();
|
|
28560
29151
|
const unsub = api2?.onAnthropicAuthStatus?.((status) => setAnthropicStatus(status));
|
|
28561
29152
|
return () => {
|
|
28562
29153
|
if (typeof unsub === "function") unsub();
|
|
28563
29154
|
};
|
|
28564
|
-
}, [api2, refreshAnthropicStatus, refreshCodexStatus]);
|
|
29155
|
+
}, [api2, refreshAnthropicStatus, refreshCodexStatus, refreshAnthropicSubStatus, claudeSubEnabled]);
|
|
28565
29156
|
const handleCodexLogin = async () => {
|
|
28566
29157
|
setCodexLoggingIn(true);
|
|
28567
29158
|
try {
|
|
@@ -28581,6 +29172,25 @@ function ModelSelector$1({ selectedModel, onSelectModel }) {
|
|
|
28581
29172
|
await api2?.openaiCodexLogout?.();
|
|
28582
29173
|
await refreshCodexStatus();
|
|
28583
29174
|
};
|
|
29175
|
+
const handleAnthropicSubLogin = async () => {
|
|
29176
|
+
setAnthropicSubLoggingIn(true);
|
|
29177
|
+
try {
|
|
29178
|
+
const result = await api2?.anthropicSubLogin?.();
|
|
29179
|
+
if (result?.success) {
|
|
29180
|
+
await refreshAnthropicSubStatus();
|
|
29181
|
+
} else {
|
|
29182
|
+
console.error("[ModelSelector] Anthropic sub login failed:", result?.error);
|
|
29183
|
+
}
|
|
29184
|
+
} catch (err) {
|
|
29185
|
+
console.error("[ModelSelector] Anthropic sub login error:", err);
|
|
29186
|
+
} finally {
|
|
29187
|
+
setAnthropicSubLoggingIn(false);
|
|
29188
|
+
}
|
|
29189
|
+
};
|
|
29190
|
+
const handleAnthropicSubLogout = async () => {
|
|
29191
|
+
await api2?.anthropicSubLogout?.();
|
|
29192
|
+
await refreshAnthropicSubStatus();
|
|
29193
|
+
};
|
|
28584
29194
|
const handleModelSelect = async (model) => {
|
|
28585
29195
|
const { provider } = parseModelKey(model.id);
|
|
28586
29196
|
if (provider === "openai-codex") {
|
|
@@ -28596,6 +29206,19 @@ function ModelSelector$1({ selectedModel, onSelectModel }) {
|
|
|
28596
29206
|
setOpen(false);
|
|
28597
29207
|
return;
|
|
28598
29208
|
}
|
|
29209
|
+
if (provider === "anthropic-sub") {
|
|
29210
|
+
if (!anthropicSubStatus?.isLoggedIn) {
|
|
29211
|
+
await handleAnthropicSubLogin();
|
|
29212
|
+
const status = await api2?.getAnthropicSubStatus?.();
|
|
29213
|
+
if (!status?.isLoggedIn) {
|
|
29214
|
+
setOpen(false);
|
|
29215
|
+
return;
|
|
29216
|
+
}
|
|
29217
|
+
}
|
|
29218
|
+
onSelectModel(model.id);
|
|
29219
|
+
setOpen(false);
|
|
29220
|
+
return;
|
|
29221
|
+
}
|
|
28599
29222
|
if (provider === "openai") {
|
|
28600
29223
|
const status = await api2?.getOpenAIAuthStatus?.();
|
|
28601
29224
|
if (!status?.hasApiKey) {
|
|
@@ -28617,7 +29240,7 @@ function ModelSelector$1({ selectedModel, onSelectModel }) {
|
|
|
28617
29240
|
refreshAnthropicStatus();
|
|
28618
29241
|
};
|
|
28619
29242
|
const { provider: currentProvider } = current ? parseModelKey(current.id) : { provider: "" };
|
|
28620
|
-
const authBadge = currentProvider === "anthropic" ? anthropicStatus?.authMode === "api-key" ? "api" : "auth" : currentProvider === "openai-codex" ? "sub" : currentProvider === "openai" ? "api" : null;
|
|
29243
|
+
const authBadge = currentProvider === "anthropic" ? anthropicStatus?.authMode === "api-key" ? "api" : "auth" : currentProvider === "anthropic-sub" ? "sub" : currentProvider === "openai-codex" ? "sub" : currentProvider === "openai" ? "api" : null;
|
|
28621
29244
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { ref, className: "relative", children: [
|
|
28622
29245
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
28623
29246
|
"button",
|
|
@@ -28638,7 +29261,7 @@ function ModelSelector$1({ selectedModel, onSelectModel }) {
|
|
|
28638
29261
|
}
|
|
28639
29262
|
),
|
|
28640
29263
|
/* @__PURE__ */ jsxRuntimeExports.jsx(Cpu, { size: 14 }),
|
|
28641
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate max-w-[
|
|
29264
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate max-w-[72px]", children: current?.label || selectedModel }),
|
|
28642
29265
|
authBadge && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] px-1 rounded border t-border t-text-muted uppercase", children: authBadge }),
|
|
28643
29266
|
/* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { size: 12, className: `transition-transform ${open ? "rotate-180" : ""}` })
|
|
28644
29267
|
]
|
|
@@ -28678,6 +29301,38 @@ function ModelSelector$1({ selectedModel, onSelectModel }) {
|
|
|
28678
29301
|
}
|
|
28679
29302
|
)
|
|
28680
29303
|
] }),
|
|
29304
|
+
provider === "Claude Subscription" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-3 pb-1 flex items-center justify-between", children: [
|
|
29305
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[11px] t-text-muted", children: anthropicSubStatus?.isLoggedIn ? "Signed in" : "OAuth required" }),
|
|
29306
|
+
anthropicSubStatus?.isLoggedIn ? /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
29307
|
+
"button",
|
|
29308
|
+
{
|
|
29309
|
+
onClick: (e) => {
|
|
29310
|
+
e.stopPropagation();
|
|
29311
|
+
handleAnthropicSubLogout();
|
|
29312
|
+
},
|
|
29313
|
+
className: "text-[10px] t-text-muted hover:t-text flex items-center gap-0.5",
|
|
29314
|
+
children: [
|
|
29315
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(LogOut, { size: 10 }),
|
|
29316
|
+
" Sign out"
|
|
29317
|
+
]
|
|
29318
|
+
}
|
|
29319
|
+
) : /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
29320
|
+
"button",
|
|
29321
|
+
{
|
|
29322
|
+
onClick: (e) => {
|
|
29323
|
+
e.stopPropagation();
|
|
29324
|
+
handleAnthropicSubLogin();
|
|
29325
|
+
},
|
|
29326
|
+
disabled: anthropicSubLoggingIn,
|
|
29327
|
+
className: "text-[10px] t-text-accent flex items-center gap-0.5 hover:opacity-80 disabled:opacity-50",
|
|
29328
|
+
children: [
|
|
29329
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(LogIn, { size: 10 }),
|
|
29330
|
+
" ",
|
|
29331
|
+
anthropicSubLoggingIn ? "Signing in..." : "Sign in"
|
|
29332
|
+
]
|
|
29333
|
+
}
|
|
29334
|
+
)
|
|
29335
|
+
] }),
|
|
28681
29336
|
(provider === "OpenAI" || provider === "Anthropic") && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-3 pb-1 text-[11px] t-text-muted", children: "API Key" }),
|
|
28682
29337
|
groupedModels[provider].map((model) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
28683
29338
|
"button",
|
|
@@ -28961,75 +29616,119 @@ function LeftSidebar() {
|
|
|
28961
29616
|
useChatStore.getState().insertContextReset();
|
|
28962
29617
|
noContextShownRef.current = false;
|
|
28963
29618
|
}, []);
|
|
28964
|
-
return
|
|
28965
|
-
|
|
28966
|
-
|
|
28967
|
-
|
|
28968
|
-
|
|
28969
|
-
|
|
28970
|
-
|
|
28971
|
-
|
|
28972
|
-
|
|
28973
|
-
|
|
28974
|
-
|
|
28975
|
-
|
|
28976
|
-
|
|
29619
|
+
return (
|
|
29620
|
+
// Narrow windows (≤1279px) get w-80 (320px) so the center panel keeps
|
|
29621
|
+
// room to breathe; wider windows (≥1280px) get w-[22rem] (352px) so the
|
|
29622
|
+
// toolbar has comfortable slack. Below ~1024px the ModelSelector label
|
|
29623
|
+
// is the first thing to truncate — see ModelSelector for the shrink
|
|
29624
|
+
// pattern introduced in commit 95312df.
|
|
29625
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("aside", { className: "w-80 xl:w-[22rem] flex flex-col border-r t-border t-bg-base pt-10", children: [
|
|
29626
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("nav", { "aria-label": "Sidebar tools", className: "px-4 pb-3 flex items-center justify-between", children: [
|
|
29627
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(ModelSelector, {}),
|
|
29628
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1", children: [
|
|
29629
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(ReasoningToggle, {}),
|
|
29630
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
29631
|
+
ToolbarButton,
|
|
29632
|
+
{
|
|
29633
|
+
onClick: handleResetContext,
|
|
29634
|
+
tooltip: "Reset AI context",
|
|
29635
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(RotateCcw, { size: 16 })
|
|
29636
|
+
}
|
|
29637
|
+
),
|
|
29638
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
29639
|
+
ToolbarButton,
|
|
29640
|
+
{
|
|
29641
|
+
onClick: toggleTheme,
|
|
29642
|
+
tooltip: `${theme === "dark" ? "Light" : "Dark"} mode`,
|
|
29643
|
+
children: theme === "dark" ? /* @__PURE__ */ jsxRuntimeExports.jsx(Sun, { size: 16 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Moon, { size: 16 })
|
|
29644
|
+
}
|
|
29645
|
+
),
|
|
29646
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
29647
|
+
ToolbarButton,
|
|
29648
|
+
{
|
|
29649
|
+
onClick: () => useUIStore.getState().toggleTerminal(),
|
|
29650
|
+
tooltip: "Terminal ⌘`",
|
|
29651
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Terminal, { size: 16 })
|
|
29652
|
+
}
|
|
29653
|
+
)
|
|
29654
|
+
] })
|
|
29655
|
+
] }),
|
|
29656
|
+
/* @__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, {}) }),
|
|
29657
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "border-t t-border p-4", children: /* @__PURE__ */ jsxRuntimeExports.jsx(UserProfile, {}) })
|
|
29658
|
+
] })
|
|
29659
|
+
);
|
|
29660
|
+
}
|
|
29661
|
+
const STARTERS = [
|
|
29662
|
+
{
|
|
29663
|
+
label: "Understand this folder",
|
|
29664
|
+
description: "Scan files, existing artifacts, and recent work to get oriented."
|
|
29665
|
+
},
|
|
29666
|
+
{
|
|
29667
|
+
label: "Start a literature review on …",
|
|
29668
|
+
description: "Plan sub-topics, search multiple sources, score and summarize."
|
|
29669
|
+
},
|
|
29670
|
+
{
|
|
29671
|
+
label: "Capture a research note about …",
|
|
29672
|
+
description: "Draft a note artifact from your description."
|
|
29673
|
+
}
|
|
29674
|
+
];
|
|
29675
|
+
function focusInput() {
|
|
29676
|
+
const input = document.querySelector("[data-chat-input]");
|
|
29677
|
+
if (!input) return;
|
|
29678
|
+
input.focus();
|
|
29679
|
+
const end = input.value.length;
|
|
29680
|
+
try {
|
|
29681
|
+
input.setSelectionRange(end, end);
|
|
29682
|
+
} catch {
|
|
29683
|
+
}
|
|
29684
|
+
}
|
|
29685
|
+
function prefillFromLabel(label) {
|
|
29686
|
+
return label.replace(/…\s*$/, "").replace(/\s+$/, "") + (label.endsWith("…") ? " " : "");
|
|
29687
|
+
}
|
|
29688
|
+
function StarterRow({ starter, onActivate }) {
|
|
29689
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
29690
|
+
"button",
|
|
29691
|
+
{
|
|
29692
|
+
type: "button",
|
|
29693
|
+
onClick: onActivate,
|
|
29694
|
+
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",
|
|
29695
|
+
children: [
|
|
28977
29696
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
28978
|
-
|
|
29697
|
+
"span",
|
|
28979
29698
|
{
|
|
28980
|
-
|
|
28981
|
-
|
|
28982
|
-
children: theme === "dark" ? /* @__PURE__ */ jsxRuntimeExports.jsx(Sun, { size: 16 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Moon, { size: 16 })
|
|
29699
|
+
"aria-hidden": true,
|
|
29700
|
+
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
29701
|
}
|
|
28984
29702
|
),
|
|
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
|
-
] });
|
|
29703
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[13px] t-text-secondary group-hover:t-text transition-colors leading-snug", children: starter.label }),
|
|
29704
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[11px] t-text-muted leading-snug", children: starter.description })
|
|
29705
|
+
]
|
|
29706
|
+
}
|
|
29707
|
+
);
|
|
28998
29708
|
}
|
|
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
29709
|
function HeroIdle() {
|
|
29006
29710
|
const setDraftText = useChatStore((s15) => s15.setDraftText);
|
|
29007
|
-
const
|
|
29008
|
-
|
|
29009
|
-
|
|
29010
|
-
|
|
29711
|
+
const handleStarter = (label) => {
|
|
29712
|
+
const prefill = prefillFromLabel(label);
|
|
29713
|
+
setDraftText(prefill);
|
|
29714
|
+
requestAnimationFrame(focusInput);
|
|
29011
29715
|
};
|
|
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
|
-
)) })
|
|
29716
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full max-w-lg px-8", children: [
|
|
29717
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "pl-4 mb-2 text-[10px] uppercase tracking-wider t-text-muted font-medium", children: "Start" }),
|
|
29718
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-col", children: STARTERS.map((s15) => /* @__PURE__ */ jsxRuntimeExports.jsx(StarterRow, { starter: s15, onActivate: () => handleStarter(s15.label) }, s15.label)) }),
|
|
29719
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-8 pl-4 flex flex-col gap-1.5 text-[10px] t-text-muted", children: [
|
|
29720
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
29721
|
+
/* @__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: "@" }),
|
|
29722
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "mention a note, paper, or file" })
|
|
29723
|
+
] }),
|
|
29724
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
29725
|
+
/* @__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: "↵" }),
|
|
29726
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "send" }),
|
|
29727
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "opacity-50", "aria-hidden": true, children: "·" }),
|
|
29728
|
+
/* @__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: "⇧↵" }),
|
|
29729
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "newline" })
|
|
29730
|
+
] })
|
|
29731
|
+
] })
|
|
29033
29732
|
] });
|
|
29034
29733
|
}
|
|
29035
29734
|
function getFileName(path2) {
|
|
@@ -29656,8 +30355,8 @@ function ToolUseStream({ events: propEvents }) {
|
|
|
29656
30355
|
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
30356
|
] });
|
|
29658
30357
|
}
|
|
29659
|
-
const api$
|
|
29660
|
-
const remarkPlugins$
|
|
30358
|
+
const api$7 = window.api;
|
|
30359
|
+
const remarkPlugins$2 = [remarkGfm];
|
|
29661
30360
|
function formatMessageTime(ts2) {
|
|
29662
30361
|
const d = new Date(ts2);
|
|
29663
30362
|
const now2 = /* @__PURE__ */ new Date();
|
|
@@ -29731,7 +30430,7 @@ function SelectionBookmark() {
|
|
|
29731
30430
|
try {
|
|
29732
30431
|
const first = selectedText.split(/[.!?\n]/)[0].trim();
|
|
29733
30432
|
const title = first.length > 60 ? first.slice(0, 57) + "…" : first || "Untitled selection";
|
|
29734
|
-
const created = await api$
|
|
30433
|
+
const created = await api$7.artifactCreate({
|
|
29735
30434
|
type: "note",
|
|
29736
30435
|
title,
|
|
29737
30436
|
content: selectedText,
|
|
@@ -29796,7 +30495,7 @@ const MessageBubble = React$2.memo(function MessageBubble2({ msg, isSaved }) {
|
|
|
29796
30495
|
try {
|
|
29797
30496
|
const first = msg.content.replace(/^#+\s*/, "").split(/[.!?\n]/)[0].trim();
|
|
29798
30497
|
const title = first.length > 60 ? first.slice(0, 57) + "…" : first || "Untitled note";
|
|
29799
|
-
const created = await api$
|
|
30498
|
+
const created = await api$7.artifactCreate({
|
|
29800
30499
|
type: "note",
|
|
29801
30500
|
title,
|
|
29802
30501
|
content: msg.content,
|
|
@@ -29825,7 +30524,7 @@ const MessageBubble = React$2.memo(function MessageBubble2({ msg, isSaved }) {
|
|
|
29825
30524
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `flex ${isUser ? "justify-end" : "justify-start"} group`, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
29826
30525
|
"div",
|
|
29827
30526
|
{
|
|
29828
|
-
className: `relative max-w-[
|
|
30527
|
+
className: `relative max-w-[90%] rounded-2xl px-4 py-3 text-sm t-text ${!isUser ? "assistant-bubble" : ""}${!isUser && isSaved ? " border-l-2 border-[var(--color-status-success)]" : ""}`,
|
|
29829
30528
|
style: {
|
|
29830
30529
|
background: isUser ? "var(--color-bubble-user)" : "var(--color-bubble-assistant)"
|
|
29831
30530
|
},
|
|
@@ -29842,7 +30541,7 @@ const MessageBubble = React$2.memo(function MessageBubble2({ msg, isSaved }) {
|
|
|
29842
30541
|
},
|
|
29843
30542
|
i
|
|
29844
30543
|
)) }),
|
|
29845
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "md-prose", style: { color: "var(--color-text)" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Markdown, { remarkPlugins: remarkPlugins$
|
|
30544
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "md-prose", style: { color: "var(--color-text)" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Markdown, { remarkPlugins: remarkPlugins$2, children: msg.content }) }),
|
|
29846
30545
|
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
30546
|
!isUser && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "absolute -right-8 top-2 flex flex-col gap-1.5", children: [
|
|
29848
30547
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -29872,11 +30571,18 @@ const MessageBubble = React$2.memo(function MessageBubble2({ msg, isSaved }) {
|
|
|
29872
30571
|
) });
|
|
29873
30572
|
});
|
|
29874
30573
|
function ThinkingIndicator() {
|
|
29875
|
-
return /* @__PURE__ */ jsxRuntimeExports.
|
|
29876
|
-
|
|
29877
|
-
|
|
29878
|
-
|
|
29879
|
-
|
|
30574
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
30575
|
+
"div",
|
|
30576
|
+
{
|
|
30577
|
+
role: "status",
|
|
30578
|
+
"aria-live": "polite",
|
|
30579
|
+
className: "flex items-center gap-2 mt-3 ml-2 text-[11px] t-text-muted",
|
|
30580
|
+
children: [
|
|
30581
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { size: 11, className: "t-text-accent-soft animate-spin shrink-0", "aria-hidden": true }),
|
|
30582
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Thinking…" })
|
|
30583
|
+
]
|
|
30584
|
+
}
|
|
30585
|
+
);
|
|
29880
30586
|
}
|
|
29881
30587
|
function StreamingBubble() {
|
|
29882
30588
|
const text2 = useChatStore((s15) => s15.streamingText);
|
|
@@ -29884,66 +30590,211 @@ function StreamingBubble() {
|
|
|
29884
30590
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-start", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
29885
30591
|
"div",
|
|
29886
30592
|
{
|
|
29887
|
-
className: "max-w-[
|
|
30593
|
+
className: "max-w-[90%] rounded-2xl px-4 py-3 text-sm t-text assistant-bubble",
|
|
29888
30594
|
style: { background: "var(--color-bubble-assistant)" },
|
|
29889
30595
|
children: [
|
|
29890
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "md-prose", style: { color: "var(--color-text)" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Markdown, { remarkPlugins: remarkPlugins$
|
|
30596
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "md-prose", style: { color: "var(--color-text)" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Markdown, { remarkPlugins: remarkPlugins$2, children: text2 }) }),
|
|
29891
30597
|
/* @__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
30598
|
]
|
|
29893
30599
|
}
|
|
29894
30600
|
) });
|
|
29895
30601
|
}
|
|
29896
|
-
|
|
29897
|
-
|
|
29898
|
-
|
|
29899
|
-
|
|
29900
|
-
|
|
29901
|
-
|
|
29902
|
-
let lastDate = "";
|
|
29903
|
-
for (const msg of userAndAssistant) {
|
|
29904
|
-
const gap = msg.timestamp - lastTs;
|
|
29905
|
-
if (gap >= GAP_THRESHOLD_MS || lastTs === 0) {
|
|
29906
|
-
const d = new Date(msg.timestamp);
|
|
29907
|
-
const dateStr = d.toDateString();
|
|
29908
|
-
const time = d.toLocaleTimeString([], { hour: "numeric", minute: "2-digit" });
|
|
29909
|
-
let label;
|
|
29910
|
-
const now2 = /* @__PURE__ */ new Date();
|
|
29911
|
-
if (dateStr !== lastDate) {
|
|
29912
|
-
const isToday = dateStr === now2.toDateString();
|
|
29913
|
-
const yesterday = new Date(now2);
|
|
29914
|
-
yesterday.setDate(yesterday.getDate() - 1);
|
|
29915
|
-
const isYesterday = dateStr === yesterday.toDateString();
|
|
29916
|
-
const dayLabel = isToday ? "" : isYesterday ? "Yest " : d.toLocaleDateString([], { month: "short", day: "numeric" }) + " ";
|
|
29917
|
-
label = dayLabel + time;
|
|
29918
|
-
lastDate = dateStr;
|
|
29919
|
-
} else {
|
|
29920
|
-
label = time;
|
|
29921
|
-
}
|
|
29922
|
-
nodes.push({ label, msgId: msg.id });
|
|
29923
|
-
}
|
|
29924
|
-
lastTs = msg.timestamp;
|
|
29925
|
-
}
|
|
29926
|
-
return nodes;
|
|
30602
|
+
function buildScrubNodes(messages) {
|
|
30603
|
+
return messages.filter((m) => m.role === "user").map((msg) => ({
|
|
30604
|
+
msgId: msg.id,
|
|
30605
|
+
preview: msg.content.replace(/^#+\s*/gm, "").slice(0, 100),
|
|
30606
|
+
time: msg.timestamp > 0 ? formatMessageTime(msg.timestamp) : ""
|
|
30607
|
+
}));
|
|
29927
30608
|
}
|
|
29928
|
-
function ChatTimeline({ messages }) {
|
|
30609
|
+
function ChatTimeline({ messages, scrollContainerRef }) {
|
|
29929
30610
|
const requestScrollTo = useChatStore((s15) => s15.requestScrollTo);
|
|
29930
|
-
const nodes = reactExports.useMemo(() =>
|
|
29931
|
-
|
|
29932
|
-
|
|
29933
|
-
|
|
29934
|
-
|
|
29935
|
-
|
|
30611
|
+
const nodes = reactExports.useMemo(() => buildScrubNodes(messages), [messages]);
|
|
30612
|
+
const positionsRef = reactExports.useRef([]);
|
|
30613
|
+
const [, forceUpdate] = reactExports.useState(0);
|
|
30614
|
+
const [hoveredIdx, setHoveredIdx] = reactExports.useState(null);
|
|
30615
|
+
const [hoverY, setHoverY] = reactExports.useState(0);
|
|
30616
|
+
const [viewport, setViewport] = reactExports.useState({ top: 0, height: 1 });
|
|
30617
|
+
const railRef = reactExports.useRef(null);
|
|
30618
|
+
const railHRef = reactExports.useRef(0);
|
|
30619
|
+
const RAIL_PAD = 8;
|
|
30620
|
+
const computePositions = reactExports.useCallback(() => {
|
|
30621
|
+
const container = scrollContainerRef.current;
|
|
30622
|
+
if (!container || nodes.length === 0) return;
|
|
30623
|
+
const scrollH = container.scrollHeight;
|
|
30624
|
+
if (scrollH <= 0) return;
|
|
30625
|
+
const containerRect = container.getBoundingClientRect();
|
|
30626
|
+
const scrollTop = container.scrollTop;
|
|
30627
|
+
const pos = nodes.map((node2) => {
|
|
30628
|
+
const el2 = container.querySelector(`[data-msg-id="${node2.msgId}"]`);
|
|
30629
|
+
if (!el2) return 0;
|
|
30630
|
+
const elRect = el2.getBoundingClientRect();
|
|
30631
|
+
const absTop = elRect.top - containerRect.top + scrollTop;
|
|
30632
|
+
return Math.min(Math.max(absTop / scrollH, 0), 1);
|
|
30633
|
+
});
|
|
30634
|
+
positionsRef.current = pos;
|
|
30635
|
+
forceUpdate((n) => n + 1);
|
|
30636
|
+
}, [nodes, scrollContainerRef]);
|
|
30637
|
+
reactExports.useEffect(() => {
|
|
30638
|
+
const container = scrollContainerRef.current;
|
|
30639
|
+
if (!container || nodes.length === 0) {
|
|
30640
|
+
positionsRef.current = [];
|
|
30641
|
+
return;
|
|
30642
|
+
}
|
|
30643
|
+
const raf = requestAnimationFrame(() => computePositions());
|
|
30644
|
+
const observer = new ResizeObserver(() => computePositions());
|
|
30645
|
+
observer.observe(container);
|
|
30646
|
+
return () => {
|
|
30647
|
+
cancelAnimationFrame(raf);
|
|
30648
|
+
observer.disconnect();
|
|
30649
|
+
};
|
|
30650
|
+
}, [nodes, messages, scrollContainerRef, computePositions]);
|
|
30651
|
+
reactExports.useEffect(() => {
|
|
30652
|
+
const rail = railRef.current;
|
|
30653
|
+
if (!rail) return;
|
|
30654
|
+
const obs = new ResizeObserver(([e]) => {
|
|
30655
|
+
railHRef.current = e.contentRect.height;
|
|
30656
|
+
forceUpdate((n) => n + 1);
|
|
30657
|
+
});
|
|
30658
|
+
obs.observe(rail);
|
|
30659
|
+
return () => obs.disconnect();
|
|
30660
|
+
}, []);
|
|
30661
|
+
reactExports.useEffect(() => {
|
|
30662
|
+
const container = scrollContainerRef.current;
|
|
30663
|
+
if (!container) return;
|
|
30664
|
+
const update = () => {
|
|
30665
|
+
const { scrollTop, scrollHeight, clientHeight } = container;
|
|
30666
|
+
if (scrollHeight <= 0) return;
|
|
30667
|
+
setViewport({
|
|
30668
|
+
top: scrollTop / scrollHeight,
|
|
30669
|
+
height: Math.min(clientHeight / scrollHeight, 1)
|
|
30670
|
+
});
|
|
30671
|
+
};
|
|
30672
|
+
update();
|
|
30673
|
+
container.addEventListener("scroll", update, { passive: true });
|
|
30674
|
+
const obs = new ResizeObserver(update);
|
|
30675
|
+
obs.observe(container);
|
|
30676
|
+
return () => {
|
|
30677
|
+
container.removeEventListener("scroll", update);
|
|
30678
|
+
obs.disconnect();
|
|
30679
|
+
};
|
|
30680
|
+
}, [scrollContainerRef, messages]);
|
|
30681
|
+
const toY = (ratio) => {
|
|
30682
|
+
const usable = railHRef.current - RAIL_PAD * 2;
|
|
30683
|
+
return usable > 0 ? RAIL_PAD + ratio * usable : 0;
|
|
30684
|
+
};
|
|
30685
|
+
const handleMouseMove = reactExports.useCallback((e) => {
|
|
30686
|
+
const rail = railRef.current;
|
|
30687
|
+
const positions2 = positionsRef.current;
|
|
30688
|
+
if (!rail || positions2.length === 0) return;
|
|
30689
|
+
const rect = rail.getBoundingClientRect();
|
|
30690
|
+
const y = e.clientY - rect.top;
|
|
30691
|
+
setHoverY(y);
|
|
30692
|
+
const usable = railHRef.current - RAIL_PAD * 2;
|
|
30693
|
+
if (usable <= 0) return;
|
|
30694
|
+
const ratio = Math.max(0, Math.min(1, (y - RAIL_PAD) / usable));
|
|
30695
|
+
let best = 0;
|
|
30696
|
+
let bestDist = Infinity;
|
|
30697
|
+
for (let i = 0; i < positions2.length; i++) {
|
|
30698
|
+
const d = Math.abs(positions2[i] - ratio);
|
|
30699
|
+
if (d < bestDist) {
|
|
30700
|
+
bestDist = d;
|
|
30701
|
+
best = i;
|
|
30702
|
+
}
|
|
30703
|
+
}
|
|
30704
|
+
setHoveredIdx(best);
|
|
30705
|
+
}, []);
|
|
30706
|
+
const handleMouseLeave = reactExports.useCallback(() => setHoveredIdx(null), []);
|
|
30707
|
+
const handleClick = reactExports.useCallback(() => {
|
|
30708
|
+
if (hoveredIdx !== null && nodes[hoveredIdx]) {
|
|
30709
|
+
requestScrollTo(nodes[hoveredIdx].msgId);
|
|
30710
|
+
}
|
|
30711
|
+
}, [hoveredIdx, nodes, requestScrollTo]);
|
|
30712
|
+
const positions = positionsRef.current;
|
|
30713
|
+
const railH = railHRef.current;
|
|
30714
|
+
const ready = nodes.length >= 3 && positions.length === nodes.length && railH > 0;
|
|
30715
|
+
const hovered = hoveredIdx !== null ? nodes[hoveredIdx] : null;
|
|
30716
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "absolute right-0 top-0 bottom-0 w-[48px] select-none", style: { zIndex: 10 }, children: [
|
|
30717
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
30718
|
+
"div",
|
|
29936
30719
|
{
|
|
29937
|
-
|
|
29938
|
-
className: "
|
|
29939
|
-
|
|
29940
|
-
|
|
29941
|
-
|
|
29942
|
-
|
|
29943
|
-
|
|
29944
|
-
|
|
29945
|
-
|
|
29946
|
-
|
|
30720
|
+
ref: railRef,
|
|
30721
|
+
className: "absolute inset-0 cursor-pointer",
|
|
30722
|
+
role: "navigation",
|
|
30723
|
+
"aria-label": "Message timeline",
|
|
30724
|
+
onMouseMove: ready ? handleMouseMove : void 0,
|
|
30725
|
+
onMouseLeave: ready ? handleMouseLeave : void 0,
|
|
30726
|
+
onClick: ready ? handleClick : void 0,
|
|
30727
|
+
children: ready && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
30728
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
30729
|
+
"div",
|
|
30730
|
+
{
|
|
30731
|
+
className: "absolute left-[23px] w-px",
|
|
30732
|
+
style: { top: RAIL_PAD, bottom: RAIL_PAD, background: "var(--color-border)", opacity: 0.25 }
|
|
30733
|
+
}
|
|
30734
|
+
),
|
|
30735
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
30736
|
+
"div",
|
|
30737
|
+
{
|
|
30738
|
+
className: "absolute left-[18px] w-[11px] rounded-full",
|
|
30739
|
+
style: {
|
|
30740
|
+
top: toY(viewport.top),
|
|
30741
|
+
height: Math.max(12, viewport.height * (railH - RAIL_PAD * 2)),
|
|
30742
|
+
background: "var(--color-accent-soft)",
|
|
30743
|
+
opacity: 0.15
|
|
30744
|
+
}
|
|
30745
|
+
}
|
|
30746
|
+
),
|
|
30747
|
+
nodes.map((node2, i) => {
|
|
30748
|
+
const isActive = hoveredIdx === i;
|
|
30749
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
30750
|
+
"div",
|
|
30751
|
+
{
|
|
30752
|
+
className: "absolute",
|
|
30753
|
+
style: {
|
|
30754
|
+
top: toY(positions[i]),
|
|
30755
|
+
left: 17,
|
|
30756
|
+
width: isActive ? 16 : 8,
|
|
30757
|
+
height: isActive ? 3 : 2,
|
|
30758
|
+
borderRadius: 1,
|
|
30759
|
+
background: "var(--color-accent-soft)",
|
|
30760
|
+
opacity: isActive ? 1 : 0.35,
|
|
30761
|
+
transition: "opacity 80ms"
|
|
30762
|
+
}
|
|
30763
|
+
},
|
|
30764
|
+
node2.msgId
|
|
30765
|
+
);
|
|
30766
|
+
}),
|
|
30767
|
+
hoveredIdx !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
30768
|
+
"div",
|
|
30769
|
+
{
|
|
30770
|
+
className: "absolute pointer-events-none",
|
|
30771
|
+
style: { top: hoverY, left: 6, right: 6, height: 1, background: "var(--color-accent-soft)", opacity: 0.6 }
|
|
30772
|
+
}
|
|
30773
|
+
)
|
|
30774
|
+
] })
|
|
30775
|
+
}
|
|
30776
|
+
),
|
|
30777
|
+
ready && hovered && hoveredIdx !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
30778
|
+
"div",
|
|
30779
|
+
{
|
|
30780
|
+
className: "absolute right-[52px] pointer-events-none",
|
|
30781
|
+
style: { top: Math.max(8, Math.min(hoverY - 28, railH - 80)), zIndex: 50 },
|
|
30782
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
30783
|
+
"div",
|
|
30784
|
+
{
|
|
30785
|
+
className: "w-56 rounded-lg border shadow-lg overflow-hidden",
|
|
30786
|
+
style: { background: "var(--color-bg-elevated)", borderColor: "var(--color-border)" },
|
|
30787
|
+
children: [
|
|
30788
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-[3px]", style: { background: "var(--color-accent-soft)" } }),
|
|
30789
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-3 py-2", children: [
|
|
30790
|
+
hovered.time && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] t-text-muted block mb-1", children: hovered.time }),
|
|
30791
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] t-text leading-relaxed line-clamp-3", children: hovered.preview || "(empty)" })
|
|
30792
|
+
] })
|
|
30793
|
+
]
|
|
30794
|
+
}
|
|
30795
|
+
)
|
|
30796
|
+
}
|
|
30797
|
+
)
|
|
29947
30798
|
] });
|
|
29948
30799
|
}
|
|
29949
30800
|
function ChatMessages() {
|
|
@@ -30002,13 +30853,14 @@ function ChatMessages() {
|
|
|
30002
30853
|
}, [scrollToMessageId]);
|
|
30003
30854
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative h-full", children: [
|
|
30004
30855
|
/* @__PURE__ */ jsxRuntimeExports.jsx(SelectionBookmark, {}),
|
|
30005
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(ChatTimeline, { messages }),
|
|
30856
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(ChatTimeline, { messages, scrollContainerRef }),
|
|
30006
30857
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
30007
30858
|
"div",
|
|
30008
30859
|
{
|
|
30009
30860
|
ref: scrollContainerRef,
|
|
30010
30861
|
onScroll: handleScroll,
|
|
30011
|
-
className: "overflow-y-auto h-full pr-[
|
|
30862
|
+
className: "overflow-y-auto h-full pr-[48px]",
|
|
30863
|
+
style: { scrollbarWidth: "none" },
|
|
30012
30864
|
role: "log",
|
|
30013
30865
|
"aria-label": "Chat messages",
|
|
30014
30866
|
"aria-live": "polite",
|
|
@@ -30050,7 +30902,7 @@ function ChatMessages() {
|
|
|
30050
30902
|
)
|
|
30051
30903
|
] });
|
|
30052
30904
|
}
|
|
30053
|
-
const api$
|
|
30905
|
+
const api$6 = window.api;
|
|
30054
30906
|
const typeIcons$1 = {
|
|
30055
30907
|
note: /* @__PURE__ */ jsxRuntimeExports.jsx(StickyNote, { size: 13, className: "t-text-warning" }),
|
|
30056
30908
|
paper: /* @__PURE__ */ jsxRuntimeExports.jsx(BookOpen, { size: 13, className: "t-text-info" }),
|
|
@@ -30109,7 +30961,7 @@ function MentionPopover({ query, onSelect, onClose }) {
|
|
|
30109
30961
|
}
|
|
30110
30962
|
}
|
|
30111
30963
|
debounceRef.current = setTimeout(() => {
|
|
30112
|
-
api$
|
|
30964
|
+
api$6.getCandidates(search2, type).then((result) => {
|
|
30113
30965
|
if (stale) return;
|
|
30114
30966
|
setCandidates(result || []);
|
|
30115
30967
|
setSelectedIdx(0);
|
|
@@ -30302,7 +31154,7 @@ const SLASH_COMMANDS = [
|
|
|
30302
31154
|
{ name: "/delete", description: "Delete an entity", args: "<id>" },
|
|
30303
31155
|
{ name: "/help", description: "Show available commands" }
|
|
30304
31156
|
];
|
|
30305
|
-
const api$
|
|
31157
|
+
const api$5 = window.api;
|
|
30306
31158
|
const ACCEPTED_IMAGE_TYPES = ["image/png", "image/jpeg", "image/gif", "image/webp"];
|
|
30307
31159
|
const MAX_IMAGES = 5;
|
|
30308
31160
|
const ACCEPTED_DOC_EXTENSIONS = [".pdf", ".csv", ".md", ".txt", ".json", ".xml", ".html", ".docx"];
|
|
@@ -30423,7 +31275,7 @@ function ChatInput() {
|
|
|
30423
31275
|
const dataUrl = reader.result;
|
|
30424
31276
|
const base64 = dataUrl.split(",")[1];
|
|
30425
31277
|
try {
|
|
30426
|
-
const result = await api$
|
|
31278
|
+
const result = await api$5.convertFileToText(file.name, base64);
|
|
30427
31279
|
if (result?.success && result.content) {
|
|
30428
31280
|
setPendingFiles((p) => p.map(
|
|
30429
31281
|
(f) => f.name === file.name ? { ...f, content: result.content, loading: false } : f
|
|
@@ -30540,19 +31392,19 @@ ${fileBlocks}`;
|
|
|
30540
31392
|
try {
|
|
30541
31393
|
switch (cmd) {
|
|
30542
31394
|
case "/notes": {
|
|
30543
|
-
const notes = await api$
|
|
31395
|
+
const notes = await api$5.listNotes();
|
|
30544
31396
|
result = notes?.length ? `**Notes (${notes.length}):**
|
|
30545
31397
|
` + notes.map((n) => `- ${n.title} \`${n.id.slice(0, 8)}\``).join("\n") : "No notes yet.";
|
|
30546
31398
|
break;
|
|
30547
31399
|
}
|
|
30548
31400
|
case "/papers": {
|
|
30549
|
-
const papers = await api$
|
|
31401
|
+
const papers = await api$5.listLiterature();
|
|
30550
31402
|
result = papers?.length ? `**Papers (${papers.length}):**
|
|
30551
31403
|
` + papers.map((p) => `- ${p.title} \`${p.citeKey}\``).join("\n") : "No papers yet.";
|
|
30552
31404
|
break;
|
|
30553
31405
|
}
|
|
30554
31406
|
case "/data": {
|
|
30555
|
-
const data = await api$
|
|
31407
|
+
const data = await api$5.listData();
|
|
30556
31408
|
result = data?.length ? `**Data (${data.length}):**
|
|
30557
31409
|
` + data.map((d) => `- ${d.name} \`${d.id.slice(0, 8)}\``).join("\n") : "No data attachments yet.";
|
|
30558
31410
|
break;
|
|
@@ -30562,7 +31414,7 @@ ${fileBlocks}`;
|
|
|
30562
31414
|
result = "Usage: `/search <query>`";
|
|
30563
31415
|
break;
|
|
30564
31416
|
}
|
|
30565
|
-
const results = await api$
|
|
31417
|
+
const results = await api$5.search(rest);
|
|
30566
31418
|
result = results?.length ? `**Search results for "${rest}":**
|
|
30567
31419
|
` + results.map((r) => `- [${r.type}] ${r.title} \`${r.id.slice(0, 8)}\``).join("\n") : `No results for "${rest}".`;
|
|
30568
31420
|
break;
|
|
@@ -30572,7 +31424,7 @@ ${fileBlocks}`;
|
|
|
30572
31424
|
result = "Usage: `/note <title>`";
|
|
30573
31425
|
break;
|
|
30574
31426
|
}
|
|
30575
|
-
const r = await api$
|
|
31427
|
+
const r = await api$5.artifactCreate({ type: "note", title: rest, content: "" });
|
|
30576
31428
|
result = r?.success ? `Note saved: **${rest}**` : `Failed: ${r?.error || "unknown error"}`;
|
|
30577
31429
|
refreshEntities();
|
|
30578
31430
|
break;
|
|
@@ -30595,7 +31447,7 @@ ${fileBlocks}`;
|
|
|
30595
31447
|
const bibtex = flags.bibtex || `@article{${citeKey},
|
|
30596
31448
|
title = {${cleaned}}
|
|
30597
31449
|
}`;
|
|
30598
|
-
const r = await api$
|
|
31450
|
+
const r = await api$5.artifactCreate({
|
|
30599
31451
|
type: "paper",
|
|
30600
31452
|
title: cleaned,
|
|
30601
31453
|
authors,
|
|
@@ -30622,7 +31474,7 @@ ${fileBlocks}`;
|
|
|
30622
31474
|
result = "Usage: `/save-data <name> --path <file>`";
|
|
30623
31475
|
break;
|
|
30624
31476
|
}
|
|
30625
|
-
const r = await api$
|
|
31477
|
+
const r = await api$5.artifactCreate({
|
|
30626
31478
|
type: "data",
|
|
30627
31479
|
title: cleaned,
|
|
30628
31480
|
filePath: flags.path,
|
|
@@ -30633,7 +31485,7 @@ ${fileBlocks}`;
|
|
|
30633
31485
|
break;
|
|
30634
31486
|
}
|
|
30635
31487
|
case "/summary": {
|
|
30636
|
-
const summaryResult = await api$
|
|
31488
|
+
const summaryResult = await api$5.sessionSummaryGet();
|
|
30637
31489
|
if (!summaryResult?.success || !summaryResult?.summary) {
|
|
30638
31490
|
result = "No session summary available yet.";
|
|
30639
31491
|
break;
|
|
@@ -30660,7 +31512,7 @@ ${s15.openQuestions.map((q2) => `- ${q2}`).join("\n")}`;
|
|
|
30660
31512
|
result = "Usage: `/delete <id>`";
|
|
30661
31513
|
break;
|
|
30662
31514
|
}
|
|
30663
|
-
const r = await api$
|
|
31515
|
+
const r = await api$5.deleteEntity(rest);
|
|
30664
31516
|
result = r?.success ? `Deleted \`${rest}\`` : `Failed: ${r?.error || "not found"}`;
|
|
30665
31517
|
refreshEntities();
|
|
30666
31518
|
break;
|
|
@@ -30879,49 +31731,245 @@ ${s15.openQuestions.map((q2) => `- ${q2}`).join("\n")}`;
|
|
|
30879
31731
|
)
|
|
30880
31732
|
] });
|
|
30881
31733
|
}
|
|
30882
|
-
|
|
30883
|
-
|
|
30884
|
-
|
|
30885
|
-
|
|
30886
|
-
|
|
30887
|
-
|
|
30888
|
-
|
|
30889
|
-
|
|
30890
|
-
|
|
30891
|
-
|
|
31734
|
+
const api$4 = window.api;
|
|
31735
|
+
const remarkPlugins$1 = [remarkGfm];
|
|
31736
|
+
function PaperFallback({ paper }) {
|
|
31737
|
+
const authors = paper.authors || [];
|
|
31738
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [
|
|
31739
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h1", { className: "text-base font-semibold t-text leading-tight", children: paper.title }),
|
|
31740
|
+
authors.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs t-text-muted", children: authors.join(", ") }),
|
|
31741
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap gap-1.5", children: [
|
|
31742
|
+
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 }),
|
|
31743
|
+
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 }),
|
|
31744
|
+
paper.doi && !paper.doi.startsWith("unknown:") && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
31745
|
+
"a",
|
|
31746
|
+
{
|
|
31747
|
+
href: `https://doi.org/${paper.doi}`,
|
|
31748
|
+
target: "_blank",
|
|
31749
|
+
rel: "noopener noreferrer",
|
|
31750
|
+
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",
|
|
31751
|
+
children: [
|
|
31752
|
+
"DOI ",
|
|
31753
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(ExternalLink, { size: 8 })
|
|
31754
|
+
]
|
|
31755
|
+
}
|
|
31756
|
+
),
|
|
31757
|
+
paper.relevanceScore != null && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "px-1.5 py-0.5 text-[10px] rounded t-bg-elevated t-text-accent", children: [
|
|
31758
|
+
paper.relevanceScore,
|
|
31759
|
+
"/10"
|
|
31760
|
+
] })
|
|
31761
|
+
] }),
|
|
31762
|
+
paper.abstract && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
31763
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] t-text-muted uppercase tracking-wider mb-1 font-medium", children: "Abstract" }),
|
|
31764
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs t-text-secondary leading-relaxed", children: paper.abstract })
|
|
31765
|
+
] }),
|
|
31766
|
+
paper.relevanceJustification && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
31767
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] t-text-muted uppercase tracking-wider mb-1 font-medium", children: "Relevance" }),
|
|
31768
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs t-text-secondary italic leading-relaxed", children: paper.relevanceJustification })
|
|
31769
|
+
] }),
|
|
31770
|
+
(paper.keyFindings || []).length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
31771
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] t-text-muted uppercase tracking-wider mb-1 font-medium", children: "Key Findings" }),
|
|
31772
|
+
/* @__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: [
|
|
31773
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0 mt-1 w-1 h-1 rounded-full bg-[var(--color-accent-soft)]" }),
|
|
31774
|
+
f
|
|
31775
|
+
] }, i)) })
|
|
31776
|
+
] }),
|
|
31777
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] t-text-muted italic pt-2", children: "No wiki page available for this paper yet." })
|
|
31778
|
+
] });
|
|
31779
|
+
}
|
|
31780
|
+
function WikiReaderPanel() {
|
|
31781
|
+
const slug = useUIStore((s15) => s15.wikiReaderSlug);
|
|
31782
|
+
const setSlug = useUIStore((s15) => s15.setWikiReaderSlug);
|
|
31783
|
+
const goBack = useUIStore((s15) => s15.wikiReaderBack);
|
|
31784
|
+
const history = useUIStore((s15) => s15.wikiReaderHistory);
|
|
31785
|
+
const papers = useEntityStore((s15) => s15.papers);
|
|
31786
|
+
const [content2, setContent] = reactExports.useState(null);
|
|
31787
|
+
const [loading, setLoading] = reactExports.useState(false);
|
|
31788
|
+
const isPaperFallback = slug?.startsWith("paper:");
|
|
31789
|
+
const fallbackPaper = isPaperFallback ? papers.find((p) => p.id === slug.replace("paper:", "")) : null;
|
|
31790
|
+
reactExports.useEffect(() => {
|
|
31791
|
+
if (!slug || isPaperFallback) {
|
|
31792
|
+
setContent(null);
|
|
31793
|
+
return;
|
|
30892
31794
|
}
|
|
30893
|
-
|
|
30894
|
-
|
|
30895
|
-
|
|
30896
|
-
|
|
30897
|
-
|
|
30898
|
-
|
|
30899
|
-
onClick: () => onSelect(null),
|
|
30900
|
-
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"}`,
|
|
30901
|
-
children: [
|
|
30902
|
-
"All Topics (",
|
|
30903
|
-
papers.length,
|
|
30904
|
-
")"
|
|
30905
|
-
]
|
|
31795
|
+
let cancelled = false;
|
|
31796
|
+
setLoading(true);
|
|
31797
|
+
api$4.wikiReadPage?.(slug).then((md) => {
|
|
31798
|
+
if (!cancelled) {
|
|
31799
|
+
setContent(md);
|
|
31800
|
+
setLoading(false);
|
|
30906
31801
|
}
|
|
30907
|
-
)
|
|
30908
|
-
|
|
30909
|
-
|
|
30910
|
-
|
|
30911
|
-
|
|
30912
|
-
|
|
30913
|
-
|
|
30914
|
-
|
|
30915
|
-
|
|
30916
|
-
|
|
30917
|
-
|
|
30918
|
-
|
|
30919
|
-
|
|
30920
|
-
|
|
30921
|
-
|
|
30922
|
-
|
|
31802
|
+
}).catch(() => {
|
|
31803
|
+
if (!cancelled) {
|
|
31804
|
+
setContent(null);
|
|
31805
|
+
setLoading(false);
|
|
31806
|
+
}
|
|
31807
|
+
});
|
|
31808
|
+
return () => {
|
|
31809
|
+
cancelled = true;
|
|
31810
|
+
};
|
|
31811
|
+
}, [slug, isPaperFallback]);
|
|
31812
|
+
const processedContent = reactExports.useMemo(() => {
|
|
31813
|
+
if (!content2) return null;
|
|
31814
|
+
return content2.replace(
|
|
31815
|
+
/<!--\s*paper:(\S+)\s*-->([\s\S]*?)<!--\s*\/paper:\1\s*-->/g,
|
|
31816
|
+
(_match, paperSlug, body) => {
|
|
31817
|
+
const firstLine = body.trim().split("\n")[0] || "";
|
|
31818
|
+
const titleMatch = firstLine.match(/\*{1,2}([^*]+)\*{1,2}/) || firstLine.match(/"([^"]+)"/);
|
|
31819
|
+
const title = titleMatch ? titleMatch[1] : paperSlug;
|
|
31820
|
+
return `
|
|
31821
|
+
---
|
|
31822
|
+
### [${title}](#wiki:${paperSlug})
|
|
31823
|
+
${body.trim()}
|
|
31824
|
+
`;
|
|
31825
|
+
}
|
|
31826
|
+
).replace(/<!--[\s\S]*?-->/g, "").replace(
|
|
31827
|
+
/\[\[([^\]]+)\]\]/g,
|
|
31828
|
+
(_match, innerSlug) => `[${innerSlug}](#wiki:${innerSlug})`
|
|
31829
|
+
);
|
|
31830
|
+
}, [content2]);
|
|
31831
|
+
const handleLinkClick = reactExports.useCallback((e) => {
|
|
31832
|
+
const target = e.target;
|
|
31833
|
+
const anchor = target.closest("a");
|
|
31834
|
+
if (!anchor) return;
|
|
31835
|
+
const href = anchor.getAttribute("href");
|
|
31836
|
+
if (href?.startsWith("#wiki:")) {
|
|
31837
|
+
e.preventDefault();
|
|
31838
|
+
setSlug(href.replace("#wiki:", ""));
|
|
31839
|
+
}
|
|
31840
|
+
}, [setSlug]);
|
|
31841
|
+
if (!slug) {
|
|
31842
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-center justify-center h-full text-center px-6", children: [
|
|
31843
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(BookOpen, { size: 28, className: "t-text-muted mb-2.5 opacity-30" }),
|
|
31844
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs t-text-muted", children: "Select a paper or concept to view details." })
|
|
31845
|
+
] });
|
|
31846
|
+
}
|
|
31847
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col h-full min-h-0", children: [
|
|
31848
|
+
/* @__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: [
|
|
31849
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
31850
|
+
"button",
|
|
31851
|
+
{
|
|
31852
|
+
onClick: goBack,
|
|
31853
|
+
disabled: history.length === 0,
|
|
31854
|
+
className: "p-1 rounded t-text-muted hover:t-text transition-colors disabled:opacity-30",
|
|
31855
|
+
title: "Back",
|
|
31856
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(ArrowLeft, { size: 14 })
|
|
31857
|
+
}
|
|
31858
|
+
),
|
|
31859
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 text-[11px] t-text-muted truncate font-mono", children: isPaperFallback ? fallbackPaper?.title || slug : slug }),
|
|
31860
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
31861
|
+
"button",
|
|
31862
|
+
{
|
|
31863
|
+
onClick: () => setSlug(null),
|
|
31864
|
+
className: "p-1 rounded t-text-muted hover:t-text transition-colors",
|
|
31865
|
+
title: "Close",
|
|
31866
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(X$1, { size: 13 })
|
|
31867
|
+
}
|
|
31868
|
+
)
|
|
31869
|
+
] }),
|
|
31870
|
+
/* @__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." }) })
|
|
30923
31871
|
] });
|
|
30924
31872
|
}
|
|
31873
|
+
function normalize(raw) {
|
|
31874
|
+
return raw.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, " ").trim();
|
|
31875
|
+
}
|
|
31876
|
+
function splitWords(s15) {
|
|
31877
|
+
const out = [];
|
|
31878
|
+
for (const w2 of s15.split(" ")) if (w2) out.push(w2);
|
|
31879
|
+
return out;
|
|
31880
|
+
}
|
|
31881
|
+
function firstAndLastWords(s15) {
|
|
31882
|
+
const words = splitWords(s15);
|
|
31883
|
+
if (words.length === 0) return [];
|
|
31884
|
+
if (words.length === 1) return [words[0]];
|
|
31885
|
+
return words[0] === words[words.length - 1] ? [words[0]] : [words[0], words[words.length - 1]];
|
|
31886
|
+
}
|
|
31887
|
+
function makeSearchable(p) {
|
|
31888
|
+
const normTitle = normalize(p.title || "");
|
|
31889
|
+
const titleWords = splitWords(normTitle);
|
|
31890
|
+
const normAuthors = (p.authors || []).map((a) => normalize(a)).filter(Boolean);
|
|
31891
|
+
const prefixTokens = /* @__PURE__ */ new Set();
|
|
31892
|
+
for (const a of normAuthors) for (const t of firstAndLastWords(a)) prefixTokens.add(t);
|
|
31893
|
+
return {
|
|
31894
|
+
normTitle,
|
|
31895
|
+
titleWords,
|
|
31896
|
+
titleWordSet: new Set(titleWords),
|
|
31897
|
+
normAuthors,
|
|
31898
|
+
authorPrefixTokens: Array.from(prefixTokens),
|
|
31899
|
+
normVenue: p.venue ? normalize(p.venue) : void 0,
|
|
31900
|
+
normTldr: p.tldr ? normalize(p.tldr) : void 0,
|
|
31901
|
+
normAbstract: p.abstract ? normalize(p.abstract) : void 0
|
|
31902
|
+
};
|
|
31903
|
+
}
|
|
31904
|
+
function tokenizeQuery(query) {
|
|
31905
|
+
const seen2 = /* @__PURE__ */ new Set();
|
|
31906
|
+
const out = [];
|
|
31907
|
+
for (const w2 of normalize(query).split(" ")) {
|
|
31908
|
+
if (w2.length < 2) continue;
|
|
31909
|
+
if (seen2.has(w2)) continue;
|
|
31910
|
+
seen2.add(w2);
|
|
31911
|
+
out.push(w2);
|
|
31912
|
+
}
|
|
31913
|
+
return out;
|
|
31914
|
+
}
|
|
31915
|
+
function isSubsequence(needle, hay) {
|
|
31916
|
+
if (needle.length === 0) return true;
|
|
31917
|
+
if (needle.length > hay.length) return false;
|
|
31918
|
+
let i = 0;
|
|
31919
|
+
for (let j2 = 0; j2 < hay.length && i < needle.length; j2++) {
|
|
31920
|
+
if (hay.charCodeAt(j2) === needle.charCodeAt(i)) i++;
|
|
31921
|
+
}
|
|
31922
|
+
return i === needle.length;
|
|
31923
|
+
}
|
|
31924
|
+
function scoreToken(token, p) {
|
|
31925
|
+
let best = 0;
|
|
31926
|
+
if (p.titleWordSet.has(token)) {
|
|
31927
|
+
best = Math.max(best, 20);
|
|
31928
|
+
} else if (p.normTitle.includes(token)) {
|
|
31929
|
+
best = Math.max(best, 10);
|
|
31930
|
+
} else if (token.length >= 4) {
|
|
31931
|
+
for (const word of p.titleWords) {
|
|
31932
|
+
if (word.length >= token.length && isSubsequence(token, word)) {
|
|
31933
|
+
best = Math.max(best, 4);
|
|
31934
|
+
break;
|
|
31935
|
+
}
|
|
31936
|
+
}
|
|
31937
|
+
}
|
|
31938
|
+
for (const pref of p.authorPrefixTokens) {
|
|
31939
|
+
if (pref.startsWith(token)) {
|
|
31940
|
+
best = Math.max(best, 10);
|
|
31941
|
+
break;
|
|
31942
|
+
}
|
|
31943
|
+
}
|
|
31944
|
+
if (best < 8) {
|
|
31945
|
+
for (const full of p.normAuthors) {
|
|
31946
|
+
if (full.includes(token)) {
|
|
31947
|
+
best = Math.max(best, 8);
|
|
31948
|
+
break;
|
|
31949
|
+
}
|
|
31950
|
+
}
|
|
31951
|
+
}
|
|
31952
|
+
if (p.normVenue && p.normVenue.includes(token)) best = Math.max(best, 3);
|
|
31953
|
+
if (p.normTldr && p.normTldr.includes(token)) best = Math.max(best, 3);
|
|
31954
|
+
if (p.normAbstract && p.normAbstract.includes(token)) best = Math.max(best, 2);
|
|
31955
|
+
return best;
|
|
31956
|
+
}
|
|
31957
|
+
function scorePaper(tokens, p) {
|
|
31958
|
+
if (tokens.length === 0) return 0;
|
|
31959
|
+
let total = 0;
|
|
31960
|
+
let hits = 0;
|
|
31961
|
+
for (const t of tokens) {
|
|
31962
|
+
const s15 = scoreToken(t, p);
|
|
31963
|
+
if (s15 > 0) {
|
|
31964
|
+
hits++;
|
|
31965
|
+
total += s15;
|
|
31966
|
+
}
|
|
31967
|
+
}
|
|
31968
|
+
const required = tokens.length <= 3 ? tokens.length : Math.ceil(0.7 * tokens.length);
|
|
31969
|
+
if (hits < required) return null;
|
|
31970
|
+
return total;
|
|
31971
|
+
}
|
|
31972
|
+
const api$3 = window.api;
|
|
30925
31973
|
function ScoreBadge({ score }) {
|
|
30926
31974
|
if (score == null) return null;
|
|
30927
31975
|
const color2 = score >= 8 ? "text-emerald-500" : score >= 6 ? "text-amber-500" : "t-text-muted";
|
|
@@ -30955,36 +32003,49 @@ function PaperRow({
|
|
|
30955
32003
|
paper,
|
|
30956
32004
|
expanded,
|
|
30957
32005
|
onToggle,
|
|
30958
|
-
|
|
32006
|
+
wikiSlug,
|
|
32007
|
+
isActive,
|
|
32008
|
+
source = "project"
|
|
30959
32009
|
}) {
|
|
32010
|
+
const setWikiSlug = useUIStore((s15) => s15.setWikiReaderSlug);
|
|
30960
32011
|
const authors = paper.authors || [];
|
|
30961
32012
|
const authorStr = authors.length <= 3 ? authors.join(", ") : `${authors.slice(0, 2).join(", ")} et al.`;
|
|
30962
32013
|
const keyFindings = paper.keyFindings || [];
|
|
30963
|
-
|
|
32014
|
+
const isWiki = source === "wiki";
|
|
32015
|
+
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: [
|
|
30964
32016
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
30965
32017
|
"div",
|
|
30966
32018
|
{
|
|
30967
|
-
className:
|
|
32019
|
+
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"}`,
|
|
30968
32020
|
onClick: onToggle,
|
|
30969
32021
|
children: [
|
|
30970
32022
|
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "shrink-0 t-text-muted", children: expanded ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { size: 14 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { size: 14 }) }),
|
|
30971
32023
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
30972
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
32024
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5 min-w-0", children: [
|
|
32025
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[13px] t-text font-medium truncate leading-tight", children: paper.title }),
|
|
32026
|
+
isWiki && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
32027
|
+
"span",
|
|
32028
|
+
{
|
|
32029
|
+
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",
|
|
32030
|
+
title: "From paper wiki — not in this project",
|
|
32031
|
+
children: "Wiki"
|
|
32032
|
+
}
|
|
32033
|
+
)
|
|
32034
|
+
] }),
|
|
30973
32035
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] t-text-muted truncate mt-0.5", children: authorStr })
|
|
30974
32036
|
] }),
|
|
30975
32037
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0 text-[11px] t-text-muted tabular-nums w-10 text-right", children: paper.year || "—" }),
|
|
30976
32038
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "shrink-0 w-10 text-right", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ScoreBadge, { score: paper.relevanceScore }) }),
|
|
30977
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0 text-[11px] t-text-muted tabular-nums w-12 text-right", children: paper.citationCount != null ? paper.citationCount : "—" }),
|
|
30978
32039
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
30979
32040
|
"button",
|
|
30980
32041
|
{
|
|
30981
32042
|
onClick: (e) => {
|
|
30982
32043
|
e.stopPropagation();
|
|
30983
|
-
|
|
32044
|
+
setWikiSlug(wikiSlug || `paper:${paper.id}`);
|
|
30984
32045
|
},
|
|
30985
|
-
className:
|
|
30986
|
-
title: "
|
|
30987
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx(BookOpen, { size:
|
|
32046
|
+
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"}`,
|
|
32047
|
+
title: wikiSlug ? "View wiki page" : "View paper details",
|
|
32048
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(BookOpen, { size: 13 })
|
|
30988
32049
|
}
|
|
30989
32050
|
)
|
|
30990
32051
|
]
|
|
@@ -30994,8 +32055,6 @@ function PaperRow({
|
|
|
30994
32055
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap gap-1.5", children: [
|
|
30995
32056
|
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 }),
|
|
30996
32057
|
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 }),
|
|
30997
|
-
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 }),
|
|
30998
|
-
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 }),
|
|
30999
32058
|
paper.doi && !paper.doi.startsWith("unknown:") && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
31000
32059
|
"a",
|
|
31001
32060
|
{
|
|
@@ -31040,6 +32099,46 @@ function PaperRow({
|
|
|
31040
32099
|
] })
|
|
31041
32100
|
] });
|
|
31042
32101
|
}
|
|
32102
|
+
function WikiStatusPill() {
|
|
32103
|
+
const [status, setStatus] = reactExports.useState(null);
|
|
32104
|
+
reactExports.useEffect(() => {
|
|
32105
|
+
let cancelled = false;
|
|
32106
|
+
api$3.wikiGetStatus?.().then((s15) => {
|
|
32107
|
+
if (!cancelled) setStatus(s15);
|
|
32108
|
+
}).catch(() => {
|
|
32109
|
+
});
|
|
32110
|
+
const unsub = api$3.onWikiStatus?.((s15) => setStatus(s15));
|
|
32111
|
+
return () => {
|
|
32112
|
+
cancelled = true;
|
|
32113
|
+
unsub?.();
|
|
32114
|
+
};
|
|
32115
|
+
}, []);
|
|
32116
|
+
if (!status || status.state === "disabled") return null;
|
|
32117
|
+
const isProcessing = status.state === "processing";
|
|
32118
|
+
const isPaused = status.state === "paused";
|
|
32119
|
+
const totalInBatch = status.processed + status.pending;
|
|
32120
|
+
const pct = totalInBatch > 0 ? Math.round(status.processed / totalInBatch * 100) : 0;
|
|
32121
|
+
const dotClass = isProcessing ? "bg-blue-500 animate-pulse" : isPaused ? "bg-yellow-500" : "bg-emerald-500";
|
|
32122
|
+
const label = isProcessing ? `Wiki · processing${totalInBatch > 0 ? ` ${status.processed}/${totalInBatch}` : ""}` : isPaused ? "Wiki · paused" : `Wiki · idle${status.totalInWiki > 0 ? ` · ${status.totalInWiki} pages` : ""}`;
|
|
32123
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
32124
|
+
"div",
|
|
32125
|
+
{
|
|
32126
|
+
className: "ml-auto flex items-center gap-2 shrink-0",
|
|
32127
|
+
title: status.lastRunAt ? `Last tick: ${new Date(status.lastRunAt).toLocaleString()}` : void 0,
|
|
32128
|
+
children: [
|
|
32129
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `inline-block w-1.5 h-1.5 rounded-full ${dotClass}` }),
|
|
32130
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-muted tabular-nums", children: label }),
|
|
32131
|
+
isProcessing && totalInBatch > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-16 h-1 rounded-full t-bg-elevated overflow-hidden", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
32132
|
+
"div",
|
|
32133
|
+
{
|
|
32134
|
+
className: "h-full bg-blue-500 transition-[width] duration-500 ease-out",
|
|
32135
|
+
style: { width: `${pct}%` }
|
|
32136
|
+
}
|
|
32137
|
+
) })
|
|
32138
|
+
]
|
|
32139
|
+
}
|
|
32140
|
+
);
|
|
32141
|
+
}
|
|
31043
32142
|
function CoverageBar$1({ papers }) {
|
|
31044
32143
|
const topicCounts = reactExports.useMemo(() => {
|
|
31045
32144
|
const counts = /* @__PURE__ */ new Map();
|
|
@@ -31069,7 +32168,7 @@ function CoverageBar$1({ papers }) {
|
|
|
31069
32168
|
highRelevance,
|
|
31070
32169
|
" highly relevant"
|
|
31071
32170
|
] }),
|
|
31072
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "
|
|
32171
|
+
/* @__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(
|
|
31073
32172
|
"div",
|
|
31074
32173
|
{
|
|
31075
32174
|
className: "h-full rounded-full t-gradient-accent-h",
|
|
@@ -31077,10 +32176,11 @@ function CoverageBar$1({ papers }) {
|
|
|
31077
32176
|
width: `${Math.min(100, highRelevance / Math.max(papers.length, 1) * 100)}%`
|
|
31078
32177
|
}
|
|
31079
32178
|
}
|
|
31080
|
-
) }) })
|
|
32179
|
+
) }) }),
|
|
32180
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(WikiStatusPill, {})
|
|
31081
32181
|
] });
|
|
31082
32182
|
}
|
|
31083
|
-
function FilterBar$1() {
|
|
32183
|
+
function FilterBar$1({ topics }) {
|
|
31084
32184
|
const filter = useUIStore((s15) => s15.literatureFilter);
|
|
31085
32185
|
const setFilter = useUIStore((s15) => s15.setLiteratureFilter);
|
|
31086
32186
|
const [showFilters, setShowFilters] = reactExports.useState(false);
|
|
@@ -31095,7 +32195,7 @@ function FilterBar$1() {
|
|
|
31095
32195
|
type: "text",
|
|
31096
32196
|
value: filter.search,
|
|
31097
32197
|
onChange: (e) => setFilter({ search: e.target.value }),
|
|
31098
|
-
placeholder: "Search papers
|
|
32198
|
+
placeholder: "Search papers...",
|
|
31099
32199
|
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)]"
|
|
31100
32200
|
}
|
|
31101
32201
|
),
|
|
@@ -31108,6 +32208,18 @@ function FilterBar$1() {
|
|
|
31108
32208
|
}
|
|
31109
32209
|
)
|
|
31110
32210
|
] }),
|
|
32211
|
+
topics.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
32212
|
+
"select",
|
|
32213
|
+
{
|
|
32214
|
+
value: filter.subTopic || "",
|
|
32215
|
+
onChange: (e) => setFilter({ subTopic: e.target.value || null }),
|
|
32216
|
+
className: "px-2 py-1.5 text-xs rounded-lg border t-border t-bg-surface t-text max-w-40",
|
|
32217
|
+
children: [
|
|
32218
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "", children: "All topics" }),
|
|
32219
|
+
topics.map((t) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: t, children: t }, t))
|
|
32220
|
+
]
|
|
32221
|
+
}
|
|
32222
|
+
),
|
|
31111
32223
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
31112
32224
|
"button",
|
|
31113
32225
|
{
|
|
@@ -31115,7 +32227,6 @@ function FilterBar$1() {
|
|
|
31115
32227
|
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"}`,
|
|
31116
32228
|
children: [
|
|
31117
32229
|
/* @__PURE__ */ jsxRuntimeExports.jsx(Filter, { size: 12 }),
|
|
31118
|
-
"Filters",
|
|
31119
32230
|
hasActiveFilters && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-1.5 h-1.5 rounded-full bg-[var(--color-accent-soft)]" })
|
|
31120
32231
|
]
|
|
31121
32232
|
}
|
|
@@ -31147,12 +32258,47 @@ function FilterBar$1() {
|
|
|
31147
32258
|
] })
|
|
31148
32259
|
] });
|
|
31149
32260
|
}
|
|
32261
|
+
function wikiMetaToEntityItem(meta) {
|
|
32262
|
+
return {
|
|
32263
|
+
id: `wiki:${meta.slug}`,
|
|
32264
|
+
type: "paper",
|
|
32265
|
+
title: meta.title,
|
|
32266
|
+
authors: meta.authors,
|
|
32267
|
+
year: meta.year,
|
|
32268
|
+
venue: meta.venue,
|
|
32269
|
+
abstract: meta.tldr
|
|
32270
|
+
// show tldr as abstract preview for wiki rows
|
|
32271
|
+
};
|
|
32272
|
+
}
|
|
31150
32273
|
function LiteratureView() {
|
|
31151
32274
|
const papers = useEntityStore((s15) => s15.papers);
|
|
31152
32275
|
const filter = useUIStore((s15) => s15.literatureFilter);
|
|
31153
32276
|
const setFilter = useUIStore((s15) => s15.setLiteratureFilter);
|
|
31154
|
-
const
|
|
31155
|
-
const
|
|
32277
|
+
const wikiReaderSlug = useUIStore((s15) => s15.wikiReaderSlug);
|
|
32278
|
+
const setWikiSlug = useUIStore((s15) => s15.setWikiReaderSlug);
|
|
32279
|
+
const [expandedKey, setExpandedKey] = reactExports.useState(null);
|
|
32280
|
+
const [wikiSlugs, setWikiSlugs] = reactExports.useState({});
|
|
32281
|
+
const [wikiMeta, setWikiMeta] = reactExports.useState([]);
|
|
32282
|
+
reactExports.useEffect(() => {
|
|
32283
|
+
let cancelled = false;
|
|
32284
|
+
api$3.wikiPaperSlugMap?.().then((map2) => {
|
|
32285
|
+
if (!cancelled && map2) setWikiSlugs(map2);
|
|
32286
|
+
}).catch(() => {
|
|
32287
|
+
});
|
|
32288
|
+
return () => {
|
|
32289
|
+
cancelled = true;
|
|
32290
|
+
};
|
|
32291
|
+
}, [papers]);
|
|
32292
|
+
reactExports.useEffect(() => {
|
|
32293
|
+
let cancelled = false;
|
|
32294
|
+
api$3.wikiListPaperMeta?.().then((list2) => {
|
|
32295
|
+
if (!cancelled && Array.isArray(list2)) setWikiMeta(list2);
|
|
32296
|
+
}).catch(() => {
|
|
32297
|
+
});
|
|
32298
|
+
return () => {
|
|
32299
|
+
cancelled = true;
|
|
32300
|
+
};
|
|
32301
|
+
}, []);
|
|
31156
32302
|
const handleSort = reactExports.useCallback(
|
|
31157
32303
|
(key) => {
|
|
31158
32304
|
if (filter.sortBy === key) {
|
|
@@ -31163,73 +32309,121 @@ function LiteratureView() {
|
|
|
31163
32309
|
},
|
|
31164
32310
|
[filter.sortBy, filter.sortDir, setFilter]
|
|
31165
32311
|
);
|
|
31166
|
-
const
|
|
31167
|
-
|
|
31168
|
-
|
|
31169
|
-
const
|
|
31170
|
-
|
|
31171
|
-
const title = (p.title || "").toLowerCase();
|
|
31172
|
-
const abstract = (p.abstract || "").toLowerCase();
|
|
31173
|
-
const authors = (p.authors || []).join(" ").toLowerCase();
|
|
31174
|
-
return title.includes(q2) || abstract.includes(q2) || authors.includes(q2);
|
|
31175
|
-
});
|
|
31176
|
-
}
|
|
31177
|
-
if (filter.subTopic) {
|
|
31178
|
-
result = result.filter(
|
|
31179
|
-
(p) => (p.subTopic || "Uncategorized") === filter.subTopic
|
|
31180
|
-
);
|
|
31181
|
-
}
|
|
31182
|
-
if (filter.minScore > 0) {
|
|
31183
|
-
result = result.filter((p) => (p.relevanceScore || 0) >= filter.minScore);
|
|
32312
|
+
const topics = reactExports.useMemo(() => {
|
|
32313
|
+
const counts = /* @__PURE__ */ new Map();
|
|
32314
|
+
for (const p of papers) {
|
|
32315
|
+
const topic = p.subTopic;
|
|
32316
|
+
if (topic) counts.set(topic, (counts.get(topic) || 0) + 1);
|
|
31184
32317
|
}
|
|
31185
|
-
|
|
31186
|
-
|
|
32318
|
+
return Array.from(counts.entries()).sort((a, b2) => b2[1] - a[1]).map(([t]) => t);
|
|
32319
|
+
}, [papers]);
|
|
32320
|
+
const projectRows = reactExports.useMemo(() => {
|
|
32321
|
+
return papers.map((p) => ({
|
|
32322
|
+
key: `project:${p.id}`,
|
|
32323
|
+
source: "project",
|
|
32324
|
+
paper: p,
|
|
32325
|
+
wikiSlug: wikiSlugs[p.id],
|
|
32326
|
+
searchable: makeSearchable({
|
|
32327
|
+
title: p.title || "",
|
|
32328
|
+
authors: p.authors || [],
|
|
32329
|
+
venue: p.venue,
|
|
32330
|
+
tldr: void 0,
|
|
32331
|
+
abstract: p.abstract
|
|
32332
|
+
})
|
|
32333
|
+
}));
|
|
32334
|
+
}, [papers, wikiSlugs]);
|
|
32335
|
+
const wikiOnlyRows = reactExports.useMemo(() => {
|
|
32336
|
+
const usedSlugs = new Set(Object.values(wikiSlugs));
|
|
32337
|
+
return wikiMeta.filter((m) => !usedSlugs.has(m.slug)).map((m) => ({
|
|
32338
|
+
key: `wiki:${m.slug}`,
|
|
32339
|
+
source: "wiki",
|
|
32340
|
+
paper: wikiMetaToEntityItem(m),
|
|
32341
|
+
wikiSlug: m.slug,
|
|
32342
|
+
searchable: makeSearchable({
|
|
32343
|
+
title: m.title,
|
|
32344
|
+
authors: m.authors,
|
|
32345
|
+
venue: m.venue,
|
|
32346
|
+
tldr: m.tldr
|
|
32347
|
+
})
|
|
32348
|
+
}));
|
|
32349
|
+
}, [wikiMeta, papers, wikiSlugs]);
|
|
32350
|
+
const filteredRows = reactExports.useMemo(() => {
|
|
32351
|
+
const query = filter.search.trim();
|
|
32352
|
+
const tokens = query ? tokenizeQuery(query) : [];
|
|
32353
|
+
const searching = tokens.length > 0;
|
|
32354
|
+
const passesProjectFilters = (p) => {
|
|
32355
|
+
if (filter.subTopic && (p.subTopic || "Uncategorized") !== filter.subTopic) return false;
|
|
32356
|
+
if (filter.minScore > 0 && (p.relevanceScore || 0) < filter.minScore) return false;
|
|
32357
|
+
if (filter.source && p.externalSource !== filter.source) return false;
|
|
32358
|
+
if (filter.round && p.addedInRound !== filter.round) return false;
|
|
32359
|
+
return true;
|
|
32360
|
+
};
|
|
32361
|
+
const scored = [];
|
|
32362
|
+
for (const row of projectRows) {
|
|
32363
|
+
if (!passesProjectFilters(row.paper)) continue;
|
|
32364
|
+
if (searching) {
|
|
32365
|
+
const s15 = scorePaper(tokens, row.searchable);
|
|
32366
|
+
if (s15 == null) continue;
|
|
32367
|
+
scored.push({ row, score: s15 });
|
|
32368
|
+
} else {
|
|
32369
|
+
scored.push({ row, score: 0 });
|
|
32370
|
+
}
|
|
31187
32371
|
}
|
|
31188
|
-
if (
|
|
31189
|
-
|
|
32372
|
+
if (searching) {
|
|
32373
|
+
for (const row of wikiOnlyRows) {
|
|
32374
|
+
const s15 = scorePaper(tokens, row.searchable);
|
|
32375
|
+
if (s15 == null) continue;
|
|
32376
|
+
scored.push({ row, score: s15 });
|
|
32377
|
+
}
|
|
31190
32378
|
}
|
|
31191
|
-
|
|
31192
|
-
|
|
32379
|
+
const dir = filter.sortDir === "desc" ? -1 : 1;
|
|
32380
|
+
const compareSortKey = (a, b2) => {
|
|
31193
32381
|
switch (filter.sortBy) {
|
|
31194
|
-
case "year":
|
|
31195
|
-
|
|
31196
|
-
|
|
31197
|
-
return (
|
|
31198
|
-
|
|
31199
|
-
|
|
31200
|
-
const as2 = a.relevanceScore || 0;
|
|
31201
|
-
const bs2 = b2.relevanceScore || 0;
|
|
31202
|
-
return (as2 - bs2) * dir;
|
|
31203
|
-
}
|
|
31204
|
-
case "citations": {
|
|
31205
|
-
const ac2 = a.citationCount || 0;
|
|
31206
|
-
const bc2 = b2.citationCount || 0;
|
|
31207
|
-
return (ac2 - bc2) * dir;
|
|
31208
|
-
}
|
|
32382
|
+
case "year":
|
|
32383
|
+
return ((a.year || 0) - (b2.year || 0)) * dir;
|
|
32384
|
+
case "relevance":
|
|
32385
|
+
return ((a.relevanceScore || 0) - (b2.relevanceScore || 0)) * dir;
|
|
32386
|
+
case "citations":
|
|
32387
|
+
return ((a.citationCount || 0) - (b2.citationCount || 0)) * dir;
|
|
31209
32388
|
case "title":
|
|
31210
32389
|
return a.title.localeCompare(b2.title) * dir;
|
|
31211
32390
|
default:
|
|
31212
32391
|
return 0;
|
|
31213
32392
|
}
|
|
32393
|
+
};
|
|
32394
|
+
scored.sort((a, b2) => {
|
|
32395
|
+
if (searching) {
|
|
32396
|
+
if (a.score !== b2.score) return b2.score - a.score;
|
|
32397
|
+
}
|
|
32398
|
+
return compareSortKey(a.row.paper, b2.row.paper);
|
|
31214
32399
|
});
|
|
31215
|
-
return
|
|
31216
|
-
}, [
|
|
31217
|
-
|
|
32400
|
+
return scored.map((s15) => s15.row);
|
|
32401
|
+
}, [projectRows, wikiOnlyRows, filter]);
|
|
32402
|
+
reactExports.useEffect(() => {
|
|
32403
|
+
if (wikiReaderSlug || filteredRows.length === 0) return;
|
|
32404
|
+
const first = filteredRows[0];
|
|
32405
|
+
if (first.source === "wiki") {
|
|
32406
|
+
setWikiSlug(first.wikiSlug);
|
|
32407
|
+
} else {
|
|
32408
|
+
setWikiSlug(first.wikiSlug || `paper:${first.paper.id}`);
|
|
32409
|
+
}
|
|
32410
|
+
}, [filteredRows, wikiReaderSlug, setWikiSlug]);
|
|
32411
|
+
const activeRowKey = reactExports.useMemo(() => {
|
|
32412
|
+
if (!wikiReaderSlug) return null;
|
|
32413
|
+
if (wikiReaderSlug.startsWith("paper:")) {
|
|
32414
|
+
return `project:${wikiReaderSlug.slice("paper:".length)}`;
|
|
32415
|
+
}
|
|
32416
|
+
for (const [paperId, slug] of Object.entries(wikiSlugs)) {
|
|
32417
|
+
if (slug === wikiReaderSlug) return `project:${paperId}`;
|
|
32418
|
+
}
|
|
32419
|
+
return `wiki:${wikiReaderSlug}`;
|
|
32420
|
+
}, [wikiReaderSlug, wikiSlugs]);
|
|
31218
32421
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex flex-col min-h-0", children: [
|
|
31219
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(FilterBar$1, {}),
|
|
32422
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(FilterBar$1, { topics }),
|
|
31220
32423
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex min-h-0", children: [
|
|
31221
|
-
|
|
31222
|
-
TopicTree,
|
|
31223
|
-
{
|
|
31224
|
-
papers,
|
|
31225
|
-
selectedTopic: filter.subTopic,
|
|
31226
|
-
onSelect: (topic) => setFilter({ subTopic: topic })
|
|
31227
|
-
}
|
|
31228
|
-
),
|
|
31229
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex flex-col min-w-0", children: [
|
|
32424
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-1/2 flex flex-col min-w-0 border-r t-border", children: [
|
|
31230
32425
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 px-3 py-1.5 border-b t-border t-bg-surface", children: [
|
|
31231
32426
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-5" }),
|
|
31232
|
-
" ",
|
|
31233
32427
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
31234
32428
|
SortHeader,
|
|
31235
32429
|
{
|
|
@@ -31262,36 +32456,34 @@ function LiteratureView() {
|
|
|
31262
32456
|
className: "w-10 justify-end"
|
|
31263
32457
|
}
|
|
31264
32458
|
),
|
|
31265
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
31266
|
-
SortHeader,
|
|
31267
|
-
{
|
|
31268
|
-
label: "Cites",
|
|
31269
|
-
sortKey: "citations",
|
|
31270
|
-
currentSort: filter.sortBy,
|
|
31271
|
-
currentDir: filter.sortDir,
|
|
31272
|
-
onSort: handleSort,
|
|
31273
|
-
className: "w-12 justify-end"
|
|
31274
|
-
}
|
|
31275
|
-
),
|
|
31276
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-8" }),
|
|
31277
|
-
" "
|
|
32459
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-8" })
|
|
31278
32460
|
] }),
|
|
31279
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 overflow-y-auto", children:
|
|
32461
|
+
/* @__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: [
|
|
31280
32462
|
/* @__PURE__ */ jsxRuntimeExports.jsx(BookOpen, { size: 32, className: "t-text-muted mb-3 opacity-40" }),
|
|
31281
32463
|
/* @__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." })
|
|
31282
|
-
] }) :
|
|
32464
|
+
] }) : filteredRows.map((row) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
31283
32465
|
PaperRow,
|
|
31284
32466
|
{
|
|
31285
|
-
paper,
|
|
31286
|
-
|
|
31287
|
-
|
|
31288
|
-
|
|
32467
|
+
paper: row.paper,
|
|
32468
|
+
source: row.source,
|
|
32469
|
+
expanded: expandedKey === row.key,
|
|
32470
|
+
isActive: activeRowKey === row.key,
|
|
32471
|
+
onToggle: () => {
|
|
32472
|
+
setExpandedKey(expandedKey === row.key ? null : row.key);
|
|
32473
|
+
if (row.source === "wiki") {
|
|
32474
|
+
setWikiSlug(row.wikiSlug);
|
|
32475
|
+
} else {
|
|
32476
|
+
setWikiSlug(row.wikiSlug || `paper:${row.paper.id}`);
|
|
32477
|
+
}
|
|
32478
|
+
},
|
|
32479
|
+
wikiSlug: row.wikiSlug
|
|
31289
32480
|
},
|
|
31290
|
-
|
|
32481
|
+
row.key
|
|
31291
32482
|
)) })
|
|
31292
|
-
] })
|
|
32483
|
+
] }),
|
|
32484
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-1/2 min-w-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(WikiReaderPanel, {}) })
|
|
31293
32485
|
] }),
|
|
31294
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(CoverageBar$1, { papers:
|
|
32486
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(CoverageBar$1, { papers: filteredRows.filter((r) => r.source === "project").map((r) => r.paper) })
|
|
31295
32487
|
] });
|
|
31296
32488
|
}
|
|
31297
32489
|
function formatDuration(seconds) {
|
|
@@ -31368,7 +32560,16 @@ function RunRow({
|
|
|
31368
32560
|
className: "flex items-center gap-3 px-3 py-2 hover:bg-[var(--color-accent-soft)]/5 transition-colors cursor-pointer",
|
|
31369
32561
|
onClick: onToggle,
|
|
31370
32562
|
children: [
|
|
31371
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
32563
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
32564
|
+
"button",
|
|
32565
|
+
{
|
|
32566
|
+
type: "button",
|
|
32567
|
+
"aria-label": expanded ? "Collapse run details" : "Expand run details",
|
|
32568
|
+
"aria-expanded": expanded,
|
|
32569
|
+
className: "shrink-0 t-text-muted",
|
|
32570
|
+
children: expanded ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { size: 14 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { size: 14 })
|
|
32571
|
+
}
|
|
32572
|
+
),
|
|
31372
32573
|
/* @__PURE__ */ jsxRuntimeExports.jsx(StatusDot, { status: run.status }),
|
|
31373
32574
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
31374
32575
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[13px] t-text font-medium truncate leading-tight font-mono", children: run.command }),
|
|
@@ -31501,7 +32702,9 @@ function FilterBar({
|
|
|
31501
32702
|
search2 && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
31502
32703
|
"button",
|
|
31503
32704
|
{
|
|
32705
|
+
type: "button",
|
|
31504
32706
|
onClick: () => onSearchChange(""),
|
|
32707
|
+
"aria-label": "Clear search",
|
|
31505
32708
|
className: "absolute right-2 top-1/2 -translate-y-1/2 t-text-muted hover:t-text",
|
|
31506
32709
|
children: /* @__PURE__ */ jsxRuntimeExports.jsx(X$1, { size: 12 })
|
|
31507
32710
|
}
|
|
@@ -31644,22 +32847,56 @@ function ViewSwitcher() {
|
|
|
31644
32847
|
const setCenterView = useUIStore((s15) => s15.setCenterView);
|
|
31645
32848
|
const paperCount = useEntityStore((s15) => s15.papers.length);
|
|
31646
32849
|
const activeComputeRuns = useActiveRunCount();
|
|
31647
|
-
return
|
|
31648
|
-
|
|
31649
|
-
|
|
31650
|
-
|
|
31651
|
-
|
|
31652
|
-
|
|
31653
|
-
|
|
31654
|
-
|
|
31655
|
-
label,
|
|
31656
|
-
|
|
31657
|
-
|
|
31658
|
-
|
|
31659
|
-
|
|
31660
|
-
|
|
31661
|
-
|
|
31662
|
-
|
|
32850
|
+
return (
|
|
32851
|
+
// Bottom hairline gives the nav a real anchor — without it, the tabs
|
|
32852
|
+
// float in a gray area between the drag region and the content.
|
|
32853
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
32854
|
+
"nav",
|
|
32855
|
+
{
|
|
32856
|
+
"aria-label": "View switcher",
|
|
32857
|
+
className: "flex items-stretch gap-1 px-4 pt-10 border-b t-border",
|
|
32858
|
+
children: viewTabs.map(({ key, label, icon: Icon2, shortcut }) => {
|
|
32859
|
+
const isActive = centerView === key;
|
|
32860
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
32861
|
+
"button",
|
|
32862
|
+
{
|
|
32863
|
+
onClick: () => setCenterView(key),
|
|
32864
|
+
"aria-current": isActive ? "page" : void 0,
|
|
32865
|
+
title: `${label} (${shortcut})`,
|
|
32866
|
+
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"}`,
|
|
32867
|
+
children: [
|
|
32868
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Icon2, { size: 14, className: isActive ? "t-text-accent" : "" }),
|
|
32869
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: label }),
|
|
32870
|
+
key === "literature" && paperCount > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
32871
|
+
"span",
|
|
32872
|
+
{
|
|
32873
|
+
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"}`,
|
|
32874
|
+
children: paperCount
|
|
32875
|
+
}
|
|
32876
|
+
),
|
|
32877
|
+
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 }),
|
|
32878
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
32879
|
+
"kbd",
|
|
32880
|
+
{
|
|
32881
|
+
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"}`,
|
|
32882
|
+
children: shortcut
|
|
32883
|
+
}
|
|
32884
|
+
),
|
|
32885
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
32886
|
+
"span",
|
|
32887
|
+
{
|
|
32888
|
+
"aria-hidden": true,
|
|
32889
|
+
className: `pointer-events-none absolute left-0 right-0 -bottom-px h-[2px] transition-colors ${isActive ? "t-bg-accent" : "bg-transparent"}`
|
|
32890
|
+
}
|
|
32891
|
+
)
|
|
32892
|
+
]
|
|
32893
|
+
},
|
|
32894
|
+
key
|
|
32895
|
+
);
|
|
32896
|
+
})
|
|
32897
|
+
}
|
|
32898
|
+
)
|
|
32899
|
+
);
|
|
31663
32900
|
}
|
|
31664
32901
|
function CenterPanel() {
|
|
31665
32902
|
const centerView = useUIStore((s15) => s15.centerView);
|
|
@@ -31680,13 +32917,13 @@ function CenterPanel() {
|
|
|
31680
32917
|
}
|
|
31681
32918
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("main", { id: "main-content", className: "flex-1 flex flex-col min-w-0", children: [
|
|
31682
32919
|
/* @__PURE__ */ jsxRuntimeExports.jsx(ViewSwitcher, {}),
|
|
31683
|
-
showHero ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntimeExports.jsx(HeroIdle, {}) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-h-0 px-6 pt-4 pb-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mx-auto h-full", style: { maxWidth: "
|
|
31684
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-6 pb-5", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mx-auto", style: { maxWidth: "
|
|
32920
|
+
showHero ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntimeExports.jsx(HeroIdle, {}) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-h-0 px-6 pt-4 pb-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mx-auto h-full", style: { maxWidth: "64rem" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChatMessages, {}) }) }),
|
|
32921
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-6 pb-5", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mx-auto", style: { maxWidth: "64rem" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChatInput, {}) }) })
|
|
31685
32922
|
] });
|
|
31686
32923
|
}
|
|
31687
32924
|
const remarkPlugins = [remarkGfm];
|
|
31688
32925
|
const LazyMilkdownMarkdownEditor = reactExports.lazy(async () => {
|
|
31689
|
-
const mod = await __vitePreload(() => import("./MilkdownMarkdownEditor-
|
|
32926
|
+
const mod = await __vitePreload(() => import("./MilkdownMarkdownEditor-CK0d0F6d.js").then((n) => n.bL), true ? __vite__mapDeps([0,1]) : void 0, import.meta.url);
|
|
31690
32927
|
return { default: mod.MilkdownMarkdownEditor };
|
|
31691
32928
|
});
|
|
31692
32929
|
const typeIcons = {
|
|
@@ -32312,14 +33549,21 @@ function StatusBar() {
|
|
|
32312
33549
|
const hasRunUsage = runTokens > 0;
|
|
32313
33550
|
const hasProjectUsage = allTimeTokens > 0;
|
|
32314
33551
|
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: [
|
|
32315
|
-
hasSkills && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center gap-2 overflow-hidden", children: activeSkills.map((name2) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
32316
|
-
|
|
32317
|
-
|
|
32318
|
-
|
|
32319
|
-
|
|
32320
|
-
|
|
33552
|
+
hasSkills && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center gap-2 overflow-hidden", children: activeSkills.map((name2) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
33553
|
+
"span",
|
|
33554
|
+
{
|
|
33555
|
+
className: "flex items-center gap-1.5 px-1.5 py-0.5 rounded t-bg-accent/10 t-text-accent whitespace-nowrap",
|
|
33556
|
+
children: [
|
|
33557
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(CircleDot, { size: 10, className: "shrink-0", "aria-hidden": true }),
|
|
33558
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: name2 })
|
|
33559
|
+
]
|
|
33560
|
+
},
|
|
33561
|
+
name2
|
|
33562
|
+
)) }),
|
|
33563
|
+
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: [
|
|
33564
|
+
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" }),
|
|
32321
33565
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "capitalize", children: t.name }),
|
|
32322
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "t-text-muted", children: [
|
|
33566
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "t-text-muted tabular-nums", children: [
|
|
32323
33567
|
"×",
|
|
32324
33568
|
t.total
|
|
32325
33569
|
] })
|
|
@@ -32337,7 +33581,7 @@ function StatusBar() {
|
|
|
32337
33581
|
"% cache"
|
|
32338
33582
|
] })
|
|
32339
33583
|
] }),
|
|
32340
|
-
hasRunUsage && hasProjectUsage && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-muted", children: "
|
|
33584
|
+
hasRunUsage && hasProjectUsage && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-muted opacity-50", "aria-hidden": true, children: "·" }),
|
|
32341
33585
|
hasProjectUsage && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "t-text-muted", title: "Project total", children: [
|
|
32342
33586
|
formatTokens(allTimeTokens),
|
|
32343
33587
|
" / ",
|
|
@@ -41131,134 +42375,437 @@ const useToolProgressStore = create$1((set) => ({
|
|
|
41131
42375
|
clearAll: () => set({ inFlight: /* @__PURE__ */ new Map() })
|
|
41132
42376
|
}));
|
|
41133
42377
|
const api = window.api;
|
|
41134
|
-
function
|
|
41135
|
-
const
|
|
41136
|
-
|
|
41137
|
-
const
|
|
41138
|
-
|
|
41139
|
-
|
|
41140
|
-
|
|
41141
|
-
|
|
41142
|
-
|
|
41143
|
-
|
|
41144
|
-
if (
|
|
41145
|
-
const
|
|
41146
|
-
|
|
41147
|
-
|
|
41148
|
-
|
|
41149
|
-
|
|
41150
|
-
|
|
41151
|
-
|
|
41152
|
-
|
|
42378
|
+
function relativeTime(iso) {
|
|
42379
|
+
const then = new Date(iso).getTime();
|
|
42380
|
+
if (!Number.isFinite(then)) return "";
|
|
42381
|
+
const diffMs = Date.now() - then;
|
|
42382
|
+
const mins = Math.floor(diffMs / 6e4);
|
|
42383
|
+
if (mins < 1) return "just now";
|
|
42384
|
+
if (mins < 60) return `${mins}m ago`;
|
|
42385
|
+
const hours = Math.floor(mins / 60);
|
|
42386
|
+
if (hours < 24) return `${hours}h ago`;
|
|
42387
|
+
const days = Math.floor(hours / 24);
|
|
42388
|
+
if (days < 7) return `${days}d ago`;
|
|
42389
|
+
const weeks = Math.floor(days / 7);
|
|
42390
|
+
if (weeks < 5) return `${weeks}w ago`;
|
|
42391
|
+
return new Date(iso).toLocaleDateString(void 0, { month: "short", day: "numeric" });
|
|
42392
|
+
}
|
|
42393
|
+
function splitPath(p) {
|
|
42394
|
+
const clean = p.replace(/\/+$/, "");
|
|
42395
|
+
const idx = clean.lastIndexOf("/");
|
|
42396
|
+
if (idx < 0) return { name: clean, parent: "" };
|
|
42397
|
+
return { name: clean.slice(idx + 1), parent: clean.slice(0, idx) };
|
|
42398
|
+
}
|
|
42399
|
+
function Kbd({ children }) {
|
|
42400
|
+
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 });
|
|
42401
|
+
}
|
|
42402
|
+
function RecentRow({
|
|
42403
|
+
entry,
|
|
42404
|
+
active,
|
|
42405
|
+
confirmRemove,
|
|
42406
|
+
stats,
|
|
42407
|
+
onActivate,
|
|
42408
|
+
onHover
|
|
42409
|
+
}) {
|
|
42410
|
+
const { name: name2, parent } = splitPath(entry.path);
|
|
42411
|
+
const totalArtifacts = stats ? stats.papers + stats.notes + stats.data : 0;
|
|
42412
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
42413
|
+
"button",
|
|
41153
42414
|
{
|
|
41154
|
-
|
|
41155
|
-
|
|
41156
|
-
|
|
41157
|
-
|
|
41158
|
-
|
|
41159
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[13px] font-medium t-text", children: [
|
|
41160
|
-
"v",
|
|
41161
|
-
update.latest,
|
|
41162
|
-
" available",
|
|
41163
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "t-text-secondary font-normal ml-1.5", children: [
|
|
41164
|
-
"(current: v",
|
|
41165
|
-
update.current,
|
|
41166
|
-
")"
|
|
41167
|
-
] })
|
|
41168
|
-
] }),
|
|
41169
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-2 flex items-center gap-2", children: [
|
|
41170
|
-
/* @__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 truncate", children: command }),
|
|
41171
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
41172
|
-
"button",
|
|
41173
|
-
{
|
|
41174
|
-
onClick: handleCopy,
|
|
41175
|
-
className: "shrink-0 p-1.5 rounded-md t-bg-surface hover:opacity-80 transition-opacity",
|
|
41176
|
-
title: "Copy command",
|
|
41177
|
-
children: copied ? /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { size: 14, className: "text-green-400" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { size: 14, className: "t-text-secondary" })
|
|
41178
|
-
}
|
|
41179
|
-
)
|
|
41180
|
-
] })
|
|
41181
|
-
] }),
|
|
42415
|
+
type: "button",
|
|
42416
|
+
onClick: onActivate,
|
|
42417
|
+
onMouseEnter: onHover,
|
|
42418
|
+
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" : ""}`,
|
|
42419
|
+
children: [
|
|
41182
42420
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
41183
|
-
"
|
|
42421
|
+
"span",
|
|
41184
42422
|
{
|
|
41185
|
-
|
|
41186
|
-
className:
|
|
41187
|
-
title: "Dismiss",
|
|
41188
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx(X$1, { size: 14 })
|
|
42423
|
+
"aria-hidden": true,
|
|
42424
|
+
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"}`
|
|
41189
42425
|
}
|
|
41190
|
-
)
|
|
41191
|
-
|
|
42426
|
+
),
|
|
42427
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
42428
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
42429
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `text-[13px] font-medium truncate ${active ? "t-text" : "t-text-secondary group-hover:t-text"}`, children: name2 }),
|
|
42430
|
+
entry.pinned && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] uppercase tracking-wider t-text-muted", children: "pinned" }),
|
|
42431
|
+
stats && !stats.initialized && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] uppercase tracking-wider t-text-muted", title: "No .research-pilot directory yet", children: "new" })
|
|
42432
|
+
] }),
|
|
42433
|
+
parent && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[11px] t-text-muted truncate font-mono mt-0.5", children: parent })
|
|
42434
|
+
] }),
|
|
42435
|
+
/* @__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: [
|
|
42436
|
+
stats && totalArtifacts > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-1.5 t-text-secondary", children: [
|
|
42437
|
+
stats.papers > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
|
|
42438
|
+
stats.papers,
|
|
42439
|
+
"p"
|
|
42440
|
+
] }),
|
|
42441
|
+
stats.notes > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
|
|
42442
|
+
stats.notes,
|
|
42443
|
+
"n"
|
|
42444
|
+
] }),
|
|
42445
|
+
stats.data > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
|
|
42446
|
+
stats.data,
|
|
42447
|
+
"d"
|
|
42448
|
+
] })
|
|
42449
|
+
] }),
|
|
42450
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: relativeTime(entry.openedAt) })
|
|
42451
|
+
] }) })
|
|
42452
|
+
]
|
|
41192
42453
|
}
|
|
41193
42454
|
);
|
|
41194
42455
|
}
|
|
42456
|
+
function WikiPanel({ onOpenSettings }) {
|
|
42457
|
+
const [stats, setStats] = reactExports.useState(null);
|
|
42458
|
+
const [recentPapers, setRecentPapers] = reactExports.useState([]);
|
|
42459
|
+
const [status, setStatus] = reactExports.useState(null);
|
|
42460
|
+
const [loaded, setLoaded] = reactExports.useState(false);
|
|
42461
|
+
reactExports.useEffect(() => {
|
|
42462
|
+
let cancelled = false;
|
|
42463
|
+
Promise.all([
|
|
42464
|
+
api.wikiGetStats?.().catch(() => null),
|
|
42465
|
+
api.wikiListPaperMeta?.().catch(() => null),
|
|
42466
|
+
api.wikiGetStatus?.().catch(() => null)
|
|
42467
|
+
]).then(([s15, list2, st2]) => {
|
|
42468
|
+
if (cancelled) return;
|
|
42469
|
+
if (s15) setStats(s15);
|
|
42470
|
+
if (Array.isArray(list2)) {
|
|
42471
|
+
const sorted = [...list2].sort((a, b2) => (b2.updatedAt || "").localeCompare(a.updatedAt || ""));
|
|
42472
|
+
setRecentPapers(sorted.slice(0, 3));
|
|
42473
|
+
}
|
|
42474
|
+
if (st2) setStatus(st2);
|
|
42475
|
+
setLoaded(true);
|
|
42476
|
+
});
|
|
42477
|
+
const unsub = api.onWikiStatus?.((s15) => setStatus(s15));
|
|
42478
|
+
return () => {
|
|
42479
|
+
cancelled = true;
|
|
42480
|
+
unsub?.();
|
|
42481
|
+
};
|
|
42482
|
+
}, []);
|
|
42483
|
+
if (!loaded) return null;
|
|
42484
|
+
const isDisabled = status?.state === "disabled";
|
|
42485
|
+
const isEmpty = (stats?.papers ?? 0) === 0;
|
|
42486
|
+
const header = /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-baseline justify-between mb-3", children: [
|
|
42487
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] uppercase tracking-wider t-text-muted font-medium", children: "Paper wiki" }),
|
|
42488
|
+
!isEmpty && stats && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] t-text-muted tabular-nums", children: stats.papers }),
|
|
42489
|
+
isDisabled && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] uppercase tracking-wider t-text-muted", children: "off" })
|
|
42490
|
+
] });
|
|
42491
|
+
if (isDisabled) {
|
|
42492
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("section", { "aria-labelledby": "wiki-panel-heading", children: [
|
|
42493
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h2", { id: "wiki-panel-heading", className: "sr-only", children: "Paper wiki" }),
|
|
42494
|
+
header,
|
|
42495
|
+
/* @__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." }),
|
|
42496
|
+
onOpenSettings && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
42497
|
+
"button",
|
|
42498
|
+
{
|
|
42499
|
+
onClick: onOpenSettings,
|
|
42500
|
+
className: "mt-3 inline-flex items-center gap-1.5 text-[11px] t-text-accent-soft hover:t-text-accent transition-colors",
|
|
42501
|
+
children: "Open settings →"
|
|
42502
|
+
}
|
|
42503
|
+
)
|
|
42504
|
+
] });
|
|
42505
|
+
}
|
|
42506
|
+
if (isEmpty) {
|
|
42507
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("section", { "aria-labelledby": "wiki-panel-heading", children: [
|
|
42508
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h2", { id: "wiki-panel-heading", className: "sr-only", children: "Paper wiki" }),
|
|
42509
|
+
header,
|
|
42510
|
+
/* @__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." }),
|
|
42511
|
+
/* @__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." })
|
|
42512
|
+
] });
|
|
42513
|
+
}
|
|
42514
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("section", { "aria-labelledby": "wiki-panel-heading", children: [
|
|
42515
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h2", { id: "wiki-panel-heading", className: "sr-only", children: "Paper wiki" }),
|
|
42516
|
+
header,
|
|
42517
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-baseline gap-3 text-[11px] t-text-secondary tabular-nums mb-6", children: [
|
|
42518
|
+
(stats?.fulltext ?? 0) > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
|
|
42519
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text font-medium", children: stats.fulltext }),
|
|
42520
|
+
" ",
|
|
42521
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-muted", children: "fulltext" })
|
|
42522
|
+
] }),
|
|
42523
|
+
(stats?.abstractOnly ?? 0) > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
42524
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-muted opacity-50", "aria-hidden": true, children: "·" }),
|
|
42525
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
|
|
42526
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text font-medium", children: stats.abstractOnly }),
|
|
42527
|
+
" ",
|
|
42528
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-muted", children: "abstract" })
|
|
42529
|
+
] })
|
|
42530
|
+
] }),
|
|
42531
|
+
(stats?.concepts ?? 0) > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
42532
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-muted opacity-50", "aria-hidden": true, children: "·" }),
|
|
42533
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
|
|
42534
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text font-medium", children: stats.concepts }),
|
|
42535
|
+
" ",
|
|
42536
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-muted", children: "concepts" })
|
|
42537
|
+
] })
|
|
42538
|
+
] })
|
|
42539
|
+
] }),
|
|
42540
|
+
recentPapers.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-6", children: [
|
|
42541
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] uppercase tracking-wider t-text-muted font-medium mb-2", children: "Recently added" }),
|
|
42542
|
+
/* @__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: [
|
|
42543
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0 text-[10px] t-text-muted mt-1", children: "·" }),
|
|
42544
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
42545
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[12px] t-text-secondary truncate leading-snug", children: p.title }),
|
|
42546
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-[10px] t-text-muted font-mono truncate", children: [
|
|
42547
|
+
p.slug,
|
|
42548
|
+
p.updatedAt && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
42549
|
+
" · ",
|
|
42550
|
+
relativeTime(p.updatedAt)
|
|
42551
|
+
] })
|
|
42552
|
+
] })
|
|
42553
|
+
] })
|
|
42554
|
+
] }, p.slug)) })
|
|
42555
|
+
] }),
|
|
42556
|
+
status && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5 text-[10px] t-text-muted", children: [
|
|
42557
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
42558
|
+
"span",
|
|
42559
|
+
{
|
|
42560
|
+
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"}`,
|
|
42561
|
+
"aria-hidden": true
|
|
42562
|
+
}
|
|
42563
|
+
),
|
|
42564
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "capitalize", children: status.state }),
|
|
42565
|
+
status.lastRunAt && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
42566
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "opacity-50", "aria-hidden": true, children: "·" }),
|
|
42567
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
|
|
42568
|
+
"last tick ",
|
|
42569
|
+
relativeTime(status.lastRunAt)
|
|
42570
|
+
] })
|
|
42571
|
+
] })
|
|
42572
|
+
] })
|
|
42573
|
+
] });
|
|
42574
|
+
}
|
|
42575
|
+
function TipsBlock() {
|
|
42576
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("section", { "aria-label": "Tips", children: [
|
|
42577
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] uppercase tracking-wider t-text-muted font-medium mb-2", children: "Tips" }),
|
|
42578
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("ul", { className: "flex flex-col gap-1.5 text-[11px] t-text-secondary", children: [
|
|
42579
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("li", { className: "flex items-center gap-2", children: [
|
|
42580
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Kbd, { children: "/" }),
|
|
42581
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "t-text-muted", children: "or" }),
|
|
42582
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Kbd, { children: "⌘K" }),
|
|
42583
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "open the command palette" })
|
|
42584
|
+
] }),
|
|
42585
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("li", { className: "flex items-center gap-2", children: [
|
|
42586
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Kbd, { children: "@" }),
|
|
42587
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "mention a note, paper, or file" })
|
|
42588
|
+
] }),
|
|
42589
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("li", { className: "flex items-center gap-2", children: [
|
|
42590
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Kbd, { children: "⌘1" }),
|
|
42591
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Kbd, { children: "⌘2" }),
|
|
42592
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "switch between chat and literature" })
|
|
42593
|
+
] })
|
|
42594
|
+
] })
|
|
42595
|
+
] });
|
|
42596
|
+
}
|
|
41195
42597
|
function FolderGate({ onOpenSettings }) {
|
|
41196
42598
|
const pickFolder = useSessionStore((s15) => s15.pickFolder);
|
|
42599
|
+
const openPath = useSessionStore((s15) => s15.openPath);
|
|
41197
42600
|
const refreshEntities = useEntityStore((s15) => s15.refreshAll);
|
|
41198
|
-
const
|
|
41199
|
-
|
|
41200
|
-
|
|
41201
|
-
|
|
42601
|
+
const [recents, setRecents] = reactExports.useState([]);
|
|
42602
|
+
const [projectStats, setProjectStats] = reactExports.useState({});
|
|
42603
|
+
const [activeIndex, setActiveIndex] = reactExports.useState(0);
|
|
42604
|
+
const [confirmRemove, setConfirmRemove] = reactExports.useState(null);
|
|
42605
|
+
const [opening, setOpening] = reactExports.useState(false);
|
|
42606
|
+
reactExports.useEffect(() => {
|
|
42607
|
+
let cancelled = false;
|
|
42608
|
+
api.listRecentProjects?.().then((list2) => {
|
|
42609
|
+
if (!cancelled && Array.isArray(list2)) setRecents(list2);
|
|
42610
|
+
}).catch(() => {
|
|
42611
|
+
});
|
|
42612
|
+
return () => {
|
|
42613
|
+
cancelled = true;
|
|
42614
|
+
};
|
|
42615
|
+
}, []);
|
|
42616
|
+
reactExports.useEffect(() => {
|
|
42617
|
+
if (recents.length === 0) {
|
|
42618
|
+
setProjectStats({});
|
|
42619
|
+
return;
|
|
41202
42620
|
}
|
|
41203
|
-
|
|
41204
|
-
|
|
41205
|
-
|
|
41206
|
-
|
|
41207
|
-
|
|
41208
|
-
|
|
41209
|
-
|
|
41210
|
-
|
|
41211
|
-
|
|
41212
|
-
|
|
41213
|
-
|
|
41214
|
-
|
|
41215
|
-
|
|
41216
|
-
|
|
41217
|
-
|
|
41218
|
-
|
|
41219
|
-
|
|
41220
|
-
|
|
41221
|
-
|
|
41222
|
-
|
|
41223
|
-
|
|
41224
|
-
|
|
41225
|
-
|
|
41226
|
-
|
|
41227
|
-
|
|
41228
|
-
|
|
41229
|
-
|
|
41230
|
-
|
|
41231
|
-
|
|
41232
|
-
|
|
41233
|
-
|
|
41234
|
-
|
|
41235
|
-
|
|
41236
|
-
|
|
41237
|
-
|
|
41238
|
-
|
|
41239
|
-
|
|
41240
|
-
|
|
41241
|
-
|
|
41242
|
-
|
|
41243
|
-
|
|
41244
|
-
|
|
41245
|
-
|
|
41246
|
-
|
|
41247
|
-
|
|
41248
|
-
|
|
41249
|
-
|
|
41250
|
-
|
|
41251
|
-
|
|
41252
|
-
|
|
41253
|
-
|
|
41254
|
-
|
|
41255
|
-
|
|
41256
|
-
|
|
41257
|
-
|
|
41258
|
-
|
|
42621
|
+
let cancelled = false;
|
|
42622
|
+
api.projectStatsBatch?.(recents.map((r) => r.path)).then(
|
|
42623
|
+
(map2) => {
|
|
42624
|
+
if (!cancelled && map2) setProjectStats(map2);
|
|
42625
|
+
}
|
|
42626
|
+
).catch(() => {
|
|
42627
|
+
});
|
|
42628
|
+
return () => {
|
|
42629
|
+
cancelled = true;
|
|
42630
|
+
};
|
|
42631
|
+
}, [recents]);
|
|
42632
|
+
const handleOpen = reactExports.useCallback(async (path2) => {
|
|
42633
|
+
if (opening) return;
|
|
42634
|
+
setOpening(true);
|
|
42635
|
+
try {
|
|
42636
|
+
const ok2 = await openPath(path2);
|
|
42637
|
+
if (ok2) await refreshEntities();
|
|
42638
|
+
} finally {
|
|
42639
|
+
setOpening(false);
|
|
42640
|
+
}
|
|
42641
|
+
}, [openPath, refreshEntities, opening]);
|
|
42642
|
+
const handlePickNew = reactExports.useCallback(async () => {
|
|
42643
|
+
if (opening) return;
|
|
42644
|
+
setOpening(true);
|
|
42645
|
+
try {
|
|
42646
|
+
const ok2 = await pickFolder();
|
|
42647
|
+
if (ok2) await refreshEntities();
|
|
42648
|
+
} finally {
|
|
42649
|
+
setOpening(false);
|
|
42650
|
+
}
|
|
42651
|
+
}, [pickFolder, refreshEntities, opening]);
|
|
42652
|
+
const handleRemove = reactExports.useCallback(async (path2) => {
|
|
42653
|
+
await api.removeRecentProject?.(path2);
|
|
42654
|
+
setRecents((prev) => {
|
|
42655
|
+
const next = prev.filter((e) => e.path !== path2);
|
|
42656
|
+
setActiveIndex((i) => Math.min(Math.max(0, i), Math.max(0, next.length - 1)));
|
|
42657
|
+
return next;
|
|
42658
|
+
});
|
|
42659
|
+
setConfirmRemove(null);
|
|
42660
|
+
}, []);
|
|
42661
|
+
reactExports.useEffect(() => {
|
|
42662
|
+
const handler = (e) => {
|
|
42663
|
+
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "o") {
|
|
42664
|
+
e.preventDefault();
|
|
42665
|
+
handlePickNew();
|
|
42666
|
+
return;
|
|
42667
|
+
}
|
|
42668
|
+
if (e.key === "ArrowDown") {
|
|
42669
|
+
if (recents.length === 0) return;
|
|
42670
|
+
e.preventDefault();
|
|
42671
|
+
setActiveIndex((i) => (i + 1) % recents.length);
|
|
42672
|
+
setConfirmRemove(null);
|
|
42673
|
+
} else if (e.key === "ArrowUp") {
|
|
42674
|
+
if (recents.length === 0) return;
|
|
42675
|
+
e.preventDefault();
|
|
42676
|
+
setActiveIndex((i) => (i - 1 + recents.length) % recents.length);
|
|
42677
|
+
setConfirmRemove(null);
|
|
42678
|
+
} else if (e.key === "Enter") {
|
|
42679
|
+
if (recents.length === 0) {
|
|
42680
|
+
e.preventDefault();
|
|
42681
|
+
handlePickNew();
|
|
42682
|
+
return;
|
|
42683
|
+
}
|
|
42684
|
+
const target = recents[activeIndex];
|
|
42685
|
+
if (target) {
|
|
42686
|
+
e.preventDefault();
|
|
42687
|
+
handleOpen(target.path);
|
|
42688
|
+
}
|
|
42689
|
+
} else if (e.key === "Backspace" || e.key === "Delete") {
|
|
42690
|
+
if (recents.length === 0) return;
|
|
42691
|
+
const target = recents[activeIndex];
|
|
42692
|
+
if (!target) return;
|
|
42693
|
+
e.preventDefault();
|
|
42694
|
+
if (confirmRemove === target.path) {
|
|
42695
|
+
handleRemove(target.path);
|
|
42696
|
+
} else {
|
|
42697
|
+
setConfirmRemove(target.path);
|
|
42698
|
+
}
|
|
42699
|
+
} else if (e.key === "Escape") {
|
|
42700
|
+
setConfirmRemove(null);
|
|
42701
|
+
}
|
|
42702
|
+
};
|
|
42703
|
+
window.addEventListener("keydown", handler);
|
|
42704
|
+
return () => window.removeEventListener("keydown", handler);
|
|
42705
|
+
}, [recents, activeIndex, confirmRemove, handleOpen, handlePickNew, handleRemove]);
|
|
42706
|
+
const hasRecents = recents.length > 0;
|
|
42707
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col h-screen w-screen t-bg-base t-text overflow-hidden", children: [
|
|
42708
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "drag-region fixed top-0 left-0 right-0 h-10 z-50" }),
|
|
42709
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
42710
|
+
"main",
|
|
42711
|
+
{
|
|
42712
|
+
id: "main-content",
|
|
42713
|
+
className: "flex-1 overflow-y-auto pt-[12vh] px-[8vw] pb-6",
|
|
42714
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mx-auto w-full max-w-6xl", children: [
|
|
42715
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-12 pl-1", children: [
|
|
42716
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h1", { className: "text-[16px] font-semibold t-text tracking-tight leading-none", children: "Research Pilot" }),
|
|
42717
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[11px] t-text-muted mt-1.5 leading-none", children: "A research workflow, not a chat window." })
|
|
42718
|
+
] }),
|
|
42719
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 xl:grid-cols-[minmax(0,1fr)_20rem] gap-12 xl:gap-16 items-start", children: [
|
|
42720
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("section", { "aria-labelledby": "recents-heading", children: [
|
|
42721
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h2", { id: "recents-heading", className: "sr-only", children: "Recent projects" }),
|
|
42722
|
+
hasRecents ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
42723
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-baseline justify-between mb-2 pl-4", children: [
|
|
42724
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] uppercase tracking-wider t-text-muted font-medium", children: "Recent projects" }),
|
|
42725
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] t-text-muted tabular-nums", children: recents.length })
|
|
42726
|
+
] }),
|
|
42727
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-col mb-6", children: recents.map((entry, i) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
42728
|
+
RecentRow,
|
|
42729
|
+
{
|
|
42730
|
+
entry,
|
|
42731
|
+
stats: projectStats[entry.path],
|
|
42732
|
+
active: i === activeIndex,
|
|
42733
|
+
confirmRemove: confirmRemove === entry.path,
|
|
42734
|
+
onActivate: () => handleOpen(entry.path),
|
|
42735
|
+
onHover: () => {
|
|
42736
|
+
setActiveIndex(i);
|
|
42737
|
+
if (confirmRemove !== entry.path) setConfirmRemove(null);
|
|
42738
|
+
}
|
|
42739
|
+
},
|
|
42740
|
+
entry.path
|
|
42741
|
+
)) })
|
|
42742
|
+
] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-6 pl-4", children: [
|
|
42743
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-baseline justify-between mb-3", children: [
|
|
42744
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] uppercase tracking-wider t-text-muted font-medium", children: "Recent projects" }),
|
|
42745
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] t-text-muted", children: "—" })
|
|
42746
|
+
] }),
|
|
42747
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[13px] t-text-secondary leading-relaxed mb-1", children: "No projects yet." }),
|
|
42748
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[12px] t-text-muted leading-relaxed max-w-md", children: [
|
|
42749
|
+
"Pick a folder to begin — we'll create a",
|
|
42750
|
+
" ",
|
|
42751
|
+
/* @__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" }),
|
|
42752
|
+
" ",
|
|
42753
|
+
"directory beside it for your notes, papers, and data. Everything stays on disk; nothing goes to the cloud."
|
|
42754
|
+
] })
|
|
42755
|
+
] }),
|
|
42756
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "pl-4", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
42757
|
+
"button",
|
|
42758
|
+
{
|
|
42759
|
+
onClick: handlePickNew,
|
|
42760
|
+
disabled: opening,
|
|
42761
|
+
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",
|
|
42762
|
+
children: [
|
|
42763
|
+
hasRecents ? "Open another folder…" : "Choose a folder to begin",
|
|
42764
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Kbd, { children: "⌘O" })
|
|
42765
|
+
]
|
|
42766
|
+
}
|
|
42767
|
+
) })
|
|
42768
|
+
] }),
|
|
42769
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("aside", { "aria-label": "Global status", className: "flex flex-col gap-10 xl:pl-4 xl:border-l t-border-subtle", children: [
|
|
42770
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "xl:pl-8", children: /* @__PURE__ */ jsxRuntimeExports.jsx(WikiPanel, { onOpenSettings }) }),
|
|
42771
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "xl:pl-8", children: /* @__PURE__ */ jsxRuntimeExports.jsx(TipsBlock, {}) })
|
|
42772
|
+
] })
|
|
42773
|
+
] }),
|
|
42774
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-16 pl-1 flex items-center gap-5 text-[10px] t-text-muted flex-wrap", children: [
|
|
42775
|
+
hasRecents && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
42776
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
42777
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Kbd, { children: "↑↓" }),
|
|
42778
|
+
" navigate"
|
|
42779
|
+
] }),
|
|
42780
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
42781
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Kbd, { children: "↵" }),
|
|
42782
|
+
" open"
|
|
42783
|
+
] }),
|
|
42784
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
42785
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Kbd, { children: "⌫" }),
|
|
42786
|
+
" remove"
|
|
42787
|
+
] })
|
|
42788
|
+
] }),
|
|
42789
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
42790
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Kbd, { children: "⌘O" }),
|
|
42791
|
+
" new folder"
|
|
42792
|
+
] }),
|
|
42793
|
+
onOpenSettings && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
42794
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Kbd, { children: "⌘," }),
|
|
42795
|
+
" settings"
|
|
42796
|
+
] }),
|
|
42797
|
+
onOpenSettings && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
42798
|
+
"button",
|
|
42799
|
+
{
|
|
42800
|
+
onClick: onOpenSettings,
|
|
42801
|
+
className: "ml-auto text-[11px] t-text-muted hover:t-text-secondary transition-colors",
|
|
42802
|
+
children: "API keys & settings →"
|
|
42803
|
+
}
|
|
42804
|
+
)
|
|
42805
|
+
] })
|
|
41259
42806
|
] })
|
|
41260
|
-
|
|
41261
|
-
|
|
42807
|
+
}
|
|
42808
|
+
)
|
|
41262
42809
|
] });
|
|
41263
42810
|
}
|
|
41264
42811
|
function App() {
|
|
@@ -41273,16 +42820,17 @@ function App() {
|
|
|
41273
42820
|
const terminalVisible = useUIStore((s15) => s15.terminalVisible);
|
|
41274
42821
|
const terminalAlive = useUIStore((s15) => s15.terminalAlive);
|
|
41275
42822
|
const theme = useUIStore((s15) => s15.theme);
|
|
41276
|
-
const [
|
|
41277
|
-
const [
|
|
41278
|
-
const [
|
|
42823
|
+
const [settingsOpen, setSettingsOpen] = reactExports.useState(false);
|
|
42824
|
+
const [settingsTab, setSettingsTab] = reactExports.useState("api-keys");
|
|
42825
|
+
const [authChecked, setAuthChecked] = reactExports.useState(false);
|
|
41279
42826
|
reactExports.useEffect(() => {
|
|
41280
|
-
api.
|
|
41281
|
-
|
|
41282
|
-
|
|
41283
|
-
|
|
41284
|
-
|
|
41285
|
-
|
|
42827
|
+
api.hasLlmAuth?.().then((hasAuth) => {
|
|
42828
|
+
if (!hasAuth) {
|
|
42829
|
+
setSettingsOpen(true);
|
|
42830
|
+
setSettingsTab("api-keys");
|
|
42831
|
+
}
|
|
42832
|
+
setAuthChecked(true);
|
|
42833
|
+
}).catch(() => setAuthChecked(true));
|
|
41286
42834
|
}, []);
|
|
41287
42835
|
reactExports.useEffect(() => {
|
|
41288
42836
|
document.documentElement.classList.remove("dark", "light");
|
|
@@ -41476,18 +43024,33 @@ function App() {
|
|
|
41476
43024
|
e.preventDefault();
|
|
41477
43025
|
useUIStore.getState().toggleTerminal();
|
|
41478
43026
|
}
|
|
43027
|
+
if ((e.metaKey || e.ctrlKey) && e.key === ",") {
|
|
43028
|
+
e.preventDefault();
|
|
43029
|
+
setSettingsOpen((prev) => !prev);
|
|
43030
|
+
}
|
|
41479
43031
|
};
|
|
41480
43032
|
window.addEventListener("keydown", handler);
|
|
41481
43033
|
return () => window.removeEventListener("keydown", handler);
|
|
41482
43034
|
}, [previewEntity, previewEditorFocused]);
|
|
41483
|
-
if (!
|
|
43035
|
+
if (!authChecked) {
|
|
41484
43036
|
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" }) });
|
|
41485
43037
|
}
|
|
41486
|
-
|
|
41487
|
-
|
|
41488
|
-
|
|
43038
|
+
const settingsModal = /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
43039
|
+
SettingsModal,
|
|
43040
|
+
{
|
|
43041
|
+
open: settingsOpen,
|
|
43042
|
+
onClose: () => setSettingsOpen(false),
|
|
43043
|
+
initialTab: settingsTab
|
|
43044
|
+
}
|
|
43045
|
+
);
|
|
41489
43046
|
if (!hasProject) {
|
|
41490
|
-
return /* @__PURE__ */ jsxRuntimeExports.
|
|
43047
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
43048
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(FolderGate, { onOpenSettings: () => {
|
|
43049
|
+
setSettingsTab("api-keys");
|
|
43050
|
+
setSettingsOpen(true);
|
|
43051
|
+
} }),
|
|
43052
|
+
settingsModal
|
|
43053
|
+
] });
|
|
41491
43054
|
}
|
|
41492
43055
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(ErrorBoundary, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col h-screen w-screen t-bg-base t-text", children: [
|
|
41493
43056
|
/* @__PURE__ */ jsxRuntimeExports.jsx("a", { href: "#main-content", className: "skip-link", children: "Skip to content" }),
|
|
@@ -41513,9 +43076,11 @@ function App() {
|
|
|
41513
43076
|
)
|
|
41514
43077
|
] })
|
|
41515
43078
|
] }),
|
|
41516
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(StatusBar, {})
|
|
43079
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(StatusBar, {}),
|
|
43080
|
+
settingsModal
|
|
41517
43081
|
] }) });
|
|
41518
43082
|
}
|
|
43083
|
+
bootTheme();
|
|
41519
43084
|
ReactDOM.createRoot(document.getElementById("root")).render(
|
|
41520
43085
|
/* @__PURE__ */ jsxRuntimeExports.jsx(React$2.StrictMode, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(App, {}) })
|
|
41521
43086
|
);
|