diff --git a/openspec/changes/agent-claude-gitguardex-dmux-cockpit-phase2-welcome-2026-05-05-09-11/proposal.md b/openspec/changes/agent-claude-gitguardex-dmux-cockpit-phase2-welcome-2026-05-05-09-11/proposal.md new file mode 100644 index 0000000..5be20d4 --- /dev/null +++ b/openspec/changes/agent-claude-gitguardex-dmux-cockpit-phase2-welcome-2026-05-05-09-11/proposal.md @@ -0,0 +1,36 @@ +# dmux-style cockpit — Phase 2: branded welcome screen + +## Why + +Phase 1 wired the dmux-style top-bar shortcuts (`[n]ew agent`, +`[t]erminal`, `[l]ogs`, `[p]rojects`). The welcome screen still shows +the original `gx` ASCII robot motif and lists only the legacy `n`/`t`/ +`s` next-actions. To match the dmux look users asked for and to +advertise the new shortcuts on first launch, the welcome page needs a +proper gitguardex brand block and an updated next-actions list. + +## What changes + +- Replace the 5-line `GUARD_MOTIF` (`/ _)`, `/ gx \`) with a 5-line + ASCII `GUARDEX` wordmark plus a single `guarded multi-agent cockpit` + strapline. +- Add `l logs` and `p projects` to the welcome screen's `Next actions` + block so users see all four primary shortcuts immediately. +- Keep the existing box, status rows (Repo / Branch / Safety / Hooks / + Locks / Agents), and shortcut block intact. + +## Impact + +- New constants `GITGUARDEX_BRAND` and `GITGUARDEX_STRAPLINE` in + `src/cockpit/welcome.js`. +- 2 lines added to the next-actions block. +- Tests: + - `renderWelcomePage snapshots the empty cockpit welcome strings` + extended to assert `l logs`, `p projects`, and the strapline. + - `renderWelcomePage stays width bounded and plain terminal safe` + swaps the obsolete `/ _)` / `/ gx \` motif assertions for the + new strapline + brand-marker checks. +- ASCII-only constraint preserved (no unicode block or box-drawing + chars, so plain terminals stay safe). +- No behavior change to safety model, branches, worktrees, locks, or + PR-only finish flow. diff --git a/openspec/changes/agent-claude-gitguardex-dmux-cockpit-phase2-welcome-2026-05-05-09-11/specs/cockpit-welcome/spec.md b/openspec/changes/agent-claude-gitguardex-dmux-cockpit-phase2-welcome-2026-05-05-09-11/specs/cockpit-welcome/spec.md new file mode 100644 index 0000000..ceb44b3 --- /dev/null +++ b/openspec/changes/agent-claude-gitguardex-dmux-cockpit-phase2-welcome-2026-05-05-09-11/specs/cockpit-welcome/spec.md @@ -0,0 +1,34 @@ +## ADDED Requirements + +### Requirement: Welcome screen renders the gitguardex brand and strapline +The cockpit welcome screen SHALL render a multi-line ASCII gitguardex +brand block followed by a single-line `guarded multi-agent cockpit` +strapline, in place of the previous `gx` ASCII robot motif. + +#### Scenario: Brand and strapline appear on the empty welcome +- **WHEN** `renderWelcomePage` is invoked with no active sessions +- **THEN** the rendered output contains the `\____|` marker from the + bottom of the ASCII brand +- **AND** the output contains the substring `guarded multi-agent cockpit`. + +### Requirement: Welcome screen advertises all four primary shortcuts +The cockpit welcome screen's `Next actions` block SHALL list `n`, `t`, +`l`, `p`, and `s` so users see all four primary dmux-style shortcuts on +first launch alongside the existing settings hint. + +#### Scenario: Next actions list includes l and p +- **WHEN** `renderWelcomePage` is invoked with any state +- **THEN** the rendered output contains the substrings `l logs` and + `p projects` in addition to the existing `n new agent`, `t terminal`, + and `s settings` lines. + +### Requirement: Welcome screen stays ASCII-only +The cockpit welcome screen SHALL remain plain-terminal safe: every +character in the rendered output (including the new brand block) MUST +fall within the printable ASCII range so terminals without unicode box +or block glyphs render correctly. + +#### Scenario: No characters above U+007F appear in the output +- **WHEN** `renderWelcomePage` is invoked with any state +- **THEN** the rendered output contains no character in the range + `[€-￿]`. diff --git a/openspec/changes/agent-claude-gitguardex-dmux-cockpit-phase2-welcome-2026-05-05-09-11/tasks.md b/openspec/changes/agent-claude-gitguardex-dmux-cockpit-phase2-welcome-2026-05-05-09-11/tasks.md new file mode 100644 index 0000000..913b11b --- /dev/null +++ b/openspec/changes/agent-claude-gitguardex-dmux-cockpit-phase2-welcome-2026-05-05-09-11/tasks.md @@ -0,0 +1,26 @@ +# Tasks + +## 1. Spec +- [x] 1.1 Capture proposal in `proposal.md` +- [x] 1.2 Capture spec delta in `specs/cockpit-welcome/spec.md` + +## 2. Tests +- [x] 2.1 Extend the empty-welcome snapshot test to assert `l logs`, + `p projects`, and the `guarded multi-agent cockpit` strapline. +- [x] 2.2 Replace the obsolete `/ _)` / `/ gx \` motif assertions + in the width-bounded test with strapline + brand-marker checks. + +## 3. Implementation +- [x] 3.1 Replace `GUARD_MOTIF` with `GITGUARDEX_BRAND` (5-line ASCII + wordmark for `GUARDEX`). +- [x] 3.2 Add `GITGUARDEX_STRAPLINE = 'guarded multi-agent cockpit'`. +- [x] 3.3 Wire the new brand and strapline into `renderWelcomePage` + in place of `GUARD_MOTIF.forEach(...)`. +- [x] 3.4 Add `l logs` and `p projects` rows to the `Next actions` + block. + +## 4. Cleanup +- [ ] 4.1 Commit changes on the agent branch. +- [ ] 4.2 Push branch and open a PR. +- [ ] 4.3 Run `gx branch finish ... --via-pr --wait-for-merge --cleanup`. +- [ ] 4.4 Record PR URL and `MERGED` evidence. diff --git a/src/cockpit/welcome.js b/src/cockpit/welcome.js index 66c4ba5..bf54780 100644 --- a/src/cockpit/welcome.js +++ b/src/cockpit/welcome.js @@ -9,13 +9,14 @@ const MIN_WIDTH = 48; const MAX_WIDTH = 88; const DEFAULT_AGENTS = ['codex', 'claude', 'opencode', 'cursor', 'gemini']; -const GUARD_MOTIF = [ - ' __', - ' / _)', - ' .-^^^-/', - '/ gx \\', - '|_|--|_|', +const GITGUARDEX_BRAND = [ + ' ____ _ _ _ ___ ___ _____ __', + ' / ___|| | | | / \\ | _ \\ | _ \\ | ____|\\ \\/ /', + '| | _ | | | |/ _ \\| |_) || | | || _| \\ /', + '| |_| || |_| / ___ \\ _ < | |_| || |___ / \\', + ' \\____| \\___/_/ \\_\\_| \\_\\____/ |_____|/_/\\_\\', ]; +const GITGUARDEX_STRAPLINE = 'guarded multi-agent cockpit'; function stringValue(value, fallback = '') { if (typeof value === 'string') { @@ -222,9 +223,13 @@ function renderWelcomePage(state = {}, settings = {}) { emptyLine(width), ]; - GUARD_MOTIF.forEach((motifLine) => { - lines.push(themedBoxedLine(motifLine, width, 'accent', theme)); + GITGUARDEX_BRAND.forEach((brandLine) => { + lines.push(themedBoxedLine(brandLine, width, 'accent', theme)); }); + lines.push( + emptyLine(width), + themedBoxedLine(GITGUARDEX_STRAPLINE, width, 'heading', theme), + ); lines.push( emptyLine(width), @@ -247,6 +252,8 @@ function renderWelcomePage(state = {}, settings = {}) { themedBoxedLine('Next actions', width, 'heading', theme), themedBoxedLine(' n new agent - start a guarded agent lane', width, 'secondary', theme), themedBoxedLine(' t terminal - open a repo terminal', width, 'secondary', theme), + themedBoxedLine(' l logs - tail apps/logs/*.log and lane events', width, 'secondary', theme), + themedBoxedLine(' p projects - switch repo (no lane selected)', width, 'secondary', theme), themedBoxedLine(' s settings - tune cockpit defaults', width, 'secondary', theme), colorize(divider(width), 'border', theme), ); diff --git a/test/cockpit-welcome.test.js b/test/cockpit-welcome.test.js index 1863a56..68a127d 100644 --- a/test/cockpit-welcome.test.js +++ b/test/cockpit-welcome.test.js @@ -28,10 +28,13 @@ test('renderWelcomePage snapshots the empty cockpit welcome strings', () => { assert.match(output, /Agents:\s+codex, claude/); assert.match(output, /n new agent/); assert.match(output, /t terminal/); + assert.match(output, /l logs/); + assert.match(output, /p projects/); assert.match(output, /s settings/); assert.match(output, /\? shortcuts/); assert.match(output, /q quit/); assert.match(output, /Next actions/); + assert.match(output, /guarded multi-agent cockpit/); assert.equal(output.endsWith('\n'), true); }); @@ -54,8 +57,8 @@ test('renderWelcomePage stays width bounded and plain terminal safe', () => { assert.equal(line.length <= width, true, `line exceeded ${width}: ${line}`); } - assert.match(output, /\/ _\)/); - assert.match(output, /\/ gx \\/); + assert.match(output, /guarded multi-agent cockpit/); + assert.match(output, /\\____\|/); assert.match(output, /Locks:\s+5/); assert.match(output, /Agents:\s+codex, gemini/); assert.doesNotMatch(output, /[\u0080-\uffff]/);