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

@akhera-horus/testenv

v0.2.0

Published

testenv/v1 declarative manifest schema, types, and validator

Readme

@horus/testenv — testenv/v1 Schema & Validator

Declarative manifest format (testenv/v1) for isolated, ephemeral test environments. Repo-agnostic: no stack-specific assumptions. Per-repo specifics (provisioner commands, service names, port numbers) are data in the manifest, not code in this package.


Overview

A .testenv/manifest.yaml file describes how to spin up an isolated copy of a repo's stack, run tests against it, and tear it down — with provable isolation invariants at each step. The format is consumed by the runner core CLI and the sdlc-testenv executor subagent. The run result / event log format is corpus-ready: a future CI regression gate reuses it unchanged.


The 6-Phase Spine

setup → launch → await_ready → connection → test → teardown

| Phase | Purpose | |---------------|-------------------------------------------------------------------------| | setup | Clone code, build, prepare file layout. Phase-1 isolation checks here. | | launch | Bring up the stack (via provisioner command or explicit steps). Phase-2 checks. | | await_ready | Poll until all services are healthy (timeout-bounded). | | connection | Emit the connection manifest (MCP settings, API base URLs, etc.). | | test | Execute test actions (the do/check/proof units). | | teardown | Release the stack. Phase-6 detective isolation checks. |


Isolation Invariants

Three enforcement points guarantee the test stack never disturbs a co-located live stack:

Phase 1 — Preventive (abort before touching anything shared):

  • Disjoint docker project / network / volumes / port space / data directory
  • All declared requires.secrets present in the environment

Phase 2 — Structural (verified after launch):

  • Distinct docker project name
  • All ports fully projected (no wildcards or overlay-merge)
  • Connection manifest emitted with correctly suffixed MCP server names

Phase 6 — Detective (verified post-teardown):

  • Live stack still running and unmodified
  • Live data contains zero test artifacts
  • No secret values in logs or temp files

Test Actions — The Do/Check/Proof Unit

Each test action is a {invoke, expect, evidence} triple:

- name: anvil-roundtrip
  invoke:
    tool: anvil_create_note
    args: { title: "check" }
  expect:
    returns: note_id
  evidence:
    capture: response
  needsStack: true

Three invocation flavors:

  1. Command{ run: "curl -sf http://localhost:8080/health" }
  2. MCP tool call{ tool: "anvil_create_note", args: { title: "check" } }
  3. HTTP request{ http: "live-anvil/search?q=check" }
  4. Ordered sequence{ sequence: [{ name, invoke, expect }, ...] }

Each action declares needsStack: boolean. When false, the runner skips setup/launch/await_ready/teardown for that action (fast unit/type inner loop).


Manifest Structure

apiVersion: testenv/v1
repo: my-app

requires:
  secrets: [MY_API_KEY, DB_PASSWORD]   # env var NAMES only — values never logged
  profiles:
    laptop: { mem: 6g }
    cloud:  { mem: 12g }

phases:
  setup:
    steps:
      - run: git clone --no-hardlinks {src} {workdir}
      - run: npm install && npm run build
    assert:
      - type: path_exists
        path: {workdir}/dist
    isolationChecks:
      disjointDockerProject: true
      disjointPortSpace: true
      allRequiredSecretsPresent: true

  launch:
    provisioner: "docker compose -p my-app-test-{slot} up -d"
    assert:
      - type: containers_running
        count: 3
      - type: ports_disjoint_from_live
        value: true
    isolationChecks:
      distinctDockerProject: true
      fullyProjectedPorts: true
      connectionManifestEmitted: true

  await_ready:
    poll:
      - probe: "GET :{api_port}/health"
        expect: http_200
    timeout: 120

  connection:
    emit: "{slot}/settings.json"
    assert:
      - type: file_parses
        path: "{slot}/settings.json"
        format: json

  test:
    policy: fail-fast      # or run-all
    actions:
      - name: health-check
        invoke:
          run: curl -sf http://localhost:{api_port}/health
        expect:
          exitCode: 0
        evidence:
          capture: stdout
      - name: isolation-proof
        invoke:
          http: "live-api/search?q=test-artifact"
        expect:
          count: 0

  teardown:
    provisioner: "docker compose -p my-app-test-{slot} down -v"
    assert:
      - type: containers_remaining
        count: 0
      - type: live_stack_unmodified
        value: true
      - type: live_data_test_artifacts_zero
        value: true
      - type: no_secret_residue
        value: true
    isolationChecks:
      liveStackUnmodified: true
      liveDataTestArtifactsZero: true
      noSecretResidue: true

Template Variables

Manifest strings may contain {var} placeholders resolved by the runner at execution time:

| Variable | Description | |-------------|--------------------------------------------------------------------| | {slot} | Unique slot identifier for this run (namespaces docker resources). | | {workdir} | Working directory for the cloned code. | | {src} | Source repository path. | | {profile} | Active run profile name (e.g., laptop, cloud). |


Supported Assertion Types

| Type | Description | |--------------------------------|-----------------------------------------------------------------| | path_exists | File or directory exists at the given path. | | cmd_exit_zero | Command exits with code 0. | | containers_running | Exactly N containers are running in the docker project. | | containers_remaining | Exactly N containers remain after teardown. | | ports_disjoint_from_live | No port conflicts with the live stack. | | docker_project_name | Docker project name matches the given pattern. | | file_parses | File is valid JSON or YAML. | | env_vars_present | All listed env var names are set (non-empty). | | live_stack_unmodified | Live stack still running and unmodified post-teardown. | | live_data_test_artifacts_zero| Live data contains zero test artifacts. | | no_secret_residue | No secret values in logs or temp files. | | mcp_names_suffixed | All MCP server names in the connection manifest carry a suffix. | | fully_projected_ports | All ports explicitly mapped (no wildcards). | | http_ok | HTTP GET returns a 2xx status. |


Run Result / Event Log Format

The runner emits a machine-readable RunResult at the end of each run. The format is corpus-ready: a future CI regression gate consumes it unchanged.

Key fields:

{
  "resultVersion": "testenv/v1/result",
  "verdict": "pass",           // pass | fail | skip | error
  "runClass": "green",         // red | green | regression | adhoc
  "repo": "my-app",
  "profile": "laptop",
  "commit": "abc123",
  "specVersion": "def456",     // commit hash of .testenv at run time
  "startedAt": "...",
  "endedAt": "...",
  "totalDurationMs": 300000,
  "phases": [...],             // per-phase results
  "actions": [...],            // per-action results (test phase)
  "events": [...]              // full structured event log
}

runClass supports the TDD red→green proof-of-work cycle:

  • red — pre-implementation run (expected failures)
  • green — post-implementation run (expected passes)
  • regression — CI gate run against committed test suite
  • adhoc — manual/exploratory run

Usage

import { validateManifest, assertManifest } from '@horus/testenv';
import { parse } from 'yaml';
import { readFileSync } from 'node:fs';

const raw = parse(readFileSync('.testenv/manifest.yaml', 'utf8'));

// Option 1: graceful error handling
const result = validateManifest(raw);
if (result.ok) {
  console.log('Valid manifest:', result.data);
} else {
  for (const err of result.errors) {
    console.error(`[${err.path}] ${err.message}`);
  }
}

// Option 2: fail-fast (throws on invalid)
const manifest = assertManifest(raw);

Development

pnpm install
pnpm build    # tsup ESM build
pnpm test     # vitest unit tests
pnpm typecheck