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
|
|
@ -5,7 +5,7 @@
|
|||
// `/agent/<name>/` on the dashboard's own origin (`location.origin`);
|
||||
// accessed directly, it's the same host on `dashboardPort`.
|
||||
export function resolveDashboardBase(dashboardPort: number): string {
|
||||
return location.pathname.startsWith('/agent/')
|
||||
? location.origin + '/'
|
||||
return location.pathname.startsWith("/agent/")
|
||||
? location.origin + "/"
|
||||
: `${location.protocol}//${location.hostname}:${dashboardPort}/`;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,16 +2,16 @@
|
|||
// output shapes — this page's operators are used to reading them).
|
||||
|
||||
export function fmtTokens(n: number): string {
|
||||
if (n >= 1_000_000) return (n / 1_000_000).toFixed(1) + 'M';
|
||||
if (n >= 1_000) return Math.round(n / 1000) + 'k';
|
||||
if (n >= 1_000_000) return (n / 1_000_000).toFixed(1) + "M";
|
||||
if (n >= 1_000) return Math.round(n / 1000) + "k";
|
||||
return String(n);
|
||||
}
|
||||
|
||||
export function fmtAge(ms: number): string {
|
||||
const s = Math.floor(ms / 1000);
|
||||
if (s < 60) return s + 's';
|
||||
if (s < 60) return s + "s";
|
||||
const m = Math.floor(s / 60);
|
||||
if (m < 60) return m + 'm ' + (s % 60) + 's';
|
||||
if (m < 60) return m + "m " + (s % 60) + "s";
|
||||
const h = Math.floor(m / 60);
|
||||
return h + 'h ' + (m % 60) + 'm';
|
||||
return h + "h " + (m % 60) + "m";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,13 +3,15 @@
|
|||
// output there, JSX fragment here). Same regex + trailing-punctuation
|
||||
// strip; deliberately text-only, never innerHTML, so untrusted row text
|
||||
// (matrix-relayed bodies, tool args) can't inject markup this way.
|
||||
import type { JSX } from 'preact';
|
||||
import type { JSX } from "preact";
|
||||
|
||||
const LINKIFY_URL_RE = /https?:\/\/[^\s<>"']+/g;
|
||||
|
||||
export function linkifyToNodes(text: string | null | undefined): (string | JSX.Element)[] {
|
||||
const str = text == null ? '' : String(text);
|
||||
if (str.indexOf('://') === -1) return [str];
|
||||
export function linkifyToNodes(
|
||||
text: string | null | undefined,
|
||||
): (string | JSX.Element)[] {
|
||||
const str = text == null ? "" : String(text);
|
||||
if (str.indexOf("://") === -1) return [str];
|
||||
const out: (string | JSX.Element)[] = [];
|
||||
let last = 0;
|
||||
let m: RegExpExecArray | null;
|
||||
|
|
@ -18,10 +20,10 @@ export function linkifyToNodes(text: string | null | undefined): (string | JSX.E
|
|||
while ((m = LINKIFY_URL_RE.exec(str)) !== null) {
|
||||
let url = m[0];
|
||||
const trail = url.match(/[.,;:!?)\]}'"]+$/);
|
||||
const tail = trail ? trail[0] : '';
|
||||
const tail = trail ? trail[0] : "";
|
||||
if (tail) url = url.slice(0, -tail.length);
|
||||
if (m.index > last) out.push(str.slice(last, m.index));
|
||||
if (!url.slice(url.indexOf('://') + 3)) {
|
||||
if (!url.slice(url.indexOf("://") + 3)) {
|
||||
// Nothing past the scheme — not a real URL, emit verbatim.
|
||||
out.push(m[0]);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -6,23 +6,38 @@
|
|||
// these three routes actually redirect today, but the same tolerant
|
||||
// check costs nothing and keeps every same-origin POST in this package
|
||||
// behaving identically.
|
||||
async function post(path: string, body?: URLSearchParams): Promise<{ ok: boolean; detail?: string }> {
|
||||
async function post(
|
||||
path: string,
|
||||
body?: URLSearchParams,
|
||||
): Promise<{ ok: boolean; detail?: string }> {
|
||||
try {
|
||||
const resp = await fetch(path, {
|
||||
method: 'POST',
|
||||
headers: body ? { 'Content-Type': 'application/x-www-form-urlencoded' } : undefined,
|
||||
method: "POST",
|
||||
headers: body
|
||||
? { "Content-Type": "application/x-www-form-urlencoded" }
|
||||
: undefined,
|
||||
body,
|
||||
redirect: 'manual',
|
||||
redirect: "manual",
|
||||
});
|
||||
const ok = resp.ok || resp.type === 'opaqueredirect' || (resp.status >= 200 && resp.status < 400);
|
||||
const ok =
|
||||
resp.ok ||
|
||||
resp.type === "opaqueredirect" ||
|
||||
(resp.status >= 200 && resp.status < 400);
|
||||
if (ok) return { ok: true };
|
||||
const detail = await resp.text().catch(() => '');
|
||||
return { ok: false, detail: `http ${resp.status}${detail ? ' — ' + detail : ''}` };
|
||||
const detail = await resp.text().catch(() => "");
|
||||
return {
|
||||
ok: false,
|
||||
detail: `http ${resp.status}${detail ? " — " + detail : ""}`,
|
||||
};
|
||||
} catch (err) {
|
||||
return { ok: false, detail: err instanceof Error ? err.message : String(err) };
|
||||
return {
|
||||
ok: false,
|
||||
detail: err instanceof Error ? err.message : String(err),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export const postLoginStart = () => post('login/start');
|
||||
export const postLoginCode = (code: string) => post('login/code', new URLSearchParams({ code }));
|
||||
export const postLoginCancel = () => post('login/cancel');
|
||||
export const postLoginStart = () => post("login/start");
|
||||
export const postLoginCode = (code: string) =>
|
||||
post("login/code", new URLSearchParams({ code }));
|
||||
export const postLoginCancel = () => post("login/cancel");
|
||||
|
|
|
|||
|
|
@ -4,22 +4,27 @@
|
|||
// agent-authored files) — `marked` itself no longer sanitizes (v5+
|
||||
// dropped the built-in sanitizer), so every parse is run through
|
||||
// DOMPurify before it's ever handed to `dangerouslySetInnerHTML`.
|
||||
import { marked } from 'marked';
|
||||
import DOMPurify from 'dompurify';
|
||||
import { marked } from "marked";
|
||||
import DOMPurify from "dompurify";
|
||||
|
||||
marked.setOptions({ breaks: true, gfm: true });
|
||||
|
||||
const ESCAPE_RE = /[&<>"]/g;
|
||||
const ESCAPE_MAP: Record<string, string> = { '&': '&', '<': '<', '>': '>', '"': '"' };
|
||||
const ESCAPE_MAP: Record<string, string> = {
|
||||
"&": "&",
|
||||
"<": "<",
|
||||
">": ">",
|
||||
'"': """,
|
||||
};
|
||||
|
||||
/** Render `text` as sanitized markdown HTML. Falls back to escaped plain
|
||||
* text if `marked` throws (mirrors app.js's try/catch fallback). */
|
||||
export function renderMarkdown(text: string | null | undefined): string {
|
||||
const src = String(text ?? '');
|
||||
const src = String(text ?? "");
|
||||
try {
|
||||
return DOMPurify.sanitize(marked.parse(src) as string);
|
||||
} catch (err) {
|
||||
console.warn('marked failed', err);
|
||||
console.warn("marked failed", err);
|
||||
return src.replace(ESCAPE_RE, (c) => ESCAPE_MAP[c] ?? c);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,22 +4,36 @@
|
|||
// ported from app.js unchanged — the endpoints don't actually redirect
|
||||
// today, but treating an opaque redirect as success costs nothing and
|
||||
// matches the existing contract exactly.
|
||||
async function post(path: string, field: string, value: string): Promise<{ ok: boolean; detail?: string }> {
|
||||
async function post(
|
||||
path: string,
|
||||
field: string,
|
||||
value: string,
|
||||
): Promise<{ ok: boolean; detail?: string }> {
|
||||
try {
|
||||
const resp = await fetch(path, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
||||
body: new URLSearchParams({ [field]: value }),
|
||||
redirect: 'manual',
|
||||
redirect: "manual",
|
||||
});
|
||||
const ok = resp.ok || resp.type === 'opaqueredirect' || (resp.status >= 200 && resp.status < 400);
|
||||
const ok =
|
||||
resp.ok ||
|
||||
resp.type === "opaqueredirect" ||
|
||||
(resp.status >= 200 && resp.status < 400);
|
||||
if (ok) return { ok: true };
|
||||
const detail = await resp.text().catch(() => '');
|
||||
return { ok: false, detail: `http ${resp.status}${detail ? ' — ' + detail : ''}` };
|
||||
const detail = await resp.text().catch(() => "");
|
||||
return {
|
||||
ok: false,
|
||||
detail: `http ${resp.status}${detail ? " — " + detail : ""}`,
|
||||
};
|
||||
} catch (err) {
|
||||
return { ok: false, detail: err instanceof Error ? err.message : String(err) };
|
||||
return {
|
||||
ok: false,
|
||||
detail: err instanceof Error ? err.message : String(err),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export const postModel = (name: string) => post('api/model', 'model', name);
|
||||
export const postEffort = (level: string) => post('api/effort', 'effort', level);
|
||||
export const postModel = (name: string) => post("api/model", "model", name);
|
||||
export const postEffort = (level: string) =>
|
||||
post("api/effort", "effort", level);
|
||||
|
|
|
|||
|
|
@ -14,10 +14,14 @@
|
|||
// navigates the whole page to whatever hive-c0re's endpoint returns —
|
||||
// here, the literal text "ok". Fire-and-forget `fetch` keeps the click
|
||||
// on the agent page.
|
||||
export async function submitPauseResume(dashboardBase: string, label: string, verb: 'pause' | 'resume'): Promise<void> {
|
||||
export async function submitPauseResume(
|
||||
dashboardBase: string,
|
||||
label: string,
|
||||
verb: "pause" | "resume",
|
||||
): Promise<void> {
|
||||
await fetch(`${dashboardBase}api/${verb}/${label}`, {
|
||||
method: 'POST',
|
||||
mode: 'no-cors',
|
||||
credentials: 'include',
|
||||
method: "POST",
|
||||
mode: "no-cors",
|
||||
credentials: "include",
|
||||
}).catch(() => {});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +1,40 @@
|
|||
// Same-origin fetch POST helpers for the term-input slash commands —
|
||||
// same shape as modelEffort.ts's `post()` ({ ok, detail } rather than
|
||||
// throwing), reused by TermInput.tsx.
|
||||
async function post(path: string, body?: URLSearchParams): Promise<{ ok: boolean; detail?: string }> {
|
||||
async function post(
|
||||
path: string,
|
||||
body?: URLSearchParams,
|
||||
): Promise<{ ok: boolean; detail?: string }> {
|
||||
try {
|
||||
const resp = await fetch(path, {
|
||||
method: 'POST',
|
||||
headers: body ? { 'Content-Type': 'application/x-www-form-urlencoded' } : undefined,
|
||||
method: "POST",
|
||||
headers: body
|
||||
? { "Content-Type": "application/x-www-form-urlencoded" }
|
||||
: undefined,
|
||||
body,
|
||||
redirect: 'manual',
|
||||
redirect: "manual",
|
||||
});
|
||||
const ok = resp.ok || resp.type === 'opaqueredirect' || (resp.status >= 200 && resp.status < 400);
|
||||
const ok =
|
||||
resp.ok ||
|
||||
resp.type === "opaqueredirect" ||
|
||||
(resp.status >= 200 && resp.status < 400);
|
||||
if (ok) return { ok: true };
|
||||
const detail = await resp.text().catch(() => '');
|
||||
return { ok: false, detail: `http ${resp.status}${detail ? ' — ' + detail : ''}` };
|
||||
const detail = await resp.text().catch(() => "");
|
||||
return {
|
||||
ok: false,
|
||||
detail: `http ${resp.status}${detail ? " — " + detail : ""}`,
|
||||
};
|
||||
} catch (err) {
|
||||
return { ok: false, detail: err instanceof Error ? err.message : String(err) };
|
||||
return {
|
||||
ok: false,
|
||||
detail: err instanceof Error ? err.message : String(err),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export const postCancelTurn = () => post('api/cancel');
|
||||
export const postCompact = () => post('api/compact');
|
||||
export const postNewSession = () => post('api/new-session');
|
||||
export const postLogout = () => post('api/logout');
|
||||
export const postSend = (body: string) => post('send', new URLSearchParams({ body }));
|
||||
export const postCancelTurn = () => post("api/cancel");
|
||||
export const postCompact = () => post("api/compact");
|
||||
export const postNewSession = () => post("api/new-session");
|
||||
export const postLogout = () => post("api/logout");
|
||||
export const postSend = (body: string) =>
|
||||
post("send", new URLSearchParams({ body }));
|
||||
|
|
|
|||
|
|
@ -3,14 +3,14 @@
|
|||
// a `TermMsg` close to as-is (see components/Row.tsx); there's no
|
||||
// separate client-side row model or classification step any more —
|
||||
// mara: "StreamRow should now match what the server sends in TermMsg."
|
||||
export type Level = 'debug' | 'info' | 'warn' | 'error';
|
||||
export type Level = "debug" | "info" | "warn" | "error";
|
||||
|
||||
export interface TermMsg {
|
||||
icon?: string;
|
||||
level: Level;
|
||||
summary: string;
|
||||
body?: string;
|
||||
body_format?: 'markdown' | 'diff';
|
||||
body_format?: "markdown" | "diff";
|
||||
coalesce_key?: string;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
// the old widget family. First click arms the button (caller renders a
|
||||
// distinct "sure? click again" label off `armed`); a second click within
|
||||
// `resetMs` fires `onConfirm`; anything else (timeout, blur) disarms.
|
||||
import { useEffect, useRef, useState } from 'preact/hooks';
|
||||
import { useEffect, useRef, useState } from "preact/hooks";
|
||||
|
||||
export function useConfirmClick(onConfirm: () => void, resetMs = 2500) {
|
||||
const [armed, setArmed] = useState(false);
|
||||
|
|
|
|||
Loading…
Reference in a new issue