Skip to content

feat: improved piping & accept stdin as image input for CLI#380

Open
axe312ger wants to merge 1 commit intomasterfrom
feat/stdin-input
Open

feat: improved piping & accept stdin as image input for CLI#380
axe312ger wants to merge 1 commit intomasterfrom
feat/stdin-input

Conversation

@axe312ger
Copy link
Owner

@axe312ger axe312ger commented Mar 3, 2026

Summary

Implements #334 — allow the CLI to accept piped image data via process.stdin.

Usage

# Pipe from curl
curl -s https://example.com/image.jpg | sqip -p pixels blur svgo

# Pipe from file
cat photo.png | sqip -p pixels -o result.svg

# Classic file input still works
sqip -i photo.jpg -p pixels

Changes

CLI (sqip-cli)

  • --input is no longer required — omit it when piping via stdin
  • Stdin detection via !process.stdin.isTTY, reads data with process.stdin.toArray()
  • --input flag takes precedence when both stdin and flag are provided
  • Stdin mode defaults: print=true (output SVG to stdout), silent=true (no metadata tables)
  • Updated help text and examples

Core (sqip)

  • Improved mime type detection for buffer input using sharp metadata (instead of returning 'unknown')
  • print now works even when silent is true, enabling clean piping workflows

Tests

  • 6 new unit tests for stdin argument handling
  • 2 new e2e tests (stdin → stdout, stdin with -o)
  • All 112 unit + 11 e2e tests pass

Test Plan

npm run test:unit   # 112 tests pass
npm run test:e2e    # 11 tests pass (incl. 2 new stdin tests)

# Manual verification
cat __tests__/fixtures/beach.jpg | node packages/sqip-cli/dist/wrapper.js -p pixels
cat __tests__/fixtures/beach.jpg | node packages/sqip-cli/dist/wrapper.js -p pixels -o /tmp/test.svg

Closes #334

Summary by CodeRabbit

  • New Features

    • Added stdin support: images can be piped directly into the CLI (e.g., cat image.jpg | sqip), with output file option (-o) and sensible defaults when reading from stdin.
    • SVG output can be streamed to stdout for piping and command chaining; stdin-sourced inputs are labeled as "stdin" in output metadata.
  • Tests

    • Expanded test coverage for stdin scenarios, validating stdout streaming, file output behavior, and default option handling.

@vercel
Copy link

vercel bot commented Mar 3, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
sqip Ready Ready Preview Mar 5, 2026 3:55pm

Request Review

@coderabbitai
Copy link

coderabbitai bot commented Mar 3, 2026

📝 Walkthrough

Walkthrough

Adds stdin support to the SQIP CLI: detect piped input via fstatSync(0).isFIFO(), read image data from stdin, treat stdin inputs as named "stdin" with MIME detection from image metadata, and route SVG output to stdout or an output file accordingly. Tests (unit and e2e) added/updated for these flows.

Changes

