Merge origin/main (v1.64.0.0) into garrytan/time-attack-fork-review

Both waves fixed several of the same bugs; resolutions keep whichever
shape this branch's tests pin (#2018 jq bind, #1798 set-- pattern,
stop-ack, lock errors, polyfill windowsHide) and take main's richer
codex Step 2A (it absorbed the same mktemp fix). True unions: memory-
ingest keeps main's capability-probed --include-gitignored inside our
GIT_CEILING defense; setup wraps main's Playwright platform override in
our stale-healing install lock; package.json takes main's diff@^9 and
the combined test glob (design/test + ios-qa/daemon/test, 30s timeout).
Generated SKILL.md files regenerated from resolved templates, never
hand-picked. Ship goldens refreshed; parity/carve budgets re-measured
for the summed preamble growth of both waves (itemized per entry).
This commit is contained in:
Garry Tan
2026-08-15 09:57:34 -07:00
241 changed files with 7683 additions and 4716 deletions
+35
View File
@@ -59,6 +59,41 @@ describe("findExecutable", () => {
const found = findExecutable("/nonexistent/path/to/nothing");
expect(found).toBeNull();
});
// access(X_OK) is TRUE for directories — they carry the execute/traverse bit — so a
// bare X_OK test returned ~/.claude/skills/browse, the skill's docs folder, as "the
// browse binary". Every browse call then failed with an empty error, which surfaced
// as make-pdf reporting "Chromium failed to launch".
test("rejects a DIRECTORY even though it passes access(X_OK)", () => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "mkpdf-dir-"));
try {
// Prove the precondition: the directory really does pass the old test.
let passesXok = true;
try {
fs.accessSync(dir, fs.constants.X_OK);
} catch {
passesXok = false;
}
expect(passesXok).toBe(true);
expect(findExecutable(dir)).toBeNull();
} finally {
fs.rmSync(dir, { recursive: true, force: true });
}
});
test("rejects a directory that shadows a real binary name", () => {
// The exact shape of the bug: a directory named like the thing being looked for.
const base = fs.mkdtempSync(path.join(os.tmpdir(), "mkpdf-shadow-"));
const shadow = path.join(base, "browse");
fs.mkdirSync(shadow);
fs.writeFileSync(path.join(shadow, "SKILL.md"), "# not a binary\n");
try {
expect(findExecutable(shadow)).toBeNull();
} finally {
fs.rmSync(base, { recursive: true, force: true });
}
});
});
describe("resolveBrowseBin", () => {
+70
View File
@@ -56,6 +56,34 @@ describe("smartypants", () => {
expect(out).toContain("\u201cdetails\u201d");
});
// A URL flush against a following tag (no whitespace between) used to let
// URL_RE's \S+ swallow the placeholder standing in for that tag. The
// placeholder never restored, so the tag vanished and its styling bled
// into the rest of the document. The test above misses this because its
// URL is followed by a space.
test("does not leak placeholders for a bare autolinked URL", () => {
const input = `<p>see <a href="https://ex.com">https://ex.com</a> ok</p>`;
const out = smartypants(input);
expect(out).not.toContain("SMARTPANTS_PRESERVED");
expect(out).toContain("</a>");
expect(out).toBe(input);
});
test("does not leak placeholders for a bold URL", () => {
const input = `<p>see <strong><a href="https://ex.com">https://ex.com</a></strong> ok</p>`;
const out = smartypants(input);
expect(out).not.toContain("SMARTPANTS_PRESERVED");
expect(out).toContain("</a></strong>");
expect(out).toBe(input);
});
test("does not leak placeholders when a URL is followed by punctuation", () => {
const input = `<p>see <a href="https://ex.com">https://ex.com</a>, ok</p>`;
const out = smartypants(input);
expect(out).not.toContain("SMARTPANTS_PRESERVED");
expect(out).toContain("</a>");
});
test("does NOT touch HTML attribute values", () => {
const out = smartypants(`<a href="it's-a-test.html">link</a>`);
expect(out).toContain(`href="it's-a-test.html"`);
@@ -249,6 +277,48 @@ describe("render (end-to-end)", () => {
expect(result.printCss).toContain("Hiragino Kaku Gothic");
expect(result.printCss).toContain("Noto Sans CJK");
});
// ─── blank-first-page regression (#1904) ────────────────────────
// Any content before the first <h1> used to become a standalone preamble
// .chapter. That section takes the `:first-of-type { break-before: auto }`
// exception, so the first real chapter inherits `break-before: page` and
// starts on page 2 — leaving a blank/near-blank page 1.
test("a leading <style> preamble does not get its own chapter (no blank page 1)", () => {
const result = render({ markdown: `<style>h1{color:#000}</style>\n\n# Hello\n\nBody.\n` });
const chapters = result.html.match(/class="chapter"/g) ?? [];
// One chapter, not two — the invisible <style> no longer forces a page break.
expect(chapters.length).toBe(1);
// ...and the style is preserved (folded into the first chapter, not dropped).
expect(result.html).toContain("<style>h1{color:#000}</style>");
expect(result.html).toMatch(/<section class="chapter"><style>[\s\S]*?<\/style>[\s\S]*?<h1/);
});
test("leading YAML frontmatter is stripped, not rendered as body text", () => {
const result = render({
markdown: `---\ntitle: My Doc\ntype: memo\ntags: [a, b]\n---\n\n# Hello\n\nBody.\n`,
});
// Frontmatter keys must not leak into the rendered body.
expect(result.html).not.toContain("type: memo");
expect(result.html).not.toContain("tags: [a, b]");
// No preamble chapter -> single chapter, first H1 on page 1.
const chapters = result.html.match(/class="chapter"/g) ?? [];
expect(chapters.length).toBe(1);
expect(result.meta.title).toBe("Hello");
});
test("a real text preamble still gets its own chapter (unchanged behavior)", () => {
const result = render({ markdown: `Intro paragraph.\n\n# Hello\n\nBody.\n` });
const chapters = result.html.match(/class="chapter"/g) ?? [];
expect(chapters.length).toBe(2);
});
test("a `---` thematic break that is not frontmatter is left intact", () => {
// Opening with visible text means the later `---` is a real <hr>, not frontmatter.
const result = render({ markdown: `# Hello\n\nBefore.\n\n---\n\nAfter.\n` });
expect(result.html).toContain("<hr>");
expect(result.html).toContain("After.");
});
});
// ─── print-css ──────────────────────────────────────────────