saffron-ai 0.9.3 → 0.9.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "saffron-ai",
3
- "version": "0.9.3",
3
+ "version": "0.9.4",
4
4
  "description": "AI-fallback test runner for end-to-end tests written in plain language: zero-token cached replay, runtime AI healing, honest reports",
5
5
  "scripts": {
6
6
  "test": "vitest run",
@@ -132,7 +132,7 @@ Scenario: Checkout happy path
132
132
 
133
133
  ```bash
134
134
  npx saffron run # record misses, replay hits, heal failures
135
- npx saffron run --filter @smoke # by tag (comma-separate several; any of them)
135
+ npx saffron run --filter @smoke # by tag; or an expression: "@e2e and not @wip", "(@smoke or @sanity) and not @flaky"
136
136
  npx saffron run --no-agent # replay only (CI without AI access)
137
137
  npx saffron status # what is cached, pending, tagged; vocabulary health
138
138
  npx saffron diff # what a proposal changes, action by action: the evidence
@@ -141,7 +141,9 @@ npx saffron accept --all # promote verified proposals to caches
141
141
  npx saffron accept <file> [<file>...] # promote chosen ones
142
142
  npx saffron reject <file> [<file>...] # discard chosen ones; the agent retries next run
143
143
  npx saffron report # open the HTML report
144
+ npx saffron dashboard # suite quality: failing, flaky, never run, slowest, per tag
144
145
  npx saffron run --rerecord --filter @t # a recording is wrong: record it fresh
146
+ npx saffron trace "<scenario>" # a red or healed scenario, step by step, with the page at every action ("trace" on in config)
145
147
  npx saffron runs # this branch's CI runs; a heal made there: saffron import --run <id>
146
148
  ```
147
149
 
@@ -69,7 +69,7 @@ your-project/
69
69
 
70
70
  | Command | Purpose |
71
71
  |---|---|
72
- | `saffron run [paths] [--filter @tag] [--no-agent] [--strict] [--browser b] [--workers n] [--shard i/n] [--shard-by scenario\|file] [--provider p] [--heal-model m] [--headed] [--trace mode]` | Run; cached replay, agent on misses/failures. `--shard 2/4` runs one part of the suite on one CI machine and writes `shard-2-of-4.json` instead of `latest.json`; `--trace retain-on-failure` keeps an execution trace of each scenario that is not green |
72
+ | `saffron run [paths] [--filter <tag expression>] [--no-agent] [--strict] [--browser b] [--workers n] [--shard i/n] [--shard-by scenario\|file] [--provider p] [--heal-model m] [--headed] [--trace mode]` | Run; cached replay, agent on misses/failures. `--filter` takes tags or an expression (`"@e2e and not @wip"`). `--shard 2/4` runs one part of the suite on one CI machine and writes `shard-2-of-4.json` instead of `latest.json`; `--trace retain-on-failure` keeps an execution trace of each scenario that is not green |
73
73
  | `saffron trace [scenario] [--port n] [--no-open] [--json] [--run startedAt]` | Open the execution replay of a scenario from the last run (scenario name, feature path or `feature:scenario`; default: every traced scenario in one replay, opening on a red one, else a yellow one); `--json` prints the parsed trace; `--run` opens it only while the last run is that one |
74
74
  | `saffron accept [files... \| --all] [--include-unverified] [--with-feature-edit] [--propagate]` | Promote proposals (`--all` skips UNVERIFIED ones unless `--include-unverified`); `--with-feature-edit` rewrites adapted steps in the feature file; `--propagate` applies a heal's locator fix to every cache using that locator |
75
75
  | `saffron reject [files... \| --all]` | Discard proposals |
@@ -81,6 +81,7 @@ your-project/
81
81
  | `saffron mcp` / `saffron lsp` | MCP tools (`search_steps`, `list_step_sets`, `project_status`) for AI assistants / language server for editors |
82
82
  | `saffron init [--examples] [--agents list]` | Install this skill into the project's agent directories, register MCP, add an AGENTS.md block, scaffold config; `--examples` adds the Saucedemo example suite |
83
83
  | `saffron report [--merge [paths]]` | Open the latest HTML report; `--merge` combines a complete set of shard reports into `latest.json`, `latest.html` and one history line |
84
+ | `saffron dashboard [--stdout] [--no-open]` | The suite's quality from the run history (failing and for how long, flaky, repeatedly healed, never run, slowest, trends, per tag); writes and opens `.saffron/reports/dashboard.html`, `--stdout` prints it |
84
85
  | `saffron export [-o file] [--branch name [--base branch]]` | In CI: pack the pending proposals, the run's report, screenshots and traces into `.saffron/reports/saffron-bundle.zip` to upload as an artifact. `--branch` also pushes the proposals as a new branch and opens a draft pull request (GitHub through `gh`, Azure DevOps through `az`); exit 1 only when the branch is pushed but the pull request could not be opened |
85
86
  | `saffron runs [--branch b] [--limit n] [--provider github\|azure] [--json]` | The branch's CI runs, with how many of each run's proposals are pending here; exit 2 when `gh` or `az` is missing or signed out |
86
87
  | `saffron import <bundles...> \| --run <id> [--overwrite] [--allow-unknown-repository] [--json]` | Bring a CI run's bundle into this checkout: its proposals (each checked against the files here), report and traces. Then `saffron diff` and `saffron accept` as usual. Exit 1 when a proposal was not imported, 2 when the bundle was refused |
@@ -119,8 +120,37 @@ npx playwright install chromium
119
120
  npx saffron run --no-agent --strict # replay committed caches; no AI, no surprises
120
121
  ```
121
122
 
122
- Record and heal on developer machines (or a dedicated job with
123
- credentials), review proposals in PRs like snapshot updates.
123
+ Record new scenarios on developer machines. A CI job that may heal (it
124
+ has the provider's login or key) runs without `--no-agent`, and its heals
125
+ travel to the reviewer as a bundle, never lost with the CI workspace:
126
+
127
+ ```yaml
128
+ # GitHub Actions
129
+ - run: npx saffron run --strict
130
+ - name: Saffron bundle
131
+ if: failure()
132
+ run: npx saffron export --out saffron-bundle.zip
133
+ - uses: actions/upload-artifact@v4
134
+ if: failure()
135
+ with:
136
+ name: saffron-bundle
137
+ path: saffron-bundle.zip
138
+ ```
139
+
140
+ Azure Pipelines is the same: `saffron export --out
141
+ $(Build.ArtifactStagingDirectory)/saffron-bundle.zip`, then publish it as
142
+ the `saffron-bundle` artifact. Keep the artifact name starting with
143
+ `saffron-bundle`: that is what `saffron import --run` and both editors'
144
+ CI runs views download. Upload a file outside `.saffron/` (`--out`), as
145
+ `upload-artifact` leaves hidden folders out.
146
+
147
+ On the reviewer's checkout: `npx saffron runs`, then `npx saffron import
148
+ --run <id>`, then `saffron diff`, `saffron accept` and commit
149
+ `.saffron/cache/`. For review in a pull request instead, add `--branch
150
+ saffron/heal-<run id>` to the export step: CI pushes the proposals (not
151
+ the caches) as a branch and opens a draft pull request whose description
152
+ says how to accept them; it needs a token that may push and open pull
153
+ requests.
124
154
 
125
155
  ## Reading a report
126
156
 
@@ -232,4 +232,9 @@ Scenario: Checkout happy path
232
232
  Scenario: ...
233
233
  ```
234
234
 
235
- `saffron run --filter @smoke`.
235
+ `saffron run --filter @smoke`. `--filter` takes a tag expression:
236
+ `and`, `or`, `not` and parentheses, with `and` binding tighter than `or`
237
+ (`--filter "@e2e and not @wip"`, `--filter "(@smoke or @sanity) and not
238
+ @flaky"`). A comma, `|`, a space or a repeated `--filter` between plain
239
+ tags means `or`; once `and`, `not` or a parenthesis appears, join every
240
+ tag with `and` or `or`. The `@` may be left out.