Skip to content

Fix/docs format check windows clean#48887

Open
soyames wants to merge 1 commit intoopenclaw:mainfrom
soyames:fix/docs-format-check-windows-clean
Open

Fix/docs format check windows clean#48887
soyames wants to merge 1 commit intoopenclaw:mainfrom
soyames:fix/docs-format-check-windows-clean

Conversation

@soyames
Copy link
Copy Markdown

@soyames soyames commented Mar 17, 2026

Summary

Describe the problem and fix in 2–5 bullets:

  • Problem: pnpm format:docs:check uses git ls-files | xargs oxfmt which fails on Windows — xargs is unavailable and single-quoted globs in cmd.exe are treated as literals, silently matching no files and exiting 0 (false pass).
  • Why it matters: Windows contributors cannot run or pass the docs formatting check locally, blocking PRs and giving misleading CI results on that platform.
  • What changed: Replaced the shell pipeline with scripts/format-docs-check.cjs — a Node.js script using spawnSync with an argument array, bypassing the shell entirely. Updated package.json to invoke it.
  • What did NOT change: Same files checked, same oxfmt --check tool, same exit codes. No runtime code, CI workflow logic, or docs content changed.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor
  • Docs
  • Security hardening
  • [x ] Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • [x ] CI/CD / infra

Linked Issue/PR

User-visible / Behavior Changes

None. Internal dev tooling only — pnpm format:docs:check now works on Windows. No product behavior changes.

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No
  • Data access scope changed?No

Repro + Verification

Environment

  • OS:
  • Runtime/container:
  • Model/provider:
  • Integration/channel (if any):
  • Relevant config (redacted):

Steps

  1. Clone the repo and run pnpm install
  2. On Windows: run pnpm format:docs:check — previously failed with xargs: command not found or silently passed with no files checked
  3. On Unix: run pnpm format:docs:check — continues to pass as before

Expected

  • Exits 0 when docs are correctly formatted on both platforms
  • Exits non-zero and surfaces offending files when formatting is wrong

Actual

  • Both platforms behave identically as expecte

Evidence

Attach at least one:

  • [x ] Failing test/log before + passing after - xargs: command not found on Windows before; clean exit after with correct file list
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios: Ran pnpm format:docs:check on Windows 11 (Git Bash and PowerShell) and Ubuntu 22.04. Confirmed identical output and exit codes. Confirmed pnpm build && pnpm check && pnpm test all pass.
  • Edge cases checked: Clean workspace, intentionally malformatted docs (confirmed non-zero exit), empty match (confirmed graceful exit with message).
  • What you did not verify: Did not test on macOS — the Node.js script has no platform-specific dependencies.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers.

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? No
  • Migration needed? No

Failure Recovery (if this breaks)

  • How to disable/revert: Revert the format:docs:check line in package.json back to git ls-files 'docs//*.md' 'docs//*.mdx' 'README.md' | xargs oxfmt --check and delete scripts/format-docs-check.cjs / .js
  • Files/config to restore: package.json, scripts/format-docs-check.cjs, scripts/format-docs-check.js
  • Known bad symptoms: pnpm format:docs:check silently passes or fails to check any file

Risks and Mitigations

List only real risks for this PR. Add/remove entries as needed. If none, write None.

  • Risk: Node.js script misses files that the git ls-files | xargs pipeline would have caught
    • Mitigation: Script uses the same git ls-files command with the same glob patterns via spawnSync — output is identical. Verified by diffing file lists on both platforms.

Note: developed with assistance from Claude and GitHub Copilot for cross-platform scripting.

@openclaw-barnacle openclaw-barnacle bot added scripts Repository scripts size: S labels Mar 17, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 17, 2026

Greptile Summary

This PR replaces the shell-based format:docs:check script (git ls-files | xargs oxfmt --check) with a Node.js script (scripts/format-docs-check.cjs) to fix Windows incompatibility. The motivation is valid and the .cjs implementation is generally correct.

Key issues found:

  • Broken duplicate file (scripts/format-docs-check.js): This file is an exact copy of the .cjs script but is never referenced in package.json. Because package.json declares "type": "module", Node.js will treat any .js file as an ES module — using require() inside it will immediately throw ReferenceError: require is not defined in ES module scope. This file should be removed.
  • Performance regression (scripts/format-docs-check.cjs): The new implementation spawns a separate oxfmt process for every matched file, whereas the original xargs approach batched all files into a single (or a few) invocations. This can be noticeably slower for repos with many Markdown files. Consider passing all files as arguments to a single spawnSync("oxfmt", ["--check", ...files]) call.
  • Missing spawn-error handling (scripts/format-docs-check.cjs): If oxfmt is not on the PATH, spawnSync sets result.error and leaves result.status as null. The current check (status !== 0) will still set failed = true, but no diagnostic message is printed. Checking result.error explicitly and surfacing its message would greatly improve the developer experience.

