keepgreen 0.1.1 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.1
4
+
5
+ - AutoHeal 0.13.0 inside (healing and test writing): OpenRouter works in AutoHeal's heal Action (`api-key` input), OpenRouter prices are looked up for healing too, and the engine is playwright-e2e-mcp 0.16.1 (Playwright 1.65, GitHub tokens kept out of test processes).
6
+ - The self-host bundle builds the AutoHeal dashboard from v0.13.0.
7
+
8
+ ## 0.2.0
9
+
10
+ Fixes from a full audit, plus the most-asked-for features.
11
+
12
+ - **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.
13
+ - **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 `;`).
14
+ - **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.
15
+ - **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.
16
+ - **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.
17
+ - **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.
18
+ - **PR bodies can't ping people.** `@name` in AI-written flow text is defused before it goes into the report.
19
+ - `summary.json` now lists each flow's result (status, file, reason) and whether the spend is priced.
20
+
3
21
  ## 0.1.1
4
22
 
5
23
  - 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.
package/README.md CHANGED
@@ -1,27 +1,75 @@
1
- # KeepGreen
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
- **Your AI test agent that writes, fixes and keeps your end-to-end tests green.**
5
+ <h1 align="center">KeepGreen</h1>
4
6
 
5
- KeepGreen is free and MIT licensed. It runs on your own CI runner or laptop with your own AI key
6
- (Anthropic, OpenAI or any OpenAI-compatible endpoint, including local models). There is no
7
- KeepGreen server, no account and no telemetry. You pay only your AI provider, and one spend cap
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
- It combines two XSignOn projects into one agent:
11
+ <p align="center">
11
12
 
