← Commit history
v0.16.4 (insiders): Send to AI for Hydrogen 1.0.187+: newbie-panel.js re-vendored at 2.22.0 (job + state polling, pre-1.0.187 delivered_to path kept), the dashboard proxies GET /ai-threads/run-prompt/status with the query string intact, and all three control-API routes now pass status, content-type and body bytes through unchanged (503 with a hint when no Hydrogen answers, never 404).
5 files changed
+37−20
bin/nb-dashboard+33−16@@ -20,7 +20,7 @@ const { execFile, spawn } = require('child_process'); const fs = require('fs'); const crypto = require('crypto'); -const VERSION = '0.16.3'; // keep in lockstep with package.json (pkg version)+const VERSION = '0.16.4'; // keep in lockstep with package.json (pkg version) // SEND TO AI IS UN-PARKED (John: "yeah, we are re-enabling the send to ai. it seems to be good now"). // The ah build thread certified the crash family dead on the gate-fixed build and the delivery leg is // proven end to end. The park const is DELETED rather than flipped, so no dead branch can resurrect it.@@ -72,6 +72,28 @@ function controlUrl() { try { const u = fs.readFileSync(path.join(require('os').homedir(), '.adom', 'hydrogen-control-url'), 'utf8').trim(); if (u) return u.replace(/\/$/, ''); } catch {} return 'http://127.0.0.1:47084'; }+// Raw pass-through to the control API: bytes in, bytes out. `u` is the path+query exactly as the page+// asked for it. Only the transport is ours; the payload is Hydrogen's.+function proxyRaw(method, u, body, res) {+ let up; try { up = new URL(controlUrl() + u); } catch { up = null; }+ const fail = (why) => {+ res.writeHead(503, { 'Content-Type': 'application/json', 'Cache-Control': 'no-store', ...CORS_ALL });+ res.end(JSON.stringify({ ok: false, error: 'control API unreachable', why, _hint: 'This dashboard proxies ' + u.split('?')[0] + ' to the Hydrogen control API read from ~/.adom/hydrogen-control-url at request time. 503 means the route IS wired but no Hydrogen answered here (not running, or a different host); a 404 would mean the route is missing.' }));+ };+ if (!up) return fail('bad control URL');+ const data = method === 'POST' ? Buffer.from(body || '', 'utf8') : null;+ const req2 = http.request({ host: up.hostname, port: up.port, path: up.pathname + up.search, method, timeout: method === 'POST' ? 120000 : 10000,+ headers: data ? { 'Content-Type': 'application/json', 'Content-Length': data.length } : {} }, (r2) => {+ const chunks = []; r2.on('data', (c) => chunks.push(c)); r2.on('end', () => {+ const buf = Buffer.concat(chunks);+ res.writeHead(r2.statusCode || 502, { 'Content-Type': r2.headers['content-type'] || 'application/json', 'Content-Length': buf.length, 'Cache-Control': 'no-store', ...CORS_ALL });+ res.end(buf);+ });+ });+ req2.on('error', (e) => fail(e.message)); req2.on('timeout', () => { req2.destroy(); fail('timeout'); });+ if (data) req2.write(data); req2.end();+}+const CORS_ALL = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type' }; function httpJson(method, url, body, timeoutMs) { return new Promise((resolve) => { try {@@ -915,21 +937,16 @@ function startServer() { } // The module talks to the AI panel from the PAGE, so these two paths proxy through this // backend: same-origin for the page, and the control URL (a DYNAMIC port) stays server-side.- if (u.startsWith('/updater/status')) {- httpJson('GET', controlUrl() + '/updater/status').then((r) => {- res.writeHead(r.status || 502, { 'Content-Type': 'application/json', ...CORS });- res.end(JSON.stringify(r.json || { error: r.error || 'control API unreachable' }));- });- return;- }- if (u.startsWith('/ai-threads/run-prompt') && req.method === 'POST') {- let b = ''; req.on('data', (c) => (b += c)); req.on('end', () => {- let body = {}; try { body = JSON.parse(b); } catch {}- httpJson('POST', controlUrl() + '/ai-threads/run-prompt', body, 120000).then((r) => {- res.writeHead(r.status || 502, { 'Content-Type': 'application/json', ...CORS });- res.end(JSON.stringify(r.json || { error: r.error || 'control API unreachable' }));- });- });+ // CONTROL API PROXY (control-api-proxy skill): three routes, forwarded RAW. Status code, content-type+ // and body BYTES pass through untouched (a JSON round trip reorders keys, drops 1.0 to 1, loses+ // precision past 2^53, and turns a non-JSON body into an invented error while every probe stays+ // green). The query string travels intact: /ai-threads/run-prompt/status is called as ?job=<uuid>+ // and a proxy that forwards only the path answers about no job at all (Hydrogen 1.0.187+, newbie-panel+ // 2.22.0). When ah is absent the answer is 503 WITH A HINT, never 404: 404 means "not wired".+ if ((u.startsWith('/updater/status') && req.method === 'GET') ||+ (u.startsWith('/ai-threads/run-prompt/status') && req.method === 'GET') ||+ (u.startsWith('/ai-threads/run-prompt') && !u.startsWith('/ai-threads/run-prompt/') && req.method === 'POST')) {+ let b = ''; req.on('data', (c) => (b += c)); req.on('end', () => proxyRaw(req.method, u, b, res)); return; } if (u.startsWith('/api/say-send') && req.method === 'POST') {
bridge/BRIDGE_VERSION+1−1@@ -1 +1 @@-0.16.3+0.16.4
bridge/bridge.json+1−1@@ -2,7 +2,7 @@ "manifest_version": 1, "name": "native-browser", "displayName": "Adom Native Browser",- "version": "0.16.3",+ "version": "0.16.4", "expectedExtensionVersion": "0.2.10", "description": "Drives the user's REAL signed-in Chrome/Edge, in two layers. Layer 1 (nb) needs NOTHING installed and works on any machine: nbrowser_open_os_window (open a URL in the user's real profile, background+flashing, the OAuth/consent path), nbrowser_os_windows, nbrowser_profiles, nbrowser_wake_profile, nbrowser_force_close. Layer 2 (nbe, the Adom Native Browser Extension) unlocks the rest: CDP driving (navigate/click/read/screenshot) inside their logged-in profile. The bridge binds an ephemeral loopback port and the native-messaging host pumps stdio <-> bridge.", "homepage": "https://wiki.adom.inc/adom/nb-bridge",
bridge/package.json+1−1@@ -1,6 +1,6 @@ { "name": "adom-native-browser-bridge",- "version": "0.16.3",+ "version": "0.16.4", "private": true, "description": "Native-browser bridge for Bridge (ab): layer 1 (nb) plus layer 2 via nbe, the Adom Native Browser Extension (Chrome + Edge).", "main": "server.js",
package.json+1−1@@ -1,6 +1,6 @@ { "slug": "nb-bridge",- "version": "0.16.3",+ "version": "0.16.4", "type": "app", "title": "NB - Native Browser Bridge", "description": "This package installs the SKILLS into your container so your AI knows how to drive your real signed-in Chrome and Edge; Bridge loads the bridge runtime itself from the release zip.",