@poco-ai/agentero-dsh-recommend 0.0.0-stage → 0.1.0

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/lib/client.js ADDED
@@ -0,0 +1,1238 @@
1
+ window.__ModuleLoader__.load({
2
+ id: "@poco-ai/agentero-dsh-recommend",
3
+ factory: (require) => {
4
+ var module = { exports: {} };
5
+ var exports = module.exports;
6
+ if (typeof document !== "undefined") {
7
+ var styleId = "@poco-ai/agentero-dsh-recommend-tailwind";
8
+ if (!document.getElementById(styleId)) {
9
+ var style = document.createElement("style");
10
+ style.id = styleId;
11
+ style.textContent = "/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){.agentero-recommend *, .agentero-recommend*,.agentero-recommend :before, .agentero-recommend:before,.agentero-recommend :after, .agentero-recommend:after,.agentero-recommend ::backdrop, .agentero-recommend::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000}}}@layer theme{:root,.agentero-recommend :host, .agentero-recommend:host{--spacing:.25rem;--leading-snug:1.375;--leading-relaxed:1.625;--animate-spin:spin 1s linear infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1)}}@layer base{.agentero-surface,.agentero-surface *,.agentero-surface:before,.agentero-surface:after,.agentero-surface :before,.agentero-surface :after{box-sizing:border-box;border:0 solid}.agentero-surface button,.agentero-surface input,.agentero-surface select,.agentero-surface textarea,.agentero-surface fieldset{font:inherit;letter-spacing:inherit;color:inherit;background-color:#0000;margin:0;padding:0}.agentero-surface{color:var(--foreground);font-family:var(--agentero-font-sans);font-size:.8125rem;line-height:1.3846}}@layer utilities{.agentero-recommend .pointer-events-none, .agentero-recommend.pointer-events-none{pointer-events:none}.agentero-recommend .collapse, .agentero-recommend.collapse{visibility:collapse}.agentero-recommend .absolute, .agentero-recommend.absolute{position:absolute}.agentero-recommend .relative, .agentero-recommend.relative{position:relative}.agentero-recommend .top-1\\/2, .agentero-recommend.top-1\\/2{top:50%}.agentero-recommend .left-2, .agentero-recommend.left-2{left:calc(var(--spacing) * 2)}.agentero-recommend .order-1, .agentero-recommend.order-1{order:1}.agentero-recommend .mt-0\\.5, .agentero-recommend.mt-0\\.5{margin-top:calc(var(--spacing) * .5)}.agentero-recommend .mt-1, .agentero-recommend.mt-1{margin-top:var(--spacing)}.agentero-recommend .mt-1\\.5, .agentero-recommend.mt-1\\.5{margin-top:calc(var(--spacing) * 1.5)}.agentero-recommend .mt-auto, .agentero-recommend.mt-auto{margin-top:auto}.agentero-recommend .mb-1, .agentero-recommend.mb-1{margin-bottom:var(--spacing)}.agentero-recommend .mb-1\\.5, .agentero-recommend.mb-1\\.5{margin-bottom:calc(var(--spacing) * 1.5)}.agentero-recommend .ml-auto, .agentero-recommend.ml-auto{margin-left:auto}.agentero-recommend .line-clamp-2, .agentero-recommend.line-clamp-2{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.agentero-recommend .flex, .agentero-recommend.flex{display:flex}.agentero-recommend .grid, .agentero-recommend.grid{display:grid}.agentero-recommend .inline-flex, .agentero-recommend.inline-flex{display:inline-flex}.agentero-recommend .size-2\\.5, .agentero-recommend.size-2\\.5{width:calc(var(--spacing) * 2.5);height:calc(var(--spacing) * 2.5)}.agentero-recommend .size-3, .agentero-recommend.size-3{width:calc(var(--spacing) * 3);height:calc(var(--spacing) * 3)}.agentero-recommend .size-3\\.5, .agentero-recommend.size-3\\.5{width:calc(var(--spacing) * 3.5);height:calc(var(--spacing) * 3.5)}.agentero-recommend .size-6, .agentero-recommend.size-6{width:calc(var(--spacing) * 6);height:calc(var(--spacing) * 6)}.agentero-recommend .h-5, .agentero-recommend.h-5{height:calc(var(--spacing) * 5)}.agentero-recommend .h-6, .agentero-recommend.h-6{height:calc(var(--spacing) * 6)}.agentero-recommend .w-20, .agentero-recommend.w-20{width:calc(var(--spacing) * 20)}.agentero-recommend .w-64, .agentero-recommend.w-64{width:calc(var(--spacing) * 64)}.agentero-recommend .w-full, .agentero-recommend.w-full{width:100%}.agentero-recommend .min-w-0, .agentero-recommend.min-w-0{min-width:0}.agentero-recommend .flex-1, .agentero-recommend.flex-1{flex:1}.agentero-recommend .shrink-0, .agentero-recommend.shrink-0{flex-shrink:0}.agentero-recommend .-translate-y-1\\/2, .agentero-recommend.-translate-y-1\\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.agentero-recommend .animate-spin, .agentero-recommend.animate-spin{animation:var(--animate-spin)}.agentero-recommend .flex-col, .agentero-recommend.flex-col{flex-direction:column}.agentero-recommend .flex-wrap, .agentero-recommend.flex-wrap{flex-wrap:wrap}.agentero-recommend .items-center, .agentero-recommend.items-center{align-items:center}.agentero-recommend .items-start, .agentero-recommend.items-start{align-items:flex-start}.agentero-recommend .items-stretch, .agentero-recommend.items-stretch{align-items:stretch}.agentero-recommend .justify-between, .agentero-recommend.justify-between{justify-content:space-between}.agentero-recommend .justify-center, .agentero-recommend.justify-center{justify-content:center}.agentero-recommend .gap-0\\.5, .agentero-recommend.gap-0\\.5{gap:calc(var(--spacing) * .5)}.agentero-recommend .gap-1, .agentero-recommend.gap-1{gap:var(--spacing)}.agentero-recommend .gap-1\\.5, .agentero-recommend.gap-1\\.5{gap:calc(var(--spacing) * 1.5)}.agentero-recommend .gap-2, .agentero-recommend.gap-2{gap:calc(var(--spacing) * 2)}.agentero-recommend .gap-x-2, .agentero-recommend.gap-x-2{column-gap:calc(var(--spacing) * 2)}.agentero-recommend .gap-y-1\\.5, .agentero-recommend.gap-y-1\\.5{row-gap:calc(var(--spacing) * 1.5)}.agentero-recommend .truncate, .agentero-recommend.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.agentero-recommend .overflow-x-auto, .agentero-recommend.overflow-x-auto{overflow-x:auto}.agentero-recommend .rounded, .agentero-recommend.rounded{border-radius:.25rem}.agentero-recommend .rounded-full, .agentero-recommend.rounded-full{border-radius:3.40282e38px}.agentero-recommend .rounded-lg, .agentero-recommend.rounded-lg{border-radius:var(--radius)}.agentero-recommend .rounded-md, .agentero-recommend.rounded-md{border-radius:calc(var(--radius) * .8)}.agentero-recommend .border, .agentero-recommend.border{border-style:var(--tw-border-style);border-width:1px}.agentero-recommend .border-0, .agentero-recommend.border-0{border-style:var(--tw-border-style);border-width:0}.agentero-recommend .border-dashed, .agentero-recommend.border-dashed{--tw-border-style:dashed;border-style:dashed}.agentero-recommend .border-border, .agentero-recommend.border-border{border-color:var(--border)}.agentero-recommend .border-input, .agentero-recommend.border-input{border-color:var(--input)}.agentero-recommend .border-primary\\/40, .agentero-recommend.border-primary\\/40{border-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.agentero-recommend .border-primary\\/40, .agentero-recommend.border-primary\\/40{border-color:color-mix(in oklab, var(--primary) 40%, transparent)}}.agentero-recommend .bg-background, .agentero-recommend.bg-background{background-color:var(--background)}.agentero-recommend .bg-muted, .agentero-recommend.bg-muted{background-color:var(--muted)}.agentero-recommend .bg-primary, .agentero-recommend.bg-primary,.agentero-recommend .bg-primary\\/10, .agentero-recommend.bg-primary\\/10{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.agentero-recommend .bg-primary\\/10, .agentero-recommend.bg-primary\\/10{background-color:color-mix(in oklab, var(--primary) 10%, transparent)}}.agentero-recommend .bg-transparent, .agentero-recommend.bg-transparent{background-color:#0000}.agentero-recommend .p-0, .agentero-recommend.p-0{padding:0}.agentero-recommend .p-0\\.5, .agentero-recommend.p-0\\.5{padding:calc(var(--spacing) * .5)}.agentero-recommend .p-2, .agentero-recommend.p-2{padding:calc(var(--spacing) * 2)}.agentero-recommend .px-1\\.5, .agentero-recommend.px-1\\.5{padding-inline:calc(var(--spacing) * 1.5)}.agentero-recommend .px-2, .agentero-recommend.px-2{padding-inline:calc(var(--spacing) * 2)}.agentero-recommend .px-2\\.5, .agentero-recommend.px-2\\.5{padding-inline:calc(var(--spacing) * 2.5)}.agentero-recommend .py-0\\.5, .agentero-recommend.py-0\\.5{padding-block:calc(var(--spacing) * .5)}.agentero-recommend .py-1\\.5, .agentero-recommend.py-1\\.5{padding-block:calc(var(--spacing) * 1.5)}.agentero-recommend .py-2, .agentero-recommend.py-2{padding-block:calc(var(--spacing) * 2)}.agentero-recommend .pt-0\\.5, .agentero-recommend.pt-0\\.5{padding-top:calc(var(--spacing) * .5)}.agentero-recommend .pt-1\\.5, .agentero-recommend.pt-1\\.5{padding-top:calc(var(--spacing) * 1.5)}.agentero-recommend .pr-0\\.5, .agentero-recommend.pr-0\\.5{padding-right:calc(var(--spacing) * .5)}.agentero-recommend .pr-2, .agentero-recommend.pr-2{padding-right:calc(var(--spacing) * 2)}.agentero-recommend .pb-0\\.5, .agentero-recommend.pb-0\\.5{padding-bottom:calc(var(--spacing) * .5)}.agentero-recommend .pb-1, .agentero-recommend.pb-1{padding-bottom:var(--spacing)}.agentero-recommend .pl-2, .agentero-recommend.pl-2{padding-left:calc(var(--spacing) * 2)}.agentero-recommend .pl-7, .agentero-recommend.pl-7{padding-left:calc(var(--spacing) * 7)}.agentero-recommend .text-left, .agentero-recommend.text-left{text-align:left}.agentero-recommend .font-mono, .agentero-recommend.font-mono{font-family:var(--agentero-font-mono)}.agentero-recommend .text-caption, .agentero-recommend.text-caption{font-size:.6875rem;line-height:var(--tw-leading,1.35);letter-spacing:var(--tw-tracking,.012em)}.agentero-recommend .text-sm, .agentero-recommend.text-sm{font-size:.8125rem;line-height:var(--tw-leading,1.3846);letter-spacing:var(--tw-tracking,0em)}.agentero-recommend .text-xs, .agentero-recommend.text-xs{font-size:.75rem;line-height:var(--tw-leading,1.35);letter-spacing:var(--tw-tracking,.006em)}.agentero-recommend .leading-relaxed, .agentero-recommend.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.agentero-recommend .leading-snug, .agentero-recommend.leading-snug{--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}.agentero-recommend .font-medium, .agentero-recommend.font-medium{--tw-font-weight:510;font-weight:510}.agentero-recommend .text-\\[\\#C792EA\\], .agentero-recommend.text-\\[\\#C792EA\\]{color:#c792ea}.agentero-recommend .text-destructive, .agentero-recommend.text-destructive{color:var(--destructive)}.agentero-recommend .text-foreground, .agentero-recommend.text-foreground,.agentero-recommend .text-foreground\\/80, .agentero-recommend.text-foreground\\/80{color:var(--foreground)}@supports (color:color-mix(in lab, red, red)){.agentero-recommend .text-foreground\\/80, .agentero-recommend.text-foreground\\/80{color:color-mix(in oklab, var(--foreground) 80%, transparent)}}.agentero-recommend .text-muted-foreground, .agentero-recommend.text-muted-foreground{color:var(--muted-foreground)}.agentero-recommend .text-primary-foreground, .agentero-recommend.text-primary-foreground{color:var(--primary-foreground)}.agentero-recommend .tabular-nums, .agentero-recommend.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.agentero-recommend .transition-colors, .agentero-recommend.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.agentero-recommend .outline-none, .agentero-recommend.outline-none{--tw-outline-style:none;outline-style:none}.agentero-recommend .placeholder\\:text-muted-foreground\\/70::placeholder, .agentero-recommend.placeholder\\:text-muted-foreground\\/70::placeholder{color:var(--muted-foreground)}@supports (color:color-mix(in lab, red, red)){.agentero-recommend .placeholder\\:text-muted-foreground\\/70::placeholder, .agentero-recommend.placeholder\\:text-muted-foreground\\/70::placeholder{color:color-mix(in oklab, var(--muted-foreground) 70%, transparent)}}@media (hover:hover){.agentero-recommend .hover\\:border-border:hover, .agentero-recommend.hover\\:border-border:hover{border-color:var(--border)}.agentero-recommend .hover\\:bg-foreground\\/10:hover, .agentero-recommend.hover\\:bg-foreground\\/10:hover{background-color:var(--foreground)}@supports (color:color-mix(in lab, red, red)){.agentero-recommend .hover\\:bg-foreground\\/10:hover, .agentero-recommend.hover\\:bg-foreground\\/10:hover{background-color:color-mix(in oklab, var(--foreground) 10%, transparent)}}.agentero-recommend .hover\\:bg-muted:hover, .agentero-recommend.hover\\:bg-muted:hover,.agentero-recommend .hover\\:bg-muted\\/40:hover, .agentero-recommend.hover\\:bg-muted\\/40:hover{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.agentero-recommend .hover\\:bg-muted\\/40:hover, .agentero-recommend.hover\\:bg-muted\\/40:hover{background-color:color-mix(in oklab, var(--muted) 40%, transparent)}}.agentero-recommend .hover\\:bg-muted\\/60:hover, .agentero-recommend.hover\\:bg-muted\\/60:hover{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.agentero-recommend .hover\\:bg-muted\\/60:hover, .agentero-recommend.hover\\:bg-muted\\/60:hover{background-color:color-mix(in oklab, var(--muted) 60%, transparent)}}.agentero-recommend .hover\\:bg-primary\\/80:hover, .agentero-recommend.hover\\:bg-primary\\/80:hover{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.agentero-recommend .hover\\:bg-primary\\/80:hover, .agentero-recommend.hover\\:bg-primary\\/80:hover{background-color:color-mix(in oklab, var(--primary) 80%, transparent)}}.agentero-recommend .hover\\:text-foreground:hover, .agentero-recommend.hover\\:text-foreground:hover{color:var(--foreground)}}.agentero-recommend .focus-visible\\:border-ring:focus-visible, .agentero-recommend.focus-visible\\:border-ring:focus-visible{border-color:var(--ring)}.agentero-recommend .focus-visible\\:ring-2:focus-visible, .agentero-recommend.focus-visible\\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.agentero-recommend .focus-visible\\:ring-ring\\/40:focus-visible, .agentero-recommend.focus-visible\\:ring-ring\\/40:focus-visible{--tw-ring-color:var(--ring)}@supports (color:color-mix(in lab, red, red)){.agentero-recommend .focus-visible\\:ring-ring\\/40:focus-visible, .agentero-recommend.focus-visible\\:ring-ring\\/40:focus-visible{--tw-ring-color:color-mix(in oklab, var(--ring) 40%, transparent)}}.agentero-recommend .disabled\\:pointer-events-none:disabled, .agentero-recommend.disabled\\:pointer-events-none:disabled{pointer-events:none}.agentero-recommend .disabled\\:opacity-30:disabled, .agentero-recommend.disabled\\:opacity-30:disabled{opacity:.3}.agentero-recommend .disabled\\:opacity-50:disabled, .agentero-recommend.disabled\\:opacity-50:disabled{opacity:.5}@media (min-width:40rem){.agentero-recommend .sm\\:grid-cols-2, .agentero-recommend.sm\\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width:64rem){.agentero-recommend .lg\\:grid-cols-4, .agentero-recommend.lg\\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}.agentero-recommend .\\[\\&_\\*\\]\\:box-border *, .agentero-recommend.\\[\\&_\\*\\]\\:box-border *{box-sizing:border-box}}:root{--agentero-font-sans:system-ui, \"Segoe UI\", -apple-system, BlinkMacSystemFont, Roboto, \"Helvetica Neue\", Arial, \"PingFang SC\", \"Hiragino Sans GB\", \"Microsoft YaHei UI\", \"Microsoft YaHei\", \"Noto Sans SC\", sans-serif;--agentero-font-heading:var(--agentero-font-sans);--agentero-font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, \"Cascadia Mono\", Consolas, \"Liberation Mono\", \"Courier New\", monospace}.agentero-surface{--background:oklch(99.5% .002 260);--foreground:oklch(21% .008 260);--card:oklch(100% .001 260);--card-foreground:oklch(21% .008 260);--popover:oklch(100% .001 260);--popover-foreground:oklch(21% .008 260);--primary:oklch(25% .012 260);--primary-foreground:oklch(99% .001 260);--default-primary:oklch(25% .012 260);--default-ring:oklch(62% .02 260);--secondary:oklch(96% .006 260);--secondary-foreground:oklch(25% .012 260);--muted:oklch(96.2% .006 260);--muted-foreground:oklch(48% .014 260);--accent:oklch(95.2% .008 260);--accent-foreground:oklch(25% .012 260);--destructive:oklch(57.7% .245 27.325);--border:oklch(90.5% .008 260);--input:oklch(90.5% .008 260);--ring:oklch(62% .02 260);--chart-1:oklch(87% .01 260);--chart-2:oklch(55.6% .014 260);--chart-3:oklch(43.9% .014 260);--chart-4:oklch(37.1% .012 260);--chart-5:oklch(26.9% .01 260);--radius:.5rem;--sidebar:oklch(96.5% .007 260);--sidebar-foreground:oklch(21% .008 260);--sidebar-primary:oklch(25% .012 260);--sidebar-primary-foreground:oklch(99% .001 260);--sidebar-accent:oklch(93.5% .01 260);--sidebar-accent-foreground:oklch(25% .012 260);--sidebar-border:oklch(90% .008 260);--sidebar-ring:oklch(62% .02 260);--brand:oklch(62.3% .214 259.815);--highlight:oklch(85.2% .199 91.936);--color-background:var(--background);--color-foreground:var(--foreground);--color-card:var(--card);--color-card-foreground:var(--card-foreground);--color-popover:var(--popover);--color-popover-foreground:var(--popover-foreground);--color-primary:var(--primary);--color-primary-foreground:var(--primary-foreground);--color-secondary:var(--secondary);--color-secondary-foreground:var(--secondary-foreground);--color-muted:var(--muted);--color-muted-foreground:var(--muted-foreground);--color-accent:var(--accent);--color-accent-foreground:var(--accent-foreground);--color-destructive:var(--destructive);--color-border:var(--border);--color-input:var(--input);--color-ring:var(--ring);color-scheme:light;min-width:0;height:100%;min-height:0}body[data-ds-dark-theme] .agentero-surface,html.dark .agentero-surface,html[data-theme=dark] .agentero-surface{--background:oklch(15.5% .006 260);--foreground:oklch(98% .004 260);--card:oklch(21.5% .008 260);--card-foreground:oklch(98% .004 260);--popover:oklch(21.5% .008 260);--popover-foreground:oklch(98% .004 260);--primary:oklch(94% .006 260);--primary-foreground:oklch(22% .01 260);--default-primary:oklch(94% .006 260);--default-ring:oklch(58% .02 260);--secondary:oklch(25.5% .008 260);--secondary-foreground:oklch(98% .004 260);--muted:oklch(25.5% .008 260);--muted-foreground:oklch(72% .012 260);--accent:oklch(27% .01 260);--accent-foreground:oklch(98% .004 260);--destructive:oklch(70.4% .191 22.216);--border:oklch(98% .004 260/.12);--input:oklch(98% .004 260/.16);--ring:oklch(58% .02 260);--chart-1:oklch(87% .01 260);--chart-2:oklch(55.6% .014 260);--chart-3:oklch(43.9% .014 260);--chart-4:oklch(37.1% .012 260);--chart-5:oklch(26.9% .01 260);--sidebar:oklch(18% .007 260);--sidebar-foreground:oklch(98% .004 260);--sidebar-primary:oklch(62% .18 255);--sidebar-primary-foreground:oklch(99% .001 260);--sidebar-accent:oklch(27% .01 260);--sidebar-accent-foreground:oklch(98% .004 260);--sidebar-border:oklch(98% .004 260/.12);--sidebar-ring:oklch(58% .02 260);--brand:oklch(70.7% .165 254.624);--highlight:oklch(85.2% .199 91.936);color-scheme:dark}.agentero-surface.agentero-recommend{height:auto;min-height:0}@property --tw-translate-x{syntax:\"*\";inherits:false;initial-value:0}@property --tw-translate-y{syntax:\"*\";inherits:false;initial-value:0}@property --tw-translate-z{syntax:\"*\";inherits:false;initial-value:0}@property --tw-border-style{syntax:\"*\";inherits:false;initial-value:solid}@property --tw-leading{syntax:\"*\";inherits:false}@property --tw-font-weight{syntax:\"*\";inherits:false}@property --tw-ordinal{syntax:\"*\";inherits:false}@property --tw-slashed-zero{syntax:\"*\";inherits:false}@property --tw-numeric-figure{syntax:\"*\";inherits:false}@property --tw-numeric-spacing{syntax:\"*\";inherits:false}@property --tw-numeric-fraction{syntax:\"*\";inherits:false}@property --tw-shadow{syntax:\"*\";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:\"*\";inherits:false}@property --tw-shadow-alpha{syntax:\"<percentage>\";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:\"*\";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:\"*\";inherits:false}@property --tw-inset-shadow-alpha{syntax:\"<percentage>\";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:\"*\";inherits:false}@property --tw-ring-shadow{syntax:\"*\";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:\"*\";inherits:false}@property --tw-inset-ring-shadow{syntax:\"*\";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:\"*\";inherits:false}@property --tw-ring-offset-width{syntax:\"<length>\";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:\"*\";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:\"*\";inherits:false;initial-value:0 0 #0000}@keyframes spin{to{transform:rotate(360deg)}}\n";
12
+ document.head.appendChild(style);
13
+ }
14
+ }
15
+
16
+ "use strict";
17
+ var __defProp = Object.defineProperty;
18
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
19
+ var __getOwnPropNames = Object.getOwnPropertyNames;
20
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
21
+ var __export = (target, all) => {
22
+ for (var name2 in all)
23
+ __defProp(target, name2, { get: all[name2], enumerable: true });
24
+ };
25
+ var __copyProps = (to, from, except, desc) => {
26
+ if (from && typeof from === "object" || typeof from === "function") {
27
+ for (let key of __getOwnPropNames(from))
28
+ if (!__hasOwnProp.call(to, key) && key !== except)
29
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
30
+ }
31
+ return to;
32
+ };
33
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
34
+
35
+ // src/client/index.ts
36
+ var index_exports = {};
37
+ __export(index_exports, {
38
+ apply: () => apply,
39
+ inject: () => inject,
40
+ name: () => name
41
+ });
42
+ module.exports = __toCommonJS(index_exports);
43
+
44
+ // ../../node_modules/.pnpm/lucide-react@0.554.0/node_modules/lucide-react/dist/esm/createLucideIcon.js
45
+ var import_react2 = require("react");
46
+
47
+ // ../../node_modules/.pnpm/lucide-react@0.554.0/node_modules/lucide-react/dist/esm/shared/src/utils.js
48
+ var toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
49
+ var toCamelCase = (string) => string.replace(
50
+ /^([A-Z])|[\s-_]+(\w)/g,
51
+ (match, p1, p2) => p2 ? p2.toUpperCase() : p1.toLowerCase()
52
+ );
53
+ var toPascalCase = (string) => {
54
+ const camelCase = toCamelCase(string);
55
+ return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);
56
+ };
57
+ var mergeClasses = (...classes) => classes.filter((className, index, array) => {
58
+ return Boolean(className) && className.trim() !== "" && array.indexOf(className) === index;
59
+ }).join(" ").trim();
60
+ var hasA11yProp = (props) => {
61
+ for (const prop in props) {
62
+ if (prop.startsWith("aria-") || prop === "role" || prop === "title") {
63
+ return true;
64
+ }
65
+ }
66
+ };
67
+
68
+ // ../../node_modules/.pnpm/lucide-react@0.554.0/node_modules/lucide-react/dist/esm/Icon.js
69
+ var import_react = require("react");
70
+
71
+ // ../../node_modules/.pnpm/lucide-react@0.554.0/node_modules/lucide-react/dist/esm/defaultAttributes.js
72
+ var defaultAttributes = {
73
+ xmlns: "http://www.w3.org/2000/svg",
74
+ width: 24,
75
+ height: 24,
76
+ viewBox: "0 0 24 24",
77
+ fill: "none",
78
+ stroke: "currentColor",
79
+ strokeWidth: 2,
80
+ strokeLinecap: "round",
81
+ strokeLinejoin: "round"
82
+ };
83
+
84
+ // ../../node_modules/.pnpm/lucide-react@0.554.0/node_modules/lucide-react/dist/esm/Icon.js
85
+ var Icon = (0, import_react.forwardRef)(
86
+ ({
87
+ color = "currentColor",
88
+ size = 24,
89
+ strokeWidth = 2,
90
+ absoluteStrokeWidth,
91
+ className = "",
92
+ children,
93
+ iconNode,
94
+ ...rest
95
+ }, ref) => (0, import_react.createElement)(
96
+ "svg",
97
+ {
98
+ ref,
99
+ ...defaultAttributes,
100
+ width: size,
101
+ height: size,
102
+ stroke: color,
103
+ strokeWidth: absoluteStrokeWidth ? Number(strokeWidth) * 24 / Number(size) : strokeWidth,
104
+ className: mergeClasses("lucide", className),
105
+ ...!children && !hasA11yProp(rest) && { "aria-hidden": "true" },
106
+ ...rest
107
+ },
108
+ [
109
+ ...iconNode.map(([tag, attrs]) => (0, import_react.createElement)(tag, attrs)),
110
+ ...Array.isArray(children) ? children : [children]
111
+ ]
112
+ )
113
+ );
114
+
115
+ // ../../node_modules/.pnpm/lucide-react@0.554.0/node_modules/lucide-react/dist/esm/createLucideIcon.js
116
+ var createLucideIcon = (iconName, iconNode) => {
117
+ const Component = (0, import_react2.forwardRef)(
118
+ ({ className, ...props }, ref) => (0, import_react2.createElement)(Icon, {
119
+ ref,
120
+ iconNode,
121
+ className: mergeClasses(
122
+ `lucide-${toKebabCase(toPascalCase(iconName))}`,
123
+ `lucide-${iconName}`,
124
+ className
125
+ ),
126
+ ...props
127
+ })
128
+ );
129
+ Component.displayName = toPascalCase(iconName);
130
+ return Component;
131
+ };
132
+
133
+ // ../../node_modules/.pnpm/lucide-react@0.554.0/node_modules/lucide-react/dist/esm/icons/check.js
134
+ var __iconNode = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
135
+ var Check = createLucideIcon("check", __iconNode);
136
+
137
+ // ../../node_modules/.pnpm/lucide-react@0.554.0/node_modules/lucide-react/dist/esm/icons/chevron-down.js
138
+ var __iconNode2 = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
139
+ var ChevronDown = createLucideIcon("chevron-down", __iconNode2);
140
+
141
+ // ../../node_modules/.pnpm/lucide-react@0.554.0/node_modules/lucide-react/dist/esm/icons/chevron-up.js
142
+ var __iconNode3 = [["path", { d: "m18 15-6-6-6 6", key: "153udz" }]];
143
+ var ChevronUp = createLucideIcon("chevron-up", __iconNode3);
144
+
145
+ // ../../node_modules/.pnpm/lucide-react@0.554.0/node_modules/lucide-react/dist/esm/icons/download.js
146
+ var __iconNode4 = [
147
+ ["path", { d: "M12 15V3", key: "m9g1x1" }],
148
+ ["path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4", key: "ih7n3h" }],
149
+ ["path", { d: "m7 10 5 5 5-5", key: "brsn70" }]
150
+ ];
151
+ var Download = createLucideIcon("download", __iconNode4);
152
+
153
+ // ../../node_modules/.pnpm/lucide-react@0.554.0/node_modules/lucide-react/dist/esm/icons/external-link.js
154
+ var __iconNode5 = [
155
+ ["path", { d: "M15 3h6v6", key: "1q9fwt" }],
156
+ ["path", { d: "M10 14 21 3", key: "gplh6r" }],
157
+ ["path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6", key: "a6xqqp" }]
158
+ ];
159
+ var ExternalLink = createLucideIcon("external-link", __iconNode5);
160
+
161
+ // ../../node_modules/.pnpm/lucide-react@0.554.0/node_modules/lucide-react/dist/esm/icons/loader-circle.js
162
+ var __iconNode6 = [["path", { d: "M21 12a9 9 0 1 1-6.219-8.56", key: "13zald" }]];
163
+ var LoaderCircle = createLucideIcon("loader-circle", __iconNode6);
164
+
165
+ // ../../node_modules/.pnpm/lucide-react@0.554.0/node_modules/lucide-react/dist/esm/icons/plus.js
166
+ var __iconNode7 = [
167
+ ["path", { d: "M5 12h14", key: "1ays0h" }],
168
+ ["path", { d: "M12 5v14", key: "s699le" }]
169
+ ];
170
+ var Plus = createLucideIcon("plus", __iconNode7);
171
+
172
+ // ../../node_modules/.pnpm/lucide-react@0.554.0/node_modules/lucide-react/dist/esm/icons/refresh-cw.js
173
+ var __iconNode8 = [
174
+ ["path", { d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8", key: "v9h5vc" }],
175
+ ["path", { d: "M21 3v5h-5", key: "1q7to0" }],
176
+ ["path", { d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16", key: "3uifl3" }],
177
+ ["path", { d: "M8 16H3v5", key: "1cv678" }]
178
+ ];
179
+ var RefreshCw = createLucideIcon("refresh-cw", __iconNode8);
180
+
181
+ // ../../node_modules/.pnpm/lucide-react@0.554.0/node_modules/lucide-react/dist/esm/icons/rotate-cw.js
182
+ var __iconNode9 = [
183
+ ["path", { d: "M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8", key: "1p45f6" }],
184
+ ["path", { d: "M21 3v5h-5", key: "1q7to0" }]
185
+ ];
186
+ var RotateCw = createLucideIcon("rotate-cw", __iconNode9);
187
+
188
+ // ../../node_modules/.pnpm/lucide-react@0.554.0/node_modules/lucide-react/dist/esm/icons/search.js
189
+ var __iconNode10 = [
190
+ ["path", { d: "m21 21-4.34-4.34", key: "14j7rj" }],
191
+ ["circle", { cx: "11", cy: "11", r: "8", key: "4ej97u" }]
192
+ ];
193
+ var Search = createLucideIcon("search", __iconNode10);
194
+
195
+ // ../../node_modules/.pnpm/lucide-react@0.554.0/node_modules/lucide-react/dist/esm/icons/settings-2.js
196
+ var __iconNode11 = [
197
+ ["path", { d: "M14 17H5", key: "gfn3mx" }],
198
+ ["path", { d: "M19 7h-9", key: "6i9tg" }],
199
+ ["circle", { cx: "17", cy: "17", r: "3", key: "18b49y" }],
200
+ ["circle", { cx: "7", cy: "7", r: "3", key: "dfmy0x" }]
201
+ ];
202
+ var Settings2 = createLucideIcon("settings-2", __iconNode11);
203
+
204
+ // ../../node_modules/.pnpm/lucide-react@0.554.0/node_modules/lucide-react/dist/esm/icons/sparkles.js
205
+ var __iconNode12 = [
206
+ [
207
+ "path",
208
+ {
209
+ d: "M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z",
210
+ key: "1s2grr"
211
+ }
212
+ ],
213
+ ["path", { d: "M20 2v4", key: "1rf3ol" }],
214
+ ["path", { d: "M22 4h-4", key: "gwowj6" }],
215
+ ["circle", { cx: "4", cy: "20", r: "2", key: "6kqj1y" }]
216
+ ];
217
+ var Sparkles = createLucideIcon("sparkles", __iconNode12);
218
+
219
+ // ../../node_modules/.pnpm/lucide-react@0.554.0/node_modules/lucide-react/dist/esm/icons/x.js
220
+ var __iconNode13 = [
221
+ ["path", { d: "M18 6 6 18", key: "1bl5f8" }],
222
+ ["path", { d: "m6 6 12 12", key: "d8bk6v" }]
223
+ ];
224
+ var X = createLucideIcon("x", __iconNode13);
225
+
226
+ // src/client/recommend-dock.tsx
227
+ var import_react3 = require("react");
228
+
229
+ // src/client/types.ts
230
+ function errorText(body) {
231
+ if (body === null || typeof body !== "object" || !("error" in body)) return void 0;
232
+ const error = body.error;
233
+ if (typeof error === "string" && error.trim() !== "") return error;
234
+ if (error !== null && typeof error === "object" && "message" in error && typeof error.message === "string") {
235
+ return error.message;
236
+ }
237
+ return void 0;
238
+ }
239
+ function record(value) {
240
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
241
+ return value;
242
+ }
243
+ function stringValue(value) {
244
+ return typeof value === "string" ? value.trim() : "";
245
+ }
246
+ function sourceValue(value) {
247
+ return value === "agentero" || value === "dsh" ? value : "none";
248
+ }
249
+ function settingsFrom(body) {
250
+ const root = record(body);
251
+ const embedding = record(root?.embedding);
252
+ const zhihu = record(root?.zhihu);
253
+ if (root === void 0 || embedding === void 0 || zhihu === void 0) {
254
+ throw new Error("invalid recommend settings");
255
+ }
256
+ return {
257
+ vaultConfigured: root.vaultConfigured === true,
258
+ embedding: {
259
+ configured: embedding.configured === true,
260
+ baseUrl: stringValue(embedding.baseUrl),
261
+ model: stringValue(embedding.model),
262
+ keyPresent: embedding.keyPresent === true,
263
+ source: sourceValue(embedding.source)
264
+ },
265
+ zhihu: {
266
+ configured: zhihu.configured === true,
267
+ source: sourceValue(zhihu.source)
268
+ }
269
+ };
270
+ }
271
+ function arxivFrom(body) {
272
+ const root = record(body);
273
+ const result = record(root?.result);
274
+ if (result === void 0) return null;
275
+ const itemsRaw = Array.isArray(result.items) ? result.items : [];
276
+ const items = [];
277
+ for (const entry of itemsRaw) {
278
+ const item = record(entry);
279
+ if (item === void 0) continue;
280
+ const arxivId = stringValue(item.arxivId);
281
+ const title = stringValue(item.title);
282
+ const url = stringValue(item.url);
283
+ if (arxivId === "" || title === "" || url === "") continue;
284
+ items.push({
285
+ arxivId,
286
+ title,
287
+ abstract: stringValue(item.abstract),
288
+ url,
289
+ ...stringValue(item.publishedAt) !== "" ? { publishedAt: stringValue(item.publishedAt) } : {},
290
+ score: typeof item.score === "number" && Number.isFinite(item.score) ? item.score : 0
291
+ });
292
+ }
293
+ return {
294
+ items,
295
+ computedAt: stringValue(result.computedAt),
296
+ categories: Array.isArray(result.categories) ? result.categories.filter((value) => typeof value === "string" && value.trim() !== "") : [],
297
+ corpusSize: typeof result.corpusSize === "number" && Number.isFinite(result.corpusSize) ? result.corpusSize : 0,
298
+ reusedCache: result.reusedCache === true
299
+ };
300
+ }
301
+ function zhihuFrom(body) {
302
+ const root = record(body);
303
+ const itemsRaw = root?.items;
304
+ if (!Array.isArray(itemsRaw)) throw new Error("invalid zhihu response");
305
+ const out = [];
306
+ for (const entry of itemsRaw) {
307
+ const item = record(entry);
308
+ if (item === void 0) continue;
309
+ const title = stringValue(item.title);
310
+ const url = stringValue(item.url);
311
+ if (title === "" || url === "") continue;
312
+ out.push({
313
+ kind: item.kind === "answer" ? "answer" : "article",
314
+ title,
315
+ url,
316
+ excerpt: stringValue(item.excerpt),
317
+ author: stringValue(item.author),
318
+ votes: typeof item.votes === "number" && Number.isFinite(item.votes) ? item.votes : 0,
319
+ score: typeof item.score === "number" && Number.isFinite(item.score) ? item.score : 0
320
+ });
321
+ }
322
+ return out;
323
+ }
324
+ function probeFrom(body) {
325
+ const root = record(body);
326
+ const dim = root?.dim;
327
+ const latencyMs = root?.latencyMs;
328
+ if (typeof dim !== "number" || !Number.isFinite(dim) || typeof latencyMs !== "number" || !Number.isFinite(latencyMs)) {
329
+ throw new Error("invalid probe response");
330
+ }
331
+ return { dim, latencyMs };
332
+ }
333
+ function reasonOf(message) {
334
+ if (message === "recommend.no_embedding") return "noEmbedding";
335
+ if (message === "recommend.probe_failed") return "probeFailed";
336
+ if (message === "recommend.empty_corpus") return "emptyCorpus";
337
+ if (message === "recommend.no_candidates") return "noCandidates";
338
+ if (message === "zhihu.no_secret") return "noSecret";
339
+ if (message === "zhihu.empty_query") return "emptyQuery";
340
+ return "other";
341
+ }
342
+ function shown(message, t) {
343
+ const reason = reasonOf(message);
344
+ if (reason === "noEmbedding") return t("needsEmbedding");
345
+ if (reason === "probeFailed") return t("probeFailed");
346
+ if (reason === "emptyCorpus") return t("needsCorpus");
347
+ if (reason === "noCandidates") return t("noCandidates");
348
+ if (reason === "noSecret") return t("zhihuNoSecret");
349
+ if (reason === "emptyQuery") return t("zhihuEmptyQuery");
350
+ if (message === "vault is not configured") return t("vaultMissing");
351
+ if (message === "") return t("actionFailed");
352
+ return message;
353
+ }
354
+ function messageOf(error) {
355
+ return error instanceof Error ? error.message : String(error);
356
+ }
357
+
358
+ // src/client/recommend-dock.tsx
359
+ var import_jsx_runtime = require("react/jsx-runtime");
360
+ var DEFAULT_CATEGORIES = ["cs.AI", "cs.CL", "cs.LG", "cs.CV", "stat.ML"];
361
+ var CATEGORIES_KEY = "agentero:recommend:categories";
362
+ var COLLAPSED_KEY = "agentero:recommend:collapsed";
363
+ function cx(...parts) {
364
+ return parts.filter((part) => typeof part === "string" && part !== "").join(" ");
365
+ }
366
+ function readJsonStorage(key) {
367
+ try {
368
+ const raw = window.localStorage.getItem(key);
369
+ return raw === null ? void 0 : JSON.parse(raw);
370
+ } catch {
371
+ return void 0;
372
+ }
373
+ }
374
+ function writeStorage(key, value) {
375
+ try {
376
+ window.localStorage.setItem(key, JSON.stringify(value));
377
+ } catch {
378
+ }
379
+ }
380
+ function loadCategories() {
381
+ const parsed = readJsonStorage(CATEGORIES_KEY);
382
+ if (Array.isArray(parsed)) {
383
+ const values = parsed.filter((value) => typeof value === "string" && value.trim() !== "");
384
+ if (values.length > 0) return values;
385
+ }
386
+ return [...DEFAULT_CATEGORIES];
387
+ }
388
+ function loadCollapsed() {
389
+ return readJsonStorage(COLLAPSED_KEY) === true;
390
+ }
391
+ function formatTime(value) {
392
+ if (value === "") return "";
393
+ const date = new Date(value);
394
+ if (Number.isNaN(date.getTime())) return "";
395
+ return date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
396
+ }
397
+ function IconButton({
398
+ label,
399
+ children,
400
+ onClick,
401
+ disabled,
402
+ pressed
403
+ }) {
404
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
405
+ "button",
406
+ {
407
+ type: "button",
408
+ "aria-label": label,
409
+ title: label,
410
+ "aria-pressed": pressed,
411
+ disabled,
412
+ onClick,
413
+ className: cx(
414
+ "inline-flex size-6 shrink-0 items-center justify-center rounded-md border-0 bg-transparent p-0 text-muted-foreground transition-colors",
415
+ "hover:bg-muted hover:text-foreground disabled:pointer-events-none disabled:opacity-50"
416
+ ),
417
+ children
418
+ }
419
+ );
420
+ }
421
+ function TextButton({
422
+ children,
423
+ onClick,
424
+ disabled,
425
+ primary
426
+ }) {
427
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
428
+ "button",
429
+ {
430
+ type: "button",
431
+ disabled,
432
+ onClick,
433
+ className: cx(
434
+ "inline-flex h-6 shrink-0 items-center gap-1 rounded-md px-2 text-caption transition-colors",
435
+ "disabled:pointer-events-none disabled:opacity-50",
436
+ primary ? "border-0 bg-primary text-primary-foreground hover:bg-primary/80" : "border border-border bg-background hover:bg-muted hover:text-foreground"
437
+ ),
438
+ children
439
+ }
440
+ );
441
+ }
442
+ function StatusCard({ text, actions }) {
443
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex w-full flex-wrap items-center gap-x-2 gap-y-1.5 rounded-lg border border-dashed border-border px-2.5 py-1.5", children: [
444
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "min-w-0 flex-1 text-caption leading-relaxed text-muted-foreground", children: text }),
445
+ actions === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex shrink-0 items-center gap-1.5", children: actions })
446
+ ] });
447
+ }
448
+ function ArxivCard({
449
+ t,
450
+ item,
451
+ imported,
452
+ importing,
453
+ onImport
454
+ }) {
455
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
456
+ "article",
457
+ {
458
+ className: cx(
459
+ "group flex w-64 shrink-0 flex-col rounded-lg border bg-background px-2.5 py-2",
460
+ "transition-colors hover:border-border hover:bg-muted/40"
461
+ ),
462
+ children: [
463
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { className: "line-clamp-2 text-sm font-medium leading-snug", title: item.title, children: item.title }),
464
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "mt-1 line-clamp-2 text-xs leading-snug text-muted-foreground", children: item.abstract }),
465
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mt-auto flex min-w-0 items-center gap-1.5 pt-1.5 text-caption text-muted-foreground", children: [
466
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "truncate font-mono", children: item.arxivId }),
467
+ item.publishedAt === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
468
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
469
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "truncate", children: item.publishedAt })
470
+ ] }),
471
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "ml-auto flex shrink-0 items-center gap-0.5", children: [
472
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
473
+ "a",
474
+ {
475
+ href: item.url,
476
+ target: "_blank",
477
+ rel: "noreferrer",
478
+ "aria-label": t("open"),
479
+ title: t("open"),
480
+ className: "inline-flex size-6 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
481
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ExternalLink, { className: "size-3" })
482
+ }
483
+ ),
484
+ imported ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "inline-flex size-6 items-center justify-center text-muted-foreground", title: t("imported"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Check, { className: "size-3" }) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconButton, { label: importing ? t("importing") : t("import"), onClick: onImport, disabled: importing, children: importing ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoaderCircle, { className: "size-3 animate-spin" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Download, { className: "size-3" }) })
485
+ ] })
486
+ ] })
487
+ ]
488
+ }
489
+ );
490
+ }
491
+ function ZhihuCard({ t, item }) {
492
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
493
+ "a",
494
+ {
495
+ href: item.url,
496
+ target: "_blank",
497
+ rel: "noreferrer",
498
+ className: cx(
499
+ "group flex w-64 shrink-0 flex-col gap-1 rounded-lg border bg-background px-2.5 py-2 text-left",
500
+ "transition-colors hover:border-border hover:bg-muted/40"
501
+ ),
502
+ children: [
503
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-start justify-between gap-2", children: [
504
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "line-clamp-2 text-sm font-medium leading-snug text-foreground", children: item.title }),
505
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "mt-0.5 shrink-0 rounded bg-muted px-1.5 py-0.5 text-caption text-muted-foreground", children: item.kind === "answer" ? t("answer") : t("article") })
506
+ ] }),
507
+ item.excerpt === "" ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "line-clamp-2 text-xs leading-relaxed text-muted-foreground", children: item.excerpt }),
508
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mt-auto flex items-center gap-1.5 pt-0.5 text-caption text-muted-foreground", children: [
509
+ item.author === "" ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "truncate", children: item.author }),
510
+ item.author === "" ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { "aria-hidden": true, children: "\xB7" }),
511
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "tabular-nums", children: t("votes", { votes: item.votes.toLocaleString() }) })
512
+ ] })
513
+ ]
514
+ }
515
+ );
516
+ }
517
+ function RecommendDock({
518
+ t,
519
+ loadSettings,
520
+ saveSettings,
521
+ probeEmbedding,
522
+ loadArxiv,
523
+ recommendArxiv,
524
+ searchZhihu,
525
+ importPaper
526
+ }) {
527
+ const [collapsed, setCollapsed] = (0, import_react3.useState)(loadCollapsed);
528
+ const [tab, setTab] = (0, import_react3.useState)("arxiv");
529
+ const [settings, setSettings] = (0, import_react3.useState)(null);
530
+ const [settingsOpen, setSettingsOpen] = (0, import_react3.useState)(false);
531
+ const [settingsError, setSettingsError] = (0, import_react3.useState)("");
532
+ const [settingsBusy, setSettingsBusy] = (0, import_react3.useState)(false);
533
+ const [settingsSaved, setSettingsSaved] = (0, import_react3.useState)(false);
534
+ const [baseUrl, setBaseUrl] = (0, import_react3.useState)("");
535
+ const [apiKey, setApiKey] = (0, import_react3.useState)("");
536
+ const [model, setModel] = (0, import_react3.useState)("");
537
+ const [zhihuSecret, setZhihuSecret] = (0, import_react3.useState)("");
538
+ const [categories, setCategories] = (0, import_react3.useState)(loadCategories);
539
+ const [categoryDraft, setCategoryDraft] = (0, import_react3.useState)("");
540
+ const [arxivBusy, setArxivBusy] = (0, import_react3.useState)(false);
541
+ const [arxivStep, setArxivStep] = (0, import_react3.useState)("probe");
542
+ const [arxivResult, setArxivResult] = (0, import_react3.useState)(null);
543
+ const [arxivMessage, setArxivMessage] = (0, import_react3.useState)("");
544
+ const [banner, setBanner] = (0, import_react3.useState)("");
545
+ const [importingId, setImportingId] = (0, import_react3.useState)("");
546
+ const [imported, setImported] = (0, import_react3.useState)({});
547
+ const [zhihuQuery, setZhihuQuery] = (0, import_react3.useState)("");
548
+ const [zhihuBusy, setZhihuBusy] = (0, import_react3.useState)(false);
549
+ const [zhihuItems, setZhihuItems] = (0, import_react3.useState)(null);
550
+ const [zhihuMessage, setZhihuMessage] = (0, import_react3.useState)("");
551
+ const loadedRef = (0, import_react3.useRef)(false);
552
+ const hasArxivResult = arxivResult !== null && arxivResult.items.length > 0;
553
+ (0, import_react3.useEffect)(() => {
554
+ let cancelled = false;
555
+ loadSettings().then((next) => {
556
+ if (cancelled) return;
557
+ setSettings(next);
558
+ setBaseUrl(next.embedding.baseUrl);
559
+ setModel(next.embedding.model);
560
+ setSettingsError("");
561
+ }).catch((error) => {
562
+ if (cancelled) return;
563
+ const message = messageOf(error);
564
+ setSettingsError(message);
565
+ setArxivMessage(message);
566
+ });
567
+ return () => {
568
+ cancelled = true;
569
+ };
570
+ }, [loadSettings]);
571
+ const loadStored = async (nextCategories) => {
572
+ setArxivBusy(true);
573
+ setArxivStep("probe");
574
+ setArxivMessage("");
575
+ try {
576
+ await probeEmbedding();
577
+ const stored = await loadArxiv(nextCategories);
578
+ if (stored !== null) setArxivResult(stored);
579
+ } catch (error) {
580
+ setArxivMessage(messageOf(error));
581
+ } finally {
582
+ setArxivBusy(false);
583
+ }
584
+ };
585
+ const runArxiv = async (nextCategories = categories) => {
586
+ setArxivBusy(true);
587
+ setArxivStep("probe");
588
+ setArxivMessage("");
589
+ setBanner("");
590
+ try {
591
+ await probeEmbedding();
592
+ setArxivStep("compute");
593
+ const result = await recommendArxiv(nextCategories);
594
+ setArxivResult(result);
595
+ } catch (error) {
596
+ setArxivMessage(messageOf(error));
597
+ } finally {
598
+ setArxivBusy(false);
599
+ }
600
+ };
601
+ (0, import_react3.useEffect)(() => {
602
+ if (loadedRef.current || settings === null) return;
603
+ loadedRef.current = true;
604
+ if (!settings.vaultConfigured) {
605
+ setArxivMessage("vault is not configured");
606
+ return;
607
+ }
608
+ if (!settings.embedding.configured) {
609
+ setArxivMessage("recommend.no_embedding");
610
+ return;
611
+ }
612
+ void loadStored(categories);
613
+ }, [settings]);
614
+ const runZhihu = async (query) => {
615
+ const trimmed = query.trim();
616
+ if (trimmed === "") {
617
+ setZhihuMessage("zhihu.empty_query");
618
+ return;
619
+ }
620
+ if (settings !== null && !settings.zhihu.configured) {
621
+ setZhihuMessage("zhihu.no_secret");
622
+ return;
623
+ }
624
+ setZhihuBusy(true);
625
+ setZhihuMessage("");
626
+ try {
627
+ setZhihuItems(await searchZhihu(trimmed, 10));
628
+ } catch (error) {
629
+ setZhihuItems(null);
630
+ setZhihuMessage(messageOf(error));
631
+ } finally {
632
+ setZhihuBusy(false);
633
+ }
634
+ };
635
+ const toggleCollapsed = () => {
636
+ setCollapsed((value) => {
637
+ writeStorage(COLLAPSED_KEY, !value);
638
+ return !value;
639
+ });
640
+ };
641
+ const addCategory = () => {
642
+ const value = categoryDraft.trim();
643
+ if (value === "" || value.length > 40) return;
644
+ if (categories.some((category) => category.toLowerCase() === value.toLowerCase())) {
645
+ setCategoryDraft("");
646
+ return;
647
+ }
648
+ const next = [...categories, value];
649
+ setCategories(next);
650
+ writeStorage(CATEGORIES_KEY, next);
651
+ setCategoryDraft("");
652
+ void runArxiv(next);
653
+ };
654
+ const removeCategory = (category) => {
655
+ if (categories.length <= 1) return;
656
+ const next = categories.filter((value) => value !== category);
657
+ setCategories(next);
658
+ writeStorage(CATEGORIES_KEY, next);
659
+ void runArxiv(next);
660
+ };
661
+ const save = () => {
662
+ setSettingsBusy(true);
663
+ setSettingsSaved(false);
664
+ const patch = {};
665
+ if (baseUrl.trim() !== "") patch.embeddingBaseUrl = baseUrl.trim();
666
+ if (model.trim() !== "") patch.embeddingModel = model.trim();
667
+ if (apiKey.trim() !== "") patch.embeddingApiKey = apiKey.trim();
668
+ if (zhihuSecret.trim() !== "") patch.zhihuAccessSecret = zhihuSecret.trim();
669
+ saveSettings(patch).then((next) => {
670
+ setSettings(next);
671
+ setBaseUrl(next.embedding.baseUrl);
672
+ setModel(next.embedding.model);
673
+ setApiKey("");
674
+ setZhihuSecret("");
675
+ setSettingsError("");
676
+ setSettingsSaved(true);
677
+ if (next.embedding.configured) void loadStored(categories);
678
+ }).catch((error) => {
679
+ setSettingsError(messageOf(error));
680
+ }).finally(() => {
681
+ setSettingsBusy(false);
682
+ });
683
+ };
684
+ const importArxiv = (item) => {
685
+ setImportingId(item.arxivId);
686
+ setBanner("");
687
+ importPaper(item.url).then(() => {
688
+ setImported((current) => ({ ...current, [item.arxivId]: true }));
689
+ }).catch((error) => {
690
+ setBanner(shown(messageOf(error), t));
691
+ }).finally(() => {
692
+ setImportingId("");
693
+ });
694
+ };
695
+ const retry = () => {
696
+ setArxivMessage("");
697
+ if (settings !== null && !settings.embedding.configured) {
698
+ setSettingsOpen(true);
699
+ return;
700
+ }
701
+ void runArxiv();
702
+ };
703
+ let arxivBody;
704
+ if (arxivBusy) {
705
+ arxivBody = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
706
+ StatusCard,
707
+ {
708
+ text: arxivStep === "probe" ? t("probing") : t("computing"),
709
+ actions: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoaderCircle, { className: "size-3 animate-spin text-muted-foreground" })
710
+ }
711
+ );
712
+ } else if (hasArxivResult && arxivResult !== null) {
713
+ arxivBody = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
714
+ banner === "" ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "mb-1 text-caption text-destructive", children: banner }),
715
+ arxivMessage === "" ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "mb-1 text-caption text-destructive", children: shown(arxivMessage, t) }),
716
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex items-stretch gap-2 overflow-x-auto pb-0.5", children: arxivResult.items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
717
+ ArxivCard,
718
+ {
719
+ t,
720
+ item,
721
+ imported: imported[item.arxivId] === true,
722
+ importing: importingId === item.arxivId,
723
+ onImport: () => {
724
+ importArxiv(item);
725
+ }
726
+ },
727
+ item.arxivId
728
+ )) })
729
+ ] });
730
+ } else {
731
+ const reason = reasonOf(arxivMessage);
732
+ const canSettings = reason === "noEmbedding";
733
+ const quiet = arxivMessage === "vault is not configured";
734
+ arxivBody = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
735
+ StatusCard,
736
+ {
737
+ text: arxivMessage === "" ? t("idle") : shown(arxivMessage, t),
738
+ actions: quiet ? void 0 : canSettings ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TextButton, { onClick: () => {
739
+ setSettingsOpen(true);
740
+ }, primary: true, children: t("openSettings") }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(TextButton, { onClick: retry, primary: true, children: [
741
+ reason === "probeFailed" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RotateCw, { className: "size-3" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RefreshCw, { className: "size-3" }),
742
+ arxivMessage === "" ? t("refresh") : t("retry")
743
+ ] })
744
+ }
745
+ );
746
+ }
747
+ let zhihuBody;
748
+ if (settings !== null && !settings.zhihu.configured) {
749
+ zhihuBody = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
750
+ StatusCard,
751
+ {
752
+ text: t("zhihuNoSecret"),
753
+ actions: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TextButton, { onClick: () => {
754
+ setSettingsOpen(true);
755
+ }, children: t("openSettings") })
756
+ }
757
+ );
758
+ } else if (zhihuBusy) {
759
+ zhihuBody = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
760
+ StatusCard,
761
+ {
762
+ text: t("zhihuLoading"),
763
+ actions: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoaderCircle, { className: "size-3 animate-spin text-muted-foreground" })
764
+ }
765
+ );
766
+ } else if (zhihuMessage !== "") {
767
+ zhihuBody = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
768
+ StatusCard,
769
+ {
770
+ text: shown(zhihuMessage, t),
771
+ actions: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(TextButton, { onClick: () => {
772
+ void runZhihu(zhihuQuery);
773
+ }, children: [
774
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RotateCw, { className: "size-3" }),
775
+ t("retry")
776
+ ] })
777
+ }
778
+ );
779
+ } else if (zhihuItems === null) {
780
+ zhihuBody = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatusCard, { text: t("zhihuHint") });
781
+ } else if (zhihuItems.length === 0) {
782
+ zhihuBody = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
783
+ StatusCard,
784
+ {
785
+ text: t("zhihuEmpty"),
786
+ actions: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(TextButton, { onClick: () => {
787
+ void runZhihu(zhihuQuery);
788
+ }, children: [
789
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RefreshCw, { className: "size-3" }),
790
+ t("zhihuRefresh")
791
+ ] })
792
+ }
793
+ );
794
+ } else {
795
+ zhihuBody = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
796
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "mb-1 text-caption text-muted-foreground", children: t("zhihuNote") }),
797
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex items-stretch gap-2 overflow-x-auto pb-0.5", children: zhihuItems.map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ZhihuCard, { t, item }, item.url)) }),
798
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "mt-1 flex justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(TextButton, { onClick: () => {
799
+ void runZhihu(zhihuQuery);
800
+ }, children: [
801
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RefreshCw, { className: "size-3" }),
802
+ t("zhihuRefresh")
803
+ ] }) })
804
+ ] });
805
+ }
806
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "agentero-recommend agentero-surface order-1 w-full min-w-0 pb-1 text-foreground [&_*]:box-border", children: [
807
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex min-w-0 items-center gap-1.5", children: [
808
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Sparkles, { className: "size-3.5 shrink-0 text-[#C792EA]", "aria-hidden": true }),
809
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "shrink-0 text-caption font-medium text-foreground/80", children: t("title") }),
810
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex shrink-0 items-center gap-0.5", children: ["arxiv", "zhihu"].map((value) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
811
+ "button",
812
+ {
813
+ type: "button",
814
+ "aria-pressed": tab === value,
815
+ onClick: () => {
816
+ setTab(value);
817
+ },
818
+ className: cx(
819
+ "inline-flex h-6 items-center rounded-md border-0 p-0 px-2 text-caption transition-colors",
820
+ tab === value ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted/60 hover:text-foreground"
821
+ ),
822
+ children: value === "arxiv" ? t("arxivTab") : t("zhihuTab")
823
+ },
824
+ value
825
+ )) }),
826
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "ml-auto flex min-w-0 items-center gap-1.5 text-caption text-muted-foreground", children: [
827
+ tab === "arxiv" && hasArxivResult && arxivResult !== null ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "truncate", children: [
828
+ t("corpusCount", { count: arxivResult.corpusSize }),
829
+ formatTime(arxivResult.computedAt) === "" ? "" : ` \xB7 ${t("updatedAt", { time: formatTime(arxivResult.computedAt) })}`
830
+ ] }) : null,
831
+ tab === "arxiv" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
832
+ IconButton,
833
+ {
834
+ label: t("refresh"),
835
+ disabled: arxivBusy,
836
+ onClick: () => {
837
+ void runArxiv();
838
+ },
839
+ children: arxivBusy ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoaderCircle, { className: "size-3.5 animate-spin" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RefreshCw, { className: "size-3.5" })
840
+ }
841
+ ) : null,
842
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
843
+ IconButton,
844
+ {
845
+ label: t("settings"),
846
+ pressed: settingsOpen,
847
+ onClick: () => {
848
+ setSettingsOpen((value) => !value);
849
+ },
850
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Settings2, { className: "size-3.5" })
851
+ }
852
+ ),
853
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconButton, { label: collapsed ? t("expand") : t("collapse"), onClick: toggleCollapsed, children: collapsed ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronUp, { className: "size-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronDown, { className: "size-3.5" }) })
854
+ ] })
855
+ ] }),
856
+ collapsed ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
857
+ settingsOpen ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mt-1.5 rounded-lg border bg-background p-2", children: [
858
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mb-1.5 flex items-start justify-between gap-2", children: [
859
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-caption leading-relaxed text-muted-foreground", children: t("settingsDescription") }),
860
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconButton, { label: t("close"), onClick: () => {
861
+ setSettingsOpen(false);
862
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(X, { className: "size-3.5" }) })
863
+ ] }),
864
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mt-1.5 grid gap-1.5 sm:grid-cols-2 lg:grid-cols-4", children: [
865
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "grid min-w-0 gap-0.5 text-caption text-muted-foreground", children: [
866
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "truncate", children: t("baseUrl") }),
867
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
868
+ "input",
869
+ {
870
+ value: baseUrl,
871
+ onChange: (event) => {
872
+ setBaseUrl(event.target.value);
873
+ },
874
+ placeholder: "https://api.openai.com/v1",
875
+ spellCheck: false,
876
+ className: "h-6 w-full rounded-md border border-input bg-transparent px-1.5 text-caption text-foreground outline-none focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/40"
877
+ }
878
+ )
879
+ ] }),
880
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "grid min-w-0 gap-0.5 text-caption text-muted-foreground", children: [
881
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "truncate", children: t("model") }),
882
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
883
+ "input",
884
+ {
885
+ value: model,
886
+ onChange: (event) => {
887
+ setModel(event.target.value);
888
+ },
889
+ placeholder: "text-embedding-3-small",
890
+ spellCheck: false,
891
+ className: "h-6 w-full rounded-md border border-input bg-transparent px-1.5 text-caption text-foreground outline-none focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/40"
892
+ }
893
+ )
894
+ ] }),
895
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "grid min-w-0 gap-0.5 text-caption text-muted-foreground", children: [
896
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "truncate", children: [
897
+ t("apiKey"),
898
+ " \xB7 ",
899
+ settings?.embedding.keyPresent === true ? t("keyConfigured") : t("keyMissing")
900
+ ] }),
901
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
902
+ "input",
903
+ {
904
+ type: "password",
905
+ value: apiKey,
906
+ onChange: (event) => {
907
+ setApiKey(event.target.value);
908
+ },
909
+ placeholder: t("keepBlank"),
910
+ autoComplete: "off",
911
+ spellCheck: false,
912
+ className: "h-6 w-full rounded-md border border-input bg-transparent px-1.5 text-caption text-foreground outline-none focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/40"
913
+ }
914
+ )
915
+ ] }),
916
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "grid min-w-0 gap-0.5 text-caption text-muted-foreground", children: [
917
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "truncate", children: [
918
+ t("zhihuSecret"),
919
+ " \xB7 ",
920
+ settings?.zhihu.configured === true ? t("secretConfigured") : t("secretMissing")
921
+ ] }),
922
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
923
+ "input",
924
+ {
925
+ type: "password",
926
+ value: zhihuSecret,
927
+ onChange: (event) => {
928
+ setZhihuSecret(event.target.value);
929
+ },
930
+ placeholder: t("keepBlank"),
931
+ autoComplete: "off",
932
+ spellCheck: false,
933
+ className: "h-6 w-full rounded-md border border-input bg-transparent px-1.5 text-caption text-foreground outline-none focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/40"
934
+ }
935
+ )
936
+ ] })
937
+ ] }),
938
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mt-1.5 flex min-w-0 flex-wrap items-center gap-1", children: [
939
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "shrink-0 text-caption text-muted-foreground", children: t("categories") }),
940
+ categories.map((category) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
941
+ "span",
942
+ {
943
+ className: "group inline-flex shrink-0 items-center gap-0.5 rounded-full border border-primary/40 bg-primary/10 py-0.5 pl-2 pr-0.5 font-mono text-caption text-foreground",
944
+ children: [
945
+ category,
946
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
947
+ "button",
948
+ {
949
+ type: "button",
950
+ disabled: categories.length <= 1 || arxivBusy,
951
+ "aria-label": t("removeCategory", { category }),
952
+ onClick: () => {
953
+ removeCategory(category);
954
+ },
955
+ className: "rounded-full border-0 bg-transparent p-0.5 hover:bg-foreground/10 disabled:pointer-events-none disabled:opacity-30",
956
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(X, { className: "size-2.5" })
957
+ }
958
+ )
959
+ ]
960
+ },
961
+ category
962
+ )),
963
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
964
+ "form",
965
+ {
966
+ className: "inline-flex shrink-0 items-center gap-1",
967
+ onSubmit: (event) => {
968
+ event.preventDefault();
969
+ addCategory();
970
+ },
971
+ children: [
972
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
973
+ "input",
974
+ {
975
+ value: categoryDraft,
976
+ onChange: (event) => {
977
+ setCategoryDraft(event.target.value);
978
+ },
979
+ placeholder: t("categoryPlaceholder"),
980
+ spellCheck: false,
981
+ className: "h-5 w-20 rounded-md border border-dashed border-border bg-transparent px-1.5 font-mono text-caption outline-none placeholder:text-muted-foreground/70 focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/40"
982
+ }
983
+ ),
984
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconButton, { label: t("addCategory"), onClick: addCategory, disabled: arxivBusy, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Plus, { className: "size-3" }) })
985
+ ]
986
+ }
987
+ )
988
+ ] }),
989
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mt-1.5 flex items-center gap-2", children: [
990
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
991
+ "button",
992
+ {
993
+ type: "button",
994
+ disabled: settingsBusy,
995
+ onClick: save,
996
+ className: "inline-flex h-6 items-center gap-1 rounded-md border-0 bg-primary px-2 text-caption text-primary-foreground transition-colors hover:bg-primary/80 disabled:pointer-events-none disabled:opacity-50",
997
+ children: [
998
+ settingsBusy ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoaderCircle, { className: "size-3 animate-spin" }) : null,
999
+ settingsBusy ? t("saving") : t("save")
1000
+ ]
1001
+ }
1002
+ ),
1003
+ settingsSaved ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-caption text-muted-foreground", children: t("saved") }) : null,
1004
+ settingsError === "" ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "min-w-0 truncate text-caption text-destructive", title: settingsError, children: shown(settingsError, t) })
1005
+ ] })
1006
+ ] }) : null,
1007
+ tab === "arxiv" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "mt-1.5", children: arxivBody }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
1008
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1009
+ "form",
1010
+ {
1011
+ className: "mt-1.5 flex items-center gap-1.5",
1012
+ onSubmit: (event) => {
1013
+ event.preventDefault();
1014
+ void runZhihu(zhihuQuery);
1015
+ },
1016
+ children: [
1017
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "relative min-w-0 flex-1", children: [
1018
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Search, { className: "pointer-events-none absolute left-2 top-1/2 size-3 -translate-y-1/2 text-muted-foreground" }),
1019
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1020
+ "input",
1021
+ {
1022
+ value: zhihuQuery,
1023
+ onChange: (event) => {
1024
+ setZhihuQuery(event.target.value);
1025
+ },
1026
+ placeholder: t("zhihuSearchPlaceholder"),
1027
+ className: "h-6 w-full rounded-md border border-input bg-transparent pl-7 pr-2 text-caption outline-none focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/40"
1028
+ }
1029
+ )
1030
+ ] }),
1031
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TextButton, { onClick: () => {
1032
+ void runZhihu(zhihuQuery);
1033
+ }, disabled: zhihuBusy, children: t("zhihuSearch") })
1034
+ ]
1035
+ }
1036
+ ),
1037
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "mt-1.5", children: zhihuBody })
1038
+ ] })
1039
+ ] })
1040
+ ] });
1041
+ }
1042
+
1043
+ // src/client/index.ts
1044
+ var DOCK_ID = "agentero-dsh-recommend";
1045
+ var NS = "agentero.recommend";
1046
+ var zh = {
1047
+ title: "\u63A8\u8350",
1048
+ arxivTab: "arXiv \u6BCF\u65E5",
1049
+ zhihuTab: "\u77E5\u4E4E",
1050
+ refresh: "\u91CD\u65B0\u8BA1\u7B97\u63A8\u8350",
1051
+ computing: "\u6B63\u5728\u751F\u6210\u4ECA\u65E5\u63A8\u8350\u2026",
1052
+ probing: "\u6B63\u5728\u68C0\u67E5 Embedding \u670D\u52A1\u2026",
1053
+ addCategory: "\u6DFB\u52A0\u5206\u7C7B",
1054
+ categoryPlaceholder: "\u4F8B\u5982 cs.RO",
1055
+ removeCategory: "\u79FB\u9664\u5206\u7C7B {category}",
1056
+ categories: "arXiv \u5206\u7C7B",
1057
+ expand: "\u5C55\u5F00\u63A8\u8350",
1058
+ collapse: "\u6536\u8D77\u63A8\u8350",
1059
+ settings: "\u8BBE\u7F6E",
1060
+ settingsDescription: "\u7559\u7A7A\u8868\u793A\u7EE7\u7EED\u4F7F\u7528 Agentero \u684C\u9762\u7AEF\u5DF2\u7ECF\u4FDD\u5B58\u7684\u914D\u7F6E\u3002",
1061
+ baseUrl: "Embedding Base URL",
1062
+ apiKey: "Embedding API Key",
1063
+ model: "Embedding \u6A21\u578B",
1064
+ zhihuSecret: "\u77E5\u4E4E Access Secret",
1065
+ save: "\u4FDD\u5B58",
1066
+ saving: "\u4FDD\u5B58\u4E2D\u2026",
1067
+ saved: "\u5DF2\u4FDD\u5B58",
1068
+ keyConfigured: "\u5DF2\u914D\u7F6E",
1069
+ keyMissing: "\u672A\u914D\u7F6E",
1070
+ secretConfigured: "\u5DF2\u914D\u7F6E",
1071
+ secretMissing: "\u672A\u914D\u7F6E",
1072
+ keepBlank: "\u7559\u7A7A\u4FDD\u6301\u4E0D\u53D8",
1073
+ close: "\u5173\u95ED",
1074
+ idle: "\u8FD8\u6CA1\u6709\u4ECA\u65E5\u63A8\u8350\u3002\u70B9\u5237\u65B0\uFF0C\u628A\u5F53\u5929 arXiv \u65B0\u8BBA\u6587\u4E0E\u8BBA\u6587\u5E93\u6392\u5E8F\u3002",
1075
+ needsEmbedding: "\u8BF7\u5148\u914D\u7F6E Embedding \u6A21\u578B\u2014\u2014\u63A8\u8350\u9700\u8981\u628A\u65B0\u8BBA\u6587\u6458\u8981\u4E0E\u4F60\u7684\u8BBA\u6587\u5E93\u6BD4\u5BF9\u3002",
1076
+ probeFailed: "Embedding \u670D\u52A1\u6CA1\u6709\u54CD\u5E94\u3002\u8BF7\u68C0\u67E5\u5730\u5740\u3001\u5BC6\u94A5\u548C\u6A21\u578B\u540E\u91CD\u8BD5\u3002",
1077
+ needsCorpus: "\u8BBA\u6587\u5E93\u91CC\u8FD8\u6CA1\u6709\u5E26\u6458\u8981\u7684\u8BBA\u6587\uFF0C\u6682\u65F6\u65E0\u6CD5\u6392\u5E8F\u3002",
1078
+ noCandidates: "\u4ECA\u5929\u7684 arXiv \u6E90\u6CA1\u6709\u53D6\u5230\u53EF\u7528\u8BBA\u6587\uFF0C\u7A0D\u540E\u518D\u8BD5\u3002",
1079
+ retry: "\u91CD\u8BD5",
1080
+ openSettings: "\u6253\u5F00\u8BBE\u7F6E",
1081
+ updatedAt: "\u66F4\u65B0\u4E8E {time}",
1082
+ corpusCount: "\u8BBA\u6587\u5E93 {count} \u7BC7",
1083
+ import: "\u5BFC\u5165",
1084
+ imported: "\u5DF2\u5BFC\u5165",
1085
+ importing: "\u5BFC\u5165\u4E2D\u2026",
1086
+ open: "\u6253\u5F00",
1087
+ actionFailed: "\u64CD\u4F5C\u5931\u8D25",
1088
+ vaultMissing: "\u5C1A\u672A\u914D\u7F6E Vault",
1089
+ zhihuSearchPlaceholder: "\u8BBA\u6587\u6807\u9898\u6216\u5173\u952E\u8BCD",
1090
+ zhihuSearch: "\u68C0\u7D22",
1091
+ zhihuNote: "\u6309\u5173\u952E\u8BCD\u68C0\u7D22\u77E5\u4E4E\uFF0C\u7ED3\u679C\u53EF\u80FD\u4E0E\u5F53\u524D\u8BBA\u6587\u65E0\u5173\u3002",
1092
+ zhihuEmpty: "\u6CA1\u6709\u627E\u5230\u76F8\u5173\u8BA8\u8BBA\u3002",
1093
+ zhihuLoading: "\u6B63\u5728\u68C0\u7D22\u77E5\u4E4E\u2026",
1094
+ zhihuRefresh: "\u6362\u4E00\u6279",
1095
+ answer: "\u56DE\u7B54",
1096
+ article: "\u6587\u7AE0",
1097
+ votes: "{votes} \u8D5E\u540C",
1098
+ zhihuNoSecret: "\u5C1A\u672A\u914D\u7F6E\u77E5\u4E4E Access Secret\u3002\u8BF7\u5728\u8BBE\u7F6E\u4E2D\u586B\u5165\u3002",
1099
+ zhihuEmptyQuery: "\u8BF7\u8F93\u5165\u68C0\u7D22\u5173\u952E\u8BCD\u3002",
1100
+ zhihuHint: "\u8F93\u5165\u8BBA\u6587\u6807\u9898\u6216\u5173\u952E\u8BCD\uFF0C\u770B\u770B\u77E5\u4E4E\u4E0A\u5927\u5BB6\u5728\u8BA8\u8BBA\u4EC0\u4E48\u3002"
1101
+ };
1102
+ var en = {
1103
+ title: "Recommend",
1104
+ arxivTab: "arXiv daily",
1105
+ zhihuTab: "Zhihu",
1106
+ refresh: "Recompute recommendations",
1107
+ computing: "Building today\u2019s recommendations\u2026",
1108
+ probing: "Checking the embedding service\u2026",
1109
+ addCategory: "Add category",
1110
+ categoryPlaceholder: "e.g. cs.RO",
1111
+ removeCategory: "Remove {category}",
1112
+ categories: "arXiv categories",
1113
+ expand: "Expand recommendations",
1114
+ collapse: "Collapse recommendations",
1115
+ settings: "Settings",
1116
+ settingsDescription: "Leave a field blank to keep using the value saved in the Agentero desktop app.",
1117
+ baseUrl: "Embedding base URL",
1118
+ apiKey: "Embedding API key",
1119
+ model: "Embedding model",
1120
+ zhihuSecret: "Zhihu Access Secret",
1121
+ save: "Save",
1122
+ saving: "Saving\u2026",
1123
+ saved: "Saved",
1124
+ keyConfigured: "configured",
1125
+ keyMissing: "not configured",
1126
+ secretConfigured: "configured",
1127
+ secretMissing: "not configured",
1128
+ keepBlank: "Leave blank to keep it",
1129
+ close: "Close",
1130
+ idle: "No recommendations yet. Refresh to rank today\u2019s arXiv papers against your library.",
1131
+ needsEmbedding: "Configure an embedding model first. Recommendations compare new abstracts with your library.",
1132
+ probeFailed: "The embedding service did not respond. Check the URL, key, and model, then retry.",
1133
+ needsCorpus: "The library has no papers with abstracts to compare against yet.",
1134
+ noCandidates: "The arXiv feeds returned no usable papers today. Try again later.",
1135
+ retry: "Retry",
1136
+ openSettings: "Open settings",
1137
+ updatedAt: "Updated {time}",
1138
+ corpusCount: "{count} library papers",
1139
+ import: "Import",
1140
+ imported: "Imported",
1141
+ importing: "Importing\u2026",
1142
+ open: "Open",
1143
+ actionFailed: "Action failed",
1144
+ vaultMissing: "Vault is not configured",
1145
+ zhihuSearchPlaceholder: "Paper title or keyword",
1146
+ zhihuSearch: "Search",
1147
+ zhihuNote: "Search is keyword-based; results may not discuss the current paper.",
1148
+ zhihuEmpty: "No related discussions found.",
1149
+ zhihuLoading: "Searching Zhihu\u2026",
1150
+ zhihuRefresh: "Refresh",
1151
+ answer: "Answer",
1152
+ article: "Article",
1153
+ votes: "{votes} upvotes",
1154
+ zhihuNoSecret: "No Zhihu Access Secret is configured. Add one in settings.",
1155
+ zhihuEmptyQuery: "Enter a search keyword.",
1156
+ zhihuHint: "Type a paper title or keyword to see what people discuss on Zhihu."
1157
+ };
1158
+ async function readResponse(transport, path, init) {
1159
+ const response = await transport(`/agentero/api/recommend${path}`, { cache: "no-store", ...init });
1160
+ const text = await response.text();
1161
+ let body;
1162
+ try {
1163
+ body = text.trim() === "" ? void 0 : JSON.parse(text);
1164
+ } catch {
1165
+ throw new Error(response.ok ? "invalid recommend response" : "");
1166
+ }
1167
+ if (!response.ok) throw new Error(errorText(body) ?? "");
1168
+ return body;
1169
+ }
1170
+ var name = "agentero-recommend";
1171
+ var inject = ["slots", "locale"];
1172
+ function apply(ctx) {
1173
+ ctx.effect(() => ctx.locale.register(NS, { zh, en }));
1174
+ const t = ctx.locale.bind(NS);
1175
+ let source;
1176
+ const transport = (url, init) => {
1177
+ const agentero = source ??= ctx.get("agentero");
1178
+ if (agentero === void 0) return Promise.reject(new Error(t("vaultMissing")));
1179
+ return agentero.request(url, init);
1180
+ };
1181
+ const request = (path, init) => readResponse(transport, path, init);
1182
+ const face = {
1183
+ async loadSettings() {
1184
+ return settingsFrom(await request("/settings"));
1185
+ },
1186
+ async saveSettings(patch) {
1187
+ return settingsFrom(await request("/settings", {
1188
+ method: "PUT",
1189
+ headers: { "content-type": "application/json" },
1190
+ body: JSON.stringify(patch)
1191
+ }));
1192
+ },
1193
+ async probeEmbedding() {
1194
+ return probeFrom(await request("/probe", {
1195
+ method: "POST",
1196
+ headers: { "content-type": "application/json" },
1197
+ body: "{}"
1198
+ }));
1199
+ },
1200
+ async loadArxiv(categories) {
1201
+ const params = new URLSearchParams({ categories: categories.join(",") });
1202
+ return arxivFrom(await request(`/arxiv?${params.toString()}`));
1203
+ },
1204
+ async recommendArxiv(categories) {
1205
+ const result = arxivFrom(await request("/arxiv", {
1206
+ method: "POST",
1207
+ headers: { "content-type": "application/json" },
1208
+ body: JSON.stringify({ categories, topN: 20, force: true })
1209
+ }));
1210
+ if (result === null) throw new Error("invalid recommend response");
1211
+ return result;
1212
+ },
1213
+ async searchZhihu(query, count = 10) {
1214
+ const params = new URLSearchParams({ query, count: String(count) });
1215
+ return zhihuFrom(await request(`/zhihu?${params.toString()}`));
1216
+ },
1217
+ async importPaper(text) {
1218
+ const response = await transport("/agentero/api/import", {
1219
+ method: "POST",
1220
+ headers: { "content-type": "application/json" },
1221
+ body: JSON.stringify({ text }),
1222
+ cache: "no-store"
1223
+ });
1224
+ const body = await response.json().catch(() => void 0);
1225
+ if (!response.ok) throw new Error(errorText(body) ?? "");
1226
+ }
1227
+ };
1228
+ ctx.effect(() => ctx.slots.inject("conversation.input.dock", () => ctx.slots.register({
1229
+ name: "conversation.input.dock",
1230
+ id: DOCK_ID,
1231
+ order: 60,
1232
+ locale: NS,
1233
+ inject: () => face
1234
+ }, RecommendDock)));
1235
+ }
1236
+ return module.exports;
1237
+ }
1238
+ });