Files
playbook/antigravity-awesome-skills/tools/scripts/pr_decision_manifest.cjs
2026-07-18 00:02:59 +00:00

121 lines
4.0 KiB
JavaScript

#!/usr/bin/env node
const fs = require("fs");
const path = require("path");
const { findProjectRoot } = require("../lib/project-root");
const { buildDecisionManifest } = require("../lib/pr-decision");
function parseArgs(argv) {
const args = {
preflight: null,
evidence: null,
output: null,
semanticReviewState: "unknown",
writeStepSummary: false,
writeGithubOutput: false,
json: false,
};
for (let index = 0; index < argv.length; index += 1) {
const arg = argv[index];
if (["--preflight", "--evidence", "--output", "--semantic-review-state"].includes(arg)) {
const value = argv[index + 1];
if (!value) throw new Error(`${arg} requires a value`);
const key = {
"--preflight": "preflight",
"--evidence": "evidence",
"--output": "output",
"--semantic-review-state": "semanticReviewState",
}[arg];
args[key] = value;
index += 1;
} else if (arg === "--write-step-summary") {
args.writeStepSummary = true;
} else if (arg === "--write-github-output") {
args.writeGithubOutput = true;
} else if (arg === "--json") {
args.json = true;
}
}
if (!args.preflight || !args.evidence) {
throw new Error("--preflight and --evidence are required");
}
return args;
}
function safePath(projectRoot, value) {
const target = path.resolve(projectRoot, value);
const relative = path.relative(projectRoot, target);
if (relative.startsWith("..") || path.isAbsolute(relative)) {
throw new Error(`Path escapes repository root: ${value}`);
}
return target;
}
function readJson(filePath) {
return JSON.parse(fs.readFileSync(filePath, "utf8"));
}
function appendSummary(manifest) {
const summaryPath = process.env.GITHUB_STEP_SUMMARY;
if (!summaryPath) return;
const lines = [
"## PR Decision Manifest (shadow)",
"",
`- Route: \`${manifest.route}\``,
`- Deterministic gate: ${manifest.deterministic_gate.blocking ? "blocking" : "pass"}`,
`- Semantic review: \`${manifest.semantic_review.state}\``,
`- Changed skills: ${manifest.change.changed_skills.length}`,
`- Sensitive paths: ${manifest.change.sensitive_paths.length}`,
`- Reasons: ${manifest.reason_codes.length ? manifest.reason_codes.map((item) => `\`${item}\``).join(", ") : "none"}`,
"",
"> Advisory artifact produced by unprivileged pull_request code. Privileged actions must recompute from trusted main.",
];
fs.appendFileSync(summaryPath, `${lines.join("\n")}\n`, "utf8");
}
function appendGithubOutput(manifest) {
const outputPath = process.env.GITHUB_OUTPUT;
if (!outputPath) return;
const lines = [
`route=${manifest.route}`,
`blocking=${manifest.deterministic_gate.blocking}`,
`semantic_review_state=${manifest.semantic_review.state}`,
`changed_skills_count=${manifest.change.changed_skills.length}`,
`sensitive_paths_count=${manifest.change.sensitive_paths.length}`,
];
fs.appendFileSync(outputPath, `${lines.join("\n")}\n`, "utf8");
}
function main() {
const args = parseArgs(process.argv.slice(2));
const projectRoot = findProjectRoot(__dirname);
const preflight = readJson(safePath(projectRoot, args.preflight));
const evidence = readJson(safePath(projectRoot, args.evidence));
const manifest = buildDecisionManifest({
preflight,
evidence,
semanticReviewState: args.semanticReviewState,
});
const serialized = `${JSON.stringify(manifest, null, 2)}\n`;
if (args.output) {
const outputPath = safePath(projectRoot, args.output);
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
fs.writeFileSync(outputPath, serialized, { encoding: "utf8", mode: 0o600 });
}
if (args.writeStepSummary) appendSummary(manifest);
if (args.writeGithubOutput) appendGithubOutput(manifest);
if (args.json || !args.output) process.stdout.write(serialized);
}
if (require.main === module) {
try {
main();
} catch (error) {
console.error(`[pr-decision] ${error.message}`);
process.exit(2);
}
}
module.exports = { appendGithubOutput, appendSummary, parseArgs, safePath };