← Commit history

Publish 1.1.0

John Lauer ·13cf779498 ·4mo ago ·parent 5789d9d
4 files changed +258−5
package.json+5−2
@@ -1,8 +1,11 @@ {   "slug": "adom-desktop-puppeteer-bridge",-  "version": "1.0.0",+  "version": "1.1.0",   "type": "app",-  "description": "Reference implementation of the Puppeteer bridge — Node + puppeteer-core + Chrome for Testing for headful browser automation, multi-window, per-tab CDP screencast recording.",+  "description": "CONTAINER-SIDE install — Claude skills only. This pkg drops the skills that teach a cloud AI to drive the pup browser bridge (the `pup` user skill + the `pup-bridge-dev` developer skill) into ~/.claude/skills/. It does NOT contain the bridge runtime. The bridge itself (Node + Chrome for Testing, the code that actually drives a browser) lives on the DESKTOP: it ships bundled inside Adom Desktop and is published here on the Releases tab as adom-bridge-puppeteer-v<ver>.zip, which Adom Desktop streams into its bridges-cache. TL;DR: `pkg install` = skills for the container; the bridge = the Release zip + bundled in Adom Desktop.",+  "keywords": ["pup", "puppeteer", "browser", "adom-desktop", "bridge", "skills"],+  "tags": ["skills", "pup", "puppeteer", "browser", "adom-desktop", "bridge"],+  "files": ["SKILL.md", "skills/**", "skills/pup-bridge-dev/SKILL.md", "install.sh", "uninstall.sh", "README.md", "package.json"],   "dependencies": {},   "scripts": {     "install": "./install.sh",
page.json+34−3
@@ -4,8 +4,15 @@   "slug": "adom-desktop-puppeteer-bridge",   "title": "Adom Desktop - Puppeteer Bridge",   "brief": "Reference implementation of the Puppeteer bridge — Node + puppeteer-core + Chrome for Testing for headful browser automation, multi-window, per-tab CDP screencast recording.",-  "version": "1.0.0",-  "tags": [],+  "version": "1.1.0",+  "tags": [+    "skills",+    "pup",+    "puppeteer",+    "browser",+    "adom-desktop",+    "bridge"+  ],   "license": "MIT",   "discovery_triggers": [     "puppeteer bridge",@@ -70,5 +77,29 @@   "created_at": "2026-05-28T05:28:43.991Z",   "updated_at": "2026-06-16T12:43:19.735Z",   "skills": [],-  "author_name": "John Lauer"+  "author_name": "John Lauer",+  "description": "CONTAINER-SIDE install — Claude skills only. This pkg drops the skills that teach a cloud AI to drive the pup browser bridge (the `pup` user skill + the `pup-bridge-dev` developer skill) into ~/.claude/skills/. It does NOT contain the bridge runtime. The bridge itself (Node + Chrome for Testing, the code that actually drives a browser) lives on the DESKTOP: it ships bundled inside Adom Desktop and is published here on the Releases tab as adom-bridge-puppeteer-v<ver>.zip, which Adom Desktop streams into its bridges-cache. TL;DR: `pkg install` = skills for the container; the bridge = the Release zip + bundled in Adom Desktop.",+  "keywords": [+    "pup",+    "puppeteer",+    "browser",+    "adom-desktop",+    "bridge",+    "skills"+  ],+  "files": [+    "SKILL.md",+    "skills/**",+    "skills/pup-bridge-dev/SKILL.md",+    "install.sh",+    "uninstall.sh",+    "README.md",+    "package.json"+  ],+  "dependencies": {},+  "scripts": {+    "install": "./install.sh",+    "uninstall": "./uninstall.sh"+  },+  "org": "adom" }\ No newline at end of file
skills/pup-bridge-dev/SKILL.mdadded+98
@@ -0,0 +1,98 @@+---+name: pup-bridge-dev+user-invocable: false+description: "DEVELOPER skill for building, publishing, and maintaining the Adom Desktop Puppeteer (pup) bridge. NOT needed by general users — they want the `pup` skill. Read this when editing the bridge code, cutting a new version, publishing to the wiki, wiring the cold-start Chrome-for-Testing self-heal, or understanding the pkg-vs-release-vs-bundled artifact model. Trigger words: pup bridge dev, publish pup bridge, build puppeteer bridge, bridge_install pup, adom-desktop-puppeteer-bridge, cold-start self-heal, browser_readiness internals, pup release, pup manifest, ship pup bridge."+---++# pup-bridge-dev — building & shipping the Puppeteer bridge++The canonical source of truth for the pup bridge is **this wiki repo**+(`wiki.adom.inc/adom/adom-desktop-puppeteer-bridge`), extracted from `adom-desktop/plugins/puppeteer`+on 2026-06-29 to be cloud-owned like the kicad/fusion bridges. Read `CLAUDE.md` (ownership boundary)+and `PUBLISHING.md` (step-by-step recipe) in this repo alongside this skill.++## The THREE artifacts — know which is which (this is the #1 confusion)++A user installs TWO different things from this one page. They are not the same:++| Artifact | What it is | Who installs it | How |+|---|---|---|---|+| **pkg tarball** (Packages tab) | the **container-side Claude skills** (`SKILL.md` + `skills/*`) — docs that teach the cloud AI how to drive pup. **No bridge runtime.** | a cloud **container** | `adom-wiki pkg install adom/adom-desktop-puppeteer-bridge`, or auto via AD's `sync_skills` |+| **release zip** (Releases tab) | the **bridge RUNTIME** (`server.js`, `chrome.js`, `bridge.json`, node deps reconstructed on spawn) — the code that actually drives Chrome on the desktop | **Adom Desktop**, streamed into `bridges-cache\puppeteer` | `bridge_install {manifestUrl}` / `refresh_bridges` (via `updateManifestUrl`) |+| **bundled seed** (inside the AD installer) | a copy of the same runtime, shipped in the NSIS for first-run/offline | every AD install | ships with Adom Desktop; superseded by a newer cache copy (cache-over-bundled, numeric version) |++So: **the pkg is skills (container). The bridge is the zip (desktop) + the bundled seed.** Keep the+pkg description saying exactly that, or people think the tarball contains the bridge — it does not.++## Repo layout++- `src/` — the runnable bridge (what the release zip contains, at zip-root). `server.js`, `chrome.js`,+  `credential_vault.js`, `bridge.json`, `BRIDGE_VERSION`, node `package.json`/`package-lock.json`, html/icons.+- `SKILL.md` (root) — the **user** skill (`name: pup`). Deployed to `~/.claude/skills/adom-desktop-puppeteer-bridge/`.+- `skills/pup-bridge-dev/` — THIS dev skill.+- `adom-bridge-puppeteer-manifest.json` (root) — the streaming manifest AD's `updateManifestUrl` points at.+- `package.json` (root) — the **adompkg descriptor** (slug/version/type/description) for `pkg publish`. NOT the node one.+- `install.sh` / `uninstall.sh` — deploy `SKILL.md` + `skills/*` into the container's `~/.claude/skills/`.+- `page.json`, `README.md`, `*.png` heroes — the wiki page presentation (the heroes are gitignored so the+  container pkg stays lean — they're already uploaded as page assets).++## Cold-start self-heal — the architecture (what 1.1.0 added, the reason this repo exists)++On a fresh PC (HD bundles AD; the installer pre-installs neither Node nor Chrome for Testing), the first+`browser_open_window` used to fail with a generic "Failed to launch Chrome after 3 attempts" + a dev+string. Now:++- **`src/chrome.js`** — `detectChrome()` (validates the ACTUAL exe, not "a dir exists"), `installChrome()`+  (programmatic via the bundled `@puppeteer/browsers`, pinned to the buildId puppeteer expects — never+  'stable', or launch() won't find it), an install-state singleton (dedup + progress), `ensureChromeReady()`+  (the gate — background install, returns immediately), `readiness()` (powers the verb + chip).+- **`browser_open_window` gate** (CfT path only; native-drive skips it): missing CfT → kick off a+  non-blocking install + return `{errorCode:"chrome_for_testing_installing", statusVerb:"browser_readiness",+  _hint:"poll then retry"}`. Install fail → `chrome_install_failed`/`chrome_download_failed` (no silent+  continue-to-doomed-launch).+- **`browser_readiness`** (poll) + **`browser_prewarm`** (install without opening a window).+- **`/status`** emits `led`/`summary`/`tooltip` truthfully (yellow installing, red failed, green ready).+- **Node** is handled by AD core BEFORE the bridge spawns (`node_not_found` → `desktop_install_node`) —+  not this bridge's job (the bridge is a node process; it can't run without node).+- **The one thing this bridge can't do:** pre-warm before first use (it isn't running until the first+  call). AD/HD must call `browser_prewarm` on embedded first-run — tracked in `HANDOFF-TO-ADOM-DESKTOP.md`.++## Publishing (the wiki has TWO storage layers — don't mix them)++Full recipe in `PUBLISHING.md`. The load-bearing rules:++1. **The bridge `.zip` → a RELEASE asset** (`adom-wiki release create` + `release upload`). NEVER+   `repo push` a `.zip` — it's gitignored and silently skipped; the manifest URL would 404.+2. **The manifest JSON + source → the git repo** (`adom-wiki repo push`). The manifest's `url` is the+   RELEASE download URL; its `sha256`/`size` MUST match the served asset (releases preserve your sha;+   re-download to confirm or `bridge_install` rejects it).+3. **The skills → a PKG** (`adom-wiki pkg publish`). The pkg description (root `package.json`) must say+   "container-side skills." `pkg pack` honors `.gitignore` for exclusion (no separate npmignore) — that's+   why the heroes are gitignored, to keep the tarball lean. Set per-version notes with `adom-wiki pkg notes`.+4. **Version display gotcha:** a RELEASE shows up in `adom-wiki pkg info` as a row with `type:null` (a+   wiki UI conflation). The real pkg rows have `type:"app"`. Use `release list` for true releases.+5. **`bridge.json` + `BRIDGE_VERSION` lockstep**, and keep the version **>** the AD bundled seed so+   cache-over-bundled wins.++## Testing a new version on a real desktop++```bash+adom-desktop targets    # multiple desktops → --target <name> is required+adom-desktop --target <name> bridge_install '{"manifestUrl":"https://wiki.adom.inc/api/v1/pages/adom-desktop-puppeteer-bridge/files/adom-bridge-puppeteer-manifest.json","force":true}'+adom-desktop --target <name> browser_readiness '{}'   # proves the new code is live+```++- **No Node on the box** → `browser_*` returns `node_not_found` before the bridge spawns (AD core; correct).+  That's a genuine cold-start demo of the FIRST link; it can't exercise `chrome.js` (no node to run it).+- **A box with Node but no Chrome for Testing** is the only place to see the full Chrome self-install live+  (`browser_open_window` → `chrome_for_testing_installing` → poll `browser_readiness` → opens). Most dev+  boxes already have CfT, so `readiness()` just returns `ready:true`.+- The streamed zip is **source-only**; AD runs `npm install` in the cache on first spawn (sharp/keytar+  ship prebuilds). The bundled seed already has node_modules. Don't put node_modules in the zip.++## Don't++- Don't edit `adom-desktop/plugins/puppeteer` as if it's live, and don't `release-bridge.sh puppeteer`+  from the adom-desktop repo — that clobbers this cloud-owned page.+- Don't ship the bridge runtime in the pkg tarball or the skills in the release zip. Two artifacts, two homes.+- Don't install 'stable' Chrome — pin to puppeteer's expected buildId (`chrome.js` does this).
skills/pup-bridge-publish/SKILL.mdadded+121
@@ -0,0 +1,121 @@+---+name: pup-bridge-publish+user-invocable: false+description: "DEVELOPER skill — the exact, battle-tested recipe for publishing a new version of the Adom Desktop Puppeteer (pup) bridge to wiki.adom.inc, plus every gotcha hit live. NOT for general users. Read before cutting a release: which artifact goes where (pkg=skills, release=bridge zip), the version-lockstep rules, the `files` allowlist + `skills/**` glob trap, the hero-bloat fix, sha matching, and the verify steps. Trigger words: publish pup bridge, ship pup bridge, release pup, pkg publish, repo push, adom-wiki release, bridge manifest, pup version bump, adom-desktop-puppeteer-bridge publish."+---++# pup-bridge-publish — shipping a new pup bridge version++The pup bridge is cloud-owned at `wiki.adom.inc/adom/adom-desktop-puppeteer-bridge`. This is the+step-by-step ship recipe + the traps that cost real time. Companion: `pup-bridge-dev` (architecture /+ownership), `PUBLISHING.md` (terse recipe), `CLAUDE.md` (ownership boundary).++## What goes WHERE — three artifacts, three homes (memorize this)++| Artifact | Home | Command | Carries |+|---|---|---|---|+| **bridge runtime `.zip`** | a **Release** asset | `adom-wiki release upload` | `src/` at zip-root (server.js, chrome.js, bridge.json, node deps). The thing AD runs. |+| **streaming manifest JSON** | the **git repo** | `adom-wiki repo push` | points at the release zip URL + its sha256/size |+| **container skills tarball** | a **Package** | `adom-wiki pkg publish` | `SKILL.md` + `skills/*` (the Claude skills). NO runtime. |++> The `.zip` is a RELEASE, never a git file: `*.zip` is gitignored and `repo push --files X.zip`+> reports `ok` but silently skips it (the URL then 404s). Binaries → `release upload`.++## Auth (once per container)++```bash+export ADOM_WIKI_TOKEN=$(cat /var/run/adom/api-key 2>/dev/null)   # container default; or session.json's session_token+adom-wiki whoami    # MUST show a real user (e.g. [email protected]). Strict-auth rejects the shared "Developer" token.+```+Every mutation needs a real `--changelog` / `-m` (≥10 chars, ≥2 words) or the server 400s.++## The recipe++### 1. Bump version IN LOCKSTEP, and keep it > the AD bundled seed++```bash+printf '1.1.1' > src/BRIDGE_VERSION+sed -i 's/"version": "1.1.0"/"version": "1.1.1"/' src/bridge.json    # bridge runtime+sed -i 's/"version": "1.1.0"/"version": "1.1.1"/' package.json       # adompkg descriptor (the pkg)+```+`src/BRIDGE_VERSION` and `src/bridge.json` MUST match (AD uses BRIDGE_VERSION to detect a stale running+process). Keep the number **above** the seed in `adom-desktop/plugins/puppeteer` so cache-over-bundled wins.++### 2. Build the bridge zip (source-only, `src/` at zip ROOT — no top-level dir)++`zip` may be absent → Python. node_modules is NEVER included (AD `npm install`s it on spawn; the seed+ships it; an 88 MB zip would blow wiki limits):++```python+import zipfile, os, hashlib+root, out = "src", "adom-bridge-puppeteer-v1.1.1.zip"+with zipfile.ZipFile(out, "w", zipfile.ZIP_DEFLATED) as z:+    for dp, dirs, files in os.walk(root):+        for skip in ("node_modules","screenshots","profiles"):+            if skip in dirs: dirs.remove(skip)+        for f in files: z.write(os.path.join(dp,f), os.path.relpath(os.path.join(dp,f), root))+print("sha256:", hashlib.sha256(open(out,"rb").read()).hexdigest(), "size:", os.path.getsize(out))+# SANITY: assert chrome.js + your change are inside before shipping.+```++### 3. Publish the zip as a Release (releases PRESERVE your sha)++```bash+adom-wiki release create adom/adom-desktop-puppeteer-bridge 1.1.1 --title "..." --changelog "<≥2 words>"+adom-wiki release upload adom/adom-desktop-puppeteer-bridge 1.1.1 adom-bridge-puppeteer-v1.1.1.zip --json+# the response's assets[].sha256/size are what the manifest MUST carry. Then VERIFY the PUBLIC url:+curl -sL https://wiki.adom.inc/download/adom/adom-desktop-puppeteer-bridge/1.1.1/adom-bridge-puppeteer-v1.1.1.zip | sha256sum+```++### 4. Point the manifest at the release + push it (git repo)++Edit `adom-bridge-puppeteer-manifest.json` → `version`, `url` (the release download URL), `sha256`,+`size` (from step 3 — **must match the served asset or `bridge_install` rejects it**). Then:++```bash+adom-wiki repo push adom/adom-desktop-puppeteer-bridge \+  --files adom-bridge-puppeteer-manifest.json src/bridge.json src/BRIDGE_VERSION src/server.js src/chrome.js \+  -m "v1.1.1: <what changed>"+```++### 5. Publish the container skills as a pkg — keep it LEAN, and MIND THE TRAPS++```bash+adom-wiki pkg pack            # ALWAYS pack + inspect BEFORE publish+tar tzf *.tgz                 # confirm: SKILL.md + skills/*/SKILL.md + install.sh, and NOTHING heavy+adom-wiki pkg publish --org adom --version 1.1.1+adom-wiki pkg notes adom/[email protected] -m "Container skills: <what changed>"+```++The pkg description lives in the root **`package.json`** `description` — keep it explicit that this is+**container-side skills only; the bridge runtime is the Release zip + bundled in Adom Desktop.**++## Traps hit live (don't relearn these)++- **`pkg pack` includes EVERYTHING by default** → a 16 MB tarball (all the hero PNGs + `src/` runtime).+  Fix: the heroes are gitignored (`*.png`) since they're already page assets, AND `package.json` has a+  **`files` allowlist**. With both, the tarball drops to ~12 KB.+- **`files` directory entries need a GLOB.** Listing `"skills"` (bare dir) silently includes ZERO skill+  files. Use **`"skills/**"`** (and/or the explicit `"skills/<name>/SKILL.md"`). Always `tar tzf` to+  confirm your skills actually made it in — a missing skill = an empty Skills tab.+- **`pkg pack` honors `.gitignore`, not a separate npmignore.** So you can't gitignore something you+  need in git (e.g. `src/`) to drop it from the pkg — use the `files` allowlist for that.+- **A RELEASE shows up in `adom-wiki pkg info` as a row with `type:null`** (wiki UI conflation). The real+  pkg rows are `type:"app"`. Use `adom-wiki release list` for true releases; don't think your pkg shipped+  just because a version appears in `pkg info`.+- **sha/size mismatch → `bridge_install` rejects the manifest.** Releases preserve the uploaded sha, so+  use the `release upload` response values verbatim and re-download to confirm.+- **The Skills tab is populated from the published PKG, not `page.json`** (`page.skills` is null even on+  pages with a full Skills tab). If skills aren't showing, you didn't `pkg publish` them (or the `files`+  glob dropped them).++## Verify (every ship)++```bash+# manifest serves at the updateManifestUrl path:+curl -s https://wiki.adom.inc/api/v1/pages/adom-desktop-puppeteer-bridge/files/adom-bridge-puppeteer-manifest.json | jq .sha256+# live install + new verbs on a real desktop (multi-desktop → --target; `adom-desktop targets` lists them):+adom-desktop --target <name> bridge_install '{"manifestUrl":".../files/adom-bridge-puppeteer-manifest.json","force":true}'+adom-desktop --target <name> browser_readiness '{}'+# render the page in pup + READ the screenshot (curl 200 is NOT verification). Confirm version + Skills tab.+```