agent-yes 1.195.0 → 1.196.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lab/ui/sw.js CHANGED
@@ -21,7 +21,7 @@ async function pickClient() {
21
21
  return all.find((c) => !new URL(c.url).pathname.startsWith(BASE + "p/")) || all[0] || null;
22
22
  }
23
23
 
24
- async function proxyPreview(request, src, port, rest) {
24
+ async function proxyPreview(request, src, port, rest, allowInject) {
25
25
  const client = await pickClient();
26
26
  if (!client) return new Response("open the agent-yes console to preview", { status: 502 });
27
27
  const headers = {};
@@ -35,23 +35,40 @@ async function proxyPreview(request, src, port, rest) {
35
35
  let resolved = false;
36
36
  mc.port1.onmessage = (ev) => {
37
37
  const msg = ev.data;
38
- if (msg.type === "head") {
39
- const stream = new ReadableStream({
40
- start(controller) {
41
- mc.port1.onmessage = (e2) => {
42
- const m2 = e2.data;
43
- if (m2.type === "body") controller.enqueue(new Uint8Array(m2.chunk));
44
- else if (m2.type === "end") controller.close();
45
- else if (m2.type === "error") controller.error(new Error(m2.message));
46
- };
47
- },
48
- });
49
- resolved = true;
50
- resolve(new Response(stream, { status: msg.status, statusText: msg.statusText, headers: msg.headers }));
51
- } else if (msg.type === "error" && !resolved) {
52
- resolved = true;
53
- resolve(new Response("preview tunnel error: " + msg.message, { status: 502 }));
38
+ if (msg.type !== "head") {
39
+ if (msg.type === "error" && !resolved) {
40
+ resolved = true;
41
+ resolve(new Response("preview tunnel error: " + msg.message, { status: 502 }));
42
+ }
43
+ return;
54
44
  }
45
+ resolved = true;
46
+ const headers = new Headers(msg.headers);
47
+ const ct = headers.get("content-type") || "";
48
+ // HTML document navigations (the /p/ path itself, not app subresources):
49
+ // buffer, strip CSP, and inject a window.WebSocket shim so the app's own
50
+ // sockets (Vite HMR) also ride the P2P tunnel. Everything else streams.
51
+ if (allowInject && ct.includes("text/html")) {
52
+ const chunks = [];
53
+ mc.port1.onmessage = (e2) => {
54
+ const m2 = e2.data;
55
+ if (m2.type === "body") chunks.push(new Uint8Array(m2.chunk));
56
+ else if (m2.type === "end") resolve(injectBootstrap(chunks, msg, headers, src, Number(port)));
57
+ else if (m2.type === "error") resolve(new Response("preview error: " + m2.message, { status: 502 }));
58
+ };
59
+ return;
60
+ }
61
+ const stream = new ReadableStream({
62
+ start(controller) {
63
+ mc.port1.onmessage = (e2) => {
64
+ const m2 = e2.data;
65
+ if (m2.type === "body") controller.enqueue(new Uint8Array(m2.chunk));
66
+ else if (m2.type === "end") controller.close();
67
+ else if (m2.type === "error") controller.error(new Error(m2.message));
68
+ };
69
+ },
70
+ });
71
+ resolve(new Response(stream, { status: msg.status, statusText: msg.statusText, headers }));
55
72
  };
56
73
  client.postMessage(
57
74
  { type: "ay-preview-fetch", src, port: Number(port), method: request.method, path: rest, headers, body },
@@ -60,6 +77,37 @@ async function proxyPreview(request, src, port, rest) {
60
77
  });
61
78
  }
62
79
 
80
+ // Concatenate the buffered HTML chunks, strip CSP, and inject a bootstrap
81
+ // <script> that replaces window.WebSocket with the parent console's tunneled
82
+ // shim — so a dev server's own sockets (Vite HMR) ride the P2P tunnel too. Runs
83
+ // first (right after <head>) so the override is in place before app scripts.
84
+ function injectBootstrap(chunks, msg, headers, src, port) {
85
+ let total = 0;
86
+ for (const c of chunks) total += c.byteLength;
87
+ const all = new Uint8Array(total);
88
+ let off = 0;
89
+ for (const c of chunks) {
90
+ all.set(c, off);
91
+ off += c.byteLength;
92
+ }
93
+ const raw = new TextDecoder().decode(all);
94
+ const boot =
95
+ "<script>(function(){try{var mk=window.parent&&window.parent.__ayMakeWS;" +
96
+ "if(mk)window.WebSocket=mk(" +
97
+ JSON.stringify(src) +
98
+ "," +
99
+ JSON.stringify(port) +
100
+ ");}catch(e){}})();</" +
101
+ "script>";
102
+ const html = /<head[^>]*>/i.test(raw)
103
+ ? raw.replace(/<head[^>]*>/i, (m) => m + boot)
104
+ : boot + raw;
105
+ headers.delete("content-security-policy");
106
+ headers.delete("content-security-policy-report-only");
107
+ headers.delete("content-length");
108
+ return new Response(html, { status: msg.status, statusText: msg.statusText, headers });
109
+ }
110
+
63
111
  const SHELL = [
64
112
  "./",
65
113
  "./index.html",
@@ -98,7 +146,9 @@ self.addEventListener("fetch", (e) => {
98
146
  const own = PREVIEW.exec(url.pathname);
99
147
  if (own) {
100
148
  const rest = (own[3] || "/") + url.search;
101
- e.respondWith(proxyPreview(req, decodeURIComponent(own[1]), own[2], rest));
149
+ // Navigations to the /p/ root/route may be an HTML doc → allow WS-shim
150
+ // injection; app subresources (below) never inject.
151
+ e.respondWith(proxyPreview(req, decodeURIComponent(own[1]), own[2], rest, true));
102
152
  return;
103
153
  }
104
154
  e.respondWith(maybePreviewFromClient(e, req, url));
@@ -112,7 +162,9 @@ async function maybePreviewFromClient(e, req, url) {
112
162
  const client = await self.clients.get(clientId).catch(() => null);
113
163
  const cm = client && PREVIEW.exec(new URL(client.url).pathname);
114
164
  if (cm) {
115
- return proxyPreview(req, decodeURIComponent(cm[1]), cm[2], url.pathname + url.search);
165
+ // Subresources (Vite's /@vite/client, module chunks, etc.) never get the
166
+ // WS shim injected — only the top-level /p/ navigation does.
167
+ return proxyPreview(req, decodeURIComponent(cm[1]), cm[2], url.pathname + url.search, false);
116
168
  }
117
169
  }
118
170
  return shellFetch(req, url);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-yes",
3
- "version": "1.195.0",
3
+ "version": "1.196.1",
4
4
  "description": "A wrapper tool that automates interactions with various AI CLI tools by automatically handling common prompts and responses.",
5
5
  "keywords": [
6
6
  "ai",
package/ts/serve.spec.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { readFile } from "fs/promises";
2
2
  import { describe, expect, it } from "vitest";
3
- import { isNoNodeExecError, oxmgrVersionHasWindowsFix } from "./serve.ts";
3
+ import { installerArgv, isNoNodeExecError, oxmgrVersionHasWindowsFix } from "./serve.ts";
4
4
 
5
5
  // Guards the Windows daemon-manager selection: on Windows we only PREFER oxmgr
6
6
  // when the installed build carries the daemon-socket-inheritance fix. Stock
@@ -90,3 +90,31 @@ describe("manager spawns pass a live env snapshot", () => {
90
90
  }
91
91
  });
92
92
  });
93
+
94
+ // Guards the oxmgr bootstrap: bun blocks untrusted postinstalls, and oxmgr's
95
+ // native binary only arrives via its postinstall — without --trust the install
96
+ // "succeeds" but leaves a launcher that dies with "oxmgr binary is missing"
97
+ // (the real reason bootstrap used to fall back to pm2 on fresh boxes).
98
+ describe("installerArgv", () => {
99
+ it("trusts oxmgr's postinstall under bun", () => {
100
+ expect(installerArgv("oxmgr", "/x/bun", null)).toEqual([
101
+ "/x/bun",
102
+ "add",
103
+ "-g",
104
+ "--trust",
105
+ "oxmgr",
106
+ ]);
107
+ });
108
+
109
+ it("keeps pm2 untrusted under bun (pure JS, no required scripts)", () => {
110
+ expect(installerArgv("pm2", "/x/bun", "/x/npm")).toEqual(["/x/bun", "add", "-g", "pm2"]);
111
+ });
112
+
113
+ it("falls back to npm without a trust flag (npm runs scripts by default)", () => {
114
+ expect(installerArgv("oxmgr", null, "/x/npm")).toEqual(["/x/npm", "install", "-g", "oxmgr"]);
115
+ });
116
+
117
+ it("returns null with neither installer", () => {
118
+ expect(installerArgv("pm2", null, null)).toBeNull();
119
+ });
120
+ });
package/ts/serve.ts CHANGED
@@ -471,16 +471,37 @@ async function resolveActiveManager(): Promise<DaemonManager | null> {
471
471
  return firstRunnable ?? resolveDaemonManager();
472
472
  }
473
473
 
474
+ // The install command for one PM package. oxmgr gets `--trust` under bun: its
475
+ // native binary arrives via the package's postinstall (scripts/install.js
476
+ // downloads the platform build), and bun BLOCKS lifecycle scripts of untrusted
477
+ // packages by default — which leaves a JS launcher that dies with "oxmgr binary
478
+ // is missing" and was the real reason bootstrap kept falling back to pm2 on
479
+ // fresh boxes. Re-adding with --trust also heals such a blocked install. pm2 is
480
+ // pure JS with no required scripts, so it stays untrusted. npm runs lifecycle
481
+ // scripts by default — no flag needed.
482
+ export function installerArgv(
483
+ pkg: "oxmgr" | "pm2",
484
+ bun: string | null,
485
+ npm: string | null,
486
+ ): string[] | null {
487
+ if (bun) return [bun, "add", "-g", ...(pkg === "oxmgr" ? ["--trust"] : []), pkg];
488
+ if (npm) return [npm, "install", "-g", pkg];
489
+ return null;
490
+ }
491
+
474
492
  // Install one PM package globally via the SAME JS package manager that installed
475
493
  // `ay` (bun preferred, npm fallback — no Rust toolchain required, so a fresh
476
494
  // Linux box with only bun from setup.sh works), then confirm the resulting
477
495
  // binary actually execs. Returns a runnable manager, or null if the install
478
496
  // failed or the binary can't run here (caller then tries the next candidate).
479
497
  async function installAndVerify(pkg: "oxmgr" | "pm2"): Promise<DaemonManager | null> {
480
- const bun = Bun.which("bun");
481
- const npm = Bun.which("npm");
482
- const installer = bun ? [bun, "add", "-g", pkg] : npm ? [npm, "install", "-g", pkg] : null;
498
+ const installer = installerArgv(pkg, Bun.which("bun"), Bun.which("npm"));
483
499
  if (!installer) return null;
500
+ // The node→bun shim must exist BEFORE the install, not just before the probe:
501
+ // oxmgr's postinstall itself runs `node scripts/install.js` to fetch the
502
+ // native binary, so on a bun-only box a missing shim silently skips the
503
+ // download even when the script is trusted.
504
+ await ensureNodeRuntime();
484
505
  process.stderr.write(`ay serve install: installing ${pkg}…\n`);
485
506
  const code =
486
507
  (await Bun.spawn(installer, {
@@ -1,8 +0,0 @@
1
- import "./ts-DDsICrj-.js";
2
- import "./logger-CDIsZ-Pp.js";
3
- import "./versionChecker-B8qEzYDu.js";
4
- import "./pidStore-BIvsBQ8X.js";
5
- import "./globalPidIndex-CoNr7tS8.js";
6
- import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-Bdj9qDRm.js";
7
-
8
- export { SUPPORTED_CLIS };