@asrunjs/asrun 0.2.0 → 0.5.2

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.
Files changed (94) hide show
  1. package/.claude/commands/explore-case.md +18 -15
  2. package/.claude/commands/gen-spec.md +16 -13
  3. package/.claude/commands/heal-spec.md +26 -23
  4. package/.claude/commands/make-case.md +11 -8
  5. package/.claude/skills/exploring-cases/SKILL.md +146 -132
  6. package/.claude/skills/exploring-cases/references/open-questions.md +116 -112
  7. package/.claude/skills/exploring-cases/references/readiness.md +146 -137
  8. package/.claude/skills/exploring-cases/references/user-handoff.md +157 -147
  9. package/.claude/skills/generating-specs/SKILL.md +219 -207
  10. package/.claude/skills/generating-specs/references/conventions.md +148 -148
  11. package/.claude/skills/making-cases/SKILL.md +72 -64
  12. package/.claude/skills/making-cases/references/normalizing.md +39 -38
  13. package/.claude/skills/making-cases/references/writes-and-email.md +37 -36
  14. package/AGENTS.md +159 -154
  15. package/CLAUDE.md +2 -1
  16. package/README.md +512 -410
  17. package/dist/lib/build-artifacts.d.ts +8 -0
  18. package/dist/lib/build-artifacts.js +10 -0
  19. package/dist/lib/case-doc.d.ts +311 -0
  20. package/dist/lib/case-doc.js +1117 -0
  21. package/dist/lib/cases.d.ts +2 -15
  22. package/dist/lib/cases.js +5 -78
  23. package/dist/lib/command.d.ts +24 -0
  24. package/dist/lib/command.js +90 -0
  25. package/dist/lib/fixtures.js +2 -2
  26. package/dist/lib/login-card.d.ts +22 -0
  27. package/dist/lib/login-card.js +183 -0
  28. package/dist/lib/node-cli.d.ts +6 -2
  29. package/dist/lib/node-cli.js +16 -6
  30. package/dist/lib/profiles.d.ts +25 -1
  31. package/dist/lib/profiles.js +54 -1
  32. package/dist/lib/run-filters.js +10 -2
  33. package/dist/lib/session.d.ts +13 -1
  34. package/dist/lib/session.js +73 -7
  35. package/dist/lib/targets.d.ts +5 -13
  36. package/dist/lib/targets.js +4 -29
  37. package/dist/lib/values.js +2 -2
  38. package/dist/scripts/build.js +2 -1
  39. package/dist/scripts/check-cases.js +74 -6
  40. package/dist/scripts/doctor.js +115 -4
  41. package/dist/scripts/explore.js +22 -1
  42. package/dist/scripts/init.d.ts +7 -1
  43. package/dist/scripts/init.js +61 -13
  44. package/dist/scripts/lint-specs.js +4 -1
  45. package/dist/scripts/login.js +30 -2
  46. package/dist/ui/server/actions.d.ts +4 -0
  47. package/dist/ui/server/actions.js +25 -12
  48. package/dist/ui/server/ai-models.d.ts +3 -0
  49. package/dist/ui/server/ai-models.js +347 -0
  50. package/dist/ui/server/ai-stream.d.ts +34 -9
  51. package/dist/ui/server/ai-stream.js +283 -77
  52. package/dist/ui/server/app.js +74 -12
  53. package/dist/ui/server/jobs.d.ts +7 -1
  54. package/dist/ui/server/jobs.js +69 -15
  55. package/dist/ui/server/profiles.d.ts +20 -1
  56. package/dist/ui/server/profiles.js +214 -38
  57. package/dist/ui/shared/ai-commands.d.ts +16 -6
  58. package/dist/ui/shared/ai-commands.js +35 -12
  59. package/dist/ui/shared/types.d.ts +114 -0
  60. package/docs/agents/framework-dev.md +79 -0
  61. package/docs/theme-guide.html +922 -692
  62. package/package.json +12 -1
  63. package/templates/.claude/commands/explore-case.md +22 -21
  64. package/templates/.claude/commands/gen-spec.md +21 -20
  65. package/templates/.claude/commands/heal-spec.md +31 -30
  66. package/templates/.claude/commands/make-case.md +13 -12
  67. package/templates/.mcp.json +8 -8
  68. package/templates/AGENTS.md +64 -45
  69. package/templates/cases/_template.md +57 -63
  70. package/templates/opencode.jsonc +16 -11
  71. package/templates/profiles.yaml +42 -29
  72. package/ui/dist/assets/{dist-BHaIOZdW.js → dist-BGbe0-Aa.js} +1 -1
  73. package/ui/dist/assets/{dist-CBV7_vDN.js → dist-Ba-HC662.js} +1 -1
  74. package/ui/dist/assets/{dist-BiE4suo9.js → dist-BtMLMthJ.js} +1 -1
  75. package/ui/dist/assets/{dist-gF2bFn-5.js → dist-C-Oyo1ZT.js} +1 -1
  76. package/ui/dist/assets/{dist-DX8knLVr.js → dist-C8MdhqgG.js} +1 -1
  77. package/ui/dist/assets/{dist-DHCY9KpV.js → dist-CG1pHn5m.js} +1 -1
  78. package/ui/dist/assets/{dist-BwYRbe5s.js → dist-CmpteMYY.js} +1 -1
  79. package/ui/dist/assets/{dist-D_I45xgJ.js → dist-DSy3dVf4.js} +1 -1
  80. package/ui/dist/assets/{dist-BqAROxzI.js → dist-Dq6sW5Ur.js} +1 -1
  81. package/ui/dist/assets/{dist-BSJMM_jp.js → dist-jjxQutEm.js} +1 -1
  82. package/ui/dist/assets/index-CTmnF0Wp.css +2 -0
  83. package/ui/dist/assets/index-P_Yo0ZZn.js +338 -0
  84. package/ui/dist/help/ai-tools.png +0 -0
  85. package/ui/dist/help/case-explore.png +0 -0
  86. package/ui/dist/help/case-generate.png +0 -0
  87. package/ui/dist/help/cases-memo.png +0 -0
  88. package/ui/dist/help/profile-form.png +0 -0
  89. package/ui/dist/help/profiles-login.png +0 -0
  90. package/ui/dist/help/reports.png +0 -0
  91. package/ui/dist/help/run-tests.png +0 -0
  92. package/ui/dist/index.html +22 -16
  93. package/ui/dist/assets/index-DmasQ6Rq.css +0 -2
  94. package/ui/dist/assets/index-I7uU93kk.js +0 -294
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@asrunjs/asrun",
3
- "version": "0.2.0",
3
+ "version": "0.5.2",
4
4
  "description": "Multi-profile end-to-end test suite: plain-language cases, AI-written Playwright specs, evidence for every run.",
