saffron-ai 0.9.7 → 0.9.9

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 CHANGED
@@ -5,6 +5,223 @@ the VS Code extension (`ChathurangaJayasinghe.saffron-vscode`) and the
5
5
  JetBrains plugin (`ai.saffron.jetbrains`). Dates are publish dates. Each
6
6
  release heading names its main feature: `## <version>: <title>`.
7
7
 
8
+ ## 0.9.9: A browser matrix in one run
9
+
10
+ Released 2026-10-06.
11
+
12
+ Runner
13
+
14
+ - **A browser matrix in one run.** `saffron run --browser
15
+ chromium,firefox,webkit` (or a list in `browser`) runs the suite in each
16
+ browser, one after another, into one report: a row per scenario per
17
+ browser, in the terminal, the report, the history and the dashboard.
18
+ Chromium-family browsers go first, so Firefox and WebKit replay what
19
+ they recorded. Every browser starts before anything runs. Screenshots
20
+ and traces are kept per browser, and `saffron trace` names them
21
+ `feature:scenario@browser`. The dashboard stands a scenario at its
22
+ worst browser and never calls a difference between browsers flaky.
23
+ Refused with `--shard`. Every result now names its browser, so running
24
+ one browser again replaces that browser's rows and keeps the others'.
25
+ `saffron status --json` (and the MCP `project_status` tool) names the
26
+ browser of each row that needs attention.
27
+ - **Device and viewport profiles.** `--device "iPhone 15"` (config
28
+ `device`) runs every scenario under a Playwright device profile,
29
+ recordings and heals included; `--viewport 1280x720` (config `viewport`)
30
+ sets the size alone. An unknown device names the closest ones, and a
31
+ mobile profile in Firefox stops the run up front.
32
+ - **Parallel recording and healing.** `--agent-workers N` (config
33
+ `agentWorkers`, default 1) lets up to N agent sessions run at once,
34
+ each in a browser of its own. An outline's rows stay together on one
35
+ worker. Each session is paid for: raise it deliberately.
36
+ - **Shards know their browser.** A shard records the browser it ran in;
37
+ `saffron report --merge` refuses shards of different browsers, a
38
+ re-run attempt replaces only its own browser's shard, and each
39
+ browser's merge keeps its own history line.
40
+ - **A bad storage state stops the run first.** A `storageState` file that
41
+ is missing, unreadable or not JSON now stops the run at startup, exit 2,
42
+ before `--rerecord` deletes any recording.
43
+ - **No second replay without an agent.** With `--workers` and
44
+ `--no-agent`, or in Firefox and WebKit, a scenario that went red in the
45
+ parallel phase is no longer run again afterwards: nothing could change
46
+ its result.
47
+ - **Per-worker timing.** The report has a timing panel (each worker's
48
+ runs, busy time and share, and the five slowest scenarios), and the
49
+ terminal prints each worker's share and the three slowest scenarios.
50
+ Merged shards list each machine's workers.
51
+ - **Saffron's own data in the replay.** Each step shows the tabs it
52
+ opened or switched to and the response each network check matched,
53
+ and the Saffron pane shows what the agent cost for the scenario. The
54
+ report's steps carry `tabs` and `responses` for tools.
55
+ - **Browsers in the editors' contracts.** `saffron status --json` and
56
+ `saffron report --run <id> --json` give each row its `browser`, and the
57
+ run's `browsers` when its rows span several.
58
+
59
+ VS Code extension 0.6.2
60
+
61
+ - After a browser-matrix run, Last Run and a CI run's results label each
62
+ row with its browser, and Open Replay and Open Trace open that
63
+ browser's execution alone (`feature:scenario@browser`).
64
+
65
+ JetBrains plugin 0.6.2
66
+
67
+ - The same in the Last Run and CI Runs tabs: rows say their browser, and
68
+ the replay opens that browser's execution alone.
69
+
70
+ ## 0.9.8: Run one scenario, from the editor too
71
+
72
+ Released 2026-10-06.
73
+
74
+ Behaviour changes
75
+
76
+ - **Tags now apply as in Cucumber**: a Feature's and a Rule's tags to
77
+ every scenario in it, an Examples block's to its rows. A CI filter can
78
+ select differently than before: `not @ignore` with `@ignore` on a
79
+ Feature now skips that feature, and `--filter @smoke` with a
80
+ Feature-level `@smoke` now takes all of its scenarios. Check your
81
+ `--filter` expressions when you upgrade. The dashboard's results per tag
82
+ and the IDEs' Tags tabs count the inherited tags too.
83
+
84
+ Runner
85
+
86
+ - **Run one scenario by its line or its name.** `saffron run
87
+ features/login.saffron:12` runs the scenario that line is in,
88
+ Cucumber-style: its Scenario line, a tag above it or any line inside it.
89
+ An Examples row runs that row alone, any other line of an outline runs
90
+ every row, and `:12:30` names two. `features/login.saffron:Successful
91
+ login` names it instead, which stays true while the file is edited,
92
+ and `:Roles (example 2)` one Examples row, as `saffron trace` lists it. A
93
+ line no scenario owns (the feature's header, a Background, a StepSet, a
94
+ Rule's header, past the end), a name no scenario has, or an outline
95
+ whose Examples have no rows yet stops the run with exit 2 and says
96
+ what is there. Works with `--filter`, `--shard` and `--rerecord`.
97
+ - **Tags on a Feature, a Rule or an Examples block apply to what they
98
+ hold**, as in Cucumber: `--filter @smoke` takes a feature tagged
99
+ `@smoke`, and `not @wip` leaves out a Rule's scenarios, or an Examples
100
+ block's rows, tagged `@wip`. Reports, history and the IDEs' tag lists
101
+ carry them; a scenario lists every row's tags.
102
+ - **A scenario whose own name ends in "(example N)" keeps its results.**
103
+ Report and history rows now carry the scenario's name; an older row is
104
+ read as a scenario of that exact name first, and as an outline's row
105
+ only when no such scenario exists, in status, the dashboard and CI
106
+ results alike.
107
+ - **A run that writes an outline's recording runs every row of it**
108
+ (`--rerecord`, or an outline not recorded yet or whose recording is
109
+ stale), also rows an Examples line or a `--filter` on Examples tags left
110
+ out: the rows share one recording. A row asked for records first and
111
+ the others replay the new recording in the same run, so one that fits
112
+ only that row comes back red, not as a proposal.
113
+ - **The dashboard keeps each Examples row's latest result** from whichever
114
+ run ran it: a run that left a row out (a tag filter, a named run) no
115
+ longer clears that row's failure; a row removed from the table stops
116
+ counting.
117
+ - **A run of named scenarios is not a suite run.** Its results replace
118
+ those scenarios' own in the last report, beside the rest of the last
119
+ run, and the report takes the run's own times and hook results. Its history line is
120
+ marked partial: the dashboard counts it for those scenarios (their
121
+ latest result, never run, recent failures), while trends, the pass-rate
122
+ series, the last run's figures and the next run's comparison count runs
123
+ of the suite only. A last report that was imported from CI, for another
124
+ base URL or billed another way (subscription or API key) is replaced,
125
+ and the run says so. Sharded, such a run merges the same way.
126
+ - **Two scenarios of one name in one file stop the run**, as any two
127
+ scenarios sharing a recording do: one per Rule was allowed, and each
128
+ overwrote the other's recording. The check now reads the configured
129
+ `features` folder, not only `features/`, and always the files the run
130
+ names.
131
+ - **One pass rate everywhere.** The run report, the trends and `saffron
132
+ status --json` (a new `passRate` per run) leave out a heal whose proof
133
+ replay failed, as the dashboard already did: the same run no longer
134
+ reads 100% in the report and 0% on the dashboard.
135
+ - **History written on Windows counts on the dashboard.** A history line
136
+ naming `features\login.saffron` is the same feature as
137
+ `features/login.saffron`, so its scenarios keep their latest result and
138
+ recent failures instead of reading as never run.
139
+ - **A refused run deletes no recording.** `--rerecord` removes recordings
140
+ only when the scenarios are about to run: a run stopped first (a cache
141
+ collision, an `{env:...}` or `{data:...}` reference, an invalid
142
+ `--trace`, `--browser` or `--assertion-policy`, a failed setup hook, a
143
+ missing browser) keeps them.
144
+ - **A path that does not exist stops the run.** `saffron run
145
+ features/chekout.saffron` (a typo) exits 2 naming it, instead of
146
+ running the other paths alone.
147
+ - **Run lenses from the language server**, for an editor that asks for
148
+ them (`initializationOptions.runLenses`). `saffron lsp` puts Run, Replay
149
+ only and Headed above each scenario, in the file's own Gherkin
150
+ language, each carrying the scenario's `file:name` and the project to
151
+ run it in. A `.feature` file outside a Saffron project gets none, and
152
+ neither does a file outside the editor's workspace, so a lens never runs
153
+ anywhere the user did not open (such a file keeps its own project's
154
+ completion and diagnostics). A scenario named like lines (`42`,
155
+ `10:30`) is targeted by its line. The JetBrains plugin also refuses a
156
+ lens whose folder is outside the IDE project.
157
+ - `saffron status --json` gives each scenario's line from the parsed file:
158
+ right in another Gherkin language, and never a `Scenario:` line inside a
159
+ doc string.
160
+ - **Open Trace on a CI run works from the editors again.** `saffron trace
161
+ --run <id>` takes `--max-download <MB>`, as the JetBrains plugin passes
162
+ it, and refuses a larger download exactly as `report --run` does: exit
163
+ 2, and with `--json` the same `kind: "too-large"` and `sizeBytes`.
164
+ - **Two editors can load one CI run at once.** Each request downloads
165
+ into its own temporary folder beside `.saffron/ci/<provider>-<id>/`, so
166
+ one never deletes another's download. When another request finished
167
+ first, Saffron uses its folder, checked as a cached one is, and removes
168
+ its own. A finished download removes only earlier attempts of the run,
169
+ never a later attempt or another request's download in progress; what
170
+ a killed download left (0.9.7's `.partial`, or a folder untouched for a
171
+ day) goes.
172
+ - **`--max-download` covers everything downloaded.** Saffron reads every
173
+ page of a GitHub run's artifacts, not just the first 100, and downloads
174
+ exactly the `saffron-bundle*` artifacts it sized, one by one by name, on
175
+ GitHub and Azure. An artifact whose name it does not accept is neither
176
+ counted nor downloaded.
177
+ - **Doc strings in `.saffron` files stay as written.** A line such as
178
+ `StepSet: sample` or `StepSet sample` inside a `"""` or ```` ``` ````
179
+ doc string is literal test data now, no longer read as a step set
180
+ definition or call.
181
+
182
+ VS Code extension 0.6.1
183
+
184
+ - **Health's pass rate of recent runs** is the runner's (saffron-ai 0.9.8
185
+ or later): a heal whose proof failed does not pass.
186
+ - **Open Report and Open Trace on a CI run keep `saffron.ciMaxDownloadMB`**
187
+ when the run's results are no longer on disk (trace with saffron-ai
188
+ 0.9.8 or later).
189
+ - **Run, Replay only and Headed above each scenario.** A click runs that
190
+ scenario alone, by name (`saffron run <file>:<name>`), as a task in the
191
+ project that owns the file. The file is saved first, and the panel's
192
+ replay-only and headed toggles apply as they do to every run. Lenses
193
+ and the side panel find scenarios in the file's own Gherkin language
194
+ (`# language:`), nameless ones too. Needs saffron-ai 0.9.8 or later; with
195
+ an older one in the project a click says so.
196
+ - **A CI run's yellow results read "pending review", not "healed".**
197
+ Yellow also covers first recordings and proposals not yet verified.
198
+ - **Each yellow or red CI scenario says whether the run verified it**:
199
+ "unverified" or "verified", and nothing when the run does not say.
200
+
201
+ JetBrains plugin 0.6.1
202
+
203
+ - **Health's pass rate of recent runs** is the runner's (saffron-ai 0.9.8
204
+ or later): a heal whose proof failed does not pass.
205
+ - **Run, Replay only and Headed above each scenario**, with LSP4IJ
206
+ installed. A click saves the files and runs that scenario alone, by
207
+ name, through a temporary run configuration made for it, so the run
208
+ widget runs it again. A saved configuration of the same name is left as
209
+ it is, and nothing from the Saffron template carries in, and a scenario
210
+ of the same name in another file gets its own. The lenses work while the
211
+ IDE indexes, and say when the project's saffron-ai is too old.
212
+ - **Right-click Run inside a scenario** runs that scenario alone, with or
213
+ without LSP4IJ, never reusing a lens's Replay only or Headed
214
+ configuration; outside one, or in a file in another Gherkin language,
215
+ it runs the whole file, as before. Both need saffron-ai 0.9.8 or later.
216
+ - **Open Trace works with every runner and keeps the download limit.**
217
+ With saffron-ai 0.9.8 it passes `--max-download` to `saffron trace`,
218
+ which downloads a run no longer on disk; with 0.9.7, which rejects the
219
+ option, it leaves it out.
220
+ - **Open Trace finds a Scenario Outline's example row** ("Login (example
221
+ 1)") by the name the run shows.
222
+ - **CI yellow results read "pending review", not "healed"**, and each
223
+ scenario says "unverified" or "verified" when the run reports it.
224
+
8
225
  ## 0.9.7: CI results without importing
9
226
 
10
227
  Released 2026-10-05.
package/README.md CHANGED
@@ -73,7 +73,7 @@ node dist/cli/index.js -p examples accept --all
73
73
 
74
74
  | Command | What it does |
75
75
  |---|---|
76
- | `saffron run [paths] [--headed] [--filter expr] [--rerecord] [--no-agent] [--strict] [--browser b] [--no-hooks] [--workers n] [--heal-model m] [--no-verify] [--no-reuse] [--model m] [--storage-state f] [--trace mode]` | 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`, keep an execution trace with `--trace retain-on-failure`. Exit 1 on red (and on yellow with `--strict`). |
76
+ | `saffron run [paths] [--headed] [--filter expr] [--rerecord] [--no-agent] [--strict] [--browser b[,b...]] [--device name] [--viewport WxH] [--no-hooks] [--workers n] [--agent-workers n] [--heal-model m] [--no-verify] [--no-reuse] [--model m] [--storage-state f] [--trace mode]` | Run features. Cached replays are deterministic; misses/failures escalate to the agent (unless `--no-agent`). A path with a line or a name, `features/login.saffron:12` or `"features/login.saffron:Successful login"`, runs that one scenario. Replay cross-browser with `--browser firefox\|webkit`, parallelize with `--workers N`, heal on a cheaper model with `--heal-model`, keep an execution trace with `--trace retain-on-failure`. Exit 1 on red (and on yellow with `--strict`). |
77
77
  | `saffron accept [files... \| --all] [--include-unverified] [--include-imported] [--with-feature-edit] [--propagate]` | Promote cache proposals to committed caches (`--all` skips UNVERIFIED ones unless `--include-unverified`, and ones imported from a CI run unless `--include-imported`); `--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. |
