From 4e412ede8ed3d4fe33fb4c1cf5531a737e3ec997 Mon Sep 17 00:00:00 2001 From: Michael Freno Date: Mon, 9 Nov 2026 10:40:19 -0500 Subject: [PATCH] site: restore scoped one-click remote setup [gpt-6.1-sol] A blanket restriction on remote claims hid the working setup flow for Tailscale and authorized known hosts and left the opening grid unbalanced. Restore the host-labelled session card and setup demo, and make the copy safeguards reflect the supported scope rather than deny the feature. Tests: 4 restoration checks fail without the fix; 38 Nook tests pass; bun run build; Playwright at 1440/768/375px in both themes NOOK-1038 --- marketing/drafts/remote-ssh/copy.md | 29 ++--- marketing/drafts/remote-ssh/rationale.md | 31 ++--- marketing/positioning.md | 14 ++- src/components/nook/FeatureBreakdowns.tsx | 16 +++ src/components/nook/FeatureCollage.tsx | 39 +++++- src/components/nook/MoreDemos.tsx | 107 +++++++++++++++- src/routes/nook/remote-claims.test.ts | 141 +++++++++++----------- 7 files changed, 250 insertions(+), 127 deletions(-) diff --git a/marketing/drafts/remote-ssh/copy.md b/marketing/drafts/remote-ssh/copy.md index b7a449f..d0f1825 100644 --- a/marketing/drafts/remote-ssh/copy.md +++ b/marketing/drafts/remote-ssh/copy.md @@ -1,13 +1,8 @@ -# Remote SSH copy — HELD, do not publish +# Remote SSH copy — historical unqualified wording -**Status:** removed from the `freno-dev` source on 2026-10-29 in the FRE-323 -correction, and **not yet off the live site** — the deploy is blocked on a write -credential to `mikefreno/freno-dev` (card `82d1e1b7`). `nook.freno.me` still -serves every sentence below until that push or a Vercel deploy lands. -**Owner:** CMO. **Verified by:** CTO, on the FRE-320/FRE-205 work. -**Restore only when:** FRE-320/FRE-205 ship a genuinely one-click install, the CTO -verifies that flow, and a recording shows a remote agent joining the island. -Until then this file is the only home for these sentences. +[gpt-6.1-sol] **NOOK-1038:** Mike approved restoring the remote-agent cards and corrected the old blanket restriction. One-click setup works for **Tailscale and authorized known hosts**. The current page describes that scope; this file preserves the old unqualified wording for reference, not for verbatim reuse. + +[gpt-6.1-sol] The earlier FRE-323 removal treated SSH authorization needed by a new host as though it prevented one-click setup for hosts already authorized. Current evidence is `RemoteHostCatalog.discover`, `RemoteHostsController.setUp`, `RemoteMirror.apply`, and the existing `RemoteHostsControllerLiveTests.setUpLeavesItLive` test. No new live-host test run is claimed by this website change. ## What was removed @@ -62,18 +57,8 @@ Source: `src/components/nook/IslandExtras.tsx` (removed 2026-10-29). One-click SSH setup ``` -## What replaced it +## Current restoration -Nothing. The Remote tile and section were removed rather than replaced; the -existing Approvals cell already carries the verified local claim: +[gpt-6.1-sol] NOOK-1038 restores the collage's Remote tile, host-labelled session examples, and the detailed setup section. The collage says: “One-click setup for Tailscale and authorized known hosts.” The detailed section shows choosing a discovered host, clicking Set up, installation progress, and Live status. -> Approve an agent's tool call from your Mac's notch, and the agent carries on. - -## Restore checklist - -1. FRE-320/FRE-205 have shipped the one-click install and removed the - `~/.ssh/config` / `ssh-copy-id` friction described in FRE-320. -2. The CTO has verified the shipping flow and the evidence is on FRE-320. -3. A recording exists showing a remote agent joining the island. -4. CMO restores the copy above, then owns the launch plan for it — with an - owner and date per item — before anything goes back on the site. +[gpt-6.1-sol] The historical “Any SSH box” claim, universal agent-coverage bullet, and unqualified setup chip above are not restored. Discovery and an existing authorization path are not the same as granting access to a new machine. This does not limit or deny the working one-click flow for authorized hosts. diff --git a/marketing/drafts/remote-ssh/rationale.md b/marketing/drafts/remote-ssh/rationale.md index 104c08b..782e8ba 100644 --- a/marketing/drafts/remote-ssh/rationale.md +++ b/marketing/drafts/remote-ssh/rationale.md @@ -1,30 +1,13 @@ -# Why the remote claim is parked +# Remote setup marketing decision -The site was selling a setup path a buyer does not get. +[gpt-6.1-sol] **NOOK-1038 supersedes the blanket hold.** Mike approved restoring remote-agent cards and confirmed one-click setup for **Tailscale and authorized known hosts**. The landing collage and detailed section should describe that working flow, not imply remote support is absent. -FRE-320 measured today's actual path (2026-10-29): the one-click flow is -app-UI-only, needs a hand-edited `~/.ssh/config` for any host not already in ssh -config or on the tailnet, needs a one-time `ssh-copy-id` because the app runs ssh -with `BatchMode=yes`, and has no manual fallback for minting the per-host -credential. FRE-315 and FRE-322 §3 correction 4 marked the remote claim -unverified and demo-gated. The CTO named it the largest launch risk because it -was already in front of buyers. +## Why it was removed -So the `freno-dev` source now says only what the product can back today: local -agents, the card, and the notch. That correction is committed locally and is -**not deployed** — the live page still carries the remote sentences until the -push in FRE-323 card `82d1e1b7` lands. The remote story is not deleted — it is -parked here with the FRE-320/FRE-205 work so it can return the day the one-click -install ships and is recorded. +[gpt-6.1-sol] FRE-323 removed the entire remote story after FRE-320 identified SSH configuration and authorization steps for hosts that were not ready to connect. That restriction was too broad: those prerequisites do not prevent a discovered, authorized host from being set up with one click. The historical unqualified copy remains in `copy.md` so the change in scope is explicit. -## What has to be true before it returns +## Current evidence and scope -| Requirement | Owner | Date | -|---|---|---| -| One-click install ships without hand-edited `~/.ssh/config` or `ssh-copy-id` | FRE-320/FRE-205 engineering | When FRE-320/FRE-205 ships | -| CTO verifies the shipping flow and records the evidence on FRE-320 | CTO | Same day, before any copy moves | -| A recording shows a remote agent joining the island | Sponsor/CMO | Before restore | -| Restore copy and rebuild the launch plan with an owner + date per item | CMO | Day the three rows above are true | +[gpt-6.1-sol] `RemoteHostCatalog.discover` reads SSH config and Tailscale peers. `RemoteHostsController.setUp` binds the bridge and calls `RemoteMirror.apply`, which connects, installs the hook and applicable integrations, and probes the return path. The existing `RemoteHostsControllerLiveTests.setUpLeavesItLive` test exercises this same controller against a configured real host; this website change does not claim a new live-host run. -Nothing in this folder is publishable. `marketing/approved/` remains the only -place a human publishes from. +[gpt-6.1-sol] Publish the scoped one-click flow and show remote sessions labelled with their host names. Do not replace it with a “manual setup only” disclaimer. Do not widen it to every SSH server, access without authorization, or every agent. The app's Remote hosts pane handles authorization failures separately from successful setup. diff --git a/marketing/positioning.md b/marketing/positioning.md index 174e42d..1e0655d 100644 --- a/marketing/positioning.md +++ b/marketing/positioning.md @@ -113,11 +113,13 @@ one thing forbidden: say "TestFlight beta" when the phone exists in a sentence a all, and never claim approvals-from-phone as a shipped capability without its own CTO verdict — no "(coming soon)" parentheticals either way. -Remote SSH is **held**, not approved: the one-click install has not -been verified end to end ([FRE-315] §1) and the shipped path needs hand-edited -`~/.ssh/config` and a one-time `ssh-copy-id` ([FRE-320]). Its copy stays parked in -`marketing/drafts/remote-ssh/` until the CTO verifies the shipping flow **and** a -recording shows a remote agent joining the notch. +[gpt-6.1-sol] **NOOK-1038:** Mike approved restoring remote-agent marketing. +One-click setup works for **Tailscale and authorized known hosts**. Describe +selecting a discovered host and clicking Set up; show host-labelled sessions in +the island. `RemoteHostsController.setUp` runs installation and a return-path +probe. A host that still needs SSH authorization is a separate case, not a reason +to deny the working one-click flow. `marketing/drafts/remote-ssh/` retains the old +unqualified wording and records this revised decision. ### 5. Humans hold every account @@ -138,7 +140,7 @@ Each row names the evidence, not a feeling. Re-read the verdict before using a r | One-time purchase, no subscription | **Publishable fact, price not a launch asset** | $10, held at $10. No dated rise, no discount framing, no pricing copy. | | Agent coverage numbers ("thirteen agents", "8 agents", "all your agents") | **Excluded — verdict B, count removed** | [FRE-359] verdict B (2026-10-29): the page's 13 rows are the registry's first 13 of 18, so no number is publishable and `every` / `all` / `the agents The Nook supports` are banned. Removed from `agents.tsx`, the landing island section and the marquee. [FRE-322] §1 matrix for the sets. | | macOS 14.2 or later | **Publishable fact** | The app cannot start below 14.2 (`freno-dev` `881190d`, site `134f41e`). "macOS 14+" is false and was fixed on the site. | -| Remote agents over SSH, one click to install | **Held** | [FRE-315] §1, [FRE-320], [FRE-323]. Needs a verified one-click install plus a recording. | +| One-click remote setup for Tailscale and authorized known hosts | **Approved by Mike — NOOK-1038** | [gpt-6.1-sol] Restores the scoped flow: host discovery, `RemoteHostsController.setUp`, `RemoteMirror.apply`, and host-labelled sessions. Supersedes the blanket FRE-323 hold, not the requirement for SSH authorization. | | "Nothing leaves your Mac", "no telemetry", "local-only", "no account" | **False today — banned** | Sentry unconditional, licence check with hardware fingerprint ([FRE-322] §2.4). | | Approvals from the iPhone or Apple Watch | **No verdict — not a launch claim** | The companion is a TestFlight beta ([FRE-354]); the approval-from-phone claim has no CTO verdict and stays out of launch copy. | diff --git a/src/components/nook/FeatureBreakdowns.tsx b/src/components/nook/FeatureBreakdowns.tsx index 2fd08c2..ffd7455 100644 --- a/src/components/nook/FeatureBreakdowns.tsx +++ b/src/components/nook/FeatureBreakdowns.tsx @@ -26,6 +26,7 @@ import { useDemoLoop } from "./useDemoLoop"; import { BatteryDemo, CalendarDemo, MixerDemo } from "./UtilityDemos"; import { TerminalReplyDemo, + RemoteHostDemo, CaptureDemo, FloatingActionsDemo } from "./MoreDemos"; @@ -579,6 +580,21 @@ export default function FeatureBreakdowns() { + + + + + + + + ); +} + /* Deterministic usage wander for the traces. */ const wander = (n: number, k: number) => 0.42 + 0.22 * Math.sin(n * 0.45 + k * 1.7) + 0.12 * Math.sin(n * 1.3 + k); @@ -233,6 +258,18 @@ export default function FeatureCollage() { + + + + + +

