keepgreen 0.1.0 → 0.2.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 +21 -0
- package/README.md +151 -58
- package/SECURITY.md +7 -1
- package/action.yml +37 -2
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +53 -7
- package/dist/cli.js.map +1 -1
- package/dist/explore.d.ts +8 -0
- package/dist/explore.js +38 -7
- package/dist/explore.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/price.d.ts +13 -0
- package/dist/price.js +42 -0
- package/dist/price.js.map +1 -0
- package/package.json +1 -1
- package/templates/keepgreen-explore.yml +56 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
Fixes from a full audit, plus the most-asked-for features.
|
|
6
|
+
|
|
7
|
+
- **Explore a deployed app.** `--url` (and `url:`) now accepts any http(s) address, such as a staging or preview deployment. 0.1.x refused anything but localhost with a message about `start-url`. An app KeepGreen starts itself (`start-command`) must still be on this machine. Point it at a test environment, not production.
|
|
8
|
+
- **Name the flows yourself.** `keepgreen explore --flow "A shopper adds the mug to the cart and the cart shows 1"` skips the AI planning and writes a test for each flow you name (repeat `--flow`). The Action has a `flows` input (one per line) and the workflow template a `flows` box (separated by `;`).
|
|
9
|
+
- **No more lost tests from name clashes.** Test file names were the first six words of the flow, so two flows starting "A visitor opens the home page..." got the same name and AutoHeal refused the second one. Names now skip filler words (`keepgreen-opens-home-clicks-account-link-lands.spec.ts`) and get `-2`, `-3` when a name is already taken, on disk or earlier in the run.
|
|
10
|
+
- **max-usd works on OpenRouter without setting prices.** For an OpenRouter `base-url`, KeepGreen looks up the model's price in OpenRouter's public model list. Before, a model with no listed price ran with only a token cap. When no price can be found, explore now says so up front.
|
|
11
|
+
- **Weekly runs don't pile up.** A scheduled explore run stops when a KeepGreen PR is still open, instead of planning the same flows again. Manual runs always go ahead.
|
|
12
|
+
- **CI runs on KeepGreen's PRs.** GitHub starts no workflows on a PR opened with the built-in token. Add an optional `KEEPGREEN_PR_TOKEN` secret (a fine-grained token for this repo) and the publish job uses it, so your checks run. Re-running the publish job no longer fails on an existing branch.
|
|
13
|
+
- **PR bodies can't ping people.** `@name` in AI-written flow text is defused before it goes into the report.
|
|
14
|
+
- `summary.json` now lists each flow's result (status, file, reason) and whether the spend is priced.
|
|
15
|
+
|
|
16
|
+
## 0.1.1
|
|
17
|
+
|
|
18
|
+
- OpenRouter and other OpenAI-compatible endpoints in the GitHub Action: new `base-url`, `api-key`, `price-in` and `price-out` inputs (the template shows them commented out). The README has an OpenRouter section.
|
|
19
|
+
- `keepgreen explore` sets `KEEPGREEN=1` for the app and the tests, so a Playwright `webServer` can reuse the app KeepGreen started: `reuseExistingServer: !process.env.CI || !!process.env.KEEPGREEN`. Without it, Playwright stops in CI with "port already in use".
|
|
20
|
+
- Explore workflow template: a blank `max-flows` input now keeps the value from `.keepgreen.yml` (it used to force 3).
|
|
21
|
+
- A refused AI request (no credit, bad key) now prints a short reason and what to do, instead of a stack trace.
|
|
22
|
+
- First release published from CI with npm provenance (0.1.0 was published by hand).
|
|
23
|
+
|
|
3
24
|
## 0.1.0
|
|
4
25
|
|
|
5
26
|
First release.
|
package/README.md
CHANGED
|
@@ -1,27 +1,75 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/xsignon-secure/keepgreen/main/docs/logo.png" alt="KeepGreen logo: a green check inside a looping arrow" width="140">
|
|
3
|
+
</p>
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
<h1 align="center">KeepGreen</h1>
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
covers every run.
|
|
7
|
+
<p align="center"><b>The AI test agent that writes, fixes and keeps your end-to-end tests green.</b><br>
|
|
8
|
+
It finds the user flows nobody tests, writes a test for each, and fixes tests when your UI changes.<br>
|
|
9
|
+
Every test it keeps <b>proved itself</b>: real assertions, green run after run.</p>
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
<p align="center">
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
finds stable locators, runs tests and reads failures.
|
|
14
|
-
- [AutoHeal](https://github.com/xsignon-secure/AutoHeal-AI) is the guarded fixer and test writer,
|
|
15
|
-
with its anti-cheat guard and stability proof.
|
|
13
|
+
[](https://www.npmjs.com/package/keepgreen) [](https://www.npmjs.com/package/keepgreen) [](https://github.com/xsignon-secure/keepgreen/actions/workflows/ci.yml) [](https://www.npmjs.com/package/keepgreen#provenance) [](LICENSE) [](#-free-forever)
|
|
16
14
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
</p>
|
|
16
|
+
|
|
17
|
+
<p align="center">⭐ <b>If KeepGreen saves you a test-writing afternoon, <a href="https://github.com/xsignon-secure/keepgreen">a star</a> helps other teams find it.</b></p>
|
|
18
|
+
|
|
19
|
+
<p align="center">
|
|
20
|
+
<a href="#-quick-start">Quick start</a> ·
|
|
21
|
+
<a href="#-github-actions">GitHub Actions</a> ·
|
|
22
|
+
<a href="#-how-explore-works">How it works</a> ·
|
|
23
|
+
<a href="#%EF%B8%8F-settings">Settings</a> ·
|
|
24
|
+
<a href="#-security">Security</a> ·
|
|
25
|
+
<a href="CHANGELOG.md">Changelog</a>
|
|
26
|
+
</p>
|
|
27
|
+
|
|
28
|
+
KeepGreen runs **on your own CI runner or laptop, with your own AI key**: Anthropic, OpenAI,
|
|
29
|
+
OpenRouter, or any OpenAI-compatible endpoint including local models. There is no KeepGreen
|
|
30
|
+
server, no account and no telemetry. You pay only your AI provider, and one spend cap covers
|
|
31
|
+
every run.
|
|
32
|
+
|
|
33
|
+
## ❌ Without it / ✅ With it
|
|
34
|
+
|
|
35
|
+
**Without it**, the checkout page ships with no end-to-end test because nobody had time to write
|
|
36
|
+
one. When a test does exist, a renamed button turns CI red and someone spends an hour patching
|
|
37
|
+
selectors, or an AI "fixes" it by deleting the assertion that mattered.
|
|
21
38
|
|
|
22
|
-
|
|
39
|
+
**With it**, KeepGreen opens your app, sees which important flows have no test, writes one for
|
|
40
|
+
each and opens **one pull request** with only the tests that passed every run. When the UI
|
|
41
|
+
changes, it fixes the broken test and proves the fix. When the app is really broken, it tells you
|
|
42
|
+
it's an app bug instead of "fixing" the test.
|
|
23
43
|
|
|
24
|
-
|
|
44
|
+
> **Real run, real cost.** On our [demo shop](https://github.com/xsignon-secure/autoheal-demo),
|
|
45
|
+
> one KeepGreen run inspected 3 pages, planned 2 untested flows and opened
|
|
46
|
+
> [a PR with 2 new tests](https://github.com/xsignon-secure/autoheal-demo/pull/9). Each passed
|
|
47
|
+
> 3 runs in a row and the anti-cheat guard. Total AI spend: **about $0.04**.
|
|
48
|
+
|
|
49
|
+
## ✨ What you get
|
|
50
|
+
|
|
51
|
+
| Recipe | What it does | Command |
|
|
52
|
+
| --- | --- | --- |
|
|
53
|
+
| 🔍 **Explore** | Looks at your app, picks the most important user flows that have **no test yet**, and writes a test for each. A test is kept only if it makes real assertions and passes every run (5 by default). | `npx keepgreen explore` |
|
|
54
|
+
| 🎯 **Explore one flow** | Skip the planning: name the flow, get the test. | `npx keepgreen explore --flow "..."` |
|
|
55
|
+
| 🩹 **Heal** | Runs your tests, finds what broke, fixes it and proves the fix. App bugs are reported, not "fixed". | `npx keepgreen heal` (local) · AutoHeal workflow (CI) |
|
|
56
|
+
|
|
57
|
+
- **Anti-cheat guard.** Tests without real assertions, or with skips, faked network answers,
|
|
58
|
+
fixed waits, forced clicks or retries, are thrown away.
|
|
59
|
+
- **Proven, not hoped.** A new test must pass `runs` times in a row before it's kept.
|
|
60
|
+
- **Your style.** Tests follow your project's imports, fixtures and locator style.
|
|
61
|
+
- **One PR, only new files.** In CI, the publish step accepts nothing but new test files.
|
|
62
|
+
- **One spend cap.** `max-usd` covers planning plus every flow. OpenRouter prices are looked up
|
|
63
|
+
for you.
|
|
64
|
+
- **Works with** Playwright Test and pytest-playwright. Healing also covers Cypress and
|
|
65
|
+
WebdriverIO.
|
|
66
|
+
|
|
67
|
+
KeepGreen joins two XSignOn projects into one agent:
|
|
68
|
+
[playwright-e2e-mcp](https://github.com/xsignon-secure/E2E) is the toolbox (opens pages, finds
|
|
69
|
+
stable locators, runs tests, reads failures) and [AutoHeal](https://github.com/xsignon-secure/AutoHeal-AI)
|
|
70
|
+
is the guarded fixer and test writer.
|
|
71
|
+
|
|
72
|
+
## ⚡ Quick start
|
|
25
73
|
|
|
26
74
|
```bash
|
|
27
75
|
npm install -D keepgreen # or use npx keepgreen ... without installing
|
|
@@ -30,63 +78,95 @@ npx keepgreen init # writes .keepgreen.yml + workflows, check
|
|
|
30
78
|
npx keepgreen explore --url http://localhost:3000
|
|
31
79
|
```
|
|
32
80
|
|
|
33
|
-
Explore prints a table of the flows it tried and which tests it kept. New files are named
|
|
34
|
-
`tests/keepgreen
|
|
35
|
-
|
|
36
|
-
Try it without writing anything first:
|
|
81
|
+
Explore prints a table of the flows it tried and which tests it kept. New files are named after
|
|
82
|
+
the flow, such as `tests/keepgreen-adds-coffee-mug-cart-count-shows.spec.ts`. Review them with
|
|
83
|
+
`git diff` and commit the ones you like.
|
|
37
84
|
|
|
38
85
|
```bash
|
|
39
|
-
|
|
40
|
-
|
|
86
|
+
# Plan only: show the flows it would test, write nothing
|
|
87
|
+
npx keepgreen explore --url http://localhost:3000 --dry-run
|
|
41
88
|
|
|
42
|
-
|
|
89
|
+
# Test the flows you name (repeat --flow for more)
|
|
90
|
+
npx keepgreen explore --url http://localhost:3000 \
|
|
91
|
+
--flow "A shopper adds the coffee mug to the cart and the cart count shows 1"
|
|
43
92
|
|
|
44
|
-
|
|
93
|
+
# Let KeepGreen start your app
|
|
45
94
|
npx keepgreen explore --start-command "npm run dev" --start-url http://localhost:3000
|
|
46
|
-
```
|
|
47
95
|
|
|
48
|
-
|
|
96
|
+
# A deployed staging or preview app works too (use a test environment, not production)
|
|
97
|
+
npx keepgreen explore --url https://staging.example.com
|
|
49
98
|
|
|
50
|
-
|
|
51
|
-
npx keepgreen heal
|
|
99
|
+
# Fix broken tests; changes stay in your working tree for review
|
|
100
|
+
npx keepgreen heal
|
|
52
101
|
```
|
|
53
102
|
|
|
54
|
-
##
|
|
103
|
+
## 🤖 GitHub Actions
|
|
55
104
|
|
|
56
105
|
`npx keepgreen init` writes two workflows:
|
|
57
106
|
|
|
58
107
|
- **`.github/workflows/keepgreen-explore.yml`** runs from *Actions > KeepGreen explore > Run
|
|
59
108
|
workflow*, or weekly if you uncomment the schedule. It opens **one PR** with the new tests that
|
|
60
|
-
passed.
|
|
61
|
-
|
|
109
|
+
passed. The explore job runs the AI-written tests with a read-only token. The publish job
|
|
110
|
+
accepts the result only if it just adds test files, then opens the PR. A scheduled run skips
|
|
111
|
+
itself while an earlier KeepGreen PR is still open.
|
|
62
112
|
- **`.github/workflows/autoheal.yml`** is written by AutoHeal's own `init`. It runs after your
|
|
63
113
|
test workflow fails and opens a fix PR.
|
|
64
114
|
|
|
65
115
|
Then:
|
|
66
116
|
|
|
67
117
|
1. Add `ANTHROPIC_API_KEY` as a repository secret. For OpenAI, add `OPENAI_API_KEY` and a
|
|
68
|
-
repository variable `AUTOHEAL_MODEL`.
|
|
118
|
+
repository variable `AUTOHEAL_MODEL`. For OpenRouter, see [below](#openrouter-or-any-openai-compatible-endpoint).
|
|
69
119
|
2. Go to *Settings > Actions > General > Workflow permissions* and tick "Allow GitHub Actions to
|
|
70
120
|
create and approve pull requests".
|
|
71
121
|
3. Make the explore job's install steps match your test workflow (Node or Python, browsers,
|
|
72
122
|
services).
|
|
123
|
+
4. Optional: add a fine-grained token (this repo only; Contents and Pull requests: read and
|
|
124
|
+
write) as the secret `KEEPGREEN_PR_TOKEN`. GitHub runs no CI on PRs opened with the built-in
|
|
125
|
+
token; with this one, your checks run on KeepGreen's PRs.
|
|
73
126
|
|
|
74
|
-
|
|
127
|
+
Or use the action directly:
|
|
75
128
|
|
|
76
129
|
```yaml
|
|
77
|
-
- uses: xsignon-secure/keepgreen@v0.
|
|
130
|
+
- uses: xsignon-secure/keepgreen@v0.2.0
|
|
78
131
|
with:
|
|
79
132
|
url: http://localhost:3000
|
|
80
133
|
anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
134
|
+
# flows: | # optional: skip planning
|
|
135
|
+
# A visitor logs in and sees the dashboard
|
|
81
136
|
# leaves keepgreen-out/ (report.md, summary.json, new-tests.patch); output `written` = tests kept
|
|
82
137
|
```
|
|
83
138
|
|
|
84
|
-
##
|
|
139
|
+
## 🔍 How explore works
|
|
140
|
+
|
|
141
|
+
```mermaid
|
|
142
|
+
flowchart LR
|
|
143
|
+
A["👀 Look<br/>inspect your pages"] --> B["🧭 Plan<br/>flows with no test yet"]
|
|
144
|
+
B --> C["✍️ Write<br/>one test per flow, your style"]
|
|
145
|
+
C --> D{"🛡️ Prove<br/>guard + N green runs"}
|
|
146
|
+
D -->|passes| E["✅ kept, in one PR"]
|
|
147
|
+
D -->|fails or cheats| F["🗑️ thrown away"]
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
1. **Look.** It opens your app's start page and every path in `pages:` with playwright-e2e-mcp's
|
|
151
|
+
`inspect-page`, which lists the interactive elements and their locators.
|
|
152
|
+
2. **Plan.** It reads the titles of your existing tests and asks your AI for the most important
|
|
153
|
+
user flows that have no test yet. Flows that pay money, send email or delete data are skipped.
|
|
154
|
+
With `--flow`, this step is skipped.
|
|
155
|
+
3. **Write.** For each flow, AutoHeal's `cover` explores the pages, checks every locator, and
|
|
156
|
+
writes one test in your project's own style.
|
|
157
|
+
4. **Prove.** The new-test guard rejects tests that cannot fail, or that use skips, faked network
|
|
158
|
+
answers, fixed waits, forced clicks or retries. The test must then pass every run in a row.
|
|
159
|
+
Anything less is thrown away.
|
|
160
|
+
|
|
161
|
+
One `max-usd` cap covers the whole run. Each flow gets an even share of what is left, so money one
|
|
162
|
+
flow saves goes to the next.
|
|
163
|
+
|
|
164
|
+
## ⚙️ Settings
|
|
85
165
|
|
|
86
166
|
`.keepgreen.yml` at the repo root. Command-line flags override it.
|
|
87
167
|
|
|
88
168
|
```yaml
|
|
89
|
-
url: http://localhost:3000 # the running app, or:
|
|
169
|
+
url: http://localhost:3000 # the running app (local, staging or preview), or:
|
|
90
170
|
# start-command: npm run dev
|
|
91
171
|
# start-url: http://localhost:3000
|
|
92
172
|
pages: # extra pages to look at when choosing flows
|
|
@@ -104,39 +184,49 @@ AI settings use AutoHeal's variables:
|
|
|
104
184
|
| --- | --- |
|
|
105
185
|
| `ANTHROPIC_API_KEY` | Use Anthropic (default model `claude-opus-5-5`) |
|
|
106
186
|
| `OPENAI_API_KEY` + `AUTOHEAL_MODEL` | Use OpenAI |
|
|
107
|
-
| `AUTOHEAL_BASE_URL` + `AUTOHEAL_MODEL` | Any OpenAI-compatible endpoint,
|
|
187
|
+
| `AUTOHEAL_BASE_URL` + `AUTOHEAL_MODEL` (+ `AUTOHEAL_API_KEY`) | Any OpenAI-compatible endpoint: OpenRouter, or Ollama at `http://localhost:11434/v1` |
|
|
108
188
|
| `AUTOHEAL_EFFORT` | Anthropic effort: `low` … `max` (default `medium`) |
|
|
109
|
-
| `AUTOHEAL_PRICE_IN` / `AUTOHEAL_PRICE_OUT` | USD per 1M tokens, for models without a
|
|
189
|
+
| `AUTOHEAL_PRICE_IN` / `AUTOHEAL_PRICE_OUT` | USD per 1M tokens, for models without a known price |
|
|
110
190
|
|
|
111
|
-
|
|
191
|
+
### OpenRouter (or any OpenAI-compatible endpoint)
|
|
112
192
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
4. **Prove.** The new-test guard rejects tests that cannot fail, or that use skips, faked network
|
|
120
|
-
answers, fixed waits, forced clicks or retries. The test must then pass every run in a row.
|
|
121
|
-
Anything less is thrown away.
|
|
193
|
+
```bash
|
|
194
|
+
export AUTOHEAL_BASE_URL=https://openrouter.ai/api/v1
|
|
195
|
+
export AUTOHEAL_API_KEY=sk-or-... # your OpenRouter key; give it a credit limit
|
|
196
|
+
export AUTOHEAL_MODEL=anthropic/claude-sonnet-5.5
|
|
197
|
+
npx keepgreen explore --url http://localhost:3000
|
|
198
|
+
```
|
|
122
199
|
|
|
123
|
-
|
|
124
|
-
|
|
200
|
+
KeepGreen looks up the model's price in OpenRouter's public model list, so `max-usd` is enforced.
|
|
201
|
+
For other endpoints, set `AUTOHEAL_PRICE_IN` and `AUTOHEAL_PRICE_OUT`.
|
|
125
202
|
|
|
126
|
-
|
|
203
|
+
In the Action: `base-url: https://openrouter.ai/api/v1`, `api-key: ${{ secrets.OPENROUTER_API_KEY }}`
|
|
204
|
+
and `model: ...`.
|
|
205
|
+
|
|
206
|
+
### Playwright `webServer`
|
|
207
|
+
|
|
208
|
+
If your `playwright.config` starts the app with `webServer`, and KeepGreen starts it too
|
|
209
|
+
(`start-command`), let Playwright reuse it during a KeepGreen run:
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
webServer: { command: 'npm run start', url: 'http://127.0.0.1:3000/', reuseExistingServer: !process.env.CI || !!process.env.KEEPGREEN },
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## 📖 All commands
|
|
127
216
|
|
|
128
217
|
```
|
|
129
218
|
keepgreen init [--force] [--dry-run]
|
|
130
219
|
keepgreen doctor
|
|
131
220
|
keepgreen explore [--url <app>] [--start-command <cmd> --start-url <url>] [--pages /a,/b]
|
|
132
|
-
[--max-flows 3] [--max-usd 3] [--runs 5]
|
|
221
|
+
[--flow "<sentence>" ...] [--max-flows 3] [--max-usd 3] [--runs 5]
|
|
222
|
+
[--dry-run] [--out <dir>]
|
|
133
223
|
keepgreen heal [AutoHeal fix options]
|
|
134
224
|
keepgreen autoheal <command> [...] # any AutoHeal command: learn, metrics, dashboard, ...
|
|
135
225
|
keepgreen check-patch <file> # CI publish step
|
|
136
226
|
keepgreen --version
|
|
137
227
|
```
|
|
138
228
|
|
|
139
|
-
## Self-host bundle (optional)
|
|
229
|
+
## 🏠 Self-host bundle (optional)
|
|
140
230
|
|
|
141
231
|
KeepGreen needs no server. If you want **test history across all CI runs** (flaky ranking, the
|
|
142
232
|
commit where a test went bad) and **AutoHeal's dashboard** (fixes, blocked cheats, AI spend),
|
|
@@ -146,12 +236,15 @@ commit where a test went bad) and **AutoHeal's dashboard** (fixes, blocked cheat
|
|
|
146
236
|
cd selfhost && sh make-env.sh your-org/your-repo && docker compose up -d --build
|
|
147
237
|
```
|
|
148
238
|
|
|
149
|
-
## Security
|
|
239
|
+
## 🔒 Security
|
|
150
240
|
|
|
151
241
|
See [SECURITY.md](SECURITY.md). In short: your key goes only to your AI provider, AI-written tests
|
|
152
242
|
never run with a write token or your AI key, the publish step only accepts new test files, and
|
|
153
|
-
every change arrives as a PR for a person to review.
|
|
243
|
+
every change arrives as a PR for a person to review. Forks never get your secrets.
|
|
244
|
+
|
|
245
|
+
## 💚 Free forever
|
|
154
246
|
|
|
155
|
-
|
|
247
|
+
MIT licensed. Free for any use, with no paid tier, no account and no telemetry. Releases are
|
|
248
|
+
published from CI with [npm provenance](https://www.npmjs.com/package/keepgreen#provenance).
|
|
156
249
|
|
|
157
|
-
|
|
250
|
+
Issues and pull requests are welcome. If KeepGreen helps you, ⭐ the repo so others can find it.
|
package/SECURITY.md
CHANGED
|
@@ -24,7 +24,13 @@ every prompt marks such text as data.
|
|
|
24
24
|
one of `runs` runs in a row. The scans are pattern based, so every test still arrives as a PR
|
|
25
25
|
for a person to review.
|
|
26
26
|
- **Pages stay on your app.** Planning only opens the app URL and the paths you list in
|
|
27
|
-
`pages:`; `cover` only opens pages on the same origin.
|
|
27
|
+
`pages:`; `cover` only opens pages on the same origin. An app KeepGreen starts must be on the
|
|
28
|
+
same machine; an app that is already running (`url:`) may be a staging or preview deployment.
|
|
29
|
+
Point KeepGreen at a test environment, never production: the tests it writes really click.
|
|
30
|
+
- **No pings from AI text.** `@name` in AI-written flow text is defused before it goes into a PR.
|
|
31
|
+
- **Optional PR token.** `KEEPGREEN_PR_TOKEN` (so your CI runs on KeepGreen's PRs) is only given
|
|
32
|
+
to the publish job, which never runs your project's code. Make it fine-grained, for this repo
|
|
33
|
+
only, with Contents and Pull requests access.
|
|
28
34
|
- **Spend cap.** One `max-usd` limit covers a whole explore run (planning plus every flow).
|
|
29
35
|
|
|
30
36
|
## Your part
|
package/action.yml
CHANGED
|
@@ -23,6 +23,10 @@ inputs:
|
|
|
23
23
|
description: Address to wait for after start-command
|
|
24
24
|
required: false
|
|
25
25
|
default: ""
|
|
26
|
+
flows:
|
|
27
|
+
description: Flows to write tests for, one sentence per line (skips planning; blank = let the AI pick)
|
|
28
|
+
required: false
|
|
29
|
+
default: ""
|
|
26
30
|
max-flows:
|
|
27
31
|
description: New tests to try (1-10; blank = .keepgreen.yml or 3)
|
|
28
32
|
required: false
|
|
@@ -44,7 +48,23 @@ inputs:
|
|
|
44
48
|
required: false
|
|
45
49
|
default: ""
|
|
46
50
|
model:
|
|
47
|
-
description: Model id (optional for Anthropic)
|
|
51
|
+
description: Model id (optional for Anthropic; for OpenRouter e.g. the id shown on openrouter.ai/models)
|
|
52
|
+
required: false
|
|
53
|
+
default: ""
|
|
54
|
+
base-url:
|
|
55
|
+
description: OpenAI-compatible endpoint, e.g. https://openrouter.ai/api/v1 (use with api-key and model)
|
|
56
|
+
required: false
|
|
57
|
+
default: ""
|
|
58
|
+
api-key:
|
|
59
|
+
description: API key for base-url (e.g. your OpenRouter key)
|
|
60
|
+
required: false
|
|
61
|
+
default: ""
|
|
62
|
+
price-in:
|
|
63
|
+
description: USD per 1M input tokens, for models KeepGreen has no price for (enforces max-usd)
|
|
64
|
+
required: false
|
|
65
|
+
default: ""
|
|
66
|
+
price-out:
|
|
67
|
+
description: USD per 1M output tokens
|
|
48
68
|
required: false
|
|
49
69
|
default: ""
|
|
50
70
|
working-directory:
|
|
@@ -54,7 +74,7 @@ inputs:
|
|
|
54
74
|
version:
|
|
55
75
|
description: keepgreen version from npm
|
|
56
76
|
required: false
|
|
57
|
-
default: "0.
|
|
77
|
+
default: "0.2.0"
|
|
58
78
|
|
|
59
79
|
outputs:
|
|
60
80
|
written:
|
|
@@ -71,6 +91,10 @@ runs:
|
|
|
71
91
|
ANTHROPIC_API_KEY: ${{ inputs.anthropic-api-key }}
|
|
72
92
|
OPENAI_API_KEY: ${{ inputs.openai-api-key }}
|
|
73
93
|
AUTOHEAL_MODEL: ${{ inputs.model }}
|
|
94
|
+
KG_BASE_URL: ${{ inputs.base-url }}
|
|
95
|
+
KG_API_KEY: ${{ inputs.api-key }}
|
|
96
|
+
KG_PRICE_IN: ${{ inputs.price-in }}
|
|
97
|
+
KG_PRICE_OUT: ${{ inputs.price-out }}
|
|
74
98
|
KG_VERSION: ${{ inputs.version }}
|
|
75
99
|
KG_URL: ${{ inputs.url }}
|
|
76
100
|
KG_START_COMMAND: ${{ inputs.start-command }}
|
|
@@ -78,11 +102,18 @@ runs:
|
|
|
78
102
|
KG_MAX_FLOWS: ${{ inputs.max-flows }}
|
|
79
103
|
KG_MAX_USD: ${{ inputs.max-usd }}
|
|
80
104
|
KG_RUNS: ${{ inputs.runs }}
|
|
105
|
+
KG_FLOWS: ${{ inputs.flows }}
|
|
81
106
|
OUT: ${{ github.workspace }}/keepgreen-out
|
|
82
107
|
run: |
|
|
83
108
|
[ -n "$ANTHROPIC_API_KEY" ] || unset ANTHROPIC_API_KEY
|
|
84
109
|
[ -n "$OPENAI_API_KEY" ] || unset OPENAI_API_KEY
|
|
85
110
|
[ -n "$AUTOHEAL_MODEL" ] || unset AUTOHEAL_MODEL
|
|
111
|
+
# Inputs win; otherwise keep any AUTOHEAL_* already set on the job.
|
|
112
|
+
if [ -n "$KG_BASE_URL" ]; then export AUTOHEAL_PROVIDER=openai-compatible AUTOHEAL_BASE_URL="$KG_BASE_URL"; fi
|
|
113
|
+
if [ -n "$KG_API_KEY" ]; then export AUTOHEAL_API_KEY="$KG_API_KEY"; fi
|
|
114
|
+
if [ -n "$KG_PRICE_IN" ]; then export AUTOHEAL_PRICE_IN="$KG_PRICE_IN"; fi
|
|
115
|
+
if [ -n "$KG_PRICE_OUT" ]; then export AUTOHEAL_PRICE_OUT="$KG_PRICE_OUT"; fi
|
|
116
|
+
unset KG_API_KEY
|
|
86
117
|
if ! [[ "$KG_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then echo "::error::version must be like 1.2.3"; exit 2; fi
|
|
87
118
|
args=(explore --out "$OUT")
|
|
88
119
|
[ -n "$KG_URL" ] && args+=(--url "$KG_URL")
|
|
@@ -91,6 +122,10 @@ runs:
|
|
|
91
122
|
[ -n "$KG_MAX_FLOWS" ] && args+=(--max-flows "$KG_MAX_FLOWS")
|
|
92
123
|
[ -n "$KG_MAX_USD" ] && args+=(--max-usd "$KG_MAX_USD")
|
|
93
124
|
[ -n "$KG_RUNS" ] && args+=(--runs "$KG_RUNS")
|
|
125
|
+
while IFS= read -r line; do
|
|
126
|
+
line="${line#"${line%%[![:space:]]*}"}"
|
|
127
|
+
[ -n "$line" ] && args+=(--flow "$line")
|
|
128
|
+
done <<< "$KG_FLOWS"
|
|
94
129
|
set +e
|
|
95
130
|
npx -y "keepgreen@$KG_VERSION" "${args[@]}"
|
|
96
131
|
code=$?
|
package/dist/cli.d.ts
CHANGED
|
@@ -9,4 +9,6 @@
|
|
|
9
9
|
export declare const USAGE: string;
|
|
10
10
|
/** Path of AutoHeal's CLI inside the installed xsignon-autoheal package. */
|
|
11
11
|
export declare function autohealCli(): string;
|
|
12
|
+
/** A running app to explore: any http(s) address without a user name or password in it. */
|
|
13
|
+
export declare function checkRemoteUrl(url: string): URL;
|
|
12
14
|
export declare function main(argv: string[]): Promise<number>;
|
package/dist/cli.js
CHANGED
|
@@ -12,12 +12,13 @@ import { appendFile, mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
|
12
12
|
import path from 'node:path';
|
|
13
13
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
14
14
|
import { parseArgs } from 'node:util';
|
|
15
|
-
import { ConfigError, CypressTools, McpTools, WdioTools, checkAppUrl, cover, frameworkSetting, isCypressProject, isPytestProject, isWdioProject, priceFor, providerFromEnv, startApp, } from 'xsignon-autoheal';
|
|
15
|
+
import { ConfigError, CypressTools, McpTools, ProviderError, WdioTools, checkAppUrl, cover, frameworkSetting, isCypressProject, isPytestProject, isWdioProject, priceFor, providerFromEnv, startApp, } from 'xsignon-autoheal';
|
|
16
16
|
import { ConfigFileError, loadConfigFile, resolveConfig } from './config.js';
|
|
17
17
|
import { existingTitles, explore, exploreReport } from './explore.js';
|
|
18
18
|
import { init } from './init.js';
|
|
19
19
|
import { newFilesPatch } from './newfiles.js';
|
|
20
20
|
import { checkPatch } from './patch.js';
|
|
21
|
+
import { lookupPrice } from './price.js';
|
|
21
22
|
import { VERSION } from './version.js';
|
|
22
23
|
export const USAGE = `keepgreen ${VERSION}: free, self-hosted AI test agent. It writes new end-to-end tests
|
|
23
24
|
for your app and fixes the ones that break, with your own AI key (Anthropic, OpenAI or any
|
|
@@ -28,9 +29,11 @@ OpenAI-compatible endpoint). Built on playwright-e2e-mcp and AutoHeal. MIT, no a
|
|
|
28
29
|
keepgreen doctor
|
|
29
30
|
check this project and machine
|
|
30
31
|
keepgreen explore [--url <app>] [--start-command <cmd> --start-url <url>] [--pages /a,/b]
|
|
31
|
-
[--max-flows 3] [--max-usd 3] [--runs 5]
|
|
32
|
+
[--flow "<sentence>" ...] [--max-flows 3] [--max-usd 3] [--runs 5]
|
|
33
|
+
[--dry-run] [--out <dir>]
|
|
32
34
|
find important user flows with no test yet and write a test for each; a test is kept
|
|
33
|
-
only if it makes real assertions and passes --runs times in a row
|
|
35
|
+
only if it makes real assertions and passes --runs times in a row. --flow skips the
|
|
36
|
+
planning and writes a test for the flow you name (repeat it for more)
|
|
34
37
|
keepgreen heal [AutoHeal fix options]
|
|
35
38
|
run your tests, fix what broke, leave the changes for you to review
|
|
36
39
|
keepgreen autoheal <command> [...]
|
|
@@ -84,14 +87,18 @@ async function cmdExplore(argv) {
|
|
|
84
87
|
framework: { type: 'string' },
|
|
85
88
|
project: { type: 'string' },
|
|
86
89
|
out: { type: 'string' },
|
|
90
|
+
flow: { type: 'string', multiple: true },
|
|
87
91
|
'dry-run': { type: 'boolean' },
|
|
88
92
|
},
|
|
89
93
|
strict: true,
|
|
90
94
|
});
|
|
91
95
|
const projectRoot = path.resolve(values.project ?? '.');
|
|
92
|
-
const { project: _p, out: _o, 'dry-run': _d, ...flags } = values;
|
|
96
|
+
const { project: _p, out: _o, 'dry-run': _d, flow: _f, ...flags } = values;
|
|
93
97
|
const config = resolveConfig(await loadConfigFile(projectRoot), flags);
|
|
94
98
|
const env = process.env;
|
|
99
|
+
// Lets playwright.config tell a KeepGreen run apart, e.g.
|
|
100
|
+
// reuseExistingServer: !process.env.CI || !!process.env.KEEPGREEN
|
|
101
|
+
env.KEEPGREEN = '1';
|
|
95
102
|
const provider = providerFromEnv(env);
|
|
96
103
|
if (!provider)
|
|
97
104
|
throw new ConfigError('keepgreen explore needs an AI key: set ANTHROPIC_API_KEY, OPENAI_API_KEY (and AUTOHEAL_MODEL) or AUTOHEAL_BASE_URL.');
|
|
@@ -111,7 +118,15 @@ async function cmdExplore(argv) {
|
|
|
111
118
|
}
|
|
112
119
|
if (!appUrl)
|
|
113
120
|
throw new ConfigError('Tell KeepGreen where your app runs: --url http://localhost:3000, or url: in .keepgreen.yml (or start-command + start-url).');
|
|
114
|
-
|
|
121
|
+
// An app KeepGreen starts must be on this machine (startApp checks it). An app that is
|
|
122
|
+
// already running may be anywhere, such as a staging or preview deployment.
|
|
123
|
+
if (app)
|
|
124
|
+
checkAppUrl(appUrl);
|
|
125
|
+
else
|
|
126
|
+
checkRemoteUrl(appUrl);
|
|
127
|
+
const price = priceFor(provider.model, env) ?? (await lookupPrice(provider.model, env.AUTOHEAL_BASE_URL, { log }));
|
|
128
|
+
if (!price)
|
|
129
|
+
log(`No price is known for ${provider.model}, so max-usd cannot be enforced (only a token cap). Set AUTOHEAL_PRICE_IN and AUTOHEAL_PRICE_OUT (USD per 1M tokens).`);
|
|
115
130
|
log(`KeepGreen ${VERSION}: exploring ${appUrl} (${framework}, ${provider.name} ${provider.model}, limit $${config.maxUsd})`);
|
|
116
131
|
engine = await McpTools.start(projectRoot);
|
|
117
132
|
runner = framework === 'cypress' ? new CypressTools(projectRoot, { log }) : framework === 'webdriverio' ? new WdioTools(projectRoot, { log }) : engine;
|
|
@@ -126,11 +141,12 @@ async function cmdExplore(argv) {
|
|
|
126
141
|
maxFlows: config.maxFlows,
|
|
127
142
|
maxUsd: config.maxUsd,
|
|
128
143
|
runs: config.runs,
|
|
129
|
-
price
|
|
144
|
+
price,
|
|
130
145
|
framework,
|
|
131
146
|
cover,
|
|
132
147
|
log,
|
|
133
148
|
dryRun: values['dry-run'] === true,
|
|
149
|
+
...(values.flow?.length ? { flows: values.flow } : {}),
|
|
134
150
|
});
|
|
135
151
|
const report = exploreReport(result, config.runs);
|
|
136
152
|
process.stdout.write(`\n${report}\n`);
|
|
@@ -139,7 +155,14 @@ async function cmdExplore(argv) {
|
|
|
139
155
|
const out = path.resolve(values.out);
|
|
140
156
|
await mkdir(out, { recursive: true });
|
|
141
157
|
await writeFile(path.join(out, 'report.md'), `${report}\n`);
|
|
142
|
-
await writeFile(path.join(out, 'summary.json'), `${JSON.stringify({
|
|
158
|
+
await writeFile(path.join(out, 'summary.json'), `${JSON.stringify({
|
|
159
|
+
version: VERSION,
|
|
160
|
+
written,
|
|
161
|
+
flows: result.flows,
|
|
162
|
+
results: result.results.map(({ flow, result: r }) => ({ flow: flow.flow, status: r.status, file: r.file, explanation: r.explanation })),
|
|
163
|
+
usd: result.usd,
|
|
164
|
+
priced: result.priced,
|
|
165
|
+
}, null, 2)}\n`);
|
|
143
166
|
await writeFile(path.join(out, 'new-tests.patch'), await newFilesPatch(projectRoot, written));
|
|
144
167
|
log(`Wrote ${path.relative(process.cwd(), out) || '.'}/report.md, summary.json and new-tests.patch`);
|
|
145
168
|
}
|
|
@@ -154,6 +177,21 @@ async function cmdExplore(argv) {
|
|
|
154
177
|
await app?.stop().catch(() => undefined);
|
|
155
178
|
}
|
|
156
179
|
}
|
|
180
|
+
/** A running app to explore: any http(s) address without a user name or password in it. */
|
|
181
|
+
export function checkRemoteUrl(url) {
|
|
182
|
+
let u;
|
|
183
|
+
try {
|
|
184
|
+
u = new URL(url);
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
throw new ConfigError(`url is not a URL: ${url}`);
|
|
188
|
+
}
|
|
189
|
+
if (u.protocol !== 'http:' && u.protocol !== 'https:')
|
|
190
|
+
throw new ConfigError('url must start with http:// or https://');
|
|
191
|
+
if (u.username || u.password)
|
|
192
|
+
throw new ConfigError('Do not put a user name or password in url.');
|
|
193
|
+
return u;
|
|
194
|
+
}
|
|
157
195
|
async function cmdInit(argv) {
|
|
158
196
|
const { values } = parseArgs({ args: argv, options: { project: { type: 'string' }, force: { type: 'boolean' }, 'dry-run': { type: 'boolean' } }, strict: true });
|
|
159
197
|
const root = path.resolve(values.project ?? '.');
|
|
@@ -242,6 +280,14 @@ export async function main(argv) {
|
|
|
242
280
|
log(error.message);
|
|
243
281
|
return 2;
|
|
244
282
|
}
|
|
283
|
+
if (error instanceof ProviderError) {
|
|
284
|
+
log(`The AI provider refused the request: ${error.message.slice(0, 600)}`);
|
|
285
|
+
if (/HTTP 402|credits|quota|insufficient/i.test(error.message))
|
|
286
|
+
log('Your AI account or key is out of credit (or its spend limit is too low). Add credit or raise the key\'s limit, then run again.');
|
|
287
|
+
else if (/HTTP 401|HTTP 403|api key|unauthori/i.test(error.message))
|
|
288
|
+
log('Check the API key (and AUTOHEAL_BASE_URL / AUTOHEAL_MODEL for OpenAI-compatible endpoints).');
|
|
289
|
+
return 1;
|
|
290
|
+
}
|
|
245
291
|
log(error instanceof Error ? (error.stack ?? error.message) : String(error));
|
|
246
292
|
return 1;
|
|
247
293
|
}
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;GAMG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC1E,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EACL,WAAW,EACX,YAAY,EACZ,QAAQ,EACR,SAAS,EACT,WAAW,EACX,KAAK,EACL,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,QAAQ,EACR,eAAe,EACf,QAAQ,GAIT,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACtE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,MAAM,CAAC,MAAM,KAAK,GAAG,aAAa,OAAO;;;;;;;;;;;;;;;;;;;;;;CAsBxC,CAAC;AAEF,MAAM,GAAG,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,eAAe,IAAI,IAAI,CAAC,CAAC;AAE5E,4EAA4E;AAC5E,MAAM,UAAU,WAAW;IACzB,MAAM,KAAK,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC;IACrE,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,CAAC;AAClD,CAAC;AAED,SAAS,WAAW,CAAC,IAAc;IACjC,MAAM,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,WAAW,EAAE,EAAE,GAAG,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;IACtF,IAAI,CAAC,CAAC,KAAK;QAAE,MAAM,CAAC,CAAC,KAAK,CAAC;IAC3B,OAAO,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC;AACvB,CAAC;AAED,KAAK,UAAU,eAAe,CAAC,IAAY,EAAE,KAAyB;IACpE,IAAI,OAA4C,CAAC;IACjD,IAAI,CAAC;QACH,OAAO,GAAG,gBAAgB,CAAC,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IACtE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,WAAW,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAChF,CAAC;IACD,IAAI,OAAO,KAAK,MAAM;QAAE,OAAO,OAAO,CAAC;IACvC,IAAI,MAAM,aAAa,CAAC,IAAI,CAAC;QAAE,OAAO,aAAa,CAAC;IACpD,IAAI,MAAM,gBAAgB,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IACnD,OAAO,CAAC,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC;AACjE,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,IAAc;IACtC,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;QAC3B,IAAI,EAAE,IAAI;QACV,OAAO,EAAE;YACP,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YACvB,eAAe,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YACnC,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC/B,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YACzB,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC/B,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC7B,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YACxB,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC7B,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC3B,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YACvB,SAAS,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;SAC/B;QACD,MAAM,EAAE,IAAI;KACb,CAAC,CAAC;IACH,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,IAAI,GAAG,CAAC,CAAC;IACxD,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,GAAG,KAAK,EAAE,GAAG,MAAM,CAAC;IACjE,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,cAAc,CAAC,WAAW,CAAC,EAAE,KAA2C,CAAC,CAAC;IAC7G,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IACxB,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;IACtC,IAAI,CAAC,QAAQ;QAAE,MAAM,IAAI,WAAW,CAAC,qHAAqH,CAAC,CAAC;IAC5J,MAAM,SAAS,GAAG,MAAM,eAAe,CAAC,WAAW,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;IAEvE,IAAI,GAAG,GAAsB,IAAI,CAAC;IAClC,IAAI,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC;IACxB,IAAI,MAAM,GAAoB,IAAI,CAAC;IACnC,IAAI,MAAM,GAAsB,IAAI,CAAC;IACrC,IAAI,CAAC;QACH,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;YACxB,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,GAAG,CAAC;YAC1C,IAAI,CAAC,GAAG;gBAAE,MAAM,IAAI,WAAW,CAAC,yDAAyD,CAAC,CAAC;YAC3F,oFAAoF;YACpF,GAAG,GAAG,MAAM,QAAQ,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,YAAY,EAAE,GAAG,EAAE,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;YAClG,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC;QACnB,CAAC;QACD,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,WAAW,CAAC,4HAA4H,CAAC,CAAC;QACjK,WAAW,CAAC,MAAM,CAAC,CAAC;QACpB,GAAG,CAAC,aAAa,OAAO,eAAe,MAAM,KAAK,SAAS,KAAK,QAAQ,CAAC,IAAI,IAAI,QAAQ,CAAC,KAAK,YAAY,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;QAC7H,MAAM,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QAC3C,MAAM,GAAG,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,YAAY,CAAC,WAAW,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,KAAK,aAAa,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC,WAAW,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QACvJ,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC;YAC3B,WAAW;YACX,QAAQ;YACR,MAAM;YACN,MAAM;YACN,MAAM;YACN,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,QAAQ,EAAE,MAAM,cAAc,CAAC,WAAW,CAAC;YAC3C,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,KAAK,EAAE,QAAQ,CAAC,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC;YACpC,SAAS;YACT,KAAK;YACL,GAAG;YACH,MAAM,EAAE,MAAM,CAAC,SAAS,CAAC,KAAK,IAAI;SACnC,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;QAClD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,MAAM,IAAI,CAAC,CAAC;QACtC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACtG,IAAI,MAAM,CAAC,GAAG,EAAE,CAAC;YACf,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACrC,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACtC,MAAM,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,EAAE,GAAG,MAAM,IAAI,CAAC,CAAC;YAC5D,MAAM,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;YACrJ,MAAM,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,iBAAiB,CAAC,EAAE,MAAM,aAAa,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC;YAC9F,GAAG,CAAC,SAAS,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,CAAC,IAAI,GAAG,8CAA8C,CAAC,CAAC;QACvG,CAAC;QACD,IAAI,GAAG,CAAC,mBAAmB;YAAE,MAAM,UAAU,CAAC,GAAG,CAAC,mBAAmB,EAAE,GAAG,MAAM,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC7G,OAAO,MAAM,CAAC,SAAS,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACrD,CAAC;YAAS,CAAC;QACT,IAAI,MAAM,IAAI,MAAM,KAAK,MAAM;YAAE,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC7E,MAAM,MAAM,EAAE,KAAK,EAAE,CAAC;QACtB,MAAM,GAAG,EAAE,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;IAC3C,CAAC;AACH,CAAC;AAED,KAAK,UAAU,OAAO,CAAC,IAAc;IACnC,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IACjK,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,IAAI,GAAG,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,KAAK,IAAI,CAAC;IAC1C,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,KAAK,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IACrE,MAAM,GAAG,GAAG,CAAC,aAAa,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;IACzC,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO;QAAE,GAAG,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC;IAClF,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO;QAAE,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,iCAAiC,CAAC,CAAC;IACnF,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,+BAA+B,EAAE,EAAE,CAAC,CAAC;IAClD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACrC,MAAM,IAAI,GAAG,WAAW,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAChJ,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB;QACE,EAAE;QACF,8BAA8B;QAC9B,iGAAiG;QACjG,sGAAsG;QACtG,kFAAkF;QAClF,uGAAuG;QACvG,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;IACF,OAAO,IAAI,CAAC;AACd,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,IAAc;IACrC,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IACrG,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,IAAI,GAAG,CAAC,CAAC;IACjD,MAAM,KAAK,GAAG,CAAC,aAAa,OAAO,SAAS,EAAE,EAAE,CAAC,CAAC;IAClD,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,cAAc,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;QAC7D,MAAM,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,kBAAkB,MAAM,CAAC,YAAY,UAAU,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,GAAG,IAAI,iBAAiB,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC;QAChK,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,yBAAyB,MAAM,EAAE,CAAC,CAAC,CAAC,iEAAiE,CAAC,CAAC;QAC3H,IAAI,MAAM,CAAC,YAAY,IAAI,CAAC,CAAC,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,GAAG,CAAC;YAAE,MAAM,GAAG,IAAI,CAAC;IAC7E,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,GAAG,IAAI,CAAC;QACd,KAAK,CAAC,IAAI,CAAC,yBAAyB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAChG,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,wCAAwC,EAAE,EAAE,CAAC,CAAC;IAC7D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACvC,MAAM,IAAI,GAAG,WAAW,CAAC,CAAC,QAAQ,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC;IACxD,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3B,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,IAAc;IACzC,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACrB,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,IAAI,WAAW,CAAC,qCAAqC,CAAC,CAAC;IAC3F,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IACxD,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;QACd,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrD,OAAO,CAAC,CAAC;IACX,CAAC;IACD,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,qBAAqB,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC;IACvK,OAAO,CAAC,CAAC;AACX,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,IAAc;IACvC,MAAM,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IAChC,IAAI,CAAC;QACH,IAAI,CAAC,OAAO,IAAI,OAAO,KAAK,MAAM,IAAI,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YAC/E,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YAC5B,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACzB,CAAC;QACD,IAAI,OAAO,KAAK,WAAW,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YACzE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC;YACrC,OAAO,CAAC,CAAC;QACX,CAAC;QACD,IAAI,OAAO,KAAK,SAAS;YAAE,OAAO,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;QACzD,IAAI,OAAO,KAAK,MAAM;YAAE,OAAO,WAAW,CAAC,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC;QAC7D,IAAI,OAAO,KAAK,UAAU;YAAE,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC;QACrD,IAAI,OAAO,KAAK,MAAM;YAAE,OAAO,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;QACnD,IAAI,OAAO,KAAK,QAAQ;YAAE,OAAO,MAAM,SAAS,CAAC,IAAI,CAAC,CAAC;QACvD,IAAI,OAAO,KAAK,aAAa;YAAE,OAAO,MAAM,aAAa,CAAC,IAAI,CAAC,CAAC;QAChE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,oBAAoB,OAAO,SAAS,KAAK,EAAE,CAAC,CAAC;QAClE,OAAO,CAAC,CAAC;IACX,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,WAAW,IAAI,KAAK,YAAY,eAAe,IAAK,KAA2B,CAAC,IAAI,EAAE,UAAU,CAAC,gBAAgB,CAAC,EAAE,CAAC;YACxI,GAAG,CAAE,KAAe,CAAC,OAAO,CAAC,CAAC;YAC9B,OAAO,CAAC,CAAC;QACX,CAAC;QACD,GAAG,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC7E,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC;AAED,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;AACzF,IAAI,OAAO,KAAK,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;IAChC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;QACxC,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/explore.d.ts
CHANGED
|
@@ -57,10 +57,18 @@ export interface ExploreOptions extends Omit<PlanOptions, 'budget'> {
|
|
|
57
57
|
cover: (options: CoverOptions) => Promise<CoverResult>;
|
|
58
58
|
/** Plan only, write nothing. */
|
|
59
59
|
dryRun?: boolean;
|
|
60
|
+
/** Flows named by the user: skip planning and write a test for each. */
|
|
61
|
+
flows?: string[];
|
|
60
62
|
}
|
|
61
63
|
/** Plan, then write one test per flow. The spend cap covers the whole run. */
|
|
62
64
|
export declare function explore(options: ExploreOptions): Promise<ExploreResult>;
|
|
63
65
|
/** tests/keepgreen-<words>.spec.ts (pytest: tests/test_keepgreen_<words>.py), so KeepGreen's tests are easy to spot. */
|
|
64
66
|
export declare function testFileFor(flow: string, framework: NonNullable<CoverOptions['framework']>): string;
|
|
67
|
+
/**
|
|
68
|
+
* testFileFor, plus -2, -3 ... when that name is already used by a file on
|
|
69
|
+
* disk or by an earlier flow of this run. AutoHeal's cover refuses to write
|
|
70
|
+
* over an existing file, so two flows with the same name used to lose one.
|
|
71
|
+
*/
|
|
72
|
+
export declare function uniqueTestFile(flow: string, framework: NonNullable<CoverOptions['framework']>, root: string, taken: Set<string>): Promise<string>;
|
|
65
73
|
/** Markdown summary for the terminal, the job summary and the PR body. */
|
|
66
74
|
export declare function exploreReport(result: ExploreResult, runs: number): string;
|
package/dist/explore.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*
|
|
11
11
|
* The AI key is the user's own. Nothing here talks to an XSignOn server.
|
|
12
12
|
*/
|
|
13
|
-
import { readdir, readFile, stat } from 'node:fs/promises';
|
|
13
|
+
import { access, readdir, readFile, stat } from 'node:fs/promises';
|
|
14
14
|
import path from 'node:path';
|
|
15
15
|
import { Budget, ProviderError, coverFile } from 'xsignon-autoheal';
|
|
16
16
|
const PLAN_PROMPT = `You are KeepGreen, a senior test engineer planning end-to-end test coverage for a web app.
|
|
@@ -158,9 +158,13 @@ export async function existingTitles(root) {
|
|
|
158
158
|
export async function explore(options) {
|
|
159
159
|
const log = options.log ?? (() => undefined);
|
|
160
160
|
const planBudget = new Budget({ maxUsd: Math.min(0.5, options.maxUsd * 0.15), maxTokens: 400_000, maxSteps: 3 }, options.price);
|
|
161
|
-
const
|
|
161
|
+
const given = options.flows?.length ? cleanFlows(options.flows.map((flow) => ({ flow, why: 'named by you' })), options.maxFlows) : null;
|
|
162
|
+
if (options.flows?.length && !given?.length)
|
|
163
|
+
throw new Error('Each --flow must be one sentence of 10 to 500 characters.');
|
|
164
|
+
const flows = given ?? (await planFlows({ ...options, budget: planBudget }));
|
|
162
165
|
let spent = planBudget.snapshot().usd;
|
|
163
|
-
let priced = planBudget.snapshot().priced;
|
|
166
|
+
let priced = given ? options.price !== null : planBudget.snapshot().priced;
|
|
167
|
+
const taken = new Set();
|
|
164
168
|
const results = [];
|
|
165
169
|
if (!flows.length)
|
|
166
170
|
log('The AI found no untested flows to add.');
|
|
@@ -184,7 +188,7 @@ export async function explore(options) {
|
|
|
184
188
|
result = await options.cover({
|
|
185
189
|
projectRoot: options.projectRoot,
|
|
186
190
|
flow: flow.flow,
|
|
187
|
-
file:
|
|
191
|
+
file: await uniqueTestFile(flow.flow, options.framework, options.projectRoot, taken),
|
|
188
192
|
appUrl: options.appUrl,
|
|
189
193
|
provider: options.provider,
|
|
190
194
|
budget,
|
|
@@ -205,12 +209,39 @@ export async function explore(options) {
|
|
|
205
209
|
}
|
|
206
210
|
return { flows, results, usd: spent, priced };
|
|
207
211
|
}
|
|
212
|
+
// Words that say nothing about the flow. Most flows start "A visitor opens the
|
|
213
|
+
// home page...", so without this every file name would start the same way.
|
|
214
|
+
const FILLER = new Set(['a', 'an', 'the', 'and', 'then', 'or', 'to', 'of', 'on', 'in', 'at', 'from', 'with', 'where', 'that', 'is', 'are', 'it', 'its', 'their', 'his', 'her', 'they', 'user', 'users', 'visitor', 'visitors', 'shopper', 'customer', 'someone', 'person', 'sees', 'see', 'can', 'least', 'for', 'page']);
|
|
208
215
|
/** tests/keepgreen-<words>.spec.ts (pytest: tests/test_keepgreen_<words>.py), so KeepGreen's tests are easy to spot. */
|
|
209
216
|
export function testFileFor(flow, framework) {
|
|
210
|
-
|
|
217
|
+
const words = flow.toLowerCase().replace(/[^a-z0-9]+/g, ' ').trim().split(' ').filter(Boolean);
|
|
218
|
+
const meaningful = [...new Set(words.filter((w) => !FILLER.has(w)))];
|
|
219
|
+
const named = (meaningful.length >= 2 ? meaningful : words).join(' ');
|
|
220
|
+
return coverFile(named || flow, framework).replace(/autoheal-/, 'keepgreen-').replace(/test_autoheal_/, 'test_keepgreen_');
|
|
211
221
|
}
|
|
222
|
+
/**
|
|
223
|
+
* testFileFor, plus -2, -3 ... when that name is already used by a file on
|
|
224
|
+
* disk or by an earlier flow of this run. AutoHeal's cover refuses to write
|
|
225
|
+
* over an existing file, so two flows with the same name used to lose one.
|
|
226
|
+
*/
|
|
227
|
+
export async function uniqueTestFile(flow, framework, root, taken) {
|
|
228
|
+
const base = testFileFor(flow, framework);
|
|
229
|
+
const dot = base.search(/(?:\.spec|\.cy|\.e2e)?\.[a-z]+$/);
|
|
230
|
+
for (let n = 1; n < 100; n++) {
|
|
231
|
+
const file = n === 1 ? base : `${base.slice(0, dot)}${framework === 'pytest' ? '_' : '-'}${n}${base.slice(dot)}`;
|
|
232
|
+
if (taken.has(file))
|
|
233
|
+
continue;
|
|
234
|
+
const onDisk = await access(path.join(root, file)).then(() => true, () => false);
|
|
235
|
+
if (onDisk)
|
|
236
|
+
continue;
|
|
237
|
+
taken.add(file);
|
|
238
|
+
return file;
|
|
239
|
+
}
|
|
240
|
+
throw new Error(`Too many test files named like ${base}.`);
|
|
241
|
+
}
|
|
242
|
+
/** One table cell. AI text goes into a PR body, so @mentions are defused (no one gets pinged). */
|
|
212
243
|
function cell(text) {
|
|
213
|
-
return text.replace(/\|/g, '\\|').replace(/\s+/g, ' ').trim();
|
|
244
|
+
return text.replace(/\|/g, '\\|').replace(/\s+/g, ' ').replace(/@(?=[A-Za-z0-9_-])/g, '@\u200b').trim();
|
|
214
245
|
}
|
|
215
246
|
/** Markdown summary for the terminal, the job summary and the PR body. */
|
|
216
247
|
export function exploreReport(result, runs) {
|
|
@@ -231,7 +262,7 @@ export function exploreReport(result, runs) {
|
|
|
231
262
|
lines.push('');
|
|
232
263
|
}
|
|
233
264
|
else if (result.flows.length) {
|
|
234
|
-
lines.push('Planned flows (dry run, nothing written):', '', ...result.flows.map((f, i) => `${i + 1}. ${f.flow} (${f.why})`), '');
|
|
265
|
+
lines.push('Planned flows (dry run, nothing written):', '', ...result.flows.map((f, i) => `${i + 1}. ${cell(f.flow)} (${cell(f.why)})`), '');
|
|
235
266
|
}
|
|
236
267
|
lines.push(`AI spend: ${result.priced ? `about $${result.usd.toFixed(2)}` : 'unknown (model price not listed; set AUTOHEAL_PRICE_IN / AUTOHEAL_PRICE_OUT)'}, billed by your own AI provider.`);
|
|
237
268
|
lines.push('', 'Review each test like any other change before you merge it.');
|
package/dist/explore.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"explore.js","sourceRoot":"","sources":["../src/explore.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"explore.js","sourceRoot":"","sources":["../src/explore.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
export { explore, planFlows, cleanFlows, existingTitles, listTestFiles, exploreReport, testFileFor, type Flow, type ExploreOptions, type ExploreResult, type PlanOptions } from './explore.js';
|
|
1
|
+
export { explore, planFlows, cleanFlows, existingTitles, listTestFiles, exploreReport, testFileFor, uniqueTestFile, type Flow, type ExploreOptions, type ExploreResult, type PlanOptions } from './explore.js';
|
|
2
2
|
export { parseConfig, resolveConfig, loadConfigFile, CONFIG_FILE, DEFAULTS, ConfigFileError, type KeepGreenConfig } from './config.js';
|
|
3
3
|
export { checkPatch, type PatchCheck } from './patch.js';
|
|
4
4
|
export { addFilePatch, newFilesPatch } from './newfiles.js';
|
|
5
5
|
export { init, type InitResult } from './init.js';
|
|
6
|
+
export { lookupPrice } from './price.js';
|
|
6
7
|
export { VERSION } from './version.js';
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
export { explore, planFlows, cleanFlows, existingTitles, listTestFiles, exploreReport, testFileFor } from './explore.js';
|
|
1
|
+
export { explore, planFlows, cleanFlows, existingTitles, listTestFiles, exploreReport, testFileFor, uniqueTestFile } from './explore.js';
|
|
2
2
|
export { parseConfig, resolveConfig, loadConfigFile, CONFIG_FILE, DEFAULTS, ConfigFileError } from './config.js';
|
|
3
3
|
export { checkPatch } from './patch.js';
|
|
4
4
|
export { addFilePatch, newFilesPatch } from './newfiles.js';
|
|
5
5
|
export { init } from './init.js';
|
|
6
|
+
export { lookupPrice } from './price.js';
|
|
6
7
|
export { VERSION } from './version.js';
|
|
7
8
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,cAAc,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAwE,MAAM,cAAc,CAAC;AAC/
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,cAAc,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,cAAc,EAAwE,MAAM,cAAc,CAAC;AAC/M,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,cAAc,EAAE,WAAW,EAAE,QAAQ,EAAE,eAAe,EAAwB,MAAM,aAAa,CAAC;AACvI,OAAO,EAAE,UAAU,EAAmB,MAAM,YAAY,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC5D,OAAO,EAAE,IAAI,EAAmB,MAAM,WAAW,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/price.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prices for models AutoHeal's table does not list. OpenRouter publishes the
|
|
3
|
+
* price of every model it serves, so for an OpenRouter base URL KeepGreen
|
|
4
|
+
* looks the model up instead of running with no dollar cap. It is a plain GET
|
|
5
|
+
* of the public model list: no key and nothing about your project goes with it.
|
|
6
|
+
*/
|
|
7
|
+
export interface LookupOptions {
|
|
8
|
+
fetchFn?: typeof fetch;
|
|
9
|
+
log?: (line: string) => void;
|
|
10
|
+
timeoutMs?: number;
|
|
11
|
+
}
|
|
12
|
+
/** USD per 1M tokens [in, out], or null when unknown. */
|
|
13
|
+
export declare function lookupPrice(model: string, baseUrl: string | undefined, options?: LookupOptions): Promise<[number, number] | null>;
|
package/dist/price.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prices for models AutoHeal's table does not list. OpenRouter publishes the
|
|
3
|
+
* price of every model it serves, so for an OpenRouter base URL KeepGreen
|
|
4
|
+
* looks the model up instead of running with no dollar cap. It is a plain GET
|
|
5
|
+
* of the public model list: no key and nothing about your project goes with it.
|
|
6
|
+
*/
|
|
7
|
+
/** USD per 1M tokens [in, out], or null when unknown. */
|
|
8
|
+
export async function lookupPrice(model, baseUrl, options = {}) {
|
|
9
|
+
if (!baseUrl || !model)
|
|
10
|
+
return null;
|
|
11
|
+
let host;
|
|
12
|
+
try {
|
|
13
|
+
host = new URL(baseUrl).hostname;
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
if (host !== 'openrouter.ai' && !host.endsWith('.openrouter.ai'))
|
|
19
|
+
return null;
|
|
20
|
+
const fetchFn = options.fetchFn ?? fetch;
|
|
21
|
+
try {
|
|
22
|
+
const res = await fetchFn('https://openrouter.ai/api/v1/models', { signal: AbortSignal.timeout(options.timeoutMs ?? 10_000) });
|
|
23
|
+
if (!res.ok)
|
|
24
|
+
return null;
|
|
25
|
+
const body = (await res.json());
|
|
26
|
+
const entry = body.data?.find((m) => m.id === model);
|
|
27
|
+
const pin = Number(entry?.pricing?.prompt);
|
|
28
|
+
const pout = Number(entry?.pricing?.completion);
|
|
29
|
+
if (!entry || !Number.isFinite(pin) || !Number.isFinite(pout) || pin < 0 || pout < 0)
|
|
30
|
+
return null;
|
|
31
|
+
const price = [round(pin * 1e6), round(pout * 1e6)];
|
|
32
|
+
options.log?.(`OpenRouter price for ${model}: $${price[0]} in / $${price[1]} out per 1M tokens`);
|
|
33
|
+
return price;
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function round(n) {
|
|
40
|
+
return Math.round(n * 1e6) / 1e6;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=price.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"price.js","sourceRoot":"","sources":["../src/price.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,yDAAyD;AACzD,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,KAAa,EAAE,OAA2B,EAAE,UAAyB,EAAE;IACvG,IAAI,CAAC,OAAO,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACpC,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,IAAI,KAAK,eAAe,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9E,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,KAAK,CAAC;IACzC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,qCAAqC,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,IAAI,MAAM,CAAC,EAAE,CAAC,CAAC;QAC/H,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,OAAO,IAAI,CAAC;QACzB,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAA0F,CAAC;QACzH,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC,CAAC;QACrD,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QAC3C,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;QAChD,IAAI,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QAClG,MAAM,KAAK,GAAqB,CAAC,KAAK,CAAC,GAAG,GAAG,GAAG,CAAC,EAAE,KAAK,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC;QACtE,OAAO,CAAC,GAAG,EAAE,CAAC,wBAAwB,KAAK,MAAM,KAAK,CAAC,CAAC,CAAC,UAAU,KAAK,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC;QACjG,OAAO,KAAK,CAAC;IACf,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,KAAK,CAAC,CAAS;IACtB,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;AACnC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "keepgreen",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Free, self-hosted AI test agent: explores your app and writes new Playwright tests, and fixes the ones that break, with your own AI key. Built on playwright-e2e-mcp and AutoHeal.",
|
|
5
5
|
"author": "xsignon-secure (https://github.com/xsignon-secure)",
|
|
6
6
|
"license": "MIT",
|
|
@@ -18,11 +18,18 @@
|
|
|
18
18
|
# version, install steps, browsers, env vars and services, so the app and
|
|
19
19
|
# the tests run here the same way they do in your CI.
|
|
20
20
|
# 3. Add your AI key as a repository secret named ANTHROPIC_API_KEY
|
|
21
|
-
# (or OPENAI_API_KEY plus a repository variable AUTOHEAL_MODEL
|
|
21
|
+
# (or OPENAI_API_KEY plus a repository variable AUTOHEAL_MODEL; or
|
|
22
|
+
# OpenRouter: see base-url / api-key below).
|
|
23
|
+
# If playwright.config has a webServer, let Playwright reuse the app
|
|
24
|
+
# KeepGreen started: reuseExistingServer: !process.env.CI || !!process.env.KEEPGREEN
|
|
22
25
|
# 4. Settings > Actions > General > Workflow permissions: tick
|
|
23
26
|
# "Allow GitHub Actions to create and approve pull requests".
|
|
24
27
|
# 5. Run it from Actions > KeepGreen explore > Run workflow, or turn on the
|
|
25
28
|
# weekly schedule below.
|
|
29
|
+
# Optional: GitHub does not start your CI on a PR opened with the built-in
|
|
30
|
+
# token. To get checks on KeepGreen's PRs, add a fine-grained token (this
|
|
31
|
+
# repo only; Contents + Pull requests: read and write) as the secret
|
|
32
|
+
# KEEPGREEN_PR_TOKEN. Only the publish job sees it.
|
|
26
33
|
#
|
|
27
34
|
# Your AI key is in the explore job, where the new tests run. Use a key with
|
|
28
35
|
# a spend limit.
|
|
@@ -36,9 +43,11 @@ on:
|
|
|
36
43
|
description: App URL to explore (blank = url in .keepgreen.yml)
|
|
37
44
|
required: false
|
|
38
45
|
max-flows:
|
|
39
|
-
description: New tests to try (1-10)
|
|
46
|
+
description: New tests to try (1-10; blank = .keepgreen.yml)
|
|
47
|
+
required: false
|
|
48
|
+
flows:
|
|
49
|
+
description: Optional. Flows to test, separated by ";" (blank = the AI picks)
|
|
40
50
|
required: false
|
|
41
|
-
default: "3"
|
|
42
51
|
# schedule:
|
|
43
52
|
# - cron: "0 6 * * 1" # every Monday 06:00 UTC
|
|
44
53
|
|
|
@@ -55,28 +64,63 @@ jobs:
|
|
|
55
64
|
timeout-minutes: 60
|
|
56
65
|
permissions:
|
|
57
66
|
contents: read
|
|
67
|
+
pull-requests: read
|
|
58
68
|
outputs:
|
|
59
69
|
written: ${{ steps.keepgreen.outputs.written }}
|
|
60
70
|
steps:
|
|
71
|
+
# A KeepGreen PR still waiting for review means the same flows would be
|
|
72
|
+
# planned again, so a scheduled run stops here. A manual run goes ahead.
|
|
73
|
+
- name: Skip if a KeepGreen PR is still open
|
|
74
|
+
id: open
|
|
75
|
+
if: github.event_name == 'schedule'
|
|
76
|
+
env:
|
|
77
|
+
GH_TOKEN: ${{ github.token }}
|
|
78
|
+
REPO: ${{ github.repository }}
|
|
79
|
+
run: |
|
|
80
|
+
n="$(gh pr list --repo "$REPO" --state open --json headRefName --jq '[.[] | select(.headRefName | startswith("keepgreen/explore-"))] | length')"
|
|
81
|
+
echo "count=$n" >> "$GITHUB_OUTPUT"
|
|
82
|
+
[ "$n" = "0" ] || echo "::notice::A KeepGreen PR is still open; review or close it first. Skipping this run."
|
|
61
83
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
84
|
+
if: steps.open.outputs.count == '0' || steps.open.outputs.count == ''
|
|
62
85
|
with:
|
|
63
86
|
persist-credentials: false
|
|
64
87
|
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
|
|
88
|
+
if: steps.open.outputs.count == '0' || steps.open.outputs.count == ''
|
|
65
89
|
with:
|
|
66
90
|
node-version: 22
|
|
67
91
|
# Your install steps (same as your test workflow):
|
|
68
|
-
-
|
|
69
|
-
|
|
92
|
+
- if: steps.open.outputs.count == '0' || steps.open.outputs.count == ''
|
|
93
|
+
run: npm ci
|
|
94
|
+
- if: steps.open.outputs.count == '0' || steps.open.outputs.count == ''
|
|
95
|
+
run: npx playwright install --with-deps chromium
|
|
96
|
+
- name: Flows you named
|
|
97
|
+
id: flows
|
|
98
|
+
if: inputs.flows != ''
|
|
99
|
+
env:
|
|
100
|
+
FLOWS: ${{ inputs.flows }}
|
|
101
|
+
run: |
|
|
102
|
+
{
|
|
103
|
+
echo 'list<<KEEPGREEN_EOF'
|
|
104
|
+
printf '%s\n' "$FLOWS" | tr ';' '\n'
|
|
105
|
+
echo 'KEEPGREEN_EOF'
|
|
106
|
+
} >> "$GITHUB_OUTPUT"
|
|
70
107
|
- id: keepgreen
|
|
108
|
+
if: steps.open.outputs.count == '0' || steps.open.outputs.count == ''
|
|
71
109
|
uses: xsignon-secure/keepgreen@v{{VERSION}}
|
|
72
110
|
with:
|
|
73
111
|
url: ${{ inputs.url }}
|
|
74
112
|
max-flows: ${{ inputs.max-flows }}
|
|
113
|
+
flows: ${{ steps.flows.outputs.list }}
|
|
75
114
|
anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
76
115
|
openai-api-key: ${{ secrets.OPENAI_API_KEY }}
|
|
77
116
|
model: ${{ vars.AUTOHEAL_MODEL }}
|
|
117
|
+
# OpenRouter or another OpenAI-compatible endpoint instead:
|
|
118
|
+
# base-url: https://openrouter.ai/api/v1
|
|
119
|
+
# api-key: ${{ secrets.OPENROUTER_API_KEY }}
|
|
120
|
+
# price-in: "3" # USD per 1M tokens of your model, so max-usd is enforced
|
|
121
|
+
# price-out: "15"
|
|
78
122
|
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
|
79
|
-
if: steps.keepgreen.outputs.written != '0'
|
|
123
|
+
if: steps.keepgreen.outputs.written != '0' && steps.keepgreen.outputs.written != ''
|
|
80
124
|
with:
|
|
81
125
|
name: keepgreen-out
|
|
82
126
|
path: keepgreen-out/
|
|
@@ -93,6 +137,10 @@ jobs:
|
|
|
93
137
|
pull-requests: write
|
|
94
138
|
steps:
|
|
95
139
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
140
|
+
with:
|
|
141
|
+
# With KEEPGREEN_PR_TOKEN the push and the PR start your CI; the
|
|
142
|
+
# built-in token works too, but GitHub then runs no checks on the PR.
|
|
143
|
+
token: ${{ secrets.KEEPGREEN_PR_TOKEN || github.token }}
|
|
96
144
|
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
|
97
145
|
with:
|
|
98
146
|
name: keepgreen-out
|
|
@@ -107,9 +155,9 @@ jobs:
|
|
|
107
155
|
run: npx -y keepgreen@{{VERSION}} check-patch "$OUT/new-tests.patch"
|
|
108
156
|
- name: Open the pull request
|
|
109
157
|
env:
|
|
110
|
-
GH_TOKEN: ${{ github.token }}
|
|
158
|
+
GH_TOKEN: ${{ secrets.KEEPGREEN_PR_TOKEN || github.token }}
|
|
111
159
|
OUT: ${{ runner.temp }}/keepgreen-out
|
|
112
|
-
BRANCH: keepgreen/explore-${{ github.run_id }}
|
|
160
|
+
BRANCH: keepgreen/explore-${{ github.run_id }}-${{ github.run_attempt }}
|
|
113
161
|
run: |
|
|
114
162
|
git -c core.hooksPath=/dev/null apply --check "$OUT/new-tests.patch"
|
|
115
163
|
git -c core.hooksPath=/dev/null apply "$OUT/new-tests.patch"
|