Skip to content

FE-845: TUI chrome resolutions pass I#196

Merged
lunelson merged 4 commits into
nextfrom
ln/fe-845-brunch-chrome-pass-i
Jun 11, 2026
Merged

FE-845: TUI chrome resolutions pass I#196
lunelson merged 4 commits into
nextfrom
ln/fe-845-brunch-chrome-pass-i

Conversation

@lunelson

@lunelson lunelson commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Suppress Pi startup noise inside the Brunch TUI.
  • Add startup/header chrome that exposes the Brunch identity and dev sidecar URL.

lunelson commented Jun 10, 2026

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@lunelson lunelson changed the title Suppress Pi startup updates in Brunch TUI FE-845: TUI chrome resolutions pass I Jun 11, 2026
@lunelson lunelson marked this pull request as ready for review June 11, 2026 07:52
Copilot AI review requested due to automatic review settings June 11, 2026 07:52
@cursor

cursor Bot commented Jun 11, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
Changes are confined to TUI chrome, launch env scoping, and dev-only tooling with broad test coverage; no graph, auth, or mutation paths are affected.

Overview
TUI launch chrome now threads the web sidecar URL and activation decision from runBrunchTui into BrunchChromeState, showing a web-ui: line in the footer and an expandable Brunch startup header (logo, shortcuts, optional expanded project/spec/session help) on every activated launch (continue, openSession, newSpec, newSession) while resume paths stay quiet.

Pi startup behavior changes: runWithScopedBrunchOfflineDefault always applies the Brunch offline default (including under BRUNCH_DEV) and restores both PI_OFFLINE and PI_SKIP_VERSION_CHECK after InteractiveMode.run(), instead of clearing offline in dev to chase live-provider behavior. Browser auto-open defaults off when BRUNCH_DEV is set unless autoOpen is explicitly true; the sidecar URL is still advertised and passed into chrome.

Adds BrunchStartupHeader and chrome wiring/docs, enables the chrome extension in src/.pi/settings.json for direct-Pi iteration, and introduces an opt-in TUI style lab (/brunch:tui-style-lab) with palette/segment helpers for dev-only styling previews. SPEC (memory/SPEC.md) and tests are updated for D35-L, D69-L, D71-L, and I42-L.

Reviewed by Cursor Bugbot for commit 25dc094. Bugbot is set up for automated code reviews on this repo. Configure here.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit b4186e2. Configure here.

return this.theme.fg('dim', `web-ui: ${sanitizeText(this.facts.sidecarUrl)}`);
}
return this.theme.fg('dim', 'Press ctrl+o to show full Brunch startup help and active surfaces.');
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Startup header expand unwired

Medium Severity

The new BrunchStartupHeader supports collapsed vs expanded rendering and tells users to use ctrl+o for “more”, but it never implements handleInput and the chrome extension does not register a shortcut to call setExpanded. With a live webSidecarUrl, the collapsed header also omits the expand hint, so session/spec detail shown only when expanded may be unreachable in normal TUI launches.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit b4186e2. Configure here.

Comment thread src/app/brunch-tui.ts

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the Brunch TUI launch path to (a) reduce Pi startup noise and (b) add visible “chrome” (header/footer/title) that surfaces Brunch identity plus the active web sidecar URL.

Changes:

  • Thread web-sidecar URL + activation decision through the TUI launch context and into the chrome state, and adjust browser auto-open defaults under BRUNCH_DEV.
  • Add chrome header/footer projections (including startup header rendering) and enable the chrome extension entrypoint in src/.pi/settings.json.
  • Introduce a dev-only “TUI style lab” extension + component helpers, with dedicated unit tests.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/app/brunch-tui.ts Threads webSidecarUrl/activation decision into session runtime + chrome; scopes Pi env vars during interactive run; updates auto-open logic.
