Handoff to the adom-desktop build thread — pup is now cloud-owned

Paste the block below into the adom-desktop build thread (the one that owns github.com/adom-inc/adom-desktop). It mirrors what was done for the kicad/fusion bridges.


Subject: The Puppeteer (pup) bridge moved out of adom-desktop into its own wiki repo — please treat it like kicad/fusion now.

We took over code management of the Puppeteer bridge. It now lives at its own canonical wiki repo, exactly like the kicad and fusion bridges:

  • Canonical repo / page: https://wiki.adom.inc/adom/adom-desktop-puppeteer-bridge
  • Current published version: 1.1.0 (release asset + streaming manifest are live)
  • Manifest (updateManifestUrl target): https://wiki.adom.inc/api/v1/pages/adom-desktop-puppeteer-bridge/files/adom-bridge-puppeteer-manifest.json
  • Release zip: https://wiki.adom.inc/download/adom/adom-desktop-puppeteer-bridge/1.1.0/adom-bridge-puppeteer-v1.1.0.zip (sha256 525eabb0350ea0eaf52a949e9b3026f5a4a035868afe9546a7478298b9539b8c, source-only — node_modules is reconstructed by AD's npm install on spawn, as today)

What changed in 1.1.0 (the reason for all this): cold-start self-heal. On a fresh PC (HD bundles AD; the installer pre-installs neither Node nor Chrome for Testing), the first "open in pup" used to fail with a generic "Failed to launch Chrome after 3 attempts" + a dev string (npx…). Now the bridge detects a missing Chrome for Testing, auto-installs it (programmatically via the bundled @puppeteer/browsers), and exposes browser_readiness + browser_prewarm; /status reports led/summary/tooltip truthfully (yellow while installing). The node_not_found path you already own is unchanged and still correct.

Please make these adom-desktop changes (all small, mirroring kicad/fusion):

  1. Keep pup a pre-installed bundled SEED (do NOT remove it from bundle.resources) — same as kicad/fusion/blender. Fresh installs must still ship a working pup offline.

  2. Update the bundled seed plugins/puppeteer/ to v1.1.0 so a fresh install ships the cold-start fix even before the first wiki sync. Easiest: download + unzip the 1.1.0 release zip (URL above) into plugins/puppeteer/ (it's the src/ tree at zip-root: server.js, chrome.js, bridge.json, BRIDGE_VERSION=1.1.0, etc.), keep the existing bundled node_modules. The seed's bridge.json already declares updateManifestUrl (see #3).

  3. Confirm the seed bridge.json carries updateManifestUrl = the manifest URL above, so AD auto-pulls our updates (cache-over-bundled, numeric version_gt) via refresh_bridges / the 4h poll — exactly like kicad/fusion. (It's already set in the 1.1.0 source.) Add a short plugins/puppeteer/CANONICAL.md breadcrumb pointing at the wiki repo, like the kicad/fusion seeds.

  4. Stop treating plugins/puppeteer as the source of truth. Don't hand-edit it as if live and don't release-bridge.sh puppeteer from the adom-desktop repo anymore (it would clobber the cloud-owned page). pup is now in the same bucket as kicad/fusion in BRIDGE_OWNERSHIP.md / release-publish.sh SKILLS_SRC — please add the same guard. (Also: pup's consumer SKILL now ships from the bridge's own wiki page, so drop pup-SKILL.md from the AD-core pkg's SKILLS_SRC to avoid a stale copy clobbering ours — same move you made for kicad/fusion.) ALSO remove "puppeteer" from AD_CORE_SKILL_BRIDGES in bridge_registry.rs so bridge_list reports skillPkg = adom/adom-desktop-puppeteer-bridge for the puppeteer bridge — that's what makes the daily sync_skills auto-install the pup skills into every container. It's hardcoded null (skill-in-core) today, which is no longer true now that the skill ships from the pup page.

  5. THE ONE AD-CORE FIX WE NEED (we can't do this from the bridge): warm Node + Chrome for Testing on the HD-embedded first-run. Today the first-launch prefetch (AUTOSTART_VERSION task in lib.rs, ~lines 3601–3607) is skipped when AD is embedded — which is exactly the HD-bundled fresh-PC case, so nothing pre-warms and the whole cold-start cost lands on the user's first "open in pup". Please either:

    • re-enable that idle-time prefetch task on the embedded path (it already calls start_browser_bridge, which now self-installs Chrome for Testing), or
    • after AD enters embedded mode, fire browser_prewarm once (fire-and-forget) to kick the Chrome download in the background. Either way, gate it behind the existing Node check (if Node is missing it's a no-op / the node_not_found path stays the recovery). Net effect: a fresh HD install quietly warms pup so the user's first "open in pup" is instant instead of a 2–3 min download.

Verify after your change: on a fresh embedded boot with Node present, bridge_list shows pup at 1.1.0 (cache or seed), browser_readiness returns {ready:true} without the user ever asking, and bridge_check_updates reaches the new page via updateManifestUrl. On a box without Node, browser_open_window still returns the clean node_not_founddesktop_install_node path.

Questions / bugs in pup itself (a browser_* verb, a hint, the Chrome self-heal) → file them against the wiki repo, not adom-desktop. Generic AD capabilities (a new lifecycle verb, the prewarm trigger above) → adom-desktop, but don't re-absorb the bridge.



ALSO: the bridge-authoring docs are stale — please update them (affects EVERY new bridge author)

A new user asking "make me an adom-desktop bridge for " gets pointed at: the adom-desktop-bridges Bridge SDK guide (#1 discovery hit), the adom-desktop-bridge-author skill, and the repo's skills/BRIDGE_SDK.md (source). The RUNTIME guidance (bridge.json, verbs, health chip, rich hints, lifecycle) is good + current. But the PUBLISH/PACKAGING guidance is outdated — and in one place WRONG. These are AD-core-owned (we won't touch them, same as you don't touch pup), so please fix all three:

  1. WRONG — "zip/bin under /files". BRIDGE_SDK.md "Publish + iterate" (and the adom-desktop-bridges page) tell authors the bridge zip goes on the page's /files. It does NOT — /files strips/rejects binaries. The zip is a RELEASE asset (adom-wiki release create + release upload); the manifest's url points at the release download URL with a matching sha256/size. (This is what fusion/kicad/pup actually do; following the doc as written produces a 404 manifest.)

  2. MISSING — the 3-artifact model. A bridge page ships THREE things and the docs only really explain one: (a) the release zip = the runtime AD streams into bridges-cache; (b) the pkg tarball (adom-wiki pkg publish) = the container-side Claude/Codex skills (how the consumer skill reaches a container — completely absent today); (c) the optional bundled seed for AD-bundled bridges.

  3. MISSING — skill packaging + dev/user separation. (a) the pkg files allowlist + the skills/** glob trap (a bare "skills" entry ships ZERO skill files); (b) keep the tarball LEAN — NO zip, NO src/, NO hero PNGs (tar tzf to confirm; it was 16 MB before guards); (c) the wiki indexes EVERY SKILL.md in the repo as an installable, Skills-tab-listed skill (skill_count) — so DEV/PUBLISH skills must be source-only, named NOT SKILL.md (e.g. dev-skills/*.md), or every user installs them.

  4. MISSING — .codex/skills. install.sh should deploy the user skill to BOTH ~/.claude/skills and ~/.codex/skills (Codex is a real second agent skills home now).

  5. MISSING — discovery triggers. Lead discovery_triggers with everyday USER phrases (not dev jargon) so "open my app in " surfaces the page; the discover snippet is auto-generated from discovery_triggers + discovery_pitch (no separate upload step).

  6. STALE URL — the retired wiki host. Both the adom-desktop-bridges page AND the adom-desktop-bridge-author skill still cite wiki-ufypy5dpx93o.adom.cloud (retired). The only host is wiki.adom.inc. Grep + scrub (incl. the page.json readme body).

Easiest path: lift the content from the pup bridge's now-canonical publish playbook — wiki.adom.inc/adom/adom-desktop-puppeteer-bridgedev-skills/pup-bridge-publish.md (it carries all six points above, battle-tested) — and generalize the pup-specifics into the SDK guide.


⚠ CRITICAL (found LIVE 2026-06-29): a wiki-streamed pup CACHE copy CRASHES — no node_modules

When AD installs pup from the wiki — bridge_install {manifestUrl}, or refresh_bridges / the 4h poll via updateManifestUrl — it streams the source-only zip into bridges-cache\puppeteer\ and spawns node server.js, which **immediately crashes**: MODULE_NOT_FOUND on require('puppeteer') (server.js:10). The cache copy has **no node_modules**, and AD's cache-spawn path does NOT npm install it or reuse the bundled node_modules. Because **cache-over-bundled wins, this replaced a working bundled v1.0.16 with a broken v1.1.0** (verified live on AdomLapper; reverted with bridge_uninstall). This is the Node-bridge analogue of why kicad/fusion (Python, no node_modules) stream fine but pup can't.

Fix — please do ONE:

  • (A) PREFERRED — give a cache-installed spawn.kind:"node" bridge its node_modules. On spawn from the cache, AD should either (i) npm install/npm ci in the cache dir first (the bespoke start_browser_bridge ALREADY does this for the bundled pup — extend it to / route the cache copy through it), or (ii) reuse/symlink the bundled node_modules into the cache dir. Then wiki-streaming + updateManifestUrl auto-update works for pup exactly like kicad/fusion.
  • (B) OR keep pup runtime "bundled-only" (the original model): the bundled-seed bump (handoff #2, which KEEPS node_modules) is the runtime delivery; wiki-streaming the runtime stays off and updateManifestUrl must NOT pull a newer runtime into the cache.

Until (A) ships: do NOT publish a wiki pup RUNTIME version newer than the AD bundled seed — any box with our updateManifestUrl persisted would pull the newer source-only zip into the cache and crash. The skills pkg is unaffected (separate path, works). Net for now: ship the pup RUNTIME via the bundled seed (#2); treat wiki-streaming as blocked on fix (A).

⭐ NEW TOP PRIORITY (found LIVE 2026-07-01 on 3 fresh Windows boxes): Node install = UAC + stale PATH dead-end

Tested cold-start on AdomLapper + two genuinely fresh boxes (AdomTestWin11 vbox, winvm Azure — both Edge-only, no Node). The browser side is now solved by the bridge (v1.5.0: installed-browser-first, spawn-verified fallback, self-warm, disk guards). The remaining cold-start blockers are both in AD-core desktop_install_node and they hard-stop the exact "AI can't recover" scenario:

  1. UAC prompt. desktop_install_node installs Node via the machine-wide MSI/winget, which is manifested requireAdministrator → a UAC dialog pops on the user's desktop ("Node.js — OpenJS Foundation, allow changes?"). A cloud AI cannot click it; the user must, and John explicitly does not want a UAC here.
  2. Stale PATH after a successful install. Even once Node installs, the already-running AD process keeps its OLD environment, so the very next browser_* STILL returns node_not_found / could not run npm for cache bridge. Reinstalling doesn't help (winget then says "No available upgrade" = already installed). The bridge can never spawn until AD is relaunched.

Both fixed by one change — install Node the portable, user-scoped way:

  • Download the Node ZIP (node-vXX-win-x64.zip), extract node.exe into a user-writable dir (e.g. %LOCALAPPDATA%\Adom Desktop\node\). No installer, no UAC.
  • Spawn bridges with that node.exe by absolute path (AD already knows where it put it) — don't rely on PATH at all. This also permanently kills the stale-PATH class of bug.
  • Even better: bundle node.exe in the AD installer (~50 MB) so a fresh AD already has Node — zero download, zero UAC, zero PATH dependency, instant first browser_open_window.
  • If you keep a PATH-based flow, at minimum probe common Node locations (%ProgramFiles%\nodejs, %LOCALAPPDATA%\..., nvm dirs) before declaring node_not_found, and refresh PATH from the registry after install.

Bridge-side hint already added (SKILL.md): if node_not_found persists after a successful install, the AI is told AD's PATH is stale → relaunch AD (desktop_relaunch_self) rather than looping the installer.

RESOLVED: the wiki-streamed cache crash (node_modules) is fixed in AD ≥ 1.9.55

The earlier CRITICAL section (wiki-streamed pup CACHE copy crashes with MODULE_NOT_FOUND) is no longer reproducing — on AD 1.9.55–1.9.62 the wiki-cache copy spawns cleanly (AD now reconstructs node_modules on the cache bridge). All 3 test boxes ran the cache copy of pup 1.3.0→1.5.0 with source:"cache". So the "ship runtime only via the bundled seed" constraint is lifted: the updateManifestUrl auto-pull works. (Still bump the bundled seed opportunistically so a truly offline first-run is current.)

⭐ DESIGN PROPOSAL: AD-managed shared runtimes (Node + Python) — see PROPOSAL-shared-runtimes.md

The Node UAC/PATH pain above is a symptom of a bigger gap: no one owns bridge runtimes. Full write-up in PROPOSAL-shared-runtimes.md (this repo). TL;DR of the recommendation (a hybrid, not either extreme):

  • AD keeps a shared, content-addressed portable-runtime cache (…\adom-runtimes\node-22.11.0\, python-3.12.7\), populated from portable zips into a user dir — no installer, no UAC. Ideally AD bundles one Node (+ Python) so a fresh box has it with zero download.
  • Bridges DECLARE their runtime in bridge.json (runtime: {kind, version, preferred}) — they do NOT install it. pup ships this declaration as of v1.6.1. Shared interpreter when compatible; a pinned version fetched only when a bridge needs an odd one (no duplication for the common case).
  • AD spawns bridges by the interpreter's ABSOLUTE PATH (…\adom-runtimes\node-22.11.0\node.exe server.js). This is the linchpin — it kills BOTH the UAC (portable/user-dir) AND the stale-PATH dead-end (no reliance on the machine PATH) at once. Python bridges get a per-bridge venv on the shared interpreter.

This replaces the per-bridge "roll your own Node" pattern (today's status quo, and the thing that caused this whole debugging session). desktop_install_node's UAC MSI becomes a last-resort fallback.