@williambeto/ai-workflow 2.9.0 → 2.9.1
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
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
## [unreleased]
|
|
2
2
|
|
|
3
|
+
## [2.9.1] - 2026-07-15
|
|
4
|
+
|
|
5
|
+
### 🐛 Bug Fixes
|
|
6
|
+
|
|
7
|
+
- Accept persisted Playwright snapshots from the scoped delivery as valid UI
|
|
8
|
+
evidence, regardless of their test-directory location
|
|
9
|
+
- Recognize screenshots generated under `.evidence/visual/` and evaluate them
|
|
10
|
+
in the same `collect-evidence` execution that captured them
|
|
11
|
+
- Avoid repeating `NOT_DELIVERED` as a second blocking diagnostic when an
|
|
12
|
+
earlier validation or quality gate already explains the failure
|
|
13
|
+
|
|
14
|
+
### 🧪 Testing
|
|
15
|
+
|
|
16
|
+
- Add regression coverage for Playwright snapshot discovery, generated visual
|
|
17
|
+
evidence ordering, missing required screenshots, and non-duplicated finalizer
|
|
18
|
+
diagnostics
|
|
19
|
+
|
|
3
20
|
## [2.9.0] - 2026-07-15
|
|
4
21
|
|
|
5
22
|
### 🚀 Features
|
package/bin/ai-workflow.js
CHANGED
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
QualityGuard,
|
|
35
35
|
ValidationPlanner,
|
|
36
36
|
parseDeliveryOutcomeClaim
|
|
37
|
-
} from "../chunk-
|
|
37
|
+
} from "../chunk-PP42PB7M.js";
|
|
38
38
|
import {
|
|
39
39
|
DeliveryDecisionEngine
|
|
40
40
|
} from "../chunk-H7GIKXFO.js";
|
|
@@ -3697,7 +3697,7 @@ var commandMap = {
|
|
|
3697
3697
|
});
|
|
3698
3698
|
},
|
|
3699
3699
|
validate: async (_, flags) => {
|
|
3700
|
-
const { runValidate } = await import("../validate-
|
|
3700
|
+
const { runValidate } = await import("../validate-7G3HBE2K.js");
|
|
3701
3701
|
await runValidate({
|
|
3702
3702
|
cwd: process.cwd(),
|
|
3703
3703
|
taskSlug: flags.taskSlug,
|
|
@@ -25,6 +25,9 @@ function parseStatusLine(line) {
|
|
|
25
25
|
function isManagedChangePath(file = "") {
|
|
26
26
|
return /(^|\/)(node_modules|vendor|dist|coverage|\.cache)(\/|$)/.test(normalizePath(file));
|
|
27
27
|
}
|
|
28
|
+
function isScreenshotPath(file = "") {
|
|
29
|
+
return /\.(png|jpe?g|webp)$/i.test(normalizePath(file));
|
|
30
|
+
}
|
|
28
31
|
async function exists(target) {
|
|
29
32
|
try {
|
|
30
33
|
await fs.access(target);
|
|
@@ -163,17 +166,22 @@ var QualityGuard = class {
|
|
|
163
166
|
}
|
|
164
167
|
async verifyUiEvidence() {
|
|
165
168
|
if (!this.isUiTask()) return { status: "NOT_RUN", reason: "Non-UI task." };
|
|
166
|
-
const candidates = ["docs", "screenshots", "evidence"];
|
|
167
|
-
const found =
|
|
169
|
+
const candidates = ["docs", "screenshots", "evidence", ".evidence"];
|
|
170
|
+
const found = /* @__PURE__ */ new Set();
|
|
171
|
+
for (const file of this.getScopedChangedFiles()) {
|
|
172
|
+
const normalized = normalizePath(file);
|
|
173
|
+
if (!isScreenshotPath(normalized) || path.isAbsolute(normalized) || normalized.startsWith("../")) continue;
|
|
174
|
+
if (await exists(path.join(this.cwd, normalized))) found.add(normalized);
|
|
175
|
+
}
|
|
168
176
|
for (const dir of candidates) {
|
|
169
177
|
const root = path.join(this.cwd, dir);
|
|
170
178
|
if (!await exists(root)) continue;
|
|
171
179
|
const entries = await fs.readdir(root, { recursive: true }).catch(() => []);
|
|
172
180
|
for (const entry of entries) {
|
|
173
|
-
if (
|
|
181
|
+
if (isScreenshotPath(String(entry))) found.add(normalizePath(path.join(dir, String(entry))));
|
|
174
182
|
}
|
|
175
183
|
}
|
|
176
|
-
if (found.
|
|
184
|
+
if (found.size) return { status: "PASS", screenshots: [...found].sort().slice(0, 20) };
|
|
177
185
|
if (this.evidencePolicy === "required") {
|
|
178
186
|
return { status: "FAIL_QUALITY_GATE", reason: "Required evidence for a high-risk or release UI change does not include a persisted screenshot." };
|
|
179
187
|
}
|
|
@@ -673,6 +681,26 @@ var EvidenceCollector = class {
|
|
|
673
681
|
const implementationFilesPresent = qualityGuard.isImplementationTask();
|
|
674
682
|
const executableBehavior = await qualityGuard.hasExecutableBehaviorChanges(this.deliveryChangedFiles || void 0);
|
|
675
683
|
const results = tasks.map((task) => this.runTask(task));
|
|
684
|
+
let visualEvidence = null;
|
|
685
|
+
if (this.visualDist) {
|
|
686
|
+
console.log(`
|
|
687
|
+
--- Capturing Visual Evidence ---`);
|
|
688
|
+
console.log(`Serving ${this.visualDist} on port ${this.port}...`);
|
|
689
|
+
try {
|
|
690
|
+
const verifier = new VisualVerifier({ cwd: this.cwd, visualDist: this.visualDist, port: this.port });
|
|
691
|
+
const screenshots = await verifier.captureScreenshots();
|
|
692
|
+
visualEvidence = {
|
|
693
|
+
desktop: path3.relative(this.cwd, screenshots[0]),
|
|
694
|
+
mobile: path3.relative(this.cwd, screenshots[1])
|
|
695
|
+
};
|
|
696
|
+
console.log(`Visual evidence captured successfully:`);
|
|
697
|
+
console.log(`- Desktop: ${visualEvidence.desktop}`);
|
|
698
|
+
console.log(`- Mobile: ${visualEvidence.mobile}`);
|
|
699
|
+
} catch (err) {
|
|
700
|
+
console.error(`Error capturing visual evidence: ${err.message}`);
|
|
701
|
+
throw err;
|
|
702
|
+
}
|
|
703
|
+
}
|
|
676
704
|
const policyValidation = await qualityGuard.verify();
|
|
677
705
|
const behaviorTests = results.filter((result) => result.kind === "test");
|
|
678
706
|
const passingBehaviorTest = behaviorTests.some((result) => result.status === "PASS");
|
|
@@ -745,7 +773,8 @@ var EvidenceCollector = class {
|
|
|
745
773
|
deliveryDecision: deliveryDecision.decision,
|
|
746
774
|
claimedOutcome: this.claimedOutcome
|
|
747
775
|
});
|
|
748
|
-
|
|
776
|
+
const deliveryOutcomeBlocks = ["NEEDS_CLARIFICATION", "NOT_DELIVERED"].includes(deliveryOutcome) && ["PASS", "PASS_WITH_NOTES"].includes(overallStatus);
|
|
777
|
+
if (deliveryOutcomeBlocks) {
|
|
749
778
|
overallStatus = "BLOCKED";
|
|
750
779
|
}
|
|
751
780
|
const limitations = [];
|
|
@@ -811,7 +840,7 @@ var EvidenceCollector = class {
|
|
|
811
840
|
"satisfy the stated decision requirement before finalizing"
|
|
812
841
|
));
|
|
813
842
|
}
|
|
814
|
-
if (
|
|
843
|
+
if (deliveryOutcomeBlocks) {
|
|
815
844
|
limitations.push(blockingDiagnostic(
|
|
816
845
|
"delivery-outcome",
|
|
817
846
|
`the resolved outcome is ${deliveryOutcome}`,
|
|
@@ -820,26 +849,6 @@ var EvidenceCollector = class {
|
|
|
820
849
|
));
|
|
821
850
|
}
|
|
822
851
|
const uniqueLimitations = [...new Set(limitations)];
|
|
823
|
-
let visualEvidence = null;
|
|
824
|
-
if (this.visualDist) {
|
|
825
|
-
console.log(`
|
|
826
|
-
--- Capturing Visual Evidence ---`);
|
|
827
|
-
console.log(`Serving ${this.visualDist} on port ${this.port}...`);
|
|
828
|
-
try {
|
|
829
|
-
const verifier = new VisualVerifier({ cwd: this.cwd, visualDist: this.visualDist, port: this.port });
|
|
830
|
-
const screenshots = await verifier.captureScreenshots();
|
|
831
|
-
visualEvidence = {
|
|
832
|
-
desktop: path3.relative(this.cwd, screenshots[0]),
|
|
833
|
-
mobile: path3.relative(this.cwd, screenshots[1])
|
|
834
|
-
};
|
|
835
|
-
console.log(`Visual evidence captured successfully:`);
|
|
836
|
-
console.log(`- Desktop: ${visualEvidence.desktop}`);
|
|
837
|
-
console.log(`- Mobile: ${visualEvidence.mobile}`);
|
|
838
|
-
} catch (err) {
|
|
839
|
-
console.error(`Error capturing visual evidence: ${err.message}`);
|
|
840
|
-
throw err;
|
|
841
|
-
}
|
|
842
|
-
}
|
|
843
852
|
const evidence = {
|
|
844
853
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
845
854
|
taskSlug: this.taskSlug,
|
|
@@ -1053,4 +1062,4 @@ export {
|
|
|
1053
1062
|
EvidenceCollector,
|
|
1054
1063
|
ValidationPlanner
|
|
1055
1064
|
};
|
|
1056
|
-
//# sourceMappingURL=chunk-
|
|
1065
|
+
//# sourceMappingURL=chunk-PP42PB7M.js.map
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
QualityGuard,
|
|
4
4
|
ValidationPlanner,
|
|
5
5
|
VisualVerifier
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-PP42PB7M.js";
|
|
7
7
|
import "./chunk-H7GIKXFO.js";
|
|
8
8
|
import "./chunk-5WRI5ZAA.js";
|
|
9
9
|
|
|
@@ -86,4 +86,4 @@ async function runValidate({
|
|
|
86
86
|
export {
|
|
87
87
|
runValidate
|
|
88
88
|
};
|
|
89
|
-
//# sourceMappingURL=validate-
|
|
89
|
+
//# sourceMappingURL=validate-7G3HBE2K.js.map
|