mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-01 14:34:42 +01:00
v1.92.19.0 Skip the Aside probe off macOS so Linux and Windows render through gstack's own browser (#2864) (#3734)
* aside-render: probeAside answers NEEDS_ASIDE off macOS without spawning (#2864) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix: pre-landing review fixes Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix: off-macOS probe detail no longer claims gstack's browser is in use Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --------- Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
93d73bf755
commit
dcc1c51bfc
7 files changed
+50
-9
No files matched your search
@@ -1,5 +1,14 @@
|
||||
# Changelog
|
||||
|
||||
## [1.92.19.0] - 2026-11-01
|
||||
|
||||
**On Linux and Windows the renderer goes straight to gstack's own browser instead of asking for Aside (#2864).** `probeAside()` in `lib/aside-render.ts`, used by /make-pdf, /diagram and `gstack-render`, used to run `aside --version` on any platform. When that failed it told the user to install a browser that only ships for macOS. Off macOS it now answers `NEEDS_ASIDE` with "Aside is macOS-only (this is linux)", without starting a process, and the renderer moves on to gstack's own browser. macOS behavior and `GSTACK_SKIP_ASIDE=1` are unchanged.
|
||||
|
||||
### Changed
|
||||
- **`probeAside(timeoutMs, platform)`** takes the platform, which defaults to `process.platform`. The fake-CLI probe tests pass `darwin`, so they still run on Linux CI.
|
||||
|
||||
Thanks to @furkankoykiran for the report. The bash readiness block inside browsing skills already prints `NEEDS_ASIDE: Linux` and is unchanged.
|
||||
|
||||
## [1.92.18.0] - 2026-11-01
|
||||
|
||||
- `install.sh --project` (through `gstack-capy-install`) resolves the directory it names to its git toplevel, which is where pregate admission looks for the install verdict. `--project <repo>/<subdir>` now writes, and reads pins from, the same place as `--project <repo>`, so a Bun pin declared only in a subpackage no longer applies. A value that isn't a directory, such as a repo slug or a directory this shell can't enter, is a usage error that asks for the checkout's path, and it stops before anything is cloned or installed. Before this change, a slug or a subdirectory keyed the verdict somewhere admission never looks, so a later pregate admission check read a stale verdict (GST-743).
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# gstack digest v1.92.18.0 — regenerate/re-copy after upgrading gstack
|
||||
# gstack digest v1.92.19.0 — regenerate/re-copy after upgrading gstack
|
||||
|
||||
Behavioral rules from gstack (https://github.com/garrytan/gstack), compressed
|
||||
for agent hosts without a full skill install. The full skills add workflows,
|
||||
|
||||
+5
-2
@@ -76,11 +76,14 @@ export type AsideProbe =
|
||||
| { ok: true; version: string }
|
||||
| { ok: false; reason: 'NEEDS_ASIDE' | 'ASIDE_NOT_RUNNING'; detail: string };
|
||||
|
||||
/** Same probe the skills run in BROWSER SETUP: binary present, app answering. */
|
||||
export function probeAside(timeoutMs = 30_000): AsideProbe {
|
||||
/** Same probe the skills run in BROWSER SETUP: binary present, app answering. Aside ships only for macOS, so any other platform answers NEEDS_ASIDE without spawning. */
|
||||
export function probeAside(timeoutMs = 30_000, platform: NodeJS.Platform = process.platform): AsideProbe {
|
||||
if (process.env.GSTACK_SKIP_ASIDE === '1') {
|
||||
return { ok: false, reason: 'NEEDS_ASIDE', detail: 'GSTACK_SKIP_ASIDE=1 — Aside skipped by request' };
|
||||
}
|
||||
if (platform !== 'darwin') {
|
||||
return { ok: false, reason: 'NEEDS_ASIDE', detail: `Aside is macOS-only (this is ${platform})` };
|
||||
}
|
||||
const which = spawnSync('aside', ['--version'], { encoding: 'utf8', timeout: 10_000 });
|
||||
if (which.error) {
|
||||
return { ok: false, reason: 'NEEDS_ASIDE', detail: 'the `aside` CLI is not on PATH — install the Aside browser (macOS 15+) from aside.com' };
|
||||
|
||||
@@ -36,6 +36,7 @@ const ROOT = path.resolve(import.meta.dir, "..", "..");
|
||||
const CLI = path.join(ROOT, "make-pdf", "src", "cli.ts");
|
||||
const TYPES = path.join(ROOT, "make-pdf", "src", "types.ts");
|
||||
const isWin = process.platform === "win32";
|
||||
const isMac = process.platform === "darwin";
|
||||
|
||||
let tmp: string;
|
||||
/** PATH for children: nothing on it (no `aside`, no `browse`, no `pdftotext`). */
|
||||
@@ -316,7 +317,7 @@ describe.skipIf(isWin)("cli.ts through fake browsers (GSTACK_BROWSE_BIN + a scru
|
||||
expect(fs.existsSync(out)).toBe(false);
|
||||
});
|
||||
|
||||
test("Aside answers the probe but cannot run the script: the PDF comes from gstack's browser, stderr says so, exit 0", () => {
|
||||
test.skipIf(!isMac)("Aside answers the probe but cannot run the script: the PDF comes from gstack's browser, stderr says so, exit 0", () => {
|
||||
const out = path.join(tmp, "mid-run", "out.pdf");
|
||||
const r = runCli(["generate", inputMd, out, "--quiet"], {
|
||||
env: childEnv({ PATH: fakeAsideBin, GSTACK_SKIP_ASIDE: undefined, GSTACK_BROWSE_BIN: browseOk }),
|
||||
@@ -326,4 +327,15 @@ describe.skipIf(isWin)("cli.ts through fake browsers (GSTACK_BROWSE_BIN + a scru
|
||||
expect(r.stderr).toContain("Aside was unavailable mid-run; the PDF was rendered through gstack's own browser.");
|
||||
expect(fs.readFileSync(out, "utf8")).toBe("%PDF-1.4 fake\n");
|
||||
});
|
||||
|
||||
test.skipIf(isMac)("off macOS an `aside` on PATH is never asked: the PDF comes straight from gstack's browser, --quiet keeps stderr empty, exit 0 (#2864)", () => {
|
||||
const out = path.join(tmp, "off-mac", "out.pdf");
|
||||
const r = runCli(["generate", inputMd, out, "--quiet"], {
|
||||
env: childEnv({ PATH: fakeAsideBin, GSTACK_SKIP_ASIDE: undefined, GSTACK_BROWSE_BIN: browseOk }),
|
||||
});
|
||||
expect(r.code).toBe(ExitCode.Success);
|
||||
expect(r.stdout).toBe(`${out}\n`);
|
||||
expect(r.stderr).toBe("");
|
||||
expect(fs.readFileSync(out, "utf8")).toBe("%PDF-1.4 fake\n");
|
||||
});
|
||||
});
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "gstack",
|
||||
"version": "1.92.18",
|
||||
"version": "1.92.19",
|
||||
"description": "Garry's Stack — Claude Code skills + fast headless browser. One repo, one install, entire AI engineering workflow.",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
|
||||
@@ -350,7 +350,7 @@ function writeDriver(dir: string): string {
|
||||
fs.writeFileSync(driver, `const M = await import(${JSON.stringify(LIB)});
|
||||
const job = JSON.parse(process.argv[2]);
|
||||
let out;
|
||||
if (job.fn === 'probeAside') out = M.probeAside(job.timeoutMs);
|
||||
if (job.fn === 'probeAside') out = M.probeAside(job.timeoutMs, job.platform);
|
||||
else if (job.fn === 'renderWithAside') out = await M.renderWithAside(job.spec);
|
||||
else if (job.fn === 'render') {
|
||||
if (job.primeAside) M.pickEngine(true, { probe: () => ({ ok: true, version: 'fake-aside' }) });
|
||||
@@ -383,9 +383,9 @@ describe.skipIf(!HERMETIC)('aside-render: probeAside classifies a fake CLI the w
|
||||
let driver: string;
|
||||
beforeAll(() => { fs.mkdirSync(bin); driver = writeDriver(tmp); });
|
||||
afterAll(() => fs.rmSync(tmp, { recursive: true, force: true }));
|
||||
const probe = (env?: Record<string, string>): AsideProbe => {
|
||||
const probe = (env?: Record<string, string>, platform = 'darwin'): AsideProbe => {
|
||||
fs.rmSync(log, { force: true });
|
||||
return runDriver<AsideProbe>(driver, { fn: 'probeAside', timeoutMs: 5_000 }, { binDir: bin, env });
|
||||
return runDriver<AsideProbe>(driver, { fn: 'probeAside', timeoutMs: 5_000, platform }, { binDir: bin, env });
|
||||
};
|
||||
|
||||
test('no `aside` on PATH → NEEDS_ASIDE (install it), never "not running"', () => {
|
||||
@@ -442,6 +442,23 @@ describe.skipIf(!HERMETIC)('aside-render: probeAside classifies a fake CLI the w
|
||||
expect(r.detail).toContain('GSTACK_SKIP_ASIDE=1');
|
||||
expect(fs.existsSync(log)).toBe(false);
|
||||
});
|
||||
|
||||
test.each(['linux', 'win32'])('on %s → NEEDS_ASIDE naming the platform, and the CLI is never invoked, even when one is on PATH (#2864)', platform => {
|
||||
writeFakeAside(bin, { repl: 'echo "ASIDE_READY /x"', log });
|
||||
const r = probe(undefined, platform);
|
||||
expect(r.ok).toBe(false);
|
||||
if (r.ok) return;
|
||||
expect(r.reason).toBe('NEEDS_ASIDE');
|
||||
expect(r.detail).toBe(`Aside is macOS-only (this is ${platform})`);
|
||||
expect(fs.existsSync(log)).toBe(false);
|
||||
});
|
||||
|
||||
test('GSTACK_SKIP_ASIDE=1 keeps precedence over the platform check', () => {
|
||||
const r = probe({ GSTACK_SKIP_ASIDE: '1' }, 'linux');
|
||||
expect(r.ok).toBe(false);
|
||||
if (r.ok) return;
|
||||
expect(r.detail).toContain('GSTACK_SKIP_ASIDE=1');
|
||||
});
|
||||
});
|
||||
|
||||
describe.skipIf(!HERMETIC)('aside-render: serveDir — loopback server contract (nonce, containment, no listings)', () => {
|
||||
|
||||
Reference in new issue
Block a user