← Commit history

1.1.26: AI thread icons in the window title bar (vendor colours, check menu, per-window matching), GET/POST /ai/*, VSIX install through the code-server binary

John Lauer ·9e4254894c ·1mo ago ·parent dcad33d
6 files changed +118−63
README.md+79−55
@@ -1,50 +1,41 @@ # adom-vscode -A CLI + VS Code extension that lets AI assistants and the Hydrogen Desktop / Hydrogen Web frontend drive VS Code from inside an Adom Docker container: open files, change settings live, run container commands, pass events to the frontend, switch modes, paste screenshots, and run any VS Code command via a local HTTP API on port 8821.+Adom VS Code Extension for Adom's Docker containers running Coder's code-server. -## The Adom panel, your AI's cockpit inside VS Code+A single Rust binary that ships a VS Code extension + CLI for controlling code-server from any process in the Docker container. AI agents (Claude Code, Codex, Kimi) and scripts use this to open files, manage extensions, control the layout, change settings live, run container commands, and pass events to the Hydrogen Desktop / Hydrogen Web frontend. The binary embeds everything: the VSIX, bash completions, and the paste-screenshot interceptor, so `adom-vscode install` sets up the entire thing. -Click the Adom icon in the activity bar to open a side panel with the Overview, Modes, Commands, AI Prompts, Settings & Theme, Exec & Queue, Container & Keys, Extensions, and the live **Claude Context** viewer, every active Claude Code session in the container with token cost and last activity at a glance.--![adom-vscode panel, activity bar sidebar with Overview, Modes, Commands, AI Prompts, and the Claude Context viewer listing live sessions](screenshots/panel.png)--## The Extension: About page--Installed in every Adom container. Open the Extensions sidebar and search for `adom-vscode`: the details pane renders the full quick-start guide, mode reference, and version metadata.--![adom-vscode in the Extensions sidebar with the detail tab open, showing description, version, and the in-editor README](screenshots/extension-about.png)+Since v1.1.0 the extension is also the native replacement for host-side `wsl.exe` plumbing: settings apply live through the VS Code API (no window reload, no dropped Claude sessions), and shell commands run inside the container via `/exec` instead of an external `wsl.exe` spawn.  ## What it does  - **Open files** in VS Code tabs (images, text, anything) - **Reveal** files/folders in the Explorer sidebar - **Preview** Markdown files in rendered view-- **Settings, live**: get/set any VS Code setting, theme, fonts, font sizes. Changes apply immediately via the native VS Code API (no reload, active AI sessions survive)-- **Exec** (HD-local only): run shell commands in the container as the workspace user, streamed (SSE) or buffered, no host-side `wsl.exe` needed. Disabled on cloud (hw) containers by security policy+- **Settings, live**: get/set any VS Code setting, theme, fonts, font sizes. Changes apply immediately via `ConfigurationTarget.Global` (no reload, active AI sessions survive)+- **Exec**: run shell commands in the container as the workspace user, streamed (SSE) or buffered - **Event queue**: any container process pushes events; the HD/HW frontend pulls them when it wants (login-refresh needed, long-job progress, anything) - **Container identity**: query whether this is an `hd` (local Hydrogen Desktop) or `hw` (Adom cloud) container, OS, kernel, key env vars - **API key**: check the health of `/var/run/adom/api-key` and inject a fresh key after a frontend login refresh-- **Extensions**: list installed extensions (with Claude/Codex/Kimi summary), query version + running state + pending update, update one or all, search, install+- **Extensions**: list installed extensions (with Claude/Codex/Kimi summary), query one extension's version + running state + pending update, update one or all, search, install - **Start** new Claude Code conversations-- **Modes**: switch VS Code into different full-screen experiences:-  - `claudecode`: Claude Code panel UI (graphical AI chat)-  - `claudetty`: full-screen terminal running the claude CLI-  - `tty`: generic full-screen terminal with optional auto-command+- **Modes**: switch VS Code into different full-screen experiences (`claudecode`, `claudetty`, `tty`) - **Control layout**: sidebar, panel, terminal, activity bar (show/hide/toggle) - **Run** any VS Code command (generic escape hatch)+- **Activity bar icon**: Adom icon with accordion sidebar showing every verb, AI prompts, and modes - **Paste image into terminal**: Ctrl+V an image while focused in a code-server terminal uploads to `/tmp/shots/` and pastes the file path (so the CLI Claude Code can ingest it) -## Already installed--Adom VS Code ships with every Adom container, you have it on day one. Try it now: ask Claude in any terminal:+## Install -> *"open `ne555-timer.kicad_sch`"* &nbsp;·&nbsp; *"set my editor font size to 14"* &nbsp;·&nbsp; *"switch to Claude Code mode"* &nbsp;·&nbsp; *"is my api key still good?"*--To upgrade after a new release lands on the wiki, ask Claude:+```bash+# Download the binary (includes embedded VSIX + completions + paste-screenshot interceptor)+gh release download --repo adom-inc/adom-vscode --pattern "adom-vscode" --output /usr/local/bin/adom-vscode --clobber+sudo chmod +x /usr/local/bin/adom-vscode -> *"update adom-vscode"*+# Self-install everything+adom-vscode install+``` -Or run it yourself: `adom-wiki pkg update adom-vscode`.+Or via gallia: `node install.mjs` downloads the binary and runs `adom-vscode install`.  ## Port discovery @@ -54,7 +45,7 @@ The extension serves its HTTP API on **127.0.0.1:8821**. If 8821 is already take ~/.local/share/adom-vscode/port.json    # { "port": N, "preferredPort": 8821, "pid": ..., "version": ..., "startedAt": ... } ``` -External services that expect the well-known port should read that file when 8821 does not answer. The CLI already does (resolution order: `ADOM_VSCODE_PORT` env var, then `port.json`, then 8821). `GET /health` reports both `port` (actual) and `preferredPort`.+External services that expect the well-known port should read that file when 8821 does not answer. The CLI already does (resolution order: `ADOM_VSCODE_PORT` env var, then `port.json`, then 8821). The extension also drops an `adom-ports claim` breadcrumb when that CLI is present, and `GET /health` reports both `port` (actual) and `preferredPort`.  ## HTTP API (the verb surface) @@ -89,6 +80,8 @@ Everything the CLI does is a plain HTTP call, so HD, HW, and any script can hit | terminal.tui.list | `GET /terminal/tui/list` | Handles: id, name, command, running state | | terminal.tui.dispose | `POST /terminal/tui/dispose` `{id?, name?}` | Close a named TUI terminal by handle | | claude.new | `POST /claude/new` | New Claude Code conversation |+| ai.providers | `GET /ai/providers` | Which AIs are installed here (Claude Code, Codex, Kimi, Antigravity), the command a new tab runs, and which icons the user shows |+| ai.new | `POST /ai/new` `{type, tui?, group?}` | Open a new thread for that AI in an editor group (default: the active one) and keep it there; `tui:true` puts the AI's CLI in a terminal tab instead | | tabs.list | `GET /tabs` | Event-driven tab census from the extension host (`window.tabGroups`): every tab with `kind` (claude \| codex \| kimi \| terminal \| other), label, group/tab index, active flags; Codex rows carry `sessionId` from the editor URI. No DOM, no CDP | | tabs.events | `GET /tabs/events` (SSE) | The same census pushed on every tab open/close/move/focus change (`event: census`), plus `event: claude-session` when the SessionStart hook reports a new Claude session. Hydrogen holds one stream per workspace instead of polling the iframes | | claude.session-start | `POST /claude/session-start` `{session_id, transcript_path?, cwd?, source?}` | Ingest for a Claude `SessionStart` hook: records the session (last 100) and broadcasts it on `/tabs/events` |@@ -98,14 +91,15 @@ Everything the CLI does is a plain HTTP call, so HD, HW, and any script can hit | command | `POST /command` `{command, args?}` | Any VS Code command (escape hatch) | | notify | `POST /notify` `{message, level?}` | Toast notification | | mode.* | `POST /mode/claudecode\|claudetty\|tty\|reset` | Full-screen mode switching |+| paste-screenshot | `POST /paste-screenshot` (raw image body) | Save clipboard image to `/tmp/shots/` |  The event queue survives window reloads (persisted to `~/.local/share/adom-vscode/queue.json`, capped at 1000 items, optional per-item TTL).  ### Why the settings verbs matter -`POST /config` uses `vscode.workspace.getConfiguration().update(key, value, ConfigurationTarget.Global)`, which applies **immediately** with no window reload. That fixes two long-standing frontend bugs at once: font-size changes that silently never landed when a host-side settings.json merge hung, and theme changes that needed a full workbench reload (which dropped the user's Claude sessions).+`POST /config` uses `vscode.workspace.getConfiguration().update(key, value, ConfigurationTarget.Global)`, which applies **immediately** with no window reload. That is the fix for two long-standing HD bugs at once: font-size changes that silently never landed when the `wsl.exe` settings.json merge hung, and theme changes that needed a full workbench reload (which dropped the user's Claude sessions). -For fonts, `GET /fonts` reports the **resolved** family the renderer actually shows (checked with `document.fonts.check` in the workbench), not just the configured stack. The configured chain often names a font that is not installed on the rendering side; the frontend needs the true value for its readout.+For fonts, `GET /fonts` reports the **resolved** family the renderer actually shows (checked with `document.fonts.check` in the workbench), not just the configured stack. The configured chain often names a font that is not installed on the rendering side; HD needs the true value for its readout.  ## CLI quick start @@ -118,9 +112,9 @@ adom-vscode preview /path/to/README.md    # Markdown preview # Settings (all apply live, no reload) adom-vscode config get workbench.colorTheme adom-vscode config set editor.fontSize 14-adom-vscode theme get+adom-vscode theme get                     # active + available themes adom-vscode theme set "Adom Dark"-adom-vscode font get+adom-vscode font get                      # all font settings + resolved families adom-vscode font set --editor-size 14 --prose-family Inter adom-vscode font-size get adom-vscode font-size set --editor 14 --terminal 13 --prose 15@@ -132,34 +126,34 @@ adom-vscode exec "uname -a" --json  # Event queue (container process -> HD/HW frontend) adom-vscode queue push login --type refresh-needed --payload '{"expiresInHours":24}'-adom-vscode queue pull --topic login-adom-vscode queue pull --peek+adom-vscode queue pull --topic login      # consume+adom-vscode queue pull --peek             # read without consuming adom-vscode queue status adom-vscode queue clear --topic progress  # Container identity + API key-adom-vscode container+adom-vscode container                     # hd or hw, OS, env, markers adom-vscode apikey status adom-vscode apikey set --stdin < new-key.txt  # Extensions-adom-vscode extensions list+adom-vscode extensions list               # + claude/codex/kimi AI summary adom-vscode extensions status anthropic.claude-code --latest adom-vscode extensions update anthropic.claude-code-adom-vscode extensions update+adom-vscode extensions update             # update all adom-vscode extensions search "python" adom-vscode extensions install ms-python.python  # Layout, modes, misc-adom-vscode claude new-adom-vscode sidebar toggle-adom-vscode panel toggle-adom-vscode terminal new-adom-vscode activity-bar toggle-adom-vscode notify "Build complete"+adom-vscode claude new                    # New Claude Code chat+adom-vscode sidebar toggle                # Toggle sidebar+adom-vscode panel toggle                  # Toggle bottom panel+adom-vscode terminal new                  # New terminal+adom-vscode activity-bar toggle           # Toggle activity bar+adom-vscode notify "Build complete"       # Toast notification adom-vscode reload                        # Reload VS Code window (drops AI sessions!)-adom-vscode command <any-vscode-command>-adom-vscode --help+adom-vscode command <any-vscode-command>  # Generic escape hatch+adom-vscode --help                        # All commands ```  ## Modes@@ -191,11 +185,24 @@ Example: `https://<slug>.adom.cloud/?mode=claudecode&folder=/home/adom/project`  When you press Ctrl+V with an image on the clipboard while focused in a code-server terminal (e.g. running CLI Claude Code), the interceptor uploads the image to the extension at `POST /paste-screenshot`, which saves it to `/tmp/shots/` (deduplicated via SHA-256) and writes the file path back to the terminal so the CLI can ingest it. Without this, code-server returns an empty string for clipboard.readText() when the clipboard holds only an image, so the paste does nothing. +## Activity bar++The extension adds an Adom icon to the VS Code activity bar. Click it to open a sidebar with accordion sections covering the full verb surface:++- **Overview**: what the extension does+- **Modes**: Claude Code, TTY modes with "open in new window" and "copy URL" buttons+- **Commands**: file, layout, and utility commands with hover tooltips+- **AI Prompts**: sample prompts to paste into Claude Code chat+- **Settings & Theme**: live config/theme/font control+- **Exec & Queue**: container exec and the frontend event queue+- **Container & Keys**: hd/hw identity and api-key health+- **Extensions**: list/status/update, incl. the AI assistants+ ## The skill pack  The page ships a parent skill plus six sub-skills so any AI in the Adom-ecosystem can discover and drive every verb. `adom-wiki pkg install` (and-`adom-vscode install`) deploys all of them to `~/.claude/skills/`:+ecosystem can discover and drive every verb. `adom-vscode install` (and+`adom-wiki pkg install`) deploys all of them to `~/.claude/skills/`:  | Skill | Covers | |---|---|@@ -222,19 +229,38 @@ VS Code UI + container shell See [ARCHITECTURE.md](ARCHITECTURE.md) for the full design document. See [COMMANDS.md](COMMANDS.md) for all VS Code commands usable with `adom-vscode command <id>`. +## Development++```bash+# Build everything locally+bash build.sh++# Release (single binary ships everything)+VERSION=$(cat VERSION | tr -d '[:space:]')+gh release create v${VERSION} \+  cli/target/release/adom-vscode \+  --repo adom-inc/adom-vscode \+  --title "v${VERSION}"+```+ ## Version -One version number everywhere: the `VERSION` file, the extension, the CLI `--version`, and the wiki package all carry the same value (1.1.10 as of this release).+The version lives in `VERSION` (single source of truth) and flows to:+- `extension/package.json`+- `cli/Cargo.toml`+- VSIX manifest (via `build.sh`)+- Activity bar sidebar footer+- Health endpoint response+- CLI `--version` flag -v1.1.10 added: live config/theme/font verbs, streamed exec, the frontend event queue, container identity (hd/hw), api-key status/inject, extension query/update (incl. Claude/Codex/Kimi), port fallback + `port.json` discovery, and verb-roster feature detection on `/health`.+v1.1.10 added: live config/theme/font verbs, streamed exec, the frontend event queue, container identity, api-key status/inject, extension query/update, port fallback + `port.json` discovery, and verb-roster feature detection on `/health`. -v1.1.11 added: the skill pack (parent + 6 sub-skills) installed by both the wiki package and `adom-vscode install`.+v1.1.11 added: the skill pack (parent + 6 sub-skills) installed by both `adom-vscode install` and the wiki package. -v1.1.12: exec verbs are HD-local only (disabled on cloud hw containers with errorCode exec_disabled_on_cloud); /health reports execAllowed and omits exec verbs where disabled.+v1.1.12: exec verbs are HD-local only (disabled on cloud hw containers, errorCode exec_disabled_on_cloud); /health reports execAllowed and omits exec verbs where disabled.  v1.1.13: extension-dir GC on every install (prunes stale version dirs VS Code's startup GC never reaps on long-lived windows; keeps current, live-process, and running-server versions), and install now pushes a system/update-pending queue event so the frontend can reload at a safe moment.--v1.1.15: version realignment (1.1.14 shipped a dependency-only bump with a 1.1.13 binary; now tarball, binary, VERSION and page all match) and the issue #642 fix: extensions --latest is platform-scoped via the VS Code-compat gallery, returns the allPlatforms matrix with an explanatory _hint, accepts --platform, and extensions update says 'already current' instead of firing a no-op install.+\nv1.1.15: version realignment and the issue #642 fix (platform-scoped extensions --latest with allPlatforms matrix, --platform flag, honest 'already current' update). \nv1.1.16: extensions install --vsix <path|url> installs a VSIX directly via code-server's CLI with the extension-host env stripped (absorbs the CODE_SERVER_PARENT_PID / not-spawned-with-IPC trap from issue #642).  v1.1.17: named TUI terminals as editor tabs with real handles (POST /terminal/tui, /terminal/tui/dispose, GET /terminal/tui/list; CLI terminal tui / tui-list / tui-dispose), built for the Hydrogen AI Threads panel; /command now passes a non-array args value as a single argument instead of silently dropping it, and reports argsShape.@@ -247,6 +273,4 @@ v1.1.20: /command returns errorCode command_not_found (HTTP 400) with did-you-me  v1.1.21: event-driven tab census + Claude session identity (John 2026-09-03: never poll the iframes again). GET /tabs and the SSE stream GET /tabs/events publish the extension host's own tabGroups census on every change; POST /claude/session-start ingests the Claude SessionStart hook (id + transcript path, before the jsonl is flushed) and GET /claude/sessions lists it; POST /claude/open-session opens an existing conversation by id and confirms the bind (retagging sdk-cli transcripts, which the Claude extension otherwise declines). Capability markers in /health: tabs.list, tabs.events, claude.open-session, claude.session-start, claude.sessions. -v1.1.22: /command maps a JSON null argument to undefined when spreading an args array (JSON has no undefined; the Claude extension's editor.open crashes on a literal null session id, which broke every send-to-AI new tab).--v1.1.23: the paste-screenshot interceptor is retired (the Claude CLI handles image paste itself). It was the only thing this tool wrote into code-server's workbench.html, and that write was the only reason it ever needed sudo, so installs are now entirely user-level and a code-server upgrade can no longer wipe a patch of ours. An already-injected block is stripped on the next install. The /paste-screenshot endpoint goes with it.+v1.1.26: AI thread icons in the window title bar (John 2026-09-06), the layout-controls row at the top right. VS Code has no contribution point there, so `browser/ai-titlebar.js` rides workbench.html (written by `adom-vscode install`, back on every reload) and calls this extension over `/proxy/<port>/ai/*`: one icon per INSTALLED AI in the vendor's own colour (Claude Code, Codex, and Kimi or Antigravity when their extension is present), a sparkle menu listing every installed AI plus its TUI (the CLI in a terminal tab), and a VS Code-style checklist of which icons to show (saved as `adom-vscode.aiIcons`; TUIs off by default). A click opens the thread in THIS window's active group (each Hydrogen VS Code tab is its own window and extension host; the script matches its visible tabs against every candidate port's census, so the thread never lands in another window) and moves it back if the AI extension split the editor. GET /ai/providers, POST /ai/new {type, tui?, group?}, POST /ai/icons {icons}. Also: `extensions install --vsix` and `adom-vscode install` used the remote-cli wrapper, which only works inside a VS Code terminal and reported success while installing nothing; both now use the code-server binary and require its own "successfully installed" line.
SKILL.md+4−5
@@ -1,6 +1,6 @@ --- name: adom-vscode-description: "Control VS Code Server (code-server) from inside the Docker container. THIS is the wrapper for the VS Code FILE EXPLORER sidebar, editor tabs, markdown preview, etc., when the user says 'reveal in file explorer' or 'open in vscode' they mean this CLI, NOT the bridge CLI (`adom-bridge-cli`, which controls Chrome browser windows). START-HERE skill of the adom-vscode pack: file ops, workspace scoping, port discovery, and the map to the sub-skills covering live settings (adom-vscode-settings), container exec (adom-vscode-exec), the frontend event queue (adom-vscode-queue), container identity + api key (adom-vscode-container), extension management (adom-vscode-extensions), and modes/layout (adom-vscode-modes). Trigger words: adom-vscode, open in vscode, reveal in explorer, file explorer, sidebar reveal, preview markdown, vscode command, vscode api, port 8821, code-server control, drive vscode, vscode verbs."+description: "Control VS Code Server (code-server) from inside the Docker container. THIS is the wrapper for the VS Code FILE EXPLORER sidebar, editor tabs, markdown preview, etc., when the user says 'reveal in file explorer' or 'open in vscode' they mean this CLI, NOT adom-desktop (which controls Chrome browser windows). START-HERE skill of the adom-vscode pack: file ops, workspace scoping, port discovery, and the map to the sub-skills covering live settings (adom-vscode-settings), container exec (adom-vscode-exec), the frontend event queue (adom-vscode-queue), container identity + api key (adom-vscode-container), extension management (adom-vscode-extensions), and modes/layout (adom-vscode-modes). Trigger words: adom-vscode, open in vscode, reveal in explorer, file explorer, sidebar reveal, preview markdown, vscode command, vscode api, port 8821, code-server control, drive vscode, vscode verbs." ---  # adom-vscode, VS Code Control (start here)@@ -12,7 +12,7 @@ description: "Control VS Code Server (code-server) from inside the Docker contai > Docker container's running VS Code instance). That's THIS > CLI: `adom-vscode reveal <path>`. >-> **Do NOT** reach for the bridge CLI (`adom-bridge-cli`) for that — it+> **Do NOT** reach for `adom-desktop` for that, `adom-desktop` > controls puppeteer / Chrome browser windows, not VS Code. > > **Do NOT** use the desktop `code` CLI either, it is not on@@ -22,14 +22,14 @@ description: "Control VS Code Server (code-server) from inside the Docker contai > > If the user mentions "vscode", "explorer", or wants to see a > file in the editor, default to `adom-vscode`. Save-> the bridge CLI for cases where the trigger is clearly Chrome /+> `adom-desktop` for cases where the trigger is clearly Chrome / > browser / pup / shotlog tab.  ## The mental model  A VS Code extension inside code-server runs an HTTP server on **127.0.0.1:8821**; the `adom-vscode` CLI wraps those verbs with AI-oriented colored output. Everything-is plain HTTP too, so scripts and the Hydrogen/hc frontend hit the API directly.+is plain HTTP too, so scripts and the HD/HW frontend hit the API directly. `GET /health` returns the full verb roster (`verbs: [...]`) for feature detection.  If 8821 is taken the extension falls back to 8822..8831 (then an ephemeral port)@@ -50,7 +50,6 @@ Binary: `~/.local/bin/adom-vscode` (also `/usr/local/bin/adom-vscode`). | **adom-vscode-container** | Container identity (hd vs hw), api-key status/inject, port discovery details, /health feature detection | | **adom-vscode-extensions** | List/query/update extensions, incl. the Claude/Codex/Kimi AI assistants | | **adom-vscode-modes** | Full-screen modes (claudecode/claudetty/tty), layout verbs, URL auto-triggers, paste-screenshot |-| **tab census + Claude sessions** (1.1.21, in this skill) | `GET /tabs` (event-driven census of every editor tab, no DOM), `GET /tabs/events` (SSE push on every change), `POST /claude/open-session {sessionId}` (open an existing Claude conversation by id, confirms the bind), `POST /claude/session-start` (SessionStart hook ingest), `GET /claude/sessions`. Hydrogen uses these instead of polling the iframes; see README for fields |  ## CRITICAL: workspace scope is `/home/adom/project` 
VERSION+1−1
@@ -1 +1 @@-1.1.23+1.1.26
bin/adom-vscode
⋯ 1 unchanged line ⋯
package.json+2−2
@@ -1,6 +1,6 @@ {   "slug": "adom-vscode",-  "version": "1.1.25",+  "version": "1.1.26",   "type": "app",   "description": "CLI + VS Code extension that lets AI assistants and the Hydrogen Desktop frontend drive VS Code from inside an Adom container: open files, live get/set of any setting/theme/font (no reload), native streamed exec, a frontend event queue, container identity (hd/hw), api-key status/inject, extension query/update, modes, paste screenshots, and any VS Code command via a local HTTP API on port 8821 (with port-file fallback discovery).",   "license": "PROPRIETARY",@@ -46,4 +46,4 @@     "adom-vscode-extensions",     "adom-vscode-modes"   ]-}+}\ No newline at end of file
skills/adom-vscode-extensions/SKILL.md+32
@@ -52,6 +52,38 @@ adom-vscode extensions install ms-python.python   # install by marketplace id  HTTP: `POST /extensions/search {query}`, `POST /extensions/install {id}`. +## AI thread icons in the window title bar (1.1.26)++The top-right row of the window (next to VS Code's layout controls) carries one icon per+INSTALLED AI, in the vendor's own colour: Claude Code (orange), Codex, and Kimi or Antigravity+when their extension is present. A "+" badge means a new thread in a tab; a ">_" badge means+the AI's CLI in a terminal tab (TUI). The sparkle icon opens a VS Code-style menu: every+installed AI, its TUI, and a checklist (check marks, like the activity bar's own menu) of which+icons to show, saved as the user setting `adom-vscode.aiIcons` (default: every installed AI,+no TUIs). VS Code has no extension contribution point for that row, so the icons are drawn by+`browser/ai-titlebar.js`, which `adom-vscode install` writes into code-server's workbench.html+(present on every reload; a code-server upgrade removes it and the next install puts it back).++Every Hydrogen VS Code tab or panel is its own window with its own extension host (ports+8821, 8822, ...). The script finds ITS window by matching the tabs it can see against each+candidate's `/tabs` census, so a click opens the thread in that window's active group, and it+moves the tab back if the AI extension split the editor.++For callers:++```bash+adom-vscode ai providers                       # installed? command? icon shown?+adom-vscode ai new '{"type":"codex"}'           # a Codex thread in the active group+adom-vscode ai new '{"type":"claude","group":2}' # in editor group 2 (1-based)+adom-vscode ai new '{"type":"claude","tui":true}' # the Claude CLI in a terminal tab+adom-vscode ai icons '{"icons":["claude","codex"]}' # the checklist+```++`POST /ai/new` answers `{ok, type, command, tab_seen, label, group, placed, ms}`; `placed` is+`stayed` or `moved a -> b`. An AI that is not installed answers `ok:false` with the provider+list, so never guess: read `installed`. Hydrogen's `/ai-threads/new` remains the route for+anything that also wants tags, names, the AI picker, or a run-prompt job.+ ## Gotchas  - An extension can be installed but `active: false` (activates lazily). For the