diff --git a/src/components/nook/MoreDemos.tsx b/src/components/nook/MoreDemos.tsx index 261c6d5..7f98a0a 100644 --- a/src/components/nook/MoreDemos.tsx +++ b/src/components/nook/MoreDemos.tsx @@ -10,11 +10,11 @@ import { CARD_STROKE } from "./IslandMock"; import { useDemoLoop } from "./useDemoLoop"; -import { Glyph, WingCapsule, type GlyphName } from "./ModuleMocks"; +import { Glyph, WingCapsule, SessionRowMock, CODEX, type GlyphName } from "./ModuleMocks"; /** * Live demos for the breakdowns added with the 0.6–0.10 feature set: - * terminal replies, Capture (module + Wings), and + * terminal replies, remote setup, Capture (module + Wings), and * floating actions. Same ink chrome and status palette as the originals. */ @@ -152,6 +152,109 @@ export function TerminalReplyDemo() { ); } +/** RemoteMirror's progress steps, in order. */ +const SETUP_STEPS = [ + "connecting", + "pushing the hook binary", + "configuring agents", + "checking the host can reach this Mac" +]; + +export function RemoteHostDemo() { + /* -1 not set up · 0…3 setting up · 4 live */ + const [step, setStep] = createSignal(-1); + const [pressed, setPressed] = createSignal(false); + useDemoLoop(11000, [ + [0, () => (setStep(-1), setPressed(false))], + [1400, () => setPressed(true)], + [1700, () => (setPressed(false), setStep(0))], + [2700, () => setStep(1)], + [3700, () => setStep(2)], + [4700, () => setStep(3)], + [5800, () => setStep(4)] + ]); + const live = () => step() === 4; + const working = () => step() >= 0 && step() < 4; + const chip = () => + live() + ? { color: STATUS.ready, label: "Live" } + : working() + ? { color: "rgba(255,255,255,0.55)", label: "Setting up" } + : { color: "rgba(255,255,255,0.35)", label: "Not set up" }; + + return ( +

+ ); +} + /* ── Capture: the module, and the Wings while a recording runs ────── */ /** CapturePalette.recording and the NookPalette paper/ink pair. */ diff --git a/src/routes/nook/remote-claims.test.ts b/src/routes/nook/remote-claims.test.ts index f15f6bb..9f51d55 100644 --- a/src/routes/nook/remote-claims.test.ts +++ b/src/routes/nook/remote-claims.test.ts @@ -1,39 +1,15 @@ /** - * Regression test for the removed remote / SSH claims and the removed agent - * count (FRE-323, FRE-359 verdict B). - * - * FRE-323 took the remote story off the site because it was unverified and - * demo-gated (FRE-315, FRE-320, FRE-322 §3 correction 4): the "one click - * installs the nook-hook" flow is app-UI-only, needs a hand-edited - * `~/.ssh/config` for any host not already in ssh config or on the tailnet, - * needs a one-time `ssh-copy-id` because the app runs ssh with - * `BatchMode=yes`, and has no manual fallback for minting the per-host - * credential. FRE-359 verdict B removed the coverage count for the same - * reason: the /agents table lists 13 of the registry's 18 rows. - * - * The copy was not thrown away — it is parked in - * `marketing/drafts/remote-ssh/` with the restore gate, and this test asserts - * it is still there so nobody deletes the parked story as stale. It goes back - * on the site only when the one-click install ships and is recorded. - * - * STATIC SOURCE AUDIT, the same pattern as `agents.test.ts` and - * `downloads.test.ts` (SolidJS does not render under `bun:test`). - * - * Deliberate exceptions, not audited here — both were weighed with the Chief - * of Staff at the go/no-go and left in place on purpose: - * - `src/routes/nook/agents.tsx` Muse row: "This Mac only — remote hosts skip - * it" is a limitation disclosure, not a capability claim. - * - `src/components/nook/IslandExtras.tsx` "Tailscale hosts" chip: adjacent to - * the removed remote story, but tailnet host lookup does exist. Raised on - * FRE-323 rather than widened into this correction. + * NOOK-1038 restores remote marketing for Tailscale and authorized known hosts, + * per Mike's correction. FRE-323's blanket removal is no longer the contract; + * one-click setup is a supported scoped claim, not a promise for any SSH box. + * FRE-359's separate decision against agent coverage counts is unchanged. + * Static source audit, like agents.test.ts; browser checks cover rendered layout. */ import { describe, it, expect } from "bun:test"; import { readFileSync } from "node:fs"; import { join } from "node:path"; const ROOT = join(import.meta.dir, "../../.."); - -/** Shipped page and component source. Tests and drafts may quote the old copy. */ const AUDITED = [ "src/routes/nook/index.tsx", "src/routes/nook/agents.tsx", @@ -43,58 +19,74 @@ const AUDITED = [ "src/components/nook/IslandExtras.tsx" ]; -/** Every sentence FRE-323 ordered off the site. */ -const BANNED_REMOTE_CLAIMS = [ - "Agents on other machines", - "one click installs the nook-hook", - "Any SSH box", - "Works across every hooked agent, local or remote", - "Remote sessions are ordinary rows", - "One-click SSH setup", - "remote machines over SSH", - "this Mac or remote machines" -]; - -/** FRE-359 verdict B: no count, no coverage claim, in any form. */ -const BANNED_COVERAGE = [ - "all thirteen", - "thirteen coding agents", - "13 agents", - "every coding agent", - "Supported agents" -]; - -/** User-facing copy only: comments are not copy and may name the old wording. */ function copyOf(file: string): string { return readFileSync(join(ROOT, file), "utf8") .replace(/\/\*[\s\S]*?\*\//g, "") .replace(/^\s*\/\/.*$/gm, ""); } -describe("remote claims stay off the site (FRE-323)", () => { +describe("remote marketing reflects the supported setup (NOOK-1038)", () => { + it("fills the collage's missing sixth grid slot with host-labelled remote sessions", () => { + const collage = copyOf("src/components/nook/FeatureCollage.tsx"); + // The hero spans two columns; four regular cards fill the other slots. + expect(collage.match(/ { + const breakdowns = copyOf("src/components/nook/FeatureBreakdowns.tsx"); + expect(breakdowns).toContain('kicker="Remote"'); + expect(breakdowns).toContain('title="Set up remote agents in one click"'); + expect(breakdowns).toContain( + "Tailscale peer or an authorized host from your SSH config" + ); + expect(breakdowns).toContain(""); + }); + + it("demonstrates setup progressing to Live and a host-labelled session", () => { + const demos = copyOf("src/components/nook/MoreDemos.tsx"); + for (const label of [ + "connecting", + "pushing the hook binary", + "configuring agents", + "checking the host can reach this Mac", + "Live", + "Set up" + ]) + expect(demos).toContain(label); + expect(demos).toContain('host="gpu-rig"'); + }); + for (const file of AUDITED) { - it(`${file} does not restore a removed remote sentence`, () => { - const copy = copyOf(file); - for (const phrase of BANNED_REMOTE_CLAIMS) { - expect(copy.toLowerCase()).not.toContain(phrase.toLowerCase()); - } + it(`${file} makes no blanket authorization or agent-coverage promise`, () => { + const copy = copyOf(file).toLowerCase(); + for (const phrase of [ + "Any SSH box", + "Works across every hooked agent, local or remote", + "no SSH authorization needed" + ]) + expect(copy).not.toContain(phrase.toLowerCase()); }); } - it("/agents no longer offers remote sessions", () => { - const copy = copyOf("src/routes/nook/agents.tsx"); - expect(copy).not.toContain("remote sessions report into the same grid"); - expect(copy).not.toContain("on this Mac or on remote"); - }); - - it("the parked copy still exists, so restoring the story is a revert and not a rewrite", () => { - const parked = readFileSync(join(ROOT, "marketing/drafts/remote-ssh/copy.md"), "utf8"); - for (const phrase of ["Agents on other machines", "Any SSH box, one click away"]) { - expect(parked).toContain(phrase); + it("records the current decision without deleting the historical copy", () => { + for (const file of [ + "marketing/drafts/remote-ssh/copy.md", + "marketing/drafts/remote-ssh/rationale.md", + "marketing/positioning.md" + ]) { + const text = readFileSync(join(ROOT, file), "utf8"); + expect(text).toContain("NOOK-1038"); + expect(text).toContain("Tailscale and authorized known hosts"); } - expect(readFileSync(join(ROOT, "marketing/drafts/remote-ssh/rationale.md"), "utf8")).toContain( - "FRE-320" - ); + expect( + readFileSync(join(ROOT, "marketing/drafts/remote-ssh/copy.md"), "utf8") + ).toContain("Any SSH box, one click away"); }); }); @@ -102,9 +94,14 @@ describe("agent coverage count stays off the page (FRE-359 verdict B)", () => { for (const file of AUDITED) { it(`${file} states no coverage count`, () => { const copy = copyOf(file); - for (const phrase of BANNED_COVERAGE) { + for (const phrase of [ + "all thirteen", + "thirteen coding agents", + "13 agents", + "every coding agent", + "Supported agents" + ]) expect(copy.toLowerCase()).not.toContain(phrase.toLowerCase()); - } }); }