Skip to content

Latest commit

ย 

History

373 Commits

Folders and files

NameName
Last commit message
Last commit date
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

โšก fsr

โœจ Your scripts. Documented. Runnable. In one Markdown file.

fsr is the script runner that lives in your docs โ€” not buried in JSON. ๐Ÿš€

You know the drill ๐Ÿ˜ค: you clone a repo, there's a README.md that vaguely gestures at some scripts, and a package.json full of cryptic one-liners. Nobody knows what to run. Nobody knows what anything does. You Slack someone. They don't know either. Someone runs the wrong thing. Staging goes down at 9am. โ˜ ๏ธ

fsr fixes this. It collapses your documentation AND your scripts into a single file โ€” fscripts.md. It's Markdown. It's human-readable. And it actually runs. ๐ŸŽ‰


๐Ÿ“ฆ install

npm i -g fscr

๐Ÿ’ก Package name: fscr. Command: fsr. Yes, on purpose. ๐Ÿ˜„


๐Ÿš€ get started in 3 commands

npm i -g fscr        # ๐Ÿ“ฆ install fsr globally
fsr generate         # โœจ imports your package.json scripts โ†’ fscripts.md
fsr                  # ๐ŸŽฏ interactive picker โ€” choose and run

That's it. Your package.json scripts are now documented, readable, and runnable from a single Markdown file. No more mystery. No more Slack messages. No more broken staging environments. ๐Ÿ™Œ


๐Ÿค” what is fscripts.md?

fscripts.md is your new source of truth. ๐Ÿ“–

It's a plain Markdown file where:

  • ๐Ÿ“ Each script is a heading
  • ๐Ÿ’ฌ The description is prose right below it
  • โ–ถ๏ธ The actual command lives in a code block
  • ๐ŸŸฐ The docs and the runner are the same file โ€” always in sync
## start:web

๐ŸŒ Starts the local dev server on port 3000. Run this first.

node server.js

build:prod

๐Ÿ—๏ธ Full production build. Cleans dist/, compiles, minifies. Takes ~2 min.

npm run clean && npm run compile && npm run minify

๐Ÿคฏ full javascript blocks โ€” yes, really

fscripts.md isn't just for bash. You can write full executable JavaScript right in your Markdown: ๐Ÿ”ฅ

## db:seed

๐ŸŒฑ Seeds the local database with test fixtures. Wipes existing data first โ€” don't run on prod.

```javascript
import { seed } from "./db/seed.js";
await seed({ wipe: true });
```

Real Node.js. Executed directly. Documented inline. No extra files. ๐Ÿ’ฅ


๐ŸŽฎ commands

command what it does
โšก fsr interactive picker โ€” shows all scripts + plugins, just pick and run
๐Ÿ—‚๏ธ fsr start browse scripts by category
๐Ÿ” fsr list fuzzy search across all tasks
โ–ถ๏ธ fsr run [task] run a specific named task directly
๐Ÿ”— fsr run-s t1 t2 run tasks sequentially, one after another
โšก fsr run-p t1 t2 run tasks in parallel, at the same time
โœจ fsr generate import package.json scripts โ†’ fscripts.md
๐Ÿ“‹ fsr toc generate / update Table of Contents in fscripts.md
๐Ÿ“ฆ fsr scripts interactive picker for package.json scripts only
๐Ÿ” fsr encrypt password-protect secret file(s)
๐Ÿ”“ fsr decrypt decrypt secret file(s)
๐Ÿ”’ fsr encryption interactive encrypt/decrypt menu
๐Ÿš€ fsr bump bump version in package.json + beautify it
โฌ†๏ธ fsr upgrade upgrade all packages (respects ignore-upgrade list)
๐Ÿฉบ fsr doctor run diagnostics & health check
๐Ÿ’ป fsr completion shell completions for bash, zsh, fish, powershell
๐ŸŒฟ fsr branch validate you're not on dev, create a new branch
๐Ÿงน fsr clear clear recent task history
๐Ÿ’ฌ fsr commit stage + commit with AI-generated conventional commit messages
๐Ÿ”Œ fsr plugins list all installed plugins (built-in and npm fscr-plugin-*)

๐ŸŒ --env <name> (alias -e) is a global flag that works with every command above. It restricts the visible and runnable tasks to a specific environment profile.


โšก parallel & sequential execution

Run multiple scripts at the same time ๐Ÿš€:

fsr run-p start:web start:desktop start:api

Or one after another ๐Ÿ”—:

fsr run-s lint test build

No extra config. No setup. Just works. โœ…


๐Ÿ” encryption

Keep secrets safe without a third-party vault ๐Ÿ”’:

fsr encrypt    # ๐Ÿ” password-protect any file(s)
fsr decrypt    # ๐Ÿ”“ unlock them when you need them

Perfect for .env files, credentials, config secrets. Built right in. No extra tools needed. ๐Ÿ›ก๏ธ


