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

@cloudflare/shell

v0.3.1

Published

Experimental sandboxed JS execution and filesystem runtime for Cloudflare Workers agents

Readme

@cloudflare/shell

Experimental. API surface is still settling — expect breaking changes.

Sandboxed JavaScript execution and filesystem runtime for Cloudflare Workers agents.

Instead of parsing shell syntax, @cloudflare/shell runs JavaScript inside an isolated Worker and exposes a typed state object for operating on a filesystem backend. It is designed for agent workflows that need structured state operations, predictable semantics, and coarse host-side filesystem primitives.

What it is

  • A runtime-neutral StateBackend interface for filesystem/state operations
  • A FileSystem interface with two implementations: InMemoryFs (ephemeral) and WorkspaceFileSystem (durable)
  • FileSystemStateBackend — a single adapter wrapping any FileSystem into a StateBackend
  • Workspace — durable file storage backed by SQLite + optional R2
  • stateTools(workspace) — a ToolProvider for @cloudflare/codemode that exposes state.* in sandboxed executions
  • createGit(filesystem) — pure-JS git operations via isomorphic-git, backed by the virtual filesystem
  • gitTools(workspace) — a ToolProvider for @cloudflare/codemode that exposes git.* in sandboxed executions with auto-injected auth
  • A prebuilt state stdlib with type declarations for LLM prompts

What it is not

This is not a bash interpreter. It does not parse shell syntax, expose pipes, or emulate POSIX shell behavior. It executes JavaScript.

Example — in-memory state

import { createMemoryStateBackend } from "@cloudflare/shell";
import { stateToolsFromBackend } from "@cloudflare/shell/workers";
import { DynamicWorkerExecutor, resolveProvider } from "@cloudflare/codemode";

const backend = createMemoryStateBackend({
  files: {
    "/src/app.ts": 'export const answer = "foo";\n'
  }
});

const executor = new DynamicWorkerExecutor({ loader: env.LOADER });

const result = await executor.execute(
  `async () => {
    const text = await state.readFile("/src/app.ts");
    await state.writeFile("/src/app.ts", text.replace("foo", "bar"));
    return await state.readFile("/src/app.ts");
  }`,
  [resolveProvider(stateToolsFromBackend(backend))]
);

Example — durable Workspace

import { Agent } from "agents";
import { Workspace } from "@cloudflare/shell";
import { stateTools } from "@cloudflare/shell/workers";
import { DynamicWorkerExecutor, resolveProvider } from "@cloudflare/codemode";

class MyAgent extends Agent<Env> {
  workspace = new Workspace({
    sql: this.ctx.storage.sql,
    r2: this.env.MY_BUCKET,
    name: () => this.name
  });

  async run(code: string) {
    const executor = new DynamicWorkerExecutor({ loader: this.env.LOADER });
    return executor.execute(code, [
      resolveProvider(stateTools(this.workspace))
    ]);
  }
}

Example — git operations

import { Agent } from "agents";
import { Workspace } from "@cloudflare/shell";
import { WorkspaceFileSystem } from "@cloudflare/shell";
import { createGit } from "@cloudflare/shell/git";

class MyAgent extends Agent<Env> {
  workspace = new Workspace({
    sql: this.ctx.storage.sql,
    name: () => this.name
  });

  async run() {
    const git = createGit(new WorkspaceFileSystem(this.workspace));

    await git.clone({ url: "https://github.com/org/repo", depth: 1 });
    await this.workspace.writeFile("/README.md", "# Updated");
    await git.add({ filepath: "." });
    await git.commit({
      message: "update readme",
      author: { name: "Agent", email: "[email protected]" }
    });
    await git.push({ token: this.env.GITHUB_TOKEN });
  }
}

Git commands

init, clone, status, add, rm, commit, log, branch, checkout, fetch, pull, push, diff, remote

Git ToolProvider for codemode

