Skip to content

Commit 91d3aaa

Browse files
phurynclaude
andcommitted
Adjustable chat font size (grok.chatFontScale, #14) (v1.4.9)
Lets users zoom the Grok chat panel on its own — text, icons, and spacing together — without rescaling the rest of VS Code (the reporter's complaint in #14 about the global Ctrl/Cmd+Shift+=). It's a percent setting (60–300, default 100) at User or Workspace scope and applies live with no reload. The webview uses CSS `zoom`, which scales layout but which `vh` units ignore — a 100vh body at zoom 0.7 renders at 70vh and leaves dead space below the composer. Both the `zoom` and a `height: calc(100vh / var(--chat-zoom))` compensation are derived from one `--chat-zoom` variable (baked into <body> by the host, updated live via postMessage), so the composer stays pinned to the bottom at any scale. Also: README screenshots for Voice input and the Agent Dashboard, plus a few wire-level details moved from the feature blurbs into docs/architecture.md. 473 tests green; live gate green (5 passed, image-gen SKIP). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 384283d commit 91d3aaa

10 files changed

Lines changed: 83 additions & 15 deletions

File tree

.vscode/settings.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
// Zoom for the Grok chat panel only (percent, 100 = default). Bump this to
3+
// 150 / 200 to test issue #14 without rescaling the rest of VS Code.
4+
"grok.chatFontScale": 100
5+
}

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# Changelog
22

3+
## 1.4.9 — 2026-06-16
4+
5+
> Make the chat bigger — just the chat.
6+
7+
### Features
8+
9+
- **Adjustable chat font size (#14).** A new `grok.chatFontScale` setting zooms the Grok chat panel only — text, icons, and spacing together — as a percent (e.g. `150`, `200`, or smaller like `70`). Unlike VS Code's global `Ctrl/Cmd+Shift+=`, it leaves the rest of the editor at its normal size, so you can enlarge (or shrink) just the chat for readability. It applies live with no reload, the composer stays pinned to the bottom of the panel at any scale, and it works at both User (global) and Workspace (local) scope. ([package.json](package.json), [src/sidebar.ts](src/sidebar.ts), [media/chat.css](media/chat.css), [media/chat.js](media/chat.js))
10+
11+
### Docs
12+
13+
- **README polish.** Added screenshots for *Voice input* and the *Agent Dashboard*, and moved a few wire-level implementation details out of the feature blurbs into [docs/architecture.md](docs/architecture.md) so the feature list reads less like internals. ([README.md](README.md), [docs/architecture.md](docs/architecture.md))
14+
315
## 1.4.8 — 2026-06-15
416

517
> Run several Grok sessions at once — switch between them instantly, and see at a glance which one needs you.

CLAUDE.md

Lines changed: 4 additions & 3 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ Works with a SuperGrok subscription or an xAI API key. **Not affiliated with xAI
1212

1313
![Generated image rendered inline from /imagine](docs/screenshots/imagine.png)
1414

15-
**[More screenshots →](docs/screenshots/)**
16-
1715
---
1816

1917
## Why an extension, not the CLI?
@@ -97,7 +95,7 @@ _Click any feature to expand._
9795
<details>
9896
<summary><strong>Permission cards with diff preview</strong> — see every edit in VS Code's native diff before you approve</summary>
9997

100-
For `kind:"edit"` tool calls the card shows a `path — N → M lines` summary and an **open diff →** button that opens VS Code's native diff editor against the proposed content. Approve with *Allow once / always*, or *Reject*. The actual write only happens *after* you approve, via `fs/write_text_file` — no surprise changes to your files.
98+
When Grok proposes an edit, the card shows a `path — N → M lines` summary and an **open diff →** button that opens VS Code's native diff editor against the proposed content. Approve with *Allow once / always*, or *Reject*. The file is written only **after** you approve — no surprise changes to your files.
10199

102100
</details>
103101

@@ -115,7 +113,7 @@ For `kind:"edit"` tool calls the card shows a `path — N → M lines` summary a
115113
<details>
116114
<summary><strong>Image & video generation</strong> — <code>/imagine</code> renders right in the chat</summary>
117115

118-
Type `/imagine <prompt>` (or `/imagine-video <prompt>`) and the result renders **inline** — images as a compact thumbnail (capped at 320px; click to open the source file), videos with native playback controls. Hover either for **Copy path** / **Open in VS Code** icons. Both are **subscription-only** Grok features, both survive a session resume, and the file is streamed from disk so even a multi-MB video plays. (Editing a reference photo with `/imagine` works too, via Grok's `image_edit` tool.) Wire-format details: [research/image-generation.md](research/image-generation.md).
116+
Type `/imagine <prompt>` (or `/imagine-video <prompt>`) and the result renders **inline** — images as a compact thumbnail (capped at 320px; click to open the source file), videos with native playback controls. Hover either for **Copy path** / **Open in VS Code** icons. Both are **subscription-only** Grok features, both survive a session resume, and even a multi-MB video plays. Editing a reference photo with `/imagine` works too. Wire-format details, for the curious: [research/image-generation.md](research/image-generation.md).
119117

120118
</details>
121119

@@ -128,6 +126,8 @@ The two-word send phrase is deliberate (it won't fire on a message that merely e
128126

129127
> **Cost:** Speech-to-Text is a *separate*, pay-as-you-go xAI product — **$0.10/hr** batch, **$0.20/hr** streaming, billed by audio duration. In practice ~500 words ≈ ½–1¢; a heavy 10,000-word day ≈ 10¢. It needs its own [console.x.ai](https://console.x.ai) key (`grok.voiceApiKey` / `GROK_VOICE_API_KEY` / `XAI_API_KEY`) — a SuperGrok subscription grants no API credit. Why it bypasses the CLI, and how the cost was measured end-to-end: [research/voice-input.md](research/voice-input.md).
130128
129+
![Voice input with live transcription in the composer](docs/screenshots/voice_mode.png)
130+
131131
</details>
132132

133133
<details>
@@ -156,21 +156,23 @@ The green/red dot is an **unread** badge: it appears when a session finishes whi
156156

157157
To keep a pile of background sessions from each pinning a live process, a session left untouched for an hour (or beyond ~8 live) is quietly shut down — never one that's working or waiting on you — and reloads from history on click, losing nothing.
158158

159+
![Session status dots in the history dropdown](docs/screenshots/v1.4.7_visual_status.jpg)
160+
159161
</details>
160162

161163
<details>
162164
<summary><strong>Instant feedback</strong> — a <em>Grokking…</em> indicator the moment you send, with no startup pause</summary>
163165

164166
Every message you send shows an animated **Grokking…** placeholder immediately, so there's always feedback that Grok received it — it's replaced in place the instant the first thought, reply, or tool action streams in.
165167

166-
There's also no longer a long silent pause before that first response. The extension primes each new session with a hidden plan-mode instruction; that primer now runs **eagerly in the background** the moment the session goes live (and on resume, and after `/compact`) instead of sitting in front of your first message — so it's almost always finished before you hit send. If you *are* quick, your message appears right away and is released the instant the primer settles. The primer text was also slimmed down so it completes in a beat rather than wandering off to read your workspace first.
168+
There's also no longer a long silent pause before that first response. Plan Mode needs a little hidden setup per session; it now happens **quietly in the background** the moment a session opens — instead of in front of your first message — so it's almost always done before you hit send. If you *are* quick, your message still appears right away. *(What that setup is and why it's needed: [How it works](#how-it-works).)*
167169

168170
</details>
169171

170172
<details>
171173
<summary><strong>Session history</strong> — resume, rename, or delete any past session</summary>
172174

173-
The clock icon lists every session the CLI saved for this project (`~/.grok/sessions/<urlencoded-cwd>/`). Click a row to resume — the extension calls `session/load` and Grok replays the conversation, with inline images, plans, and reasoning intact. Hover to rename (pencil) or delete (trash); names default to the first message. Renames live in VS Code's `globalState` and never touch Grok's own files.
175+
The clock icon lists every session the CLI saved for this project. Click a row to resume — Grok replays the conversation, with inline images, plans, and reasoning intact. Hover to rename (pencil) or delete (trash); names default to the first message. Renames are stored by the extension and never touch Grok's own files.
174176

175177
</details>
176178

@@ -184,7 +186,7 @@ Every action Grok takes appears in chat — a single flat row ("Read sidebar.ts
184186
<details>
185187
<summary><strong>Math &amp; LaTeX rendering</strong> — equations render as math, not raw TeX</summary>
186188

187-
When Grok answers with LaTeX — inline `\(…\)`, display `\[…\]`, and environments like `\begin{pmatrix}` matrices, `cases`, integrals, sums, and Greek — the chat renders it as real typeset math via [MathJax](https://www.mathjax.org), vendored into the extension so it works **offline with no network**. Inline math sits on the text baseline in your editor's text color; display equations get their own centered block with horizontal scroll so a wide matrix doesn't overflow the narrow sidebar. A malformed expression shows a small inline error instead of blanking the message. **Hover a display equation** for actions: copy its LaTeX source, or export it as a PNG (your theme's background) or a transparent SVG tuned for a light or dark background. Bare `$…$` is intentionally **not** a delimiter — it would mangle prose like "it costs $5 and then $10".
189+
When Grok answers with LaTeX — inline `\(…\)`, display `\[…\]`, and environments like `\begin{pmatrix}` matrices, `cases`, integrals, sums, and Greek — the chat renders it as real typeset math via [MathJax](https://www.mathjax.org), bundled into the extension so it works **offline with no network**. Inline math sits on the text baseline in your editor's text color; display equations get their own centered block with horizontal scroll so a wide matrix doesn't overflow the narrow sidebar. A malformed expression shows a small inline error instead of blanking the message. **Hover a display equation** for actions: copy its LaTeX source, or export it as a PNG (your theme's background) or a transparent SVG tuned for a light or dark background. Bare `$…$` is intentionally **not** a delimiter — it would mangle prose like "it costs $5 and then $10".
188190

189191
![LaTeX expressions rendered as typeset math](docs/screenshots/v1.4.5%20LaTeX%20expressions.png)
190192

@@ -193,7 +195,7 @@ When Grok answers with LaTeX — inline `\(…\)`, display `\[…\]`, and enviro
193195
<details>
194196
<summary><strong>Mermaid diagrams</strong> — flowcharts and sequence diagrams render as diagrams</summary>
195197

196-
When Grok answers with a ` ```mermaid ` block — flowcharts, sequence and state diagrams, git graphs, class and ER diagrams, and more — the chat renders it as a real diagram via [Mermaid](https://mermaid.js.org), vendored into the extension so it works **offline with no network**. Diagrams are themed to match your VS Code light/dark mode and scroll horizontally so a wide flowchart doesn't overflow the narrow sidebar. **Hover a diagram** to copy its source, or export it as a PNG (your theme's background) or a transparent SVG re-themed for a light or dark background. If a diagram is still streaming or turns out to be malformed, the readable diagram source is shown instead — you never lose the content.
198+
When Grok answers with a ` ```mermaid ` block — flowcharts, sequence and state diagrams, git graphs, class and ER diagrams, and more — the chat renders it as a real diagram via [Mermaid](https://mermaid.js.org), bundled into the extension so it works **offline with no network**. Diagrams are themed to match your VS Code light/dark mode and scroll horizontally so a wide flowchart doesn't overflow the narrow sidebar. **Hover a diagram** to copy its source, or export it as a PNG (your theme's background) or a transparent SVG re-themed for a light or dark background. If a diagram is still streaming or turns out to be malformed, the readable diagram source is shown instead — you never lose the content.
197199

198200
![Mermaid diagram rendered inline in the chat](docs/screenshots/v1.4.6%20Mermaid%20diagrams.png)
199201

@@ -202,7 +204,7 @@ When Grok answers with a ` ```mermaid ` block — flowcharts, sequence and state
202204
<details>
203205
<summary><strong>Model picker</strong> — switch models live, no restart</summary>
204206

205-
Click the model name in the gear popover. The list comes from the CLI's `session/new` response; switching is live (`session/set_model`) with no restart when the target model belongs to the same agent.
207+
Click the model name in the gear popover. The model list comes from your CLI; switching is live with no restart in most cases. (A few models belong to a different agent and need a quick session restart — the extension detects that and handles it for you, carrying your context forward.)
206208

207209
</details>
208210

@@ -247,6 +249,7 @@ Or edit the config via gear → *Open global / project config*, then click **+**
247249
| `grok.defaultEffort` | `""` | Reasoning effort forwarded as `--reasoning-effort` (`none` / `minimal` / `low` / `medium` / `high` / `xhigh`). Empty = CLI default. Changing it restarts the session. |
248250
| `grok.includeActiveFileByDefault` | `true` | Auto-add the active editor as a context chip. |
249251
| `grok.useCtrlEnterToSend` | `false` | When true, Enter inserts a newline and Ctrl/Cmd+Enter sends. |
252+
| `grok.chatFontScale` | `100` | Zoom for the chat panel only, as a percent (`150`, `200`, …). Scales the whole chat UI without rescaling the rest of VS Code (unlike `Ctrl/Cmd+Shift+=`). Applies live; supports User (global) and Workspace (local) scope. |
250253
| `grok.voiceApiKey` | `""` | xAI API key for voice Speech-to-Text — a separate [console.x.ai](https://console.x.ai) developer key, not the CLI login. Empty = fall back to `GROK_VOICE_API_KEY` / `XAI_API_KEY` in the workspace `.env`. |
251254
| `grok.ffmpegPath` | `""` | Path to `ffmpeg` for microphone recording. Empty = use `ffmpeg` from `PATH`. |
252255
| `grok.voiceInputDevice` | `""` | Microphone device override. Empty = system default (Windows auto-detects the first DirectShow audio device). |

docs/architecture.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,18 @@ The full pedagogical write-up lives in
216216
- **`available_commands_update` drives slash autocomplete.** No hardcoded command
217217
list; the CLI tells the extension what's available, so plugin/skill installs
218218
surface immediately.
219+
- **Model switching is agent-aware.** Models belong to *agent types*
220+
(`grok-build`/`grok-build-plan` vs. the `cursor` agent that owns the Composer
221+
models). The CLI binds the agent when the process spawns and locks it after the
222+
first turn (including our primer), so a live `session/set_model` only works
223+
*within* the same agent — a cross-agent switch errors
224+
`MODEL_SWITCH_INCOMPATIBLE_AGENT`. So `switchModel` tries the live switch and,
225+
on that specific error (`isIncompatibleAgentError` in
226+
[src/acp-dispatch.ts](../src/acp-dispatch.ts)), persists the pick to
227+
`grok.defaultModel` and restarts — `newSession` re-applies the model *before* the
228+
primer runs, while the agent is still rebindable. No history → transparent
229+
restart; with history → the same Summarize / Just-Restart choice as an effort
230+
change.
219231
- **Generated media is path-based, not an ACP image block.** `/imagine` and
220232
`/imagine-video` write a file into the session dir and report its *path* as
221233
JSON-in-text on the completed tool result. The host parses the path, classifies
361 KB
Loading

media/chat.css

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,14 @@ html, body {
1818
body {
1919
display: flex;
2020
flex-direction: column;
21-
height: 100vh;
21+
/* grok.chatFontScale zooms the chat via --chat-zoom (set inline on <body>).
22+
`zoom` scales layout but `vh` ignores it, so a 100vh body at zoom 0.7 would
23+
render at 70vh and leave dead space below the composer — divide the height
24+
back out so the body always fills the viewport and the composer stays
25+
pinned to the bottom at any scale. */
26+
zoom: var(--chat-zoom, 1);
27+
height: calc(100vh / var(--chat-zoom, 1));
28+
overflow: hidden;
2229
}
2330

2431
.muted { color: var(--vscode-descriptionForeground); }

media/chat.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2721,6 +2721,13 @@
27212721
state.cwd = msg.cwd || "";
27222722
state.extVersion = msg.extVersion || "";
27232723
break;
2724+
case "fontScale":
2725+
// Live chat-only zoom (grok.chatFontScale). Initial value is baked into
2726+
// <body style="--chat-zoom:…"> by the host; this just applies later edits.
2727+
// The CSS derives both `zoom` and the viewport-height compensation from
2728+
// this one variable, so the composer stays pinned to the bottom.
2729+
document.body.style.setProperty("--chat-zoom", String(msg.value || 1));
2730+
break;
27242731
case "grokUpdateStatus":
27252732
// Reply to the About panel's checkGrokUpdate. The check also reports the
27262733
// CLI's current version — adopt it, since the ACP handshake doesn't always

package.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "grok-vscode-phuryn",
33
"displayName": "Grok Build",
44
"description": "Thin VS Code sidebar client for the Grok Build CLI over Agent Client Protocol (ACP). Streams responses with thinking traces, tool calls, file chips, and permission cards with diff preview. All session state stays in the CLI. Not affiliated with xAI.",
5-
"version": "1.4.8",
5+
"version": "1.4.9",
66
"publisher": "PawelHuryn",
77
"author": {
88
"name": "Paweł Huryn",
@@ -191,6 +191,13 @@
191191
"default": false,
192192
"description": "Use Ctrl/Cmd+Enter to send (Enter inserts newline)."
193193
},
194+
"grok.chatFontScale": {
195+
"type": "number",
196+
"default": 100,
197+
"minimum": 60,
198+
"maximum": 300,
199+
"markdownDescription": "Zoom for the Grok chat panel only, as a percent (100 = default). Scales the whole chat UI — text, icons, spacing — without affecting the rest of VS Code (unlike `Ctrl/Cmd+Shift+=`). Applies live, no reload needed. Supports User (global) and Workspace (local) scope."
200+
},
194201
"grok.voiceApiKey": {
195202
"type": "string",
196203
"default": "",

src/sidebar.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,9 @@ export class GrokSidebar implements vscode.WebviewViewProvider {
187187
) {
188188
this.postVoiceConfigured();
189189
}
190+
if (e.affectsConfiguration("grok.chatFontScale")) {
191+
this.postFontScale();
192+
}
190193
});
191194
}
192195

@@ -1623,6 +1626,17 @@ See design doc for the full state machine diagram.`;
16231626

16241627
/** Tell the webview whether a voice API key is resolvable, so the mic button
16251628
* can show a "needs setup" hint up front instead of only failing on click. */
1629+
/** Chat-panel zoom factor (1.0 = 100%). Clamped to the declared 60–300% range. */
1630+
private chatFontScale(): number {
1631+
const pct = vscode.workspace.getConfiguration("grok").get<number>("chatFontScale", 100);
1632+
const n = Number.isFinite(pct) ? (pct as number) : 100;
1633+
return Math.min(300, Math.max(60, n)) / 100;
1634+
}
1635+
1636+
private postFontScale(): void {
1637+
this.post({ type: "fontScale", value: this.chatFontScale() });
1638+
}
1639+
16261640
private postVoiceConfigured(): void {
16271641
const cwd = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath ?? process.cwd();
16281642
const cfg = vscode.workspace.getConfiguration("grok");
@@ -2359,7 +2373,7 @@ See design doc for the full state machine diagram.`;
23592373
content="default-src 'none'; style-src ${webview.cspSource} 'unsafe-inline'; img-src ${webview.cspSource} data:; media-src ${webview.cspSource} data:; font-src ${webview.cspSource}; script-src 'nonce-${nonce}';" />
23602374
<link rel="stylesheet" href="${mediaUri("chat.css")}" />
23612375
</head>
2362-
<body>
2376+
<body style="--chat-zoom: ${this.chatFontScale()}">
23632377
23642378
<header class="top-bar">
23652379
<button id="history-btn" class="toolbar-btn" title="Session history"></button>

0 commit comments

Comments
 (0)