๐Ÿ”Œ plugins

fsr has a plugin system ๐Ÿงฉ. Plugins hook into execution โ€” fire logic before or after any script runs.

Perfect for:

  • ๐Ÿงน Clearing cache before a build
  • ๐Ÿ“ฌ Sending notifications after deploy
  • ๐Ÿ“Š Logging execution time
  • ๐Ÿ” Anything your workflow needs

Plugins show up right alongside built-in commands in the interactive picker. No extra steps. No ceremony. ๐ŸŽ‰

built-in plugins

Drop a folder into lib/plugins/ with an index.js that exports a default plugin object:

// lib/plugins/my-plugin/index.js
export default {
    name: "my-plugin",
    version: "1.0.0",
    description: "Does something great",

    async init(context) {
        // Hook into lifecycle events
        context.registerHook("post-task", async ({ taskName, duration, success }) => {
            context.logger.info(`[my-plugin] ${taskName} finished in ${duration}ms`);
        });

        // Register new fsr commands
        context.registerCommand({
            name: "my-cmd",
            description: "My custom command",
            handler: async (options, ctx) => {
                ctx.logger.success("Hello from my-plugin!");
            }
        });
    },

    // Optional: appear in the interactive picker
    async run(ctx) {
        ctx.logger.success("Running my-plugin interactively");
    }
};

project-local plugins

Drop a plugin into .fsr/plugins/<name>/index.js in your project root โ€” no config, no install step:

my-repo/
  .fsr/
    plugins/
      cache-cleaner/
        index.js   โ† same export contract as built-in plugins

Useful for repo-specific automation you don't want to publish. Committed to the repo alongside your code.

npm plugins

Any npm package named fscr-plugin-* is auto-discovered at startup โ€” no config needed. Just install it:

npm i fscr-plugin-notify

fsr picks it up automatically on next run. Same plugin contract as built-in plugins.

plugin storage

Plugins get persistent key-value storage scoped to their name, written to .fscr/<plugin-name>/storage.json:

async init(context) {
    // Read previously saved data (returns {} if nothing saved yet)
    const data = context.getStorage();

    context.registerHook("post-task", async ({ taskName }) => {
        data.runs = (data.runs || 0) + 1;
        context.setStorage(data); // persists to disk
    });
}

lifecycle hooks

hook when it fires
pre-task before any fsr command or plugin run starts
post-task after any fsr command or plugin run completes successfully
post-command after any plugin-registered command completes
task-error when a command or plugin run throws

list installed plugins

fsr plugins

Shows all loaded plugins with their source ([builtin], [local], or [npm]) and description.


๐Ÿ“‹ table of contents

Your fscripts.md grows fast ๐Ÿ“ˆ. Keep it navigable:

fsr toc

Generates and updates a Table of Contents at the top of your fscripts.md. Auto-linked. Always current. โœ…


๐Ÿฉบ doctor

Something broken? Run the doc ๐Ÿฅ:

fsr doctor            # ๐Ÿ” check system health
fsr doctor --fix      # ๐Ÿ”ง auto-fix where possible
fsr doctor --json     # ๐Ÿ“Š output results as JSON (great for CI)
fsr doctor --verbose  # ๐Ÿ”ฌ show everything

๐Ÿ˜ค why not just use package.json?

package.json scripts have four problems:

problem reality
๐Ÿ˜ต Invisible cryptic one-liners with zero explanation
๐Ÿ๏ธ Isolated docs live somewhere else โ€” or nowhere at all
๐Ÿšง Inflexible no prose, no full scripts, no real structure
๐Ÿ•ต๏ธ A black box every new teammate asks the exact same questions

fsr doesn't replace package.json. It makes it irrelevant as an interface. ๐Ÿ˜Ž

You write in Markdown. Humans read it. fsr runs it.


๐Ÿ“ the fscripts.md format

# ๐Ÿ—‚๏ธ Group Name

## script-name

Description of what this does, when to run it, any gotchas. โœ๏ธ

```bash
your-command --here
```

another-script

// ๐ŸŸจ full Node.js โ€” executed directly
import { something } from "./lib/index.js";
await something();
  • ๐Ÿ—‚๏ธ Groups = top-level # headings
  • โ–ถ๏ธ Tasks = ## headings (the script name)
  • ๐Ÿ’ฌ Docs = prose between the heading and code block
  • ๐Ÿ”ฅ Runner = the code block itself (bash or javascript)
  • ๐ŸŒ Env boundary = ## [env:name] heading โ€” tags all subsequent tasks in the group with that environment profile (see environment profiles)

๐ŸŒ environment profiles

Different environments โ€” same fscripts.md. Use ## [env:name] headers inside any group to tag tasks to a specific deployment target, then pass --env <name> to surface only those tasks.

syntax