src/app/brunch-tui.test.ts Extends boot tests for decision propagation, auto-open defaults under BRUNCH_DEV, and env scoping behavior.
src/.pi/settings.json Enables the chrome extension entrypoint for direct Pi iteration.
src/.pi/extensions/tui-lab/index.ts Adds dev-gated TUI style lab command + interactive overlay component.
src/.pi/extensions/README.md Documents new chrome ownership rules and launch-facts plumbing.
src/.pi/extensions/chrome/index.ts Adds startup header + sidecar URL projection into chrome; updates default extension entrypoint to register chrome.
src/.pi/components/tui-lab/style-palette.ts Adds palette/badge helpers for style lab rendering.
src/.pi/components/tui-lab/segment-track.ts Adds segment track helpers for cycling demo state in style lab.
src/.pi/components/tui-lab/index.ts Re-exports style lab component helpers.
src/.pi/components/chrome-header.ts Adds BrunchStartupHeader component that renders identity/help + optional sidecar URL.
src/.pi/tests/tui-lab-style.test.ts Tests palette/badge rendering and extension registration gating.
src/.pi/tests/tui-lab-cycle.test.ts Tests segment cycling helpers + demo component behavior.
src/.pi/tests/extension-registry.test.ts Asserts chrome entrypoint remains enabled in .pi/settings.json.
src/.pi/tests/chrome.test.ts Extends chrome projection tests for sidecar footer line + startup header behavior.
memory/SPEC.md Updates D35-L/D69-L/D71-L language to reflect the new chrome + startup suppression direction.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/app/brunch-tui.ts
Comment on lines 448 to 451
try {
if (options.dev) {
delete env.PI_OFFLINE;
} else {
applyBrunchOfflineDefault(env);
}
applyBrunchOfflineDefault(env);
await options.run();
} finally {
Comment on lines 459 to 465
@@ -443,19 +465,37 @@ describe('Brunch TUI boot', () => {
}),
Comment on lines 471 to +478
await expect(
runWithScopedBrunchOfflineDefault({
dev: true,
env: devEnv,
run: async () => {
expect(devEnv.PI_OFFLINE).toBeUndefined();
expect(devEnv.PI_OFFLINE).toBe('1');
},
}),
Comment thread src/app/brunch-tui.ts
Comment on lines 438 to 441
export async function runWithScopedBrunchOfflineDefault(options: {
readonly dev: boolean;
readonly env?: { PI_OFFLINE?: string };
readonly env?: { PI_OFFLINE?: string; PI_SKIP_VERSION_CHECK?: string };
readonly run: () => Promise<void>;
Comment on lines +74 to +78
return formatBrunchProductIdentity({
logoLines: readBrunchAnsiLogo({ assetUrl: ASSET_DIR, truecolor: true }),
version: brunchVersion(),
theme: this.theme,
});
Comment thread memory/SPEC.md
- **D40-L — Runtime state is transcript-backed Brunch session-agent state, not hidden extension memory.** `src/session/runtime-state.ts` owns the transcript entry facts (`brunch.agent_runtime_state` schema, parser, and init/switch append helpers); `src/projections/session/runtime-state.ts` owns the pure reusable projection, `src/projections/session/runtime-policy.ts` owns operational-mode/role policy plus shared grade legality tables, and `src/projections/session/affordances.ts` owns the pure `(resolvedState, readinessGrade) → legal options + default-on-switch` derivation for goal/strategy/lens. The projection reconstructs agent posture from linear `brunch.agent_runtime_state` entries (`reason: "init" | "switch"`), last-writer-wins at turn preparation and over `session.runtimeState`; default/empty slots are explicit when no entry family exists. Runtime-state entries are Pi JSONL state-change facts, not assistant/user chat content: init and switch entries should render, when visible, as dim non-chat state rows analogous to Pi thinking/model-change rows, and must not enter LLM context as ordinary conversation. Its axes are `op_mode` (`elicit`, future `execute`) plus optional, AUTO-able objective axes `strategy`, `lens`, and `goal` (D25-L, D59-L). **Posture switches (durable `reason: "switch"` entries) are a user/system authority: the foreground agent never emits a posture switch.** The agent's only in-axis freedom is `AUTO` (per-turn implicit selection from the D58-L manifest); what it actually chose each turn is legible downstream via per-emission facet stamping (D25-L), not via runtime-state — so runtime-state is the *frame/constraints* while emitted facets carry the agent's per-turn choice. User-mutable axes are `op_mode`, `strategy`, and `lens`; `goal` is internal/grade-derived and not part of the user posture-change surface for now (D59-L). On a parent switch that invalidates a child axis, the child defaults to `AUTO`. The `source: "agent"` entry value is reserved — no current path emits it; it is parked for a future execute-mode orchestrator that might legitimately steer sub-postures. `session.runtimeState` also exposes shaped mention slots, world-update watermarks (latest graph LSN and optional git head, without raw transcript detail bags), and lifecycle facts when transcript-backed entries make them computable; this is a projection contract, not a mutable state table. The **foreground session agent** (`elicitor` now, future `executor`) is *derived* from `op_mode`, not stored; the other agent roles (`reviewer`, `reconciler`, future `scout`/`researcher`) are async sub-agent/side-chain workers (D29-L, D44-L) invoked out-of-band, never part of the session state machine. `op_mode` gates tool authority, applied by `src/.pi/extensions/runtime/index.ts` (current `elicit` policy denies side-effecting `bash`/`edit`/`write` plus user-shell interception) while `.pi` reuses session-owned entry definitions and projected policy. Prompt composition is a separate concern (D58-L). Depends on: D17-L, D23-L, D25-L, D39-L, D58-L, D59-L. Supersedes: mode-only vocabulary, extension-local mutable state as authority, storing the foreground role as independent session state, the "runtime bundle / role preset" as one knob deriving model/thinking/resources, and binding prompt-resource location to `src/.pi/context/`.
- **D34-L — Command containment separates visibility suppression from effect blocking.** Current Pi extension seams can hide unsupported slash suggestions with autocomplete wrapping and can cancel branch/session effects through lifecycle hooks, but they cannot strictly suppress exact interactive built-in commands before `InteractiveMode` dispatches them. Brunch-owned commands must use product-specific names and route writes through Brunch handlers/`CommandExecutor`; extension command collisions are not an override mechanism. Strict built-in command/keybinding policy is a Pi upstream/API ask, while POC safety relies on hiding generic affordances, blocking dangerous effects (`/fork`, `/clone`, `/tree`, raw session replacement), and failing fast on branched transcripts. Brunch's command-policy code should live in `src/.pi/extensions/commands/policy.ts`, merging branch/session-effect blocking with any product command allow/deny behavior instead of preserving a branch-only module. Depends on: D2-L, D24-L, A18-L. Supersedes: treating extension `input` handlers or command-name collisions as built-in command allowlisting.
- **D35-L — Dynamic TUI chrome is a Brunch projection wrapper over Pi UI primitives.** Downstream TUI affordances should call a Brunch-owned renderer (`renderBrunchChrome` or its successor) with one activated product-state value rather than scattering raw `ctx.ui.setHeader`, `setFooter`, `setWidget`, title, or working-indicator calls. The wrapper is stateless projection over canonical workspace/session/graph facts, including the discovered project name, selected spec, and real activated session id/label, while its TUI footer compositor may read Pi footer telemetry (`getGitBranch`, foreign `getExtensionStatuses`) at render time. Brunch chrome and startup dialog are project-first shell surfaces with selected-spec context: the project name labels the cwd container, the spec title labels the selected graph, and the session label distinguishes transcript instances. Brunch chrome does not publish a `brunch.chrome` status key; `ctx.ui.setStatus(key, text)` remains a lateral contribution channel for other extensions and future dynamic Brunch state. RPC clients should rely only on surfaces Pi actually emits for the wrapper (currently diagnostic widget/title, plus any future explicit status adapter) because header/footer/working-indicator are TUI-only in current Pi RPC mode. Session display names are product projections over Pi session metadata: every Brunch-created session should immediately receive a neutral workspace-global `Untitled Session N` `session_info` label, and later user/generated names may characterize the transcript without replacing spec identity or graph truth. Depends on: D2-L, D21-L, D34-L, A18-L. Supersedes: treating Pi UI methods as direct downstream affordance APIs, rendering placeholder session state such as `unbound` after a session is activated, consuming the status-key namespace for chrome's own static summary, using spec title as the default session label, or allowing two unchanged Brunch-created default names to collide in one cwd.
- **D35-L — Dynamic TUI chrome is a Brunch projection wrapper over Pi UI primitives.** Downstream TUI affordances should call a Brunch-owned renderer (`renderBrunchChrome` or its successor) with one activated product-state value rather than scattering raw `ctx.ui.setHeader`, `setFooter`, `setWidget`, title, or working-indicator calls. The wrapper is stateless projection over canonical workspace/session/graph facts, including the discovered project name, selected spec, real activated session id/label, launch activation kind for new-session startup headers, and app-supplied live sidecar URL when present, while its TUI footer compositor may read Pi footer telemetry (`getGitBranch`, foreign `getExtensionStatuses`) at render time. Brunch chrome and startup dialog are project-first shell surfaces with selected-spec context: the project name labels the cwd container, the spec title labels the selected graph, and the session label distinguishes transcript instances. New `newSpec` / `newSession` launches keep Pi `quietStartup` but install a Brunch-owned expandable header through the chrome wrapper; resume/open launches stay quiet. Brunch chrome does not publish a `brunch.chrome` status key; `ctx.ui.setStatus(key, text)` remains a lateral contribution channel for other extensions and future dynamic Brunch state. RPC clients should rely only on surfaces Pi actually emits for the wrapper (currently sidecar/widget-compatible string arrays and title, plus any future explicit status adapter) because header/footer/working-indicator are TUI-only in current Pi RPC mode. Session display names are product projections over Pi session metadata: every Brunch-created session should immediately receive a neutral workspace-global `Untitled Session N` `session_info` label, and later user/generated names may characterize the transcript without replacing spec identity or graph truth. Depends on: D2-L, D21-L, D34-L, A18-L. Supersedes: treating Pi UI methods as direct downstream affordance APIs, rendering placeholder session state such as `unbound` after a session is activated, consuming the status-key namespace for chrome's own static summary, using spec title as the default session label, or allowing two unchanged Brunch-created default names to collide in one cwd.
Base automatically changed from ln/fe-846-web-revamp-ii to next June 11, 2026 12:18
@lunelson lunelson force-pushed the ln/fe-845-brunch-chrome-pass-i branch from b4186e2 to 25dc094 Compare June 11, 2026 14:30
@lunelson lunelson merged commit 2114616 into next Jun 11, 2026
6 checks passed
@lunelson lunelson deleted the ln/fe-845-brunch-chrome-pass-i branch June 11, 2026 14:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants