# `scripts` block

## Usage

The `scripts` block maps filesystem script paths to ops groups. It replaces `entrypoints` and generates standalone executables.

```ops
scripts = {
  bin/deploy: @release
  bin/lint: @lint
}
```

If the right-hand side omits a group, it defaults to **main**.

**Validation:** Bats tests covering `scripts` generation and wiring.

## Grammar

```
ScriptsBlock    = 'scripts' '=' '{' ScriptEntry* '}'
ScriptEntry     = SCRIPT_PATH ':' BlockRef
BlockRef        = '@' IDENT | IDENT
```

`entrypoints` is accepted as a **deprecated** alias of `scripts` (same shape), with a deprecation warning.

## IR representation

Canonical script field shape lives in [ir_schema](../ir_schema.md).

```json
{
  "role": "file",
  "payload": [
    { "role": "script", "name": "bin/deploy", "payload": "release" },
    { "role": "script", "name": "bin/lint", "payload": "lint" }
  ]
}
```

## Implementation

**Tier 8 — Scripts block & main keyword**

| Area | Responsibility |
|------|----------------|
| `ast.rs` | `TopLevel::ScriptsBlock` |
| `parser.rs` | Parse `scripts = { ... }`; warn on `entrypoints` |
| `lower.rs` | Lower `scripts` into `role: "script"` file objects |

## Design decisions

- **`scripts` vs `entrypoints`:** `scripts` is the canonical name; `entrypoints` remains temporarily for migration.
- **Default group:** Omitted explicit group in a script entry resolves to `main`.
- **Commas:** Bash output may require commas (`IFS=','`); the Rust parser treats commas as optional, whitespace-equivalent separators for a single canonical surface syntax.

## Caveats

- Comma handling differs between emitted bash and the Rust parser’s accepted input; tests should cover both styles if both are meant to be valid in source.

## Open questions

_None captured for this feature._
