forked from Mike/freno-dev
agents: drop the count and the coverage claim (FRE-359 verdict B)
FRE-359's verdict is B: the page's thirteen is the registry's first thirteen of eighteen rows, so the count, "every coding agent The Nook supports" and "Supported agents" all overstate or understate the app. The permitted sentences are the CTO's, verbatim. - agents.tsx: head description, ogTitle and H1 paragraph replaced with the verdict's sentences; title/H1 "Supported agents" -> "Agent coverage". - agents.test.ts: the stale NOOK-336 guard asserted "all thirteen" and the 13-name roster, so it passed in lockstep with the page. It now asserts no count of any form, no completeness phrase, and that the rows are a subset of the 18-name registry list (copied 2026-10-29, @ f4258034) in registry order. The table still lists 13 rows; regenerating it from the registry is its own ticket, and the guard no longer pretends otherwise. - FeatureBreakdowns.tsx / IslandExtras.tsx: the landing "13 agents:" bullet and the "13 agents" marquee chip lose the count; the chip becomes "Agents wired in". bun test src/routes/nook/agents.test.ts: 4 pass. Server security and appcast suites fail in this checkout on missing env (Environment validation failed / mainDBConnection), unrelated to these files. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
@@ -851,7 +851,7 @@ export default function FeatureBreakdowns() {
|
||||
title="Your whole fleet, in one pixel strip"
|
||||
body="Every session, every agent, one square each. The pill never wraps, never grows — an arriving question flashes the fire and swaps the slot, then hands the notch back."
|
||||
bullets={[
|
||||
"13 agents: Claude Code, Codex, Gemini CLI, OpenCode, Pi, Muse, and more",
|
||||
"Claude Code, Codex, Gemini CLI, OpenCode, Pi, Muse, Cursor and more",
|
||||
"Custom agents: your own coding agent can wire itself in from the published contract",
|
||||
"Slot rankings — you choose which data earns the notch",
|
||||
"You don't need a notch — external displays get the same island, floating top-center"
|
||||
|
||||
@@ -722,7 +722,7 @@ function LayoutMock() {
|
||||
/* ── Marquee ─────────────────────────────────────────────────────── */
|
||||
|
||||
const CHIPS_A = [
|
||||
"13 agents",
|
||||
"Agents wired in",
|
||||
"Custom agents",
|
||||
"Six chiptunes",
|
||||
"Focus-aware slots",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/**
|
||||
* Regression test for the /agents roster (NOOK-336).
|
||||
* Regression test for the /agents roster (NOOK-336) and its coverage wording
|
||||
* (FRE-359).
|
||||
*
|
||||
* The page mirrors the app's registry, `AgentSpec.all` in
|
||||
* the-nook/Sources/NookCore/Agents/AgentRegistry.swift. When Muse joined
|
||||
@@ -8,6 +9,12 @@
|
||||
* them. The registry lives in another repo, so the expected roster is
|
||||
* restated here; when an agent is added there, add it here and on the page.
|
||||
*
|
||||
* FRE-359 verdict B: the page no longer states a count or claims coverage
|
||||
* ("all thirteen", "every coding agent The Nook supports"). The page still
|
||||
* lists 13 of the registry's 18 rows — the table is hand-mirrored and its
|
||||
* regeneration is its own ticket — so the roster check here is a subset
|
||||
* check in registry order, not an equality check.
|
||||
*
|
||||
* STATIC SOURCE AUDIT, the same pattern as the downloads regressions.
|
||||
*/
|
||||
import { describe, it, expect } from "bun:test";
|
||||
@@ -16,7 +23,10 @@ import { join } from "node:path";
|
||||
|
||||
const SOURCE = readFileSync(join(import.meta.dir, "agents.tsx"), "utf8");
|
||||
|
||||
/** AgentSpec.all display names, in registry order. */
|
||||
/** User-facing copy only: comments are not copy and may name the old wording. */
|
||||
const COPY = SOURCE.replace(/\/\*[\s\S]*?\*\//g, "").replace(/^\s*\/\/.*$/gm, "");
|
||||
|
||||
/** AgentSpec.all display names, in registry order (18 rows). @ The-Nook f4258034, 2026-10-29 */
|
||||
const REGISTRY = [
|
||||
"Claude Code",
|
||||
"Codex",
|
||||
@@ -30,25 +40,59 @@ const REGISTRY = [
|
||||
"Gemini CLI",
|
||||
"Cline",
|
||||
"Qwen Code",
|
||||
"DeepSeek"
|
||||
"DeepSeek",
|
||||
"Kimi",
|
||||
"GitHub Copilot CLI",
|
||||
"Crush",
|
||||
"Cursor",
|
||||
"Amp"
|
||||
];
|
||||
|
||||
const NUMBER_WORDS = ["twelve", "thirteen", "fourteen", "fifteen"];
|
||||
const NUMBER_WORDS = ["twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen"];
|
||||
|
||||
const entries = [...SOURCE.matchAll(/^\s{4}name: "([^"]+)",$/gm)].map((m) => m[1]);
|
||||
|
||||
/** The page's rows are a subset of the registry, in registry order. */
|
||||
function subsetInOrder(page: string[], registry: string[]): boolean {
|
||||
let cursor = 0;
|
||||
for (const name of page) {
|
||||
const at = registry.indexOf(name, cursor);
|
||||
if (at === -1) return false;
|
||||
cursor = at + 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
describe("Nook /agents roster (NOOK-336)", () => {
|
||||
it("lists every registry agent, in registry order", () => {
|
||||
expect(entries).toEqual(REGISTRY);
|
||||
it("lists only registry agents, in registry order", () => {
|
||||
expect(entries.length).toBeGreaterThan(0);
|
||||
expect(subsetInOrder(entries, REGISTRY)).toBe(true);
|
||||
});
|
||||
|
||||
it("states the same count everywhere it names one", () => {
|
||||
const word = NUMBER_WORDS[entries.length - 12];
|
||||
for (const other of NUMBER_WORDS.filter((w) => w !== word)) {
|
||||
expect(SOURCE.toLowerCase()).not.toContain(other);
|
||||
}
|
||||
expect(SOURCE).toContain(`all ${word}`);
|
||||
expect(SOURCE).toContain(`The ${entries.length} agents`);
|
||||
expect(SOURCE).toContain(`watches ${word} coding agents`);
|
||||
it("lists each agent at most once", () => {
|
||||
expect(new Set(entries).size).toBe(entries.length);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Nook /agents coverage wording (FRE-359)", () => {
|
||||
it("states no agent count anywhere on the page", () => {
|
||||
for (const word of NUMBER_WORDS) {
|
||||
expect(COPY.toLowerCase()).not.toContain(word);
|
||||
}
|
||||
// A bare numeral count ("13 agents", "The 13") is just as precise and just
|
||||
// as unverified; the page must not state one in any form.
|
||||
expect(COPY).not.toMatch(/\b\d{1,2} agents\b/);
|
||||
expect(COPY).not.toMatch(/\ball \d{1,2}\b/);
|
||||
});
|
||||
|
||||
it("makes no completeness claim over the agent set", () => {
|
||||
for (const banned of [
|
||||
"every coding agent",
|
||||
"the agents the nook supports",
|
||||
"agents the nook supports",
|
||||
"supported agents"
|
||||
]) {
|
||||
expect(COPY.toLowerCase()).not.toContain(banned);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
/**
|
||||
* `/agents` on the Nook subdomain — supported agents and their event coverage.
|
||||
* `/agents` on the Nook subdomain — the agent roster and each row's event
|
||||
* coverage. It states no agent count and claims no completeness over the
|
||||
* registry (FRE-359 verdict B).
|
||||
*
|
||||
* The registry below mirrors `AgentSpec.all` in the app
|
||||
* (~/Code/the-nook/Sources/NookCore/Agents/AgentSpec.swift) and each agent's
|
||||
@@ -282,19 +284,19 @@ export default function NookAgentsPage() {
|
||||
<>
|
||||
<EdgeCacheHeaders maxAge={300} />
|
||||
<PageHead
|
||||
title="Supported agents"
|
||||
description="Every coding agent The Nook supports — all thirteen, with each hook's exact event coverage and what you can do from a card: watch sessions live, answer permission prompts, unblock work."
|
||||
ogTitle="The 13 agents The Nook supports, and what each hook sees"
|
||||
title="Agent coverage"
|
||||
description="The coding agents The Nook connects to, with the events each hook reports and what you can do from a card: watch sessions live, answer permission prompts, unblock work."
|
||||
ogTitle="The coding agents The Nook connects to, and what each hook sees"
|
||||
/>
|
||||
<SubdomainHeader />
|
||||
<main class="min-h-screen px-[8vw] py-[8vh]">
|
||||
<h1 class="text-text mb-3 text-3xl font-bold tracking-tight sm:text-4xl">
|
||||
Supported agents
|
||||
Agent coverage
|
||||
</h1>
|
||||
<p class="text-subtext0 mb-2 max-w-2xl text-lg">
|
||||
The Nook watches thirteen coding agents in one place — your menu bar and
|
||||
notch show every session that is running, thinking, or blocked, and a
|
||||
card answers permission prompts without leaving your keyboard.
|
||||
The Nook watches coding agents in one place — your menu bar and notch
|
||||
show sessions that are running, thinking, or blocked, and a card can
|
||||
answer a permission prompt without leaving your keyboard.
|
||||
</p>
|
||||
<p class="text-subtext1 mb-10 max-w-2xl text-sm">
|
||||
Each agent reports its own set of events. "Allow / Deny from a card"
|
||||
|
||||
Reference in New Issue
Block a user