gitTools(workspace) exposes all git commands inside sandboxed executions. Auth tokens are auto-injected into clone/fetch/pull/push — the LLM never sees secrets.

import { stateTools } from "@cloudflare/shell/workers";
import { gitTools } from "@cloudflare/shell/git";

const providers = [
  resolveProvider(stateTools(this.workspace)),
  resolveProvider(gitTools(this.workspace, { token: this.env.GITHUB_TOKEN }))
];

Design goals

  • Structured state operations instead of shell parsing
  • Coarse host-side operations like glob() and diff() to avoid chatty RPC
  • Compatibility with both ephemeral in-memory state and durable Workspace
  • Secure execution with isolate-level timeouts and outbound network blocking by default

state object API

The state object is available inside every isolate and exposes:

Primitive filesystem

readFile, writeFile, appendFile, readFileBytes, writeFileBytes, mkdir, rm, cp, mv, symlink, readlink, realpath, readdir, glob, stat, lstat, exists, diff, diffContent

JSON helpers

readJson(path), writeJson(path, value, { spaces? }), queryJson(path, query), updateJson(path, operations)

Search and replace

searchText(path, query, options?), searchFiles(glob, query, options?), replaceInFile(path, search, replacement, options?), replaceInFiles(glob, search, replacement, { dryRun?, rollbackOnError?, ...options })

Filesystem queries

find(path, options?), walkTree(path, { maxDepth? }), summarizeTree(path, { maxDepth? })

Archive and compression

createArchive(path, sources), listArchive(path), extractArchive(path, destination), compressFile(path, destination?), decompressFile(path, destination?), hashFile(path, { algorithm? }), detectFile(path)

Structured edit planning

planEdits(instructions), applyEditPlan(plan, { dryRun?, rollbackOnError? }), applyEdits(edits, { dryRun?, rollbackOnError? })

Multi-file workflow

// Preview changes without applying
const preview = await state.replaceInFiles("src/**/*.ts", "foo", "bar", {
  dryRun: true
});

// Plan structured edits with intent
const plan = await state.planEdits([
  { kind: "replace", path: "/src/app.ts", search: "foo", replacement: "bar" },
  { kind: "writeJson", path: "/src/config.json", value: { enabled: true } }
]);
await state.applyEditPlan(plan);

// Apply raw edits transactionally
await state.applyEdits([
  { path: "/src/generated.ts", content: "export const generated = true;\n" }
]);

Batch writes roll back by default if any write fails. Set rollbackOnError: false to allow partial progress.

Rough command translation

| Shell command | state equivalent | | -------------------- | -------------------------------------------------------------------------- | | cat | state.readFile() | | echo x > file | state.writeFile() | | mkdir | state.mkdir() | | ls / find | state.readdir() / state.glob() | | find with filters | state.find() | | tree / du | state.walkTree() / state.summarizeTree() | | cp / mv / rm | state.cp() / state.mv() / state.rm() | | diff | state.diff() / state.diffContent() | | grep | state.searchText() / state.searchFiles() | | sed | state.replaceInFile() / state.replaceInFiles() | | jq | state.readJson() / state.queryJson() / state.updateJson() | | tar | state.createArchive() / state.listArchive() / state.extractArchive() | | gzip / gunzip | state.compressFile() / state.decompressFile() | | sha256sum / file | state.hashFile() / state.detectFile() | | git | git.* via @cloudflare/shell/git |

Maybe later

  • Stream-oriented transforms inspired by sort, uniq, comm, cut, paste, tr
  • Full rg CLI parity — file types, ignore controls, multiple roots
  • Richer JSON query semantics closer to jq filters
  • Structured patch helpers covering more of diff / codemod workflows
  • A smaller "command" library built on top of state.*

Relationship to other packages

  • @cloudflare/codemode: executes sandboxed JavaScript that orchestrates tools
  • @cloudflare/shell: provides filesystem backends and stateTools() ToolProvider for codemode