agent/app.js: final cookie scrub — 0 cookies (#713 batch 3 final)
All 19 remaining cookies in app.js were attribution refs to closed issues / PRs / past mara/argus reviews. Substance is already in docs from earlier batches (PR #780). This batch collapses the cookie attributions to brief inline notes pointing at docs where appropriate. - #360 side-panel duplication note → drop closed-issue framing - #394 vibec0re header redesign (×5) → drop cookies, prose stays - #589 hive-qualified label glyphic-title note → drop cookie - #576/#542/#584 logout chain rationale → drop cookies, prose preserved (the WHY + .credentials.json + mcp-needs-auth- cache.json detail stays inline) - #14 relative paths convention → docs/web-ui.md::Per-agent relative paths pointer - #233 marked autolinks new-tab → drop cookie - #559/#566 mark-all-read flyout (×3) → docs/web-ui.md::Per-agent page (Loose-ends flyout) pointer + drop attribution - #666 ask→operator inline-answer slot (×2) → docs/web-ui.md:: Per-agent page (Ask → operator inline-answer binding) pointer app.js: 19 → 0 cookies (100% reduction). Combined with PR #780 + batch 1 + 2, app.js is fully migrated for #713 scope. Closes #713 — all agent UI files (app.js, agent.css, screen.html, index.html, stats.js, stats.html) at 0 issue-ref cookies.
This commit is contained in:
parent
db2a48cde6
commit
4cee50a3be
1 changed files with 49 additions and 64 deletions
|
|
@ -79,8 +79,7 @@ window.marked = marked;
|
|||
|
||||
// ─── side panel (singleton drawer for inbox + loose-ends flyouts) ──────
|
||||
// Shared shape with the dashboard's panel. Candidate for extraction
|
||||
// into @hive/shared in a follow-up — keeping the duplication for
|
||||
// now to land #360 without simultaneously refactoring the dashboard.
|
||||
// into @hive/shared once both surfaces stabilise.
|
||||
const Panel = (() => {
|
||||
const root = $('side-panel');
|
||||
const titleEl = $('side-panel-title');
|
||||
|
|
@ -141,13 +140,12 @@ window.marked = marked;
|
|||
// ─── state rendering ────────────────────────────────────────────────────
|
||||
function setHeader(label, qualifiedLabel, dashboardPort) {
|
||||
const title = $('title');
|
||||
// Title is now just the glowing identity glyph — DASHB04RD,
|
||||
// R3BU1LD, NEW SESSION all live in the overflow `⋯` menu now
|
||||
// (#394). Glow + uppercase styling from h2 / .agent-header-title-row.
|
||||
// The glyphic title stays short (no @hive suffix) — the hive
|
||||
// qualifier lives on the second row's `qualified` chip + the
|
||||
// browser tab title so the cinematic header reads cleanly at a
|
||||
// glance (#589).
|
||||
// Title is just the glowing identity glyph — DASHB04RD, R3BU1LD,
|
||||
// NEW SESSION live in the overflow `⋯` menu. Glow + uppercase
|
||||
// styling from h2 / .agent-header-title-row. The glyphic title
|
||||
// stays short (no @hive suffix) — the hive qualifier lives on
|
||||
// the second row's `qualified` chip + the browser tab title so
|
||||
// the cinematic header reads cleanly at a glance.
|
||||
title.textContent = `◆ ${label} ◆`;
|
||||
// Document title carries the qualified name so the browser's tab
|
||||
// bar disambiguates between same-named agents on different hives
|
||||
|
|
@ -160,20 +158,17 @@ window.marked = marked;
|
|||
populateOverflowMenu(label, dashUrl);
|
||||
}
|
||||
|
||||
// Overflow popover: dashboard back-link + rebuild + new-session.
|
||||
// Per #394 mara's spec — rebuild + new-session both moved off the
|
||||
// header strip into the `⋯` menu (rare actions, both destructive
|
||||
// enough to warrant one extra click; the operator rebuilds from
|
||||
// the host dashboard normally). Dashboard link also slotted in so
|
||||
// every "leave this page" action lives in one menu.
|
||||
// Overflow popover: dashboard back-link + rebuild + new-session +
|
||||
// logout. Rare + destructive actions live here behind one extra
|
||||
// click (the operator rebuilds from the host dashboard normally).
|
||||
// See docs/web-ui.md::Per-agent page (Overflow button).
|
||||
let overflowMenuPopulated = false;
|
||||
function populateOverflowMenu(label, dashUrl) {
|
||||
const menu = $('overflow-menu');
|
||||
if (!menu) return;
|
||||
menu.replaceChildren();
|
||||
|
||||
// ↑ dashboard — host dashboard back-link (was `.btn-dashlink`
|
||||
// beside the title pre-#394).
|
||||
// ↑ dashboard — host dashboard back-link.
|
||||
menu.append(el('a', {
|
||||
class: 'overflow-item overflow-item-dashboard',
|
||||
href: dashUrl,
|
||||
|
|
@ -227,15 +222,14 @@ window.marked = marked;
|
|||
});
|
||||
menu.append(newSessBtn);
|
||||
|
||||
// 🔓 logout (#576) — SIGINTs claude, wipes the credentials dir,
|
||||
// flips the harness LoginState to NeedsLogin. The turn loop's
|
||||
// next iteration parks in wait_for_login; a fresh `claude auth
|
||||
// login` from the dashboard re-arms it (#542 mtime resumption).
|
||||
// Operator has to re-paste OAuth creds on the login screen after,
|
||||
// but the --continue session history is preserved (#584 narrowed
|
||||
// the backend wipe to just .credentials.json + mcp-needs-auth-
|
||||
// cache.json) — so the agent picks up where it left off on the
|
||||
// next turn after re-login.
|
||||
// 🔓 logout — SIGINTs claude, wipes the credentials dir, flips
|
||||
// the harness LoginState to NeedsLogin. The turn loop's next
|
||||
// iteration parks in wait_for_login; a fresh `claude auth login`
|
||||
// from the dashboard re-arms it. Operator has to re-paste OAuth
|
||||
// creds on the login screen after, but the --continue session
|
||||
// history is preserved (the backend wipe is narrowed to just
|
||||
// .credentials.json + mcp-needs-auth-cache.json) — so the agent
|
||||
// picks up where it left off on the next turn after re-login.
|
||||
const logoutBtn = el('button', {
|
||||
type: 'button',
|
||||
class: 'overflow-item overflow-item-logout',
|
||||
|
|
@ -464,8 +458,9 @@ window.marked = marked;
|
|||
if (termAPI) termAPI.row('turn-end-fail', '✗ ' + label + ' failed: ' + err);
|
||||
}
|
||||
}
|
||||
// First arg is the URL path (relative to document base, #14);
|
||||
// second is the slash-command label rendered in the local note.
|
||||
// First arg is the URL path (relative to document base — see
|
||||
// docs/web-ui.md::Per-agent relative paths); second is the
|
||||
// slash-command label rendered in the local note.
|
||||
const postCancelTurn = () => postSimple('api/cancel', '/cancel');
|
||||
const postCompact = () => postSimple('api/compact', '/compact');
|
||||
const postNewSession = () => postSimple('api/new-session', '/new-session');
|
||||
|
|
@ -485,7 +480,7 @@ window.marked = marked;
|
|||
return true;
|
||||
case '/clear':
|
||||
termAPI.clear();
|
||||
// #666: detached `ask → operator` rows no longer have a live
|
||||
// Detached `ask → operator` rows no longer have a live
|
||||
// mount-point in the DOM — drop their slots so subsequent
|
||||
// loose-ends reconciliation doesn't walk dead references.
|
||||
pendingAskBinds.length = 0;
|
||||
|
|
@ -837,12 +832,11 @@ window.marked = marked;
|
|||
return wrap;
|
||||
}
|
||||
|
||||
/** #559: "mark all read" affordance for the agent's inbox flyout.
|
||||
* Returns a DOM row containing a button + an inline status pill.
|
||||
* POSTs to the host dashboard's `/api/agent/{name}/mark-all-read`
|
||||
* (damocles PR #566) and surfaces the `{ marked: N }` count back to
|
||||
* the operator. Re-runs `onCleared` on success so the caller can
|
||||
* refresh whatever state it owns. */
|
||||
/** "mark all read" affordance for the agent's inbox flyout —
|
||||
* see docs/web-ui.md::Per-agent page (Loose-ends flyout) for the
|
||||
* cross-origin POST + count rendering. Returns a DOM row
|
||||
* containing a button + an inline status pill; re-runs
|
||||
* `onCleared` on success so the caller can refresh its own state. */
|
||||
function buildInboxMarkAllRow(label, onCleared) {
|
||||
const status = el('span', { class: 'inbox-mark-status' });
|
||||
const btn = el('button', {
|
||||
|
|
@ -896,12 +890,12 @@ window.marked = marked;
|
|||
'inbox empty.'));
|
||||
return wrap;
|
||||
}
|
||||
// #559: "mark all read" header row drains the host broker's
|
||||
// pending + delivered-unacked rows for this agent (damocles PR
|
||||
// #566). Visible rows here are the most-recent-N regardless of
|
||||
// ack state, so the list itself doesn't visually empty on click —
|
||||
// the status pill confirms the drain count, and the next
|
||||
// turn_start's "unread" badge will read zero.
|
||||
// "mark all read" header row drains the host broker's pending +
|
||||
// delivered-unacked rows for this agent. Visible rows here are
|
||||
// the most-recent-N regardless of ack state, so the list itself
|
||||
// doesn't visually empty on click — the status pill confirms
|
||||
// the drain count, and the next turn_start's "unread" badge
|
||||
// will read zero.
|
||||
wrap.append(buildInboxMarkAllRow(currentLabel, () => {
|
||||
// Refresh state so any UI surface that DOES depend on
|
||||
// delivery state (eg future per-status filters) picks up
|
||||
|
|
@ -1029,10 +1023,6 @@ window.marked = marked;
|
|||
});
|
||||
})();
|
||||
|
||||
// (#394) — `↻ new session` button moved into the overflow `⋯`
|
||||
// menu and wired by `populateOverflowMenu()` above. Previously
|
||||
// wired here as a static `#new-session-btn` in index.html.
|
||||
|
||||
// Track banner activity by reference-counting in-flight turns. A turn
|
||||
// can begin while the previous turn_end is still in the pipeline (rare
|
||||
// but happens on tight wake cycles), so we count rather than toggle.
|
||||
|
|
@ -1074,9 +1064,8 @@ window.marked = marked;
|
|||
rel: 'noopener',
|
||||
title: lnk.label || '',
|
||||
});
|
||||
// Layout gap comes from `.agent-nav { gap }` (#394) — drop
|
||||
// the legacy per-link inline `marginLeft`. The trailing `→`
|
||||
// is the "leaves this page" affordance.
|
||||
// Layout gap comes from `.agent-nav { gap }`. The trailing
|
||||
// `→` is the "leaves this page" affordance.
|
||||
a.append(((lnk.icon || '') + ' ' + (lnk.label || '')).trim() + ' →');
|
||||
metaLinks.append(a);
|
||||
});
|
||||
|
|
@ -1154,7 +1143,7 @@ window.marked = marked;
|
|||
marked.setOptions({ breaks: true, gfm: true });
|
||||
div.innerHTML = marked.parse(src);
|
||||
// marked autolinks URLs but leaves them same-tab — open them
|
||||
// externally so a click never unloads the terminal. (issue #233)
|
||||
// externally so a click never unloads the terminal.
|
||||
div.querySelectorAll('a[href]').forEach((a) => {
|
||||
a.target = '_blank';
|
||||
a.rel = 'noopener noreferrer';
|
||||
|
|
@ -1306,15 +1295,10 @@ window.marked = marked;
|
|||
const d = detailsOpenMd(api, 'tool-use',
|
||||
'ask → ' + to + (lines > 1 ? ` · ${lines}L` : ''),
|
||||
q);
|
||||
// #666: when the ask targets the operator, mount an inline
|
||||
// answer slot in the live terminal so the operator doesn't
|
||||
// need to open the loose-ends side panel (or jump to Y3R C4LL
|
||||
// on the dashboard) to respond. The slot starts empty and
|
||||
// gets populated by `reconcileAskBinds()` once the
|
||||
// loose-ends fetch identifies a matching pending question
|
||||
// (by asker == this agent + question text). Resolved
|
||||
// questions render as a struck-through [answered ✓] tag
|
||||
// instead of a form.
|
||||
// When the ask targets the operator, mount an inline answer
|
||||
// slot in the live terminal — see docs/web-ui.md::Per-agent
|
||||
// page (Ask → operator inline-answer binding) for the slot
|
||||
// registry + reconciler + [resolved] semantics.
|
||||
if (to === 'operator') {
|
||||
const slot = el('div', { class: 'ask-answer-inline-slot' });
|
||||
// Stash the question text on the slot so the reconciler
|
||||
|
|
@ -1356,12 +1340,13 @@ window.marked = marked;
|
|||
: (c.content || '');
|
||||
const sourceName = c.tool_use_id ? toolNameById.get(c.tool_use_id) : null;
|
||||
const isMessageBearing = sourceName === 'mcp__hyperhive__recv';
|
||||
// #666: when an ask's tool_result lands the broker has just
|
||||
// persisted the question with its assigned id. Refresh loose
|
||||
// ends so `reconcileAskBinds` finds the new entry and mounts
|
||||
// the inline answer form under the rendered ask row. Skipped
|
||||
// during history replay (the question's likely long-resolved;
|
||||
// turn_end refresh on cold-load already covers reconciliation).
|
||||
// When an ask's tool_result lands the broker has just
|
||||
// persisted the question with its assigned id. Refresh
|
||||
// loose-ends so reconcileAskBinds finds the new entry and
|
||||
// mounts the inline answer form under the rendered ask row.
|
||||
// Skipped during history replay (the question's likely
|
||||
// long-resolved; turn_end refresh on cold-load covers
|
||||
// reconciliation).
|
||||
if (sourceName === 'mcp__hyperhive__ask' && !api.fromHistory) {
|
||||
refreshLooseEnds();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue