treefmt: apply prettier
Pure `nix fmt` output from the commit before this one — no hand edits. 203 files: 52 md, 42 tsx, 32 js, 32 css, 21 ts, 13 html, 8 json, 3 mjs. Reproduce with `nix develop -c nix fmt` on the parent commit; the result should be byte-identical to this tree. None of the 13 `.prettierignore` entries appears here — verified by intersecting the changed-file list against the ignore file, with a control proving the intersection finds a match when one exists.
This commit is contained in:
parent
5d24bedd60
commit
39b95c2ede
203 changed files with 10090 additions and 6085 deletions
|
|
@ -4,55 +4,61 @@
|
|||
// `needs_login_in_progress` recovery flow (`LoginFlow`) — an agent with
|
||||
// no credentials has no other web-UI path back online, so this isn't
|
||||
// optional polish.
|
||||
import { useEffect, useRef, useState } from 'preact/hooks';
|
||||
import type { BadgeTone } from '@hive/shared/badge.js';
|
||||
import { SettingsMenu } from '@hive/shared/settings-menu.js';
|
||||
import { useApplyThemeOverride } from '@hive/shared/theme-apply.js';
|
||||
import { useApplyMotionOverride } from '@hive/shared/motion-apply.js';
|
||||
import { Header } from './components/Header.js';
|
||||
import { MetaNav } from './components/MetaNav.js';
|
||||
import { ExpandDetailsSetting } from './components/ExpandDetailsSetting.js';
|
||||
import { StatusChips } from './components/StatusChips.js';
|
||||
import { LiveStream, type LiveStreamHandle } from './components/LiveStream.js';
|
||||
import { HeaderPill } from './components/HeaderPill.js';
|
||||
import { SidePanel } from './components/SidePanel.js';
|
||||
import { InboxPanel } from './components/InboxPanel.js';
|
||||
import { TodosPanel } from './components/TodosPanel.js';
|
||||
import { TermInput } from './components/TermInput.js';
|
||||
import { LoginFlow } from './components/LoginFlow.js';
|
||||
import { useAgentState } from './hooks/useAgentState.js';
|
||||
import { useTodos } from './hooks/useTodos.js';
|
||||
import { fmtAge, fmtTokens } from './lib/format.js';
|
||||
import { resolveDashboardBase } from './lib/dashboardBase.js';
|
||||
import { submitPauseResume } from './lib/pauseAction.js';
|
||||
import { postModel, postEffort } from './lib/modelEffort.js';
|
||||
import { postCancelTurn } from './lib/termActions.js';
|
||||
import type { TokenUsage } from './types.js';
|
||||
import { useEffect, useRef, useState } from "preact/hooks";
|
||||
import type { BadgeTone } from "@hive/shared/badge.js";
|
||||
import { SettingsMenu } from "@hive/shared/settings-menu.js";
|
||||
import { useApplyThemeOverride } from "@hive/shared/theme-apply.js";
|
||||
import { useApplyMotionOverride } from "@hive/shared/motion-apply.js";
|
||||
import { Header } from "./components/Header.js";
|
||||
import { MetaNav } from "./components/MetaNav.js";
|
||||
import { ExpandDetailsSetting } from "./components/ExpandDetailsSetting.js";
|
||||
import { StatusChips } from "./components/StatusChips.js";
|
||||
import { LiveStream, type LiveStreamHandle } from "./components/LiveStream.js";
|
||||
import { HeaderPill } from "./components/HeaderPill.js";
|
||||
import { SidePanel } from "./components/SidePanel.js";
|
||||
import { InboxPanel } from "./components/InboxPanel.js";
|
||||
import { TodosPanel } from "./components/TodosPanel.js";
|
||||
import { TermInput } from "./components/TermInput.js";
|
||||
import { LoginFlow } from "./components/LoginFlow.js";
|
||||
import { useAgentState } from "./hooks/useAgentState.js";
|
||||
import { useTodos } from "./hooks/useTodos.js";
|
||||
import { fmtAge, fmtTokens } from "./lib/format.js";
|
||||
import { resolveDashboardBase } from "./lib/dashboardBase.js";
|
||||
import { submitPauseResume } from "./lib/pauseAction.js";
|
||||
import { postModel, postEffort } from "./lib/modelEffort.js";
|
||||
import { postCancelTurn } from "./lib/termActions.js";
|
||||
import type { TokenUsage } from "./types.js";
|
||||
|
||||
type OpenPanel = 'inbox' | 'todos' | null;
|
||||
type OpenPanel = "inbox" | "todos" | null;
|
||||
|
||||
// Storage keys this page owns for `@hive/shared`'s settings mechanism —
|
||||
// kept here, not derived, so `useApplyThemeOverride`/`useApplyMotionOverride`
|
||||
// (mounted once below) and `<SettingsMenu>` (in `pills`, further down)
|
||||
// always agree on which browser-local key they're reading/writing.
|
||||
const THEME_KEY = 'agent:theme-override';
|
||||
const MOTION_KEY = 'agent:motion-override';
|
||||
const THEME_KEY = "agent:theme-override";
|
||||
const MOTION_KEY = "agent:motion-override";
|
||||
|
||||
const ALIVE_LABELS: Record<string, { glyph: string; text: string; tone: BadgeTone }> = {
|
||||
online: { glyph: '●', text: 'alive', tone: 'positive' },
|
||||
rate_limited: { glyph: '⊘', text: 'rate limited', tone: 'warning' },
|
||||
needs_login_idle: { glyph: '◌', text: 'needs login', tone: 'warning' },
|
||||
needs_login_in_progress: { glyph: '◌', text: 'logging in', tone: 'warning' },
|
||||
const ALIVE_LABELS: Record<
|
||||
string,
|
||||
{ glyph: string; text: string; tone: BadgeTone }
|
||||
> = {
|
||||
online: { glyph: "●", text: "alive", tone: "positive" },
|
||||
rate_limited: { glyph: "⊘", text: "rate limited", tone: "warning" },
|
||||
needs_login_idle: { glyph: "◌", text: "needs login", tone: "warning" },
|
||||
needs_login_in_progress: { glyph: "◌", text: "logging in", tone: "warning" },
|
||||
};
|
||||
const STATE_LABELS: Record<string, { glyph: string; text: string; tone: BadgeTone }> = {
|
||||
idle: { glyph: '💤', text: 'idle', tone: 'neutral' },
|
||||
thinking: { glyph: '🧠', text: 'thinking', tone: 'accent' },
|
||||
compacting: { glyph: '📦', text: 'compacting', tone: 'warning' },
|
||||
const STATE_LABELS: Record<
|
||||
string,
|
||||
{ glyph: string; text: string; tone: BadgeTone }
|
||||
> = {
|
||||
idle: { glyph: "💤", text: "idle", tone: "neutral" },
|
||||
thinking: { glyph: "🧠", text: "thinking", tone: "accent" },
|
||||
compacting: { glyph: "📦", text: "compacting", tone: "warning" },
|
||||
};
|
||||
const STATE_TOOLTIPS: Record<string, string> = {
|
||||
offline: 'harness unreachable or claude not logged in',
|
||||
idle: 'turn loop running, no claude invocation in flight',
|
||||
thinking: 'claude is executing the current turn',
|
||||
offline: "harness unreachable or claude not logged in",
|
||||
idle: "turn loop running, no claude invocation in flight",
|
||||
thinking: "claude is executing the current turn",
|
||||
compacting: "operator-triggered /compact running on the persistent session",
|
||||
};
|
||||
|
||||
|
|
@ -61,7 +67,11 @@ const STATE_TOOLTIPS: Record<string, string> = {
|
|||
// title breakdown, not folded into the headline number).
|
||||
function tokenTotal(u: TokenUsage | null): number | null {
|
||||
if (!u) return null;
|
||||
return (u.input_tokens ?? 0) + (u.cache_read_input_tokens ?? 0) + (u.cache_creation_input_tokens ?? 0);
|
||||
return (
|
||||
(u.input_tokens ?? 0) +
|
||||
(u.cache_read_input_tokens ?? 0) +
|
||||
(u.cache_creation_input_tokens ?? 0)
|
||||
);
|
||||
}
|
||||
|
||||
export function Root() {
|
||||
|
|
@ -96,13 +106,15 @@ export function Root() {
|
|||
state.qualified_label && state.qualified_label !== state.label
|
||||
? state.qualified_label
|
||||
: state.label;
|
||||
document.title = state.hive_name ? `${state.label} // ${state.hive_name}` : `${tab} // hyperhive`;
|
||||
document.title = state.hive_name
|
||||
? `${state.label} // ${state.hive_name}`
|
||||
: `${tab} // hyperhive`;
|
||||
}, [state?.label, state?.qualified_label, state?.hive_name]);
|
||||
const termInput = (
|
||||
<footer class="agent-composer">
|
||||
<TermInput
|
||||
label={state?.label ?? '…'}
|
||||
online={state?.status === 'online'}
|
||||
label={state?.label ?? "…"}
|
||||
online={state?.status === "online"}
|
||||
onLocalNote={(text) => liveStreamRef.current?.pushNote(text)}
|
||||
onClear={() => liveStreamRef.current?.clear()}
|
||||
/>
|
||||
|
|
@ -111,8 +123,20 @@ export function Root() {
|
|||
|
||||
const pills = (
|
||||
<>
|
||||
<HeaderPill kind="inbox" icon="📬" label="inbox" count={state?.inbox.length ?? 0} onClick={() => setOpenPanel('inbox')} />
|
||||
<HeaderPill kind="todos" icon="📋" label="todos" count={todos.length} onClick={() => setOpenPanel('todos')} />
|
||||
<HeaderPill
|
||||
kind="inbox"
|
||||
icon="📬"
|
||||
label="inbox"
|
||||
count={state?.inbox.length ?? 0}
|
||||
onClick={() => setOpenPanel("inbox")}
|
||||
/>
|
||||
<HeaderPill
|
||||
kind="todos"
|
||||
icon="📋"
|
||||
label="todos"
|
||||
count={todos.length}
|
||||
onClick={() => setOpenPanel("todos")}
|
||||
/>
|
||||
{/* Needs a loaded snapshot for its data (links/forge_public_url,
|
||||
* dashboard_port) — omitted until the first /api/state resolves,
|
||||
* same as the old page's populateOverflowMenu (now deleted —
|
||||
|
|
@ -135,17 +159,28 @@ export function Root() {
|
|||
// component — SidePanel's slide/fade CSS transitions only fire on a
|
||||
// class change after mount, not on an already-open initial render, so
|
||||
// mount-on-open would skip both the open AND the close animation.
|
||||
const panelTitle = openPanel === 'inbox' ? `inbox · ${state?.inbox.length ?? 0}` : openPanel === 'todos' ? `todos · ${todos.length}` : '';
|
||||
const panelTitle =
|
||||
openPanel === "inbox"
|
||||
? `inbox · ${state?.inbox.length ?? 0}`
|
||||
: openPanel === "todos"
|
||||
? `todos · ${todos.length}`
|
||||
: "";
|
||||
const panel = (
|
||||
<SidePanel open={openPanel !== null} title={panelTitle} onClose={() => setOpenPanel(null)}>
|
||||
{openPanel === 'inbox' ? (
|
||||
<SidePanel
|
||||
open={openPanel !== null}
|
||||
title={panelTitle}
|
||||
onClose={() => setOpenPanel(null)}
|
||||
>
|
||||
{openPanel === "inbox" ? (
|
||||
<InboxPanel
|
||||
rows={state?.inbox ?? []}
|
||||
label={state?.label ?? ''}
|
||||
dashboardBase={state ? resolveDashboardBase(state.dashboard_port) : ''}
|
||||
label={state?.label ?? ""}
|
||||
dashboardBase={
|
||||
state ? resolveDashboardBase(state.dashboard_port) : ""
|
||||
}
|
||||
onCleared={refresh}
|
||||
/>
|
||||
) : openPanel === 'todos' ? (
|
||||
) : openPanel === "todos" ? (
|
||||
<TodosPanel todos={todos} onCleared={refreshTodos} />
|
||||
) : null}
|
||||
</SidePanel>
|
||||
|
|
@ -179,13 +214,22 @@ export function Root() {
|
|||
);
|
||||
}
|
||||
|
||||
const alive = ALIVE_LABELS[state.status] ?? { glyph: '○', text: 'offline', tone: 'negative' as BadgeTone };
|
||||
const alive = ALIVE_LABELS[state.status] ?? {
|
||||
glyph: "○",
|
||||
text: "offline",
|
||||
tone: "negative" as BadgeTone,
|
||||
};
|
||||
// Mirrors app.js's refreshState: any non-'online' status forces the
|
||||
// turn-state badge to 'offline' regardless of the server's last-known
|
||||
// turn_state (login/rate-limit takes visual priority over a stale
|
||||
// idle/thinking reading from before the harness went offline).
|
||||
const effectiveTurnState = state.status === 'online' ? state.turn_state : 'offline';
|
||||
const turnDef = STATE_LABELS[effectiveTurnState] ?? { glyph: '○', text: 'offline', tone: 'negative' as BadgeTone };
|
||||
const effectiveTurnState =
|
||||
state.status === "online" ? state.turn_state : "offline";
|
||||
const turnDef = STATE_LABELS[effectiveTurnState] ?? {
|
||||
glyph: "○",
|
||||
text: "offline",
|
||||
tone: "negative" as BadgeTone,
|
||||
};
|
||||
const stateAge = fmtAge(now - state.turn_state_since * 1000);
|
||||
// Consolidated status badge (mara: "why do we have separate alive
|
||||
// badge? ... one badge that shows thinking / idle / paused").
|
||||
|
|
@ -195,10 +239,20 @@ export function Root() {
|
|||
// thinking regardless of its last turn_state. Online + running →
|
||||
// turn-state + age, same as before.
|
||||
const primaryStatus =
|
||||
state.status !== 'online'
|
||||
? { glyph: alive.glyph, text: alive.text, tone: alive.tone, tooltip: undefined as string | undefined }
|
||||
state.status !== "online"
|
||||
? {
|
||||
glyph: alive.glyph,
|
||||
text: alive.text,
|
||||
tone: alive.tone,
|
||||
tooltip: undefined as string | undefined,
|
||||
}
|
||||
: state.paused
|
||||
? { glyph: '⏸', text: 'paused', tone: 'warning' as BadgeTone, tooltip: undefined }
|
||||
? {
|
||||
glyph: "⏸",
|
||||
text: "paused",
|
||||
tone: "warning" as BadgeTone,
|
||||
tooltip: undefined,
|
||||
}
|
||||
: {
|
||||
glyph: turnDef.glyph,
|
||||
text: `${turnDef.text} · ${stateAge}`,
|
||||
|
|
@ -212,7 +266,10 @@ export function Root() {
|
|||
<>
|
||||
<Header
|
||||
label={state.label}
|
||||
hiveLabel={[state.swarm_name, state.hive_name].filter(Boolean).join(' / ') || null}
|
||||
hiveLabel={
|
||||
[state.swarm_name, state.hive_name].filter(Boolean).join(" / ") ||
|
||||
null
|
||||
}
|
||||
pills={pills}
|
||||
>
|
||||
<StatusChips
|
||||
|
|
@ -234,22 +291,32 @@ export function Root() {
|
|||
costLabel={cost !== null ? fmtTokens(cost) : undefined}
|
||||
paused={state.paused}
|
||||
onTogglePause={() => {
|
||||
submitPauseResume(resolveDashboardBase(state.dashboard_port), state.label, state.paused ? 'resume' : 'pause').then(
|
||||
() => refresh(),
|
||||
);
|
||||
submitPauseResume(
|
||||
resolveDashboardBase(state.dashboard_port),
|
||||
state.label,
|
||||
state.paused ? "resume" : "pause",
|
||||
).then(() => refresh());
|
||||
}}
|
||||
thinking={effectiveTurnState === 'thinking'}
|
||||
thinking={effectiveTurnState === "thinking"}
|
||||
onCancelTurn={() =>
|
||||
postCancelTurn().then((r) => {
|
||||
if (!r.ok) liveStreamRef.current?.pushNote(`✗ /cancel failed${r.detail ? ': ' + r.detail : ''}`);
|
||||
if (!r.ok)
|
||||
liveStreamRef.current?.pushNote(
|
||||
`✗ /cancel failed${r.detail ? ": " + r.detail : ""}`,
|
||||
);
|
||||
refresh();
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Header>
|
||||
<main className="agent-main">
|
||||
{state.status === 'needs_login_idle' || state.status === 'needs_login_in_progress' ? (
|
||||
<LoginFlow status={state.status} session={state.session} onRefresh={refresh} />
|
||||
{state.status === "needs_login_idle" ||
|
||||
state.status === "needs_login_in_progress" ? (
|
||||
<LoginFlow
|
||||
status={state.status}
|
||||
session={state.session}
|
||||
onRefresh={refresh}
|
||||
/>
|
||||
) : null}
|
||||
<LiveStream ref={liveStreamRef} />
|
||||
</main>
|
||||
|
|
|
|||
Loading…
Reference in a new issue