5
5
  "license": "MIT",
6
6
  "author": "Zoro Chen",
@@ -55,7 +55,11 @@
55
55
  "@codemirror/lang-yaml": "^6.1.3",
56
56
  "@codemirror/language": "^6.13.1",
57
57
  "@codemirror/language-data": "^6.5.2",
58
+ "@codemirror/state": "^6.7.6",
58
59
  "@codemirror/view": "^6.43.15",
60
+ "@dnd-kit/core": "^6.3.1",
61
+ "@dnd-kit/sortable": "^10.0.0",
62
+ "@dnd-kit/utilities": "^3.2.2",
59
63
  "@hono/node-server": "^2.1.5",
60
64
  "@lezer/highlight": "^1.2.5",
61
65
  "@napi-rs/canvas": "^1.0.13",
@@ -92,6 +96,13 @@
92
96
  "spec:lint": "tsx scripts/lint-specs.ts",
93
97
  "baselines:review": "tsx scripts/review-baselines.ts",
94
98
  "pdf:render": "tsx scripts/render-pdf.ts",
99
+ "demo:up": "node scripts/demo.mjs up",
100
+ "demo:build": "node scripts/demo.mjs build",
101
+ "demo:seed": "node scripts/demo.mjs seed",
102
+ "demo:reset": "node scripts/demo.mjs reset",
103
+ "demo:down": "node scripts/demo.mjs down",
104
+ "demo:logs": "node scripts/demo.mjs logs",
105
+ "demo:status": "node scripts/demo.mjs status",
95
106
  "typecheck": "tsc --noEmit && tsc --noEmit -p ui/tsconfig.json",
96
107
  "ui": "tsx scripts/ui.ts",
97
108
  "ui:build": "tsx scripts/ui-build.ts",