Cohort / File(s) Summary
CLI stdin input handling
packages/sqip-cli/src/sqip-cli.ts
Detect piped stdin via fstatSync(0).isFIFO(), read stdin when --input absent, set outputFileName/name to "stdin", adjust silent/print defaults for stdin, update help text and option descriptions.
Core processing adjustments
packages/sqip/src/sqip.ts
When processing stdin (filePath === '-'), derive filename from config.outputFileName or "stdin", derive mimeType from sharp metadata fallback, and print SVG to stdout when silent+print are enabled.
Unit tests for stdin
packages/sqip-cli/__tests__/unit/sqip-cli.test.ts
Add fs mocking for fstatSync to simulate FIFO, restore mocks between tests, and add tests covering stdin precedence, defaults, output filename resolution, -o behavior, and silent/print defaults.
End-to-end stdin tests
packages/sqip-cli/__tests__/e2e/sqip-cli-e2e.test.ts
Add e2e tests piping an image to the CLI via `cat

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant Shell
  participant SQIP_CLI as SQIP CLI
  participant SQIP_Core as sqip (processor)
  participant FS as Filesystem

  rect rgba(200,200,255,0.5)
  User->>Shell: curl ... | sqip
  Shell->>SQIP_CLI: piped stdin (fd 0)
  SQIP_CLI->>SQIP_CLI: fstatSync(0).isFIFO() -> true
  SQIP_CLI->>SQIP_CLI: read stdin bytes
  SQIP_CLI->>SQIP_Core: processImage(buffer, config with outputFileName="stdin")
  SQIP_Core->>SQIP_Core: sharp.metadata() -> determine mimeType
  SQIP_Core-->>SQIP_CLI: SVG result
  alt output to file (-o)
    SQIP_CLI->>FS: write SVG to output path
    FS-->>SQIP_CLI: write complete
    SQIP_CLI->>Shell: (no stdout if silent)
  else print to stdout (default for stdin)
    SQIP_CLI->>Shell: write SVG to stdout
  end
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I heard a pipe and gave a hop,
Bytes tumbled in—no need to stop.
I named it "stdin", guessed its kind,
And spat out art for humankind.
A happy hop — SVG on top! 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main feature: implementing stdin support and improved piping for the CLI tool, which aligns with the core changes across the codebase.
Linked Issues check ✅ Passed The PR fully implements the objective from issue #334: CLI now accepts piped image data via stdin, detects stdin presence, reads the stream into a buffer, preserves file-input behavior, and allows --input flag to override stdin.
Out of Scope Changes check ✅ Passed All code changes are scoped to stdin support and piping improvements: CLI stdin detection/handling, core MIME-type detection enhancements, and comprehensive test coverage for the new functionality.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/stdin-input

Comment @coderabbitai help to get the list of available commands and usage tips.

@axe312ger
Copy link
Owner Author

@xerc WDYT? :)

}

if (missing.length) {
if (!args.input) {
Copy link
Owner Author

@axe312ger axe312ger Mar 4, 2026

Choose a reason for hiding this comment

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

SQIP actually only used required for the input parameter, all the others have sane defaults.

So dropping the missing others check is totally fine here!

@axe312ger axe312ger changed the title feat: accept stdin as image input for CLI feat: improved piping & accept stdin as image input for CLI Mar 4, 2026
@xerc
Copy link
Contributor

xerc commented Mar 4, 2026

@axe312ger these could also be from other GLOBAL packages ..

INFOs
% node -v
v20.20.0
% npm -g list
/usr/local/lib
├── css-checker-kit@0.4.2
├── glyphhanger@5.0.0
├── npm-check@6.0.1
├── npm@11.11.0
└── porffor@0.61.11
ERRORs
npm error code 1
npm error path /usr/local/lib/node_modules/sqip-plugin-data-uri/node_modules/sharp
npm error command failed
npm error command sh -c node install/check.js || npm run build
npm error > sharp@0.34.5 build
npm error > node install/build.js
npm error
npm error sharp: Attempting to build from source via node-gyp
npm error sharp: See https://sharp.pixelplumbing.com/install#building-from-source
npm error sharp: Found node-addon-api
npm error sharp: Please add node-gyp to your dependencies
DEPRECATED
npm warn deprecated stable@0.1.8: Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility
npm warn deprecated q@1.5.1: You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.
npm warn deprecated (For a CapTP with native promises, see @endo/eventual-send and @endo/captp)
npm warn deprecated xmldom@0.1.31: Deprecated due to CVE-2021-21366 resolved in 0.5.0
npm warn deprecated prebuild-install@7.1.3: No longer maintained. Please contact the author of the relevant native addon; alternatives are available.
npm warn deprecated argv@0.0.2: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.
npm warn deprecated svgo@0.7.2: This SVGO version is no longer supported. Upgrade to v2.x.x.
npm warn deprecated svgo@1.3.2: This SVGO version is no longer supported. Upgrade to v2.x.x.

@axe312ger
Copy link
Owner Author

@xerc did you run from this branch for sure? If you npm install -g, this won't be included yet.

Allow piping image data via process.stdin, enabling usage like:

  curl -s https://example.com/image.jpg | sqip -p pixels
  cat photo.png | sqip -p pixels -o result.svg

When stdin is detected (via !process.stdin.isTTY), the CLI reads all
data into a buffer and passes it to the core sqip() function. Stdin
mode defaults to print=true and silent=true for clean piping output.
The --input flag takes precedence when both are provided.

Also improves buffer input handling in the core library:
- Detect mime type from buffer contents using sharp metadata
- Allow print to work even when silent is true (for piping)

Closes #334

Co-Authored-By: Mastra Code (anthropic/claude-opus-4-6) <noreply@mastra.ai>
@axe312ger
Copy link
Owner Author

I rebased this branch now as well, so most of the dependency updates from yesterday should be in here now as well

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/sqip-cli/__tests__/unit/sqip-cli.test.ts (1)

54-54: Consider using mockClear() instead of mockRestore() for consistency.

Using mockRestore() on mockedFstatSync resets it to the original implementation, which may cause the mock to behave unexpectedly in subsequent tests since the module-level vi.mock already wraps it. Consider using mockClear() to reset call history while preserving the mock wrapper, or explicitly re-apply the mock behavior in tests that need it.

♻️ Suggested change
-    mockedFstatSync.mockRestore()
+    mockedFstatSync.mockClear()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/sqip-cli/__tests__/unit/sqip-cli.test.ts` at line 54, The test
currently calls mockedFstatSync.mockRestore(), which restores the original
implementation and can interfere with module-level vi.mock wrappers; replace
that call with mockedFstatSync.mockClear() to clear call history while
preserving the mock wrapper (or, if the intention was to fully restore, re-apply
the mock afterwards); locate the call to mockedFstatSync.mockRestore() in the
test file and change it to mockedFstatSync.mockClear() (or add a re-mock step)
to ensure consistent mock behavior across tests.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/sqip-cli/__tests__/unit/sqip-cli.test.ts`:
- Line 54: The test currently calls mockedFstatSync.mockRestore(), which
restores the original implementation and can interfere with module-level vi.mock
wrappers; replace that call with mockedFstatSync.mockClear() to clear call
history while preserving the mock wrapper (or, if the intention was to fully
restore, re-apply the mock afterwards); locate the call to
mockedFstatSync.mockRestore() in the test file and change it to
mockedFstatSync.mockClear() (or add a re-mock step) to ensure consistent mock
behavior across tests.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e34fe509-c26b-48bb-9fee-33d3763207b0

📥 Commits

Reviewing files that changed from the base of the PR and between abd4c37 and 9add34f.

⛔ Files ignored due to path filters (3)
  • packages/sqip-cli/__tests__/e2e/__snapshots__/sqip-cli-e2e.test.ts.snap is excluded by !**/*.snap
  • packages/sqip-cli/__tests__/unit/__snapshots__/sqip-cli.test.ts.snap is excluded by !**/*.snap
  • packages/sqip/__tests__/unit/__snapshots__/sqip.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (4)
  • packages/sqip-cli/__tests__/e2e/sqip-cli-e2e.test.ts
  • packages/sqip-cli/__tests__/unit/sqip-cli.test.ts
  • packages/sqip-cli/src/sqip-cli.ts
  • packages/sqip/src/sqip.ts

@xerc
Copy link
Contributor

xerc commented Mar 6, 2026

npm install

DEPR
npm warn deprecated git-raw-commits@3.0.0: This package is no longer maintained. For the JavaScript API, please use @conventional-changelog/git-client instead.
npm warn deprecated git-semver-tags@5.0.1: This package is no longer maintained. For the JavaScript API, please use @conventional-changelog/git-client instead.
npm warn deprecated whatwg-encoding@3.1.1: Use @exodus/bytes instead for a more spec-conformant and faster implementation
npm warn deprecated glob@11.1.0: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
INFO
npm error code 1
npm error path github-sqip/packages/sqip-plugin-primitive
npm error command failed
npm error command sh -c npm run build-vendor
npm error > sqip-plugin-primitive@1.0.0-alpha.53 build-vendor
npm error > node scripts/bundle-vendor.js
npm error
npm error
npm error ---
npm error
npm error Unable to download and build primitive from https://github.com/hashbite/primitive.
npm error
npm error Is go installed?
npm error
npm error Some users might just want to download it from here: https://golang.org/dl/
npm error
npm error Brew users: brew install go
npm error
npm error ---

ERROR

npm error code 1
npm error path github-sqip/node_modules/sharp
npm error command failed
npm error command sh -c node install/check.js || npm run build
npm error > sharp@0.34.5 build
npm error > node install/build.js
npm error
npm error sharp: Attempting to build from source via node-gyp
npm error sharp: See https://sharp.pixelplumbing.com/install#building-from-source
npm error sharp: Please add node-addon-api to your dependencies

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Accept process.stdin as image --input

2 participants