Skip to content

[Bug]: npm test cannot pass on a Windows checkout of 2.0.0-beta-dev (api-docs gate blocks, then 3 tests fail) #312

Description

@Hotragn

Affected component

Build, CI, or tooling

What happened?

npm test cannot pass on a fresh Windows clone of 2.0.0-beta-dev (a25f488). It stops at the second gate, and once that is unblocked three tests fail. None of the causes are in product code — they are line-ending, symlink, and platform assumptions inside the repo's own checks — so the Linux CI runner cannot see any of them and they only ever hit contributors.

Environment: Windows 11, Node 24, default Git for Windows settings (core.autocrlf=true, core.symlinks=false).

npm test
-> Error: skills/ego-browser/references/api.md is stale; run npm run generate:api-docs

That message is a dead end: the file is not stale. Regenerating rewrites byte-identical content, git diff stays empty, and the next checkout restores CRLF.

After working around that gate, the suite runs and 3 tests fail deterministically:

330 tests, 327 pass, 3 fail
  ✖ project Agent and Codex entries share the canonical Skill
      EINVAL: invalid argument, readlink '...\.agents\skills\ego-browser'
  ✖ the direct CLI prints an ordinary uncaught error once
      Expected values to be strictly equal: undefined !== 1
  ✖ Page keyboard press and type use the addressed target session
      Meta+A must retain the native selectAll editing command

Root causes

1. scripts/generate-api-reference.mjs--check compares representation, not content

It compares the generated markdown (always LF, written via writeFile(..., "utf8")) against the working-copy file with !==. Git for Windows checks api.md out as CRLF — measured on this branch: 96 CRLF, 0 bare LF — so the strings differ while the content is identical.

2. scripts/check-skill-translation.mjs — same defect, one step later (currently dormant)

It sha256s the raw bytes of SKILL.md, so a CRLF checkout digests differently from the LF digest recorded in the translation. Measured on this branch: worktree 7109fd54… vs LF-normalized cc00450d…. This gate exits 0 early today because skills/ego-browser/workbench/SKILL.zh.v2.md is not on the branch, so it is latent rather than live — it breaks the moment that file lands.

3. src/skill-package.test.mjsreadlink() on a non-symlink

Git for Windows materializes .agents/skills/ego-browser and .codex/skills/ego-browser as regular files containing the target path (core.symlinks=false is the default without Developer Mode), and readlink() then throws EINVAL.

4. src/run-output-sink.test.mjsURL.pathname is not a filesystem path

The spawned entry path comes from URL.pathname, which keeps percent-encoding and the leading slash of a Windows drive path, so spawnSync never launches the bundle (status: undefined, hence undefined !== 1). Note this one is not Windows-only: pathname percent-encodes spaces, so the test also fails on macOS or Linux in any checkout whose path contains a space.

5. src/page-model.test.mjs — a test inherits the host platform

"Page keyboard press and type use the addressed target session" asserts Meta+A yields the native selectAll command and modifiers === 4. editingCommandsForKey() deliberately emits that only when the platform is darwin, and this test does not pin the platform, so it fails off macOS. The source is correct here — roughly ten sibling tests in the same file already pass { platform: "darwin" } through the existing taskForRound seam; this one just omits it.

Also observed (not part of the above)

  • npm run style:check reports 112 files on a Windows checkout, because Prettier's default endOfLine: "lf" flags every CRLF file. The natural fix is a repo-wide .gitattributes, which is what fix(ego-browser): make the repo build, test, and commit on Windows #148 already proposes for the dev line — I have deliberately not duplicated that.
  • Two delayed-popup tests are flaky, independent of platform: background target discovery adopts a delayed popup and reports its opener and using a delayed popup suppresses its notice before round output. Three identical runs of just those two gave fail/fail, fail/fail, pass/pass. waitForLedgerTarget() budgets 50 attempts × 2 ms rather than a wall-clock deadline, which is my guess at the cause. Happy to open that separately if useful.

Fix

I have the fix ready and verified — 38 lines across 5 files, no product code, no .gitattributes:

https://github.com/Hotragn/ego-lite/tree/beta/api-docs-crlf (branched from a25f488)

  • both check scripts compare content with line endings normalized;
  • the symlink test reads whichever form the checkout produced, so it still proves the entry points at ../../skills/ego-browser;
  • the CLI test uses fileURLToPath();
  • the keyboard test pins { platform: "darwin" } using the file's own existing seam.

Result on Windows: 330 tests, 328 pass, 2 fail, the 2 being only the pre-existing popup flake above. Linux behavior is unchanged by construction — on an LF checkout the normalization is a no-op, lstat().isSymbolicLink() still takes the readlink branch, fileURLToPath() returns what pathname did for space-free paths, and the keyboard test now pins the platform it was already assuming.

I could not open a PR for this: 2.0.0-beta-dev rejects pull requests from forks (CreatePullRequest is refused for that base, while the same account opens PRs against dev normally), and these files exist on no other branch. Tell me where you would like it and I will send it there, or cherry-pick the branch directly — whichever is less work for you.

Before submitting

  • I searched the existing issues and did not find a duplicate.
  • I removed secrets and sensitive data.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions