saffron-ai 0.7.1 → 0.8.0
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/CHANGELOG.md +117 -1
- package/README.md +13 -10
- package/dist-pkg/cli.js +133 -118
- package/package.json +3 -3
- package/skills/saffron/SKILL.md +6 -3
- package/skills/saffron/references/config.md +5 -0
- package/skills/saffron/references/syntax.md +54 -0
- package/templates/saucedemo/data/catalog.json +11 -0
- package/templates/saucedemo/features/shopping.saffron +9 -0
- package/textmate/saffron/syntaxes/saffron.tmLanguage.json +7 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,122 @@ All notable changes to Saffron, in one place: the `saffron-ai` runner (npm),
|
|
|
4
4
|
the VS Code extension (`ChathurangaJayasinghe.saffron-vscode`) and the
|
|
5
5
|
JetBrains plugin (`ai.saffron.jetbrains`). Dates are publish dates.
|
|
6
6
|
|
|
7
|
+
## 0.8.0
|
|
8
|
+
|
|
9
|
+
Released 2026-09-21.
|
|
10
|
+
|
|
11
|
+
Test data moves out of the feature file: a `data/` folder, `{data:...}`
|
|
12
|
+
references, list checks, `Examples` from a file, values unique per run, and
|
|
13
|
+
data per environment.
|
|
14
|
+
|
|
15
|
+
Runner
|
|
16
|
+
|
|
17
|
+
- **Test data outside the feature file: `{data:file.key}`.** Put values in
|
|
18
|
+
JSON files under `data/` and reference them from a step, a table cell or
|
|
19
|
+
a doc string: `When I sign in as {data:users.admin.email}`. Same family
|
|
20
|
+
as `{env:VAR}`: the recording stores the token and replay reads the file,
|
|
21
|
+
so changing a value changes the next replay at zero tokens. A recording
|
|
22
|
+
that still spells out the old value goes stale instead of replaying
|
|
23
|
+
yesterday's data, and a missing file or key stops the run by name before
|
|
24
|
+
a browser opens. New config key `dataDir` (default `data`). Not for
|
|
25
|
+
secrets: data files are committed.
|
|
26
|
+
- **Check a whole list in one step.** `Then the status filter should list
|
|
27
|
+
every {data:enums.OrderStatus}` records ONE assertion (`expectEach`) that
|
|
28
|
+
names the list and its container. Replay reads the list from the file, so
|
|
29
|
+
a value added to the data is checked on the next run at zero tokens, and
|
|
30
|
+
a missing one fails by name with how many were found. Values match as
|
|
31
|
+
whole text ("Paid" is not "Unpaid"), extra entries such as "All" are
|
|
32
|
+
allowed, and a closed dropdown works.
|
|
33
|
+
- **`Examples` from a file**, in `.saffron` files: `Examples: {data:roles}`
|
|
34
|
+
reads `data/roles.csv` (header row = placeholders) or a JSON list of
|
|
35
|
+
records. One recording, one zero-token replay per row; a row added to the
|
|
36
|
+
file records nothing. A placeholder without a column, a missing file and a
|
|
37
|
+
`.feature` file using it are each parse errors that say what to do.
|
|
38
|
+
- **`{unique:name}`**: a value that is new on every run and the same within
|
|
39
|
+
one, for scenarios that create things. The agent types the generated
|
|
40
|
+
value while recording and Saffron turns it back into the token; a run that
|
|
41
|
+
is not green lists what each token stood for. `{unique:name:digits}` for
|
|
42
|
+
numeric fields.
|
|
43
|
+
- **Data per environment**: `--env staging` (or `SAFFRON_ENV`, or `env` in
|
|
44
|
+
the config) lays `data/users.staging.json` over `data/users.json`, key by
|
|
45
|
+
key. The reference in the step stays the same on every target.
|
|
46
|
+
- `saffron status --json` gains `data`: the folder, the environment, the
|
|
47
|
+
files, and references that do not resolve. `saffron lsp` completes
|
|
48
|
+
`{data:` paths, shows values on hover, jumps to the key and flags
|
|
49
|
+
unresolved references. The bundled grammar highlights `{data:...}` and
|
|
50
|
+
`{unique:...}`. `saffron init --examples` installs `data/catalog.json` and
|
|
51
|
+
a scenario that uses it, and the agent skill, its syntax reference and the
|
|
52
|
+
AGENTS.md block teach the new syntax.
|
|
53
|
+
|
|
54
|
+
- **`saffron prune` covers failure screenshots.** A deleted scenario also
|
|
55
|
+
leaves its screenshot folder behind under `.saffron/artifacts/`. Prune
|
|
56
|
+
lists those folders with the caches and proposals and removes them with
|
|
57
|
+
`--yes`; a live scenario's folder is kept, per Examples row. `saffron
|
|
58
|
+
status --json` reports them as orphans of kind `artifact`, and both IDE
|
|
59
|
+
panels (VS Code 0.2.6, JetBrains 0.2.3) show them.
|
|
60
|
+
|
|
61
|
+
## 0.7.2
|
|
62
|
+
|
|
63
|
+
Released 2026-09-21.
|
|
64
|
+
|
|
65
|
+
Runner
|
|
66
|
+
|
|
67
|
+
- **Failure screenshots.** When a step fails, Saffron saves a screenshot of
|
|
68
|
+
the tab it failed in and shows it in the HTML report, embedded so the
|
|
69
|
+
report stays one file. A healed scenario keeps the picture of the moment
|
|
70
|
+
its cached step stopped working, for whoever reviews the proposal; a
|
|
71
|
+
scenario still red after the agent ran is photographed again at the end.
|
|
72
|
+
`latest.json` carries the paths under `evidence`. New config key
|
|
73
|
+
`screenshot`: `viewport` (default), `full-page` or `off`. Files live in
|
|
74
|
+
`.saffron/artifacts/`, latest run only, and `saffron init` git-ignores
|
|
75
|
+
it: **add `.saffron/artifacts/` to your `.gitignore` if your project was
|
|
76
|
+
initialised earlier.** A screenshot shows whatever your page shows,
|
|
77
|
+
including a secret it displays; `{env:VAR}` masking cannot reach pixels.
|
|
78
|
+
|
|
79
|
+
- **A feature file that fails to parse says which file, and why.** Invalid
|
|
80
|
+
Gherkin reached the terminal as a raw stack trace with positions and no
|
|
81
|
+
file name. It is now one line per problem, `file:line:column`. A standard
|
|
82
|
+
`.feature` file that uses `StepSet` gets the actual answer instead of a
|
|
83
|
+
parser dump: rename it to `.saffron`, nothing else needs to change.
|
|
84
|
+
|
|
85
|
+
- `saffron status --json` gains `lastRun.attention`: every scenario of the
|
|
86
|
+
last run that was not green, red first, with the failed step, the first
|
|
87
|
+
line of the error and the screenshots that still exist on disk.
|
|
88
|
+
|
|
89
|
+
Editors (VS Code extension 0.2.6, JetBrains plugin 0.2.3)
|
|
90
|
+
|
|
91
|
+
- **`{data:...}` in the editor.** VS Code completes data files and keys with
|
|
92
|
+
their values, shows the current value (or a list's values, or an Examples
|
|
93
|
+
file's columns) on hover, jumps to the key, and underlines a reference
|
|
94
|
+
that does not resolve, reading the same files and environment overlay the
|
|
95
|
+
runner does. JetBrains gets the same through `saffron lsp`. Both highlight
|
|
96
|
+
`{data:...}` and `{unique:...}` like `{env:VAR}`, including on an
|
|
97
|
+
`Examples:` line.
|
|
98
|
+
- **Last run, with the screenshot one click away.** Both IDEs list what the
|
|
99
|
+
last run left to look at: failed scenarios, then healed ones, with the
|
|
100
|
+
step that failed. VS Code opens the screenshot in its image preview on
|
|
101
|
+
click; JetBrains opens it in the image viewer on double-click. Each also
|
|
102
|
+
jumps to the scenario. With a runner that predates failure screenshots,
|
|
103
|
+
both say so instead of reporting that everything passed.
|
|
104
|
+
|
|
105
|
+
Docs
|
|
106
|
+
|
|
107
|
+
- **A page for "`.saffron` and `.feature` files"**: what each is, a
|
|
108
|
+
side-by-side table, which to write, and what renaming a file means for its
|
|
109
|
+
recordings. The rest of the docs say "feature file" for both, where they
|
|
110
|
+
used to say `.feature` alone.
|
|
111
|
+
|
|
112
|
+
Editors (JetBrains plugin 0.2.2)
|
|
113
|
+
|
|
114
|
+
- **LSP4IJ is an optional dependency.** A first upload of 0.2.2 was rejected
|
|
115
|
+
by the Marketplace verifier on 2026.3 EAP because LSP4IJ had no release
|
|
116
|
+
for that build yet, and a mandatory dependency that cannot be resolved
|
|
117
|
+
blocks the whole plugin. Highlighting, run configurations and the tool
|
|
118
|
+
window now work without it; completion, go-to-definition, hover and
|
|
119
|
+
diagnostics switch on when LSP4IJ is installed, and a one-time
|
|
120
|
+
notification says so when it is missing. The presence check uses no
|
|
121
|
+
plugin-manager API, so it stays clean as that API turns internal.
|
|
122
|
+
|
|
7
123
|
## 0.7.1
|
|
8
124
|
|
|
9
125
|
Released 2026-09-20.
|
|
@@ -588,7 +704,7 @@ Released 2026-07-10.
|
|
|
588
704
|
First public release, free for any use under the Saffron Free Use License.
|
|
589
705
|
|
|
590
706
|
- Gherkin-native runner: an AI agent records each scenario once; later runs
|
|
591
|
-
|
|
707
|
+
are replayed by Saffron in a real browser at zero tokens; runtime healing files
|
|
592
708
|
reviewable proposals; assertions are never healed.
|
|
593
709
|
- Verified proposals (zero-AI proof replay), honest cost reporting, run
|
|
594
710
|
history and trends, chronic-scenario detection.
|
package/README.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
**Gherkin-native test runner with zero-token cached replay and runtime AI healing.**
|
|
4
4
|
|
|
5
|
-
Free to use · [npm: saffron-ai](https://www.npmjs.com/package/saffron-ai) · [site](https://saffron-ai.
|
|
5
|
+
Free to use · [npm: saffron-ai](https://www.npmjs.com/package/saffron-ai) · [site](https://saffron-ai.io)
|
|
6
6
|
|
|
7
|
-
Write tests as
|
|
7
|
+
Write tests as Gherkin feature files: `.saffron`, Saffron's superset of Gherkin with step sets, or standard `.feature`. 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, Saffron replays the cache in a real browser: **zero AI calls, zero tokens**, at the speed of the browser and your app. The cache is Saffron's own JSON, not a generated script; replay runs on Playwright's browser engine, and Playwright MCP is only how the agent operates the browser while it records or heals.
|
|
8
8
|
|
|
9
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
|
|
|
@@ -13,7 +13,7 @@ When the UI changes and a cached step fails at runtime, the agent takes over mid
|
|
|
13
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, including a suggested
|
|
16
|
+
- **Caches are git artifacts.** Proposals show diffs, including a suggested feature-file 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
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, and name the models used. On an API key the dollars are what was billed; on a Claude subscription the headline is the 5-hour plan window before and after the run, with the dollars as the API-equivalent.
|
|
19
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.
|
|
@@ -89,9 +89,11 @@ Configuration lives in `saffron.config.json` at your project root:
|
|
|
89
89
|
{
|
|
90
90
|
"baseURL": "http://localhost:4173",
|
|
91
91
|
"features": "features",
|
|
92
|
+
"dataDir": "data",
|
|
92
93
|
"actionTimeoutMs": 5000,
|
|
93
94
|
"pollIntervalMs": 100,
|
|
94
95
|
"retries": 1,
|
|
96
|
+
"screenshot": "viewport",
|
|
95
97
|
"model": "claude-sonnet-5",
|
|
96
98
|
"maxTurns": 100,
|
|
97
99
|
"storageState": ".auth/state.json",
|
|
@@ -113,7 +115,7 @@ cached replays *and* the agent start authenticated. Generate one with
|
|
|
113
115
|
|
|
114
116
|
## How it works
|
|
115
117
|
|
|
116
|
-
The full execution-model diagram is on the site: https://saffron-ai.
|
|
118
|
+
The full execution-model diagram is on the site: https://saffron-ai.io/docs
|
|
117
119
|
|
|
118
120
|
- 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.
|
|
119
121
|
- 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, and multi-tab scenarios are plain prose ("switch back to the first tab", "close the preview tab", "open a new tab at …") recorded as tab actions; 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.
|
|
@@ -128,12 +130,13 @@ The full execution-model diagram is on the site: https://saffron-ai.lovable.app/
|
|
|
128
130
|
proposals/ pending AI-generated cache updates (review these)
|
|
129
131
|
history.jsonl one line per run: trends (commit recommended)
|
|
130
132
|
reports/ latest.html / latest.json (gitignore these)
|
|
131
|
-
|
|
133
|
+
artifacts/ failure screenshots from the latest run (gitignore these)
|
|
134
|
+
features/ your .saffron and .feature files
|
|
132
135
|
```
|
|
133
136
|
|
|
134
137
|
## Roadmap
|
|
135
138
|
|
|
136
|
-
See the roadmap on **[the site](https://saffron-ai.
|
|
139
|
+
See the roadmap on **[the site](https://saffron-ai.io/#roadmap)**, the single source of truth for
|
|
137
140
|
milestones, statuses, and decision gates. Headlines:
|
|
138
141
|
action-vocabulary additions as real-world failures surface them, the
|
|
139
142
|
Level-2 shared step library (gated on Level-1 divergence data), LLM-less
|
|
@@ -143,10 +146,10 @@ far is in the roadmap's "Where we are" table.
|
|
|
143
146
|
|
|
144
147
|
## Documentation
|
|
145
148
|
|
|
146
|
-
- [Website](https://saffron-ai.
|
|
147
|
-
- [Documentation](https://saffron-ai.
|
|
148
|
-
- [Changelog](CHANGELOG.md), also at https://saffron-ai.
|
|
149
|
-
- [Issues & questions](https://github.com/s-chathuranga-j/saffron-
|
|
149
|
+
- [Website](https://saffron-ai.io): what Saffron is, the honesty rules, economics, quickstart
|
|
150
|
+
- [Documentation](https://saffron-ai.io/docs): the cache lifecycle, step sets & the `.saffron` dialect, the step vocabulary, and the guarantees, with diagrams
|
|
151
|
+
- [Changelog](CHANGELOG.md), also at https://saffron-ai.io/docs/changelog
|
|
152
|
+
- [Issues & questions](https://github.com/s-chathuranga-j/saffron-community/issues)
|
|
150
153
|
- **Docs site**: `npm run docs` builds a self-contained page at
|
|
151
154
|
## License
|
|
152
155
|
|