Skip to content

Commit fd4069e

Browse files
committed
Merge remote-tracking branch 'origin/main' into dev/yuazha/codex-session
# Conflicts: # tools/wta/src/agent_hooks_installer.rs # tools/wta/src/agent_sessions.rs # tools/wta/src/app.rs
2 parents de8c93e + 1851384 commit fd4069e

248 files changed

Lines changed: 9661 additions & 4938 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/actions/spelling/allow/allow.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ parallelizable
152152
passthrough
153153
peekable
154154
perlw
155+
pkgver
155156
postmodern
156157
Powerline
157158
Prereq

.github/actions/spelling/expect/expect.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -962,6 +962,7 @@ maxval
962962
maxversiontested
963963
MAXWORD
964964
maybenull
965+
mbr
965966
MBUTTON
966967
MBUTTONDBLCLK
967968
MBUTTONDOWN

CLAUDE.md

Lines changed: 173 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ WindowEmperor (one WT process, N AppHosts/windows)
5555
+-- AppHost[] → TerminalWindow → TerminalPage
5656
|-- CommandPalette (? / & prefixes)
5757
|-- Per-tab agent pane: ConptyConnection ───► wta-helper (conpty child)
58-
| (one helper per agent pane)
58+
| (one helper per tab, pre-warmed)
5959
+-- Protocol bridge (TerminalPage.Protocol.cpp)
6060
6161
External: Agent → wtcli → COM (IProtocolServer) → TerminalProtocolComServer → WindowEmperor
@@ -71,6 +71,19 @@ helper events (`agent_state_changed`, `agent_status`, `autofix_state`,
7171
`_FindTabByStableId` instead of fanning out across every pane / window.
7272
See `doc/specs/Multi-window-agent-pane.md` §7.
7373

74+
**Helper is pre-warmed per tab.** Every new tab spawns a stashed agent
75+
pane on creation (`_InitializeTab``_AutoCreateHiddenAgentPaneShared`
76+
with `autoStash=true`, `--start-stashed`), so the helper is running and
77+
its ACP session connects in the background from the start — even if the
78+
user never opens the pane. This is what lets autofix work on a tab the
79+
user hasn't interacted with. The agent CLI itself is spawned once by
80+
`wta-master` at startup and shared across all helpers (each helper's
81+
`initialize` is a cached replay; only `session/new` round-trips to the
82+
CLI). `--start-stashed` only seeds `pane_open=false`; it does not defer
83+
the handshake. The pre-warm is skipped when wta is unavailable, GPO
84+
blocks all agents, or the tab arrived with an agent pane via cross-window
85+
drag-in (`agentLeavesSeen > 0`). See `TabManagement.cpp:366`.
86+
7487
**Agent pane toggle = stash, not destroy.** `Ctrl+Shift+.` /
7588
`Ctrl+Shift+/` / the bottom-bar button toggle via
7689
`Tab::StashAgentPane`/`RestoreStashedAgentPane` (built on WT's
@@ -101,49 +114,179 @@ Detects command failures in other panes and auto-suggests fixes via the agent.
101114

102115
**Pipeline**: Shell emits `OSC 133;D;<exit_code>``TerminalPage` raises `ProtocolVtSequenceReceived` → COM server forwards to clients → WTA (via `wtcli listen --json`) classifies → `maybe_trigger_autofix()`.
103116

104-
**Requirements**: PowerShell shell integration (OSC 133 marks), agent pane open, `wtcli` on PATH.
117+
**Requirements**: PowerShell shell integration (OSC 133 marks), a helper
118+
whose ACP session has reached `Connected`, `wtcli` on PATH. The pane does
119+
**not** need to be visible — the per-tab pre-warmed helper (see
120+
Architecture) makes autofix work on a stashed pane. But a failure that
121+
lands before the helper's session connects (cold start of master/agent
122+
CLI, in-flight `session/new`, or a `Failed` agent) is **dropped**:
123+
`trigger_autofix_inner` early-returns when `state != Connected`
124+
(`app.rs:6820`). The bottom-bar notification banner still shows; only the
125+
autofix pill / LLM call is skipped, and the failure is not re-triggered
126+
once the session later connects.
105127

106128
**Key code**: `tools/wta/src/app.rs` (`classify_wt_event`, `maybe_trigger_autofix`), `TerminalPage.cpp:2650-2740` (event handlers), `TerminalProtocolComServer.cpp` (`_ensurePageEventsRegistered`).
107129

108130
**Diag log**: `wta-ensure-host.log` in the WTA log directory — shows event flow, classification, and autofix triggers.
109131

110-
## Logs
111-
112-
WTA writes structured logs to:
132+
## Hooks plugin auto-upgrade
133+
134+
When IT is installed or upgraded, the bundled `wt-agent-hooks` plugin
135+
(`tools/wta/wt-agent-hooks/{copilot,claude,gemini-extension}/`) needs to
136+
re-land into any agent CLI the user already opted into (via Settings UI /
137+
FRE "Install hooks" or `wta hooks install`). This is handled silently by
138+
`agent_hooks_installer::upgrade_installed_hooks`, fired once per
139+
`wta-master` startup on a blocking-pool thread.
140+
141+
**Trigger model — bundle version is the upgrade signal.** A tiny state
142+
file `<LocalCache>/IntelligentTerminal/hooks-upgrade-state.json` records
143+
the bundle version this wta process last saw per CLI. At startup we read
144+
each CLI's bundle `plugin.json` / `gemini-extension.json` (cheap, <5ms)
145+
and compare; if all match, we return immediately (no spawns, no IO
146+
beyond the cache compare). Only after the user installs / upgrades IT
147+
does the bundle version change → cache miss → per-CLI flow runs once,
148+
then the state file is rewritten and the fast path resumes.
149+
150+
**Opt-in only.** Even on cache miss, CLIs that don't already have
151+
`wt-agent-hooks` installed are skipped. The auto-upgrade never installs
152+
into a CLI the user hasn't accepted. Disabled plugins are also skipped
153+
(`enabled: false` in Copilot's `config.json` / `claude plugin list`).
154+
155+
**Per-CLI strategy.** Copilot and Claude use their `plugin update`
156+
subcommands; before invoking them we rewrite any stale marketplace
157+
`source.path` to the current bundle dir (Copilot: existing
158+
`cleanup_stale_copilot_marketplace`; Claude: new
159+
`cleanup_stale_claude_marketplace`). Gemini's `extensions update`
160+
silently returns `NOT_UPDATABLE` when the recorded install source no
161+
longer exists (typical after an MSIX version-dir bump), so we peek at
162+
`~/.gemini/extensions/wt-agent-hooks/.gemini-extension-install.json`
163+
first: if `type==local` AND `source` is still under the current bundle,
164+
run `extensions update` in place; otherwise fall back to
165+
uninstall+install while preserving the `isActive` flag.
166+
167+
**Trigger-point caveat.** The agent CLI master spawns concurrently may
168+
already be past its plugin-load step by the time `plugin update` writes
169+
the new files — so the freshly upgraded hooks may not take effect until
170+
the next agent restart. Acceptable because blocking master startup on a
171+
Node-based `plugin update` (1-30s) would hurt every IT-upgrade boot.
172+
173+
**Diag**: `wta-install-hooks.log` (existing) plus `target=agent_hooks`
174+
+ `target={copilot,gemini}_hooks` trace events in
175+
`wta-main_master.log` show every per-CLI decision (`upgrade decision`
176+
log line carries `installed_version`, `bundle_version`, `action`).
177+
178+
## Logs & runtime data layout
179+
180+
WTA runtime data lives under the **package-private** store, split by lifetime
181+
into two roots (both resolved in `runtime_paths.rs`, both falling back to the
182+
same bare path when the process has no package identity):
113183

114184
```
115-
C:\Users\<user>\AppData\Local\IntelligentTerminal\logs\
185+
# Packaged (every production wta process — helper is a conpty child of the
186+
# packaged WindowsTerminal.exe, master is spawned in-package by SharedWta):
187+
188+
…\Packages\<PackageFamilyName>\LocalState\IntelligentTerminal\ <- STATE root
189+
prompts\ (prompt overrides) intelligent_terminal_root()
190+
agent-pane-sessions.jsonl (session origin index)
191+
master-pipe.txt (helper↔master rendezvous)
192+
193+
…\Packages\<PackageFamilyName>\LocalCache\Local\IntelligentTerminal\ <- LOCAL/cache root
194+
logs\<pkgver>\ (ALL logs for that build — Rust wta-*.log,
195+
C++ terminal-agent-pane.log, PS hook-trace.log)
196+
hook-bundle-staging\ … (hook-installer staging)
197+
hooks-upgrade-state.json (per-CLI bundle version cache for the
198+
hooks auto-upgrade fast-path)
199+
200+
# Unpackaged (dev builds run straight out of the Cargo target dir, tests):
201+
# BOTH roots collapse to the legacy bare %LOCALAPPDATA%\IntelligentTerminal\.
116202
```
117203

118-
The path is built off the `LOCALAPPDATA` env var, which is **not** redirected
119-
into the package sandbox on Win10/11 (the env-var virtualization that
120-
hides the regular LOCALAPPDATA was a UWP-era behavior; current Windows
121-
keeps the env var pointing at the real `\AppData\Local\`). Packaged and
122-
unpackaged wta processes therefore share the same log directory.
123-
124-
The sandbox path
125-
`%LOCALAPPDATA%\Packages\IntelligentTerminal_<id>\LocalCache\Local\IntelligentTerminal\logs`
126-
exists as a transparent virtualization of the same directory (NTFS reparse
127-
points) — both paths return the same files.
128-
129-
Log level is controlled by `WTA_LOG` env var (default: `info`; set `debug`
130-
for the noisy traces).
204+
Rationale for the split: **State** = persistent, must-survive, package-private
205+
data → `LocalState` (alongside the WT app's own `settings.json` / `state.json`).
206+
**Local/cache** = transient, regenerable diagnostics → `LocalCache\Local`, the
207+
cache store that doesn't roam / back up.
208+
209+
Both roots are package-private — removed on uninstall and isolated between the
210+
dev-sideload family (`IntelligentTerminal_rd9vj3e6a2mbr`) and the store family
211+
(`Microsoft.IntelligentTerminal_8wekyb3d8bbwe`) — instead of sharing one bare
212+
`%LOCALAPPDATA%\IntelligentTerminal` directory. The family name comes from
213+
`GetCurrentPackageFamilyName` (windows-sys); the `Packages\<pfn>\LocalState` and
214+
`…\LocalCache\Local` paths are what WinRT `ApplicationData.Current.LocalFolder`
215+
/ `LocalCacheFolder` resolve to, so we construct them directly rather than
216+
pulling in the WinRT projection.
217+
218+
**All three writers share one per-version dir** `logs\<pkgver>\`, where
219+
`<pkgver>` is the **package version** (`GetCurrentPackageId`, e.g. `0.8.0.2`) —
220+
read identically at runtime by Rust (`logging::package_version`) and C++
221+
(`IntelligentTerminal::PackageVersionDir`), so no build-time version sync is
222+
needed:
223+
- Rust wta processes → `logging::log_dir()` (`logs\<pkgver>\wta-*.log`).
224+
- C++ `AgentPaneLog.h``IntelligentTerminal::LogDirVersioned()`
225+
`terminal-agent-pane.log` (renamed from the old `wta-agent-pane.log`).
226+
- PowerShell hooks (`send-event.ps1`) → `hook-trace.log`, via the
227+
`WTA_HOOK_LOG_DIR` env var set to `LogDirVersioned()` (C++ ConptyConnection
228+
for shell panes; `spawn.rs` for agent-pane CLIs).
229+
230+
`IntelligentTerminal::LogDir()` stays the **root** (`…\logs`, no version) and is
231+
used only by the bug-report-zip action so it archives every version at once.
232+
Unpackaged (dev-from-cargo / tests) has no package identity → all writers fall
233+
back to the flat bare `…\logs\`.
234+
235+
> Earlier builds wrote everything to the bare `%LOCALAPPDATA%\IntelligentTerminal`
236+
> regardless of identity (the `LOCALAPPDATA` env var is **not** redirected into
237+
> the sandbox on Win10/11). There is no migration — old data is left in place
238+
> and simply ignored.
239+
240+
**Log level** is controlled by the `WTA_LOG` (or `RUST_LOG`) env var. When
241+
unset, the default comes from the build: **debug builds default to `debug`,
242+
release builds default to `info`** (`logging::default_filter_directive`). Set
243+
`WTA_LOG=debug|trace` for the noisy traces, or `WTA_LOG=warn` to quiet a
244+
release build further.
245+
246+
**Logging is initialized once** in `main()` immediately after arg parsing
247+
(`logging::init(&process_label(&cli))`), before locale/ETW setup, so even
248+
early-startup failures land on disk. The non-blocking appender's `WorkerGuard`
249+
lives in a global and is flushed via `logging::shutdown_flush()` on every exit
250+
path — including before each `std::process::exit` (which would otherwise skip
251+
the guard drop and lose buffered records). Every launch mode — including
252+
short-lived `wtcli`-style commands — now writes a log file (previously only 6
253+
entry points did).
254+
255+
**Per-version storage + retention** (`logging::housekeeping`): each build's
256+
logs live in their own subdir, `logs\<pkgver>\` (the package version — see
257+
above). On every start, `prune_old_version_dirs` keeps **only the current
258+
version's dir** and deletes all other version dirs wholesale. The current
259+
version's dir is never a deletion target, so cleanup is **lock-free and
260+
concurrency-safe** (no process can delete a file another is writing). Within the
261+
current version's dir, per-PID helper logs older than **3 days** are pruned and
262+
`wta-cli.log` rotates daily keeping 3 days (`max_log_files`).
131263

132264
### Log files in the helper+master architecture
133265

134266
```
135-
wta-main_master.log — wta-master process: agent CLI spawn, named pipe accept loop,
136-
per-helper routing, session_to_helper map updates,
137-
agent CLI exit detection
138-
wta-main_helper.log — each wta-helper process: pipe connect, ACP initialize,
139-
session/new, prompts sent, agent responses received,
140-
TUI lifecycle
141-
wta-ensure-host.log — WT-side background ensure-running diagnostics (kept from
142-
M3-M6 era; remains useful for SharedWta lifecycle)
143-
wta-acp-debug.log — low-level ACP JSON-RPC wire trace
144-
wta-delegate.log — `?<prompt>` delegation flow (separate from agent pane)
267+
wta-main_master.log — wta-master process: agent CLI spawn, named pipe accept
268+
loop, per-helper routing, session_to_helper map updates,
269+
agent CLI exit detection, connection failures
270+
wta-main_helper-{pid}.log — each wta-helper process (one file per PID, so concurrent
271+
per-tab helpers don't interleave): pipe connect, ACP
272+
initialize, session/new, prompts, agent responses,
273+
TUI lifecycle, connection failures
274+
wta-cli.log — short-lived wtcli-style commands (list-*, capture-pane,
275+
listen, sessions, …); daily-rotated, 3-day retention
276+
wta-delegate.log — `?<prompt>` delegation flow (separate from agent pane)
277+
wta-probe.log — `probe-models` ACP model-list probe
278+
wta-install-hooks.log — `hooks install` agent-hook bridge installation
279+
wta-ensure-host.log — WT-side background ensure-running diagnostics (kept from
280+
M3-M6 era; remains useful for SharedWta lifecycle)
281+
wta-acp-debug.log — low-level ACP JSON-RPC wire trace
145282
```
146283

284+
Two files in the per-version dir are **not** written by the Rust wta binary —
285+
`hook-trace.log` (PowerShell hooks) and `terminal-agent-pane.log` (C++ side);
286+
see **All three writers share one per-version dir** above. They live in the
287+
same `logs\<pkgver>\` and so are cleaned together with the Rust logs when that
288+
version's dir ages out.
289+
147290
### Tracking flows by `target` field
148291

149292
All tracing uses structured `target` + key=value fields. Grep patterns for common
@@ -157,6 +300,7 @@ scenarios:
157300
| Trace one prompt end-to-end | grep `session_id="X"`, look for `step="helper→agent" op="prompt"` (sent) then `step="master→helper" op="session_notification"` (response chunks) |
158301
| Helper pipe lifecycle | `target=master helper_id=…` shows connect+exit |
159302
| Agent CLI failures | `target=agent_stderr` |
303+
| Connection failures (either side) | `"exiting with error"``target=master` in `wta-main_master.log`, `target=helper` in `wta-main_helper-{pid}.log`; plus inline `step="acp_initialize"` / `step="pipe_connect"` for the helper handshake |
160304
| Internal control routing | `target=internal_control` (legacy; mostly empty post-Z) |
161305

162306
### Example: end-to-end trace of one user prompt

README.md

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,11 @@
3939

4040
Intelligent Terminal is an experimental fork of [Windows Terminal](https://github.com/microsoft/terminal) with native agent integration.
4141

42-
[GitHub Copilot](https://github.com/features/copilot/cli/) is the default agent CLI, but it works with any [Agent Client Protocol (ACP)-compatible](https://agentclientprotocol.com/get-started/agents) agent CLI. All you need is to install your preferred agent CLI on your PC, and Intelligent Terminal should detect it.
42+
Intelligent Terminal works with any [Agent Client Protocol (ACP)-compatible](https://agentclientprotocol.com/get-started/agents) agent CLI. All you need is to install your preferred agent CLI on your PC. If you don't have a preferred agent, we'll get you setup with [GitHub Copilot CLI](https://github.com/features/copilot/cli/).
4343

44-
Everything else about Intelligent Terminal is the same as Windows Terminal: tabs, profiles, themes, settings, shells, and keyboard shortcuts all work the way you expect.
44+
Intelligent Terminal takes all the features you love in Windows Terminal such as: tabs, profiles, themes, settings, shells, and keyboard shortcuts, which all work the way you expect.
45+
46+
Read the [announcement blog post](https://devblogs.microsoft.com/commandline/announcing-intelligent-terminal-version-0-1/) for more details.
4547

4648
---
4749

@@ -79,13 +81,20 @@ winget install --id Microsoft.IntelligentTerminal -e
7981

8082
1. On first launch, choose your agent. Intelligent Terminal auto-detects several [ACP-compatible](https://agentclientprotocol.com/get-started/agents) agent CLIs on your machine (Copilot/Claude/Codex/Gemini). If none are found, it defaults to GitHub Copilot CLI and installs it for you via WinGet.
8183
3. If you aren't already authenticated, the agent pane walks you through sign-in.
82-
4. Start asking questions. The agent has context on your shell output, no copy-pasting needed.
84+
4. Start asking questions and using the agent pane for assistance. The agent has context on your shell output, no copy-pasting needed.
85+
86+
> [!TIP]
87+
> If you see "running scripts is disabled on this system" or an `UnauthorizedAccess` error in PowerShell, your execution policy is blocking your profile and Intelligent Terminal can't initialize shell integration. Run:
88+
> ```powershell
89+
> Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned
90+
> ```
91+
> If you run into any other issues or dependency errors, see [installing-dependencies.md](./doc/installing-dependencies.md).
8392
8493
---
8594
8695
## Keyboard Shortcuts
8796
88-
All shortcuts are customizable through terminal settings.
97+
All shortcuts are customizable through Intelligent Terminal settings.
8998
9099
| Shortcut | Action |
91100
|----------|--------|
@@ -99,7 +108,7 @@ All shortcuts are customizable through terminal settings.
99108
100109
## Configuration
101110
102-
Everything is configurable through terminal settings, under "Agent" settings.
111+
Everything is configurable through Intelligent Terminal settings, under "Agent" settings.
103112
104113
| Setting | Options |
105114
|---------|---------|
@@ -119,7 +128,7 @@ Everything is configurable through terminal settings, under "Agent" settings.
119128
<img src="./images/intelligent-terminal-status-bar.png" alt="Screenshot of the agent status bar at the bottom of the terminal window">
120129
</p>
121130
122-
The agent status bar sits at the bottom of the window and gives you quick access to everything agent-related. On the left: the agent pane toggle and the error detection icon, which lights up when a fixable error is detected. On the right: the agent management icon that opens your session management panel. It's a persistent, minimal control surface so you're never more than one click away from your agents.
131+
The agent status bar sits at the bottom of the window and gives you quick access to everything agent-related. On the left: the agent pane toggle (hotkey: <kbd>Ctrl+Shift+.</kbd>) and the error detection icon (hotkey: <kbd>Ctrl+Alt+.</kbd>), which lights up when a fixable error is detected. On the right: the agent management icon (hotkey: <kbd>Ctrl+Shift+/</kbd>) that opens your session management panel. It's a persistent, minimal control surface so you're never more than one click away from your agents.
123132
124133
### Agent Pane
125134
@@ -129,6 +138,12 @@ The agent status bar sits at the bottom of the window and gives you quick access
129138
130139
A context-aware, docked pane with your agent CLI of choice. The pane has context on your shell output across all your shells. Toggle with <kbd>Ctrl+Shift+.</kbd>, switch focus with <kbd>Ctrl+Shift+I</kbd>. If the agent needs to do multiple or complex tasks, it spins up background tasks in new tabs so your active shell stays focused.
131140
141+
<p align="center">
142+
<img src="./images/intelligent-terminal-agent-focus.png" alt="Screenshot of the agent pane with focus, showing multiple panes">
143+
</p>
144+
145+
When you have multiple panes active, a small "Agent" indicator will appear on the pane that your agent has "focus" on.
146+
132147
### Agent Management
133148
134149
<p align="center">

0 commit comments

Comments
 (0)