Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 

README.md

@context-fs/cli

Generic CLI runner framework for creating command-line tools that serve @context-fs/core virtual filesystems.

Installation

npm install @context-fs/cli

Quick Start

#!/usr/bin/env node
import { run } from "@context-fs/cli";
import { createFileSystem, read } from "@context-fs/core";

await run({
  name: "My VFS",

  async createVfs({ values, positionals }) {
    return createFileSystem({
      "hello.txt": {
        [read]: () => "Hello, world!",
      },
    });
  },

  examples: ({ mountPoint }) => [`cat "${mountPoint}/hello.txt"`],
});

API

run(options)

Main entry point for CLI tools. Handles argument parsing, server setup, mounting, and graceful shutdown.

interface RunOptions<TExtraValues> {
  // Display name for help and status messages
  name: string;

  // Factory function to create the VFS
  createVfs: (
    args: RunArgs<TExtraValues>,
  ) => Promise<VirtualFileSystem> | VirtualFileSystem;

  // Additional parseArgs options for custom flags
  options?: ParseArgsConfig["options"];

  // Default values for host, port, exportName
  defaults?: {
    host?: string;
    port?: number;
    exportName?: string;
  };

  // Example commands to show after mounting
  examples?: (ctx: { mountPoint: string }) => string[];
}

Built-in Flags

Flag Description Default
--mount <path> Mount point directory (server only)
--host <host> Server bind address 127.0.0.1
--port <port> Server port 2049
--exportName <name> NFS export name /
-h, --help Show help message

Custom Flags

Add custom flags via the options parameter:

await run<{ apiKey?: string; verbose?: boolean }>({
  name: "My API VFS",

  options: {
    apiKey: { type: "string", short: "k" },
    verbose: { type: "boolean", short: "v" },
  },

  async createVfs({ values }) {
    const apiKey = values.apiKey ?? process.env.API_KEY;
    if (!apiKey) throw new Error("API key required");

    if (values.verbose) {
      console.log("Verbose mode enabled");
    }

    return createFileSystem({
      /* ... */
    });
  },
});

Positional Arguments

Access positional arguments via positionals:

await run({
  name: "File Browser",

  async createVfs({ positionals }) {
    const [rootPath] = positionals;
    if (!rootPath) throw new Error("Root path required");

    return createFileSystem({
      /* ... */
    });
  },

  examples: ({ mountPoint }) => [`ls "${mountPoint}"`],
});

// Usage: my-cli /path/to/root --mount /tmp/browser

Behavior

Server Mode (no --mount)

When --mount is not provided, the CLI starts an NFS server without mounting:

$ my-cli --port 2049
My VFS running on 127.0.0.1:2049

Mount with:
  sudo mount -t nfs -o port=2049,mountport=2049,vers=3,tcp,nolocks 127.0.0.1:/ /mnt/point

Press Ctrl+C to stop

Mount Mode (with --mount)

When --mount is provided, the CLI mounts the filesystem and shows example commands:

$ my-cli --mount /tmp/my-vfs
My VFS mounted at /tmp/my-vfs

Try:
  cat "/tmp/my-vfs/hello.txt"

Press Ctrl+C to unmount

Graceful Shutdown

The CLI handles SIGINT (Ctrl+C) and SIGTERM for clean shutdown, automatically unmounting if needed.

Complete Example

#!/usr/bin/env node
import { run } from "@context-fs/cli";
import { createFileSystem, read, list } from "@context-fs/core";

interface CliValues {
  token?: string;
  refresh?: boolean;
}

await run<CliValues>({
  name: "GitHub VFS",

  defaults: {
    port: 2049,
  },

  options: {
    token: {
      type: "string",
      short: "t",
      description: "GitHub API token",
    },
    refresh: {
      type: "boolean",
      short: "r",
      description: "Refresh cache on start",
    },
  },

  async createVfs({ values }) {
    const token = values.token ?? process.env.GITHUB_TOKEN;
    if (!token) {
      throw new Error("GitHub token required (--token or GITHUB_TOKEN)");
    }

    if (values.refresh) {
      console.log("Refreshing cache...");
    }

    return createFileSystem({
      repos: {
        ":owner": {
          ":repo": {
            [list]: async () => {
              // Fetch repos...
              return [{ owner: "octocat", repo: "Hello-World" }];
            },
            "README.md": {
              [read]: async (c) => {
                // Fetch README...
                return `# ${c.params.repo}`;
              },
            },
          },
        },
      },
    });
  },

  examples: ({ mountPoint }) => [
    `ls "${mountPoint}/repos/octocat"`,
    `cat "${mountPoint}/repos/octocat/Hello-World/README.md"`,
  ],
});

Related Packages

License

MIT