12
- - [playwright-e2e-mcp](https://github.com/xsignon-secure/E2E) is the toolbox. It opens pages,
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
+ [![npm](https://img.shields.io/npm/v/keepgreen?color=059669)](https://www.npmjs.com/package/keepgreen) [![npm downloads](https://img.shields.io/npm/dm/keepgreen?color=059669)](https://www.npmjs.com/package/keepgreen) [![CI](https://github.com/xsignon-secure/keepgreen/actions/workflows/ci.yml/badge.svg)](https://github.com/xsignon-secure/keepgreen/actions/workflows/ci.yml) [![npm provenance](https://img.shields.io/badge/npm-provenance-059669)](https://www.npmjs.com/package/keepgreen#provenance) [![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE) [![100% free](https://img.shields.io/badge/price-100%25%20free-16a34a)](#-free-forever)
16
14
 
17
- | Recipe | What it does | Command |
18
- | --- | --- | --- |
19
- | **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` |
20
- | **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) |
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
21
34
 
22
- Works with Playwright Test and pytest-playwright. Healing also covers Cypress and WebdriverIO.
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.
23
38
 
24
- ## Quick start (your machine)
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.
43
+
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-<flow>.spec.ts`. Review them with `git diff` and commit the ones you like.
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
- npx keepgreen explore --url http://localhost:3000 --dry-run # plan only: shows the flows it would test
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
- Let KeepGreen start your app:
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
- ```bash
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
- Fix broken tests:
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
- ```bash
51
- npx keepgreen heal # = AutoHeal's `autoheal fix`; changes stay in your working tree for review
99
+ # Fix broken tests; changes stay in your working tree for review
100
+ npx keepgreen heal
52
101
  ```
53
102
 
54
- ## In GitHub Actions
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. It has two jobs. The explore job runs the AI-written tests with a read-only token. The
61
- publish job accepts the result only if it just adds test files, then opens the PR.
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
- You can also use the action directly:
127
+ Or use the action directly:
75
128
 
76
129
  ```yaml
77
- - uses: xsignon-secure/keepgreen@v0.1.1
130
+ - uses: xsignon-secure/keepgreen@v0.2.1
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
- ## Settings
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
@@ -106,20 +186,22 @@ AI settings use AutoHeal's variables:
106
186
  | `OPENAI_API_KEY` + `AUTOHEAL_MODEL` | Use OpenAI |
107
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 listed price |
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
193
  ```bash
114
194
  export AUTOHEAL_BASE_URL=https://openrouter.ai/api/v1
115
195
  export AUTOHEAL_API_KEY=sk-or-... # your OpenRouter key; give it a credit limit
116
- export AUTOHEAL_MODEL=<model id from openrouter.ai/models>
117
- export AUTOHEAL_PRICE_IN=3 AUTOHEAL_PRICE_OUT=15 # USD per 1M tokens of that model, so max-usd is enforced
196
+ export AUTOHEAL_MODEL=anthropic/claude-sonnet-5.5
118
197
  npx keepgreen explore --url http://localhost:3000
119
198
  ```
120
199
 
121
- In the Action: `base-url: https://openrouter.ai/api/v1`, `api-key: ${{ secrets.OPENROUTER_API_KEY }}`,
122
- `model: ...`, and `price-in` / `price-out`.
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`.
202
+
203
+ In the Action: `base-url: https://openrouter.ai/api/v1`, `api-key: ${{ secrets.OPENROUTER_API_KEY }}`
204
+ and `model: ...`.
123
205
 
124
206
  ### Playwright `webServer`
125
207
 
@@ -130,35 +212,21 @@ If your `playwright.config` starts the app with `webServer`, and KeepGreen start
130
212
  webServer: { command: 'npm run start', url: 'http://127.0.0.1:3000/', reuseExistingServer: !process.env.CI || !!process.env.KEEPGREEN },
131
213
  ```
132
214
 
133
- ## How explore works
134
-
135
- 1. **Look.** It opens your app's start page and every path in `pages:` with playwright-e2e-mcp's
136
- `inspect-page`, which lists the interactive elements and their locators.
137
- 2. **Plan.** It reads the titles of your existing tests and asks your AI for the most important
138
- user flows that have no test yet. Flows that pay money, send email or delete data are skipped.
139
- 3. **Write.** For each flow, AutoHeal's `cover` explores the pages, checks every locator, and
140
- writes one test in your project's own style.
141
- 4. **Prove.** The new-test guard rejects tests that cannot fail, or that use skips, faked network
142
- answers, fixed waits, forced clicks or retries. The test must then pass every run in a row.
143
- Anything less is thrown away.
144
-
145
- One `max-usd` cap covers the whole run. Each flow gets an even share of what is left, so money one
146
- flow saves goes to the next.
147
-
148
- ## All commands
215
+ ## 📖 All commands
149
216
 
150
217
  ```
151
218
  keepgreen init [--force] [--dry-run]
152
219
  keepgreen doctor
153
220
  keepgreen explore [--url <app>] [--start-command <cmd> --start-url <url>] [--pages /a,/b]
154
- [--max-flows 3] [--max-usd 3] [--runs 5] [--dry-run] [--out <dir>]
221
+ [--flow "<sentence>" ...] [--max-flows 3] [--max-usd 3] [--runs 5]
222
+ [--dry-run] [--out <dir>]
155
223
  keepgreen heal [AutoHeal fix options]
156
224
  keepgreen autoheal <command> [...] # any AutoHeal command: learn, metrics, dashboard, ...
157
225
  keepgreen check-patch <file> # CI publish step
158
226
  keepgreen --version
159
227
  ```
160
228
 
161
- ## Self-host bundle (optional)
229
+ ## 🏠 Self-host bundle (optional)
162
230
 
163
231
  KeepGreen needs no server. If you want **test history across all CI runs** (flaky ranking, the
164
232
  commit where a test went bad) and **AutoHeal's dashboard** (fixes, blocked cheats, AI spend),
@@ -168,12 +236,15 @@ commit where a test went bad) and **AutoHeal's dashboard** (fixes, blocked cheat
168
236
  cd selfhost && sh make-env.sh your-org/your-repo && docker compose up -d --build
169
237
  ```
170
238
 
171
- ## Security
239
+ ## 🔒 Security
172
240
 
173
241
  See [SECURITY.md](SECURITY.md). In short: your key goes only to your AI provider, AI-written tests
174
242
  never run with a write token or your AI key, the publish step only accepts new test files, and
175
- 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
176
246
 
177
- ## License
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).
178
249
 
179
- MIT. Free for any use, with no paid tier.
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
@@ -70,7 +74,7 @@ inputs:
70
74
  version:
71
75
  description: keepgreen version from npm
72
76
  required: false
73
- default: "0.1.1"
77
+ default: "0.2.1"
74
78
 
75
79
  outputs:
76
80
  written:
@@ -98,6 +102,7 @@ runs:
98
102
  KG_MAX_FLOWS: ${{ inputs.max-flows }}
99
103
  KG_MAX_USD: ${{ inputs.max-usd }}
100
104
  KG_RUNS: ${{ inputs.runs }}
105
+ KG_FLOWS: ${{ inputs.flows }}
101
106
  OUT: ${{ github.workspace }}/keepgreen-out
102
107
  run: |
103
108
  [ -n "$ANTHROPIC_API_KEY" ] || unset ANTHROPIC_API_KEY
@@ -117,6 +122,10 @@ runs:
117
122
  [ -n "$KG_MAX_FLOWS" ] && args+=(--max-flows "$KG_MAX_FLOWS")
118
123
  [ -n "$KG_MAX_USD" ] && args+=(--max-usd "$KG_MAX_USD")
119
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"
120
129
  set +e
121
130
  npx -y "keepgreen@$KG_VERSION" "${args[@]}"
122
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
@@ -18,6 +18,7 @@ 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] [--dry-run] [--out <dir>]
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,12 +87,13 @@ 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;
95
99
  // Lets playwright.config tell a KeepGreen run apart, e.g.
@@ -114,7 +118,15 @@ async function cmdExplore(argv) {
114
118
  }
115
119
  if (!appUrl)
116
120
  throw new ConfigError('Tell KeepGreen where your app runs: --url http://localhost:3000, or url: in .keepgreen.yml (or start-command + start-url).');
117
- checkAppUrl(appUrl);
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).`);
118
130
  log(`KeepGreen ${VERSION}: exploring ${appUrl} (${framework}, ${provider.name} ${provider.model}, limit $${config.maxUsd})`);
119
131
  engine = await McpTools.start(projectRoot);
120
132
  runner = framework === 'cypress' ? new CypressTools(projectRoot, { log }) : framework === 'webdriverio' ? new WdioTools(projectRoot, { log }) : engine;
@@ -129,11 +141,12 @@ async function cmdExplore(argv) {
129
141
  maxFlows: config.maxFlows,
130
142
  maxUsd: config.maxUsd,
131
143
  runs: config.runs,
132
- price: priceFor(provider.model, env),
144
+ price,
133
145
  framework,
134
146
  cover,
135
147
  log,
136
148
  dryRun: values['dry-run'] === true,
149
+ ...(values.flow?.length ? { flows: values.flow } : {}),
137
150
  });
138
151
  const report = exploreReport(result, config.runs);
139
152
  process.stdout.write(`\n${report}\n`);
@@ -142,7 +155,14 @@ async function cmdExplore(argv) {
142
155
  const out = path.resolve(values.out);
143
156
  await mkdir(out, { recursive: true });
144
157
  await writeFile(path.join(out, 'report.md'), `${report}\n`);
145
- await writeFile(path.join(out, 'summary.json'), `${JSON.stringify({ version: VERSION, written, flows: result.flows, usd: result.usd }, null, 2)}\n`);
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`);
146
166
  await writeFile(path.join(out, 'new-tests.patch'), await newFilesPatch(projectRoot, written));
