@asrunjs/asrun 0.8.0 → 0.9.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/.claude/commands/explore-case.md +6 -2
- package/.claude/commands/gen-spec.md +4 -1
- package/.claude/commands/heal-spec.md +18 -7
- package/.claude/skills/exploring-cases/SKILL.md +19 -8
- package/.claude/skills/exploring-cases/references/open-questions.md +2 -2
- package/.claude/skills/generating-specs/SKILL.md +85 -30
- package/AGENTS.md +17 -9
- package/README.md +4 -3
- package/dist/ui/server/actions.js +9 -4
- package/dist/ui/shared/ai-commands.d.ts +6 -3
- package/dist/ui/shared/ai-commands.js +11 -7
- package/dist/ui/shared/types.d.ts +1 -1
- package/docs/ai-workflow.md +38 -11
- package/docs/theme-guide.html +93 -5
- package/docs/troubleshooting.md +7 -3
- package/docs/web-ui.md +28 -6
- package/package.json +1 -1
- package/templates/.claude/commands/explore-case.md +7 -2
- package/templates/.claude/commands/gen-spec.md +4 -1
- package/templates/.claude/commands/heal-spec.md +22 -12
- package/ui/dist/assets/{dist-ChBHX4rh.js → dist-B7HeglDd.js} +1 -1
- package/ui/dist/assets/{dist-CJiwxr1r.js → dist-B9_GXR2G.js} +1 -1
- package/ui/dist/assets/{dist-N-o4QIaZ.js → dist-Bb36rNUw.js} +1 -1
- package/ui/dist/assets/{dist-BpkTvixI.js → dist-DevASegc.js} +1 -1
- package/ui/dist/assets/{dist-DoChb6QQ.js → dist-DfBpjgZT.js} +1 -1
- package/ui/dist/assets/{dist-BgPbx2GZ.js → dist-Dq4Vnw5N.js} +1 -1
- package/ui/dist/assets/{dist-CavmZIv7.js → dist-Dqc_tfzC.js} +1 -1
- package/ui/dist/assets/{dist-Do_MhHKF.js → dist-G9KNeh6u.js} +1 -1
- package/ui/dist/assets/{dist-D6jmnDr-.js → dist-GvRUDL-2.js} +1 -1
- package/ui/dist/assets/{dist-BC_P1Gnf.js → dist-WvvCZeeu.js} +1 -1
- package/ui/dist/assets/index-BJ5D2mFK.js +346 -0
- package/ui/dist/assets/index-BXY-eKBn.css +2 -0
- package/ui/dist/help/case-explore.png +0 -0
- package/ui/dist/index.html +2 -2
- package/ui/dist/assets/index-Cy2l91qV.css +0 -2
- package/ui/dist/assets/index-DGQ5logJ.js +0 -338
|
@@ -7,12 +7,16 @@ In this repository the workspace is `examples/demo` (set `ASRUN_ROOT=examples/de
|
|
|
7
7
|
Rules combine in this order, and a later one wins where they conflict: the framework baseline `AGENTS.md`, the
|
|
8
8
|
framework skill, `.claude/skills/exploring-cases.md` if it exists, then the workspace `AGENTS.md` §2 in `examples/demo`
|
|
9
9
|
(Project rules). F1–F6 always win.
|
|
10
|
-
Arguments: `<case-id> <env> [--attended]`. The case id is the path below cases/ without `.md` (it may include a group
|
|
10
|
+
Arguments: `<case-id> <env> [--attended] [--profiles a,b]`. The case id is the path below cases/ without `.md` (it may include a group
|
|
11
11
|
folder, e.g. documents/landing-page) and is required. `<env>` is `staging` or `production`; it is required and there is no
|
|
12
12
|
default (without one, stop and say so). With `--attended` I am at the machine and the browser window is visible: when a step
|
|
13
13
|
writes data or needs a choice, hand it to me as the skill describes, wait for me, and record what I did as a general
|
|
14
14
|
recipe under the step it belongs to (`- Recipe:` lines). Without `--attended`, never wait for me.
|
|
15
|
+
`--profiles a,b` explores only those profiles (comma-separated ids from profiles.yaml); without it, at least one
|
|
16
|
+
logged-in profile per domain. A profile the list leaves out is not opened and nothing is written about it: runs add up,
|
|
17
|
+
so a later run covers the rest.
|
|
15
18
|
Follow `assertion-targets.md` (list the candidates, never pick when in doubt, ask for the exact image/text/place/UI)
|
|
16
19
|
and `readiness.md` (wait for the key requests and the content before you read anything) of the skill.
|
|
17
20
|
This command edits cases/<case-id>.md only (plus screenshots under `.explore/targets/`). Do not ask me questions in the chat: write open questions into the case
|
|
18
|
-
file as the skill describes, and end with the `RESULT:` line.
|
|
21
|
+
file as the skill describes, and end with the `RESULT:` line. If you are not allowed to write files at all (a plan-mode
|
|
22
|
+
run, a read-only sandbox), say what blocked you and end with `RESULT: needs-input`.
|
|
@@ -10,7 +10,10 @@ framework skill, `.claude/skills/generating-specs.md` if it exists, then the wor
|
|
|
10
10
|
Arguments: `<case-id> [<env>] [--force]`. The case file is cases/<case-id>.md (the id may include one group folder, e.g.
|
|
11
11
|
documents/landing-page). `<env>` is the environment to explore in (`staging` or `production`); there is no default. If the spec already exists, it is
|
|
12
12
|
left alone unless `--force` is given; with `--force` it is regenerated and overwritten.
|
|
13
|
+
There is no profile option: the spec is generated for every profile the case holds information for (its `## Values`
|
|
14
|
+
keys, its target cards and its observations), not for a chosen subset and not only for the profiles that are logged in.
|
|
13
15
|
Follow the skill's procedure exactly, including `assertion-targets.md` and `readiness.md`; run `pnpm spec:lint <case-id>`. Only generate the spec: do not run `pnpm asrun` (running specs is a separate
|
|
14
16
|
process), and do not create baselines.
|
|
15
17
|
Do not ask me questions: resolve ambiguity as the skill describes (explore the page, use observed values marked for QA,
|
|
16
|
-
write the remaining questions into the case file), and end with the `RESULT:` line.
|
|
18
|
+
write the remaining questions into the case file), and end with the `RESULT:` line. If you are not allowed to write
|
|
19
|
+
files at all (a plan-mode run, a read-only sandbox), say what blocked you and end with `RESULT: needs-input`.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
|
-
description:
|
|
2
|
+
description: Repair a failing spec, or refine a case and its spec on request, without hiding real product regressions
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
Load the `generating-specs` skill, section "Healing a
|
|
5
|
+
Load the `generating-specs` skill, section "Healing and refining a spec", and follow it exactly.
|
|
6
6
|
In this repository the workspace is `examples/demo` (set `ASRUN_ROOT=examples/demo`); the framework is `.`.
|
|
7
7
|
Rules combine in this order, and a later one wins where they conflict: the framework baseline `AGENTS.md`, the
|
|
8
8
|
framework skill, `.claude/skills/generating-specs.md` if it exists, then the workspace `AGENTS.md` §2 in `examples/demo`
|
|
@@ -11,14 +11,25 @@ Arguments: $ARGUMENTS
|
|
|
11
11
|
Format: `<case-id> <env> [--profiles a,b] [--report <run-id>] [--hints <file>]`, with optional free text after them.
|
|
12
12
|
- `<case-id>` and `<env>` (`staging` or `production`) are required. There is no default environment. Without one, stop
|
|
13
13
|
and say so.
|
|
14
|
-
- `--profiles`: the profiles to
|
|
14
|
+
- `--profiles`: the profiles to run when evidence is needed. Without it, every profile that is logged in in `<env>`.
|
|
15
15
|
- `--report`: the report (folder name under `reports/`) to read first. Without it, the newest report of this case.
|
|
16
|
-
- `--hints <file>`: a file with what the user
|
|
17
|
-
after the arguments is the same kind of
|
|
18
|
-
|
|
16
|
+
- `--hints <file>`: a file with what the user wants repaired or improved, with any evidence. Read it first. Any free
|
|
17
|
+
text after the arguments is the same kind of request. Both are optional.
|
|
18
|
+
A passing run is not a reason to refuse a request: healing also refines a case and its spec. Never lower the bar for a
|
|
19
|
+
product finding to make a test pass.
|
|
20
|
+
|
|
21
|
+
Do not ask me questions in the chat: this may run unattended. Resolve what the report, the case and the page can
|
|
22
|
+
resolve, and write what still needs a person into the case as a `[blocking]` question. End with the `RESULT:` line:
|
|
23
|
+
`ready` when the healing or the refinement is finished, `needs-input` when something is still open. If you could not
|
|
24
|
+
write files at all (a plan-mode run, a read-only sandbox, a refused permission), say in one sentence what blocked you
|
|
25
|
+
and end with `RESULT: needs-input`: never answer with a plan and a question instead.
|
|
26
|
+
|
|
27
|
+
Before you decide "product or test", audit the assertion itself (target card, baseline content, readiness): see step 5
|
|
19
28
|
of the skill's healing section, `assertion-targets.md` and `readiness.md`. Run `pnpm spec:lint <case-id>`.
|
|
20
29
|
Read the existing report first (`pnpm heal:evidence --case <case-id> --env <env>`), and run the case again only when the
|
|
21
|
-
skill says it is needed. Always run with `--logged-in`.
|
|
30
|
+
skill says it is needed. Always run with `--logged-in`. If the change leaves an open question or an unconfirmed marker
|
|
31
|
+
in the case, stop there, tell me to review the case and run `/explore-case`, and end with `RESULT: needs-input`.
|
|
32
|
+
Otherwise tell me whether it is a test problem or a product finding.
|
|
22
33
|
|
|
23
34
|
Run `pnpm asrun ...`, `pnpm heal:evidence ...`, `pnpm spec:lint ...`, `pnpm baselines:review ...` and `pnpm status ...` as plain commands, optionally piped to `tail` or
|
|
24
35
|
`head`, and do not chain other commands with them (`;` or `&&`). Only these exact forms run outside Claude Code's
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: exploring-cases
|
|
3
|
-
description: Explores the real pages for one case document (cases/<id>.md) before its spec is generated. Checks the case against profiles.yaml and the pages, fixes wording mistakes, records what the pages show, turns unknowns into answerable TODO blocks, and, in an attended run, lets the person do the steps that write data or need a choice while it waits and records a general recipe under that step's `- Recipe:` lines. Ends with RESULT ready or needs-input. Use when asked to explore, review, check, clean up or narrow down a case, or for /explore-case. Its open-question rules are shared with generating-specs.
|
|
3
|
+
description: Explores the real pages for one case document (cases/<id>.md) before its spec is generated, for every logged-in profile or only the ones named with --profiles. Checks the case against profiles.yaml and the pages, fixes wording mistakes, records what the pages show, turns unknowns into answerable TODO blocks, and, in an attended run, lets the person do the steps that write data or need a choice while it waits and records a general recipe under that step's `- Recipe:` lines. Ends with RESULT ready or needs-input. Use when asked to explore, review, check, clean up or narrow down a case, or for /explore-case. Its open-question rules are shared with generating-specs.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Exploring a case document
|
|
@@ -34,8 +34,10 @@ under `.auth/`.
|
|
|
34
34
|
choice (see `references/user-handoff.md`).
|
|
35
35
|
|
|
36
36
|
It never stops to ask in the chat. A question that cannot be answered from the page goes into the case file, where
|
|
37
|
-
the user answers it by editing the file, and the report says `RESULT: needs-input`.
|
|
38
|
-
|
|
37
|
+
the user answers it by editing the file, and the report says `RESULT: needs-input`. This holds whatever mode or agent
|
|
38
|
+
the run is in: if you are not allowed to write files (plan mode, a read-only sandbox, a refused permission), say what
|
|
39
|
+
blocked you in one sentence and end with `RESULT: needs-input` instead of answering with a plan and a question. The
|
|
40
|
+
one exception is a handoff in an attended run, where waiting for the person is the point.
|
|
39
41
|
|
|
40
42
|
## Inputs
|
|
41
43
|
- A case id (path below `cases/` without `.md`, e.g. `documents/landing-page`). It is required: an attended exploration of
|
|
@@ -44,13 +46,18 @@ an attended run, where waiting for the person is the point.
|
|
|
44
46
|
before exploring and report `RESULT: needs-input` ("pass the environment").
|
|
45
47
|
- Optionally `--attended`: a person is at the machine and the browser window is visible, so handoffs may happen.
|
|
46
48
|
Without it nothing waits, and a step that needs a person becomes a `[blocking]` TODO.
|
|
49
|
+
- Optionally `--profiles a,b`: explore only these profiles (ids from `profiles.yaml`, comma-separated). Without it, at
|
|
50
|
+
least one logged-in profile per domain. The selection is never widened: a profile it leaves out is not opened and
|
|
51
|
+
nothing about it is written into the case. Runs add up: a later run with other profiles adds their observations and
|
|
52
|
+
`## Values` entries next to the ones recorded before.
|
|
47
53
|
|
|
48
54
|
## Procedure
|
|
49
55
|
1. **Read** the case, `profiles.yaml` and `cases/_template.md`. Apply uncommitted user edits as they are: they are the
|
|
50
56
|
newest wording. Use targeted edits, never rewrite a whole file.
|
|
51
57
|
2. **Static review.** Find:
|
|
52
58
|
- missing values for a profile: compare the entries of `## Values` (keyed by `default` and profile ids) with the
|
|
53
|
-
ids in `profiles.yaml
|
|
59
|
+
ids in `profiles.yaml` (with `--profiles`, only those ids: the rest belong to a run of their own). A missing
|
|
60
|
+
entry is a gap, not something to invent: leave it to the observations and
|
|
54
61
|
`/gen-spec`. The case's `## Values` is the only place for expected values; never copy them into `profiles.yaml`;
|
|
55
62
|
- ambiguous steps and checks without an expected result;
|
|
56
63
|
- steps that write data or need a choice: mark them `[writes]` / `[input]`. The front matter must list the
|
|
@@ -70,9 +77,11 @@ an attended run, where waiting for the person is the point.
|
|
|
70
77
|
`RESULT: needs-input`.
|
|
71
78
|
Run `pnpm status --env <env>`. If it cannot run (a sandbox error such as
|
|
72
79
|
`listen EPERM` or a Chromium start failure), do not give up: open the profile's page through the MCP, and a page
|
|
73
|
-
that lands on the login page means the profile is not logged in. Explore
|
|
74
|
-
domain with the `playwright-test` MCP
|
|
75
|
-
`
|
|
80
|
+
that lands on the login page means the profile is not logged in. Explore each profile `--profiles` names that is
|
|
81
|
+
logged in, and, without `--profiles`, at least one logged-in profile per domain, with the `playwright-test` MCP
|
|
82
|
+
(`generator_setup_page` with `project=<profile-id>` and
|
|
83
|
+
`seedFile=tests/seed.spec.ts`). Never explore a profile the selection leaves out, and never add a profile to fill
|
|
84
|
+
a gap. Profiles that are selected but not logged in are skipped and named in the report; a human runs
|
|
76
85
|
`pnpm signin <profile-id>`.
|
|
77
86
|
- Do the read-only steps yourself: open, look, read, hover, switch tabs, open and close dialogs and menus.
|
|
78
87
|
- **A step that writes or needs a choice is done by the person**, per `references/user-handoff.md`: announce it,
|
|
@@ -129,7 +138,8 @@ an attended run, where waiting for the person is the point.
|
|
|
129
138
|
8. **Check**: run `pnpm case:check` (it fails on an incomplete target card and warns on a check that has none) and fix every FAIL. If it fails with a sandbox error (`listen EPERM`), run
|
|
130
139
|
`node --import tsx <framework>/scripts/check-cases.ts` instead; it checks the same thing.
|
|
131
140
|
9. **Report** in the user's language: what was changed (wording fixes, observations added, TODOs closed or narrowed),
|
|
132
|
-
what was explored (profile ids), which
|
|
141
|
+
what was explored (profile ids), which profiles `--profiles` left out (and that a run with them covers the rest),
|
|
142
|
+
which steps the person did and what was recorded for them, what was skipped and
|
|
133
143
|
why, the target cards written (and which ones are still questions), the steps whose first read was too early,
|
|
134
144
|
the steps that could not be observed (and why), the questions that remain with the sentence that deleting each block would confirm, and findings that look
|
|
135
145
|
like product bugs. End with the `RESULT:` line.
|
|
@@ -141,6 +151,7 @@ an attended run, where waiting for the person is the point.
|
|
|
141
151
|
- Never invent expected values, profile names, counts or UI texts. Observations are marked as such. Values that a
|
|
142
152
|
check asserts are written into the case's `## Values` under the profile id (or `default` when they hold for every
|
|
143
153
|
profile), and never into `profiles.yaml`.
|
|
154
|
+
- Never explore a profile that `--profiles` leaves out, and never widen the selection to cover a gap in the case.
|
|
144
155
|
- Never pick a target when in doubt, and never record a fact that was read before the content finished loading.
|
|
145
156
|
- Never read or print anything under `.auth/`. Never automate login or 2FA.
|
|
146
157
|
- Prose follows the artifact language of the workspace `AGENTS.md` §2 (English by default); structural tokens stay English.
|
|
@@ -110,7 +110,7 @@ RESULT: needs-input
|
|
|
110
110
|
|
|
111
111
|
- `ready`: no `[blocking]` question remains. Non-blocking ones may remain; list them so QA can confirm them.
|
|
112
112
|
- `needs-input`: at least one `[blocking]` question remains in the case file (list each with its parent sentence),
|
|
113
|
-
or the work could not be done (no environment, nobody logged in
|
|
114
|
-
then re-run.
|
|
113
|
+
or the work could not be done (no environment, nobody logged in, or no permission to write files: a plan-mode run,
|
|
114
|
+
a read-only sandbox). Say what the user should edit in the case file, then re-run.
|
|
115
115
|
|
|
116
116
|
Do not write anything after the `RESULT:` line.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: generating-specs
|
|
3
|
-
description: Turns a human-written test case (cases/<id>.md, the id may include a group folder such as documents/landing-page) into a Playwright spec (tests/<id>.spec.ts) for the multi-profile test suite, explores the real pages to learn the locators and values, and completes the case's own "## Values" block. It only generates: it never runs the tests. Use when asked to generate, update, fix or
|
|
3
|
+
description: Turns a human-written test case (cases/<id>.md, the id may include a group folder such as documents/landing-page) into a Playwright spec (tests/<id>.spec.ts) for the multi-profile test suite, explores the real pages to learn the locators and values, and completes the case's own "## Values" block. It only generates: it never runs the tests. Healing (repairing a failing spec, or refining a case and its spec on request) is the exception. Use when asked to generate, update, fix, heal or refine a spec, or for /gen-spec or /heal-spec.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Generating specs from case documents
|
|
@@ -12,16 +12,26 @@ defines how open questions are written into the case file, resolved and reported
|
|
|
12
12
|
`../exploring-cases/references/readiness.md` (wait for the content, verify downloads in five parts). All three are binding here.
|
|
13
13
|
|
|
14
14
|
This skill never stops to ask the user in the chat, because it may run without anybody present (a one-shot
|
|
15
|
-
`claude -p` / `opencode run`).
|
|
16
|
-
|
|
15
|
+
`claude -p` / `opencode run`). This holds whatever mode or agent the run is in: plan mode changes what you may write,
|
|
16
|
+
never how you end. If you are not allowed to write files (plan mode, a read-only sandbox, a refused permission), say
|
|
17
|
+
what blocked you in one sentence and end with `RESULT: needs-input` instead of answering with a plan and a question.
|
|
18
|
+
Questions go into the case file; the final line is `RESULT: ready` or `RESULT: needs-input`.
|
|
17
19
|
|
|
18
20
|
This skill trusts the case. What the pages show, what a person has to enter, and what the open questions are is
|
|
19
21
|
settled by `/explore-case` and recorded in the case (`(observed, ...)` marks, the step recipes). Generating
|
|
20
22
|
only finds locators and writes code: it replays the case and does not judge the case again.
|
|
21
23
|
|
|
24
|
+
The profile scope is the case's, not a selection. It is every profile id that appears in the case — the keys of
|
|
25
|
+
`## Values`, a target card's `Reference <profile-id>:` line, a step observation — plus the `default` entry. There is no
|
|
26
|
+
`--profiles` here: never narrow the scope to the profiles that are logged in, and never ask for a subset. The spec runs
|
|
27
|
+
once per profile in the environment, so it must cover every profile the case says something about. A profile the case
|
|
28
|
+
says nothing about runs on `default` alone; name those in the report. Runs of `/explore-case` add up, so a case explored
|
|
29
|
+
with A and B first and C later generates a spec for all three.
|
|
30
|
+
|
|
22
31
|
Generating a spec and running it are separate processes. This skill only writes files: it does not run
|
|
23
32
|
`pnpm asrun`, does not create screenshot baselines and does not judge whether the spec passes. The user runs the
|
|
24
|
-
spec afterwards (see the report). Healing
|
|
33
|
+
spec afterwards (see the report). Healing (below) is the exception: it reads the last report first, may edit the case
|
|
34
|
+
and the spec, and runs only the profiles that are logged in, and only when the report is not enough.
|
|
25
35
|
|
|
26
36
|
## Before you start
|
|
27
37
|
Read the workspace `AGENTS.md`: its §2 holds the project rules, and it points at the framework baseline. If
|
|
@@ -33,6 +43,8 @@ continue with the procedure below.
|
|
|
33
43
|
- The case id and the environment to explore in (`staging` or `production`). There is no default. If the
|
|
34
44
|
environment is missing, stop before exploring and report `RESULT: needs-input` ("pass the environment").
|
|
35
45
|
- Optionally `--force`: regenerate the spec from scratch and overwrite the existing one. See "An existing spec".
|
|
46
|
+
- No profile selection: the profile scope is the case's (see above). A case id and an environment are all this command
|
|
47
|
+
takes besides `--force`.
|
|
36
48
|
|
|
37
49
|
A case id is its path below `cases/` without `.md`: `hub-landing`, or `documents/landing-page` when the case is in a
|
|
38
50
|
folder (one level only). The spec is at the same path below `tests/` (`tests/documents/landing-page.spec.ts`); both import
|
|
@@ -94,9 +106,11 @@ Decide this first, before exploring anything. The spec path is `tests/<id>.spec.
|
|
|
94
106
|
- Do not invent expected values. If the case's `## Values` and the spec disagree, the case wins: fix the spec and
|
|
95
107
|
mention the change in the report.
|
|
96
108
|
3. **Check sessions** if `login: required`: run `pnpm status --env <env>`. If a profile needs login, tell the
|
|
97
|
-
user to run `pnpm signin <profile-id>` and continue with the profiles that are ready.
|
|
98
|
-
|
|
99
|
-
|
|
109
|
+
user to run `pnpm signin <profile-id>` and continue with the profiles that are ready. A profile the case holds
|
|
110
|
+
information for is never dropped because it is not logged in: write its part from the case and mark it
|
|
111
|
+
`not verified on the page` in the report. If `pnpm status` cannot run (a sandbox error such as `listen EPERM` or a
|
|
112
|
+
Chromium start failure), judge by the page instead: a page that lands on the login page means the profile is not
|
|
113
|
+
logged in.
|
|
100
114
|
4. **Replay the case on the real page** with the `playwright-test` MCP. If its tools are not registered in this
|
|
101
115
|
session (no `browser_*` / `generator_*` tool) or it reports that it failed to start, do not fall back to ad-hoc
|
|
102
116
|
Playwright scripts: stop, tell the user which MCP server is missing and to run `pnpm asrun doctor`, write no spec,
|
|
@@ -109,10 +123,11 @@ Decide this first, before exploring anything. The spec path is `tests/<id>.spec.
|
|
|
109
123
|
of the spec from the `- Recipe:` lines under the step (positions, `[asrun]` names, control labels and roles that
|
|
110
124
|
`/explore-case` recorded). Pages that only exist after such a step cannot be seen from here: write their locators
|
|
111
125
|
from what the recipe and the exploration notes say, mark them in the report as "not verified on the page", and
|
|
112
|
-
leave the first run of the spec (or `/heal-spec`) to confirm them. Do this for at least one profile
|
|
113
|
-
per domain (example.com and exampleshop.com differ in markup).
|
|
114
|
-
named in the report
|
|
115
|
-
|
|
126
|
+
leave the first run of the spec (or `/heal-spec`) to confirm them. Do this for at least one logged-in profile
|
|
127
|
+
per domain (example.com and exampleshop.com differ in markup). A profile the case holds information for that is
|
|
128
|
+
not logged in is skipped and named in the report; its part is written from the case and marked `not verified` in
|
|
129
|
+
the assertion table. Use this exploration to answer the open points of step 2, and read each profile's value from
|
|
130
|
+
the case's `## Values`: open that profile's page only when a value or a behavior still has to be resolved for it.
|
|
116
131
|
Keep every browser call short (one action, about 60 s at most, a snapshot between steps, `{timeout: 5000}` when
|
|
117
132
|
something may not appear, no third retry): see "Keep every browser call short" in `../exploring-cases/SKILL.md`.
|
|
118
133
|
**Ready before you read, here too** (`readiness.md`): `browser_network_clear`, act, wait for the key requests
|
|
@@ -126,8 +141,11 @@ Decide this first, before exploring anything. The spec path is `tests/<id>.spec.
|
|
|
126
141
|
`(observed, 🔍 to be confirmed by QA)`, remove the TODO blocks they answer (rewrite the sentence above the block),
|
|
127
142
|
and narrow the ones that remain. Keep the shape of `open-questions.md` for every block. Edit the case
|
|
128
143
|
with targeted edits; never touch its `## Source` table.
|
|
129
|
-
5. **Complete the case's `## Values`**: for every profile the
|
|
130
|
-
asserts (the same keys as `default`, only what differs)
|
|
144
|
+
5. **Complete the case's `## Values`**: for every profile the case holds information for, add the entry with the
|
|
145
|
+
literals the spec asserts (the same keys as `default`, only what differs); put a literal that holds for every profile
|
|
146
|
+
in `default`. Do not add an entry for a profile the case says nothing about, and never invent a value to fill one: a
|
|
147
|
+
profile without an entry runs on `default` alone, and a literal the case does not hold is a question in the case.
|
|
148
|
+
Do not move values into `profiles.yaml`; it holds connection
|
|
131
149
|
settings only. Mention every value you added or corrected in the report.
|
|
132
150
|
6. **Write `tests/<id>.spec.ts`** (inside the group folder if the id has one, creating it if needed) following the conventions. One `test()` per outcome, and every
|
|
133
151
|
case step wrapped in `test.step()` with the case's step text as the title, and the top-level
|
|
@@ -150,7 +168,8 @@ Decide this first, before exploring anything. The spec path is `tests/<id>.spec.
|
|
|
150
168
|
Do NOT run `pnpm asrun`, do not use
|
|
151
169
|
`--update-snapshots` and do not create baselines: the first run of the spec does that, and a person reviews them.
|
|
152
170
|
8. **Report** in the user's language: spec path, **an assertion table** (step, what is asserted, target card, ready signal, and
|
|
153
|
-
`observed on the page` or `not verified`; no row may be missing), profiles explored, profiles skipped (and why),
|
|
171
|
+
`observed on the page` or `not verified`; no row may be missing), profiles explored, profiles skipped (and why),
|
|
172
|
+
the profiles of `profiles.yaml` the case holds no information for (they run on `default` alone), whether the case file was
|
|
154
173
|
translated, what was added to the case file as observed, checks generated from observations (QA must confirm
|
|
155
174
|
them), visual checks that need a baseline on the first run, and the remaining TODO blocks (`[blocking]` ones with
|
|
156
175
|
the sentence that deleting the block would confirm). State that the spec was not run and give the command to run it:
|
|
@@ -166,34 +185,51 @@ spec does, when a person runs it in an environment that `writes` lists. Elsewher
|
|
|
166
185
|
notice. Never send email in production; in other environments only if `profile.email` is true, otherwise skip that step and say so
|
|
167
186
|
in the report.
|
|
168
187
|
|
|
169
|
-
## Healing a
|
|
188
|
+
## Healing and refining a spec
|
|
170
189
|
Inputs: the case id and the environment (both required, there is no default: without an environment stop and say so),
|
|
171
190
|
optionally `--profiles a,b`, `--report <run-id>` and `--hints <file>` (or free text after the arguments). Healing is
|
|
172
191
|
the one case where this skill runs specs, and only in the environment given.
|
|
173
192
|
|
|
193
|
+
Healing has two jobs, and the same command does both: **repair** a spec that fails, and **refine** a case and its spec
|
|
194
|
+
when the user asks for a change. A passing run is never a reason to refuse a request, and "nothing failed" is never a
|
|
195
|
+
reason to do nothing when the user asked for something.
|
|
196
|
+
|
|
174
197
|
Heal from evidence, not from a habit of rerunning. A report that already exists says what failed.
|
|
175
198
|
|
|
176
|
-
1. **Read the user's
|
|
177
|
-
evidence the report lacks.
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
199
|
+
1. **Read the user's request first** (the `--hints` file, or the free text). It says what to repair or improve and may
|
|
200
|
+
hold evidence the report lacks. Decide which kind of work it is:
|
|
201
|
+
- a failure to repair (the last run failed, or the user names one);
|
|
202
|
+
- an improvement, even when the last run passed: a check that is too loose, a step, expectation, value or target
|
|
203
|
+
that no longer matches the page, wording a person cannot follow;
|
|
204
|
+
- both.
|
|
205
|
+
Quote the request you used, or say that it did not hold up, in the report. It guides the work and nothing else: it
|
|
206
|
+
never lowers the bar for a product finding and never allows an expectation to be changed just to make a test pass.
|
|
207
|
+
- **No report and no request:** do not invent work. Say that nothing asks for a change, list what
|
|
208
|
+
`pnpm spec:lint <case-id>` and the last report call weak (as suggestions, not edits), and end with `RESULT: ready`.
|
|
209
|
+
- **A passing report and no request:** the same. Do not start an improvement of your own.
|
|
210
|
+
2. **Read the existing report** if there is one: run `pnpm heal:evidence --case <case-id> --env <env>` (add `--profile a,b` when `--profiles`
|
|
181
211
|
was given). It reads `reports/*/summary.json` and prints, per profile, the status, the failed step, the error, the call
|
|
182
212
|
log, the screenshots and videos, and ends with `EVIDENCE: fresh | stale | no-failure | none`. With `--report <run-id>`,
|
|
183
213
|
read `reports/<run-id>/summary.json` instead. Look at the screenshot when the error alone does not explain it. A profile
|
|
184
|
-
that failed only because it was not logged in is no evidence about the spec.
|
|
214
|
+
that failed only because it was not logged in is no evidence about the spec. `EVIDENCE: none` or `no-failure` with an
|
|
215
|
+
improvement request is a starting point, not a stop.
|
|
185
216
|
3. **Decide whether to rerun the case**. Do not rerun when the report is `fresh`, names the failing step and the error,
|
|
186
217
|
and that is enough to tell whether the product changed or the test is wrong. Rerun when:
|
|
187
218
|
- there is no report (`none`), or it is `stale` (the spec, the case or `profiles.yaml` changed after it);
|
|
188
219
|
- the report does not explain the failure (a bare timeout with no locator, a failure before any step, a truncated log);
|
|
189
|
-
- a clue
|
|
220
|
+
- a clue or a requested improvement has to be checked against the real page, and no recent report shows it;
|
|
190
221
|
- a profile that must be healed has no result in the report (for example it was not logged in then).
|
|
191
222
|
Rerun with one plain command, as few profiles as possible, and say why in the report:
|
|
192
223
|
`pnpm asrun --env <env> --logged-in --profile <ids> --grep <case-id>` (optionally piped to `tail`; do not chain it
|
|
193
224
|
with other commands, or it runs inside Claude's sandbox and fails with `listen EPERM`). Always add `--logged-in`: it
|
|
194
225
|
leaves out the profiles that are not logged in instead of failing them. A profile that is not logged in is never healed:
|
|
195
226
|
name it in the report with `pnpm signin <profile-id>`.
|
|
196
|
-
4. **
|
|
227
|
+
4. **Look at the pages when the change depends on them.** Reading a page is not a run and is always allowed, also for an
|
|
228
|
+
improvement request with no failure behind it. Use the `playwright-test` MCP exactly as `/gen-spec` step 4 describes
|
|
229
|
+
(`generator_setup_page` with `project=<profile-id>`, one action per call, ready before you read). Do the read-only
|
|
230
|
+
steps only: **never perform a step that writes or needs a choice**, in any environment. What you see goes into the
|
|
231
|
+
case as `(observed, 🔍 to be confirmed by QA)`, so the person can confirm it in the review gate below.
|
|
232
|
+
5. **Audit the assertion before you blame anyone.** Read the `assertion-targets.md` and `readiness.md` sections on healing.
|
|
197
233
|
- Is the locator still what the target card says (`What`, `Identified by`)? Open the failure screenshot and the
|
|
198
234
|
baseline (`pnpm baselines:review <case-id>`) and look at each: a baseline that shows something other than the card
|
|
199
235
|
(a content image instead of a logo) is a wrong test, and passing runs on it prove nothing. Delete it and report it; a
|
|
@@ -204,16 +240,35 @@ Heal from evidence, not from a habit of rerunning. A report that already exists
|
|
|
204
240
|
- A download that fails says which stage failed (start, finish, exists, valid): fix the stage, do not loosen the check.
|
|
205
241
|
- Doubt about which element is meant: write the question into the case (a `[blocking]` TODO naming the exact image,
|
|
206
242
|
text, place or UI) instead of choosing; do not rewrite the card quietly.
|
|
207
|
-
|
|
243
|
+
6. **Decide what the change belongs to, and change the case first.**
|
|
208
244
|
- Locator/timing problem: fix the spec.
|
|
209
245
|
- A real product difference (wrong logo, wrong name): do NOT change the expectation to make it
|
|
210
246
|
pass. Report it as a finding with the trace/screenshot path.
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
247
|
+
- A request the case can settle: the case is the source of truth, so write the change into `cases/<case-id>.md`
|
|
248
|
+
first, then into the spec. That covers a step, an expectation, a value in `## Values`, a target card, a ready
|
|
249
|
+
signal and a recipe. The spec follows the case (its step titles copy the case's step text). When the case changed
|
|
250
|
+
more than a sentence (a new or removed step, different expected values, another target), regenerate the spec from
|
|
251
|
+
the case as "## Procedure" steps 5–6 describes instead of patching it; otherwise edit it in place. Say in the
|
|
252
|
+
report which of the two you did.
|
|
253
|
+
7. **Stop at the review gate.** After editing the case, read it back. If **this run** left a `🚫 TODO [blocking]` or
|
|
254
|
+
`❓ TODO [non-blocking]` block, or a `🔍 to be confirmed by QA` or `👁️ not observed` marker, do not edit or
|
|
255
|
+
regenerate the spec any further: a case that still asks something is not a source for a spec. Report exactly what
|
|
256
|
+
to review, that answering or deleting those blocks comes first, and that the next command is
|
|
257
|
+
`/explore-case <case-id> <env>` (with `--attended` when a step writes data). End with `RESULT: needs-input`. Blocks
|
|
258
|
+
and markers that were already in the case before this run and that it did not touch do not stop it.
|
|
259
|
+
8. **After editing the spec, run it once to confirm** (same command as in step 3, for the profiles you healed). That rerun
|
|
260
|
+
is the only one that is always allowed. Run `pnpm typecheck`, `pnpm spec:lint <case-id>` and `pnpm case:check`, and
|
|
261
|
+
fix every failure of the checks you touched. An improvement may make the run fail on purpose: a tightened check that
|
|
262
|
+
now fails is evidence about the product, so report it as a finding instead of loosening it again.
|
|
263
|
+
9. **Report** in the user's language: which report was read (or that there was none) and whether it was fresh or stale,
|
|
264
|
+
whether the case was run again and why (or why not), what the request asked for and what came of it, what was
|
|
265
|
+
changed in the case and in the spec (and whether the spec was regenerated), what is a product finding (with paths),
|
|
266
|
+
which assertions were wrong or raced the page, which baselines are wrong and were deleted, what the user's request
|
|
267
|
+
contributed, which profiles were left out because they are not logged in, and the result of the
|
|
268
|
+
confirming run. The last line is `RESULT: ready` (nothing left for a person, the spec changed and its checks pass)
|
|
269
|
+
or `RESULT: needs-input` (the case waits for a review, as in step 7, or a person has to decide something). A run
|
|
270
|
+
that could not write files at all (plan mode, a read-only sandbox, a refused permission) is `needs-input` too:
|
|
271
|
+
never end with a plan and a question instead.
|
|
217
272
|
|
|
218
273
|
A case that writes data in `production` needs a person's confirmation at run time, so the rerun is refused there:
|
|
219
274
|
use the report, or heal in staging, and never add `--allow-writes`.
|
package/AGENTS.md
CHANGED
|
@@ -143,14 +143,16 @@ The framework folder is read-only in a project: never edit it. Its own layout an
|
|
|
143
143
|
Three steps, each learns one thing: the intent, the facts and inputs, the implementation.
|
|
144
144
|
1. `making-cases` (or `/make-case <notes>`) turns raw notes into case documents. It writes `cases/*.md` only and
|
|
145
145
|
never opens a browser. Check them with `pnpm case:check`.
|
|
146
|
-
2. `exploring-cases` (or `/explore-case <case-id> <env> [--attended]`) explores the real pages for one
|
|
147
|
-
edits that case file only: wording, observations, TODO blocks, and, with `--attended`, the `- Recipe:` lines
|
|
148
|
-
the steps that write or need a choice.
|
|
146
|
+
2. `exploring-cases` (or `/explore-case <case-id> <env> [--attended] [--profiles a,b]`) explores the real pages for one
|
|
147
|
+
case. It edits that case file only: wording, observations, TODO blocks, and, with `--attended`, the `- Recipe:` lines
|
|
148
|
+
of the steps that write or need a choice. `--profiles` narrows the run to those profiles; runs add up, so the case
|
|
149
|
+
can be explored in passes.
|
|
149
150
|
3. `generating-specs` (or `/gen-spec <case-id> <env>`) turns the case into a spec. It replays the case and its
|
|
150
151
|
step recipes and `## Values`, writes the spec (values stay in the case document), but never runs the tests, never
|
|
151
|
-
writes data and never creates baselines.
|
|
152
|
-
|
|
153
|
-
(`
|
|
152
|
+
writes data and never creates baselines. There is no profile selection here: it covers every profile the case names,
|
|
153
|
+
which is why a case explored in passes generates one spec for all of them. A tagged step with no `- Recipe:` line
|
|
154
|
+
(an old `## Inputs` line counts until it is moved) stops with `needs-input`: run `/explore-case` first. Running specs
|
|
155
|
+
is a separate step (`pnpm asrun`, or the Run page).
|
|
154
156
|
Workspace maintenance is separate from the AI steps: `pnpm asrun upgrade` installs the newest framework, refreshes the
|
|
155
157
|
generated files and applies the release's workspace migrations (it checks the target release for breaking changes
|
|
156
158
|
before installing), `pnpm asrun init [--update] [--force]` writes or refreshes the workspace files, `pnpm asrun
|
|
@@ -161,9 +163,15 @@ Do not hand-write specs unless asked. Do not edit `lib/` to make a single spec p
|
|
|
161
163
|
Every case step is wrapped in `test.step('<n>. <case step text>', ...)` so reports and traces show the
|
|
162
164
|
case's own steps (see the skill's `references/conventions.md`).
|
|
163
165
|
Every AI command needs an environment (`--env`/`<env>`); there is no default and no "no environment" mode.
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
166
|
+
A one-shot AI run is a build run: it writes the case or the spec, never a plan. AsRun starts OpenCode with
|
|
167
|
+
`--agent build`, because OpenCode keeps the agent (build or plan) on the session and a plan session would only propose
|
|
168
|
+
changes and ask a question nobody can answer. Whatever mode or sandbox a run finds itself in, it still ends with the
|
|
169
|
+
`RESULT:` line: a run that was not allowed to write files is `needs-input`, never a plan and a question.
|
|
170
|
+
`/heal-spec <case-id> <env>` repairs one failing spec or refines a case and its spec on request (a passing run is not
|
|
171
|
+
a reason to refuse): it reads the existing report first (`pnpm heal:evidence --case <id> --env <env>`), the user's
|
|
172
|
+
request (`--hints <file>`), runs only the profiles that are logged in (`--logged-in`) and runs the case again only
|
|
173
|
+
when the report is missing, stale or not enough. A change that leaves an open question or an unconfirmed observation
|
|
174
|
+
in the case stops before the spec: the person reviews the case and runs `/explore-case` again.
|
|
167
175
|
Run `pnpm typecheck`, `pnpm spec:lint <case-id>` and `pnpm case:check` before reporting that a spec was generated. Run
|
|
168
176
|
`pnpm asrun --env <env> --profile <id> --grep <case-id>` only when healing a spec or when asked to.
|
|
169
177
|
Pick `--env staging` while developing. A case that does not list `production` under `writes` is skipped in
|
package/README.md
CHANGED
|
@@ -13,8 +13,8 @@ AsRun is a devDependency, not a service. Your profiles, cases, specs and baselin
|
|
|
13
13
|
- **One spec, every profile.** Each entry in `profiles.yaml` becomes a Playwright project with its own base URL,
|
|
14
14
|
saved login and screenshot baselines. Two accounts of one site give two independent runs.
|
|
15
15
|
- **An AI workflow, not a prompt dump.** `/make-case` turns raw notes into cases, `/explore-case` checks them against
|
|
16
|
-
the real pages, `/gen-spec` writes the spec, `/heal-spec` repairs it from the last report
|
|
17
|
-
`RESULT: ready` or `RESULT: needs-input`, so it works unattended.
|
|
16
|
+
the real pages, `/gen-spec` writes the spec, `/heal-spec` repairs it from the last report or refines a case and its
|
|
17
|
+
spec on request. Each command ends with `RESULT: ready` or `RESULT: needs-input`, so it works unattended.
|
|
18
18
|
- **Evidence for every run.** One video per test (browser tabs joined), a trace with every action and request,
|
|
19
19
|
screenshots on failure, and a report that puts the failure first.
|
|
20
20
|
- **Safe by default.** A case is read-only unless it lists environments under `writes`; writing anywhere except
|
|
@@ -100,7 +100,8 @@ exempts `@asrunjs/asrun` from pnpm's 24-hour release age, so a fresh release ins
|
|
|
100
100
|
notes with `/make-case notes.md`. Fill in the steps, what is expected and the exact values.
|
|
101
101
|
4. **Check it against the real pages.** `/explore-case header-logo staging` opens the pages (with your saved session),
|
|
102
102
|
writes what they show into the case and turns what it cannot know into questions. Answer them in the case file, or
|
|
103
|
-
in the UI's **Answer** sheet, and run it again.
|
|
103
|
+
in the UI's **Answer** sheet, and run it again. With many profiles, `--profiles a,b` opens only those; a later run
|
|
104
|
+
with the others adds theirs, and the case keeps both.
|
|
104
105
|
5. **Generate, run, read.** `/gen-spec header-logo staging` writes `tests/header-logo.spec.ts` and fills the case's
|
|
105
106
|
`## Values`. Then:
|
|
106
107
|
|
|
@@ -209,15 +209,20 @@ export function buildJobSpec(request) {
|
|
|
209
209
|
if (request.attended && request.command !== 'explore-case') {
|
|
210
210
|
throw new ActionError('Only explore-case can be attended.');
|
|
211
211
|
}
|
|
212
|
-
if ((request.
|
|
213
|
-
throw new ActionError('Only heal-spec takes
|
|
212
|
+
if ((request.hints !== undefined || request.report) && request.command !== 'heal-spec') {
|
|
213
|
+
throw new ActionError('Only heal-spec takes hints and a report.');
|
|
214
|
+
}
|
|
215
|
+
// The spec is generated for every profile the case names (and runs for every profile), so a selection could only
|
|
216
|
+
// narrow it wrongly.
|
|
217
|
+
if (request.profiles && request.command === 'gen-spec') {
|
|
218
|
+
throw new ActionError('gen-spec takes no profiles: it uses every profile the case holds information for.');
|
|
214
219
|
}
|
|
215
220
|
const profilesInEnv = listProfiles(request.env, knownProfiles).map((profile) => profile.id);
|
|
216
221
|
if (request.profiles?.some((id) => !profilesInEnv.includes(id))) {
|
|
217
222
|
throw new ActionError(`Unknown profile for "${request.env}".`);
|
|
218
223
|
}
|
|
219
224
|
if (request.profiles?.length === 0)
|
|
220
|
-
throw new ActionError('Choose at least one profile
|
|
225
|
+
throw new ActionError('Choose at least one profile.');
|
|
221
226
|
if (request.report !== undefined && !(REPORT_ID.test(request.report) && fs.existsSync(path.join(REPORTS_DIR, request.report, 'summary.json')))) {
|
|
222
227
|
throw new ActionError(`Unknown report "${request.report}".`);
|
|
223
228
|
}
|
|
@@ -234,7 +239,7 @@ export function buildJobSpec(request) {
|
|
|
234
239
|
thinking: request.thinking,
|
|
235
240
|
force: request.force,
|
|
236
241
|
attended: request.attended,
|
|
237
|
-
// Naming every profile is the same as leaving it out: the agent then takes all that are logged in.
|
|
242
|
+
// Naming every profile of the environment is the same as leaving it out: the agent then takes all that are logged in.
|
|
238
243
|
profiles: request.profiles && request.profiles.length < profilesInEnv.length ? request.profiles : undefined,
|
|
239
244
|
hints: hintsPath,
|
|
240
245
|
report: request.report,
|
|
@@ -32,9 +32,12 @@ export interface AiRunOptions {
|
|
|
32
32
|
attended?: boolean;
|
|
33
33
|
/** Show the agent's reasoning in the log (`--thinking` for OpenCode). Off by default: it costs tokens and time. */
|
|
34
34
|
thinking?: boolean;
|
|
35
|
-
/**
|
|
35
|
+
/**
|
|
36
|
+
* `explore-case` and `heal-spec` only: the profiles to open / heal. Omitted = every profile that applies in `env`
|
|
37
|
+
* (all that are logged in, for heal). `gen-spec` takes none: it uses every profile the case names.
|
|
38
|
+
*/
|
|
36
39
|
profiles?: string[];
|
|
37
|
-
/** `heal-spec` only: file (relative to the project root) with the user
|
|
40
|
+
/** `heal-spec` only: file (relative to the project root) with what the user wants repaired or improved, and any clues. */
|
|
38
41
|
hints?: string;
|
|
39
42
|
/** `heal-spec` only: the report (folder name under reports/) to read first instead of the newest one. */
|
|
40
43
|
report?: string;
|
|
@@ -48,7 +51,7 @@ export interface AiSession {
|
|
|
48
51
|
id: string;
|
|
49
52
|
resume: boolean;
|
|
50
53
|
}
|
|
51
|
-
/** The prompt of a one-shot run.
|
|
54
|
+
/** The prompt of a one-shot run. Every command may leave open questions in the case, so every one ends with a RESULT line. */
|
|
52
55
|
export declare function headlessPrompt(command: AiCommand, caseId: string, options: AiRunOptions): string;
|
|
53
56
|
/** Executable and arguments of the one-shot (non-interactive) run. */
|
|
54
57
|
export declare function headlessInvocation(tool: AiTool, command: AiCommand, caseId: string, options: AiRunOptions, session?: AiSession): {
|
|
@@ -17,16 +17,18 @@ export const AI_COMMAND_WRITES = {
|
|
|
17
17
|
* Agents never write data in any of them: a person does those steps.
|
|
18
18
|
*/
|
|
19
19
|
export const AI_ENV_HINT = {
|
|
20
|
-
'explore-case': 'Where the agent explores.
|
|
20
|
+
'explore-case': 'Where the agent explores. Only the profiles you tick are opened; it only reads, and with Attended on you do the steps that write data.',
|
|
21
21
|
'gen-spec': 'Where the agent explores and verifies the spec.',
|
|
22
|
-
'heal-spec': 'Where the
|
|
22
|
+
'heal-spec': 'Where the failure is diagnosed and the pages are checked. Only the profiles that are logged in there are run.',
|
|
23
23
|
};
|
|
24
24
|
export const slashCommand = (command, caseId, options) => {
|
|
25
25
|
const { env, force, attended, profiles, hints, report } = options;
|
|
26
26
|
const heal = command === 'heal-spec';
|
|
27
|
+
// gen-spec has no profile option: its scope is every profile the case names.
|
|
28
|
+
const picksProfiles = command === 'explore-case' || heal;
|
|
27
29
|
return (`/${command} ${caseId} ${env}${force && command === 'gen-spec' ? ' --force' : ''}` +
|
|
28
30
|
`${attended && command === 'explore-case' ? ' --attended' : ''}` +
|
|
29
|
-
`${
|
|
31
|
+
`${picksProfiles && profiles?.length ? ` --profiles ${profiles.join(',')}` : ''}` +
|
|
30
32
|
`${heal && report ? ` --report ${report}` : ''}` +
|
|
31
33
|
`${heal && hints ? ` --hints ${hints}` : ''}`);
|
|
32
34
|
};
|
|
@@ -69,7 +71,9 @@ const STREAM_ARGS = {
|
|
|
69
71
|
opencode: ['--format', 'json'],
|
|
70
72
|
};
|
|
71
73
|
function invocation(tool, prompt, writes, session, model, thinking) {
|
|
72
|
-
// OpenCode creates the session when the id does not exist yet, and continues it when it does.
|
|
74
|
+
// OpenCode creates the session when the id does not exist yet, and continues it when it does. It also keeps the
|
|
75
|
+
// agent (build/plan) on the session, so a session started in plan mode would only propose changes and ask a question
|
|
76
|
+
// nobody can answer; every one-shot run is a build run, whatever the session it continues.
|
|
73
77
|
// A model is named on every run: without one OpenCode falls back to its built-in free model, which has a daily
|
|
74
78
|
// usage limit, and nothing in the CLI's own state (the TUI's last-used model) applies to a one-shot run.
|
|
75
79
|
if (tool === 'opencode')
|
|
@@ -78,6 +82,8 @@ function invocation(tool, prompt, writes, session, model, thinking) {
|
|
|
78
82
|
args: [
|
|
79
83
|
'run',
|
|
80
84
|
'--auto',
|
|
85
|
+
'--agent',
|
|
86
|
+
'build',
|
|
81
87
|
...STREAM_ARGS.opencode,
|
|
82
88
|
...(session ? ['-s', session.id] : []),
|
|
83
89
|
...(model ? ['--model', model] : []),
|
|
@@ -121,11 +127,9 @@ const ATTENDED = 'Attended run: a person is at the machine and the browser windo
|
|
|
121
127
|
'inside the call that runs the card: the web UI sees that a person is needed only from that call, so without it ' +
|
|
122
128
|
'there is no "Your turn" badge and no notification. Nobody can answer questions in the chat, so write open ' +
|
|
123
129
|
'questions into the case file as the skill describes and end with the RESULT: line.';
|
|
124
|
-
/** The prompt of a one-shot run.
|
|
130
|
+
/** The prompt of a one-shot run. Every command may leave open questions in the case, so every one ends with a RESULT line. */
|
|
125
131
|
export function headlessPrompt(command, caseId, options) {
|
|
126
132
|
const slash = slashCommand(command, caseId, options);
|
|
127
|
-
if (command === 'heal-spec')
|
|
128
|
-
return slash;
|
|
129
133
|
if (command === 'explore-case' && options.attended)
|
|
130
134
|
return `${slash} ${ATTENDED}`;
|
|
131
135
|
return `${slash} ${NON_INTERACTIVE}`;
|
|
@@ -103,7 +103,7 @@ export type StartJobRequest = {
|
|
|
103
103
|
* its built-in free model. `heal-spec` keeps the model of the run it continues.
|
|
104
104
|
*/
|
|
105
105
|
model?: string;
|
|
106
|
-
/** `heal-spec` only: the profiles to heal; omitted = every profile that
|
|
106
|
+
/** `explore-case` and `heal-spec` only: the profiles to open / heal; omitted = every profile that applies. `gen-spec` takes none: it uses every profile the case names. */
|
|
107
107
|
profiles?: string[];
|
|
108
108
|
/** `heal-spec` only: what the user knows (optional). The server stores it as a file for the agent. */
|
|
109
109
|
hints?: string;
|