yam-flow 0.1.7 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/COMMANDS.md +6 -1
- package/README.md +9 -1
- package/dist/bin/yam.js +272 -10
- package/dist/lib/trust-kernel.d.ts +42 -0
- package/dist/lib/trust-kernel.js +154 -0
- package/package.json +1 -1
- package/src/bin/yam.ts +283 -11
- package/src/lib/trust-kernel.ts +188 -0
- package/yam.manifest.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to yam-flow are documented here.
|
|
4
4
|
|
|
5
|
+
## v0.1.8 - 2026-06-16
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Added `yam loop report [--json]` as a read-only loop artifact for intent, stages, evidence, blockers, next action, remaining tasks, tool intent, truth status, and study note.
|
|
10
|
+
- Added `yam.study-note.v1` so reports can carry short non-specialist explanations of the failing code, its role, observed symptom, changed code, why it matters, and learning note without guessing missing details.
|
|
11
|
+
- Added `publish_readiness` and `study_note` to `yam release report --json` with read-only npm registry/auth/version probes and redacted account/token details.
|
|
12
|
+
- Added Ueye `design_brief` and `anti_slop_review` fields with `--brief-dimension`, `--constraint`, `--anti-slop`, `--invented-metric`, `--placeholder-copy`, and `--generic-visual`.
|
|
13
|
+
|
|
14
|
+
### Improved
|
|
15
|
+
|
|
16
|
+
- Ueye anti-slop P0 findings now feed the design completion gate so `done` claims are blocked until fix-first issues are resolved.
|
|
17
|
+
- Release reports now separate publish readiness evidence from the publish action; `npm publish` remains outside the report.
|
|
18
|
+
- CLI smoke coverage now asserts loop report, study note limits, and Ueye design brief/anti-slop blocked paths.
|
|
19
|
+
|
|
20
|
+
### Verification
|
|
21
|
+
|
|
22
|
+
- `npm run typecheck`
|
|
23
|
+
- `npm run build`
|
|
24
|
+
- `npm run cli-smoke`
|
|
25
|
+
- `npm run verify:self`
|
|
26
|
+
- `npm run forbidden-names:check`
|
|
27
|
+
- `npm run package-boundary:check`
|
|
28
|
+
- `npm run dist:freshness`
|
|
29
|
+
- `node ./dist/bin/yam.js release report --json` (blocked as expected by npm auth readiness and dirty git)
|
|
30
|
+
- `npm whoami --registry https://registry.npmjs.org/` (E401, confirms auth/token blocker)
|
|
31
|
+
|
|
5
32
|
## v0.1.7 - 2026-06-12
|
|
6
33
|
|
|
7
34
|
### 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" --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" --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,6 +148,7 @@ 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 loop report --route quick --intent "fix release readiness" --stage "inspect:passed:read release report" --evidence "typecheck passed" --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
|
|
151
152
|
yam proof /path/to/project
|
|
152
153
|
yam proof --route deep --truth verified --command "npm run build: pass"
|
|
153
154
|
yam proof --route ueye --truth verified --visual "reference image only"
|
|
@@ -187,15 +188,19 @@ yam release report --json
|
|
|
187
188
|
yam runtime evidence --backend terminal --claim cleanup-verified --cleanup-observed --exit-code 0 --cleanup-method "exit observed" --json
|
|
188
189
|
yam mission queue --agent-id reviewer --scope "changed files review" --changed src/bin/yam.ts --verification-hint "npm run typecheck" --json
|
|
189
190
|
yam benchmark report --label "bundle size" --baseline 120 --current 118 --unit kB --target lower --json
|
|
191
|
+
yam loop report --route deep --intent "verify release readiness" --blocked "npm auth not verified" --next-action "refresh npm token, then rerun npm whoami" --json
|
|
190
192
|
```
|
|
191
193
|
|
|
192
194
|
Supported report shapes:
|
|
193
195
|
|
|
194
196
|
- Runtime evidence mini: command/process, observation, cleanup, truth status, next action.
|
|
195
197
|
- Patch queue lite: mission lane status, changed files, verification hint, rollback hint, truth status.
|
|
198
|
+
- Loop report: intent, stage outcomes, evidence, blockers, next action, remaining tasks, and study note.
|
|
199
|
+
- Study note: short non-specialist explanation of the failing code, its role, observed symptom, changed code, and why it matters.
|
|
196
200
|
- Benchmark optimization loop lite: baseline, one change, rerun, keep/revert decision.
|
|
197
201
|
- Structured diagnostic next action: severity, evidence, owner route, next action, truth status.
|
|
198
202
|
- Ueye continuity/comparison: previous report, current report, comparison delta, design quality, next action.
|
|
203
|
+
- Ueye design brief/anti-slop: brief dimensions, constraints, invented metrics, placeholder copy, generic visuals, and custom P0 blockers.
|
|
199
204
|
- Context pressure: project pack age/size, memory summary, dirty scope, scripts, instruction surfaces, and route hint.
|
|
200
205
|
- Cleanup scan: advisory-only list of confusing surfaces with destructive=false.
|
|
201
206
|
|
package/README.md
CHANGED
|
@@ -142,6 +142,7 @@ yam ueye report --reference ./reference.png --actual .yam/screens/home.png --pre
|
|
|
142
142
|
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"}'
|
|
143
143
|
yam media proof --requested --attempted --output ./generated.png --wait-loop --json
|
|
144
144
|
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"}'
|
|
145
|
+
yam loop report --route quick --intent "fix release readiness" --stage "inspect:passed:read release report" --evidence "typecheck passed" --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
|
|
145
146
|
yam release report --json
|
|
146
147
|
yam safety "supabase db reset"
|
|
147
148
|
yam detect /path/to/project
|
|
@@ -194,10 +195,13 @@ Publishing still requires confirming the final npm package name and account acce
|
|
|
194
195
|
- runtime evidence mini summaries
|
|
195
196
|
- mission patch queue lite records
|
|
196
197
|
- release report JSON
|
|
198
|
+
- loop report JSON
|
|
199
|
+
- study note JSON
|
|
197
200
|
- structured diagnostic next actions
|
|
198
201
|
- context pressure summaries
|
|
199
202
|
- advisory cleanup scans
|
|
200
203
|
- publish blocker evidence
|
|
204
|
+
- publish readiness evidence
|
|
201
205
|
- change insight reporting
|
|
202
206
|
- reference source boundary notes
|
|
203
207
|
- media generation proof caps
|
|
@@ -212,7 +216,10 @@ These shapes keep reports machine-readable without turning normal work into a he
|
|
|
212
216
|
- Runtime evidence mini: compact route, command/process, observation, cleanup, truth status, and next action fields for `$deep` or `$mission` runtime claims.
|
|
213
217
|
- Patch queue lite: `$mission` lane records with pending/applied/verified/reverted/blocked state, changed files, verification hint, rollback hint, truth status, and next action.
|
|
214
218
|
- Release report JSON: `yam release report --json` summarizes typecheck, forbidden-name scan, package boundary, registry status, CLI smoke, dist freshness, diagnostics, and final truth status.
|
|
219
|
+
- Loop report JSON: `yam loop report --json` records a read-only loop artifact: intent, stages, evidence, blockers, next action, remaining tasks, tool intent, truth status, and study note.
|
|
220
|
+
- Study note: `yam.study-note.v1` keeps short non-specialist explanations for what code was failing, what role it plays, how the symptom showed up, what changed, and why it matters. Missing details stay in `limits` instead of being guessed.
|
|
215
221
|
- Publish blocker evidence: release reports classify common npm auth, permission, OTP, immutable-version, cache, registry, and tarball failures into safe next actions.
|
|
222
|
+
- Publish readiness evidence: release reports run read-only registry/auth/version probes, redact account/token details, and keep npm publish outside the report.
|
|
216
223
|
- Context pressure: `yam context pressure` explains when project context is getting stale, broad, or confusing enough to summarize, refresh, narrow scope, or deepen route.
|
|
217
224
|
- Cleanup scan: `yam cleanup scan` is read-only and advisory; it reports confusing hooks, local skill folders, stale traces, or old proof artifacts without deleting anything.
|
|
218
225
|
- Benchmark optimization loop lite: use `yam measure <route>` and `yam template tuning` to record baseline, one route wording change, rerun result, keep/revert decision, and stop condition.
|
|
@@ -220,6 +227,7 @@ These shapes keep reports machine-readable without turning normal work into a he
|
|
|
220
227
|
- Ueye review continuity/comparison report: `$ueye` run reports can link a previous review, current evidence, comparison delta, design quality result, and next action.
|
|
221
228
|
- 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.
|
|
222
229
|
- 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.
|
|
230
|
+
- 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.
|
|
223
231
|
|
|
224
232
|
## Ueye Capture And Compare
|
|
225
233
|
|
|
@@ -229,7 +237,7 @@ These shapes keep reports machine-readable without turning normal work into a he
|
|
|
229
237
|
yam ueye capture --url http://localhost:3000 --out .yam/screens/home.png
|
|
230
238
|
yam ueye compare --reference ./reference.png --actual .yam/screens/home.png --json
|
|
231
239
|
yam ueye preflight . --json
|
|
232
|
-
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 --provider-context local --execution-surface in-app-browser --browser-surface in-app-browser --preserved-state --json
|
|
240
|
+
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
|
|
233
241
|
```
|
|
234
242
|
|
|
235
243
|
`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.
|
package/dist/bin/yam.js
CHANGED
|
@@ -8,7 +8,7 @@ import os from 'node:os';
|
|
|
8
8
|
import path from 'node:path';
|
|
9
9
|
import process from 'node:process';
|
|
10
10
|
import { fileURLToPath } from 'node:url';
|
|
11
|
-
import { TRUTH_STATUSES, buildMediaGenerationProof, buildMissionPatchEnvelope, buildRollbackHint, buildRuntimeBackendEvidence, buildUeyeDesignCompletionGate, buildUeyeVisualProvenance, buildUeyeRunReport, buildUeyeSurfaceContext, buildYamCompletionProof, detectDbSafetyText as detectTrustDbSafetyText, isTruthStatus } from '../lib/trust-kernel.js';
|
|
11
|
+
import { TRUTH_STATUSES, buildLoopReport, buildMediaGenerationProof, buildMissionPatchEnvelope, buildRollbackHint, buildRuntimeBackendEvidence, buildStudyNote, buildUeyeDesignCompletionGate, buildUeyeVisualProvenance, buildUeyeRunReport, buildUeyeSurfaceContext, buildYamCompletionProof, detectDbSafetyText as detectTrustDbSafetyText, isTruthStatus } from '../lib/trust-kernel.js';
|
|
12
12
|
function errorMessage(error) {
|
|
13
13
|
return error instanceof Error ? error.message : String(error);
|
|
14
14
|
}
|
|
@@ -122,6 +122,7 @@ Usage:
|
|
|
122
122
|
yam tools doctor [dir]
|
|
123
123
|
yam proof [dir|--from file] [--route route] [--truth status] [--command text] [--evidence text]
|
|
124
124
|
yam proof write [dir] [--format json|md] [--out file] [--route route] [--truth status] [--command text]
|
|
125
|
+
yam loop report [--route route] [--intent text] [--stage id:status:note] [--evidence text] [--json]
|
|
125
126
|
yam ueye capture --url URL --out screenshot.png [--viewport 1440x900] [--full-page] [--json]
|
|
126
127
|
yam ueye compare --reference ref.png --actual screenshot.png [--json]
|
|
127
128
|
yam ueye preflight [dir] [--json]
|
|
@@ -503,6 +504,8 @@ function toolIntentForCommand(command = '') {
|
|
|
503
504
|
const text = String(command || '').toLowerCase();
|
|
504
505
|
if (!text)
|
|
505
506
|
return 'read_only';
|
|
507
|
+
if (/(npm\s+(view|whoami|config\s+get|owner\s+ls)|registry:check)/i.test(text))
|
|
508
|
+
return 'read_only';
|
|
506
509
|
if (/(publish|registry|release|npm pack|npm publish)/i.test(text))
|
|
507
510
|
return 'publish';
|
|
508
511
|
if (/(rm |delete|drop|truncate|reset|migrate|push|deploy|write|commit|add |install)/i.test(text))
|
|
@@ -1531,6 +1534,11 @@ async function release(args = []) {
|
|
|
1531
1534
|
if (report.tarball.file_count !== undefined)
|
|
1532
1535
|
console.log(`- Tarball files: ${report.tarball.file_count}`);
|
|
1533
1536
|
}
|
|
1537
|
+
if (report.publish_readiness) {
|
|
1538
|
+
console.log(`- Publish readiness: ${report.publish_readiness.status}`);
|
|
1539
|
+
console.log(`- Registry: ${report.publish_readiness.registry.url || 'not-verified'}`);
|
|
1540
|
+
console.log(`- npm auth: ${report.publish_readiness.auth.status}`);
|
|
1541
|
+
}
|
|
1534
1542
|
if (report.failed.length) {
|
|
1535
1543
|
console.log('- Failed:');
|
|
1536
1544
|
for (const id of report.failed)
|
|
@@ -1548,6 +1556,9 @@ async function release(args = []) {
|
|
|
1548
1556
|
for (const action of report.next_actions)
|
|
1549
1557
|
console.log(` - ${action.next_action}`);
|
|
1550
1558
|
}
|
|
1559
|
+
if (report.study_note?.problem?.summary || report.study_note?.problem?.symptom) {
|
|
1560
|
+
console.log(`- Study note: ${report.study_note.problem.summary || report.study_note.problem.symptom}`);
|
|
1561
|
+
}
|
|
1551
1562
|
if (!report.ok)
|
|
1552
1563
|
process.exitCode = 1;
|
|
1553
1564
|
}
|
|
@@ -1566,19 +1577,23 @@ function runReleaseReport() {
|
|
|
1566
1577
|
const tarball = releaseTarballProvenance();
|
|
1567
1578
|
const freshness = releaseFreshness(checks, provenance, tarball);
|
|
1568
1579
|
const publishBlockerEvidence = publishBlockerEvidenceFromRelease(checks, tarball);
|
|
1569
|
-
const
|
|
1580
|
+
const publishReadiness = releasePublishReadiness(checks, provenance, tarball, publishBlockerEvidence);
|
|
1581
|
+
const nextActions = releaseNextActions(checks, provenance, tarball, publishBlockerEvidence, publishReadiness);
|
|
1582
|
+
const ok = failed.length === 0 && publishReadiness.status === 'ready';
|
|
1570
1583
|
return {
|
|
1571
1584
|
schema: 'yam.release-report.v1',
|
|
1572
1585
|
generated_at: startedAt,
|
|
1573
1586
|
packageName: PACKAGE_JSON.name,
|
|
1574
1587
|
version: VERSION,
|
|
1575
|
-
ok
|
|
1576
|
-
truth_status:
|
|
1588
|
+
ok,
|
|
1589
|
+
truth_status: ok ? 'verified' : 'blocked',
|
|
1577
1590
|
checks,
|
|
1578
1591
|
failed,
|
|
1579
1592
|
provenance,
|
|
1580
1593
|
tarball,
|
|
1581
1594
|
freshness,
|
|
1595
|
+
publish_readiness: publishReadiness,
|
|
1596
|
+
study_note: releaseStudyNote(publishReadiness, publishBlockerEvidence),
|
|
1582
1597
|
publishBlockerEvidence,
|
|
1583
1598
|
next_actions: nextActions
|
|
1584
1599
|
};
|
|
@@ -1656,7 +1671,131 @@ function releaseFreshness(checks = [], provenance = {}, tarball = {}) {
|
|
|
1656
1671
|
truth_status: [dist, registry, boundary, smoke, tarballStatus].every((value) => !/not-verified|needs-check/.test(value)) ? 'verified' : 'partial'
|
|
1657
1672
|
};
|
|
1658
1673
|
}
|
|
1659
|
-
function
|
|
1674
|
+
function releasePublishReadiness(checks = [], provenance = {}, tarball = {}, publishBlockers = []) {
|
|
1675
|
+
const failedChecks = checks.filter((check) => check.status !== 'passed');
|
|
1676
|
+
const registryProbe = runReadOnlyCommandResult('npm', ['config', 'get', 'registry']);
|
|
1677
|
+
const registryUrl = registryProbe.stdout.trim() || String(PACKAGE_JSON.publishConfig?.registry || 'https://registry.npmjs.org/');
|
|
1678
|
+
const whoamiProbe = runReadOnlyCommandResult('npm', ['whoami', '--registry', registryUrl]);
|
|
1679
|
+
const registryStatus = releaseRegistryStatusFromChecks(checks);
|
|
1680
|
+
const latestProbe = registryStatus.checked
|
|
1681
|
+
? { ok: true, stdout: registryStatus.latest_version, note: registryStatus.note }
|
|
1682
|
+
: runReadOnlyCommandResult('npm', ['view', PACKAGE_JSON.name, 'version', '--registry', registryUrl]);
|
|
1683
|
+
const latestVersion = latestProbe.ok ? String(latestProbe.stdout || '').trim() : '';
|
|
1684
|
+
const blockers = [];
|
|
1685
|
+
const versionStatus = latestProbe.ok
|
|
1686
|
+
? registryStatus.not_published ? 'package_not_published' : latestVersion === VERSION ? 'already_published' : 'new_version'
|
|
1687
|
+
: 'not_verified';
|
|
1688
|
+
if (!registryProbe.ok) {
|
|
1689
|
+
blockers.push(readinessBlocker('registry_not_verified', 'npm registry could not be read from this shell', 'run `npm config get registry` and confirm it points to the intended public registry', 'npm config get registry', 'error'));
|
|
1690
|
+
}
|
|
1691
|
+
if (!whoamiProbe.ok) {
|
|
1692
|
+
blockers.push(readinessBlocker('auth_not_verified', whoamiProbe.note || 'npm whoami did not confirm an authenticated publisher in this shell', 'refresh npm login/token, then rerun `npm whoami` before publishing', 'npm whoami', 'error'));
|
|
1693
|
+
}
|
|
1694
|
+
if (!latestProbe.ok) {
|
|
1695
|
+
const blocker = classifyPublishBlockerText(latestProbe.note);
|
|
1696
|
+
blockers.push(readinessBlocker(blocker?.blocker_kind || 'latest_version_not_verified', blocker?.likely_cause || 'npm latest version could not be read', blocker?.safe_next_action || 'rerun the read-only registry check before publishing', 'npm view', 'error'));
|
|
1697
|
+
}
|
|
1698
|
+
if (versionStatus === 'already_published') {
|
|
1699
|
+
blockers.push(readinessBlocker('version_already_published', `${PACKAGE_JSON.name}@${VERSION} is already present on the registry`, 'bump package.json to the next patch version before publishing', 'npm view', 'error'));
|
|
1700
|
+
}
|
|
1701
|
+
if (failedChecks.length) {
|
|
1702
|
+
blockers.push(readinessBlocker('release_checks_failed', `${failedChecks.length} release check(s) did not pass`, 'fix failing release checks before publishing', 'npm run release:check', 'error'));
|
|
1703
|
+
}
|
|
1704
|
+
if (provenance.git_dirty) {
|
|
1705
|
+
blockers.push(readinessBlocker('git_dirty', 'working tree has uncommitted changes', 'commit intended changes or keep them explicitly local before tagging/publishing', 'git status --short'));
|
|
1706
|
+
}
|
|
1707
|
+
if (provenance.dist_changed_files?.length) {
|
|
1708
|
+
blockers.push(readinessBlocker('dist_not_fresh', 'dist has changed files after freshness check', 'run build and commit dist only if this package publishes dist', 'npm run build'));
|
|
1709
|
+
}
|
|
1710
|
+
if (tarball.status !== 'checked') {
|
|
1711
|
+
blockers.push(readinessBlocker('tarball_not_verified', tarball.reason || 'npm pack dry-run did not produce tarball provenance', 'fix tarball/package-boundary issues before publishing', 'npm pack --dry-run', 'error'));
|
|
1712
|
+
}
|
|
1713
|
+
for (const blocker of publishBlockers) {
|
|
1714
|
+
blockers.push(readinessBlocker(blocker.blocker_kind, blocker.likely_cause, blocker.safe_next_action, 'npm publish', 'error'));
|
|
1715
|
+
}
|
|
1716
|
+
const uniqueBlockers = uniqueReadinessBlockers(blockers);
|
|
1717
|
+
const status = uniqueBlockers.length ? 'blocked' : 'ready';
|
|
1718
|
+
return {
|
|
1719
|
+
schema: 'yam.release-publish-readiness.v1',
|
|
1720
|
+
generated_at: new Date().toISOString(),
|
|
1721
|
+
package_name: PACKAGE_JSON.name,
|
|
1722
|
+
local_version: VERSION,
|
|
1723
|
+
status,
|
|
1724
|
+
registry: {
|
|
1725
|
+
url: registryUrl,
|
|
1726
|
+
latest_version: latestVersion,
|
|
1727
|
+
version_status: versionStatus,
|
|
1728
|
+
truth_status: latestProbe.ok ? 'verified' : 'blocked'
|
|
1729
|
+
},
|
|
1730
|
+
auth: {
|
|
1731
|
+
command: 'npm whoami',
|
|
1732
|
+
status: whoamiProbe.ok ? 'authenticated' : 'not_authenticated',
|
|
1733
|
+
account: whoamiProbe.ok ? 'observed_redacted' : '',
|
|
1734
|
+
note: whoamiProbe.ok ? 'npm account observed; username intentionally redacted' : whoamiProbe.note,
|
|
1735
|
+
truth_status: whoamiProbe.ok ? 'verified' : 'blocked'
|
|
1736
|
+
},
|
|
1737
|
+
blockers: uniqueBlockers,
|
|
1738
|
+
next_action: uniqueBlockers[0]?.safe_next_action || 'publish readiness is complete; run publish only when the user explicitly intends it',
|
|
1739
|
+
truth_status: status === 'ready' ? 'verified' : 'blocked'
|
|
1740
|
+
};
|
|
1741
|
+
}
|
|
1742
|
+
function releaseRegistryStatusFromChecks(checks = []) {
|
|
1743
|
+
const registryCheck = checks.find((check) => check.id === 'registry_status');
|
|
1744
|
+
const note = String(registryCheck?.note || '');
|
|
1745
|
+
if (registryCheck?.status !== 'passed')
|
|
1746
|
+
return { checked: false, latest_version: '', not_published: false, note };
|
|
1747
|
+
const latest = note.match(/\blatest\s+([^,\s)]+)/i)?.[1] || '';
|
|
1748
|
+
return {
|
|
1749
|
+
checked: true,
|
|
1750
|
+
latest_version: latest,
|
|
1751
|
+
not_published: /not published yet/i.test(note),
|
|
1752
|
+
note
|
|
1753
|
+
};
|
|
1754
|
+
}
|
|
1755
|
+
function readinessBlocker(kind, reason, safeNextAction, command = '', severity = 'warning') {
|
|
1756
|
+
return {
|
|
1757
|
+
kind,
|
|
1758
|
+
severity,
|
|
1759
|
+
reason: summarizeCheckOutput(redactSensitiveText(reason)),
|
|
1760
|
+
safe_next_action: safeNextAction,
|
|
1761
|
+
command,
|
|
1762
|
+
truth_status: 'partial'
|
|
1763
|
+
};
|
|
1764
|
+
}
|
|
1765
|
+
function uniqueReadinessBlockers(blockers = []) {
|
|
1766
|
+
const seen = new Set();
|
|
1767
|
+
return blockers.filter((blocker) => {
|
|
1768
|
+
const key = `${blocker.kind}:${blocker.safe_next_action}`;
|
|
1769
|
+
if (seen.has(key))
|
|
1770
|
+
return false;
|
|
1771
|
+
seen.add(key);
|
|
1772
|
+
return true;
|
|
1773
|
+
});
|
|
1774
|
+
}
|
|
1775
|
+
function releaseStudyNote(publishReadiness = {}, publishBlockers = []) {
|
|
1776
|
+
const authBlocked = publishReadiness.blockers?.find((blocker) => /auth|otp|permission|forbidden|not_found/i.test(`${blocker.kind} ${blocker.reason}`));
|
|
1777
|
+
const firstBlocker = authBlocked || publishReadiness.blockers?.[0] || publishBlockers[0];
|
|
1778
|
+
if (!firstBlocker) {
|
|
1779
|
+
return buildStudyNote({
|
|
1780
|
+
changed_code: 'yam release report',
|
|
1781
|
+
changed_role: 'It checks whether the package looks ready to publish without running npm publish.',
|
|
1782
|
+
change_summary: 'Release readiness passed the read-only checks that were available.',
|
|
1783
|
+
why_important: 'A publish command changes public package state, so yam keeps the readiness proof separate from the publish action.',
|
|
1784
|
+
learning_note: 'Readiness means the checks looked good; publishing still requires an explicit user action.'
|
|
1785
|
+
});
|
|
1786
|
+
}
|
|
1787
|
+
return buildStudyNote({
|
|
1788
|
+
issue_code: 'npm publish readiness',
|
|
1789
|
+
issue_role: 'This part checks registry, version, auth, tarball, and local release checks before any public publish.',
|
|
1790
|
+
issue_symptom: firstBlocker.reason || firstBlocker.likely_cause || 'Publish readiness is blocked.',
|
|
1791
|
+
changed_code: 'yam release report',
|
|
1792
|
+
changed_role: 'It now explains the likely publish blocker instead of only showing a raw npm failure.',
|
|
1793
|
+
change_summary: 'The report adds auth-safe readiness, safe next action, and beginner-readable blocker evidence.',
|
|
1794
|
+
why_important: 'A bad token or wrong npm account can make publish fail or target the wrong package context.',
|
|
1795
|
+
learning_note: 'When release readiness is blocked, fix the first blocker before trying a publish command.'
|
|
1796
|
+
});
|
|
1797
|
+
}
|
|
1798
|
+
function releaseNextActions(checks = [], provenance = {}, tarball = {}, publishBlockers = [], publishReadiness = {}) {
|
|
1660
1799
|
const actions = [];
|
|
1661
1800
|
for (const check of checks) {
|
|
1662
1801
|
if (check.status === 'passed')
|
|
@@ -1675,6 +1814,9 @@ function releaseNextActions(checks = [], provenance = {}, tarball = {}, publishB
|
|
|
1675
1814
|
for (const blocker of publishBlockers) {
|
|
1676
1815
|
actions.push(nextActionDetail(`publish-${blocker.blocker_kind}`, blocker.truth_status === 'blocked' ? 'error' : 'warning', blocker.likely_cause, blocker.safe_next_action, 'npm publish'));
|
|
1677
1816
|
}
|
|
1817
|
+
for (const blocker of publishReadiness.blockers || []) {
|
|
1818
|
+
actions.push(nextActionDetail(`publish-readiness-${blocker.kind}`, blocker.severity || 'warning', blocker.reason, blocker.safe_next_action, blocker.command || 'npm publish'));
|
|
1819
|
+
}
|
|
1678
1820
|
return uniqueNextActionDetails(actions);
|
|
1679
1821
|
}
|
|
1680
1822
|
function publishBlockerEvidenceFromRelease(checks = [], tarball = {}) {
|
|
@@ -1746,6 +1888,23 @@ function runReadOnlyCommand(command, args = []) {
|
|
|
1746
1888
|
return '';
|
|
1747
1889
|
return String(result.stdout || '');
|
|
1748
1890
|
}
|
|
1891
|
+
function runReadOnlyCommandResult(command, args = []) {
|
|
1892
|
+
const result = spawnSync(command, args, {
|
|
1893
|
+
cwd: ROOT,
|
|
1894
|
+
encoding: 'utf8',
|
|
1895
|
+
env: { ...process.env, npm_config_cache: path.join(os.tmpdir(), 'yam-npm-cache') },
|
|
1896
|
+
timeout: 30000
|
|
1897
|
+
});
|
|
1898
|
+
const stdout = redactSensitiveText(String(result.stdout || ''));
|
|
1899
|
+
const stderr = redactSensitiveText(String(result.stderr || result.error?.message || ''));
|
|
1900
|
+
return {
|
|
1901
|
+
ok: result.status === 0,
|
|
1902
|
+
status: typeof result.status === 'number' ? result.status : null,
|
|
1903
|
+
stdout,
|
|
1904
|
+
stderr,
|
|
1905
|
+
note: summarizeCheckOutput([stdout, stderr].filter(Boolean).join('\n'))
|
|
1906
|
+
};
|
|
1907
|
+
}
|
|
1749
1908
|
function runReadOnlyCommandIn(cwd, command, args = []) {
|
|
1750
1909
|
const result = spawnSync(command, args, {
|
|
1751
1910
|
cwd,
|
|
@@ -1777,12 +1936,19 @@ function runReleaseCheck(id, commandSpec) {
|
|
|
1777
1936
|
};
|
|
1778
1937
|
}
|
|
1779
1938
|
function summarizeCheckOutput(output = '') {
|
|
1780
|
-
const lines = String(output || '').split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
1939
|
+
const lines = redactSensitiveText(String(output || '')).split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
1781
1940
|
if (!lines.length)
|
|
1782
1941
|
return '';
|
|
1783
1942
|
const highSignal = lines.filter((line) => !line.startsWith('>')).slice(-4);
|
|
1784
1943
|
return highSignal.join(' | ').slice(0, 600);
|
|
1785
1944
|
}
|
|
1945
|
+
function redactSensitiveText(text = '') {
|
|
1946
|
+
return String(text || '')
|
|
1947
|
+
.replace(/(_authToken\s*=\s*)[^\s]+/gi, '$1[redacted]')
|
|
1948
|
+
.replace(/\b(password|passwd|api[_-]?key|secret|token)\s*[:=]\s*\S+/gi, '$1=[redacted]')
|
|
1949
|
+
.replace(/\/\/([^:\s]+):([^@\s]+)@/g, '//[redacted]@')
|
|
1950
|
+
.replace(/\b(npm_[A-Za-z0-9]{20,}|gh[pousr]_[A-Za-z0-9_]{20,}|sk-[A-Za-z0-9_-]{20,})\b/g, '[redacted-token]');
|
|
1951
|
+
}
|
|
1786
1952
|
async function readStdinTextIfAvailable() {
|
|
1787
1953
|
if (process.stdin.isTTY)
|
|
1788
1954
|
return '';
|
|
@@ -1791,6 +1957,54 @@ async function readStdinTextIfAvailable() {
|
|
|
1791
1957
|
chunks.push(Buffer.from(chunk));
|
|
1792
1958
|
return Buffer.concat(chunks).toString('utf8').trim();
|
|
1793
1959
|
}
|
|
1960
|
+
async function loop(args = []) {
|
|
1961
|
+
const subcommand = args[0] || 'help';
|
|
1962
|
+
if (subcommand === 'help' || subcommand === '--help' || subcommand === '-h')
|
|
1963
|
+
return loopUsage();
|
|
1964
|
+
if (subcommand === 'report')
|
|
1965
|
+
return loopReport(args.slice(1));
|
|
1966
|
+
console.error(`unknown loop command: ${subcommand}`);
|
|
1967
|
+
process.exitCode = 1;
|
|
1968
|
+
return loopUsage();
|
|
1969
|
+
}
|
|
1970
|
+
function loopUsage() {
|
|
1971
|
+
console.log(`yam loop
|
|
1972
|
+
|
|
1973
|
+
Read-only loop artifact helpers. A loop report records intent, stages, evidence, blockers, next action, and a short study note. It does not run agents, start processes, publish packages, or write files.
|
|
1974
|
+
|
|
1975
|
+
Usage:
|
|
1976
|
+
yam loop report [--route route] [--intent text] [--loop-kind harness|release|ueye|scout|deep|mission] [--stage id:status:note] [--evidence text] [--blocked text] [--remaining-task 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]
|
|
1977
|
+
`);
|
|
1978
|
+
}
|
|
1979
|
+
async function loopReport(args = []) {
|
|
1980
|
+
if (args[0] === 'help' || args[0] === '--help' || args[0] === '-h')
|
|
1981
|
+
return loopUsage();
|
|
1982
|
+
const flags = parseSimpleFlags(args, new Set(['route', 'intent', 'loop-kind', 'stage', 'evidence', 'blocked', 'blocker', 'next-action', 'remaining-task', 'truth', 'intent-label', 'tool-intent', 'issue-code', 'issue-role', 'issue-symptom', 'changed-code', 'changed-role', 'change-summary', 'why-important', 'learning-note', 'json']));
|
|
1983
|
+
const blockers = [...arrayFlag(flags.blocked), ...arrayFlag(flags.blocker)];
|
|
1984
|
+
const report = buildLoopReport({
|
|
1985
|
+
route: normalizeRoute(flags.route) || String(flags.route || ''),
|
|
1986
|
+
intent: String(flags.intent || ''),
|
|
1987
|
+
loop_kind: String(flags.loop_kind || flags.route || 'harness'),
|
|
1988
|
+
stages: arrayFlag(flags.stage),
|
|
1989
|
+
evidence: arrayFlag(flags.evidence),
|
|
1990
|
+
blockers,
|
|
1991
|
+
truth_status: isTruthStatus(flags.truth) ? flags.truth : undefined,
|
|
1992
|
+
intent_label: normalizeToolIntent(flags.intent_label || flags.tool_intent || 'read_only'),
|
|
1993
|
+
next_action: String(flags.next_action || ''),
|
|
1994
|
+
remaining_tasks: arrayFlag(flags.remaining_task),
|
|
1995
|
+
issue_code: String(flags.issue_code || ''),
|
|
1996
|
+
issue_role: String(flags.issue_role || ''),
|
|
1997
|
+
issue_symptom: String(flags.issue_symptom || ''),
|
|
1998
|
+
changed_code: String(flags.changed_code || ''),
|
|
1999
|
+
changed_role: String(flags.changed_role || ''),
|
|
2000
|
+
change_summary: String(flags.change_summary || ''),
|
|
2001
|
+
why_important: String(flags.why_important || ''),
|
|
2002
|
+
learning_note: String(flags.learning_note || '')
|
|
2003
|
+
});
|
|
2004
|
+
printJsonOrHuman(report, Boolean(flags.json), 'Loop report');
|
|
2005
|
+
if (report.truth_status === 'blocked')
|
|
2006
|
+
process.exitCode = 1;
|
|
2007
|
+
}
|
|
1794
2008
|
async function ueye(args = []) {
|
|
1795
2009
|
const subcommand = args[0] || 'help';
|
|
1796
2010
|
if (subcommand === 'help' || subcommand === '--help' || subcommand === '-h')
|
|
@@ -1815,7 +2029,7 @@ Usage:
|
|
|
1815
2029
|
yam ueye capture --url URL --out screenshot.png [--viewport 1440x900] [--full-page] [--json]
|
|
1816
2030
|
yam ueye compare --reference ref.png --actual screenshot.png [--json]
|
|
1817
2031
|
yam ueye preflight [dir] [--json]
|
|
1818
|
-
yam ueye report [--reference ref.png] [--actual screenshot.png] [--preflight-id id] [--p0-risk text] [--quality-gate-note text] [--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]
|
|
2032
|
+
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]
|
|
1819
2033
|
|
|
1820
2034
|
Notes:
|
|
1821
2035
|
capture uses a locally available Playwright install when present. It does not download browsers or install dependencies.
|
|
@@ -2056,7 +2270,7 @@ async function ueyeCompare(args = []) {
|
|
|
2056
2270
|
async function ueyeReport(args = []) {
|
|
2057
2271
|
if (args[0] === 'help' || args[0] === '--help' || args[0] === '-h')
|
|
2058
2272
|
return ueyeUsage();
|
|
2059
|
-
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', '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']));
|
|
2273
|
+
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']));
|
|
2060
2274
|
const reference = String(flags.reference || flags.ref || '');
|
|
2061
2275
|
const actual = String(flags.actual || flags.screenshot || '');
|
|
2062
2276
|
const referenceSources = [];
|
|
@@ -2065,6 +2279,8 @@ async function ueyeReport(args = []) {
|
|
|
2065
2279
|
let blockedReason = String(flags.blocked_reason || '');
|
|
2066
2280
|
const reviewSessionId = String(flags.review_session_id || `ueye-${timestampId()}`);
|
|
2067
2281
|
const previousReport = await readPreviousUeyeReport(flags.previous_report);
|
|
2282
|
+
const designBrief = buildUeyeDesignBrief(flags);
|
|
2283
|
+
const antiSlopReview = buildUeyeAntiSlopReview(flags);
|
|
2068
2284
|
const surfaceContext = buildUeyeSurfaceContext({
|
|
2069
2285
|
provider_context: String(flags.provider_context || 'not-recorded'),
|
|
2070
2286
|
provider_badge: String(flags.provider_badge || flags.provider_context || 'not-recorded'),
|
|
@@ -2149,7 +2365,7 @@ async function ueyeReport(args = []) {
|
|
|
2149
2365
|
completion_claim: flags.completion_claim || flags.completion_status || 'draft',
|
|
2150
2366
|
design_score: numberOrNull(flags.design_score),
|
|
2151
2367
|
min_design_score: numberOrNull(flags.min_design_score) ?? 8,
|
|
2152
|
-
p0: [...arrayFlag(flags.p0), ...arrayFlag(flags.open_p0), ...arrayFlag(flags.p0_risk)],
|
|
2368
|
+
p0: [...arrayFlag(flags.p0), ...arrayFlag(flags.open_p0), ...arrayFlag(flags.p0_risk), ...antiSlopReview.blockers],
|
|
2153
2369
|
p1: [...arrayFlag(flags.p1), ...arrayFlag(flags.open_p1)],
|
|
2154
2370
|
states_checked: Boolean(flags.states_checked),
|
|
2155
2371
|
mobile_checked: Boolean(flags.mobile_checked),
|
|
@@ -2190,6 +2406,8 @@ async function ueyeReport(args = []) {
|
|
|
2190
2406
|
const result = {
|
|
2191
2407
|
...report,
|
|
2192
2408
|
review_session_id: reviewSessionId,
|
|
2409
|
+
design_brief: designBrief,
|
|
2410
|
+
anti_slop_review: antiSlopReview,
|
|
2193
2411
|
preflight: {
|
|
2194
2412
|
preflight_id: String(flags.preflight_id || ''),
|
|
2195
2413
|
p0_risks: arrayFlag(flags.p0_risk),
|
|
@@ -2206,6 +2424,48 @@ async function ueyeReport(args = []) {
|
|
|
2206
2424
|
if (report.truth_status === 'blocked')
|
|
2207
2425
|
process.exitCode = 1;
|
|
2208
2426
|
}
|
|
2427
|
+
function buildUeyeDesignBrief(flags = {}) {
|
|
2428
|
+
const dimensions = arrayFlag(flags.brief_dimension);
|
|
2429
|
+
const constraints = arrayFlag(flags.constraint);
|
|
2430
|
+
const hasBrief = dimensions.length || constraints.length;
|
|
2431
|
+
return {
|
|
2432
|
+
schema: 'yam.ueye-design-brief.v1',
|
|
2433
|
+
dimensions,
|
|
2434
|
+
constraints,
|
|
2435
|
+
source_boundary: hasBrief ? 'operator_provided_cli_flags' : 'not_provided',
|
|
2436
|
+
next_action: hasBrief ? 'use this brief as context, not as visual proof' : 'add --brief-dimension and --constraint when design direction matters',
|
|
2437
|
+
truth_status: hasBrief ? 'partial' : 'assumed'
|
|
2438
|
+
};
|
|
2439
|
+
}
|
|
2440
|
+
function buildUeyeAntiSlopReview(flags = {}) {
|
|
2441
|
+
const explicit = arrayFlag(flags.anti_slop);
|
|
2442
|
+
const checks = [
|
|
2443
|
+
antiSlopCheck('invented_metric', 'Invented metrics or unsupported numeric claims', Boolean(flags.invented_metric), 'replace invented metrics with measured values or remove the claim'),
|
|
2444
|
+
antiSlopCheck('placeholder_copy', 'Placeholder copy remains in the UI', Boolean(flags.placeholder_copy), 'replace placeholder copy with product-specific text before claiming done'),
|
|
2445
|
+
antiSlopCheck('generic_visual', 'Generic visual treatment does not fit the product context', Boolean(flags.generic_visual), 'tie visuals to the product, state, or reference before claiming design quality')
|
|
2446
|
+
];
|
|
2447
|
+
const blockers = [
|
|
2448
|
+
...explicit,
|
|
2449
|
+
...checks.filter((check) => check.status === 'fail').map((check) => `${check.id}: ${check.next_action}`)
|
|
2450
|
+
];
|
|
2451
|
+
return {
|
|
2452
|
+
schema: 'yam.ueye-anti-slop-review.v1',
|
|
2453
|
+
checks,
|
|
2454
|
+
blockers,
|
|
2455
|
+
next_action: blockers[0] || (checks.some((check) => check.status === 'pass') || explicit.length ? 'anti-slop risks are recorded; keep visual proof separate' : 'record anti-slop risks when they matter before claiming done'),
|
|
2456
|
+
truth_status: blockers.length ? 'blocked' : checks.some((check) => check.status === 'pass') || explicit.length ? 'partial' : 'assumed'
|
|
2457
|
+
};
|
|
2458
|
+
}
|
|
2459
|
+
function antiSlopCheck(id, label, failed = false, nextAction = '') {
|
|
2460
|
+
return {
|
|
2461
|
+
id,
|
|
2462
|
+
label,
|
|
2463
|
+
status: failed ? 'fail' : 'not_checked',
|
|
2464
|
+
severity: failed ? 'P0' : 'P2',
|
|
2465
|
+
next_action: nextAction,
|
|
2466
|
+
truth_status: failed ? 'blocked' : 'assumed'
|
|
2467
|
+
};
|
|
2468
|
+
}
|
|
2209
2469
|
async function readPreviousUeyeReport(file = '') {
|
|
2210
2470
|
const target = String(file || '');
|
|
2211
2471
|
if (!target)
|
|
@@ -2587,7 +2847,7 @@ function parseSimpleFlags(args = [], allowed = new Set()) {
|
|
|
2587
2847
|
if (allowed.size && !allowed.has(key))
|
|
2588
2848
|
continue;
|
|
2589
2849
|
const normalizedKey = key.replace(/-/g, '_');
|
|
2590
|
-
if (['json', 'full-page', 'requested', 'attempted', 'available', 'wait-loop', 'cleanup-checked', 'cleanup-observed', 'left-running-intentionally', 'strict', 'preserved-state', 'states-checked', 'mobile-checked', 'responsive-checked', 'contrast-checked', 'accessibility-checked', 'cta-checked', 'direction-locked', 'reference-read'].includes(key)) {
|
|
2850
|
+
if (['json', 'full-page', 'requested', 'attempted', 'available', 'wait-loop', 'cleanup-checked', 'cleanup-observed', 'left-running-intentionally', 'strict', 'preserved-state', 'states-checked', 'mobile-checked', 'responsive-checked', 'contrast-checked', 'accessibility-checked', 'cta-checked', 'direction-locked', 'reference-read', 'invented-metric', 'placeholder-copy', 'generic-visual'].includes(key)) {
|
|
2591
2851
|
flags[normalizedKey] = true;
|
|
2592
2852
|
continue;
|
|
2593
2853
|
}
|
|
@@ -3870,6 +4130,8 @@ async function main() {
|
|
|
3870
4130
|
return tools(process.argv.slice(3));
|
|
3871
4131
|
if (command === 'proof')
|
|
3872
4132
|
return proof(process.argv.slice(3));
|
|
4133
|
+
if (command === 'loop')
|
|
4134
|
+
return loop(process.argv.slice(3));
|
|
3873
4135
|
if (command === 'ueye')
|
|
3874
4136
|
return ueye(process.argv.slice(3));
|
|
3875
4137
|
if (command === 'media')
|
|
@@ -5,6 +5,8 @@ export type EvidenceKind = 'command' | 'evidence' | 'visual' | 'runtime' | 'skip
|
|
|
5
5
|
export type RuntimeSubsystem = 'real_runtime' | 'tmux_physical' | 'process_cleanup' | 'browser_visual' | 'db_safety';
|
|
6
6
|
export type RuntimeBackend = 'none' | 'in_app_browser' | 'playwright' | 'terminal' | 'tmux' | 'zellij' | 'unknown';
|
|
7
7
|
export type RuntimeClaim = 'not_started' | 'started' | 'observed' | 'stopped' | 'cleanup_verified' | 'blocked' | 'unknown';
|
|
8
|
+
export type LoopStageStatus = 'passed' | 'failed' | 'blocked' | 'skipped' | 'partial' | 'pending' | 'recorded';
|
|
9
|
+
export type ToolIntent = 'read_only' | 'write' | 'destructive' | 'runtime' | 'visual' | 'publish';
|
|
8
10
|
export interface SafetyHit {
|
|
9
11
|
level: SafetyLevel;
|
|
10
12
|
reason: string;
|
|
@@ -124,6 +126,44 @@ export interface RuntimeBackendEvidence {
|
|
|
124
126
|
note: string;
|
|
125
127
|
truth_status: TruthStatus;
|
|
126
128
|
}
|
|
129
|
+
export interface StudyNoteSection {
|
|
130
|
+
code: string;
|
|
131
|
+
role: string;
|
|
132
|
+
symptom?: string;
|
|
133
|
+
summary?: string;
|
|
134
|
+
truth_status: TruthStatus;
|
|
135
|
+
}
|
|
136
|
+
export interface StudyNote {
|
|
137
|
+
schema: 'yam.study-note.v1';
|
|
138
|
+
problem: StudyNoteSection;
|
|
139
|
+
change: StudyNoteSection;
|
|
140
|
+
why_it_matters: string;
|
|
141
|
+
learning_note: string;
|
|
142
|
+
limits: string[];
|
|
143
|
+
truth_status: TruthStatus;
|
|
144
|
+
}
|
|
145
|
+
export interface LoopStage {
|
|
146
|
+
id: string;
|
|
147
|
+
status: LoopStageStatus;
|
|
148
|
+
note: string;
|
|
149
|
+
truth_status: TruthStatus;
|
|
150
|
+
}
|
|
151
|
+
export interface LoopReport {
|
|
152
|
+
schema: 'yam.loop-report.v1';
|
|
153
|
+
generated_at: string;
|
|
154
|
+
route: string;
|
|
155
|
+
intent: string;
|
|
156
|
+
loop_kind: string;
|
|
157
|
+
stages: LoopStage[];
|
|
158
|
+
evidence: string[];
|
|
159
|
+
blockers: string[];
|
|
160
|
+
truth_status: TruthStatus;
|
|
161
|
+
intent_label: ToolIntent;
|
|
162
|
+
tool_intent: ToolIntent;
|
|
163
|
+
next_action: string;
|
|
164
|
+
remaining_tasks: string[];
|
|
165
|
+
study_note: StudyNote;
|
|
166
|
+
}
|
|
127
167
|
export interface UeyeRunReport {
|
|
128
168
|
schema: 'yam.ueye-run-report.v1';
|
|
129
169
|
reference_sources: UeyeVisualProvenance[];
|
|
@@ -230,6 +270,8 @@ export declare function buildUeyeDesignCompletionGate(input?: Partial<UeyeDesign
|
|
|
230
270
|
export declare function buildRollbackHint(input?: Partial<RollbackHint>): RollbackHint;
|
|
231
271
|
export declare function buildMissionPatchEnvelope(input?: Partial<MissionPatchEnvelope>): MissionPatchEnvelope;
|
|
232
272
|
export declare function buildRuntimeBackendEvidence(input?: Partial<RuntimeBackendEvidence>): RuntimeBackendEvidence;
|
|
273
|
+
export declare function buildStudyNote(input?: Partial<StudyNote> & Record<string, unknown>): StudyNote;
|
|
274
|
+
export declare function buildLoopReport(input?: Partial<LoopReport> & Record<string, unknown>): LoopReport;
|
|
233
275
|
export declare function buildUeyeRunReport(input?: UeyeRunReportInput): UeyeRunReport;
|
|
234
276
|
export declare function buildMediaGenerationProof(input?: Partial<MediaGenerationProof>): MediaGenerationProof;
|
|
235
277
|
export declare function isTruthStatus(value?: unknown): value is TruthStatus;
|