78
78
  | `saffron reject [files... \| --all]` | Discard proposals; the agent will try again next run. |
79
79
  | `saffron export [-o file] [--branch name]` / `saffron runs` / `saffron import <bundles...> \| --run <id>` | Carry a CI heal to your machine: export packs the run's proposals, report, screenshots and traces into one bundle for CI to upload; `runs` lists the branch's CI runs (GitHub Actions or Azure Pipelines); import (of a file, or of a run with `--run`) checks the bundle against your checkout (repository, each proposal's binding) and files it there, ready for `saffron diff` and `saffron accept`. `--branch` also has CI commit the proposals to a new branch and open a draft pull request with their diffs. |
@@ -155,8 +155,7 @@ milestones, statuses and decision gates, and everything shipped so far in
155
155
  its "Where we are" table.
156
156
  Headlines ahead: API testing (reusable REST operations, fixtures and schema
157
157
  validation), scenarios with two users in two browsers, a configurable
158
- features folder, running one scenario (`file:line`, with run icons in both
159
- IDEs), parallel recording and a browser matrix in one run, failure video,
158
+ features folder, failure video,
160
159
  agent-blind secrets, LLM-less MCP replay, the Level-2 shared step library
161
160
  (gated on Level-1 divergence data), and the long-term open-core SaaS layer.
162
161