@@ -1,21 +1,22 @@
1
- ---
2
- description: Explore the real pages for one case (optionally attended: you do the steps that write data), before generating the spec
3
- ---
4
-
5
- Load the framework skill `{{framework}}/.claude/skills/exploring-cases/SKILL.md` and explore: $ARGUMENTS
6
-
7
- If `.claude/skills/exploring-cases.md` exists, apply it after the framework skill; on conflict it wins, except rules
8
- tagged `[non-negotiable]`. Project facts are in `AGENTS.md` §3.
9
-
10
- Arguments: `<case-id> <env> [--attended]`. The case id is the path below `cases/` without `.md` (it may include a
11
- group folder, e.g. `documents/landing-page`) and is required. `<env>` is `staging` or `production`; it is required and there
12
- is no default (without one, stop and say so). With `--attended` I am at the machine and the browser window is
13
- visible: when a step writes data or needs a choice, hand it to me as the skill describes, wait for me, and record
14
- what I did as a general recipe under "## Inputs". Without `--attended`, never wait for me.
15
-
16
- Follow `{{framework}}/.claude/skills/exploring-cases/references/assertion-targets.md` (list the candidates, never
17
- pick when in doubt, ask for the exact image/text/place/UI) and `readiness.md` (wait for the key requests and the
18
- content before you read anything) of the skill.
19
-
20
- This command edits `cases/<case-id>.md` only (plus screenshots under `.explore/targets/`). Do not ask me questions in
21
- the chat: write open questions into the case file as the skill describes, and end with the `RESULT:` line.
1
+ ---
2
+ description: Explore the real pages for one case (optionally attended: you do the steps that write data), before generating the spec
3
+ ---
4
+
5
+ Load the framework skill `{{framework}}/.claude/skills/exploring-cases/SKILL.md` and explore: $ARGUMENTS
6
+
7
+ Rules combine in this order, and a later one wins where they conflict: the framework baseline
8
+ `{{framework}}/AGENTS.md`, the framework skill, `.claude/skills/exploring-cases.md` if it exists, then the workspace
9
+ `AGENTS.md` §2 (Project rules). F1–F6 always win. Project facts are in `AGENTS.md` §3.
10
+
11
+ Arguments: `<case-id> <env> [--attended]`. The case id is the path below `cases/` without `.md` (it may include a
12
+ group folder, e.g. `documents/landing-page`) and is required. `<env>` is `staging` or `production`; it is required and there
13
+ is no default (without one, stop and say so). With `--attended` I am at the machine and the browser window is
14
+ visible: when a step writes data or needs a choice, hand it to me as the skill describes, wait for me, and record
15
+ what I did as a general recipe under the step it belongs to (`- Recipe:` lines). Without `--attended`, never wait for me.
16
+
17
+ Follow `{{framework}}/.claude/skills/exploring-cases/references/assertion-targets.md` (list the candidates, never
18
+ pick when in doubt, ask for the exact image/text/place/UI) and `readiness.md` (wait for the key requests and the
19
+ content before you read anything) of the skill.
20
+
21
+ This command edits `cases/<case-id>.md` only (plus screenshots under `.explore/targets/`). Do not ask me questions in
22
+ the chat: write open questions into the case file as the skill describes, and end with the `RESULT:` line.
@@ -1,20 +1,21 @@
1
- ---
2
- description: Generate or update tests/<id>.spec.ts from cases/<id>.md (the id may be <group>/<name>)
3
- ---
4
-
5
- Load the framework skill `{{framework}}/.claude/skills/generating-specs/SKILL.md` and generate the spec for:
6
- $ARGUMENTS
7
-
8
- If `.claude/skills/generating-specs.md` exists, apply it after the framework skill; on conflict it wins, except rules
9
- tagged `[non-negotiable]`. Project facts are in `AGENTS.md` §3.
10
-
11
- Arguments: `<case-id> [<env>] [--force]`. The case file is `cases/<case-id>.md` (the id may include one group folder,
12
- e.g. `documents/landing-page`). `<env>` is the environment to explore in (`staging` or `production`); there is no default. If
13
- the spec already exists, it is left alone unless `--force` is given; with `--force` it is regenerated and overwritten.
14
-
15
- Follow the skill's procedure exactly, including its `assertion-targets.md` and `readiness.md`; run
16
- `pnpm spec:lint <case-id>`. Only generate the spec: do not run `pnpm asrun` (running specs is a separate
17
- process), and do not create baselines.
18
-
19
- Do not ask me questions: resolve ambiguity as the skill describes (explore the page, use observed values marked for
20
- QA, write the remaining questions into the case file), and end with the `RESULT:` line.
1
+ ---
2
+ description: Generate or update tests/<id>.spec.ts from cases/<id>.md (the id may be <group>/<name>)
3
+ ---
4
+
5
+ Load the framework skill `{{framework}}/.claude/skills/generating-specs/SKILL.md` and generate the spec for:
6
+ $ARGUMENTS
7
+
8
+ Rules combine in this order, and a later one wins where they conflict: the framework baseline
9
+ `{{framework}}/AGENTS.md`, the framework skill, `.claude/skills/generating-specs.md` if it exists, then the workspace
10
+ `AGENTS.md` §2 (Project rules). F1–F6 always win. Project facts are in `AGENTS.md` §3.
11
+
12
+ Arguments: `<case-id> [<env>] [--force]`. The case file is `cases/<case-id>.md` (the id may include one group folder,
13
+ e.g. `documents/landing-page`). `<env>` is the environment to explore in (`staging` or `production`); there is no default. If
14
+ the spec already exists, it is left alone unless `--force` is given; with `--force` it is regenerated and overwritten.
15
+
16
+ Follow the skill's procedure exactly, including its `assertion-targets.md` and `readiness.md`; run
17
+ `pnpm spec:lint <case-id>`. Only generate the spec: do not run `pnpm asrun` (running specs is a separate
18
+ process), and do not create baselines.
19
+
20
+ Do not ask me questions: resolve ambiguity as the skill describes (explore the page, use observed values marked for
21
+ QA, write the remaining questions into the case file), and end with the `RESULT:` line.
@@ -1,30 +1,31 @@
1
- ---
2
- description: Diagnose and fix a failing spec from its last report (without hiding real product regressions)
3
- ---
4
-
5
- Load the framework skill `{{framework}}/.claude/skills/generating-specs/SKILL.md`, section "Healing a failing
6
- spec", and follow it exactly.
7
-
8
- If `.claude/skills/generating-specs.md` exists, apply it after the framework skill; on conflict it wins, except rules
9
- tagged `[non-negotiable]`. Project facts are in `AGENTS.md` §3.
10
-
11
- Arguments: $ARGUMENTS
12
- Format: `<case-id> <env> [--profiles a,b] [--report <run-id>] [--hints <file>]`, with optional free text after them.
13
- - `<case-id>` and `<env>` (`staging` or `production`) are required. There is no default environment. Without one,
14
- stop and say so.
15
- - `--profiles`: the profiles to heal. Without it, every profile that is logged in in `<env>`.
16
- - `--report`: the report (folder name under `reports/`) to read first. Without it, the newest report of this case.
17
- - `--hints <file>`: a file with what the user knows (what to heal, evidence, clues). Read it first. Any free text
18
- after the arguments is the same kind of clue. Both are optional.
19
-
20
- Before you decide "product or test", audit the assertion itself (target card, baseline content, readiness): see
21
- step 4 of the skill's healing section, `assertion-targets.md` and `readiness.md`. Run `pnpm spec:lint <case-id>`.
22
- Read the existing report first (`pnpm heal:evidence --case <case-id> --env <env>`), and run the case again only when
23
- the skill says it is needed. Always run with `--logged-in`. Tell me whether it is a test problem or a product
24
- finding.
25
-
26
- Run `pnpm asrun ...`, `pnpm heal:evidence ...`, `pnpm spec:lint ...`, `pnpm baselines:review ...` and
27
- `pnpm status ...` as plain commands, optionally piped to `tail` or `head`, and do not chain other commands with them
28
- (`;` or `&&`). Only these exact forms run outside Claude Code's sandbox, which tsx and the browser need. If a
29
- command still fails with `listen EPERM` or a sandbox error, stop and report it. Do not ask to disable the sandbox,
30
- and never add `--allow-writes` or set `ASRUN_ALLOW_WRITES`.
1
+ ---
2
+ description: Diagnose and fix a failing spec from its last report (without hiding real product regressions)
3
+ ---
4
+
5
+ Load the framework skill `{{framework}}/.claude/skills/generating-specs/SKILL.md`, section "Healing a failing
6
+ spec", and follow it exactly.
7
+
8
+ Rules combine in this order, and a later one wins where they conflict: the framework baseline
9
+ `{{framework}}/AGENTS.md`, the framework skill, `.claude/skills/generating-specs.md` if it exists, then the workspace
10
+ `AGENTS.md` §2 (Project rules). F1–F6 always win. Project facts are in `AGENTS.md` §3.
11
+
12
+ Arguments: $ARGUMENTS
13
+ Format: `<case-id> <env> [--profiles a,b] [--report <run-id>] [--hints <file>]`, with optional free text after them.
14
+ - `<case-id>` and `<env>` (`staging` or `production`) are required. There is no default environment. Without one,
15
+ stop and say so.
16
+ - `--profiles`: the profiles to heal. Without it, every profile that is logged in in `<env>`.
17
+ - `--report`: the report (folder name under `reports/`) to read first. Without it, the newest report of this case.
18
+ - `--hints <file>`: a file with what the user knows (what to heal, evidence, clues). Read it first. Any free text
19
+ after the arguments is the same kind of clue. Both are optional.
20
+
21
+ Before you decide "product or test", audit the assertion itself (target card, baseline content, readiness): see
22
+ step 4 of the skill's healing section, `assertion-targets.md` and `readiness.md`. Run `pnpm spec:lint <case-id>`.
23
+ Read the existing report first (`pnpm heal:evidence --case <case-id> --env <env>`), and run the case again only when
24
+ the skill says it is needed. Always run with `--logged-in`. Tell me whether it is a test problem or a product
25
+ finding.
26
+
27
+ Run `pnpm asrun ...`, `pnpm heal:evidence ...`, `pnpm spec:lint ...`, `pnpm baselines:review ...` and
28
+ `pnpm status ...` as plain commands, optionally piped to `tail` or `head`, and do not chain other commands with them
29
+ (`;` or `&&`). Only these exact forms run outside Claude Code's sandbox, which tsx and the browser need. If a
30
+ command still fails with `listen EPERM` or a sandbox error, stop and report it. Do not ask to disable the sandbox,
31
+ and never add `--allow-writes` or set `ASRUN_ALLOW_WRITES`.
@@ -1,12 +1,13 @@
1
- ---
2
- description: Turn raw test notes (pasted text or a file) into case documents in cases/
3
- ---
4
-
5
- Load the framework skill `{{framework}}/.claude/skills/making-cases/SKILL.md` and turn this input into case
6
- documents: $ARGUMENTS
7
-
8
- If `.claude/skills/making-cases.md` exists, apply it after the framework skill; on conflict it wins, except rules
9
- tagged `[non-negotiable]`. Project facts are in `AGENTS.md` §3.
10
-
11
- The input is either text or a path to a file with the notes. Follow the skill's procedure exactly. Ask me the open
12
- questions before writing any case file. Do not generate specs; that is `/gen-spec`.
1
+ ---
2
+ description: Turn raw test notes (pasted text or a file) into case documents in cases/
3
+ ---
4
+
5
+ Load the framework skill `{{framework}}/.claude/skills/making-cases/SKILL.md` and turn this input into case
6
+ documents: $ARGUMENTS
7
+
8
+ Rules combine in this order, and a later one wins where they conflict: the framework baseline
9
+ `{{framework}}/AGENTS.md`, the framework skill, `.claude/skills/making-cases.md` if it exists, then the workspace
10
+ `AGENTS.md` §2 (Project rules). F1–F6 always win. Project facts are in `AGENTS.md` §3.
11
+
12
+ The input is either text or a path to a file with the notes. Follow the skill's procedure exactly. Ask me the open
13
+ questions before writing any case file. Do not generate specs; that is `/gen-spec`.
@@ -1,8 +1,8 @@
1
- {
2
- "mcpServers": {
3
- "playwright-test": {
4
- "command": "./node_modules/.bin/playwright",
5
- "args": ["run-test-mcp-server"]
6
- }
7
- }
8
- }
1
+ {
2
+ "mcpServers": {
3
+ "playwright-test": {
4
+ "command": "{{playwright}}",
5
+ "args": ["run-test-mcp-server"]
6
+ }
7
+ }
8
+ }
@@ -1,45 +1,64 @@
1
- # <project name> — asrun workspace
2
-
3
- This project uses the asrun framework, which lives in `{{framework}}` as an installed dependency. The framework is
4
- read-only here: never edit files inside it, and never commit test data into it.
5
-
6
- Read this file, then the framework baseline, before any AI step.
7
-
8
- ## 1. Framework baseline (binding)
9
-
10
- Read `{{framework}}/AGENTS.md` in full. It is part of this project's rules. Its hard rules carry ids `F1`..`F10`,
11
- its browser rules `B1`..`B4`, its assertion rules `A1`..`A6`. Rules tagged `[non-negotiable]` cannot be narrowed.
12
-
13
- The framework skills are in `{{framework}}/.claude/skills/`. The commands in `.claude/commands/` load them. A
14
- project that needs different wording puts an override at `.claude/skills/<skill>.md` (for example
15
- `.claude/skills/exploring-cases.md`); the command applies the framework skill first and the override afterwards, and
16
- on conflict the override wins except for `[non-negotiable]` rules. `pnpm asrun doctor` lists every override.
17
-
18
- ## 2. Project rules (only stricter)
19
-
20
- Add rules that narrow the baseline for this project, and name the baseline rule each one narrows. The rules `F1`..`F6`
21
- cannot be narrowed, so they never appear here. Example:
22
-
23
- | Rule | Project rule |
24
- |---|---|
25
- | F9 | Staging writes are limited to accounts named `qa-*` and names starting with `[asrun]`. |
26
- | F7 | This project runs production profiles only from a scheduled job; people use `--env staging`. |
27
-
28
- `pnpm asrun doctor` fails when this table names a `[non-negotiable]` rule.
29
-
30
- ## 3. Project facts
31
-
32
- - Profiles and environments: `profiles.yaml`.
33
- - Areas: one folder per area below `cases/` (for example `cases/<area>/<name>.md`).
34
- - Expected values: they live in each case's `## Values` block, never here and never in `profiles.yaml`.
35
- - Who owns a finding, and where findings are reported: <fill in>.
36
-
37
- ## Layout of this workspace
38
-
39
- - `cases/**/*.md` human-written test cases (committed)
40
- - `tests/**/*.spec.ts` generated Playwright specs and their `*-snapshots/` baselines (committed)
41
- - `profiles.yaml` one entry per environment, connection settings only (committed)
42
- - `.auth/` saved logins: never read, never commit
43
- - `reports/` run reports: never commit
44
- - `{{framework}}/` the framework (installed package): never edit
45
- - `.env` local settings (`ASRUN_ROOT`): never commit
1
+ # <project name> — asrun workspace
2
+
3
+ This project uses the asrun framework, which lives in `{{framework}}` as an installed dependency. The framework is
4
+ read-only here: never edit files inside it, and never commit test data into it.
5
+
6
+ Read this file and the framework baseline it points at, before any AI step.
7
+
8
+ ## 1. How rules combine
9
+
10
+ Rules are applied in this order, and a later layer wins where they conflict (the framework baseline, "Precedence"):
11
+
12
+ 1. `F1`–`F6` of the framework baseline: safety, in every project. Nothing here can change them.
13
+ 2. The framework baseline, `{{framework}}/AGENTS.md`.
14
+ 3. The framework skill (`{{framework}}/.claude/skills/<skill>/SKILL.md`).
15
+ 4. A project skill override, `.claude/skills/<skill>.md` (optional; the command and the skill read it).
16
+ 5. This file, §2 below: what this project does differently.
17
+
18
+ The framework skills are loaded by the commands in `.claude/commands/` (Claude Code) and `.opencode/commands/`
19
+ (OpenCode). The skills live in the framework package; §3 holds this project's facts.
20
+
21
+ ## 2. Project rules
22
+
23
+ Only what differs from the baseline: name the rule id, and whether it `narrows` (stricter) or `replaces` (a different
24
+ default, for example the artifact language) the baseline rule. `replaces` is refused for `F1`–`F6`. Rows whose first
25
+ cell is not a rule id are ignored, so the placeholder below can stay until you need it.
26
+
27
+ | Rule | Project rule | Effect |
28
+ |---|---|---|
29
+ | <rule id, e.g. F10> | <what this project does differently from the baseline> | narrows |
30
+
31
+ Examples (delete what you do not use; the fenced block is an example, not a rule):
32
+
33
+ ```markdown
34
+ | F10 | Case prose, report summaries and assertion messages in Simplified Chinese; code and commit messages stay English. | replaces |
35
+ | F9 | Staging writes are limited to accounts named `qa-*` and names starting with `[asrun]`. | narrows |
36
+ | F7 | This project runs production profiles only from a scheduled job; people use `--env staging`. | narrows |
37
+ ```
38
+
39
+ `pnpm asrun doctor` fails when this table names a `[non-negotiable]` rule, an unknown rule id, or an `Effect` that is
40
+ not `narrows` or `replaces`.
41
+
42
+ The structural tokens are fixed English whatever the project language: the section headings (`## Values`, `## Targets`,
43
+ ...), a step's `- Recipe (phase): ...` lines, `### T<n>`, the `TODO` blocks with their `Answer:` line,
44
+ `[input]`/`[writes]`/`[email]`, `RESULT:`, and the front-matter keys. See "Fixed tokens" in the framework baseline.
45
+
46
+ ## 3. Project facts
47
+
48
+ - Profiles and environments: `profiles.yaml`.
49
+ - Areas: one folder per area below `cases/` (for example `cases/<area>/<name>.md`).
50
+ - Expected values: they live in each case's `## Values` block, never here and never in `profiles.yaml`.
51
+ - Who owns a finding, and where findings are reported: <fill in>.
52
+
53
+ ## Layout of this workspace
54
+
55
+ - `cases/**/*.md` human-written test cases (committed)
56
+ - `tests/**/*.spec.ts` generated Playwright specs and their `*-snapshots/` baselines (committed)
57
+ - `profiles.yaml` one entry per environment, connection settings only (committed)
58
+ - `.claude/commands/` `/make-case`, `/explore-case`, `/gen-spec`, `/heal-spec` for Claude Code
59
+ - `.opencode/commands/` the same commands for OpenCode (it does not read `.claude/commands`)
60
+ - `.claude/skills/` optional overrides of a framework skill: `<skill>.md`
61
+ - `.auth/` saved logins: never read, never commit
62
+ - `reports/` run reports: never commit
63
+ - `{{framework}}/` the framework (installed package): never edit
64
+ - `.env` local settings (`ASRUN_ROOT`): never commit
@@ -1,63 +1,57 @@
1
- ---
2
- id: {{id}}
3
- title: One-line summary of what this case proves
4
- login: required # required | none (none = public page, no saved session needed)
5
- suites: [smoke, regression] # a case may be in several suites; filter with `pnpm asrun --suite <name>`
6
- # writes: [staging] # omit = read-only. The environments in which the case may create or change data of the test accounts (and cleans it up); elsewhere it is skipped with a notice
7
- # writes-note: What the case creates or changes, e.g. one draft named "[asrun] ...", deleted at the end. (required when writes is set)
8
- # envs: [production, staging] # optional: run only in these environments (default: all); must include every environment in `writes`
9
- ---
10
-
11
- ## Goal
12
- Why this case exists, in one or two sentences.
13
-
14
- ## Steps
15
- 1. Open <page or path, e.g. /account/>.
16
- 2. <What to look at or click.>
17
-
18
- ## Expected
19
- - <Behaviour that must hold for every profile.>
20
-
21
- ## Values
22
- The exact values the spec asserts. `default` applies to every profile; an entry named after a profile id is
23
- deep-merged over it. Put only the literals here (names, labels, options, test data names); the checks themselves stay
24
- in Steps and Expected, and the selectors come from `## Targets`. The case document is the only place where expected
25
- values live: `profiles.yaml` holds connection settings only.
26
-
27
- ```yaml
28
- default:
29
- exampleKey: Example value
30
- example-staging:
31
- exampleKey: Example value on staging
32
- ```
33
-
34
- ## Visual checks
35
- - <Which element must match a screenshot baseline, e.g. the header logo.>
36
-
37
- ## Targets
38
- One card per image, logo, icon, file, PDF or repeated text that a check looks at. Checks above refer to it as `[T1]`.
39
- Written by `/explore-case`; do not guess: when it is unclear which element is meant, answer the TODO with the exact
40
- image, text, place or UI. Rules: `{{framework}}/.claude/skills/exploring-cases/references/assertion-targets.md`.
41
-
42
- ### T1 <short name, e.g. Preview logo>
43
- - What: <the thing itself, and what it is NOT when a look-alike exists>.
44
- - Where: <region of the page, dialog, tab or file page>.
45
- - Identified by: <role and name, test id, alt text or title; never a position>.
46
- - Not: <look-alikes that must not be matched, e.g. a content image>.
47
- - Ready when: <what shows that the content has loaded>.
48
- - Reference <profile-id>: .explore/targets/<case-id>/T1-<profile-id>.png
49
-
50
- ## Data
51
- Only for cases with `writes`. Say what is created, its name (prefix `[asrun]`), and how it is removed at the end
52
- (also when the case fails). Mark steps that write with `[writes]`, steps that need a person's choice with `[input]`,
53
- and steps that send email with `[email]` (email is never sent in production; in other environments only for profiles
54
- with `email: true`).
55
-
56
- ## Inputs
57
- Only for cases with `[input]` steps. Written by `/explore-case --attended` from what a person did in the browser, as a
58
- general recipe: positions instead of names ("select items #1 to #3"), `[asrun]` names for created data, control
59
- labels and roles but no selectors or ids. One bullet per `[input]` step, keyed by the step number.
60
- - Step <n> (<what>): <the general recipe>.
61
-
62
- ## Notes
63
- Read-only unless the front matter has `writes`.
1
+ ---
2
+ id: {{id}}
3
+ title: One-line summary of what this case proves
4
+ login: required # required | none (none = public page, no saved session needed)
5
+ suites: [smoke, regression] # a case may be in several suites; filter with `pnpm asrun --suite <name>`
6
+ # writes: [staging] # omit = read-only. The environments in which the case may create or change data of the test accounts (and cleans it up); elsewhere it is skipped with a notice
7
+ # writes-note: What the case creates or changes, e.g. one draft named "[asrun] ...", deleted at the end. (required when writes is set)
8
+ # envs: [production, staging] # optional: run only in these environments (default: all); must include every environment in `writes`
9
+ ---
10
+
11
+ ## Goal
12
+ Why this case exists, in one or two sentences.
13
+
14
+ ## Steps
15
+ 1. Open <page or path, e.g. /account/>.
16
+ - Ready when: <the one positive signal that what this step loads is really there, e.g. the list shows its first
17
+ row. It says when to look; what must be true afterwards goes under Expected.>
18
+ 2. <What to look at or click.>
19
+ 3. <A step that needs a person's choice or writes something.> [input] [writes]
20
+ - Recipe (start): <what the person did, recorded by /explore-case --attended: positions, [asrun] names, control
21
+ labels; never selectors or ids. One line per phase.>
22
+
23
+ ## Expected
24
+ - <Behaviour that must hold for every profile.>
25
+
26
+ ## Values
27
+ The exact values the spec asserts. `default` applies to every profile; an entry named after a profile id is
28
+ deep-merged over it. Put only the literals here (names, labels, options, test data names); the checks themselves stay
29
+ in Steps and Expected, and the selectors come from `## Targets`. The case document is the only place where expected
30
+ values live: `profiles.yaml` holds connection settings only.
31
+
32
+ ```yaml
33
+ default:
34
+ exampleKey: Example value
35
+ example-staging:
36
+ exampleKey: Example value on staging
37
+ ```
38
+
39
+ ## Visual checks
40
+ - <Which element must match a screenshot baseline, e.g. the header logo.>
41
+
42
+ ## Targets
43
+ One card per image, logo, icon, file, PDF or repeated text that a check looks at. Checks above refer to it as `[T1]`.
44
+ Written by `/explore-case`; do not guess: when it is unclear which element is meant, answer the TODO with the exact
45
+ image, text, place or UI. Rules: `{{framework}}/.claude/skills/exploring-cases/references/assertion-targets.md`.
46
+
47
+ ### T1 <short name, e.g. Preview logo>
48
+ - What: <the thing itself, and what it is NOT when a look-alike exists>.
49
+ - Where: <region of the page, dialog, tab or file page>.
50
+ - Identified by: <role and name, test id, alt text or title; never a position>.
51
+ - Not: <look-alikes that must not be matched, e.g. a content image>.
52
+ - Ready when: <what shows that the content has loaded>.
53
+ - Reference <profile-id>: .explore/targets/<case-id>/T1-<profile-id>.png
54
+
55
+ ## Notes
56
+ Assumptions and constraints for a reviewer. For a case with `writes`, `writes-note` is the one place that says what is
57
+ created, changed and removed; the removal is a step above, and it runs also when a step fails.
@@ -1,11 +1,16 @@
1
- {
2
- "$schema": "https://opencode.ai/config.json",
3
- "mcp": {
4
- // Playwright's test-runner MCP: opens a page through a profile project, so the saved
5
- // login for that profile is applied automatically (use the `project` argument).
6
- "playwright-test": {
7
- "type": "local",
8
- "command": ["./node_modules/.bin/playwright", "run-test-mcp-server"]
9
- }
10
- }
11
- }
1
+ {
2
+ "$schema": "https://opencode.ai/config.json",
3
+ // The model the AI commands run with. Without one, OpenCode falls back to its built-in free model, which has a
4
+ // daily usage limit; the field also decides what `opencode run` uses, since a one-shot run ignores the model the
5
+ // TUI last picked. The AsRun web UI offers the same choice (read from `opencode models`) in its top bar.
6
+ // "model": "openrouter/deepseek/deepseek-v4.1-flash-1017",
7
+ "mcp": {
8
+ // Playwright's test-runner MCP: opens a page through a profile project, so the saved
9
+ // login for that profile is applied automatically (use the `project` argument).
10
+ // OpenCode reads this file only (it does not read `.mcp.json`, which is Claude Code's).
11
+ "playwright-test": {
12
+ "type": "local",
13
+ "command": ["{{playwright}}", "run-test-mcp-server"]
14
+ }
15
+ }
16
+ }
@@ -1,29 +1,42 @@
1
- # One entry per environment target. Each profile becomes one Playwright project named after its id,
2
- # so every test runs once per profile. Connection settings only: expected values live in the case documents.
3
- #
4
- # id: lowercase words with single dashes. The Playwright project name, the saved session
5
- # file (`.auth/<id>.json`) and the screenshot baseline names all use it.
6
- # name: what people see in the UI and the reports.
7
- # env: the environment this profile points at (`production`, `staging`, ...). Any environment
8
- # that is not `staging` is protected: cases that write data need a person's confirmation
9
- # there. `--env <env>` selects the profiles of one environment.
10
- # baseURL: the site address, without a path.
11
- # account: a label for humans (a mailbox or username). Never a password; logins live in .auth/.
12
- # tags: optional lowercase words, for grouping and `pnpm asrun --tag <tag>`.
13
- # email: `true` only when a real mailbox is connected, so tests may send email. Never in production.
14
- # sessionCheckPath: a page that redirects to /login when the session is missing or expired.
15
-
16
- profiles:
17
- - id: example-staging
18
- name: Example (staging)
19
- env: staging
20
- baseURL: https://staging.example.com
21
- tags:
22
- - core
23
- email: false
24
-
25
- # - id: example-production
26
- # name: Example
27
- # env: production
28
- # baseURL: https://www.example.com
29
- # email: false
1
+ # One entry per environment target. Each profile becomes one Playwright project named after its id,
2
+ # so every test runs once per profile. Connection settings only: expected values live in the case documents.
3
+ #
4
+ # id: lowercase words with single dashes. The Playwright project name, the saved session
5
+ # file (`.auth/<id>.json`) and the screenshot baseline names all use it.
6
+ # name: what people see in the UI and the reports.
7
+ # env: the environment this profile points at (`production`, `staging`, ...). Any environment
8
+ # that is not `staging` is protected: cases that write data need a person's confirmation
9
+ # there. `--env <env>` selects the profiles of one environment.
10
+ # baseURL: the site address, without a path.
11
+ # account: a label for humans (a mailbox or username). Never a password; logins live in .auth/.
12
+ # tags: optional lowercase words, for grouping and `pnpm asrun --tag <tag>`.
13
+ # email: `true` only when a real mailbox is connected, so tests may send email. Never in production.
14
+ # startPath: the page "Visit" on the Profiles page opens after a login, e.g. `/app/home`.
15
+ # Empty (the default) opens the site root; a path on the site, never another host.
16
+ # sessionCheckPath: a page only a signed-in visitor sees, e.g. `/settings`; that is how "Verify" and the
17
+ # pre-run check find out whether the saved login still works.
18
+ # sessionCheck: optional, how that page shows a missing login. The defaults fit the common case (a
19
+ # redirect to /login); name what your site does when it differs:
20
+ # loggedOutUrl: where a signed-out visitor ends up (default `/login`): a path on the
21
+ # site, or a full URL for single sign-on. A 401/403 response counts too.
22
+ # loggedInSelector: a selector that is only there while signed in, e.g.
23
+ # "input[name='username']". Without it, "not redirected to the login
24
+ # page" is taken as signed in, which a single-page app can mislead.
25
+ # loggedOutSelector: a selector that shows the visitor is signed out, e.g. the password
26
+ # field of a login form the site shows at the same address.
27
+ # timeoutMs: how long to wait for one of those signals (default 3000).
28
+
29
+ profiles:
30
+ - id: example-staging
31
+ name: Example (staging)
32
+ env: staging
33
+ baseURL: https://staging.example.com
34
+ tags:
35
+ - core
36
+ email: false
37
+
38
+ # - id: example-production
39
+ # name: Example
40
+ # env: production
41
+ # baseURL: https://www.example.com
42
+ # email: false