frontend-harness 0.7.9 → 0.8.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/CHANGELOG.md +29 -0
- package/README.md +20 -10
- package/dist/cli/index.js +388 -66
- package/dist/cli/index.js.map +1 -1
- package/dist/runtime/builtin-skills.js +1 -1
- package/dist/runtime/clean.js +25 -3
- package/dist/runtime/clean.js.map +1 -1
- package/dist/runtime/command-taxonomy.js +6 -1
- package/dist/runtime/command-taxonomy.js.map +1 -1
- package/dist/runtime/context.d.ts +33 -2
- package/dist/runtime/context.js +112 -13
- package/dist/runtime/context.js.map +1 -1
- package/dist/runtime/evidence.d.ts +27 -0
- package/dist/runtime/evidence.js +302 -19
- package/dist/runtime/evidence.js.map +1 -1
- package/dist/runtime/graph.js +11 -4
- package/dist/runtime/graph.js.map +1 -1
- package/dist/runtime/ingest.d.ts +38 -0
- package/dist/runtime/ingest.js +157 -0
- package/dist/runtime/ingest.js.map +1 -0
- package/dist/runtime/knowledge/constants.d.ts +9 -0
- package/dist/runtime/knowledge/constants.js +25 -0
- package/dist/runtime/knowledge/constants.js.map +1 -0
- package/dist/runtime/knowledge/core.d.ts +25 -0
- package/dist/runtime/knowledge/core.js +1569 -0
- package/dist/runtime/knowledge/core.js.map +1 -0
- package/dist/runtime/knowledge/types.d.ts +241 -0
- package/dist/runtime/knowledge/types.js +2 -0
- package/dist/runtime/knowledge/types.js.map +1 -0
- package/dist/runtime/knowledge.d.ts +2 -188
- package/dist/runtime/knowledge.js +1 -1126
- package/dist/runtime/knowledge.js.map +1 -1
- package/dist/runtime/plan/component-resolver.js +17 -6
- package/dist/runtime/plan/component-resolver.js.map +1 -1
- package/dist/runtime/plan/guidance.d.ts +1 -1
- package/dist/runtime/plan/guidance.js +88 -25
- package/dist/runtime/plan/guidance.js.map +1 -1
- package/dist/runtime/plan/proposal.js +9 -0
- package/dist/runtime/plan/proposal.js.map +1 -1
- package/dist/runtime/plan/workflow.d.ts +1 -0
- package/dist/runtime/plan/workflow.js +32 -1
- package/dist/runtime/plan/workflow.js.map +1 -1
- package/dist/runtime/plan.d.ts +13 -0
- package/dist/runtime/plan.js +137 -82
- package/dist/runtime/plan.js.map +1 -1
- package/dist/runtime/policy-provenance.d.ts +17 -1
- package/dist/runtime/policy-provenance.js +84 -16
- package/dist/runtime/policy-provenance.js.map +1 -1
- package/dist/runtime/project-discovery.js +32 -17
- package/dist/runtime/project-discovery.js.map +1 -1
- package/dist/runtime/project-paths.js +7 -1
- package/dist/runtime/project-paths.js.map +1 -1
- package/dist/runtime/protocol-init.js +117 -26
- package/dist/runtime/protocol-init.js.map +1 -1
- package/dist/runtime/repair-decision.js +76 -16
- package/dist/runtime/repair-decision.js.map +1 -1
- package/dist/runtime/repair-packet.js +141 -20
- package/dist/runtime/repair-packet.js.map +1 -1
- package/dist/runtime/scaffold/vue-template.js +1 -1
- package/dist/runtime/scaffold/vue-template.js.map +1 -1
- package/dist/runtime/scaffold.js +44 -8
- package/dist/runtime/scaffold.js.map +1 -1
- package/dist/runtime/skills.d.ts +9 -0
- package/dist/runtime/skills.js +133 -18
- package/dist/runtime/skills.js.map +1 -1
- package/dist/runtime/state-explain.js +39 -7
- package/dist/runtime/state-explain.js.map +1 -1
- package/dist/runtime/state.js +85 -10
- package/dist/runtime/state.js.map +1 -1
- package/dist/runtime/task-context.d.ts +122 -0
- package/dist/runtime/task-context.js +1322 -0
- package/dist/runtime/task-context.js.map +1 -0
- package/dist/runtime/task-signals.d.ts +1 -0
- package/dist/runtime/task-signals.js +1 -1
- package/dist/runtime/task-signals.js.map +1 -1
- package/dist/runtime/ui-restoration.d.ts +3 -3
- package/dist/runtime/ui-restoration.js +3 -3
- package/dist/runtime/ui-restoration.js.map +1 -1
- package/dist/runtime/ui-source.d.ts +6 -0
- package/dist/runtime/ui-source.js +66 -0
- package/dist/runtime/ui-source.js.map +1 -0
- package/dist/runtime/units.js +11 -4
- package/dist/runtime/units.js.map +1 -1
- package/dist/runtime/verification-commands.js +95 -21
- package/dist/runtime/verification-commands.js.map +1 -1
- package/dist/runtime/verify.js +129 -43
- package/dist/runtime/verify.js.map +1 -1
- package/dist/runtime/visual-compare.js +104 -12
- package/dist/runtime/visual-compare.js.map +1 -1
- package/dist/schemas/types.d.ts +75 -2
- package/dist/schemas/validation.js +257 -6
- package/dist/schemas/validation.js.map +1 -1
- package/dist/storage/json.d.ts +9 -1
- package/dist/storage/json.js +106 -8
- package/dist/storage/json.js.map +1 -1
- package/docs/DIRECTION.md +13 -11
- package/docs/RELEASE.md +5 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/runtime/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AACvE,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/runtime/context.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,6 +12,13 @@ export interface EvidenceTemplateResult {
|
|
|
12
12
|
generatedAt: string;
|
|
13
13
|
status: "ready" | "not_configured";
|
|
14
14
|
entries: EvidenceManifestEntry[];
|
|
15
|
+
limits: {
|
|
16
|
+
entries: {
|
|
17
|
+
selected: number;
|
|
18
|
+
total: number;
|
|
19
|
+
omitted: number;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
15
22
|
instructions: string[];
|
|
16
23
|
}
|
|
17
24
|
export interface EvidenceRecordResult {
|
|
@@ -20,6 +27,26 @@ export interface EvidenceRecordResult {
|
|
|
20
27
|
manifestPath: string;
|
|
21
28
|
recordedEntries: EvidenceManifestEntry[];
|
|
22
29
|
entryCount: number;
|
|
30
|
+
provenance: EvidenceManifestProvenance;
|
|
31
|
+
}
|
|
32
|
+
export interface EvidenceManifestProvenance {
|
|
33
|
+
planArtifactPath?: string;
|
|
34
|
+
taskContextArtifactPath?: string;
|
|
35
|
+
taskInputs?: {
|
|
36
|
+
prd?: string;
|
|
37
|
+
apiSource?: string;
|
|
38
|
+
uiSource?: unknown;
|
|
39
|
+
agentProposal?: string;
|
|
40
|
+
};
|
|
41
|
+
selectedApiContractSources?: string[];
|
|
42
|
+
selectedUiSources?: string[];
|
|
43
|
+
selectedIngestSources?: string[];
|
|
44
|
+
limits?: {
|
|
45
|
+
selectedEvidenceSources: number;
|
|
46
|
+
omittedSelectedApiContractSources: number;
|
|
47
|
+
omittedSelectedUiSources: number;
|
|
48
|
+
omittedSelectedIngestSources: number;
|
|
49
|
+
};
|
|
23
50
|
}
|
|
24
51
|
export declare function createEvidenceTemplate(projectRoot: string): EvidenceTemplateResult;
|
|
25
52
|
export declare function recordEvidence(projectRoot: string, inputPath: string | undefined): EvidenceRecordResult;
|
package/dist/runtime/evidence.js
CHANGED
|
@@ -1,22 +1,39 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import { readJson, writeJson } from "../storage/json.js";
|
|
4
|
+
import { isRegularFileWithoutSymlink, readJson, writeJson } from "../storage/json.js";
|
|
5
5
|
import { projectScriptCommand } from "./command-taxonomy.js";
|
|
6
6
|
import { isProjectRelativeSubpath, normalizeProjectRelativePath, resolveProjectOrHarnessRelativePath } from "./project-paths.js";
|
|
7
7
|
import { loadState } from "./state.js";
|
|
8
|
+
import { discoverKnowledgeCards } from "./knowledge.js";
|
|
9
|
+
import { externalDesignReference, isGeneratedMarkupExtension, isVisualArtifactExtension } from "./ui-source.js";
|
|
10
|
+
const MAX_EVIDENCE_ARTIFACT_HASH_BYTES = 32 * 1024 * 1024;
|
|
11
|
+
const MAX_EVIDENCE_MANIFEST_BYTES = 2 * 1024 * 1024;
|
|
12
|
+
const EVIDENCE_HASH_CHUNK_BYTES = 64 * 1024;
|
|
13
|
+
const SELECTED_EVIDENCE_SOURCE_LIMIT = 8;
|
|
14
|
+
const EVIDENCE_TEMPLATE_ENTRY_LIMIT = 20;
|
|
15
|
+
const EVIDENCE_ERROR_DETAIL_LIMIT = 20;
|
|
8
16
|
export function createEvidenceTemplate(projectRoot) {
|
|
9
17
|
const manifestPath = ".frontend-harness/verification/evidence.json";
|
|
10
18
|
const requiredEvidence = requiredVerificationEvidence(projectRoot);
|
|
11
19
|
const generatedAt = new Date().toISOString();
|
|
20
|
+
const selectedRequiredEvidence = requiredEvidence.slice(0, EVIDENCE_TEMPLATE_ENTRY_LIMIT);
|
|
12
21
|
return {
|
|
13
22
|
manifestPath,
|
|
14
23
|
generatedAt,
|
|
15
24
|
status: requiredEvidence.length > 0 ? "ready" : "not_configured",
|
|
16
|
-
entries:
|
|
25
|
+
entries: selectedRequiredEvidence.map((required) => evidenceTemplateEntry(projectRoot, required, generatedAt)),
|
|
26
|
+
limits: {
|
|
27
|
+
entries: {
|
|
28
|
+
selected: selectedRequiredEvidence.length,
|
|
29
|
+
total: requiredEvidence.length,
|
|
30
|
+
omitted: Math.max(0, requiredEvidence.length - selectedRequiredEvidence.length)
|
|
31
|
+
}
|
|
32
|
+
},
|
|
17
33
|
instructions: requiredEvidence.length > 0
|
|
18
34
|
? [
|
|
19
35
|
"Use this as a schema template, not as proof.",
|
|
36
|
+
"Template entries are bounded; record real evidence for every required unit evidence kind before verification.",
|
|
20
37
|
"Replace placeholder artifact paths, timestamps, metadata values, and hashes with facts from real source capture, command output, browser/manual inspection, or screenshot comparison.",
|
|
21
38
|
"For design_to_code sources, preserve the generated artifact under .frontend-harness/ and classify usability before copying or mining it for project source; only localize temporary assets when the artifact is used as project source.",
|
|
22
39
|
"For visual-restoration entries, repair project UI when comparison fails before recording a passing verdict."
|
|
@@ -35,7 +52,7 @@ export function recordEvidence(projectRoot, inputPath) {
|
|
|
35
52
|
if (isProjectRelativeSubpath(input.relativePath, ".frontend-harness") && !isProjectRelativeSubpath(input.relativePath, ".frontend-harness/evidence")) {
|
|
36
53
|
throw new Error("evidence input file under .frontend-harness must be stored below .frontend-harness/evidence/.");
|
|
37
54
|
}
|
|
38
|
-
if (!
|
|
55
|
+
if (!isRegularFileWithoutSymlink(input.fullPath)) {
|
|
39
56
|
throw new Error(`evidence input file does not exist: ${input.relativePath}`);
|
|
40
57
|
}
|
|
41
58
|
const submitted = readEvidenceManifest(projectRoot, input.relativePath, { fillMissingCreatedAt: new Date().toISOString() });
|
|
@@ -48,12 +65,12 @@ export function recordEvidence(projectRoot, inputPath) {
|
|
|
48
65
|
const required = requiredVerificationEvidence(projectRoot);
|
|
49
66
|
const unsupported = submitted.entries.filter((entry) => !required.some((candidate) => candidate.unitId === entry.unitId && candidate.kind === entry.kind));
|
|
50
67
|
if (unsupported.length > 0) {
|
|
51
|
-
throw new Error(
|
|
68
|
+
throw new Error(formatBoundedEvidenceError("Evidence input contains entries that are not required by the current plan", unsupported.map((entry) => `${entry.unitId}: ${entry.kind}`), ", "));
|
|
52
69
|
}
|
|
53
70
|
const submittedRequired = submitted.entries.map((entry) => ({ unitId: entry.unitId, kind: entry.kind }));
|
|
54
71
|
const errors = validateEvidenceEntries(projectRoot, submittedRequired, submitted.entries);
|
|
55
72
|
if (errors.length > 0) {
|
|
56
|
-
throw new Error(
|
|
73
|
+
throw new Error(formatBoundedEvidenceError("Evidence input failed validation", errors));
|
|
57
74
|
}
|
|
58
75
|
const manifestPath = ".frontend-harness/verification/evidence.json";
|
|
59
76
|
const existing = readOptionalEvidenceEntries(projectRoot, manifestPath);
|
|
@@ -67,13 +84,55 @@ export function recordEvidence(projectRoot, inputPath) {
|
|
|
67
84
|
next.push(entry);
|
|
68
85
|
}
|
|
69
86
|
}
|
|
70
|
-
|
|
87
|
+
const mergedRequired = next.map((entry) => ({ unitId: entry.unitId, kind: entry.kind }));
|
|
88
|
+
const mergedErrors = validateEvidenceEntries(projectRoot, mergedRequired, next);
|
|
89
|
+
if (mergedErrors.length > 0) {
|
|
90
|
+
throw new Error(formatBoundedEvidenceError("Existing evidence manifest failed validation after merge", mergedErrors));
|
|
91
|
+
}
|
|
92
|
+
const provenance = buildEvidenceManifestProvenance(projectRoot);
|
|
93
|
+
writeJson(path.join(projectRoot, manifestPath), {
|
|
94
|
+
...(Object.keys(provenance).length > 0 ? { provenance } : {}),
|
|
95
|
+
entries: next
|
|
96
|
+
});
|
|
71
97
|
return {
|
|
72
98
|
status: "passed",
|
|
73
99
|
inputPath: input.relativePath,
|
|
74
100
|
manifestPath,
|
|
75
101
|
recordedEntries: submitted.entries,
|
|
76
|
-
entryCount: next.length
|
|
102
|
+
entryCount: next.length,
|
|
103
|
+
provenance
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function formatBoundedEvidenceError(prefix, details, separator = " ") {
|
|
107
|
+
const selected = details.slice(0, EVIDENCE_ERROR_DETAIL_LIMIT);
|
|
108
|
+
const omitted = Math.max(0, details.length - selected.length);
|
|
109
|
+
return `${prefix} (selected: ${selected.length}; total: ${details.length}; omitted: ${omitted}): ${selected.join(separator)}`;
|
|
110
|
+
}
|
|
111
|
+
function buildEvidenceManifestProvenance(projectRoot) {
|
|
112
|
+
const state = loadState(projectRoot);
|
|
113
|
+
const planArtifactPath = ".frontend-harness/plans/latest.json";
|
|
114
|
+
const taskContextArtifactPath = ".frontend-harness/context/task-latest.json";
|
|
115
|
+
const taskInputs = state.task?.inputs;
|
|
116
|
+
const selectedApiContractSources = selectedApiContractEvidenceSources(projectRoot, state);
|
|
117
|
+
const selectedUiSources = selectedUiEvidenceSources(projectRoot, state);
|
|
118
|
+
const selectedIngestSources = selectedIngestEvidenceSources(projectRoot);
|
|
119
|
+
return {
|
|
120
|
+
...(isRegularFileWithoutSymlink(path.join(projectRoot, planArtifactPath)) ? { planArtifactPath } : {}),
|
|
121
|
+
...(isRegularFileWithoutSymlink(path.join(projectRoot, taskContextArtifactPath)) ? { taskContextArtifactPath } : {}),
|
|
122
|
+
...(taskInputs && Object.keys(taskInputs).length > 0 ? { taskInputs } : {}),
|
|
123
|
+
...(selectedApiContractSources.sources.length > 0 ? { selectedApiContractSources: selectedApiContractSources.sources } : {}),
|
|
124
|
+
...(selectedUiSources.sources.length > 0 ? { selectedUiSources: selectedUiSources.sources } : {}),
|
|
125
|
+
...(selectedIngestSources.sources.length > 0 ? { selectedIngestSources: selectedIngestSources.sources } : {}),
|
|
126
|
+
...(selectedApiContractSources.sources.length > 0 || selectedUiSources.sources.length > 0 || selectedIngestSources.sources.length > 0
|
|
127
|
+
? {
|
|
128
|
+
limits: {
|
|
129
|
+
selectedEvidenceSources: SELECTED_EVIDENCE_SOURCE_LIMIT,
|
|
130
|
+
omittedSelectedApiContractSources: selectedApiContractSources.omitted,
|
|
131
|
+
omittedSelectedUiSources: selectedUiSources.omitted,
|
|
132
|
+
omittedSelectedIngestSources: selectedIngestSources.omitted
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
: {})
|
|
77
136
|
};
|
|
78
137
|
}
|
|
79
138
|
export function assertDesignSourceReadyForProjectChanges(projectRoot, files) {
|
|
@@ -90,7 +149,7 @@ export function assertDesignSourceReadyForProjectChanges(projectRoot, files) {
|
|
|
90
149
|
return [normalized];
|
|
91
150
|
}).filter((file) => {
|
|
92
151
|
const fullPath = path.join(projectRoot, file);
|
|
93
|
-
return
|
|
152
|
+
return isRegularFileWithoutSymlink(fullPath);
|
|
94
153
|
});
|
|
95
154
|
if (existingProjectFiles.length === 0) {
|
|
96
155
|
return;
|
|
@@ -143,9 +202,7 @@ export function checkVerificationEvidence(projectRoot) {
|
|
|
143
202
|
}
|
|
144
203
|
function requiredVerificationEvidence(projectRoot) {
|
|
145
204
|
const state = loadState(projectRoot);
|
|
146
|
-
return state.units.flatMap((unit) => [...new Set(unit.verificationEvidence ?? [])]
|
|
147
|
-
.map(evidenceArtifactKind)
|
|
148
|
-
.filter((kind) => Boolean(kind))
|
|
205
|
+
return state.units.flatMap((unit) => [...new Set((unit.verificationEvidence ?? []).map(evidenceArtifactKind).filter((kind) => Boolean(kind)))]
|
|
149
206
|
.map((kind) => ({ unitId: unit.id, kind })));
|
|
150
207
|
}
|
|
151
208
|
function requiresDesignRestorationEvidence(state) {
|
|
@@ -173,22 +230,29 @@ function evidenceArtifactKind(evidence) {
|
|
|
173
230
|
if (normalized.includes("interaction")) {
|
|
174
231
|
return "interaction-smoke";
|
|
175
232
|
}
|
|
233
|
+
if (normalized.includes("api contract") || normalized.includes("api mapping")) {
|
|
234
|
+
return "api-contract-mapping";
|
|
235
|
+
}
|
|
236
|
+
if (normalized.includes("integration test") || normalized.includes("api mock")) {
|
|
237
|
+
return "api-integration-test";
|
|
238
|
+
}
|
|
176
239
|
if (normalized.includes("responsive")) {
|
|
177
240
|
return "responsive-rendering";
|
|
178
241
|
}
|
|
179
242
|
return null;
|
|
180
243
|
}
|
|
181
|
-
function evidenceTemplateEntry(required, createdAt) {
|
|
244
|
+
function evidenceTemplateEntry(projectRoot, required, createdAt) {
|
|
182
245
|
const artifactPath = `.frontend-harness/evidence/${required.unitId}-${required.kind}.md`;
|
|
183
246
|
return {
|
|
184
247
|
unitId: required.unitId,
|
|
185
248
|
kind: required.kind,
|
|
186
249
|
artifactPaths: [artifactPath],
|
|
187
250
|
createdAt,
|
|
188
|
-
metadata: evidenceMetadataTemplate(required.kind)
|
|
251
|
+
metadata: evidenceMetadataTemplate(projectRoot, required.kind)
|
|
189
252
|
};
|
|
190
253
|
}
|
|
191
|
-
function evidenceMetadataTemplate(kind) {
|
|
254
|
+
function evidenceMetadataTemplate(projectRoot, kind) {
|
|
255
|
+
const plannedApiSource = [...plannedApiEvidenceSources(projectRoot)][0] ?? "<plan API source>";
|
|
192
256
|
switch (kind) {
|
|
193
257
|
case "design-source":
|
|
194
258
|
return {
|
|
@@ -248,15 +312,35 @@ function evidenceMetadataTemplate(kind) {
|
|
|
248
312
|
return {
|
|
249
313
|
checkedInteractions: ["<interaction checked>"]
|
|
250
314
|
};
|
|
315
|
+
case "api-contract-mapping":
|
|
316
|
+
return {
|
|
317
|
+
apiSource: plannedApiSource,
|
|
318
|
+
mappedEndpoints: ["METHOD /path"],
|
|
319
|
+
dtoMappings: ["<request or response DTO mapping>"],
|
|
320
|
+
contractShapeChecks: ["<schema, generated type, runtime parser, or fixture shape check>"],
|
|
321
|
+
contractAssumptions: ["<known API assumption or none>"]
|
|
322
|
+
};
|
|
323
|
+
case "api-integration-test":
|
|
324
|
+
return {
|
|
325
|
+
apiSource: plannedApiSource,
|
|
326
|
+
coveredEndpoints: ["METHOD /path"],
|
|
327
|
+
mockStrategy: "<project mock, fixture, or integration boundary>",
|
|
328
|
+
mockedResponses: ["<mocked, fixture, or captured response shape used by the test>"],
|
|
329
|
+
commandOrProcedure: "<test command or manual verification procedure>"
|
|
330
|
+
};
|
|
251
331
|
default:
|
|
252
332
|
return {};
|
|
253
333
|
}
|
|
254
334
|
}
|
|
255
335
|
function readEvidenceManifest(projectRoot, relativePath, options = {}) {
|
|
256
336
|
const fullPath = path.join(projectRoot, relativePath);
|
|
257
|
-
if (!
|
|
337
|
+
if (!isRegularFileWithoutSymlink(fullPath)) {
|
|
258
338
|
return { ok: false, error: `Missing evidence manifest: ${relativePath}.` };
|
|
259
339
|
}
|
|
340
|
+
const stat = fs.statSync(fullPath);
|
|
341
|
+
if (stat.size > MAX_EVIDENCE_MANIFEST_BYTES) {
|
|
342
|
+
return { ok: false, error: `Evidence manifest exceeds ${MAX_EVIDENCE_MANIFEST_BYTES} bytes.` };
|
|
343
|
+
}
|
|
260
344
|
let parsed;
|
|
261
345
|
try {
|
|
262
346
|
parsed = readJson(fullPath);
|
|
@@ -351,13 +435,21 @@ function validateEvidenceEntries(projectRoot, requiredEvidence, entries) {
|
|
|
351
435
|
return errors;
|
|
352
436
|
}
|
|
353
437
|
function validateEvidenceArtifactPath(projectRoot, artifactPath, label, errors) {
|
|
438
|
+
if (artifactPath.includes("\\") || /^[A-Za-z]:/.test(artifactPath)) {
|
|
439
|
+
errors.push(`Evidence artifact for ${label} must be a POSIX-style project-relative path under .frontend-harness/: ${artifactPath}.`);
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
354
442
|
const normalized = path.posix.normalize(artifactPath.replace(/\\/g, "/"));
|
|
355
443
|
if (!normalized.startsWith(".frontend-harness/") || normalized.includes("..") || path.isAbsolute(artifactPath)) {
|
|
356
444
|
errors.push(`Evidence artifact for ${label} must be a project-relative path under .frontend-harness/: ${artifactPath}.`);
|
|
357
445
|
return;
|
|
358
446
|
}
|
|
447
|
+
if (!isAllowedEvidenceArtifactPath(normalized)) {
|
|
448
|
+
errors.push(`Evidence artifact for ${label} must be stored under .frontend-harness/evidence/ or .frontend-harness/visual/: ${artifactPath}.`);
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
359
451
|
const fullPath = path.join(projectRoot, normalized);
|
|
360
|
-
if (!
|
|
452
|
+
if (!isRegularFileWithoutSymlink(fullPath)) {
|
|
361
453
|
errors.push(`Evidence artifact for ${label} does not exist: ${artifactPath}.`);
|
|
362
454
|
}
|
|
363
455
|
}
|
|
@@ -406,6 +498,22 @@ function validateEvidenceMetadata(projectRoot, entry, label, errors) {
|
|
|
406
498
|
requireMetadataObject(metadata, label, errors);
|
|
407
499
|
requireMetadataStringArray(metadata, "checkedInteractions", label, errors);
|
|
408
500
|
break;
|
|
501
|
+
case "api-contract-mapping":
|
|
502
|
+
requireMetadataObject(metadata, label, errors);
|
|
503
|
+
requirePlanApiSource(metadata, projectRoot, label, errors);
|
|
504
|
+
requireMetadataStringArray(metadata, "mappedEndpoints", label, errors);
|
|
505
|
+
requireMetadataStringArray(metadata, "dtoMappings", label, errors);
|
|
506
|
+
requireMetadataStringArray(metadata, "contractShapeChecks", label, errors);
|
|
507
|
+
requireMetadataStringArray(metadata, "contractAssumptions", label, errors);
|
|
508
|
+
break;
|
|
509
|
+
case "api-integration-test":
|
|
510
|
+
requireMetadataObject(metadata, label, errors);
|
|
511
|
+
requirePlanApiSource(metadata, projectRoot, label, errors);
|
|
512
|
+
requireMetadataStringArray(metadata, "coveredEndpoints", label, errors);
|
|
513
|
+
requireMetadataString(metadata, "mockStrategy", label, errors);
|
|
514
|
+
requireMetadataStringArray(metadata, "mockedResponses", label, errors);
|
|
515
|
+
requireMetadataString(metadata, "commandOrProcedure", label, errors);
|
|
516
|
+
break;
|
|
409
517
|
}
|
|
410
518
|
}
|
|
411
519
|
function requireMetadataObject(metadata, label, errors) {
|
|
@@ -427,12 +535,152 @@ function requireMetadataString(metadata, key, label, errors) {
|
|
|
427
535
|
errors.push(`Evidence metadata for ${label} must replace placeholder ${key} with real evidence.`);
|
|
428
536
|
}
|
|
429
537
|
}
|
|
538
|
+
function requirePlanApiSource(metadata, projectRoot, label, errors) {
|
|
539
|
+
requireMetadataString(metadata, "apiSource", label, errors);
|
|
540
|
+
if (!metadata || typeof metadata["apiSource"] !== "string") {
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
const expectedApiSources = plannedApiEvidenceSources(projectRoot);
|
|
544
|
+
const apiSource = normalizeEvidenceSource(metadata["apiSource"]);
|
|
545
|
+
if (expectedApiSources.size > 0 && ![...expectedApiSources].some((source) => sameEvidenceSourceReference(source, apiSource))) {
|
|
546
|
+
errors.push(`Evidence metadata for ${label} must reference planned API source ${[...expectedApiSources].join(" or ")}.`);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
function plannedApiEvidenceSources(projectRoot) {
|
|
550
|
+
const state = loadState(projectRoot);
|
|
551
|
+
const sources = new Set();
|
|
552
|
+
if (state.task?.inputs?.apiSource) {
|
|
553
|
+
sources.add(normalizeEvidenceSource(state.task.inputs.apiSource));
|
|
554
|
+
}
|
|
555
|
+
for (const sourcePath of selectedApiContractEvidenceSources(projectRoot, state).sources) {
|
|
556
|
+
sources.add(normalizeEvidenceSource(sourcePath));
|
|
557
|
+
}
|
|
558
|
+
return sources;
|
|
559
|
+
}
|
|
560
|
+
function selectedApiContractEvidenceSources(projectRoot, state) {
|
|
561
|
+
const sources = new Set();
|
|
562
|
+
const selectedReferences = new Set(state.task?.policyProvenance?.knowledgeReferences ?? []);
|
|
563
|
+
if (!selectedReferences.size) {
|
|
564
|
+
return { sources: [], omitted: 0 };
|
|
565
|
+
}
|
|
566
|
+
for (const card of discoverKnowledgeCards(projectRoot)) {
|
|
567
|
+
if (card.status !== "active" || card.type !== "api_contract" || !selectedReferences.has(card.path)) {
|
|
568
|
+
continue;
|
|
569
|
+
}
|
|
570
|
+
for (const sourcePath of card.sourcePaths) {
|
|
571
|
+
sources.add(normalizeEvidenceSource(sourcePath));
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
return compactSelectedEvidenceSources(sources);
|
|
575
|
+
}
|
|
576
|
+
function selectedUiEvidenceSources(projectRoot, state) {
|
|
577
|
+
const selectedReferences = new Set(state.task?.policyProvenance?.knowledgeReferences ?? []);
|
|
578
|
+
if (!selectedReferences.size) {
|
|
579
|
+
return { sources: [], omitted: 0 };
|
|
580
|
+
}
|
|
581
|
+
const sources = new Set();
|
|
582
|
+
for (const card of discoverKnowledgeCards(projectRoot)) {
|
|
583
|
+
if (card.status !== "active" || !selectedReferences.has(card.path)) {
|
|
584
|
+
continue;
|
|
585
|
+
}
|
|
586
|
+
for (const sourcePath of card.sourcePaths) {
|
|
587
|
+
if (isUiEvidenceSource(sourcePath)) {
|
|
588
|
+
sources.add(normalizeEvidenceSource(sourcePath));
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
return compactSelectedEvidenceSources(sources);
|
|
593
|
+
}
|
|
594
|
+
function selectedIngestEvidenceSources(projectRoot) {
|
|
595
|
+
const taskContextPath = path.join(projectRoot, ".frontend-harness/context/task-latest.json");
|
|
596
|
+
if (!isRegularFileWithoutSymlink(taskContextPath)) {
|
|
597
|
+
return { sources: [], omitted: 0 };
|
|
598
|
+
}
|
|
599
|
+
let context;
|
|
600
|
+
try {
|
|
601
|
+
context = readJson(taskContextPath);
|
|
602
|
+
}
|
|
603
|
+
catch {
|
|
604
|
+
return { sources: [], omitted: 0 };
|
|
605
|
+
}
|
|
606
|
+
if (!context || typeof context !== "object" || Array.isArray(context)) {
|
|
607
|
+
return { sources: [], omitted: 0 };
|
|
608
|
+
}
|
|
609
|
+
const selected = context["selectedIngestSources"];
|
|
610
|
+
if (!Array.isArray(selected)) {
|
|
611
|
+
return { sources: [], omitted: 0 };
|
|
612
|
+
}
|
|
613
|
+
const limits = context["limits"];
|
|
614
|
+
const contextOmittedValue = limits && typeof limits === "object" && !Array.isArray(limits)
|
|
615
|
+
? limits["omittedSelectedIngestSources"]
|
|
616
|
+
: undefined;
|
|
617
|
+
const contextOmitted = typeof contextOmittedValue === "number" && Number.isFinite(contextOmittedValue)
|
|
618
|
+
? Math.max(0, Math.trunc(contextOmittedValue))
|
|
619
|
+
: 0;
|
|
620
|
+
const sources = new Set();
|
|
621
|
+
for (const item of selected) {
|
|
622
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) {
|
|
623
|
+
continue;
|
|
624
|
+
}
|
|
625
|
+
const ingestRef = item["ingestRef"];
|
|
626
|
+
if (typeof ingestRef === "string" && ingestRef.startsWith("ingest://")) {
|
|
627
|
+
sources.add(normalizeEvidenceSource(ingestRef));
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
const compact = compactSelectedEvidenceSources(sources);
|
|
631
|
+
return {
|
|
632
|
+
sources: compact.sources,
|
|
633
|
+
omitted: compact.omitted + contextOmitted
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
function compactSelectedEvidenceSources(sources) {
|
|
637
|
+
const sorted = [...sources].sort();
|
|
638
|
+
const selected = sorted.slice(0, SELECTED_EVIDENCE_SOURCE_LIMIT);
|
|
639
|
+
return {
|
|
640
|
+
sources: selected,
|
|
641
|
+
omitted: Math.max(0, sorted.length - selected.length)
|
|
642
|
+
};
|
|
643
|
+
}
|
|
644
|
+
function isUiEvidenceSource(sourcePath) {
|
|
645
|
+
const normalized = sourcePath.replace(/\\/g, "/").toLowerCase();
|
|
646
|
+
if (normalized.startsWith("ingest://ui-package/")) {
|
|
647
|
+
return true;
|
|
648
|
+
}
|
|
649
|
+
if (/^https?:\/\//.test(normalized)) {
|
|
650
|
+
return externalDesignReference(normalized) !== null;
|
|
651
|
+
}
|
|
652
|
+
const extension = path.extname(normalized);
|
|
653
|
+
if (isGeneratedMarkupExtension(extension)) {
|
|
654
|
+
return true;
|
|
655
|
+
}
|
|
656
|
+
if (isVisualArtifactExtension(extension)) {
|
|
657
|
+
return true;
|
|
658
|
+
}
|
|
659
|
+
return [".json", ".fig", ".sketch"].includes(extension)
|
|
660
|
+
&& /(^|[\\/._-])(design|ui|mockup|wireframe|prototype|screen|screenshot)([\\/._-]|$)/i.test(sourcePath);
|
|
661
|
+
}
|
|
662
|
+
function normalizeEvidenceSource(sourcePath) {
|
|
663
|
+
const normalized = sourcePath.replace(/\\/g, "/");
|
|
664
|
+
const match = /^ingest:\/\/(prd|openapi|ui-package)\/(.+)$/i.exec(normalized);
|
|
665
|
+
if (!match?.[1] || !match[2]) {
|
|
666
|
+
return normalized;
|
|
667
|
+
}
|
|
668
|
+
return `ingest://${match[1].toLowerCase()}/${match[2]}`;
|
|
669
|
+
}
|
|
670
|
+
function sameEvidenceSourceReference(left, right) {
|
|
671
|
+
const normalizedLeft = normalizeEvidenceSource(left);
|
|
672
|
+
const normalizedRight = normalizeEvidenceSource(right);
|
|
673
|
+
if (/^https?:\/\//i.test(normalizedLeft) && /^https?:\/\//i.test(normalizedRight)) {
|
|
674
|
+
return normalizedLeft.toLowerCase() === normalizedRight.toLowerCase();
|
|
675
|
+
}
|
|
676
|
+
return normalizedLeft === normalizedRight;
|
|
677
|
+
}
|
|
430
678
|
function requireDesignToCodeUsability(metadata, label, errors) {
|
|
431
679
|
if (!metadata || metadata["sourceType"] !== "design_to_code") {
|
|
432
680
|
return;
|
|
433
681
|
}
|
|
434
682
|
const usability = metadata["usability"];
|
|
435
|
-
const allowed = ["
|
|
683
|
+
const allowed = ["usable_as_visual_baseline", "usable_for_patch_reference", "usable_as_source", "unusable"];
|
|
436
684
|
if (typeof usability !== "string" || !allowed.includes(usability)) {
|
|
437
685
|
errors.push(`Evidence metadata for ${label} with sourceType design_to_code must include usability of ${allowed.join(", ")}.`);
|
|
438
686
|
}
|
|
@@ -602,22 +850,57 @@ function requireArtifactHashMatch(projectRoot, artifactPath, expectedHash, label
|
|
|
602
850
|
if (!fullPath) {
|
|
603
851
|
return;
|
|
604
852
|
}
|
|
605
|
-
const
|
|
853
|
+
const stat = fs.statSync(fullPath, { throwIfNoEntry: false });
|
|
854
|
+
if (!stat || stat.size > MAX_EVIDENCE_ARTIFACT_HASH_BYTES) {
|
|
855
|
+
errors.push(`Evidence metadata for ${label} cannot verify oversized artifact sha256 for ${artifactPath}; artifact exceeds ${MAX_EVIDENCE_ARTIFACT_HASH_BYTES} bytes.`);
|
|
856
|
+
return;
|
|
857
|
+
}
|
|
858
|
+
const actualHash = sha256File(fullPath);
|
|
606
859
|
if (actualHash.toLowerCase() !== expectedHash.toLowerCase()) {
|
|
607
860
|
errors.push(`Evidence metadata for ${label} must match actual artifact sha256 for ${artifactPath}.`);
|
|
608
861
|
}
|
|
609
862
|
}
|
|
863
|
+
function sha256File(filePath) {
|
|
864
|
+
const hash = createHash("sha256");
|
|
865
|
+
const buffer = Buffer.alloc(EVIDENCE_HASH_CHUNK_BYTES);
|
|
866
|
+
const fd = fs.openSync(filePath, "r");
|
|
867
|
+
try {
|
|
868
|
+
let position = 0;
|
|
869
|
+
while (true) {
|
|
870
|
+
const bytesRead = fs.readSync(fd, buffer, 0, buffer.length, position);
|
|
871
|
+
if (bytesRead === 0) {
|
|
872
|
+
break;
|
|
873
|
+
}
|
|
874
|
+
hash.update(buffer.subarray(0, bytesRead));
|
|
875
|
+
position += bytesRead;
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
finally {
|
|
879
|
+
fs.closeSync(fd);
|
|
880
|
+
}
|
|
881
|
+
return hash.digest("hex");
|
|
882
|
+
}
|
|
610
883
|
function evidenceArtifactFullPath(projectRoot, artifactPath) {
|
|
884
|
+
if (artifactPath.includes("\\") || /^[A-Za-z]:/.test(artifactPath)) {
|
|
885
|
+
return null;
|
|
886
|
+
}
|
|
611
887
|
const normalized = path.posix.normalize(artifactPath.replace(/\\/g, "/"));
|
|
612
888
|
if (!normalized.startsWith(".frontend-harness/") || normalized.includes("..") || path.isAbsolute(artifactPath)) {
|
|
613
889
|
return null;
|
|
614
890
|
}
|
|
891
|
+
if (!isAllowedEvidenceArtifactPath(normalized)) {
|
|
892
|
+
return null;
|
|
893
|
+
}
|
|
615
894
|
const fullPath = path.join(projectRoot, normalized);
|
|
616
|
-
if (!
|
|
895
|
+
if (!isRegularFileWithoutSymlink(fullPath)) {
|
|
617
896
|
return null;
|
|
618
897
|
}
|
|
619
898
|
return fullPath;
|
|
620
899
|
}
|
|
900
|
+
function isAllowedEvidenceArtifactPath(relativePath) {
|
|
901
|
+
return relativePath.startsWith(".frontend-harness/evidence/")
|
|
902
|
+
|| relativePath.startsWith(".frontend-harness/visual/");
|
|
903
|
+
}
|
|
621
904
|
function isSha256(value) {
|
|
622
905
|
return /^[a-f0-9]{64}$/i.test(value);
|
|
623
906
|
}
|