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.
Files changed (98) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +20 -10
  3. package/dist/cli/index.js +388 -66
  4. package/dist/cli/index.js.map +1 -1
  5. package/dist/runtime/builtin-skills.js +1 -1
  6. package/dist/runtime/clean.js +25 -3
  7. package/dist/runtime/clean.js.map +1 -1
  8. package/dist/runtime/command-taxonomy.js +6 -1
  9. package/dist/runtime/command-taxonomy.js.map +1 -1
  10. package/dist/runtime/context.d.ts +33 -2
  11. package/dist/runtime/context.js +112 -13
  12. package/dist/runtime/context.js.map +1 -1
  13. package/dist/runtime/evidence.d.ts +27 -0
  14. package/dist/runtime/evidence.js +302 -19
  15. package/dist/runtime/evidence.js.map +1 -1
  16. package/dist/runtime/graph.js +11 -4
  17. package/dist/runtime/graph.js.map +1 -1
  18. package/dist/runtime/ingest.d.ts +38 -0
  19. package/dist/runtime/ingest.js +157 -0
  20. package/dist/runtime/ingest.js.map +1 -0
  21. package/dist/runtime/knowledge/constants.d.ts +9 -0
  22. package/dist/runtime/knowledge/constants.js +25 -0
  23. package/dist/runtime/knowledge/constants.js.map +1 -0
  24. package/dist/runtime/knowledge/core.d.ts +25 -0
  25. package/dist/runtime/knowledge/core.js +1569 -0
  26. package/dist/runtime/knowledge/core.js.map +1 -0
  27. package/dist/runtime/knowledge/types.d.ts +241 -0
  28. package/dist/runtime/knowledge/types.js +2 -0
  29. package/dist/runtime/knowledge/types.js.map +1 -0
  30. package/dist/runtime/knowledge.d.ts +2 -188
  31. package/dist/runtime/knowledge.js +1 -1126
  32. package/dist/runtime/knowledge.js.map +1 -1
  33. package/dist/runtime/plan/component-resolver.js +17 -6
  34. package/dist/runtime/plan/component-resolver.js.map +1 -1
  35. package/dist/runtime/plan/guidance.d.ts +1 -1
  36. package/dist/runtime/plan/guidance.js +88 -25
  37. package/dist/runtime/plan/guidance.js.map +1 -1
  38. package/dist/runtime/plan/proposal.js +9 -0
  39. package/dist/runtime/plan/proposal.js.map +1 -1
  40. package/dist/runtime/plan/workflow.d.ts +1 -0
  41. package/dist/runtime/plan/workflow.js +32 -1
  42. package/dist/runtime/plan/workflow.js.map +1 -1
  43. package/dist/runtime/plan.d.ts +13 -0
  44. package/dist/runtime/plan.js +137 -82
  45. package/dist/runtime/plan.js.map +1 -1
  46. package/dist/runtime/policy-provenance.d.ts +17 -1
  47. package/dist/runtime/policy-provenance.js +84 -16
  48. package/dist/runtime/policy-provenance.js.map +1 -1
  49. package/dist/runtime/project-discovery.js +32 -17
  50. package/dist/runtime/project-discovery.js.map +1 -1
  51. package/dist/runtime/project-paths.js +7 -1
  52. package/dist/runtime/project-paths.js.map +1 -1
  53. package/dist/runtime/protocol-init.js +117 -26
  54. package/dist/runtime/protocol-init.js.map +1 -1
  55. package/dist/runtime/repair-decision.js +76 -16
  56. package/dist/runtime/repair-decision.js.map +1 -1
  57. package/dist/runtime/repair-packet.js +141 -20
  58. package/dist/runtime/repair-packet.js.map +1 -1
  59. package/dist/runtime/scaffold/vue-template.js +1 -1
  60. package/dist/runtime/scaffold/vue-template.js.map +1 -1
  61. package/dist/runtime/scaffold.js +44 -8
  62. package/dist/runtime/scaffold.js.map +1 -1
  63. package/dist/runtime/skills.d.ts +9 -0
  64. package/dist/runtime/skills.js +133 -18
  65. package/dist/runtime/skills.js.map +1 -1
  66. package/dist/runtime/state-explain.js +39 -7
  67. package/dist/runtime/state-explain.js.map +1 -1
  68. package/dist/runtime/state.js +85 -10
  69. package/dist/runtime/state.js.map +1 -1
  70. package/dist/runtime/task-context.d.ts +122 -0
  71. package/dist/runtime/task-context.js +1322 -0
  72. package/dist/runtime/task-context.js.map +1 -0
  73. package/dist/runtime/task-signals.d.ts +1 -0
  74. package/dist/runtime/task-signals.js +1 -1
  75. package/dist/runtime/task-signals.js.map +1 -1
  76. package/dist/runtime/ui-restoration.d.ts +3 -3
  77. package/dist/runtime/ui-restoration.js +3 -3
  78. package/dist/runtime/ui-restoration.js.map +1 -1
  79. package/dist/runtime/ui-source.d.ts +6 -0
  80. package/dist/runtime/ui-source.js +66 -0
  81. package/dist/runtime/ui-source.js.map +1 -0
  82. package/dist/runtime/units.js +11 -4
  83. package/dist/runtime/units.js.map +1 -1
  84. package/dist/runtime/verification-commands.js +95 -21
  85. package/dist/runtime/verification-commands.js.map +1 -1
  86. package/dist/runtime/verify.js +129 -43
  87. package/dist/runtime/verify.js.map +1 -1
  88. package/dist/runtime/visual-compare.js +104 -12
  89. package/dist/runtime/visual-compare.js.map +1 -1
  90. package/dist/schemas/types.d.ts +75 -2
  91. package/dist/schemas/validation.js +257 -6
  92. package/dist/schemas/validation.js.map +1 -1
  93. package/dist/storage/json.d.ts +9 -1
  94. package/dist/storage/json.js +106 -8
  95. package/dist/storage/json.js.map +1 -1
  96. package/docs/DIRECTION.md +13 -11
  97. package/docs/RELEASE.md +5 -1
  98. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/runtime/context.ts"],"names":[],"mappings":"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"}
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;
@@ -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: requiredEvidence.map((required) => evidenceTemplateEntry(required, generatedAt)),
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 (!fs.existsSync(input.fullPath) || !fs.statSync(input.fullPath).isFile()) {
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(`Evidence input contains entries that are not required by the current plan: ${unsupported.map((entry) => `${entry.unitId}: ${entry.kind}`).join(", ")}.`);
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(`Evidence input failed validation: ${errors.join(" ")}`);
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
- writeJson(path.join(projectRoot, manifestPath), { entries: next });
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 fs.existsSync(fullPath) && fs.statSync(fullPath).isFile();
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 (!fs.existsSync(fullPath)) {
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 (!fs.existsSync(fullPath) || !fs.statSync(fullPath).isFile()) {
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 = ["usable_as_source", "usable_as_visual_baseline", "usable_for_patch_reference", "unusable"];
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 actualHash = createHash("sha256").update(fs.readFileSync(fullPath)).digest("hex");
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 (!fs.existsSync(fullPath) || !fs.statSync(fullPath).isFile()) {
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
  }