Add an ## [env:name] heading anywhere inside a # group. Every ## task that follows it (until the next ## [env:โ€ฆ] header or the next # group) inherits that environment tag:

# Deployment

## [env:staging]

## deploy:api

Deploy the API to the staging cluster.

```bash
node deploy.js --env staging
```

## deploy:web

```bash
node web.js --env staging
```

## [env:production]

## deploy:api

Deploy the API to the production cluster.

```bash
node deploy.js --env production
```

using --env

Pass --env <name> (alias -e) to any fsr command. Only tasks tagged with that profile are shown or executed. Tasks defined before any ## [env:โ€ฆ] header (i.e. with no profile) are excluded when --env is set.

fsr --env staging          # ๐ŸŽฏ interactive picker โ€” staging tasks only
fsr start --env staging    # ๐Ÿ—‚๏ธ  browse staging tasks by category
fsr list --env production  # ๐Ÿ” fuzzy-search production tasks
fsr run deploy:api --env staging   # โ–ถ๏ธ  run the staging variant of deploy:api
fsr run-s deploy:api deploy:web --env staging  # ๐Ÿ”— sequential, staging only
fsr run-p deploy:api deploy:web --env staging  # โšก parallel, staging only

The --env flag is global: it works on every command that reads fscripts.md.

shorthand aliases

--prod and --dev are convenience shortcuts that are resolved before yargs parses the command. They map to --env production and --env development respectively:

fsr --prod                          # equivalent to: fsr --env production
fsr --dev                           # equivalent to: fsr --env development
fsr run deploy:api --prod           # runs deploy:api with env=production

These shortcuts also normalise the prod / dev shortnames when used with --env:

fsr --env prod    # resolved to: fsr --env production
fsr --env dev     # resolved to: fsr --env development

behaviour at a glance

scenario result
No --env flag all tasks returned (env-tagged and plain alike)
--env staging only tasks under ## [env:staging] blocks
New # group heading env resets to none for tasks in that group
Same task name in two env sections both preserved; --env picks the right one
--env unknown empty result โ€” no tasks, no error

worked example

# Deploy

## build

Build the project (no env tag โ€” always available).

```bash
npm run build

[env:staging]

push

Push image to staging registry.

docker push registry/myapp:staging

[env:production]

push

Push image to production registry.

docker push registry/myapp:production

```bash
fsr run push --env staging     # runs: docker push registry/myapp:staging
fsr run push --env production  # runs: docker push registry/myapp:production

๐Ÿ†š fsr vs. the alternatives

fsr raw package.json Makefile nx / turbo
๐Ÿ“– Human-readable docs โœ… โŒ ๐Ÿ˜ฌ โŒ
โ–ถ๏ธ Run from Markdown โœ… โŒ โŒ โŒ
๐ŸŸจ Full JS script blocks โœ… โŒ โŒ โŒ
โšก Parallel execution โœ… โš ๏ธ โš ๏ธ โœ…
๐Ÿ” Built-in encryption โœ… โŒ โŒ โŒ
๐ŸŽฎ Interactive picker โœ… โŒ โŒ โŒ
๐Ÿ”Œ Plugin system (npm-based) โœ… โŒ โŒ โœ…
๐ŸŒ Environment profiles โœ… โŒ โŒ โš ๏ธ
๐Ÿ“ฆ Zero config โœ… โœ… โŒ โŒ
๐Ÿš€ 3-command onboarding โœ… โŒ โŒ โŒ

๐Ÿ’ก pro tips

  • ๐Ÿ”„ Run fsr generate on any existing repo โ€” instant fscripts.md from your package.json
  • ๐ŸŽฏ Just type fsr โ€” the interactive picker means you never have to memorize a command name
  • ๐ŸŸจ Use javascript blocks for scripts that need real logic โ€” imports, async, conditionals
  • ๐Ÿ”Œ Build a plugin to clear cache before every run โ€” set it once, forget it forever
  • ๐Ÿ“ฆ Publish a plugin as fscr-plugin-<name> on npm โ€” anyone who installs it gets it auto-loaded
  • ๐Ÿ“‹ Run fsr toc after adding new scripts โ€” keeps your fscripts.md navigable
  • ๐Ÿฉบ Run fsr doctor when something feels off โ€” it'll tell you what's wrong
  • ๐Ÿ’ฌ Run fsr commit to stage and commit with AI-written conventional commit messages
  • ๐ŸŒ Use ## [env:staging] / ## [env:production] sections and fsr --env staging in CI โ€” one fscripts.md, zero duplicated scripts

๐Ÿ“„ license

MIT ๐ŸŽ‰


โšก Built by the Freedcamp team. Battle-tested on our own repos before unleashing it on yours. We eat our own cooking. ๐Ÿณ

Similar

About

๐Ÿ˜ค The README lies. The package.json is cryptic. fsr collapses both into one beautiful Markdown file. ๐Ÿ”ฅ

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages