mirror of
https://github.com/garrytan/gstack.git
synced 2026-05-21 12:18:24 +08:00
Merge origin/main into garrytan/prompt-injection-guard
Main landed v1.4.0.0 with /make-pdf (PR #1086), so this branch bumps to v1.5.0.0 and keeps main's entry intact below. Conflicts resolved: - CHANGELOG.md: both branches used v1.4.0.0 — renumbered this branch to v1.5.0.0, kept main's v1.4.0.0 entry directly below. - test/skill-validation.test.ts: both branches fixed the same set of failing tests. Took main's more conservative assertions (check for "Code paths:" / "User flows:" summary labels instead of the older "CODE PATHS" / "USER FLOWS" header strings). ALLOWED_SUBSTEPS stays the same on both sides. - bun.lock: kept both new deps (matcher from this branch, marked from main's /make-pdf). Verified via bun install. - scripts/resolvers/preamble/generate-preamble-bash.ts: both branches added _EXPLAIN_LEVEL + _QUESTION_TUNING echoes. Kept main's version (which has value validation) and removed the duplicate block my branch added. Regenerated all SKILL.md files. - Golden fixtures refreshed after regen. VERSION: 1.4.0.0 → 1.5.0.0. package.json synced. All tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
86
browse/test/pdf-flags.test.ts
Normal file
86
browse/test/pdf-flags.test.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* $B pdf flag contract tests.
|
||||
*
|
||||
* Pure unit tests of the parsing/validation logic. These do NOT spin up
|
||||
* Chromium — that's covered by make-pdf's integration tests.
|
||||
*/
|
||||
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
import * as os from "node:os";
|
||||
|
||||
import { extractTabId } from "../src/cli";
|
||||
|
||||
// We can't import the internal parsePdfArgs directly without exporting it,
|
||||
// but we can exercise it end-to-end through the browse CLI. For fast unit
|
||||
// coverage we test the flag-extraction layer here.
|
||||
|
||||
describe("extractTabId", () => {
|
||||
test("strips --tab-id and returns the value", () => {
|
||||
const { tabId, args } = extractTabId(["--tab-id", "3", "extra"]);
|
||||
expect(tabId).toBe(3);
|
||||
expect(args).toEqual(["extra"]);
|
||||
});
|
||||
|
||||
test("returns undefined when flag is absent", () => {
|
||||
const { tabId, args } = extractTabId(["goto", "https://example.com"]);
|
||||
expect(tabId).toBeUndefined();
|
||||
expect(args).toEqual(["goto", "https://example.com"]);
|
||||
});
|
||||
|
||||
test("ignores trailing --tab-id with no value", () => {
|
||||
const { tabId, args } = extractTabId(["click", "@e1", "--tab-id"]);
|
||||
expect(tabId).toBeUndefined();
|
||||
expect(args).toEqual(["click", "@e1"]);
|
||||
});
|
||||
|
||||
test("handles --tab-id at different positions", () => {
|
||||
const front = extractTabId(["--tab-id", "5", "pdf", "/tmp/out.pdf"]);
|
||||
expect(front.tabId).toBe(5);
|
||||
expect(front.args).toEqual(["pdf", "/tmp/out.pdf"]);
|
||||
|
||||
const middle = extractTabId(["pdf", "--tab-id", "7", "/tmp/out.pdf"]);
|
||||
expect(middle.tabId).toBe(7);
|
||||
expect(middle.args).toEqual(["pdf", "/tmp/out.pdf"]);
|
||||
|
||||
const end = extractTabId(["pdf", "/tmp/out.pdf", "--tab-id", "9"]);
|
||||
expect(end.tabId).toBe(9);
|
||||
expect(end.args).toEqual(["pdf", "/tmp/out.pdf"]);
|
||||
});
|
||||
|
||||
test("ignores non-numeric --tab-id values", () => {
|
||||
const { tabId, args } = extractTabId(["--tab-id", "abc", "pdf"]);
|
||||
expect(tabId).toBeUndefined();
|
||||
expect(args).toEqual(["pdf"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("pdf --from-file payload shape", () => {
|
||||
test("writes a JSON payload file and reads it back", () => {
|
||||
const tmpPath = path.join(os.tmpdir(), `browse-pdf-test-${Date.now()}.json`);
|
||||
const payload = {
|
||||
output: "/tmp/browse-out.pdf",
|
||||
format: "letter",
|
||||
marginTop: "1in",
|
||||
marginRight: "1in",
|
||||
marginBottom: "1in",
|
||||
marginLeft: "1in",
|
||||
pageNumbers: true,
|
||||
tagged: true,
|
||||
outline: true,
|
||||
toc: false,
|
||||
headerTemplate: '<div style="font-size:9pt">Title</div>',
|
||||
footerTemplate: undefined,
|
||||
};
|
||||
fs.writeFileSync(tmpPath, JSON.stringify(payload));
|
||||
try {
|
||||
const readBack = JSON.parse(fs.readFileSync(tmpPath, "utf8"));
|
||||
expect(readBack.output).toBe("/tmp/browse-out.pdf");
|
||||
expect(readBack.pageNumbers).toBe(true);
|
||||
expect(readBack.headerTemplate).toContain("Title");
|
||||
} finally {
|
||||
fs.unlinkSync(tmpPath);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -501,8 +501,12 @@ describe('BROWSE_TAB tab pinning (cross-tab isolation)', () => {
|
||||
});
|
||||
|
||||
test('CLI reads BROWSE_TAB and sends tabId in command body', () => {
|
||||
// BROWSE_TAB env var is still honored (sidebar-agent path). After the
|
||||
// make-pdf refactor, the CLI layer now also accepts --tab-id <N>, with
|
||||
// the CLI flag taking precedence over the env var. Both resolve to the
|
||||
// same `tabId` body field.
|
||||
expect(cliSrc).toContain('process.env.BROWSE_TAB');
|
||||
expect(cliSrc).toContain('tabId: parseInt(browseTab');
|
||||
expect(cliSrc).toContain('parseInt(envTab, 10)');
|
||||
});
|
||||
|
||||
test('handleCommandInternal accepts tabId from request body', () => {
|
||||
@@ -548,8 +552,11 @@ describe('BROWSE_TAB tab pinning (cross-tab isolation)', () => {
|
||||
expect(handleFn).toContain('tabId !== null');
|
||||
});
|
||||
|
||||
test('CLI only sends tabId when BROWSE_TAB is set', () => {
|
||||
// Should conditionally include tabId in the body
|
||||
expect(cliSrc).toContain('browseTab ? { tabId:');
|
||||
test('CLI only sends tabId when it is a valid number', () => {
|
||||
// Body should conditionally include tabId. Historically that was keyed off
|
||||
// the BROWSE_TAB env var. After the make-pdf refactor, the CLI also honors
|
||||
// a --tab-id <N> flag on the CLI itself, so the check is "tabId defined
|
||||
// AND not NaN" rather than literally inspecting the env var.
|
||||
expect(cliSrc).toContain('tabId !== undefined && !isNaN(tabId)');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user