frontend-harness 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +48 -0
- package/CLAUDE.md +48 -0
- package/README.md +262 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +380 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/runtime/builtin-skills.d.ts +6 -0
- package/dist/runtime/builtin-skills.js +269 -0
- package/dist/runtime/builtin-skills.js.map +1 -0
- package/dist/runtime/clean.d.ts +11 -0
- package/dist/runtime/clean.js +85 -0
- package/dist/runtime/clean.js.map +1 -0
- package/dist/runtime/command-taxonomy.d.ts +12 -0
- package/dist/runtime/command-taxonomy.js +72 -0
- package/dist/runtime/command-taxonomy.js.map +1 -0
- package/dist/runtime/context.d.ts +71 -0
- package/dist/runtime/context.js +153 -0
- package/dist/runtime/context.js.map +1 -0
- package/dist/runtime/graph.d.ts +12 -0
- package/dist/runtime/graph.js +211 -0
- package/dist/runtime/graph.js.map +1 -0
- package/dist/runtime/knowledge.d.ts +48 -0
- package/dist/runtime/knowledge.js +383 -0
- package/dist/runtime/knowledge.js.map +1 -0
- package/dist/runtime/plan.d.ts +18 -0
- package/dist/runtime/plan.js +571 -0
- package/dist/runtime/plan.js.map +1 -0
- package/dist/runtime/policy-provenance.d.ts +17 -0
- package/dist/runtime/policy-provenance.js +195 -0
- package/dist/runtime/policy-provenance.js.map +1 -0
- package/dist/runtime/project-discovery.d.ts +17 -0
- package/dist/runtime/project-discovery.js +166 -0
- package/dist/runtime/project-discovery.js.map +1 -0
- package/dist/runtime/project-paths.d.ts +6 -0
- package/dist/runtime/project-paths.js +47 -0
- package/dist/runtime/project-paths.js.map +1 -0
- package/dist/runtime/protocol-init.d.ts +50 -0
- package/dist/runtime/protocol-init.js +256 -0
- package/dist/runtime/protocol-init.js.map +1 -0
- package/dist/runtime/repair-decision.d.ts +3 -0
- package/dist/runtime/repair-decision.js +195 -0
- package/dist/runtime/repair-decision.js.map +1 -0
- package/dist/runtime/repair-packet.d.ts +7 -0
- package/dist/runtime/repair-packet.js +159 -0
- package/dist/runtime/repair-packet.js.map +1 -0
- package/dist/runtime/skills.d.ts +19 -0
- package/dist/runtime/skills.js +230 -0
- package/dist/runtime/skills.js.map +1 -0
- package/dist/runtime/state-explain.d.ts +2 -0
- package/dist/runtime/state-explain.js +106 -0
- package/dist/runtime/state-explain.js.map +1 -0
- package/dist/runtime/state.d.ts +10 -0
- package/dist/runtime/state.js +237 -0
- package/dist/runtime/state.js.map +1 -0
- package/dist/runtime/units.d.ts +10 -0
- package/dist/runtime/units.js +181 -0
- package/dist/runtime/units.js.map +1 -0
- package/dist/runtime/verification-commands.d.ts +11 -0
- package/dist/runtime/verification-commands.js +89 -0
- package/dist/runtime/verification-commands.js.map +1 -0
- package/dist/runtime/verify.d.ts +7 -0
- package/dist/runtime/verify.js +192 -0
- package/dist/runtime/verify.js.map +1 -0
- package/dist/schemas/types.d.ts +244 -0
- package/dist/schemas/types.js +2 -0
- package/dist/schemas/types.js.map +1 -0
- package/dist/schemas/validation.d.ts +2 -0
- package/dist/schemas/validation.js +21 -0
- package/dist/schemas/validation.js.map +1 -0
- package/dist/storage/json.d.ts +5 -0
- package/dist/storage/json.js +24 -0
- package/dist/storage/json.js.map +1 -0
- package/dist/storage/paths.d.ts +3 -0
- package/dist/storage/paths.js +9 -0
- package/dist/storage/paths.js.map +1 -0
- package/docs/DIRECTION.md +67 -0
- package/package.json +35 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type UnitCheckStatus = "passed" | "failed" | "not_configured";
|
|
2
|
+
export interface UnitCheckResult {
|
|
3
|
+
status: UnitCheckStatus;
|
|
4
|
+
artifactPath: string;
|
|
5
|
+
unitCount: number;
|
|
6
|
+
independentUnitIds: string[];
|
|
7
|
+
errors: string[];
|
|
8
|
+
warnings: string[];
|
|
9
|
+
}
|
|
10
|
+
export declare function checkExecutionUnits(projectRoot: string): UnitCheckResult;
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { relativeHarnessPath } from "../storage/paths.js";
|
|
4
|
+
import { discoverVerificationCommands, defaultVerificationCommandNames } from "./verification-commands.js";
|
|
5
|
+
const policyVerificationNames = [
|
|
6
|
+
"targeted test",
|
|
7
|
+
"regression test",
|
|
8
|
+
"integration test or API mock",
|
|
9
|
+
"affected regression test",
|
|
10
|
+
"knowledge review"
|
|
11
|
+
];
|
|
12
|
+
export function checkExecutionUnits(projectRoot) {
|
|
13
|
+
const artifactPath = relativeHarnessPath("execution-units", "latest.json");
|
|
14
|
+
const fullPath = path.join(projectRoot, artifactPath);
|
|
15
|
+
if (!fs.existsSync(fullPath)) {
|
|
16
|
+
return {
|
|
17
|
+
status: "not_configured",
|
|
18
|
+
artifactPath,
|
|
19
|
+
unitCount: 0,
|
|
20
|
+
independentUnitIds: [],
|
|
21
|
+
errors: [],
|
|
22
|
+
warnings: ["Run frontend-harness plan before checking execution units."]
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
const errors = [];
|
|
26
|
+
const warnings = [];
|
|
27
|
+
const knownVerificationNames = new Set([
|
|
28
|
+
...defaultVerificationCommandNames,
|
|
29
|
+
...policyVerificationNames,
|
|
30
|
+
...discoverVerificationCommands(projectRoot)
|
|
31
|
+
.filter((command) => command.command)
|
|
32
|
+
.map((command) => command.name)
|
|
33
|
+
]);
|
|
34
|
+
const artifact = readArtifact(fullPath, errors);
|
|
35
|
+
const units = getUnits(artifact, errors);
|
|
36
|
+
const ids = new Set();
|
|
37
|
+
const duplicateIds = new Set();
|
|
38
|
+
for (const [index, unit] of units.entries()) {
|
|
39
|
+
if (!isRecord(unit)) {
|
|
40
|
+
errors.push(`units[${index}] must be an object.`);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
const id = validateId(unit, index, errors);
|
|
44
|
+
if (id) {
|
|
45
|
+
if (ids.has(id)) {
|
|
46
|
+
duplicateIds.add(id);
|
|
47
|
+
}
|
|
48
|
+
ids.add(id);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
for (const duplicateId of duplicateIds) {
|
|
52
|
+
errors.push(`Duplicate execution unit id: ${duplicateId}.`);
|
|
53
|
+
}
|
|
54
|
+
for (const [index, unit] of units.entries()) {
|
|
55
|
+
if (!isRecord(unit)) {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
validateUnit(unit, index, ids, knownVerificationNames, errors);
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
status: errors.length > 0 ? "failed" : "passed",
|
|
62
|
+
artifactPath,
|
|
63
|
+
unitCount: units.length,
|
|
64
|
+
independentUnitIds: findIndependentUnitIds(units),
|
|
65
|
+
errors,
|
|
66
|
+
warnings
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function readArtifact(fullPath, errors) {
|
|
70
|
+
try {
|
|
71
|
+
return JSON.parse(fs.readFileSync(fullPath, "utf8"));
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
75
|
+
errors.push(`Execution unit artifact is not valid JSON: ${message}`);
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function getUnits(artifact, errors) {
|
|
80
|
+
if (!isRecord(artifact)) {
|
|
81
|
+
errors.push("Execution unit artifact root must be an object.");
|
|
82
|
+
return [];
|
|
83
|
+
}
|
|
84
|
+
if (!Array.isArray(artifact["units"])) {
|
|
85
|
+
errors.push("Execution unit artifact must contain a units array.");
|
|
86
|
+
return [];
|
|
87
|
+
}
|
|
88
|
+
return artifact["units"];
|
|
89
|
+
}
|
|
90
|
+
function validateUnit(unit, index, ids, knownVerificationNames, errors) {
|
|
91
|
+
validateFile(unit, index, errors);
|
|
92
|
+
validateTask(unit, index, errors);
|
|
93
|
+
validateVerification(unit, index, knownVerificationNames, errors);
|
|
94
|
+
validateDependsOn(unit, index, ids, errors);
|
|
95
|
+
validateParallelGroup(unit, index, errors);
|
|
96
|
+
}
|
|
97
|
+
function validateId(unit, index, errors) {
|
|
98
|
+
if (typeof unit.id !== "string" || !unit.id.trim()) {
|
|
99
|
+
errors.push(`units[${index}].id must be a non-empty string.`);
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
return unit.id;
|
|
103
|
+
}
|
|
104
|
+
function validateFile(unit, index, errors) {
|
|
105
|
+
if (typeof unit.file !== "string" || !unit.file.trim()) {
|
|
106
|
+
errors.push(`units[${index}].file must be a non-empty project-relative path.`);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (!isProjectRelativeSourcePath(unit.file)) {
|
|
110
|
+
errors.push(`units[${index}].file must be project-relative and outside generated harness directories.`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function validateTask(unit, index, errors) {
|
|
114
|
+
if (typeof unit.task !== "string" || !unit.task.trim()) {
|
|
115
|
+
errors.push(`units[${index}].task must be a non-empty string.`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function validateVerification(unit, index, knownVerificationNames, errors) {
|
|
119
|
+
if (!Array.isArray(unit.verification) || unit.verification.length === 0) {
|
|
120
|
+
errors.push(`units[${index}].verification must contain at least one known verification name.`);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
for (const [verificationIndex, verification] of unit.verification.entries()) {
|
|
124
|
+
if (typeof verification !== "string" || !knownVerificationNames.has(verification)) {
|
|
125
|
+
errors.push(`units[${index}].verification[${verificationIndex}] must be one of: ${[...knownVerificationNames].join(", ")}.`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
function validateDependsOn(unit, index, ids, errors) {
|
|
130
|
+
if (!Array.isArray(unit.dependsOn)) {
|
|
131
|
+
errors.push(`units[${index}].dependsOn must be an array.`);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const id = typeof unit.id === "string" ? unit.id : null;
|
|
135
|
+
for (const [dependencyIndex, dependency] of unit.dependsOn.entries()) {
|
|
136
|
+
if (typeof dependency !== "string" || !dependency.trim()) {
|
|
137
|
+
errors.push(`units[${index}].dependsOn[${dependencyIndex}] must be a non-empty unit id.`);
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
if (dependency === id) {
|
|
141
|
+
errors.push(`units[${index}].dependsOn[${dependencyIndex}] cannot reference the same unit.`);
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
if (!ids.has(dependency)) {
|
|
145
|
+
errors.push(`units[${index}].dependsOn[${dependencyIndex}] references unknown unit id: ${dependency}.`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function validateParallelGroup(unit, index, errors) {
|
|
150
|
+
if (unit.parallelGroup === null) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
if (typeof unit.parallelGroup !== "string" || !unit.parallelGroup.trim()) {
|
|
154
|
+
errors.push(`units[${index}].parallelGroup must be null or a non-empty string.`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
function findIndependentUnitIds(units) {
|
|
158
|
+
return units
|
|
159
|
+
.filter(isRecord)
|
|
160
|
+
.filter((unit) => Array.isArray(unit["dependsOn"]) && unit["dependsOn"].length === 0)
|
|
161
|
+
.map((unit) => unit["id"])
|
|
162
|
+
.filter((id) => typeof id === "string" && Boolean(id.trim()));
|
|
163
|
+
}
|
|
164
|
+
function isProjectRelativeSourcePath(file) {
|
|
165
|
+
if (path.isAbsolute(file) || file.startsWith("/")) {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
const normalized = path.posix.normalize(file.replace(/\\/g, "/"));
|
|
169
|
+
if (!normalized || normalized === "." || normalized === ".." || normalized.startsWith("../")) {
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
if (normalized.startsWith("/") || /^[a-zA-Z]:\//.test(normalized)) {
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
const firstSegment = normalized.split("/")[0];
|
|
176
|
+
return firstSegment !== ".frontend-harness" && firstSegment !== ".omx";
|
|
177
|
+
}
|
|
178
|
+
function isRecord(value) {
|
|
179
|
+
return typeof value === "object" && value !== null;
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=units.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"units.js","sourceRoot":"","sources":["../../src/runtime/units.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare const defaultVerificationCommandNames: readonly ["typecheck", "test", "build"];
|
|
2
|
+
export type DefaultVerificationCommandName = typeof defaultVerificationCommandNames[number];
|
|
3
|
+
export type VerificationCommandName = DefaultVerificationCommandName | string;
|
|
4
|
+
export type VerificationCommandSource = "flag" | "config" | "package" | "none";
|
|
5
|
+
export type VerificationCommandOverrides = Partial<Record<DefaultVerificationCommandName, string>>;
|
|
6
|
+
export interface VerificationCommandDiscovery {
|
|
7
|
+
name: VerificationCommandName;
|
|
8
|
+
source: VerificationCommandSource;
|
|
9
|
+
command: string | null;
|
|
10
|
+
}
|
|
11
|
+
export declare function discoverVerificationCommands(projectRoot: string, overrides?: VerificationCommandOverrides): VerificationCommandDiscovery[];
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { harnessPath } from "../storage/paths.js";
|
|
4
|
+
import { readJson } from "../storage/json.js";
|
|
5
|
+
export const defaultVerificationCommandNames = ["typecheck", "test", "build"];
|
|
6
|
+
export function discoverVerificationCommands(projectRoot, overrides = {}) {
|
|
7
|
+
const config = readJson(harnessPath(projectRoot, "config.json")) ?? {};
|
|
8
|
+
const scripts = readPackageScripts(projectRoot);
|
|
9
|
+
const commands = defaultVerificationCommandNames.map((name) => {
|
|
10
|
+
const overrideCommand = overrides[name];
|
|
11
|
+
if (overrideCommand) {
|
|
12
|
+
return {
|
|
13
|
+
name,
|
|
14
|
+
source: "flag",
|
|
15
|
+
command: overrideCommand
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
const configCommand = config.verification?.[name];
|
|
19
|
+
if (configCommand) {
|
|
20
|
+
return {
|
|
21
|
+
name,
|
|
22
|
+
source: "config",
|
|
23
|
+
command: configCommand
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
if (scripts[name]) {
|
|
27
|
+
return {
|
|
28
|
+
name,
|
|
29
|
+
source: "package",
|
|
30
|
+
command: `npm run ${name}`
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
name,
|
|
35
|
+
source: "none",
|
|
36
|
+
command: null
|
|
37
|
+
};
|
|
38
|
+
});
|
|
39
|
+
const customCommands = readCustomConfigCommands(config);
|
|
40
|
+
const defaultNames = new Set(defaultVerificationCommandNames);
|
|
41
|
+
const configuredNames = new Set(commands.map((entry) => entry.name));
|
|
42
|
+
for (const customCommand of customCommands) {
|
|
43
|
+
if (defaultNames.has(customCommand.name) || configuredNames.has(customCommand.name)) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
commands.push(customCommand);
|
|
47
|
+
configuredNames.add(customCommand.name);
|
|
48
|
+
}
|
|
49
|
+
return commands;
|
|
50
|
+
}
|
|
51
|
+
function readCustomConfigCommands(config) {
|
|
52
|
+
if (!Array.isArray(config.verification?.commands)) {
|
|
53
|
+
return [];
|
|
54
|
+
}
|
|
55
|
+
const commands = [];
|
|
56
|
+
const names = new Set();
|
|
57
|
+
for (const entry of config.verification.commands) {
|
|
58
|
+
if (!isRecord(entry)) {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
const name = typeof entry["name"] === "string" ? entry["name"].trim() : "";
|
|
62
|
+
const command = typeof entry["command"] === "string" ? entry["command"].trim() : "";
|
|
63
|
+
if (!isValidCommandName(name) || !command || names.has(name)) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
commands.push({
|
|
67
|
+
name,
|
|
68
|
+
source: "config",
|
|
69
|
+
command
|
|
70
|
+
});
|
|
71
|
+
names.add(name);
|
|
72
|
+
}
|
|
73
|
+
return commands;
|
|
74
|
+
}
|
|
75
|
+
function readPackageScripts(projectRoot) {
|
|
76
|
+
const packageJsonPath = path.join(projectRoot, "package.json");
|
|
77
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
78
|
+
return {};
|
|
79
|
+
}
|
|
80
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
81
|
+
return packageJson.scripts ?? {};
|
|
82
|
+
}
|
|
83
|
+
function isValidCommandName(value) {
|
|
84
|
+
return /^[a-zA-Z0-9][a-zA-Z0-9:_-]{0,79}$/.test(value);
|
|
85
|
+
}
|
|
86
|
+
function isRecord(value) {
|
|
87
|
+
return typeof value === "object" && value !== null;
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=verification-commands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verification-commands.js","sourceRoot":"","sources":["../../src/runtime/verification-commands.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import process from "node:process";
|
|
5
|
+
import { harnessPath } from "../storage/paths.js";
|
|
6
|
+
import { ensureDir, readJson, writeJson, writeText } from "../storage/json.js";
|
|
7
|
+
import { updateVerificationState } from "./state.js";
|
|
8
|
+
import { discoverVerificationCommands } from "./verification-commands.js";
|
|
9
|
+
import { createRepairPacket } from "./repair-packet.js";
|
|
10
|
+
export function runVerification(projectRoot, options) {
|
|
11
|
+
const commands = resolveCommands(projectRoot, options);
|
|
12
|
+
const startedFromFailed = readPreviousStatus(projectRoot) === "failed";
|
|
13
|
+
if (commands.length === 0) {
|
|
14
|
+
const result = {
|
|
15
|
+
status: "not_configured",
|
|
16
|
+
results: [
|
|
17
|
+
{
|
|
18
|
+
name: "verification",
|
|
19
|
+
command: null,
|
|
20
|
+
source: "none",
|
|
21
|
+
status: "not_configured",
|
|
22
|
+
exitCode: null,
|
|
23
|
+
durationMs: 0,
|
|
24
|
+
logPath: null
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
retryGuidance: null
|
|
28
|
+
};
|
|
29
|
+
writeResult(projectRoot, result);
|
|
30
|
+
updateVerificationState(projectRoot, "not_configured", startedFromFailed);
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
33
|
+
const results = commands.map(({ name, source, command }) => runCommand(projectRoot, name, source, command));
|
|
34
|
+
const failed = results.filter((result) => result.status === "failed" || result.status === "error");
|
|
35
|
+
const status = failed.length > 0 ? "failed" : "passed";
|
|
36
|
+
const result = {
|
|
37
|
+
status,
|
|
38
|
+
results,
|
|
39
|
+
retryGuidance: failed.length > 0
|
|
40
|
+
? {
|
|
41
|
+
summary: `${failed.map((item) => item.name).join(", ")} failed`,
|
|
42
|
+
failedCommands: failed.map((item) => item.command).filter((command) => Boolean(command)),
|
|
43
|
+
logs: failed.map((item) => item.logPath).filter((logPath) => Boolean(logPath)),
|
|
44
|
+
nextAgentInstruction: [
|
|
45
|
+
"Read .frontend-harness/verification/latest.json and the failed command logs.",
|
|
46
|
+
"Patch the relevant project files without changing generated harness artifacts.",
|
|
47
|
+
"Record newly changed files with frontend-harness state record-change <file>.",
|
|
48
|
+
"Rerun frontend-harness verify --json until verification passes."
|
|
49
|
+
].join(" ")
|
|
50
|
+
}
|
|
51
|
+
: null
|
|
52
|
+
};
|
|
53
|
+
writeResult(projectRoot, result);
|
|
54
|
+
updateVerificationState(projectRoot, status, startedFromFailed);
|
|
55
|
+
if (status === "failed") {
|
|
56
|
+
createRepairPacket(projectRoot, { verification: result });
|
|
57
|
+
}
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
function resolveCommands(projectRoot, options) {
|
|
61
|
+
return discoverVerificationCommands(projectRoot, options)
|
|
62
|
+
.flatMap((entry) => entry.command ? [{ name: entry.name, source: entry.source, command: entry.command }] : []);
|
|
63
|
+
}
|
|
64
|
+
function runCommand(projectRoot, name, source, command) {
|
|
65
|
+
const started = Date.now();
|
|
66
|
+
const stamp = new Date().toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
|
|
67
|
+
const relativeLogPath = `.frontend-harness/logs/${name}-${stamp}.log`;
|
|
68
|
+
const logPath = path.join(projectRoot, relativeLogPath);
|
|
69
|
+
ensureDir(path.dirname(logPath));
|
|
70
|
+
const result = spawnVerificationCommand(projectRoot, command);
|
|
71
|
+
const durationMs = Date.now() - started;
|
|
72
|
+
const output = [
|
|
73
|
+
`$ ${command}`,
|
|
74
|
+
"",
|
|
75
|
+
"## stdout",
|
|
76
|
+
result.stdout ?? "",
|
|
77
|
+
"## stderr",
|
|
78
|
+
result.stderr ?? ""
|
|
79
|
+
].join("\n");
|
|
80
|
+
writeText(logPath, output);
|
|
81
|
+
const commandLaunchError = result.error
|
|
82
|
+
|| (result.status !== 0
|
|
83
|
+
&& /not found|not recognized|command not found/i.test(`${result.stderr ?? ""}\n${result.stdout ?? ""}`));
|
|
84
|
+
if (commandLaunchError) {
|
|
85
|
+
return {
|
|
86
|
+
name,
|
|
87
|
+
command,
|
|
88
|
+
source,
|
|
89
|
+
status: "error",
|
|
90
|
+
exitCode: null,
|
|
91
|
+
durationMs,
|
|
92
|
+
logPath: relativeLogPath
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
name,
|
|
97
|
+
command,
|
|
98
|
+
source,
|
|
99
|
+
status: result.status === 0 ? "passed" : "failed",
|
|
100
|
+
exitCode: result.status,
|
|
101
|
+
durationMs,
|
|
102
|
+
logPath: relativeLogPath
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function spawnVerificationCommand(projectRoot, command) {
|
|
106
|
+
const packageScript = resolvePackageScript(projectRoot, command);
|
|
107
|
+
if (packageScript) {
|
|
108
|
+
return spawnVerificationCommand(projectRoot, packageScript);
|
|
109
|
+
}
|
|
110
|
+
if (process.platform === "win32") {
|
|
111
|
+
const nodeCommand = parseUnquotedWindowsNodeCommand(command);
|
|
112
|
+
if (nodeCommand) {
|
|
113
|
+
return spawnSync(nodeCommand.executable, nodeCommand.args, {
|
|
114
|
+
cwd: projectRoot,
|
|
115
|
+
shell: false,
|
|
116
|
+
encoding: "utf8"
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return spawnSync(command, {
|
|
121
|
+
cwd: projectRoot,
|
|
122
|
+
shell: true,
|
|
123
|
+
encoding: "utf8"
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
function resolvePackageScript(projectRoot, command) {
|
|
127
|
+
if (process.platform !== "win32") {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
const match = /^npm run ([^\s]+)$/.exec(command.trim());
|
|
131
|
+
if (!match) {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
const packageJsonPath = path.join(projectRoot, "package.json");
|
|
135
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
const parsed = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
140
|
+
const scriptName = match[1];
|
|
141
|
+
if (scriptName === undefined) {
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
const script = parsed.scripts?.[scriptName];
|
|
145
|
+
if (typeof script !== "string" || !parseUnquotedWindowsNodeCommand(script)) {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
return script;
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
function parseUnquotedWindowsNodeCommand(command) {
|
|
155
|
+
const marker = "\\node.exe";
|
|
156
|
+
const lowerCommand = command.toLowerCase();
|
|
157
|
+
const markerIndex = lowerCommand.indexOf(marker);
|
|
158
|
+
if (markerIndex === -1) {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
const executable = command.slice(0, markerIndex + marker.length);
|
|
162
|
+
if (!path.isAbsolute(executable) || !executable.toLowerCase().endsWith(marker)) {
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
const remainder = command.slice(executable.length).trim();
|
|
166
|
+
if (!remainder.startsWith("-e ")) {
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
const script = parseQuotedArgument(remainder.slice(3).trim());
|
|
170
|
+
return script === null ? null : { executable, args: ["-e", script] };
|
|
171
|
+
}
|
|
172
|
+
function parseQuotedArgument(value) {
|
|
173
|
+
if (value.length < 2) {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
const quote = value[0];
|
|
177
|
+
if (quote !== "\"" && quote !== "'") {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
if (value.at(-1) !== quote) {
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
return value.slice(1, -1);
|
|
184
|
+
}
|
|
185
|
+
function readPreviousStatus(projectRoot) {
|
|
186
|
+
const previous = readJson(harnessPath(projectRoot, "verification", "latest.json"));
|
|
187
|
+
return previous?.status ?? "not_run";
|
|
188
|
+
}
|
|
189
|
+
function writeResult(projectRoot, result) {
|
|
190
|
+
writeJson(harnessPath(projectRoot, "verification", "latest.json"), result);
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=verify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/runtime/verify.ts"],"names":[],"mappings":"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"}
|