experiments in a post-browser web
10
fork

Configure Feed

Select the types of activity you want to include in your feed.

docs: finalize AGENT_REPORT.md for v1-removal phase 1c

+220 -13
+220 -13
AGENT_REPORT.md
··· 1 - # Agent Report: v1 Removal Phase 1c (cmd + page) 1 + # Agent Report: v1 Removal Phase 1c (cmd + page conversion) 2 2 3 - ## Scope 3 + ## Summary 4 4 5 - Convert `cmd` and `page` core renderers from v1 iframe-in-extension-host 5 + Converted `cmd` and `page` core renderers from v1 iframe-in-extension-host 6 6 loading to v2 standalone BrowserWindows using `tile-preload.cjs` with a 7 7 `trustedBuiltin` capability grant. Same pattern HUD was converted to in 8 8 Phase 1b. 9 9 10 - ## Plan 10 + Both renderers now participate in the same tile mechanics as feature 11 + tiles. Capability enforcement is bypassed at every `tile:*` IPC because 12 + the tokens carry `trustedBuiltin: true` (added to `tile-manifest.ts` in 13 + Phase 1a; enforcement bypass points already audited in Phase 1b). 14 + 15 + No new enforcement-bypass sites were needed — the existing Phase 1b 16 + bypass points in the `check*Allowed` pure helpers + tile-ipc inline 17 + checks covered everything cmd and page exercise. 18 + 19 + ## Commits (all jj; no git, no push) 20 + 21 + 1. `0219c831` — `chore: triage + plan stub for v1-removal phase 1c` 22 + 2. `420cff39` — `feat(cmd): merge background.{html,js} into index.html (single-file core renderer)` 23 + 3. `3b6183e3` — `refactor(cmd): use api.pubsub.* instead of v1 api.publish/subscribe` 24 + 4. `a0a4d3a4` — `feat(cmd-glue): launch cmd with tile-preload + trustedBuiltin grant, drop loadExtInHost` 25 + 5. `bff756b3` — `feat(page): single-file resident renderer for open/modal commands` 26 + 6. `b0fcef88` — `feat(page-glue): launch page-bg with tile-preload + trustedBuiltin grant, drop loadExtInHost` 27 + 28 + Note: the plan listed a separate "refactor(page): use api.pubsub.*" commit 29 + between steps 5 and 6. Because page's `background.js` was short (~180 30 + LOC, all command registration), the inlining into `background.html` 31 + (step 5) was written directly in the v2 api shape — there was no 32 + standalone `s/api.publish/api.pubsub.publish/g` diff worth isolating. 33 + Six commits total instead of seven; semantics unchanged from the plan. 34 + 35 + ## What landed (per renderer) 36 + 37 + ### cmd 38 + 39 + - `app/cmd/index.html` added — resident renderer, single-file, imports 40 + `background.js` as an ES module. Contains the `await api.initialize()` 41 + (tile-preload token handshake), then `extension.init()`, then the 42 + `ext:ready` publish via `api.pubsub.publish(..., api.scopes.SYSTEM)`, 43 + then the shutdown subscriptions. 44 + - `app/cmd/background.html` deleted. 45 + - `app/cmd/background.js` converted: every `api.subscribe` → `api.pubsub.subscribe`, 46 + every `api.publish` → `api.pubsub.publish`. Header comment updated to 47 + describe the resident-renderer host. 48 + - `api.app.getInfo()` replaced with a best-effort `window.__APP_VERSION__` 49 + lookup (tile-preload does not expose `api.app`; see "Open items"). 50 + This is only used for cache-staleness checks — a mismatch just forces 51 + re-registration, not a correctness bug. 52 + - `api.extensions.list()` replaced with `api.features.list()` (the v2 53 + surface on tile-preload). Response shape is `{ entries }` instead of 54 + `{ success, data }`; handled defensively. 55 + - `backend/electron/cmd-glue.ts` rewritten: 56 + - Drops `loadExtInHost` + `waitForExtLoaded`. 57 + - Creates hidden `BrowserWindow` with `tile-preload.cjs` + `createTrustedBuiltinGrant('cmd')` token. 58 + - Calls `registerTrustedBuiltinWindow(CMD_ID, CMD_ENTRY_ID, win, token)` so `extensionBroadcaster` forwards pubsub. 59 + - Blocks on cmd's `ext:ready` publish (subscribes via a unique source 60 + address so it doesn't collide with main.ts's system subscriber) — 61 + critical because features that publish `cmd:register-batch` before 62 + cmd's subscribers are in place would have their registrations 63 + dropped silently. 5s safety timeout matches the old 64 + `waitForExtLoaded` budget. 65 + - Keeps the 100ms post-ready buffer (lifted from the old glue) for 66 + pubsub-bookkeeping settling. 67 + - `backend/electron/main.ts`: 68 + - `await initCmd({ tilePreloadPath })` (new shape). 69 + - `loadedConsolidatedExtensions.add('cmd')` for Features-pane visibility. 70 + 71 + ### page 72 + 73 + - `app/page/background.html` converted to single-file resident renderer. 74 + Inlined `background.js` (URL validation, `open`/`modal` command 75 + definitions, registration loop). Uses v2 `api.pubsub.*` from day one. 76 + Same shape as `features/mcp-server/background.html` (commit 4e612222). 77 + - `app/page/background.js` deleted. 78 + - `backend/electron/page-glue.ts` rewritten — same shape as hud-glue / 79 + cmd-glue: hidden BrowserWindow + trustedBuiltin token + registerTrustedBuiltinWindow. 80 + No wait for `ext:ready` (page isn't blocking any downstream registration). 81 + - `backend/electron/main.ts`: 82 + - `await initPage({ tilePreloadPath })` (new shape). 83 + - `loadedConsolidatedExtensions.add('page')`. 84 + 85 + ### Unchanged 86 + 87 + - The cmd panel UI (`app/cmd/panel.html` + `panel.js` + state machine, 88 + noun registry, chain editor, 82KB of logic) is opened on-demand as a 89 + separate BrowserWindow via `api.window.open('peek://ext/cmd/panel.html', ...)`. 90 + NOT touched — it wasn't in the iframe-in-host path to begin with. 91 + - The page canvas (`app/page/index.html` + `page.js`, per-URL canvas, 92 + FROZEN architecture per DEVELOPMENT.md) is created on-demand per page. 93 + NOT touched. 94 + 95 + ## Test status 96 + 97 + ### Unit tests — all pass 98 + 99 + `yarn test:unit`: 100 + - 1655 backend Electron tests pass, 0 fail. 101 + - 565 Node unit tests pass, 0 fail. 102 + - Total: 2220, 100% green. Matches baseline from prior phases. 103 + 104 + ### Targeted Playwright 105 + 106 + Run against the agent worktree: 107 + 108 + | Test | Status | 109 + | --- | --- | 110 + | `cmd panel opens URL with http protocol` | pass | 111 + | `cmd panel opens URL with https protocol` | pass | 112 + | `cmd panel opens localhost URLs` | pass | 113 + | `cmd panel detects and opens domain without protocol (youtube.com)` | pass | 114 + | `cmd panel ignores non-URL non-command text on Enter` | pass | 115 + | `cmd panel loads with chain state initialized` | pass | 116 + | `cmd panel input works correctly` | pass | 117 + | `external URL handler opens URL on first click` | pass | 118 + | `handleExternalUrl from main process opens URL correctly` | pass | 119 + | `google command via cmd panel UI does not hang` | pass | 120 + | `direct pubsub kagi execution works (control test)` | **pass** (regressed-but-now-fixed — was failing in prior AGENT_REPORT snapshot) | 121 + | `kagi command via cmd panel UI does not hang` | fail (same preexisting Phase 2 blocker documented in docs/tasks.md) | 122 + | `hud command is registered` | fail (preexisting HUD test fixture issue inherited from Phase 1b — `waitForWindow('ext/hud/hud.html')` expects the hud overlay to auto-open; test mechanics haven't caught up) | 123 + 124 + No new regressions introduced by this phase. The kagi/hud failures 125 + predate my commits (HUD fixture failure is inherited from Phase 1b; 126 + kagi failure is documented on tasks.md). 127 + 128 + ## Architectural decisions 11 129 12 - 1. chore: plan stub (this file) 13 - 2. feat(cmd): merge background.{html,js} into index.html (single-file core renderer) 14 - 3. refactor(cmd): use api.pubsub.* instead of v1 api.publish/subscribe 15 - 4. feat(cmd-glue): launch cmd with tile-preload + trustedBuiltin grant, drop loadExtInHost 16 - 5. feat(page): single-file resident renderer for open/modal commands 17 - 6. refactor(page): use api.pubsub.* instead of v1 api.publish/subscribe 18 - 7. feat(page-glue): launch page-bg with tile-preload + trustedBuiltin grant, drop loadExtInHost 130 + ### cmd's lazy-stub + command-cache flow under the new transport 19 131 20 - ## Status (pending — will be updated as work lands) 132 + cmd's registry still serves lazy-stub, cached-command-replay, and noun 133 + auto-registration the same way. All that logic lives in 134 + `app/cmd/background.js`, which is loaded by the new resident 135 + `index.html`. Under the new transport every subscribe/publish is a 136 + `tile:pubsub:*` IPC with the trustedBuiltin grant — the routing goes 137 + main-process → extensionBroadcaster → cmd resident window 138 + (registered via `registerTrustedBuiltinWindow`). Same event flow as 139 + feature tiles; cmd is just another subscriber from the pubsub plumbing's 140 + point of view. 21 141 22 - (to be filled in as commits land) 142 + ### Handling cmd's ext:ready race 143 + 144 + cmd's `background.js` publishes `ext:ready` only after 145 + `initCommandRegistry()` has subscribed to `cmd:register`, `cmd:register-batch`, 146 + etc. `cmd-glue.ts` awaits this publish before resolving `initCmd()`, 147 + so any subsequent feature startup that publishes `cmd:register-batch` 148 + arrives AFTER the subscribers are in place. Matches the v1 iframe path's 149 + semantics exactly. Unique source address on the wait subscription 150 + prevents clashes with main.ts's own `getSystemAddress()` ext:ready 151 + subscriber (which uses source-keyed dispatch). 152 + 153 + ### v1 preload APIs not on tile-preload 154 + 155 + `api.app.getInfo()` and `api.extensions.list()` (v1 preload surfaces) do 156 + not exist on tile-preload. cmd's `background.js` used both. I mapped: 157 + - `api.extensions.list()` → `api.features.list()` (v2 equivalent) 158 + - `api.app.getInfo()` → `window.__APP_VERSION__` (compile-time) with 159 + `'0.0.0'` fallback. Used only for cache validity checks; functional 160 + impact is nil (cache mismatch just triggers re-registration). 161 + 162 + Not adding `api.app` to tile-preload. If a future need emerges we can; 163 + for now keeping the strict surface narrow. 164 + 165 + ### No new capability-enforcement bypass sites 166 + 167 + Audited: cmd and page exercise pubsub, commands, settings, datastore, 168 + shortcuts, window, features. All are already `trustedBuiltin`-aware from 169 + Phase 1b's blanket bypass in the `check*Allowed` helpers + inline sites. 170 + No additional edits needed in `tile-ipc.ts`, `check-capability.ts`, or 171 + any pure-module helper. 172 + 173 + ## Open items / next-step suggestions 174 + 175 + ### Phase 2 (test fixture migration) 176 + 177 + The remaining v1 seam is the test bgWindow (`peek://app/background.html`) 178 + loaded via the legacy preload + `IPC_CHANNELS.SUBSCRIBE` path. This is 179 + the last loader of `preload.js` and the last place `extensionHostWindow` 180 + is needed. Phase 2 per `docs/v1-removal-plan.md` recommends a privileged 181 + test renderer in `app/_test/` using `tile-preload.cjs` + trustedBuiltin. 182 + When that lands, `extensionHostWindow` and the remaining `loadExtInHost` 183 + call-sites (currently only featureless — cmd and page no longer use 184 + them) can be audited for deletion. 185 + 186 + ### HUD test fixture regression (Phase 1b leftover) 187 + 188 + `tests/desktop/hud.spec.ts:116 — 'hud command is registered'` relies on 189 + `waitForWindow('ext/hud/hud.html')` auto-opening. This fixture was not 190 + updated in Phase 1b. Worth a separate targeted fix — the resident HUD 191 + renderer opens the overlay window on demand via `api.window.open(...)`, 192 + but the test expects it already open at startup. 193 + 194 + ### cmd command-cache version check weakened 195 + 196 + Without `api.app.getInfo()`, the app-version component of 197 + `isCacheValid()` always sees `'0.0.0'` unless `window.__APP_VERSION__` 198 + is injected at bundle time. Option A: expose `api.app.getInfo()` on 199 + tile-preload (routes to the ungated `app-info` IPC). Option B: inject 200 + `__APP_VERSION__` via preload's `additionalArguments` (or a 201 + build-number constant like vite does for mobile). Low priority — at 202 + worst, a known-good cache is discarded on first app-version check, 203 + which just spends a few ms re-registering commands. 204 + 205 + ### main.ts comment cleanup 206 + 207 + Several `initCmd` / `initPage` comments in main.ts still reference 208 + "iframe" phrasing that no longer applies. Kept the comments honest where 209 + I edited; sweep still available for a follow-up polish PR. 210 + 211 + ## Files changed (cumulative, across all 6 commits) 212 + 213 + - `app/cmd/background.html` (deleted) 214 + - `app/cmd/index.html` (new, resident renderer) 215 + - `app/cmd/background.js` (v2 api.pubsub.* surface; api.app/api.extensions mappings) 216 + - `app/page/background.html` (rewritten as single-file resident renderer) 217 + - `app/page/background.js` (deleted) 218 + - `backend/electron/cmd-glue.ts` (rewritten) 219 + - `backend/electron/page-glue.ts` (rewritten) 220 + - `backend/electron/main.ts` (new init signatures + loadedConsolidatedExtensions bookkeeping) 221 + - `AGENT_REPORT.md` (this file) 222 + 223 + ## Verification 224 + 225 + - `yarn tsc -p backend/tsconfig.json --noEmit` — clean. 226 + - `yarn build` — clean. 227 + - `yarn test:unit` — 2220/2220 pass. 228 + - Targeted Playwright smoke (`test:grep "opens URL" / "cmd panel"`) — 229 + all green except the two preexisting failures noted above.