npm package: @overshift/sfs
Description: StoryFlowSteps - Agent-oriented browser automation protocol for validating user story flows
Latest version: 3.1.1

# SFS (StoryFlowSteps)

An agent-oriented automation protocol for validating user story flows. SFS provides a high-level, natural language syntax for describing browser and terminal automation tests, designed to be executed by an AI agent.

## Key Features

- **Agent-Oriented Design** - Built for AI agents to understand context and make intelligent decisions
- **Flexible Selectors** - Supports explicit selectors with fuzzy fallback matching
- **User Story Traceability** - Each SFS file maps to a user story (US-XXX-001) for coverage tracking
- **Natural Language Syntax** - Commands read like human actions
- **Multi-Environment Config** - Environment layering for CI/staging/local
- **Persona Management** - Define user roles with environment-specific credentials
- **Lifecycle Hooks** - Complete session orchestration (before/after session, before/after each)
- **Terminal Runner** - Interactive CLI testing with process management, stdin/stdout, key presses

## Installation

```bash
npm install @sfs/cli
```

Requires Node.js >= 18.0.0

## Quick Start

Initialize SFS in your project:

```bash
npx sfs init
```

This creates:
- `sfs.config.md` - Base configuration
- `example.sfs` - Example browser login flow
- `terminal-example.sfs` - Example terminal CLI test
- `.sfsignore` - Coverage scan exclusions

## CLI Commands

### Run SFS Flows

```bash
npx sfs run                           # Run all .sfs files
npx sfs run stories/US-SHOP-01a.sfs   # Run specific file
npx sfs run "stories/**/*.sfs"        # Run with glob pattern
npx sfs run --env ci                  # Use CI-specific config
npx sfs run --headed                  # Show browser GUI
npx sfs run --verbose                 # Verbose output
npx sfs run --shells bash,powershell  # Cross-shell terminal testing
```

### Validate Syntax

```bash
npx sfs validate stories/US-SHOP-01a.sfs
npx sfs validate "stories/**/*.sfs"
```

### Coverage Report

```bash
npx sfs coverage                              # Scan entire project, table output
npx sfs coverage -f json                      # JSON output for CI pipelines
npx sfs coverage -f summary                   # One-line summary
npx sfs coverage -s docs/stories              # Scan only docs/stories directory
npx sfs coverage --story-pattern "JIRA-\d+"   # Custom story ID pattern
```

By default, coverage scans the entire project (respecting `.sfsignore` exclusions). Use `--stories <dir>` to restrict scope.

## SFS File Syntax

```sfs
STORY       US-LOGIN-01a
ENTRYPOINT  http://localhost:3000
RUNNER      browser
LOCALE      en-US

HINT        Standard login form with email and password fields
ON FAILURE  capture screenshot and describe visible state

BEFORE THIS
  ASSERT port 3000 is open

--- page-load ---
OBSERVE login form is visible

--- enter-credentials ---
TYPE "testuser@example.com" INTO email field >> selector:testid:email-input
TYPE "password123" INTO password field >> selector:testid:password-input
CAPTURE before-submit

--- submit-login ---
CLICK login button >> selector:testid:login-btn
WAIT FOR url contains /dashboard

--- verify-dashboard ---
OBSERVE dashboard content is visible
OBSERVE logout button is visible

DONE WHEN user is logged in and dashboard is visible
```

### Terminal Runner Syntax

```sfs
STORY       CLI-WIZARD-01
ENTRYPOINT  ./my-project
RUNNER      terminal

HINT  CLI tool with interactive prompts

--- launch ---
RUN "node bin/create-app.js"
WAIT FOR "Project name:" in output

--- fill-name ---
TYPE "my-awesome-app"
PRESS Enter
WAIT FOR "Select template:" in output

--- select-template ---
PRESS ArrowDown
PRESS Enter
WAIT FOR process to exit

--- verify ---
READ exit code INTO $code
OBSERVE $code is 0

DONE WHEN project wizard completed successfully
```

### Command Reference

| Category | Commands |
|----------|----------|
| **Interactions** | `CLICK`, `TYPE`, `SELECT`, `DOUBLE CLICK`, `HOVER`, `SCROLL TO`, `UPLOAD`, `PRESS`, `CLEAR` |
| **Navigation** | `NAVIGATE TO`, `WAIT FOR` |
| **Observations** | `OBSERVE`, `CAPTURE`, `READ ... INTO $var` |
| **Tabs** | `TAB EXPECT NEW`, `TAB SWITCH TO`, `TAB CLOSE`, `TAB COUNT IS` |
| **Dialogs** | `ACCEPT DIALOG`, `DISMISS DIALOG` |
| **Terminal** | `RUN`, `RUN ... AS`, `STOP`, `SIGNAL`, `SESSION`, `SESSION COUNT IS` |
| **Assertions** | `ASSERT port`, `ASSERT env`, `ASSERT file` |

### Selectors

Commands support explicit selectors with fuzzy fallback:

```sfs
CLICK login button                                  # Fuzzy (agent resolves)
CLICK login button >> selector:testid:login-btn    # Explicit with fallback
CLICK login button >> selector:css:.btn-login      # CSS selector
CLICK login button >> selector:xpath://button[1]   # XPath selector
CLICK login button >> selector:text:Log In         # Text selector
```

## Configuration

### sfs.config.md

```markdown
# SFS Configuration

## Settings

| Setting | Value |
|---------|-------|
| ENTRYPOINT | http://localhost:3000 |
| LOCALE | en-US |
| TIMEOUT | 30s |
| ON FAILURE | capture screenshot |
| PRESERVE STATE ON FAILURE | true |

## Personas

| Persona | Username | Password | Description |
|---------|----------|----------|-------------|
| user | testuser@example.com | {{TEST_USER_PASSWORD}} | Standard user |
| admin | admin@example.com | {{ADMIN_PASSWORD}} | Administrator |
| guest | | | Unauthenticated |
```

### Terminal Config

Add a `## Terminal` section to configure terminal runner behavior:

```markdown
## Terminal

| Setting | Value |
|---------|-------|
| BACKEND | spawn |
| SHELL | bash |
| COLS | 120 |
| ROWS | 40 |
| DEFAULT_TIMEOUT | 30000 |
| STRIP_ANSI | true |
| SHELLS | bash, powershell |
```

### .sfsignore

Control which directories are excluded from coverage scanning:

```
# Comments start with #
node_modules
dist
build
vendor
*.log
docs/archive
```

Bare names auto-expand to glob patterns (e.g., `vendor` becomes `**/vendor/**`). Built-in defaults (`node_modules`, `.git`, `dist`, `build`, `coverage`) always apply.

### Story ID Pattern

Configure custom story ID patterns in `sfs.config.md`:

```markdown
| STORY_ID_PATTERN | JIRA-\d+ |
```

Or via CLI: `--story-pattern "JIRA-\d+"`

### Environment Layering

Configuration files are merged in order:

```
sfs.config.md           → Base configuration
sfs.config.{env}.md     → Environment-specific (ci, staging)
sfs.config.local.md     → Local overrides (gitignored)
```

## Project Structure

```
/stories/
  sfs.config.md              # Base config
  sfs.config.ci.md           # CI overrides
  sfs.config.local.md        # Local overrides (gitignored)

  US-SHOP-01/
    US-SHOP-01a.sfs          # Primary flow
    US-SHOP-01a.edge.sfs     # Edge cases

  /runs/                     # Test output (gitignored)
    2024-02-04T14-30-00/
      run.report.md
```

## Development

```bash
npm install          # Install dependencies
npm run dev          # Run in development
npm run build        # Build
npm test             # Run tests
npm run lint         # Lint
npm run format       # Format
```

### Pre-commit Checks

This project uses a Definition of Done (DoD) quality gate that runs before each commit. The checks include:

**Critical (must pass):** build, test, lint, format
**Warnings (informational):** longfiles, knip, seccheck, audit

Run checks manually with npm scripts:

```bash
npm run dod          # Run all checks (default)
npm run dod:all      # Run all checks (explicit)
npm run dod:core     # Run only critical checks (faster)
npm run dod:skip     # Skip all checks
```

Commit with check level control:

```bash
npm run commit:check -- -m "message"           # All checks (default)
npm run commit:check:all -- -m "message"       # All checks (explicit)
npm run commit:check:core -- -m "message"      # Core checks only
npm run commit:check:skip -- -m "message"      # Skip DoD checks
git commit --no-verify -m "message"            # Skip all hooks
```

## Documentation

- [SFS Language Specification](SFS-SPEC.md)
- [Configuration Specification](SFS-CONFIG-SPEC.md)

## License

MIT

For quetions / ideas contact amirtac@gmail.com