saffron-ai 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -22
- package/dist-pkg/cli.js +64 -63
- package/package.json +2 -1
- package/skills/saffron/SKILL.md +16 -16
- package/skills/saffron/references/config.md +5 -5
- package/skills/saffron/references/syntax.md +5 -5
- package/textmate/saffron/language-configuration.json +16 -0
- package/textmate/saffron/package.json +31 -0
- package/textmate/saffron/syntaxes/saffron.tmLanguage.json +127 -0
package/README.md
CHANGED
|
@@ -4,29 +4,29 @@
|
|
|
4
4
|
|
|
5
5
|
Free to use · [npm: saffron-ai](https://www.npmjs.com/package/saffron-ai) · [site](https://saffron-ai.lovable.app)
|
|
6
6
|
|
|
7
|
-
Write tests as plain `.feature` files. On the first run, an AI agent (Claude Agent SDK + Playwright MCP) executes each scenario in a real browser and records what it did into a **cache
|
|
7
|
+
Write tests as plain `.feature` files. On the first run, an AI agent (Claude Agent SDK + Playwright MCP) executes each scenario in a real browser and records what it did into a **cache**. A human-reviewable JSON action list committed to git. Every run after that replays the cache with plain Playwright: **zero AI calls, zero tokens, ~100ms per scenario**.
|
|
8
8
|
|
|
9
|
-
When the UI changes and a cached step fails at runtime, the agent takes over mid-execution with full scenario context, adapts, and finishes the run
|
|
9
|
+
When the UI changes and a cached step fails at runtime, the agent takes over mid-execution with full scenario context, adapts, and finishes the run, then files a **cache proposal** you accept or reject, like a snapshot test update. Reports state exactly what was adapted and what it cost.
|
|
10
10
|
|
|
11
11
|
## The rules that keep it honest
|
|
12
12
|
|
|
13
|
-
- **Assertions are sacred.** By default no `Then` is ever healed
|
|
13
|
+
- **Assertions are sacred.** By default no `Then` is ever healed: the AI may help *reach* an assertion, never make it pass; enforced mechanically, not by prompt. Projects may opt into `adaptable-mid` for mid-scenario checkpoints, but the **final assertion block** of a scenario is strict under every policy, forever.
|
|
14
14
|
- **Three result states.** Green = cached pass. Yellow = passed with AI adaptation (pending your review). Red = failed.
|
|
15
15
|
- **Diagnose before adapting.** On a step failure the agent first decides: UI drift (heal) or application defect (fail with a diagnosis).
|
|
16
|
-
- **Caches are git artifacts.** Proposals show diffs
|
|
16
|
+
- **Caches are git artifacts.** Proposals show diffs, including a suggested `.feature` edit when the written steps no longer match reality, and nothing is committed without you.
|
|
17
17
|
- **Verified proposals.** Every recording/heal is proof-replayed zero-AI before it's filed (with one bounded refinement pass on failure), so proposals arrive stamped `verified ✓` or honestly `UNVERIFIED ✗`.
|
|
18
|
-
- **Honest cost reporting.** Reports break out prompt-cache reads/writes
|
|
19
|
-
- **Trend memory.** Every run appends to `.saffron/history.jsonl`; reports show deltas vs the previous run and 20-run sparklines, and Saffron flags **chronic scenarios** (healing repeatedly
|
|
18
|
+
- **Honest cost reporting.** Reports break out prompt-cache reads/writes (the real bill of agent sessions) next to the in+out token count, per scenario and in totals.
|
|
19
|
+
- **Trend memory.** Every run appends to `.saffron/history.jsonl`; reports show deltas vs the previous run and 20-run sparklines, and Saffron flags **chronic scenarios** (healing repeatedly. Re-record instead of paying again) plus recurring failure themes.
|
|
20
20
|
|
|
21
21
|
## Step reuse: new scenarios get cheaper as your suite grows
|
|
22
22
|
|
|
23
|
-
Like a maturing Cucumber suite, most of a new feature file is steps you already have. Saffron derives a **step index** from committed caches and, when recording a new scenario, replays every seeded island of known steps zero-AI
|
|
23
|
+
Like a maturing Cucumber suite, most of a new feature file is steps you already have. Saffron derives a **step index** from committed caches and, when recording a new scenario, replays every seeded island of known steps zero-AI. The agent records only the genuinely novel steps, wherever they sit. Exact step text is the identity (Cucumber-style); quoted values may differ (`"admin"` seeds from `"bob"`); data-table steps seed on matching keys. Measured on a live site: a 6-step scenario with one novel step recorded for **$0.15 / 6 AI calls**, vs $2.07 for a full unseeded recording of comparable length.
|
|
24
24
|
|
|
25
|
-
**Step sets** (shipped): `.saffron` files
|
|
25
|
+
**Step sets** (shipped): `.saffron` files, a superset dialect of Gherkin, add the `StepSet:` keyword for named, reusable step sequences invoked with `StepSet <name>` inside any scenario. Sets expand at parse time, so their steps cache and seed like ordinary steps; editing a set makes every invoking scenario honestly stale (re-recorded mostly seeded), and heal edits route to the set definition, one fix, every caller follows. Sets are **project-wide**: keep application-wide flows in a sets-only library file (convention: `features/shared.steps.saffron`) and invoke them from any feature.
|
|
26
26
|
|
|
27
|
-
**IDE integration & authoring** (shipped): `saffron steps` lists the project vocabulary with recorded/divergent/unrecorded badges (`--snippets` for native VS Code completion), `saffron mcp` serves it to AI assistants, `saffron lsp` brings completion/navigation/diagnostics to **JetBrains** (incl. Community editions via LSP4IJ) and Neovim, `saffron author` drafts feature files from prose in your own vocabulary, and duplicate wordings that record identical actions get **behavior-proven rename proposals**. The **Saffron VS Code extension** is on the [Marketplace](https://marketplace.visualstudio.com/items?itemName=ChathurangaJayasinghe.saffron-vscode) (`code --install-extension ChathurangaJayasinghe.saffron-vscode`).
|
|
27
|
+
**IDE integration & authoring** (shipped): `saffron steps` lists the project vocabulary with recorded/divergent/unrecorded badges (`--snippets` for native VS Code completion), `saffron mcp` serves it to AI assistants, `saffron lsp` brings completion/navigation/diagnostics to **JetBrains** (incl. Community editions via LSP4IJ) and Neovim, `saffron author` drafts feature files from prose in your own vocabulary, and duplicate wordings that record identical actions get **behavior-proven rename proposals**. The **Saffron VS Code extension** is on the [Marketplace](https://marketplace.visualstudio.com/items?itemName=ChathurangaJayasinghe.saffron-vscode) (`code --install-extension ChathurangaJayasinghe.saffron-vscode`). JetBrains users get the same in one click from the **Saffron JetBrains plugin** (sibling repo `saffron-jetbrains`: `.saffron` file type, bundled grammar, LSP4IJ wiring; Marketplace listing pending).
|
|
28
28
|
|
|
29
|
-
Data tables and doc strings are first-class: 2-column key/value tables parameterize the recording (`<table:username>`), multi-row record tables parameterize per cell (`<table:1:firstName>`), and `"""` doc strings record as `<docstring
|
|
29
|
+
Data tables and doc strings are first-class: 2-column key/value tables parameterize the recording (`<table:username>`), multi-row record tables parameterize per cell (`<table:1:firstName>`), and `"""` doc strings record as `<docstring>`, so editing *values* or *content* replays at zero tokens, while structural changes (keys, headers, row counts) honestly re-record. Unambiguous params are scenario-wide, so a later assertion on a note's text follows content edits too. **Secrets** stay out of everything: `{env:VAR}` resolves from the environment (or a git-ignored `.env`) at replay, recordings and reports are masked back to the token, and missing variables fail fast by name.
|
|
30
30
|
|
|
31
31
|
## Install
|
|
32
32
|
|
|
@@ -37,10 +37,10 @@ npx saffron init # config + the Saffron agent skill for your AI assistant
|
|
|
37
37
|
npx saffron run
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
**Built for the AI era:** the package ships an [Agent Skill](https://agentskills.io) that teaches Claude Code, Codex, Cursor, Copilot and any skill-aware agent to write Saffron tests efficiently
|
|
40
|
+
**Built for the AI era:** the package ships an [Agent Skill](https://agentskills.io) that teaches Claude Code, Codex, Cursor, Copilot and any skill-aware agent to write Saffron tests efficiently. Reuse recorded wordings, keep assertions sacred, secrets as `{env:VAR}`, so the tests your agents write replay at zero tokens instead of paying for near-duplicate recordings.
|
|
41
41
|
|
|
42
42
|
CI tip: `saffron run --strict` treats yellow (passed-with-adaptation) as a
|
|
43
|
-
failure until its cache proposal is reviewed
|
|
43
|
+
failure until its cache proposal is reviewed: cached-green-only builds.
|
|
44
44
|
|
|
45
45
|
## Quick start (this repo)
|
|
46
46
|
|
|
@@ -52,7 +52,7 @@ npx playwright install chromium
|
|
|
52
52
|
# start the demo app
|
|
53
53
|
node examples/demo-app/server.mjs 4173 &
|
|
54
54
|
|
|
55
|
-
# replay the example suite from its committed caches
|
|
55
|
+
# replay the example suite from its committed caches, zero AI
|
|
56
56
|
node dist/cli/index.js -p examples run
|
|
57
57
|
|
|
58
58
|
# delete a cache and watch the agent re-record it (needs Claude Code auth
|
|
@@ -67,12 +67,12 @@ node dist/cli/index.js -p examples accept --all
|
|
|
67
67
|
| Command | What it does |
|
|
68
68
|
|---|---|
|
|
69
69
|
| `saffron run [paths] [--headed] [--filter @tags] [--no-agent] [--strict] [--browser b] [--workers n] [--heal-model m] [--no-verify] [--no-reuse] [--model m] [--storage-state f]` | Run features. Cached replays are deterministic; misses/failures escalate to the agent (unless `--no-agent`). Replay cross-browser with `--browser firefox\|webkit`, parallelize with `--workers N`, heal on a cheaper model with `--heal-model`. Exit 1 on red (and on yellow with `--strict`). |
|
|
70
|
-
| `saffron accept [file \| --all] [--with-feature-edit] [--propagate]` | Promote cache proposals to committed caches; `--with-feature-edit` also rewrites the adapted steps in the `.feature` file (and keeps the cache in sync); `--propagate` applies the heal's locator fixes to every other cache using the same locator
|
|
70
|
+
| `saffron accept [file \| --all] [--with-feature-edit] [--propagate]` | Promote cache proposals to committed caches; `--with-feature-edit` also rewrites the adapted steps in the `.feature` file (and keeps the cache in sync); `--propagate` applies the heal's locator fixes to every other cache using the same locator. One heal repairs N scenarios before they ever fail. No args: list pending proposals. |
|
|
71
71
|
| `saffron reject [file \| --all]` | Discard proposals; the agent will try again next run. |
|
|
72
72
|
| `saffron steps [search] [--json] [--snippets]` | List/search the step vocabulary (files + caches) with recorded/divergent/unrecorded badges and usage; `--snippets` writes `.vscode/saffron.code-snippets` for native VS Code completion. |
|
|
73
|
-
| `saffron mcp` | Serve the vocabulary to AI assistants over stdio MCP (`search_steps`, `list_step_sets`)
|
|
73
|
+
| `saffron mcp` | Serve the vocabulary to AI assistants over stdio MCP (`search_steps`, `list_step_sets`), e.g. `claude mcp add saffron -- npx saffron mcp`. |
|
|
74
74
|
| `saffron author <prose-file> [-o out]` | Draft a `.saffron` feature file from plain-paragraph requirements, reusing the project's step vocabulary (AI; reports how many lines are seedable). |
|
|
75
|
-
| `saffron lsp` | Run the Saffron language server over stdio
|
|
75
|
+
| `saffron lsp` | Run the Saffron language server over stdio for JetBrains (LSP4IJ/Ultimate), Neovim, any LSP editor: badge completion, StepSet go-to-definition, hover, diagnostics. Highlighting for JetBrains comes from the bundled TextMate grammar (`textmate/saffron` in the package); run `npx saffron lsp` in a terminal for setup steps. |
|
|
76
76
|
| `saffron init [--agents list]` | Make the project agent-ready: installs the bundled **Saffron agent skill** into `.claude/skills` and `.agents/skills` (Copilot/Cursor via `--agents`), registers the `saffron mcp` server in `.mcp.json` / `.cursor/mcp.json` / `.vscode/mcp.json`, adds a managed block to `AGENTS.md`/`CLAUDE.md`, scaffolds config. |
|
|
77
77
|
| `saffron report` | Open the latest HTML report. |
|
|
78
78
|
|
|
@@ -108,7 +108,7 @@ cached replays *and* the agent start authenticated. Generate one with
|
|
|
108
108
|
The full execution-model diagram is on the site: https://saffron-ai.lovable.app/docs
|
|
109
109
|
|
|
110
110
|
- Caches store per-step action lists with semantic targets (`role` + accessible name, `nameRegex` for volatile labels, CSS fallbacks) and `<param>` placeholders, so one cache serves every Examples row of a Scenario Outline.
|
|
111
|
-
- Dynamic-content vocabulary for real-world apps: `captureText` stores displayed values (prices, counters) under a name; `expectDiffers` compares against captured values; `expectMatches`/`expectAttribute` assert patterns instead of literals; `{date±N}` templates keep date-picker locators valid across days; the replayer follows links that open new tabs; native dialogs, file uploads, drag-and-drop, and iframe-scoped elements replay on all three engines; network-aware steps wait on or assert backend API responses (`waitForResponse` / sacred `expectResponse`) with URL/method/status/body matchers
|
|
111
|
+
- Dynamic-content vocabulary for real-world apps: `captureText` stores displayed values (prices, counters) under a name; `expectDiffers` compares against captured values; `expectMatches`/`expectAttribute` assert patterns instead of literals; `{date±N}` templates keep date-picker locators valid across days; the replayer follows links that open new tabs; native dialogs, file uploads, drag-and-drop, and iframe-scoped elements replay on all three engines; network-aware steps wait on or assert backend API responses (`waitForResponse` / sacred `expectResponse`) with URL/method/status/body matchers, "wait for the order API to return 201" instead of a sleep.
|
|
112
112
|
- The agent and the replayer share one browser over CDP, so healing continues from the exact page state where replay failed.
|
|
113
113
|
- Every recorded action carries a page fingerprint (hash of the normalized aria snapshot) for token-free drift detection.
|
|
114
114
|
|
|
@@ -118,14 +118,14 @@ The full execution-model diagram is on the site: https://saffron-ai.lovable.app/
|
|
|
118
118
|
.saffron/
|
|
119
119
|
cache/ committed replay caches (commit these)
|
|
120
120
|
proposals/ pending AI-generated cache updates (review these)
|
|
121
|
-
history.jsonl one line per run
|
|
121
|
+
history.jsonl one line per run: trends (commit recommended)
|
|
122
122
|
reports/ latest.html / latest.json (gitignore these)
|
|
123
123
|
features/ your .feature files
|
|
124
124
|
```
|
|
125
125
|
|
|
126
126
|
## Roadmap
|
|
127
127
|
|
|
128
|
-
See the roadmap on **[the site](https://saffron-ai.lovable.app/#roadmap)
|
|
128
|
+
See the roadmap on **[the site](https://saffron-ai.lovable.app/#roadmap)**, the single source of truth for
|
|
129
129
|
milestones, statuses, and decision gates. Headlines:
|
|
130
130
|
action-vocabulary additions as real-world failures surface them, the
|
|
131
131
|
Level-2 shared step library (gated on Level-1 divergence data), LLM-less
|
|
@@ -135,10 +135,10 @@ far is in the roadmap's "Where we are" table.
|
|
|
135
135
|
|
|
136
136
|
## Documentation
|
|
137
137
|
|
|
138
|
-
- [Website](https://saffron-ai.lovable.app)
|
|
139
|
-
- [Documentation](https://saffron-ai.lovable.app/docs)
|
|
138
|
+
- [Website](https://saffron-ai.lovable.app): what Saffron is, the honesty rules, economics, quickstart
|
|
139
|
+
- [Documentation](https://saffron-ai.lovable.app/docs): the cache lifecycle, step sets & the `.saffron` dialect, the step vocabulary, and the guarantees, with diagrams
|
|
140
140
|
- [Issues & questions](https://github.com/s-chathuranga-j/saffron-ai/issues)
|
|
141
141
|
- **Docs site**: `npm run docs` builds a self-contained page at
|
|
142
142
|
## License
|
|
143
143
|
|
|
144
|
-
Free to use
|
|
144
|
+
Free to use, including commercially, under the Saffron Free Use License (see LICENSE). The source opens up later; a CLA will accompany that step.
|