yam-flow 2.1.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +2 -1
- package/CHANGELOG.md +14 -0
- package/COMMANDS.md +9 -4
- package/README.md +10 -6
- package/dist/bin/yam.js +209 -29
- package/dist/lib/trust-kernel.d.ts +31 -1
- package/dist/lib/trust-kernel.js +128 -6
- package/package.json +2 -1
- package/references/final-report.md +5 -3
- package/references/study-note.md +22 -6
- package/references/ueye-proof.md +42 -1
- package/references/ueye.md +29 -3
- package/skills/deep/SKILL.md +3 -2
- package/skills/mission/SKILL.md +3 -2
- package/skills/quick/SKILL.md +3 -2
- package/skills/ueye/SKILL.md +3 -2
- package/src/bin/yam.ts +215 -30
- package/src/lib/trust-kernel.ts +155 -7
- package/templates/yam.project.md +2 -1
- package/yam.manifest.json +3 -2
package/AGENTS.md
CHANGED
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
14. For UI work, inspect real states and responsive behavior when feasible.
|
|
17
17
|
15. For long-running processes, do not claim cleanup unless process exit is checked.
|
|
18
18
|
16. When code, config, release metadata, documentation, or project artifacts changed, include a Study Note even if no yam skill was explicitly invoked.
|
|
19
|
-
17. Explain useful change insight for non-specialists: what the touched code or artifact does, what role it has, what was wrong or missing, what changed, what behavior is expected, one useful syntax/structure insight, what was verified, and what remains uncertain.
|
|
19
|
+
17. Explain useful change insight for non-specialists: what the touched code or artifact does, what role it has, where it runs or is read, what was wrong or missing, what changed before/after, what behavior is expected, one useful syntax/structure insight, what was verified, and what remains uncertain.
|
|
20
20
|
18. Use external references deliberately, preserve source clarity in research/proof notes, and rework good ideas into yam style.
|
|
21
21
|
19. Treat security as the first project lens: identify sensitive surfaces early and guide safer defaults before convenience.
|
|
22
22
|
20. Keep final reports short and concrete, but always include remaining tasks or state that none are meaningful.
|
|
23
|
+
21. When relevant, include architecture hygiene in the Study Note: avoid dumping unrelated logic into `page.tsx`, one-off component CSS into `global.css`, or structured product data into broad DB `jsonb` blobs when existing project boundaries, scoped styles, typed tables, constraints, or indexes fit better.
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to yam-flow are documented here.
|
|
4
4
|
|
|
5
|
+
## v2.2.0 - 2026-07-07
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Added `yam study-note check` as a read-only Study Note Guard Lite for changed files and supplied final-report text.
|
|
10
|
+
- Added an opt-in `study-note` hook profile via `yam hook enable study-note --global` for prompt-time Study Note reminders without auto-generating or editing reports.
|
|
11
|
+
- Extended `yam loop report --json` with resume-ready handoff fields: touched/read/verified files, skipped checks, stop condition, resume hint, and readiness state.
|
|
12
|
+
- Added Ueye deep visual review fields for acceptance criteria, touched/read/verified files, skipped checks, residual risks, stop condition, resume hint, design-system evidence, implementation evidence, and state matrix.
|
|
13
|
+
|
|
14
|
+
### Improved
|
|
15
|
+
|
|
16
|
+
- Strengthened Study Note v3 guidance for non-developer learning with execution point, before/after behavior, expected behavior, and architecture hygiene checks for `page.tsx`, `global.css`, and DB `jsonb` boundaries.
|
|
17
|
+
- Strengthened Ueye guidance so serious UI work can carry Deep-grade verification inside the Ueye route without requiring a separate Deep route.
|
|
18
|
+
|
|
5
19
|
## v2.1.0 - 2026-06-30
|
|
6
20
|
|
|
7
21
|
### Added
|
package/COMMANDS.md
CHANGED
|
@@ -45,7 +45,7 @@ Opt-in visual evidence helpers:
|
|
|
45
45
|
yam ueye preflight /path/to/project --json
|
|
46
46
|
yam ueye capture --url http://localhost:3000 --out .yam/screens/home.png
|
|
47
47
|
yam ueye compare --reference ./reference.png --actual .yam/screens/home.png
|
|
48
|
-
yam ueye report --reference ./reference.png --actual .yam/screens/home.png --preflight-id ueye-preflight-123 --p0-risk "mobile CTA may clip" --quality-gate-note "check CTA contrast before done" --brief-dimension "primary CTA clarity" --constraint "mobile first" --review-session-id pricing-card-v1 --provider-context local --execution-surface in-app-browser --browser-surface in-app-browser --similar "overall hierarchy" --different "button glow intensity" --missing "mobile state" --design-quality needs-polish --json
|
|
48
|
+
yam ueye report --reference ./reference.png --actual .yam/screens/home.png --preflight-id ueye-preflight-123 --p0-risk "mobile CTA may clip" --quality-gate-note "check CTA contrast before done" --brief-dimension "primary CTA clarity" --constraint "mobile first" --acceptance-criterion "primary CTA remains visible on mobile" --design-system-evidence "uses existing button token" --implementation-evidence "browser screenshot reviewed" --state-check default:pass --state-check mobile:partial --skipped-check "hover state not checked on touch viewport" --residual-risk "tablet breakpoint still needs visual pass" --stop-condition "stop after primary states are checked and residual risk is recorded" --resume-hint "capture tablet screenshot next" --review-session-id pricing-card-v1 --provider-context local --execution-surface in-app-browser --browser-surface in-app-browser --similar "overall hierarchy" --different "button glow intensity" --missing "mobile state" --design-quality needs-polish --json
|
|
49
49
|
yam ueye report --reference ./reference.png --actual .yam/screens/home.png --completion-claim done --design-quality pass --direction-locked --reference-read --states-checked --mobile-checked --contrast-checked --cta-checked --json
|
|
50
50
|
yam media proof --requested --attempted --output ./generated.png --wait-loop --json
|
|
51
51
|
yam proof --route ueye --truth partial --visual "browser/local screenshot comparison executed" --require-visual
|
|
@@ -148,7 +148,8 @@ yam tools doctor /path/to/project
|
|
|
148
148
|
yam tools doctor /path/to/project --json
|
|
149
149
|
yam context pressure /path/to/project --json
|
|
150
150
|
yam cleanup scan /path/to/project --json
|
|
151
|
-
yam
|
|
151
|
+
yam study-note check /path/to/project --text "Study Note: Touched code role before/after verification limits." --json
|
|
152
|
+
yam loop report --route quick --intent "fix release readiness" --stage "inspect:passed:read release report" --evidence "typecheck passed" --evidence-level local --evidence-stamp "sha256:release-report" --touched-file src/bin/yam.ts --read-file README.md --verified-file scripts/cli-smoke.mjs --skipped-check "npm publish skipped by design" --stop-condition "stop after readiness evidence is recorded" --resume-hint "rerun release report after npm auth refresh" --readiness-state blocked --covered-requirement "release report is read-only" --uncovered-requirement "npm auth verified" --blocked-kind auth_blocked --failure-cause auth_token_invalid --safe-retry "retry after npm whoami succeeds" --recovery-hint "refresh npm auth, then rerun readiness checks" --fix-first-item "npm auth must be verified before publish" --remaining-task "rerun release report after auth refresh" --recommended-direction "fix npm auth first, then publish manually" --implementation-note "keep loop report read-only" --why-this-next "auth blocks public release claims" --blocked-by "npm whoami E401" --owner-route deep --owner-scope "release readiness only" --scope-owner deep --side-effect "no publish attempted" --avoidance-note "do not retry publish before npm auth is proven" --issue-code "src/bin/yam.ts release report" --issue-role "summarizes release readiness without publishing" --issue-symptom "npm auth failure needs clearer next action" --changed-code "yam loop report" --changed-role "records loop evidence and learning note" --change-summary "added a read-only loop artifact" --why-important "it helps users learn what changed without overclaiming verification" --learning-note "fix blockers before claiming done" --json
|
|
152
153
|
yam proof /path/to/project
|
|
153
154
|
yam proof --route deep --truth verified --command "npm run build: pass"
|
|
154
155
|
yam proof --route ueye --truth verified --visual "reference image only"
|
|
@@ -196,12 +197,14 @@ Supported report shapes:
|
|
|
196
197
|
- Runtime evidence mini: command/process, observation, cleanup, truth status, next action.
|
|
197
198
|
- Patch queue lite: mission lane status, changed files, verification hint, rollback hint, truth status.
|
|
198
199
|
- Verification Ladder: L0 stated, L1 inspected, L2 local check, L3 integrated, L4 release/runtime/visual proof, L5 bounded deep with stop condition and skipped/remaining work.
|
|
199
|
-
- Loop report: intent, guided stage outcomes, evidence level/stamp, blockers, blocker kind, safe retry, next action, fix-first items, remaining tasks, recommended direction, blocked-by notes, owner route/scope, side effects, and study note.
|
|
200
|
-
- Study note:
|
|
200
|
+
- Loop report: intent, guided stage outcomes, touched/read/verified files, skipped checks, stop condition, resume hint, readiness state, evidence level/stamp, blockers, blocker kind, safe retry, next action, fix-first items, remaining tasks, recommended direction, blocked-by notes, owner route/scope, side effects, and study note.
|
|
201
|
+
- Study note: non-specialist explanation of the changed code/artifact, its role, execution point, before/after behavior, expected behavior, one syntax/structure insight, verification, uncertainty, and architecture hygiene around `page.tsx`, `global.css`, and DB `jsonb`.
|
|
202
|
+
- Study Note guard: read-only check for changed files and supplied final-report text; opt into prompt-time reminders with `yam hook enable study-note --global`.
|
|
201
203
|
- Benchmark optimization loop lite: baseline, one change, rerun, keep/revert decision.
|
|
202
204
|
- Structured diagnostic next action: severity, evidence, owner route, next action, truth status.
|
|
203
205
|
- Ueye continuity/comparison: previous report, current report, comparison delta, design quality, next action.
|
|
204
206
|
- Ueye design brief/anti-slop: brief dimensions, constraints, invented metrics, placeholder copy, generic visuals, and custom P0 blockers.
|
|
207
|
+
- Ueye deep visual review: acceptance criteria, touched/read/verified files, skipped checks, residual risks, stop condition, resume hint, design-system evidence, implementation evidence, and state matrix.
|
|
205
208
|
- Context pressure: project pack age/size, memory summary, dirty scope, scripts, instruction surfaces, and route hint.
|
|
206
209
|
- Cleanup scan: advisory-only list of confusing surfaces with destructive=false.
|
|
207
210
|
|
|
@@ -212,5 +215,7 @@ Advisory-only hook. It does not run checks or force routes.
|
|
|
212
215
|
```bash
|
|
213
216
|
yam hook status --global
|
|
214
217
|
yam hook enable lite --global
|
|
218
|
+
yam hook enable study-note --global
|
|
215
219
|
yam hook disable lite --global
|
|
220
|
+
yam hook disable study-note --global
|
|
216
221
|
```
|
package/README.md
CHANGED
|
@@ -134,6 +134,7 @@ yam tools doctor /path/to/project
|
|
|
134
134
|
yam tools doctor /path/to/project --json
|
|
135
135
|
yam context pressure /path/to/project --json
|
|
136
136
|
yam cleanup scan /path/to/project --json
|
|
137
|
+
yam study-note check /path/to/project --text "Study Note: ..." --json
|
|
137
138
|
yam proof /path/to/project
|
|
138
139
|
yam proof write /path/to/project --route quick --truth verified --command "npm run verify:self: pass"
|
|
139
140
|
yam proof --route ueye --truth verified --visual "reference image only"
|
|
@@ -141,17 +142,18 @@ yam proof --route ueye --truth partial --visual-provenance '{"source_kind":"refe
|
|
|
141
142
|
yam ueye capture --url http://localhost:3000 --out .yam/screens/home.png
|
|
142
143
|
yam ueye compare --reference ./reference.png --actual .yam/screens/home.png
|
|
143
144
|
yam ueye preflight /path/to/project --json
|
|
144
|
-
yam ueye report --reference ./reference.png --actual .yam/screens/home.png --preflight-id ueye-preflight-123 --p0-risk "mobile CTA may clip" --quality-gate-note "check CTA contrast before done" --completion-claim done --design-quality pass --direction-locked --reference-read --states-checked --mobile-checked --contrast-checked --cta-checked --provider-context local --execution-surface in-app-browser --app-surface codex-app --browser-surface in-app-browser --preserved-state --json
|
|
145
|
+
yam ueye report --reference ./reference.png --actual .yam/screens/home.png --preflight-id ueye-preflight-123 --p0-risk "mobile CTA may clip" --quality-gate-note "check CTA contrast before done" --acceptance-criterion "primary CTA remains visible on mobile" --state-check default:pass --state-check mobile:partial --implementation-evidence "browser screenshot reviewed" --completion-claim done --design-quality pass --direction-locked --reference-read --states-checked --mobile-checked --contrast-checked --cta-checked --provider-context local --execution-surface in-app-browser --app-surface codex-app --browser-surface in-app-browser --preserved-state --json
|
|
145
146
|
yam proof --route ueye --truth verified --visual "implementation screenshot evidence recorded" --design-completion '{"completion_claim":"done","has_implementation_screenshot":true,"design_quality":"pass","states_checked":true,"mobile_checked":true,"contrast_checked":true,"cta_checked":true,"direction_locked":true,"truth_status":"verified"}'
|
|
146
147
|
yam media proof --requested --attempted --output ./generated.png --wait-loop --json
|
|
147
148
|
yam proof --route mission --mission-envelope '{"agent_id":"implementer","assigned_scope":"target component","changed_files":["src/file.ts"],"verification_hint":"npm run typecheck","truth_status":"partial"}'
|
|
148
|
-
yam loop report --route quick --intent "fix release readiness" --stage "inspect:passed:read release report" --evidence "typecheck passed" --evidence-level local --evidence-stamp "sha256:release-report" --covered-requirement "release report is read-only" --uncovered-requirement "npm auth verified" --blocked-kind auth_blocked --failure-cause auth_token_invalid --safe-retry "retry after npm whoami succeeds" --recovery-hint "refresh npm auth, then rerun readiness checks" --fix-first-item "npm auth must be verified before publish" --remaining-task "rerun release report after auth refresh" --recommended-direction "fix npm auth first, then publish manually" --implementation-note "keep loop report read-only" --why-this-next "auth blocks public release claims" --blocked-by "npm whoami E401" --owner-route deep --owner-scope "release readiness only" --scope-owner deep --side-effect "no publish attempted" --avoidance-note "do not retry publish before npm auth is proven" --issue-code "src/bin/yam.ts release report" --issue-role "summarizes release readiness without publishing" --issue-symptom "npm auth failure needs clearer next action" --changed-code "yam loop report" --changed-role "records loop evidence and learning note" --change-summary "added a read-only loop artifact" --why-important "it helps users learn what changed without overclaiming verification" --learning-note "fix blockers before claiming done" --json
|
|
149
|
+
yam loop report --route quick --intent "fix release readiness" --stage "inspect:passed:read release report" --evidence "typecheck passed" --evidence-level local --evidence-stamp "sha256:release-report" --touched-file src/bin/yam.ts --read-file README.md --verified-file scripts/cli-smoke.mjs --skipped-check "npm publish skipped by design" --stop-condition "stop after readiness evidence is recorded" --resume-hint "rerun release report after npm auth refresh" --readiness-state blocked --covered-requirement "release report is read-only" --uncovered-requirement "npm auth verified" --blocked-kind auth_blocked --failure-cause auth_token_invalid --safe-retry "retry after npm whoami succeeds" --recovery-hint "refresh npm auth, then rerun readiness checks" --fix-first-item "npm auth must be verified before publish" --remaining-task "rerun release report after auth refresh" --recommended-direction "fix npm auth first, then publish manually" --implementation-note "keep loop report read-only" --why-this-next "auth blocks public release claims" --blocked-by "npm whoami E401" --owner-route deep --owner-scope "release readiness only" --scope-owner deep --side-effect "no publish attempted" --avoidance-note "do not retry publish before npm auth is proven" --issue-code "src/bin/yam.ts release report" --issue-role "summarizes release readiness without publishing" --issue-symptom "npm auth failure needs clearer next action" --changed-code "yam loop report" --changed-role "records loop evidence and learning note" --change-summary "added a read-only loop artifact" --why-important "it helps users learn what changed without overclaiming verification" --learning-note "fix blockers before claiming done" --json
|
|
149
150
|
yam release report --json
|
|
150
151
|
yam safety "supabase db reset"
|
|
151
152
|
yam detect /path/to/project
|
|
152
153
|
yam pack /path/to/project
|
|
153
154
|
yam hook status --global
|
|
154
155
|
yam hook enable lite --global
|
|
156
|
+
yam hook enable study-note --global
|
|
155
157
|
yam hook disable lite --global
|
|
156
158
|
yam budget ueye
|
|
157
159
|
yam measure ueye --files 5 --commands 2 --report-lines 12 --seconds 180
|
|
@@ -220,8 +222,9 @@ These shapes keep reports machine-readable without turning normal work into a he
|
|
|
220
222
|
- Patch queue lite: `$mission` lane records with pending/applied/verified/reverted/blocked state, changed files, verification hint, rollback hint, truth status, and next action.
|
|
221
223
|
- Verification Ladder: L0 stated, L1 inspected, L2 local check, L3 integrated, L4 release/runtime/visual proof, and L5 bounded deep. Heavier claims require heavier evidence, but stop conditions prevent endless proof loops.
|
|
222
224
|
- Release report JSON: `yam release report --json` summarizes typecheck, forbidden-name scan, package boundary, registry status, CLI smoke, dist freshness, diagnostics, readiness receipt, and final truth status.
|
|
223
|
-
- Loop report JSON: `yam loop report --json` records a read-only handoff artifact: guided stages, requirement coverage, evidence level/stamp, blocker kind, failure cause, safe retry, recovery hint, owner route/scope, side effects, next action, fix-first items, remaining tasks, recommended direction, implementation notes, blocked-by notes, avoidance note, tool intent, truth status, and study note.
|
|
224
|
-
- Study note: `yam.study-note.v1` and `references/study-note.md` keep non-specialist explanations for what code/artifact changed, what role it plays, what
|
|
225
|
+
- Loop report JSON: `yam loop report --json` records a read-only handoff artifact: guided stages, touched/read/verified files, skipped checks, stop condition, resume hint, readiness state, requirement coverage, evidence level/stamp, blocker kind, failure cause, safe retry, recovery hint, owner route/scope, side effects, next action, fix-first items, remaining tasks, recommended direction, implementation notes, blocked-by notes, avoidance note, tool intent, truth status, and study note.
|
|
226
|
+
- Study note: `yam.study-note.v1` and `references/study-note.md` keep non-specialist explanations for what code/artifact changed, what role it plays, where it runs, what changed from before to after, what behavior is expected, one syntax/structure insight, what was verified, and what remains uncertain. Missing details stay in `limits` instead of being guessed. Study Note v3 also asks whether work was dumped into `page.tsx`, `global.css`, or broad DB `jsonb` when a smaller component, style module/token, typed column, relation, or validation schema would teach and scale better.
|
|
227
|
+
- Study Note guard: `yam study-note check` is a read-only missing-note guard. It checks changed files against supplied final-report text and can be used directly or through the opt-in `yam hook enable study-note --global` advisory hook.
|
|
225
228
|
- Avoidance note: loop reports may include one short mistake-to-avoid note, but durable memory stays explicit through `yam memory add`; `yam loop report` does not write `.yam/memory`.
|
|
226
229
|
- Publish blocker evidence: release reports classify common npm auth, permission, OTP, immutable-version, cache, registry, and tarball failures into safe next actions.
|
|
227
230
|
- Publish readiness evidence: release reports run read-only registry/auth/version probes, redact account/token details, keep npm publish outside the report, and include a `yam.release-readiness-receipt.v1` basis for the readiness judgment.
|
|
@@ -233,6 +236,7 @@ These shapes keep reports machine-readable without turning normal work into a he
|
|
|
233
236
|
- Ueye surface context: `$ueye` run reports can record provider context, provider badge, execution surface, app surface, browser surface, control mode, preserved URL/state, and evidence id.
|
|
234
237
|
- Ueye design completion gate: `$ueye` can stay fast for draft work, but a `done` claim is capped until implementation evidence, comparison/design-quality status, P0/P1 status, key states, mobile/responsive behavior, contrast/accessibility visuals, CTA affordance, and direction/reference-read proof are recorded when relevant.
|
|
235
238
|
- Ueye design brief and anti-slop review: `$ueye` reports can record operator-provided brief dimensions, constraints, invented metrics, placeholder copy, generic visuals, and custom anti-slop blockers. P0 anti-slop findings block `done` claims.
|
|
239
|
+
- Ueye deep visual review: `$ueye` can record acceptance criteria, touched/read/verified files, skipped checks, residual risks, stop condition, resume hint, design-system evidence, implementation evidence, and a state matrix so serious UI work can carry Deep-grade verification without leaving the Ueye route.
|
|
236
240
|
|
|
237
241
|
## Ueye Capture And Compare
|
|
238
242
|
|
|
@@ -242,14 +246,14 @@ These shapes keep reports machine-readable without turning normal work into a he
|
|
|
242
246
|
yam ueye capture --url http://localhost:3000 --out .yam/screens/home.png
|
|
243
247
|
yam ueye compare --reference ./reference.png --actual .yam/screens/home.png --json
|
|
244
248
|
yam ueye preflight . --json
|
|
245
|
-
yam ueye report --reference ./reference.png --actual .yam/screens/home.png --brief-dimension "primary CTA clarity" --constraint "mobile first" --anti-slop "placeholder copy remains" --completion-claim done --design-quality pass --direction-locked --reference-read --states-checked --mobile-checked --contrast-checked --cta-checked --provider-context local --execution-surface in-app-browser --browser-surface in-app-browser --preserved-state --json
|
|
249
|
+
yam ueye report --reference ./reference.png --actual .yam/screens/home.png --brief-dimension "primary CTA clarity" --constraint "mobile first" --anti-slop "placeholder copy remains" --acceptance-criterion "pricing card CTA remains visible on mobile" --design-system-evidence "uses existing button token" --implementation-evidence "browser screenshot reviewed" --state-check default:pass --state-check mobile:partial --skipped-check "hover state not checked on touch viewport" --residual-risk "tablet breakpoint still needs visual pass" --stop-condition "stop after primary states are checked and residual risk is recorded" --resume-hint "capture tablet screenshot next" --completion-claim done --design-quality pass --direction-locked --reference-read --states-checked --mobile-checked --contrast-checked --cta-checked --provider-context local --execution-surface in-app-browser --browser-surface in-app-browser --preserved-state --json
|
|
246
250
|
```
|
|
247
251
|
|
|
248
252
|
`capture` uses a Playwright install from the current project when present, then falls back to the package context. It does not install browsers or add runtime dependencies by itself. If capture is unavailable, the visual claim stays `partial` or `blocked` until a real screenshot is supplied.
|
|
249
253
|
|
|
250
254
|
`compare` is local-only and dependency-free. It records file hashes, dimensions, comparison result, and proof-ready visual provenance. Exact image matches can be `verified`; different screenshots stay `partial` so visual parity is not overclaimed.
|
|
251
255
|
|
|
252
|
-
`report` gathers reference sources, implementation screenshots, comparison result, continuity fields, design quality judgment, design completion gate, surface context, and next action into one compact proof-ready JSON object. Draft and needs-polish work can stay fast; `--completion-claim done` turns on the stricter design gate.
|
|
256
|
+
`report` gathers reference sources, implementation screenshots, comparison result, continuity fields, design quality judgment, design completion gate, deep visual review, surface context, and next action into one compact proof-ready JSON object. Draft and needs-polish work can stay fast; `--completion-claim done` turns on the stricter design gate.
|
|
253
257
|
|
|
254
258
|
`preflight` does not claim visual verification. It is a pre-work checklist for reference source, target states, mobile/responsive needs, CTA/contrast/accessibility risk, screenshot availability, and likely P0/P1 candidates.
|
|
255
259
|
|
package/dist/bin/yam.js
CHANGED
|
@@ -50,6 +50,7 @@ const PROJECT_PACK = 'yam.project.md';
|
|
|
50
50
|
const LEGACY_PROJECT_PACK = 'timeto.project.md';
|
|
51
51
|
const PACK_STALE_DAYS = 30;
|
|
52
52
|
const YAM_LITE_HOOK_COMMAND = `node ${path.join(ROOT, 'dist', 'bin', 'yam.js')} hook run lite`;
|
|
53
|
+
const YAM_STUDY_NOTE_HOOK_COMMAND = `node ${path.join(ROOT, 'dist', 'bin', 'yam.js')} hook run study-note`;
|
|
53
54
|
const REQUIRED_PACK_SECTIONS = [
|
|
54
55
|
'Product Direction',
|
|
55
56
|
'UI Direction',
|
|
@@ -122,6 +123,7 @@ Usage:
|
|
|
122
123
|
yam tools doctor [dir]
|
|
123
124
|
yam proof [dir|--from file] [--route route] [--truth status] [--command text] [--evidence text]
|
|
124
125
|
yam proof write [dir] [--format json|md] [--out file] [--route route] [--truth status] [--command text]
|
|
126
|
+
yam study-note check [dir] [--report file|--text text] [--json]
|
|
125
127
|
yam loop report [--route route] [--intent text] [--stage id:status:note] [--evidence text] [--json]
|
|
126
128
|
yam ueye capture --url URL --out screenshot.png [--viewport 1440x900] [--full-page] [--json]
|
|
127
129
|
yam ueye compare --reference ref.png --actual screenshot.png [--json]
|
|
@@ -134,7 +136,7 @@ Usage:
|
|
|
134
136
|
yam release report [--json]
|
|
135
137
|
yam safety [text...]
|
|
136
138
|
yam memory <init|add|list|summary|resolve> [dir] [options]
|
|
137
|
-
yam hook <status|enable|disable|run> [lite] [--global|--project dir]
|
|
139
|
+
yam hook <status|enable|disable|run> [lite|study-note] [--global|--project dir]
|
|
138
140
|
yam template <project|ueye|mission|proof|tuning>
|
|
139
141
|
yam tune-log [dir]
|
|
140
142
|
yam install
|
|
@@ -531,6 +533,12 @@ function normalizeLoopEvidenceLevelFlag(value = '') {
|
|
|
531
533
|
return text;
|
|
532
534
|
return 'none';
|
|
533
535
|
}
|
|
536
|
+
function normalizeReadinessStateFlag(value = '') {
|
|
537
|
+
const text = String(value || '').toLowerCase().replace(/[-\s]/g, '_');
|
|
538
|
+
if (['usable', 'degraded', 'blocked', 'unknown'].includes(text))
|
|
539
|
+
return text;
|
|
540
|
+
return 'unknown';
|
|
541
|
+
}
|
|
534
542
|
function uniqueNextActionDetails(actions = []) {
|
|
535
543
|
const seen = new Set();
|
|
536
544
|
const unique = [];
|
|
@@ -708,6 +716,124 @@ async function cleanup(args = []) {
|
|
|
708
716
|
console.error(`unknown cleanup command: ${subcommand}`);
|
|
709
717
|
return cleanupUsage();
|
|
710
718
|
}
|
|
719
|
+
async function studyNote(args = []) {
|
|
720
|
+
const subcommand = args[0] || 'help';
|
|
721
|
+
if (subcommand === 'help' || subcommand === '--help' || subcommand === '-h')
|
|
722
|
+
return studyNoteUsage();
|
|
723
|
+
if (subcommand === 'check')
|
|
724
|
+
return studyNoteCheck(args.slice(1));
|
|
725
|
+
console.error(`unknown study-note command: ${subcommand}`);
|
|
726
|
+
return studyNoteUsage();
|
|
727
|
+
}
|
|
728
|
+
function studyNoteUsage() {
|
|
729
|
+
console.log(`yam study-note
|
|
730
|
+
|
|
731
|
+
Usage:
|
|
732
|
+
yam study-note check [dir] [--report file|--text text] [--json]
|
|
733
|
+
|
|
734
|
+
Notes:
|
|
735
|
+
Read-only guard. It checks whether changed work has a Study Note and whether relevant UI/CSS/DB hygiene was reported.
|
|
736
|
+
It does not generate, edit, or infer the Study Note for you.
|
|
737
|
+
`);
|
|
738
|
+
}
|
|
739
|
+
async function studyNoteCheck(args = []) {
|
|
740
|
+
const flags = parseSimpleFlags(args, new Set(['report', 'text', 'json']));
|
|
741
|
+
const dir = path.resolve(firstPositional(args) || process.cwd());
|
|
742
|
+
const changedFiles = await gitChangedFiles(dir);
|
|
743
|
+
const reportText = await readStudyNoteReportText(flags, dir);
|
|
744
|
+
const needsStudyNote = changedFiles.length > 0;
|
|
745
|
+
const hygieneRequirements = studyNoteHygieneRequirements(changedFiles);
|
|
746
|
+
const checks = [
|
|
747
|
+
studyNoteGuardCheck('changed_files', needsStudyNote ? 'pass' : 'skipped', needsStudyNote ? 'changed files detected; Study Note is required before final completion' : 'no changed files detected'),
|
|
748
|
+
studyNoteGuardCheck('study_note_present', !needsStudyNote || hasStudyNoteMarker(reportText) ? 'pass' : 'fail', 'final report should include a Study Note when project artifacts changed'),
|
|
749
|
+
studyNoteGuardCheck('role_or_responsibility', !needsStudyNote || /(\brole\b|\bresponsib|\bdoes\b|역할|기능)/i.test(reportText) ? 'pass' : 'fail', 'Study Note should explain what the touched code/artifact does'),
|
|
750
|
+
studyNoteGuardCheck('before_after_or_change', !needsStudyNote || /(\bbefore\b|\bafter\b|before\/after|changed|change meaning|바뀌|변경|수정)/i.test(reportText) ? 'pass' : 'fail', 'Study Note should explain what changed from before to after'),
|
|
751
|
+
studyNoteGuardCheck('verification_or_limits', !needsStudyNote || /(verification|verified|checked|limits|uncertain|검증|확인|한계|모르는)/i.test(reportText) ? 'pass' : 'fail', 'Study Note should say what was checked and what remains uncertain')
|
|
752
|
+
];
|
|
753
|
+
for (const requirement of hygieneRequirements) {
|
|
754
|
+
checks.push(studyNoteGuardCheck(requirement.id, requirementSatisfied(reportText, requirement), requirement.note));
|
|
755
|
+
}
|
|
756
|
+
const blockers = checks.filter((check) => check.status === 'fail').map((check) => `${check.id}: ${check.next_action}`);
|
|
757
|
+
const result = {
|
|
758
|
+
schema: 'yam.study-note-guard.v1',
|
|
759
|
+
generated_at: new Date().toISOString(),
|
|
760
|
+
project: dir,
|
|
761
|
+
changed_files: changedFiles,
|
|
762
|
+
changed_file_count: changedFiles.length,
|
|
763
|
+
report_source: flags.report ? path.resolve(dir, String(flags.report)) : flags.text ? 'inline_text' : 'not_provided',
|
|
764
|
+
checks,
|
|
765
|
+
blockers,
|
|
766
|
+
next_action: blockers[0] || (needsStudyNote ? 'Study Note guard passed for the supplied report text' : 'no Study Note required because no changed files were detected'),
|
|
767
|
+
truth_status: blockers.length ? 'blocked' : needsStudyNote ? 'verified' : 'skipped'
|
|
768
|
+
};
|
|
769
|
+
printJsonOrHuman(result, Boolean(flags.json), 'Study Note guard');
|
|
770
|
+
if (blockers.length)
|
|
771
|
+
process.exitCode = 1;
|
|
772
|
+
}
|
|
773
|
+
function firstPositional(args = []) {
|
|
774
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
775
|
+
const arg = String(args[index] || '');
|
|
776
|
+
if (arg.startsWith('--')) {
|
|
777
|
+
if (!arg.includes('=') && !['--json'].includes(arg))
|
|
778
|
+
index += 1;
|
|
779
|
+
continue;
|
|
780
|
+
}
|
|
781
|
+
if (arg === 'check')
|
|
782
|
+
continue;
|
|
783
|
+
return arg;
|
|
784
|
+
}
|
|
785
|
+
return '';
|
|
786
|
+
}
|
|
787
|
+
async function gitChangedFiles(dir) {
|
|
788
|
+
const output = runReadOnlyCommandIn(dir, 'git', ['status', '--short']);
|
|
789
|
+
return output
|
|
790
|
+
.split(/\r?\n/)
|
|
791
|
+
.filter(Boolean)
|
|
792
|
+
.map((line) => line.replace(/^..\s+/, '').replace(/^.* -> /, ''))
|
|
793
|
+
.map((line) => line.trim())
|
|
794
|
+
.filter((file) => file && !file.startsWith('dist/') && !file.endsWith('.tgz'));
|
|
795
|
+
}
|
|
796
|
+
async function readStudyNoteReportText(flags, dir) {
|
|
797
|
+
if (flags.text)
|
|
798
|
+
return String(flags.text || '');
|
|
799
|
+
if (!flags.report)
|
|
800
|
+
return '';
|
|
801
|
+
const file = path.resolve(dir, String(flags.report));
|
|
802
|
+
try {
|
|
803
|
+
return await fsp.readFile(file, 'utf8');
|
|
804
|
+
}
|
|
805
|
+
catch {
|
|
806
|
+
return '';
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
function hasStudyNoteMarker(text = '') {
|
|
810
|
+
return /(study note|study-note|학습\s*노트|스터디\s*노트)/i.test(text);
|
|
811
|
+
}
|
|
812
|
+
function studyNoteGuardCheck(id, status, nextAction) {
|
|
813
|
+
return {
|
|
814
|
+
id,
|
|
815
|
+
status,
|
|
816
|
+
next_action: nextAction,
|
|
817
|
+
truth_status: status === 'pass' ? 'verified' : status === 'fail' ? 'blocked' : status === 'skipped' ? 'skipped' : 'partial'
|
|
818
|
+
};
|
|
819
|
+
}
|
|
820
|
+
function studyNoteHygieneRequirements(files = []) {
|
|
821
|
+
const requirements = [];
|
|
822
|
+
if (files.some((file) => /(^|\/)page\.tsx$/i.test(file))) {
|
|
823
|
+
requirements.push({ id: 'page_tsx_hygiene', terms: ['page.tsx', 'component', 'hook', 'helper', 'server action', 'route'], note: 'Study Note should say whether page.tsx stayed focused or needs component/hook/helper/server-action separation' });
|
|
824
|
+
}
|
|
825
|
+
if (files.some((file) => /(^|\/)global\.css$/i.test(file))) {
|
|
826
|
+
requirements.push({ id: 'global_css_hygiene', terms: ['global.css', 'token', 'component', 'scoped', 'module', 'utility'], note: 'Study Note should say whether CSS belongs globally or should move to tokens/scoped/component styles' });
|
|
827
|
+
}
|
|
828
|
+
if (files.some((file) => /(migration|schema|db|database|sql|prisma|drizzle|supabase)/i.test(file))) {
|
|
829
|
+
requirements.push({ id: 'jsonb_hygiene', terms: ['jsonb', 'column', 'table', 'constraint', 'index', 'schema', 'relation'], note: 'Study Note should say whether structured product data belongs in typed columns/tables/constraints/indexes instead of broad DB jsonb' });
|
|
830
|
+
}
|
|
831
|
+
return requirements;
|
|
832
|
+
}
|
|
833
|
+
function requirementSatisfied(text = '', requirement) {
|
|
834
|
+
const normalized = String(text || '').toLowerCase();
|
|
835
|
+
return requirement.terms.some((term) => normalized.includes(term.toLowerCase())) ? 'pass' : 'fail';
|
|
836
|
+
}
|
|
711
837
|
function cleanupUsage() {
|
|
712
838
|
console.log(`yam cleanup
|
|
713
839
|
|
|
@@ -1271,20 +1397,20 @@ function hookUsage() {
|
|
|
1271
1397
|
|
|
1272
1398
|
Usage:
|
|
1273
1399
|
yam hook status [--global|--project dir]
|
|
1274
|
-
yam hook enable lite [--global|--project dir]
|
|
1275
|
-
yam hook disable [lite] [--global|--project dir]
|
|
1276
|
-
yam hook run lite
|
|
1400
|
+
yam hook enable <lite|study-note> [--global|--project dir]
|
|
1401
|
+
yam hook disable [lite|study-note] [--global|--project dir]
|
|
1402
|
+
yam hook run <lite|study-note>
|
|
1277
1403
|
|
|
1278
1404
|
Notes:
|
|
1279
|
-
|
|
1405
|
+
hooks are opt-in and advisory-only. They do not run tmux, subagents, or proof gates.
|
|
1280
1406
|
`);
|
|
1281
1407
|
}
|
|
1282
1408
|
function parseHookArgs(args = []) {
|
|
1283
1409
|
const result = { mode: 'project', projectDir: process.cwd(), profile: 'lite' };
|
|
1284
1410
|
for (let index = 0; index < args.length; index += 1) {
|
|
1285
1411
|
const arg = args[index];
|
|
1286
|
-
if (arg === 'lite') {
|
|
1287
|
-
result.profile =
|
|
1412
|
+
if (arg === 'lite' || arg === 'study-note') {
|
|
1413
|
+
result.profile = arg;
|
|
1288
1414
|
}
|
|
1289
1415
|
else if (arg === '--global') {
|
|
1290
1416
|
result.mode = 'global';
|
|
@@ -1309,13 +1435,19 @@ function hookPathFor(parsed) {
|
|
|
1309
1435
|
function isYamLiteHook(handler = {}) {
|
|
1310
1436
|
return handler?.type === 'command' && String(handler.command || '').includes('yam.js hook run lite');
|
|
1311
1437
|
}
|
|
1312
|
-
function
|
|
1438
|
+
function isYamStudyNoteHook(handler = {}) {
|
|
1439
|
+
return handler?.type === 'command' && String(handler.command || '').includes('yam.js hook run study-note');
|
|
1440
|
+
}
|
|
1441
|
+
function isYamHookProfile(handler = {}, profile = 'lite') {
|
|
1442
|
+
return profile === 'study-note' ? isYamStudyNoteHook(handler) : isYamLiteHook(handler);
|
|
1443
|
+
}
|
|
1444
|
+
function stripYamHooks(config = {}, profile = 'lite') {
|
|
1313
1445
|
const next = { ...config };
|
|
1314
1446
|
for (const event of Object.keys(next)) {
|
|
1315
1447
|
const entries = Array.isArray(next[event]) ? next[event] : [];
|
|
1316
1448
|
const keptEntries = [];
|
|
1317
1449
|
for (const entry of entries) {
|
|
1318
|
-
const hooks = Array.isArray(entry?.hooks) ? entry.hooks.filter((handler) => !
|
|
1450
|
+
const hooks = Array.isArray(entry?.hooks) ? entry.hooks.filter((handler) => !isYamHookProfile(handler, profile)) : [];
|
|
1319
1451
|
const rest = { ...entry, hooks };
|
|
1320
1452
|
if (hooks.length > 0)
|
|
1321
1453
|
keptEntries.push(rest);
|
|
@@ -1327,14 +1459,14 @@ function stripYamLiteHooks(config = {}) {
|
|
|
1327
1459
|
}
|
|
1328
1460
|
return next;
|
|
1329
1461
|
}
|
|
1330
|
-
function
|
|
1331
|
-
const next =
|
|
1462
|
+
function withYamHook(config = {}, profile = 'lite') {
|
|
1463
|
+
const next = stripYamHooks(config, profile);
|
|
1332
1464
|
const event = 'UserPromptSubmit';
|
|
1333
1465
|
const entry = {
|
|
1334
1466
|
hooks: [
|
|
1335
1467
|
{
|
|
1336
1468
|
type: 'command',
|
|
1337
|
-
command: YAM_LITE_HOOK_COMMAND,
|
|
1469
|
+
command: profile === 'study-note' ? YAM_STUDY_NOTE_HOOK_COMMAND : YAM_LITE_HOOK_COMMAND,
|
|
1338
1470
|
timeout: 5
|
|
1339
1471
|
}
|
|
1340
1472
|
]
|
|
@@ -1346,26 +1478,29 @@ async function hookStatus(args = []) {
|
|
|
1346
1478
|
const parsed = parseHookArgs(args);
|
|
1347
1479
|
const target = hookPathFor(parsed);
|
|
1348
1480
|
const config = await readJsonOrDefault(target, {});
|
|
1349
|
-
|
|
1350
|
-
console.log(`yam-
|
|
1481
|
+
console.log(`yam-lite hook: ${hookConfigHasProfile(config, 'lite') ? 'enabled' : 'disabled'}`);
|
|
1482
|
+
console.log(`yam-study-note hook: ${hookConfigHasProfile(config, 'study-note') ? 'enabled' : 'disabled'}`);
|
|
1351
1483
|
console.log(`scope: ${parsed.mode}`);
|
|
1352
1484
|
console.log(`file: ${target}`);
|
|
1353
1485
|
}
|
|
1354
1486
|
function hookConfigHasYamLite(config = {}) {
|
|
1487
|
+
return hookConfigHasProfile(config, 'lite');
|
|
1488
|
+
}
|
|
1489
|
+
function hookConfigHasProfile(config = {}, profile = 'lite') {
|
|
1355
1490
|
return Object.values(config).some((entries) => Array.isArray(entries) && entries.some((entry) => {
|
|
1356
|
-
return Array.isArray(entry?.hooks) && entry.hooks.some(
|
|
1491
|
+
return Array.isArray(entry?.hooks) && entry.hooks.some((handler) => isYamHookProfile(handler, profile));
|
|
1357
1492
|
}));
|
|
1358
1493
|
}
|
|
1359
1494
|
async function hookEnable(args = []) {
|
|
1360
1495
|
const parsed = parseHookArgs(args);
|
|
1361
|
-
if (parsed.profile
|
|
1362
|
-
console.error('Only
|
|
1496
|
+
if (!['lite', 'study-note'].includes(parsed.profile)) {
|
|
1497
|
+
console.error('Only lite and study-note hooks are supported: yam hook enable <lite|study-note>');
|
|
1363
1498
|
process.exitCode = 1;
|
|
1364
1499
|
return;
|
|
1365
1500
|
}
|
|
1366
1501
|
const target = hookPathFor(parsed);
|
|
1367
1502
|
const current = await readJsonOrDefault(target, {});
|
|
1368
|
-
const next =
|
|
1503
|
+
const next = withYamHook(current, parsed.profile);
|
|
1369
1504
|
await fsp.mkdir(path.dirname(target), { recursive: true });
|
|
1370
1505
|
if (await exists(target)) {
|
|
1371
1506
|
const backup = `${target}.yam-backup-${timestampId()}`;
|
|
@@ -1373,29 +1508,29 @@ async function hookEnable(args = []) {
|
|
|
1373
1508
|
console.log(`backup: ${backup}`);
|
|
1374
1509
|
}
|
|
1375
1510
|
await fsp.writeFile(target, `${JSON.stringify(next, null, 2)}\n`);
|
|
1376
|
-
console.log(`yam
|
|
1511
|
+
console.log(`yam-${parsed.profile} hook enabled (${parsed.mode}): ${target}`);
|
|
1377
1512
|
console.log('Restart Codex or start a new thread if the app does not pick up hook changes immediately.');
|
|
1378
1513
|
}
|
|
1379
1514
|
async function hookDisable(args = []) {
|
|
1380
1515
|
const parsed = parseHookArgs(args);
|
|
1381
1516
|
const target = hookPathFor(parsed);
|
|
1382
1517
|
const current = await readJsonOrDefault(target, {});
|
|
1383
|
-
if (!
|
|
1384
|
-
console.log(`yam
|
|
1518
|
+
if (!hookConfigHasProfile(current, parsed.profile)) {
|
|
1519
|
+
console.log(`yam-${parsed.profile} hook already disabled (${parsed.mode}): ${target}`);
|
|
1385
1520
|
return;
|
|
1386
1521
|
}
|
|
1387
|
-
const next =
|
|
1522
|
+
const next = stripYamHooks(current, parsed.profile);
|
|
1388
1523
|
if (Object.keys(next).length === 0) {
|
|
1389
1524
|
await rmrf(target);
|
|
1390
1525
|
}
|
|
1391
1526
|
else {
|
|
1392
1527
|
await fsp.writeFile(target, `${JSON.stringify(next, null, 2)}\n`);
|
|
1393
1528
|
}
|
|
1394
|
-
console.log(`yam
|
|
1529
|
+
console.log(`yam-${parsed.profile} hook disabled (${parsed.mode}): ${target}`);
|
|
1395
1530
|
}
|
|
1396
1531
|
async function hookRun(args = []) {
|
|
1397
1532
|
const profile = args[0] || 'lite';
|
|
1398
|
-
if (
|
|
1533
|
+
if (!['lite', 'study-note'].includes(profile)) {
|
|
1399
1534
|
console.log(JSON.stringify({ continue: true }));
|
|
1400
1535
|
return;
|
|
1401
1536
|
}
|
|
@@ -1403,7 +1538,9 @@ async function hookRun(args = []) {
|
|
|
1403
1538
|
const event = input?.hook_event_name || input?.hookEventName || input?.event || 'UserPromptSubmit';
|
|
1404
1539
|
const cwd = String(input?.cwd || process.cwd());
|
|
1405
1540
|
const prompt = extractPrompt(input);
|
|
1406
|
-
const additionalContext =
|
|
1541
|
+
const additionalContext = profile === 'study-note'
|
|
1542
|
+
? await buildStudyNoteHookContext({ cwd })
|
|
1543
|
+
: await buildYamLiteContext({ cwd, prompt });
|
|
1407
1544
|
const output = {
|
|
1408
1545
|
continue: true,
|
|
1409
1546
|
hookSpecificOutput: {
|
|
@@ -1461,6 +1598,26 @@ async function buildYamLiteContext({ cwd, prompt }) {
|
|
|
1461
1598
|
lines.push(routeHint);
|
|
1462
1599
|
return lines.join('\n');
|
|
1463
1600
|
}
|
|
1601
|
+
async function buildStudyNoteHookContext({ cwd }) {
|
|
1602
|
+
const dir = path.resolve(cwd || process.cwd());
|
|
1603
|
+
const changedFiles = await gitChangedFiles(dir);
|
|
1604
|
+
const lines = [
|
|
1605
|
+
'yam Study Note guard active: if this turn changes code, config, release metadata, docs, or project artifacts, include a Study Note in the final response.'
|
|
1606
|
+
];
|
|
1607
|
+
if (!changedFiles.length) {
|
|
1608
|
+
lines.push('No changed files were detected at prompt time; if you change artifacts during this turn, add the Study Note before final.');
|
|
1609
|
+
return lines.join('\n');
|
|
1610
|
+
}
|
|
1611
|
+
lines.push(`Changed files detected (${Math.min(changedFiles.length, 8)} shown): ${changedFiles.slice(0, 8).join(', ')}`);
|
|
1612
|
+
lines.push('Study Note minimum: touched code/artifact, role, execution point, before/after change, expected behavior, one syntax/structure insight, verification, and limits.');
|
|
1613
|
+
const hygiene = studyNoteHygieneRequirements(changedFiles);
|
|
1614
|
+
if (hygiene.length) {
|
|
1615
|
+
lines.push(`Architecture hygiene required: ${hygiene.map((item) => item.id).join(', ')}.`);
|
|
1616
|
+
lines.push('Report whether the change avoided dumping unrelated logic into page.tsx, one-off CSS into global.css, or structured product data into broad DB jsonb.');
|
|
1617
|
+
}
|
|
1618
|
+
lines.push('This hook is advisory; it does not generate or edit the Study Note.');
|
|
1619
|
+
return lines.join('\n');
|
|
1620
|
+
}
|
|
1464
1621
|
function yamLiteRouteHint(prompt = '') {
|
|
1465
1622
|
const text = String(prompt || '').toLowerCase();
|
|
1466
1623
|
if (!text)
|
|
@@ -2023,13 +2180,13 @@ function loopUsage() {
|
|
|
2023
2180
|
Read-only loop artifact helpers. A loop report records intent, stages, evidence, blockers, next action, handoff fields, and a short study note. It does not run agents, start processes, publish packages, or write files.
|
|
2024
2181
|
|
|
2025
2182
|
Usage:
|
|
2026
|
-
yam loop report [--route route] [--intent text] [--loop-kind harness|release|ueye|scout|deep|mission] [--stage id:status:note] [--evidence text] [--evidence-level none|fixture|smoke|local|real] [--evidence-stamp text] [--source-digest text] [--covered-requirement text] [--uncovered-requirement text] [--blocked text] [--blocked-kind text] [--failure-cause text] [--safe-retry text] [--recovery-hint text] [--fix-first-item text] [--remaining-task text] [--recommended-direction text] [--implementation-note text] [--why-this-next text] [--blocked-by text] [--owner-route route] [--owner-scope text] [--scope-owner text] [--side-effect text] [--avoidance-note text] [--truth status] [--intent-label read_only|write|destructive|runtime|visual|publish] [--issue-code text] [--issue-role text] [--issue-symptom text] [--changed-code text] [--changed-role text] [--change-summary text] [--why-important text] [--learning-note text] [--json]
|
|
2183
|
+
yam loop report [--route route] [--intent text] [--loop-kind harness|release|ueye|scout|deep|mission] [--stage id:status:note] [--evidence text] [--evidence-level none|fixture|smoke|local|real] [--evidence-stamp text] [--source-digest text] [--touched-file file] [--read-file file] [--verified-file file] [--skipped-check text] [--stop-condition text] [--resume-hint text] [--readiness-state usable|degraded|blocked|unknown] [--covered-requirement text] [--uncovered-requirement text] [--blocked text] [--blocked-kind text] [--failure-cause text] [--safe-retry text] [--recovery-hint text] [--fix-first-item text] [--remaining-task text] [--recommended-direction text] [--implementation-note text] [--why-this-next text] [--blocked-by text] [--owner-route route] [--owner-scope text] [--scope-owner text] [--side-effect text] [--avoidance-note text] [--truth status] [--intent-label read_only|write|destructive|runtime|visual|publish] [--issue-code text] [--issue-role text] [--issue-symptom text] [--changed-code text] [--changed-role text] [--change-summary text] [--why-important text] [--learning-note text] [--json]
|
|
2027
2184
|
`);
|
|
2028
2185
|
}
|
|
2029
2186
|
async function loopReport(args = []) {
|
|
2030
2187
|
if (args[0] === 'help' || args[0] === '--help' || args[0] === '-h')
|
|
2031
2188
|
return loopUsage();
|
|
2032
|
-
const flags = parseSimpleFlags(args, new Set(['route', 'intent', 'loop-kind', 'stage', 'stage-convention', 'evidence', 'evidence-level', 'evidence-stamp', 'source-digest', 'covered-requirement', 'uncovered-requirement', 'blocked', 'blocker', 'blocked-kind', 'failure-cause', 'next-action', 'safe-retry', 'recovery-hint', 'fix-first-item', 'remaining-task', 'recommended-direction', 'direction', 'implementation-note', 'why-this-next', 'blocked-by', 'owner-route', 'owner-scope', 'scope-owner', 'owner', 'scope', 'side-effect', 'avoidance-note', 'truth', 'intent-label', 'tool-intent', 'issue-code', 'issue-role', 'issue-symptom', 'changed-code', 'changed-role', 'change-summary', 'why-important', 'learning-note', 'json']));
|
|
2189
|
+
const flags = parseSimpleFlags(args, new Set(['route', 'intent', 'loop-kind', 'stage', 'stage-convention', 'evidence', 'evidence-level', 'evidence-stamp', 'source-digest', 'touched-file', 'read-file', 'verified-file', 'skipped-check', 'stop-condition', 'resume-hint', 'readiness-state', 'covered-requirement', 'uncovered-requirement', 'blocked', 'blocker', 'blocked-kind', 'failure-cause', 'next-action', 'safe-retry', 'recovery-hint', 'fix-first-item', 'remaining-task', 'recommended-direction', 'direction', 'implementation-note', 'why-this-next', 'blocked-by', 'owner-route', 'owner-scope', 'scope-owner', 'owner', 'scope', 'side-effect', 'avoidance-note', 'truth', 'intent-label', 'tool-intent', 'issue-code', 'issue-role', 'issue-symptom', 'changed-code', 'changed-role', 'change-summary', 'why-important', 'learning-note', 'json']));
|
|
2033
2190
|
const blockers = [...arrayFlag(flags.blocked), ...arrayFlag(flags.blocker)];
|
|
2034
2191
|
const report = buildLoopReport({
|
|
2035
2192
|
route: normalizeRoute(flags.route) || String(flags.route || ''),
|
|
@@ -2041,6 +2198,13 @@ async function loopReport(args = []) {
|
|
|
2041
2198
|
evidence_level: normalizeLoopEvidenceLevelFlag(flags.evidence_level),
|
|
2042
2199
|
evidence_stamp: String(flags.evidence_stamp || ''),
|
|
2043
2200
|
source_digest: String(flags.source_digest || ''),
|
|
2201
|
+
touched_files: arrayFlag(flags.touched_file),
|
|
2202
|
+
read_files: arrayFlag(flags.read_file),
|
|
2203
|
+
verified_files: arrayFlag(flags.verified_file),
|
|
2204
|
+
skipped_checks: arrayFlag(flags.skipped_check),
|
|
2205
|
+
stop_condition: String(flags.stop_condition || ''),
|
|
2206
|
+
resume_hint: String(flags.resume_hint || ''),
|
|
2207
|
+
readiness_state: normalizeReadinessStateFlag(flags.readiness_state),
|
|
2044
2208
|
covered_requirements: arrayFlag(flags.covered_requirement),
|
|
2045
2209
|
uncovered_requirements: arrayFlag(flags.uncovered_requirement),
|
|
2046
2210
|
blockers,
|
|
@@ -2099,7 +2263,7 @@ Usage:
|
|
|
2099
2263
|
yam ueye capture --url URL --out screenshot.png [--viewport 1440x900] [--full-page] [--json]
|
|
2100
2264
|
yam ueye compare --reference ref.png --actual screenshot.png [--json]
|
|
2101
2265
|
yam ueye preflight [dir] [--json]
|
|
2102
|
-
yam ueye report [--reference ref.png] [--actual screenshot.png] [--preflight-id id] [--p0-risk text] [--quality-gate-note text] [--brief-dimension text] [--constraint text] [--anti-slop text] [--invented-metric] [--placeholder-copy] [--generic-visual] [--review-session-id id] [--provider-context local] [--execution-surface in-app-browser] [--app-surface codex-app] [--browser-surface in-app-browser] [--control-mode manual|automated] [--preserved-state] [--preserved-url URL] [--completion-claim draft|needs-polish|done] [--strict] [--design-score n] [--p0 text] [--p1 text] [--states-checked] [--mobile-checked] [--contrast-checked] [--similar text] [--different text] [--missing text] [--resolved text] [--new-finding text] [--still-open text] [--regression text] [--viewport 1440x900] [--state default] [--design-quality pass|needs-polish|fails|not-checked] [--json]
|
|
2266
|
+
yam ueye report [--reference ref.png] [--actual screenshot.png] [--preflight-id id] [--p0-risk text] [--quality-gate-note text] [--brief-dimension text] [--constraint text] [--anti-slop text] [--invented-metric] [--placeholder-copy] [--generic-visual] [--acceptance-criterion text] [--touched-file file] [--read-file file] [--verified-file file] [--skipped-check text] [--residual-risk text] [--stop-condition text] [--resume-hint text] [--deep-visual-check text] [--design-system-evidence text] [--implementation-evidence text] [--state-check default:pass] [--review-session-id id] [--provider-context local] [--execution-surface in-app-browser] [--app-surface codex-app] [--browser-surface in-app-browser] [--control-mode manual|automated] [--preserved-state] [--preserved-url URL] [--completion-claim draft|needs-polish|done] [--strict] [--design-score n] [--p0 text] [--p1 text] [--states-checked] [--mobile-checked] [--contrast-checked] [--similar text] [--different text] [--missing text] [--resolved text] [--new-finding text] [--still-open text] [--regression text] [--viewport 1440x900] [--state default] [--design-quality pass|needs-polish|fails|not-checked] [--json]
|
|
2103
2267
|
|
|
2104
2268
|
Notes:
|
|
2105
2269
|
capture uses a locally available Playwright install when present. It does not download browsers or install dependencies.
|
|
@@ -2340,7 +2504,7 @@ async function ueyeCompare(args = []) {
|
|
|
2340
2504
|
async function ueyeReport(args = []) {
|
|
2341
2505
|
if (args[0] === 'help' || args[0] === '--help' || args[0] === '-h')
|
|
2342
2506
|
return ueyeUsage();
|
|
2343
|
-
const flags = parseSimpleFlags(args, new Set(['reference', 'ref', 'actual', 'screenshot', 'capture-backend', 'compare-backend', 'design-quality', 'blocked-reason', 'next-action', 'next-visual-action', 'review-session-id', 'preflight-id', 'p0-risk', 'quality-gate-note', 'brief-dimension', 'constraint', 'anti-slop', 'invented-metric', 'placeholder-copy', 'generic-visual', 'reference-id', 'screenshot-id', 'previous-screenshot-id', 'current-screenshot-id', 'previous-report', 'comparison-notes', 'similar', 'different', 'missing', 'resolved', 'new-finding', 'still-open', 'regression', 'viewport', 'state', 'provider-context', 'provider-badge', 'execution-surface', 'app-surface', 'browser-surface', 'control-mode', 'preserved-state', 'preserved-url', 'url', 'evidence-id', 'completion-claim', 'completion-status', 'gate-mode', 'strict', 'design-score', 'min-design-score', 'p0', 'p1', 'open-p0', 'open-p1', 'states-checked', 'mobile-checked', 'responsive-checked', 'contrast-checked', 'accessibility-checked', 'cta-checked', 'direction-locked', 'reference-read', 'comparison-result', 'json']));
|
|
2507
|
+
const flags = parseSimpleFlags(args, new Set(['reference', 'ref', 'actual', 'screenshot', 'capture-backend', 'compare-backend', 'design-quality', 'blocked-reason', 'next-action', 'next-visual-action', 'review-session-id', 'preflight-id', 'p0-risk', 'quality-gate-note', 'brief-dimension', 'constraint', 'anti-slop', 'invented-metric', 'placeholder-copy', 'generic-visual', 'acceptance-criterion', 'touched-file', 'read-file', 'verified-file', 'skipped-check', 'residual-risk', 'stop-condition', 'resume-hint', 'deep-visual-check', 'design-system-evidence', 'implementation-evidence', 'state-check', 'reference-id', 'screenshot-id', 'previous-screenshot-id', 'current-screenshot-id', 'previous-report', 'comparison-notes', 'similar', 'different', 'missing', 'resolved', 'new-finding', 'still-open', 'regression', 'viewport', 'state', 'provider-context', 'provider-badge', 'execution-surface', 'app-surface', 'browser-surface', 'control-mode', 'preserved-state', 'preserved-url', 'url', 'evidence-id', 'completion-claim', 'completion-status', 'gate-mode', 'strict', 'design-score', 'min-design-score', 'p0', 'p1', 'open-p0', 'open-p1', 'states-checked', 'mobile-checked', 'responsive-checked', 'contrast-checked', 'accessibility-checked', 'cta-checked', 'direction-locked', 'reference-read', 'comparison-result', 'json']));
|
|
2344
2508
|
const reference = String(flags.reference || flags.ref || '');
|
|
2345
2509
|
const actual = String(flags.actual || flags.screenshot || '');
|
|
2346
2510
|
const referenceSources = [];
|
|
@@ -2446,6 +2610,20 @@ async function ueyeReport(args = []) {
|
|
|
2446
2610
|
direction_locked: Boolean(flags.direction_locked),
|
|
2447
2611
|
reference_read: Boolean(flags.reference_read)
|
|
2448
2612
|
},
|
|
2613
|
+
deep_visual_review: {
|
|
2614
|
+
acceptance_criteria: arrayFlag(flags.acceptance_criterion),
|
|
2615
|
+
touched_files: arrayFlag(flags.touched_file),
|
|
2616
|
+
read_files: arrayFlag(flags.read_file),
|
|
2617
|
+
verified_files: arrayFlag(flags.verified_file),
|
|
2618
|
+
skipped_checks: arrayFlag(flags.skipped_check),
|
|
2619
|
+
residual_risks: arrayFlag(flags.residual_risk),
|
|
2620
|
+
stop_condition: String(flags.stop_condition || ''),
|
|
2621
|
+
resume_hint: String(flags.resume_hint || ''),
|
|
2622
|
+
deep_visual_checks: arrayFlag(flags.deep_visual_check),
|
|
2623
|
+
design_system_evidence: arrayFlag(flags.design_system_evidence),
|
|
2624
|
+
implementation_evidence: arrayFlag(flags.implementation_evidence),
|
|
2625
|
+
state_check: arrayFlag(flags.state_check)
|
|
2626
|
+
},
|
|
2449
2627
|
blocked_reason: blockedReason,
|
|
2450
2628
|
next_action: String(flags.next_visual_action || flags.next_action || '')
|
|
2451
2629
|
});
|
|
@@ -4200,6 +4378,8 @@ async function main() {
|
|
|
4200
4378
|
return tools(process.argv.slice(3));
|
|
4201
4379
|
if (command === 'proof')
|
|
4202
4380
|
return proof(process.argv.slice(3));
|
|
4381
|
+
if (command === 'study-note')
|
|
4382
|
+
return studyNote(process.argv.slice(3));
|
|
4203
4383
|
if (command === 'loop')
|
|
4204
4384
|
return loop(process.argv.slice(3));
|
|
4205
4385
|
if (command === 'ueye')
|