waygraph 0.15.18 → 0.15.19
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/README.md +29 -16
- package/dist/practices-check.d.ts +1 -1
- package/dist/practices-check.js +36 -0
- package/examples/saucedemo/.waygraph-auto/7eded669.log +0 -0
- package/examples/saucedemo/.waygraph-auto/9f0287e6.json +8 -0
- package/examples/saucedemo/.waygraph-auto/9f0287e6.log +0 -0
- package/package.json +1 -1
- package/templates/scaffold/src/map/(external)/mailpit/_methods/open-message.method.block.ts +1 -0
- package/templates/skills/waygraph-convention.skill.md +13 -3
package/README.md
CHANGED
|
@@ -298,10 +298,26 @@ code, an autonomous agent authoring Blocks) - it warns, never fails the process.
|
|
|
298
298
|
|
|
299
299
|
**`waygraph typecheck [project]`** runs `tsc --noEmit` then the same **bad-practice** scan
|
|
300
300
|
(wildcard `Checkpoint<string>`, assert blocks missing type args, multi-`.fill()` Methods,
|
|
301
|
-
fill+click in one Method
|
|
302
|
-
skip the scan. Opt out per
|
|
303
|
-
`// waygraph-ignore: multi-input, combined-action
|
|
304
|
-
`waygraph --skill-convention`.
|
|
301
|
+
fill+click in one Method, empty `verify` on a transition Block or `defineAssertBlock`).
|
|
302
|
+
Practices warn only unless `tsc` fails; use `--no-practices` to skip the scan. Opt out per
|
|
303
|
+
file: `// waygraph-ignore-practices` or `// waygraph-ignore: multi-input, combined-action,
|
|
304
|
+
empty-verify`. Print full agent guidance: `waygraph --skill-convention`.
|
|
305
|
+
|
|
306
|
+
**Empty verify is the one that matters most for codegen'd Blocks.** A framework can enforce
|
|
307
|
+
that a check *exists* and stays structurally honest (typed, wired, right file) - it cannot
|
|
308
|
+
author the semantic content of that check, since only someone who knows what "success" means
|
|
309
|
+
for this specific app can write it. That's a correct place to draw the line, but it shifts
|
|
310
|
+
all the risk onto whether anything catches a Block left with a placeholder `verify: []` by
|
|
311
|
+
the time it ships - which would otherwise pass every static check, the orphan scan, and
|
|
312
|
+
`tsc`, and run green in CI forever, because an empty array isn't a wrong check, it's the
|
|
313
|
+
*absence* of one. `waygraph check`/`typecheck` now flag exactly that: a `defineMethodBlock`/
|
|
314
|
+
`defineEffectBlock` whose `In`/`Out` Checkpoints actually differ (a real transition, not a
|
|
315
|
+
self-loop like `fill-username`) with no `verify` key or a literal `verify: []`, and the same
|
|
316
|
+
for `defineAssertBlock` (whose entire job is checking). Silence it deliberately, the same as
|
|
317
|
+
any other practice warning, with `// waygraph-ignore: empty-verify` - e.g. when a downstream
|
|
318
|
+
`defineAssertBlock` right after it in the `.flow.ts` is what actually confirms the transition
|
|
319
|
+
(see `templates/scaffold`'s own `open-message.method.block.ts`, confirmed by
|
|
320
|
+
`AssertEmailContentBlock` right after it, not by its own `verify`).
|
|
305
321
|
|
|
306
322
|
### Demo narration
|
|
307
323
|
|
|
@@ -998,25 +1014,22 @@ really a Nav/Page/Assert/Method from this package's own factories.
|
|
|
998
1014
|
|------|---------|
|
|
999
1015
|
| Watch Sauce Demo step-through (temp dir only) | `npx waygraph try demo` |
|
|
1000
1016
|
| Interactive explore (Add/Remove/Open details from live page) | `cd examples/saucedemo && npm i && npx waygraph auto` |
|
|
1001
|
-
| Scaffold a new **offline** project (green `npm test` on local fixture `:4177`) | `npx
|
|
1017
|
+
| Scaffold a new **offline** project (green `npm test` on local fixture `:4177`) | `npx waygraph init my-app` |
|
|
1002
1018
|
| Install coding-agent defs for diving an app into Blocks | `npx waygraph agent-dive --loop claude` (also `opencode` / `cursor` / `vscode`) |
|
|
1003
1019
|
| Print a packaged agent skill to stdout | `npx waygraph --skill` (list) / `--skill-pilot` / `--skill-pilot-blind` / `--skill-convention` |
|
|
1004
1020
|
| Add waygraph to an existing repo | `npm install waygraph @playwright/test` |
|
|
1005
1021
|
|
|
1006
|
-
**Scaffold is not hidden inside waygraph alone** - the offline starter also ships as
|
|
1007
|
-
[`create-waygraph`](https://github.com/deviate-dv8/create-waygraph) on npm (same template
|
|
1008
|
-
as `waygraph init` since 0.7.5). Use whichever entry you already have:
|
|
1009
|
-
`npx create-waygraph my-app` when reading the GitHub Pages docs, or `npx waygraph init my-app`
|
|
1010
|
-
when the CLI is already installed. After either:
|
|
1011
|
-
|
|
1012
1022
|
```bash
|
|
1023
|
+
npx waygraph init my-app
|
|
1013
1024
|
cd my-app && npm install && npx playwright install chromium && npm test
|
|
1014
1025
|
```
|
|
1015
1026
|
|
|
1016
1027
|
`try demo` is different: live saucedemo.com, step-through **Sign In -> Shop & Checkout ->
|
|
1017
1028
|
blocked Viewer login**, then headless tests. Permanent full example:
|
|
1018
|
-
[`examples/saucedemo`](./examples/saucedemo). Offline empty scaffold: `init
|
|
1019
|
-
|
|
1029
|
+
[`examples/saucedemo`](./examples/saucedemo). Offline empty scaffold: `init`.
|
|
1030
|
+
|
|
1031
|
+
**`create-waygraph` (npm) is deprecated** - it was the identical `init` template shipped as
|
|
1032
|
+
a second package for no real benefit. Use `npx waygraph init my-app` instead.
|
|
1020
1033
|
|
|
1021
1034
|
```bash
|
|
1022
1035
|
# From this checkout, after npm run build:
|
|
@@ -1090,8 +1103,8 @@ suite - it forwards to the local `node_modules/.bin/playwright` (falling back to
|
|
|
1090
1103
|
`npx playwright` if the project hasn't installed it locally yet), so `waygraph test` behaves
|
|
1091
1104
|
exactly like `playwright test`, and anything after it (`--grep`, a spec path, `--headed`, …)
|
|
1092
1105
|
passes straight through. `waygraph test ui` (or `waygraph test --ui`) launches Playwright's
|
|
1093
|
-
interactive UI Mode the same way. Scaffolded projects (`waygraph init
|
|
1094
|
-
|
|
1106
|
+
interactive UI Mode the same way. Scaffolded projects (`waygraph init`) wire this up as
|
|
1107
|
+
`npm test` / `npm run test:ui`, and ship `trace: "retain-on-failure"` plus
|
|
1095
1108
|
the `html` reporter in `playwright.config.ts`, so a failing `waygraph test` already has a
|
|
1096
1109
|
trace waiting - `waygraph test report` opens the HTML report, and
|
|
1097
1110
|
`waygraph test show-trace <trace.zip>` opens one trace directly (both forward to Playwright's
|
|
@@ -1321,7 +1334,7 @@ src/
|
|
|
1321
1334
|
index.ts public barrel
|
|
1322
1335
|
examples/saucedemo/ live Sauce Demo (Page + methods/ + Sel)
|
|
1323
1336
|
templates/quickstart/ try demo / init template (mirrors sauce)
|
|
1324
|
-
templates/scaffold/ offline
|
|
1337
|
+
templates/scaffold/ offline waygraph init scaffold template
|
|
1325
1338
|
templates/agents/ waygraph agent-dive coding-agent definitions
|
|
1326
1339
|
docs/ GitHub Pages static HTML + docs/proposals/ RFCs
|
|
1327
1340
|
openspec/ spec-driven planning: specs/ (current), changes/ (in-flight),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type PracticeKind = "wildcard-checkpoint" | "assert-no-type-arg" | "multi-input" | "combined-action";
|
|
1
|
+
export type PracticeKind = "wildcard-checkpoint" | "assert-no-type-arg" | "multi-input" | "combined-action" | "empty-verify";
|
|
2
2
|
export interface PracticeWarning {
|
|
3
3
|
kind: PracticeKind;
|
|
4
4
|
file: string;
|
package/dist/practices-check.js
CHANGED
|
@@ -9,6 +9,19 @@ import { relative } from "node:path";
|
|
|
9
9
|
const WILDCARD_CHECKPOINT = /\bdefine(?:Method|Effect|Page|Nav|MemNav|NavClick|Action)Block\s*<[^>]*\bCheckpoint\s*<\s*string\s*>/;
|
|
10
10
|
/** defineAssertBlock({ … }) with no explicit Out type — defaults to wildcard. */
|
|
11
11
|
const ASSERT_NO_TYPE_ARG = /\bdefineAssertBlock\s*\(\s*\{/;
|
|
12
|
+
/** defineAssertBlock, any form - used to scope the empty-verify check below. */
|
|
13
|
+
const IS_ASSERT_BLOCK = /\bdefineAssertBlock\s*[<(]/;
|
|
14
|
+
/**
|
|
15
|
+
* define(Method|Effect)Block<In, Out> with two BARE identifier type args
|
|
16
|
+
* (never a nested generic like Checkpoint<string> - that's WILDCARD_CHECKPOINT's
|
|
17
|
+
* own warning) - lets a real transition (In !== Out) be told apart from a
|
|
18
|
+
* self-loop (In === Out, e.g. fill-username) using only source text.
|
|
19
|
+
*/
|
|
20
|
+
const METHOD_EFFECT_GENERIC = /\bdefine(?:Method|Effect)Block\s*<\s*([A-Za-z_$][\w$]*)\s*,\s*([A-Za-z_$][\w$]*)\s*>/;
|
|
21
|
+
/** `verify: []` - a literal empty array, the codegen-stub shape this check exists for. */
|
|
22
|
+
const EMPTY_VERIFY_ARRAY = /\bverify\s*:\s*\[\s*\]/;
|
|
23
|
+
/** Any `verify:` key at all, empty or not. */
|
|
24
|
+
const HAS_VERIFY_KEY = /\bverify\s*:/;
|
|
12
25
|
const SCAN_GLOB = /\.(block|flow)\.ts$/;
|
|
13
26
|
const METHOD_OR_EFFECT_FILE = /\.(method|effect)\.block\.ts$/;
|
|
14
27
|
const METHOD_OR_EFFECT_DEFINE = /\bdefine(?:Method|Effect)Block\b/;
|
|
@@ -80,6 +93,27 @@ export function collectPracticeWarnings(projectDir, walkDir, opts) {
|
|
|
80
93
|
detail: "Method/Effect act() mixes .fill() and .click() — fill and submit must be separate Blocks (see examples/saucedemo login split)",
|
|
81
94
|
});
|
|
82
95
|
}
|
|
96
|
+
const genericMatch = METHOD_EFFECT_GENERIC.exec(src);
|
|
97
|
+
const isTransition = !!genericMatch && genericMatch[1] !== genericMatch[2];
|
|
98
|
+
if (isTransition &&
|
|
99
|
+
!isIgnored("empty-verify", ignore) &&
|
|
100
|
+
(!HAS_VERIFY_KEY.test(src) || EMPTY_VERIFY_ARRAY.test(src))) {
|
|
101
|
+
warnings.push({
|
|
102
|
+
kind: "empty-verify",
|
|
103
|
+
file: rel,
|
|
104
|
+
detail: `transition Block (${genericMatch[1]} → ${genericMatch[2]}) has no verify checks — resolve() moving ` +
|
|
105
|
+
"to a new Checkpoint is never confirmed by anything; add a Trait (or defineAssertBlock right after it), " +
|
|
106
|
+
"or opt out explicitly with // waygraph-ignore: empty-verify if that's intentional",
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (!isIgnored("empty-verify", ignore) && IS_ASSERT_BLOCK.test(src) && EMPTY_VERIFY_ARRAY.test(src)) {
|
|
111
|
+
warnings.push({
|
|
112
|
+
kind: "empty-verify",
|
|
113
|
+
file: rel,
|
|
114
|
+
detail: "defineAssertBlock's verify array is empty — an assert Block whose only job is checking will pass " +
|
|
115
|
+
"trivially forever; fill in real Traits or remove the stub",
|
|
116
|
+
});
|
|
83
117
|
}
|
|
84
118
|
}
|
|
85
119
|
return warnings;
|
|
@@ -94,6 +128,8 @@ export function practiceKindLabel(kind) {
|
|
|
94
128
|
return "multiple inputs in one Block";
|
|
95
129
|
case "combined-action":
|
|
96
130
|
return "fill and click in one Block";
|
|
131
|
+
case "empty-verify":
|
|
132
|
+
return "empty verify — transition unconfirmed";
|
|
97
133
|
default: {
|
|
98
134
|
const _exhaustive = kind;
|
|
99
135
|
return _exhaustive;
|
|
File without changes
|
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// waygraph-ignore: empty-verify (confirmed by AssertEmailContentBlock right after it in mail-verify.flow.ts)
|
|
1
2
|
import { defineMethodBlock, checkpoint } from "waygraph";
|
|
2
3
|
import type { MailpitInbox, MailpitMessageOpen } from "../../../../states/demo.states.js";
|
|
3
4
|
import { ExpectedRecipient } from "../../../../states/demo.mem-keys.js";
|
|
@@ -24,9 +24,9 @@ against a live site, use `--skill-pilot-blind`.
|
|
|
24
24
|
an explicit type argument when it sits between two specifically-typed Blocks in a Flow.
|
|
25
25
|
Not just static content or an action's result - it also names a *feature state* worth a
|
|
26
26
|
Checkpoint of its own (a submit button greyed out until required fields are filled, a
|
|
27
|
-
field error under one input, a stale "Save" re-enabling).
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
field error under one input, a stale "Save" re-enabling). `Trait.disabled(selector)` /
|
|
28
|
+
`Trait.enabled(selector)` cover that directly; write a custom Trait only for a state
|
|
29
|
+
condition neither one expresses.
|
|
30
30
|
5. **`requires` = externally supplied.** A key an earlier Block in the same chain produces
|
|
31
31
|
is never listed under `requires` - preflight checks the whole chain up front.
|
|
32
32
|
6. **Keep Checkpoints typed — never `Checkpoint<string>`.** Block helpers take concrete
|
|
@@ -37,6 +37,16 @@ against a live site, use `--skill-pilot-blind`.
|
|
|
37
37
|
7. **One input/action per Method Block.** No block that `.fill()`s two fields or `.fill()` + `.click()` in one
|
|
38
38
|
`act()` — split like saucedemo login (`fill-username`, `fill-password`, `submit-login`). Opt out per file:
|
|
39
39
|
`// waygraph-ignore: multi-input` or `// waygraph-ignore-practices`.
|
|
40
|
+
8. **A transition never ships with an empty `verify`.** A framework can enforce that a check
|
|
41
|
+
*exists*; it can't author the semantic content of one - only whoever knows what "success"
|
|
42
|
+
means for this app can write it. That's the right line to draw, but it means an unfilled
|
|
43
|
+
`verify: []` placeholder (codegen's honest way of not guessing) is indistinguishable from
|
|
44
|
+
a Block that was never given real verification at all, and it passes `check`/`typecheck`/
|
|
45
|
+
the orphan scan/`tsc` silently unless something is actually looking for it. Something is:
|
|
46
|
+
`defineMethodBlock`/`defineEffectBlock` where `In`/`Out` genuinely differ (a transition,
|
|
47
|
+
not a self-loop) needs a non-empty `verify`, same for `defineAssertBlock`. Opt out only
|
|
48
|
+
when a *different* Block right after it in the `.flow.ts` is what actually confirms the
|
|
49
|
+
transition (e.g. an `AssertXBlock`) - `// waygraph-ignore: empty-verify`.
|
|
40
50
|
|
|
41
51
|
## Block kinds (file convention)
|
|
42
52
|
|