147
167
  log(`Wrote ${path.relative(process.cwd(), out) || '.'}/report.md, summary.json and new-tests.patch`);
148
168
  }
@@ -157,6 +177,21 @@ async function cmdExplore(argv) {
157
177
  await app?.stop().catch(() => undefined);
158
178
  }
159
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
+ }
160
195
  async function cmdInit(argv) {
161
196
  const { values } = parseArgs({ args: argv, options: { project: { type: 'string' }, force: { type: 'boolean' }, 'dry-run': { type: 'boolean' } }, strict: true });
162
197
  const root = path.resolve(values.project ?? '.');
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
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 flows = await planFlows({ ...options, budget: planBudget });
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: testFileFor(flow.flow, options.framework),
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
- return coverFile(flow, framework).replace(/autoheal-/, 'keepgreen-').replace(/test_autoheal_/, 'test_keepgreen_');
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.');
@@ -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/L,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,OAAO,EAAE,MAAM,cAAc,CAAC"}
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"}
@@ -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.1.1",
3
+ "version": "0.2.1",
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",
@@ -58,7 +58,7 @@
58
58
  "prepublishOnly": "npm test"
59
59
  },
60
60
  "dependencies": {
61
- "xsignon-autoheal": "0.12.1"
61
+ "xsignon-autoheal": "0.13.0"
62
62
  },
63
63
  "devDependencies": {
64
64
  "@types/node": "^22.10.0",
@@ -32,7 +32,7 @@ services:
32
32
 
33
33
  dashboard:
34
34
  build:
35
- context: https://github.com/xsignon-secure/AutoHeal-AI.git#v0.12.1
35
+ context: https://github.com/xsignon-secure/AutoHeal-AI.git#v0.13.0
36
36
  restart: unless-stopped
37
37
  environment:
38
38
  AUTOHEAL_DASHBOARD_SECRET: ${AUTOHEAL_DASHBOARD_SECRET:?set AUTOHEAL_DASHBOARD_SECRET in .env}
@@ -26,6 +26,10 @@
26
26
  # "Allow GitHub Actions to create and approve pull requests".
27
27
  # 5. Run it from Actions > KeepGreen explore > Run workflow, or turn on the
28
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.
29
33
  #
30
34
  # Your AI key is in the explore job, where the new tests run. Use a key with
31
35
  # a spend limit.
@@ -41,6 +45,9 @@ on:
41
45
  max-flows:
42
46
  description: New tests to try (1-10; blank = .keepgreen.yml)
43
47
  required: false
48
+ flows:
49
+ description: Optional. Flows to test, separated by ";" (blank = the AI picks)
50
+ required: false
44
51
  # schedule:
45
52
  # - cron: "0 6 * * 1" # every Monday 06:00 UTC
46
53
 
@@ -57,23 +64,53 @@ jobs:
57
64
  timeout-minutes: 60
58
65
  permissions:
59
66
  contents: read
67
+ pull-requests: read
60
68
  outputs:
61
69
  written: ${{ steps.keepgreen.outputs.written }}
62
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."
63
83
  - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
84
+ if: steps.open.outputs.count == '0' || steps.open.outputs.count == ''
64
85
  with:
65
86
  persist-credentials: false
66
87
  - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
88
+ if: steps.open.outputs.count == '0' || steps.open.outputs.count == ''
67
89
  with:
68
90
  node-version: 22
69
91
  # Your install steps (same as your test workflow):
70
- - run: npm ci
71
- - run: npx playwright install --with-deps chromium
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"
72
107
  - id: keepgreen
108
+ if: steps.open.outputs.count == '0' || steps.open.outputs.count == ''
73
109
  uses: xsignon-secure/keepgreen@v{{VERSION}}
74
110
  with:
75
111
  url: ${{ inputs.url }}
76
112
  max-flows: ${{ inputs.max-flows }}
113
+ flows: ${{ steps.flows.outputs.list }}
77
114
  anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
78
115
  openai-api-key: ${{ secrets.OPENAI_API_KEY }}
79
116
  model: ${{ vars.AUTOHEAL_MODEL }}
@@ -83,7 +120,7 @@ jobs:
83
120
  # price-in: "3" # USD per 1M tokens of your model, so max-usd is enforced
84
121
  # price-out: "15"
85
122
  - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
86
- if: steps.keepgreen.outputs.written != '0'
123
+ if: steps.keepgreen.outputs.written != '0' && steps.keepgreen.outputs.written != ''
87
124
  with:
88
125
  name: keepgreen-out
89
126
  path: keepgreen-out/
@@ -100,6 +137,10 @@ jobs:
100
137
  pull-requests: write
101
138
  steps:
102
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 }}
103
144
  - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
104
145
  with:
105
146
  name: keepgreen-out
@@ -114,9 +155,9 @@ jobs:
114
155
  run: npx -y keepgreen@{{VERSION}} check-patch "$OUT/new-tests.patch"
115
156
  - name: Open the pull request
116
157
  env:
117
- GH_TOKEN: ${{ github.token }}
158
+ GH_TOKEN: ${{ secrets.KEEPGREEN_PR_TOKEN || github.token }}
118
159
  OUT: ${{ runner.temp }}/keepgreen-out
119
- BRANCH: keepgreen/explore-${{ github.run_id }}
160
+ BRANCH: keepgreen/explore-${{ github.run_id }}-${{ github.run_attempt }}
120
161
  run: |
121
162
  git -c core.hooksPath=/dev/null apply --check "$OUT/new-tests.patch"
122
163
  git -c core.hooksPath=/dev/null apply "$OUT/new-tests.patch"