npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@effected/env

v0.5.0

Published

Effect-native environment detection: agent, CI, terminal colour level, hyperlinks, columns and audience — read once through Config, swapped in tests with layerTest

Readme

@effected/env

npm License: MIT Node.js %3E%3D24.11.0 TypeScript 7.0

Effect-native environment detection for any front end of a tool: who is running it (an AI agent, a CI job, or neither), what the terminal can do (colour level, OSC 8 hyperlinks and width, per stream), and who the output is for (a human, an agent or CI). Every answer is read once through Config, never from process, and every service has a layerTest, so a test sets the environment it wants without touching a global.

Pre-1.0.0. This package is part of the @effected/* kit, built on stable Effect v4 (effect ^4.0.0) and still in 0.x development. Stable Effect makes a kit 1.0.0 possible, not automatic. To keep your effect and @effect/* versions on the line the kit is built and tested against, install @effected/pnpm-plugin-effect.

Stability: unstable. This package's API surface is not yet considered complete and may change across 0.x releases. Pin an exact version. Full policy: release strategy.

Why @effected/env

Every tool that prints ends up asking these questions, usually by reading process.env and process.stdout.isTTY wherever the answer is needed. The answers then drift (the help text and the report disagree about colour), they cannot be tested without mutating globals, and the rules are subtle: FORCE_COLOR beats NO_COLOR, an empty NO_COLOR means unset, TERM=dumb is a terminal that cannot move the cursor, a Windows console sets no TERM at all yet draws truecolor, and an agent running inside CI should get agent output.

This package makes each decision once, as a service, from rules taken from established sources: colour depth from Node's own getColorDepth (with OS=Windows_NT standing in for its platform check, which gives a Windows terminal truecolor as Node does from Windows 10 build 14931), hyperlink support from std-osc8's terminal table, and agent detection from std-env's table.

Install

npm install @effected/env effect
pnpm add @effected/env effect

Requires Node.js >=24.11.0. effect v4 is the only peer. There are no runtime dependencies, no platform import and no @effected/* edge, so it runs unchanged on Node, Bun and Deno.

All @effected/* packages are ESM-only: the exports maps publish only import conditions, so require() fails with Node's ERR_PACKAGE_PATH_NOT_EXPORTED. Import from an ES module.

Quick start

Decide the audience once, as a service, and let anything that prints ask it:

import { Audience, CurrentRuntimeEnv } from "@effected/env";
import { Effect, Layer } from "effect";

// A valid MYTOOL_AUDIENCE beats detection; then an agent, then CI, then a human.
const AudienceLive = Audience.layer({ envVar: "MYTOOL_AUDIENCE" }).pipe(Layer.provide(CurrentRuntimeEnv.layer));

const program = Effect.gen(function* () {
  const audience = yield* Audience;
  if (audience.kind === "agent") {
    // plain text, no escapes
  }
});

Effect.runPromise(program.pipe(Effect.provide(AudienceLive)));

What the terminal can do comes from TerminalEnv, which reads core's Stdio and Terminal from your platform layer:

import { TerminalEnv } from "@effected/env";
import { NodeServices } from "@effect/platform-node";
import { Effect } from "effect";

const describe = Effect.gen(function* () {
  const terminal = yield* TerminalEnv;
  return `${terminal.stdout.color} colour, ${terminal.width()} columns`;
});

Effect.runPromise(describe.pipe(Effect.provide(TerminalEnv.layer()), Effect.provide(NodeServices.layer)));

In a test, fix the answers instead:

import { Audience, TerminalEnv } from "@effected/env";
import { Layer, Option } from "effect";

const Environment = Layer.mergeAll(
  Audience.layerTest("agent"),
  TerminalEnv.layerTest({ stdout: { isTerminal: true, color: "256", columns: Option.some(120) } }),
);

What it exports

  • RuntimeEnv: a schema-class snapshot of the agent, the CI and the terminal program, persistable as plain JSON. RuntimeEnv.fromRecord(env) builds one as a pure function.
  • CurrentRuntimeEnv: that snapshot as a service. layer reads the ambient ConfigProvider once; layerFrom(source) reads a record or provider of your own, fresh on every use, for a long-lived host; layerTest(overrides) fixes it.
  • TerminalEnv: per-stream isTerminal, colour level (none, basic, 256, truecolor), hyperlinks and columns, plus width(fallback). layer() needs Stdio and Terminal; layerStdio() needs only Stdio; colorLevel("stdout") decides colour alone.
  • Audience: human, agent or ci, and the source that decided it. layer({ envVar }) decides from CurrentRuntimeEnv and an override variable you name.
  • EnvOverride: reads a variable that picks a mode within an audience, accepting only the literals you list per audience. readResult reports without logging; read logs one warning for a rejected value.

Documentation

The guides and the full API reference are at effected.spencerbeg.gs/env. @effected/cli builds its whole presentation layer on these services.

License

MIT