Cookbook UI: Ollama browser, advanced serve fold, API tokens form, diagnosis toolbar, polish

Surface a lot of accumulated cookbook + UI work as a single non-agent
commit so the agent rework lands cleanly.

Highlights:
- Ollama as a first-class backend in the Cookbook:
  * Download input accepts ollama-style names (name:tag) → backend=ollama
  * /api/cookbook/ollama/library (cached scrape of ollama.com + curated
    fallback so classic models like qwen2.5 stay reachable)
  * "Browse Ollama library" toggle below Download with size chips
  * Engine=Ollama in hwfit toolbar merges the Ollama library into the
    main scan list as per-tag rows with the same Fit/Param/Quant/VRAM
    columns; click → fills Download input
- API Tokens form added to Integrations panel (matching wired
  loadTokens()/initTokenForm() that had no HTML)
- Serve panel polish: Advanced fold tightening (-8px nudges on vLLM
  checks, Extra args, Spec row), n_cpu_moe + Split Mode controls
  pulled up 8px to align with the row's checkboxes, GGUF File dropdown
  exposed for Ollama backend, GPU re-render on Edit serve restore,
  _forceBackend flag so saved serveState wins over backend detection,
  cookbook:servers-changed CustomEvent so panels don't need refresh
- Models page redesign: Add Models row (URL + hidden API key reveal +
  Type select + Scan/Ollama/Key/Test/Add icon buttons), Probe All +
  Clear-offline buttons in Added Models toolbar, offline-pill removed
  (opacity already conveys state), Engine dropdown gains Ollama option
- _ping_endpoint probes /v1/models then base, accepts 4xx as
  reachable (vLLM returns 404 on bare /v1, fully working endpoints
  were showing offline)
- Diagnosis card: × dismiss + Copy bundle buttons restored on the
  serve error feedback card
- Orphan tmux sweep re-enabled behind a 60s rate-limit + background
  Thread (off the main event loop) so dead serves get discovered
- cookbook_routes auto-register watchdog: drops the endpoint if the
  serve session exits non-zero within the first ~3min