Confidence Score: 3/5

  • Safe to merge with caveats — the .cjs script works correctly on all platforms, but the duplicate .js file is broken and should be removed before merging.
  • The active script (format-docs-check.cjs) solves the stated Windows problem and is functionally correct. However, the committed format-docs-check.js file is dead, broken code that will throw a ReferenceError if invoked directly (due to "type": "module"), and there is a performance regression from the per-file spawn loop vs. the original single-invocation approach.
  • scripts/format-docs-check.js — broken duplicate that should be removed; scripts/format-docs-check.cjs — per-file spawn loop warrants review.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: scripts/format-docs-check.js
Line: 1-5

Comment:
**`require()` will throw in an ESM package**

`package.json` declares `"type": "module"`, so Node.js treats all `.js` files as ES modules. Running `node scripts/format-docs-check.js` will immediately throw:

```
ReferenceError: require is not defined in ES module scope
```

The `.cjs` sibling file works correctly because the `.cjs` extension always forces CommonJS mode regardless of `"type"`. This `.js` file is also unreferenced in `package.json`, making it dead code that is broken if anyone tries to invoke it directly. It should either be removed entirely, or — if it is meant as a fallback — converted to ESM (`import { spawnSync } from 'child_process'`, `import fs from 'fs'`).

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: scripts/format-docs-check.cjs
Line: 19-29

Comment:
**Performance regression: N separate `oxfmt` spawns instead of one**

The original `xargs oxfmt --check` invocation passed all matching files in a single (or a few batched) subprocess calls. The new loop spawns a fresh `oxfmt` process for every file. On a repository with many Markdown files this can be significantly slower due to per-process startup overhead.

Consider passing all files to a single `oxfmt` invocation:

```js
function runOxfmt(files) {
  const result = spawnSync("oxfmt", ["--check", ...files], {
    stdio: "inherit",
  });
  if (result.error) {
    console.error("Failed to run oxfmt:", result.error.message);
    process.exit(1);
  }
  if (result.status !== 0) {
    process.exit(result.status ?? 1);
  }
}
```

This matches the original behavior and avoids the per-file spawn cost. If you intentionally want per-file output isolation, a comment explaining the rationale would be helpful.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: scripts/format-docs-check.cjs
Line: 22-26

Comment:
**Spawn errors (e.g. `oxfmt` not on PATH) are silently swallowed**

When `spawnSync` cannot find the executable, it sets `result.error` (an `Error` object) and leaves `result.status` as `null`. `null !== 0` evaluates to `true`, so the code does mark `failed = true` — but it never prints *why*, leaving the user with no output and a confusing non-zero exit. Adding an explicit check improves the developer experience:

```js
if (result.error) {
  console.error(`Failed to spawn oxfmt: ${result.error.message}`);
  process.exit(1);
}
```

How can I resolve this? If you propose a fix, please make it concise.

Last reviewed commit: dfa42bc

Comment on lines +1 to +5
// scripts/format-docs-check.js
// Cross-platform docs formatting check for Windows
const { spawnSync } = require("child_process");
const fs = require("fs");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 require() will throw in an ESM package

package.json declares "type": "module", so Node.js treats all .js files as ES modules. Running node scripts/format-docs-check.js will immediately throw:

ReferenceError: require is not defined in ES module scope

The .cjs sibling file works correctly because the .cjs extension always forces CommonJS mode regardless of "type". This .js file is also unreferenced in package.json, making it dead code that is broken if anyone tries to invoke it directly. It should either be removed entirely, or — if it is meant as a fallback — converted to ESM (import { spawnSync } from 'child_process', import fs from 'fs').

Prompt To Fix With AI
This is a comment left during a code review.
Path: scripts/format-docs-check.js
Line: 1-5

Comment:
**`require()` will throw in an ESM package**

`package.json` declares `"type": "module"`, so Node.js treats all `.js` files as ES modules. Running `node scripts/format-docs-check.js` will immediately throw:

```
ReferenceError: require is not defined in ES module scope
```

The `.cjs` sibling file works correctly because the `.cjs` extension always forces CommonJS mode regardless of `"type"`. This `.js` file is also unreferenced in `package.json`, making it dead code that is broken if anyone tries to invoke it directly. It should either be removed entirely, or — if it is meant as a fallback — converted to ESM (`import { spawnSync } from 'child_process'`, `import fs from 'fs'`).

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown
Author

@soyames soyames Mar 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed - removed format-docs-check.js entirely. It was dead code (unreferenced in package.json) and broken in an ESM package. The .cjs file is the sole implementation.