- ollama-rocm sidecar awareness in download wrapper (`docker exec
  ollama-rocm ollama pull` when host ollama isn't installed)
- Skill extractor sets initial_status="published" when
  auto_approve_skills pref is on (audit demotes later)
- Skill list / model list / cookbook scan misc polish
This commit is contained in:
pewdiepie-archdaemon
2026-06-08 22:38:49 +09:00
parent 646f8bd2a9
commit fa8c93ec0a
28 changed files with 3033 additions and 1026 deletions
+266 -14
View File
@@ -2048,12 +2048,64 @@ body.bg-pattern-sparkles {
.msg-user .body {
color: var(--fg);
}
.msg-ai .body {
color: var(--fg);
}
.rag-sources {
margin-top: 12px;
border: 1px solid var(--border);
.msg-ai .body {
color: var(--fg);
}
.model-endpoint-add-btn {
display: inline-flex;
align-items: center;
gap: 4px;
margin-left: 7px;
padding: 2px 7px;
border: 1px solid color-mix(in srgb, var(--red) 34%, var(--border));
border-radius: 999px;
background: color-mix(in srgb, var(--red) 8%, transparent);
color: var(--red);
font: inherit;
font-size: 0.78em;
line-height: 1.45;
cursor: pointer;
vertical-align: 1px;
}
.model-endpoint-add-btn:hover {
background: color-mix(in srgb, var(--red) 14%, transparent);
border-color: color-mix(in srgb, var(--red) 55%, var(--border));
}
.model-endpoint-add-btn:disabled {
cursor: default;
opacity: 0.72;
}
.model-endpoint-add-btn.added {
color: var(--color-save-green, #4caf50);
border-color: color-mix(in srgb, var(--color-save-green, #4caf50) 45%, var(--border));
background: color-mix(in srgb, var(--color-save-green, #4caf50) 9%, transparent);
}
.task-completed-marker {
display: inline-flex;
align-items: center;
gap: 7px;
margin: 7px 0 2px;
padding: 5px 9px;
border: 1px solid color-mix(in srgb, var(--color-save-green, #4caf50) 42%, var(--border));
border-radius: 999px;
background: color-mix(in srgb, var(--color-save-green, #4caf50) 9%, transparent);
color: var(--color-save-green, #4caf50);
font-size: 0.86em;
font-weight: 600;
}
.task-completed-icon {
display: inline-flex;
align-items: center;
justify-content: center;
width: 17px;
height: 17px;
border-radius: 50%;
background: color-mix(in srgb, var(--color-save-green, #4caf50) 18%, transparent);
flex: 0 0 auto;
}
.rag-sources {
margin-top: 12px;
border: 1px solid var(--border);
border-radius: 6px;
padding: 8px;
font-size: 12px;
@@ -2182,7 +2234,7 @@ body.bg-pattern-sparkles {
position: absolute;
top: 0;
right: 0;
z-index: 2;
z-index: 250;
transform-origin: top right;
transition: opacity 0.22s ease, transform 0.22s ease;
will-change: opacity, transform;
@@ -2704,7 +2756,7 @@ body.bg-pattern-sparkles {
position: absolute;
bottom: calc(100% + 16px);
right: 0;
z-index: 300;
z-index: 250;
min-width: 260px;
max-width: 360px;
background: var(--panel);
@@ -8367,6 +8419,14 @@ body.hide-thinking .thinking-section { display: none !important; }
transition: background 0.2s ease;
}
.thinking-header > .token-new {
display: none;
}
.thinking-header > div:last-child {
flex-shrink: 0;
}
.thinking-header:hover {
background: color-mix(in srgb, var(--red) 12%, transparent);
}
@@ -8382,6 +8442,7 @@ body.hide-thinking .thinking-section { display: none !important; }
min-width: 0;
}
.thinking-header-left span {
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
@@ -8760,6 +8821,22 @@ body.hide-thinking .thinking-section { display: none !important; }
.agent-thread-node + .agent-thread-node {
margin-top: 2px;
}
/* Supervisor ladder cards same chrome as tool cards but tinted so the
user can tell at a glance "this is the agent recovering" vs "this is
the agent doing work". Stop rung gets the red accent. */
.agent-thread-node.supervisor-step .agent-thread-tool {
color: color-mix(in srgb, var(--accent, #c08a3e) 80%, var(--fg));
font-style: italic;
}
.agent-thread-node.supervisor-step .agent-thread-dot {
background: color-mix(in srgb, var(--accent, #c08a3e) 60%, transparent);
}
.agent-thread-node.supervisor-step[data-rung="stop"] .agent-thread-tool {
color: var(--red, #d65a5a);
}
.agent-thread-node.supervisor-step[data-rung="stop"] .agent-thread-dot {
background: color-mix(in srgb, var(--red, #d65a5a) 60%, transparent);
}
.agent-thread-dot {
position: absolute;
left: -20px;
@@ -15144,10 +15221,28 @@ body.right-dock-active:not(.email-doc-split-active) .doc-editor-pane {
}
}
/* Cookbook's cached-model list should scale with viewport height, not be capped at 400px */
/* Cookbook's cached-model list: NO inner-scroll cap. Two nested scroll
surfaces (this + the outer .admin-card) trapped the wheel so an expanded
serve panel couldn't be reached on tall content. Let the outer
.admin-card (overflow-y:auto) be the single scroll surface. */
.hwfit-cached-list {
max-height: min(75vh, 900px) !important;
overflow-y: auto;
max-height: none !important;
overflow-y: visible !important;
}
/* Serve panel specifically: the admin-card inline style is
`overflow:hidden` (so the toolbar/header don't drift), and the list
inside has overflow:visible. On short windows that combination
clipped the cards off the bottom with no scrollbar. Make the list
itself the scroll surface so the rest of the card stays put. */
.cookbook-group[data-backend-group="Serve"] > .admin-card {
min-height: 0;
}
.cookbook-group[data-backend-group="Serve"] > .admin-card > #hwfit-cached-list,
.cookbook-group[data-backend-group="Serve"] > .admin-card > .hwfit-cached-list {
flex: 1 1 0;
min-height: 0;
overflow-y: auto !important;
overscroll-behavior: contain;
}
/* Drag-and-drop visual hint for the email compose pane. Subtle accent
outline + tinted overlay so it's obvious files will attach if dropped. */
@@ -17924,8 +18019,11 @@ body.gallery-selecting .gallery-dl-btn,
}
#cookbook-modal .cookbook-group > .admin-card {
min-height: 0;
overflow-y: auto !important;
overflow-x: hidden !important;
/* Let .cookbook-body be the SINGLE scroll surface. Nesting another
overflow:auto here trapped the wheel inside the cached-list when a
serve panel expanded the page couldn't scroll past the panel's
bottom (Launch button got hidden). */
overflow: visible !important;
}
#cookbook-modal .cookbook-section-body {
min-height: 0;
@@ -18733,6 +18831,13 @@ body.gallery-selecting .gallery-dl-btn,
justify-content: flex-end;
margin-bottom: 4px;
}
/* When the Save split sits inside Row 1 (next to GPUs), align it with the
input baseline (the row's grid cells stretch top-down; without this the
Save buttons sit above the GPU button group). */
.hwfit-serve-row .cookbook-serve-slots {
align-self: end;
margin-bottom: 4px;
}
.cookbook-slot-btn {
min-width: 22px; height: 22px;
padding: 0 6px;
@@ -20207,6 +20312,21 @@ body.gallery-selecting .gallery-dl-btn,
background: color-mix(in srgb, var(--color-error) 8%, transparent);
border: 1px solid color-mix(in srgb, var(--color-error) 30%, transparent);
border-radius: 6px;
/* The diagnosis body can carry traceback fragments and long unbroken
paths (e.g. /home/.../snapshots/<sha>/<file>.gguf). Without these,
a single long token pushes the card wider than the cookbook modal,
scrolling the row right and clipping the action buttons. */
min-width: 0;
max-width: 100%;
overflow-wrap: anywhere;
word-break: break-word;
}
.cookbook-diagnosis pre,
.cookbook-diagnosis code {
white-space: pre-wrap;
word-break: break-word;
overflow-wrap: anywhere;
max-width: 100%;
}
.cookbook-diag-header {
display: flex;
@@ -20400,6 +20520,14 @@ body.gallery-selecting .gallery-dl-btn,
opacity: 0.5;
font-family: inherit;
}
/* Brief border+glow flash when an Ollama row in the hwfit list autofills the
Download input helps the user see what landed when the input is offscreen
or above a tall list. */
.cookbook-dl-repo.cookbook-dl-flash {
border-color: var(--red) !important;
box-shadow: 0 0 0 3px color-mix(in srgb, var(--red) 25%, transparent) !important;
transition: border-color 0.2s, box-shadow 0.2s;
}
.cookbook-dl-btn {
background: var(--accent, var(--red));
color: #fff;
@@ -22446,6 +22574,88 @@ input.settings-select::placeholder { color: color-mix(in srgb, var(--fg) 35%, tr
text-align: right;
}
.settings-fallback-row .settings-select { flex: 1; min-width: 0; }
/* Cookbook Serve Advanced fold wraps the rarely-touched tuning rows
(KV/Attention/Swap/Env for vLLM, llama.cpp batch/cache/split, VRAM
monitor, speculative, extra args). Matches the existing .hwfit-panel-
advanced look: muted-gray label, no caps, no letter-spacing, no
warning-y opacity. Content flows into the parent's existing scroll
surface (no inner max-height) and inner rows reset their margin so
stacking gaps don't double when the fold opens. */
/* Styled to match the Add Models page collapsible sections
(.adm-section-toggle) same border/background/caret pattern, so the
two folds across the app read consistently. */
details.hwfit-serve-advanced {
margin-top: 8px;
overflow: visible;
}
details.hwfit-serve-advanced > summary.hwfit-serve-advanced-summary {
cursor: pointer;
user-select: none;
list-style: none;
display: flex;
align-items: center;
gap: 6px;
font-size: 11px;
color: var(--fg);
opacity: 0.8;
border: 1px solid var(--border);
border-radius: 6px;
padding: 6px 9px;
background: color-mix(in srgb, var(--fg) 4%, transparent);
transition: border-color 0.12s, background 0.12s, opacity 0.12s, border-radius 0s;
}
details.hwfit-serve-advanced > summary.hwfit-serve-advanced-summary::-webkit-details-marker {
display: none;
}
details.hwfit-serve-advanced > summary.hwfit-serve-advanced-summary:hover {
opacity: 1;
border-color: var(--red);
background: color-mix(in srgb, var(--red) 8%, transparent);
}
/* Caret on the right, rotates open/closed. SVG-style rectangles via
borders keep this glyph-free + crisp at small sizes. */
details.hwfit-serve-advanced > summary.hwfit-serve-advanced-summary::after {
content: '';
margin-left: auto;
width: 0;
height: 0;
border-left: 4px solid currentColor;
border-top: 3px solid transparent;
border-bottom: 3px solid transparent;
opacity: 0.6;
transform: rotate(90deg);
transition: transform 0.18s ease;
}
details.hwfit-serve-advanced:not([open]) > summary.hwfit-serve-advanced-summary::after {
transform: rotate(0deg);
}
/* Body rows below the header tight rhythm so the fold doesn't
feel airy. The cookbook modal's existing .cookbook-body is the
scroll surface; nothing inside the fold should add its own scroll. */
details.hwfit-serve-advanced[open] > summary.hwfit-serve-advanced-summary {
margin-bottom: 6px;
}
details.hwfit-serve-advanced > .hwfit-serve-row,
details.hwfit-serve-advanced > .hwfit-serve-checks,
details.hwfit-serve-advanced > .hwfit-serve-cmd-wrap,
details.hwfit-serve-advanced > .hwfit-serve-extra {
margin-top: 0;
margin-bottom: 0;
}
/* Pull the vLLM/SGLang checks row, Extra args, and the trailing
model-specific (Speculative) checks row up tight against the row
above the previous 4px gap plus per-row baseline padding left a
~8px gap that read as too airy in the Advanced fold. */
details.hwfit-serve-advanced > .hwfit-serve-checks.hwfit-backend-vllm,
details.hwfit-serve-advanced > .hwfit-serve-checks.hwfit-backend-sglang,
details.hwfit-serve-advanced > .hwfit-serve-extra {
margin-top: -8px;
}
details.hwfit-serve-advanced > .hwfit-serve-row:last-of-type,
details.hwfit-serve-advanced > .hwfit-serve-checks:last-of-type {
margin-bottom: 0;
}
.settings-fallback-remove {
flex-shrink: 0;
margin-right: 4px;
@@ -22463,6 +22673,9 @@ input.settings-select::placeholder { color: color-mix(in srgb, var(--fg) 35%, tr
transition: border-color 0.12s, color 0.12s, background 0.12s;
position: relative;
top: -6px;
/* Glyph baseline trim: nudge × up 1px inside the button without moving the
button. line-height < 1 lets the glyph float toward the top of its line box. */
line-height: 0.85;
}
.settings-fallback-remove:hover {
border-color: var(--red);
@@ -33593,7 +33806,24 @@ button.cal-add-btn.cal-add-btn-text.cal-add-btn-sm:hover .cal-add-label {
/* Only the direct-child compose button gets pushed right; nested chips
inside #email-lib-accounts pack to the left as normal flex items. */
.email-accounts-row > .memory-toolbar-btn { flex-shrink: 0; margin-left: auto; }
#email-lib-accounts { justify-content: flex-start; }
#email-lib-accounts { justify-content: flex-start; flex-wrap: wrap; }
/* Mobile: collapse the account chips to a single horizontally-scrollable
strip instead of stacking onto multiple rows. The compose "New" button
stays outside the scroller (it's a sibling of #email-lib-accounts inside
.email-accounts-row) so it remains pinned on the right. */
@media (max-width: 768px) {
#email-lib-accounts {
flex-wrap: nowrap;
overflow-x: auto;
overflow-y: hidden;
scrollbar-width: none;
-ms-overflow-style: none;
scroll-snap-type: x proximity;
-webkit-overflow-scrolling: touch;
}
#email-lib-accounts::-webkit-scrollbar { display: none; height: 0; }
#email-lib-accounts > * { flex-shrink: 0; scroll-snap-align: start; }
}
.email-accounts-loading-whirlpool {
width: 14px;
height: 14px;
@@ -36198,6 +36428,16 @@ body.theme-frosted .modal {
justify-content: center;
}
/* Mobile: drop the inline icons on Launch + Cancel in the serve panel so
the buttons are text-only and don't wrap on narrow screens. Icons stay
on desktop where horizontal space isn't tight. */
@media (max-width: 600px) {
.hwfit-serve-launch > svg,
.hwfit-serve-cancel > svg {
display: none !important;
}
}
/* Schedule form mounted inside the cookbook serve panel. Uses the
theme tokens (--bg, --panel, --border, --accent, --red) so it
matches the rest of the cookbook chrome instead of inline whites. */
@@ -36249,6 +36489,18 @@ body.theme-frosted .modal {
flex-wrap: wrap;
gap: 5px;
}
/* Days field inline with From / Until push it + the action buttons to
the right end of the row so the row reads: From | Until | gap | Days | Cancel | Save. */
.hwfit-schedule-days-field {
margin-left: auto;
}
.hwfit-schedule-actions-inline {
display: inline-flex;
align-items: flex-end;
gap: 6px;
align-self: flex-end;
padding-bottom: 1px;
}
.hwfit-sched-day-chip {
width: 32px;
height: 32px;