Comment on lines +19 to +29
function runOxfmt(files) {
let failed = false;
for (const file of files) {
const result = spawnSync("oxfmt", ["--check", file], {
stdio: "inherit",
});
if (result.status !== 0) {
failed = true;
}
}
if (failed) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Performance regression: N separate oxfmt spawns instead of one

The original xargs oxfmt --check invocation passed all matching files in a single (or a few batched) subprocess calls. The new loop spawns a fresh oxfmt process for every file. On a repository with many Markdown files this can be significantly slower due to per-process startup overhead.

Consider passing all files to a single oxfmt invocation:

function runOxfmt(files) {
  const result = spawnSync("oxfmt", ["--check", ...files], {
    stdio: "inherit",
  });
  if (result.error) {
    console.error("Failed to run oxfmt:", result.error.message);
    process.exit(1);
  }
  if (result.status !== 0) {
    process.exit(result.status ?? 1);
  }
}

This matches the original behavior and avoids the per-file spawn cost. If you intentionally want per-file output isolation, a comment explaining the rationale would be helpful.

Prompt To Fix With AI
This is a comment left during a code review.
Path: scripts/format-docs-check.cjs
Line: 19-29

Comment:
**Performance regression: N separate `oxfmt` spawns instead of one**

The original `xargs oxfmt --check` invocation passed all matching files in a single (or a few batched) subprocess calls. The new loop spawns a fresh `oxfmt` process for every file. On a repository with many Markdown files this can be significantly slower due to per-process startup overhead.

Consider passing all files to a single `oxfmt` invocation:

```js
function runOxfmt(files) {
  const result = spawnSync("oxfmt", ["--check", ...files], {
    stdio: "inherit",
  });
  if (result.error) {
    console.error("Failed to run oxfmt:", result.error.message);
    process.exit(1);
  }
  if (result.status !== 0) {
    process.exit(result.status ?? 1);
  }
}
```

This matches the original behavior and avoids the per-file spawn cost. If you intentionally want per-file output isolation, a comment explaining the rationale would be helpful.

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all files are now passed to a single oxfmt invocation, matching the original xargs batching behaviour.

Comment on lines +22 to +26
const result = spawnSync("oxfmt", ["--check", file], {
stdio: "inherit",
});
if (result.status !== 0) {
failed = true;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Spawn errors (e.g. oxfmt not on PATH) are silently swallowed

When spawnSync cannot find the executable, it sets result.error (an Error object) and leaves result.status as null. null !== 0 evaluates to true, so the code does mark failed = true — but it never prints why, leaving the user with no output and a confusing non-zero exit. Adding an explicit check improves the developer experience:

if (result.error) {
  console.error(`Failed to spawn oxfmt: ${result.error.message}`);
  process.exit(1);
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: scripts/format-docs-check.cjs
Line: 22-26

Comment:
**Spawn errors (e.g. `oxfmt` not on PATH) are silently swallowed**

When `spawnSync` cannot find the executable, it sets `result.error` (an `Error` object) and leaves `result.status` as `null`. `null !== 0` evaluates to `true`, so the code does mark `failed = true` — but it never prints *why*, leaving the user with no output and a confusing non-zero exit. Adding an explicit check improves the developer experience:

```js
if (result.error) {
  console.error(`Failed to spawn oxfmt: ${result.error.message}`);
  process.exit(1);
}
```

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added result.error checks for both the git ls-files and oxfmt calls with explicit error messages

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dfa42bc16d

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@@ -0,0 +1,40 @@
// scripts/format-docs-check.js
// Cross-platform docs formatting check for Windows
const { spawnSync } = require("child_process");
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Remove ESM-incompatible duplicate script entrypoint

This newly added .js script is not runnable in this repository because package.json sets "type": "module", so node scripts/format-docs-check.js throws ReferenceError: require is not defined in ES module scope at startup. Even though format:docs:check currently points to the .cjs file, keeping a broken duplicate entrypoint in-tree is a maintainability trap and can break anyone who invokes the .js script directly or wires it into tooling later.

Useful? React with 👍 / 👎.

The existing format:docs:check used `git ls-files | xargs oxfmt` which
fails on Windows — xargs is unavailable and single-quoted globs in
cmd.exe are treated as literals, silently matching no files.

Replace with scripts/format-docs-check.cjs, a Node.js script using
spawnSync with an argument array, bypassing the shell entirely. This
gives identical behaviour on Windows, macOS, and Linux.

- package.json: format:docs:check now calls node scripts/format-docs-check.cjs
- scripts/format-docs-check.cjs: passes all files in a single oxfmt
  invocation (matches original xargs batching), with explicit error
  handling for missing executables

Related openclaw#3460
@soyames soyames force-pushed the fix/docs-format-check-windows-clean branch from 5932a26 to 7596519 Compare March 17, 2026 09:43
@johnsonshi
Copy link
Copy Markdown
Contributor

This looks like a solid, low-risk cross-platform improvement. The change is tightly scoped to package.json plus the new scripts/format-docs-check.cjs helper, and it preserves the existing git ls-files patterns along with the oxfmt --check workflow. The helper also adds sensible handling for git / oxfmt execution failures and for the no-files case.

I checked the current branch/diff and do not see any duplicate .js helper file, so the earlier bot note about a broken duplicate file appears stale.

As a follow-up, it may be worth adding a small unit or integration test around the helper so future refactors do not accidentally change the file-selection behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

scripts Repository scripts size: XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants