Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
node_modules/
.review-hero/
.caller-base/
22 changes: 20 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 18 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,25 @@
{
"private": true,
"name": "@beyondessential/review-hero",
"version": "0.1.0",
"description": "Shared review logic for Review Hero: finding parsing, consensus and cross-agent grouping, suppression filtering, agent discovery, scope filtering, prompt assembly, and summary formatting.",
"type": "module",
"exports": {
".": {
"types": "./src/index.d.ts",
"import": "./src/index.mjs"
}
},
"main": "./src/index.mjs",
"types": "./src/index.d.ts",
"files": [
"src/",
"prompts/"
],
"scripts": {
"test": "node --test \"scripts/**/*.test.mjs\""
"test": "node --test \"scripts/**/*.test.mjs\" \"src/**/*.test.mjs\""
},
"dependencies": {
"@actions/core": "^1.11.1"
"@actions/core": "^1.11.1",
"yaml": "^2.9.0"
}
}
84 changes: 5 additions & 79 deletions scripts/lib.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@
* Common helpers used by auto-fix and other action scripts.
*/

import { readFileSync, writeFileSync, existsSync, copyFileSync, chmodSync } from "node:fs";
import { readFileSync, writeFileSync, copyFileSync, chmodSync } from "node:fs";
import { execSync, execFileSync } from "node:child_process";
import * as core from "@actions/core";

// Prompt assembly and result parsing live in the shared library so the
// Actions side and any external consumer share one implementation.
export { buildBasePromptSections, parseClaudeResult } from "../src/prompt.mjs";

// ── Constants ────────────────────────────────────────────────────────────────

/** Maximum number of voters allowed per agent (matches GitHub Actions matrix limits). */
Expand Down Expand Up @@ -329,84 +333,6 @@ export function logClaudeSession(raw, label = "Claude") {
}
}

export function parseClaudeResult(raw) {
let text = raw;
try {
const parsed = JSON.parse(raw);
if (Array.isArray(parsed.result)) return parsed.result;
if (parsed.result) text = parsed.result;
else if (Array.isArray(parsed)) return parsed;
} catch {
// Not valid JSON at top level — search for embedded array below
}

let searchFrom = 0;
while (searchFrom < text.length) {
const start = text.indexOf("[", searchFrom);
if (start === -1) break;
let searchEnd = text.length;
while (searchEnd > start) {
const end = text.lastIndexOf("]", searchEnd - 1);
if (end <= start) break;
try {
const arr = JSON.parse(text.slice(start, end + 1));
if (Array.isArray(arr)) return arr;
} catch {
// try shorter span
}
searchEnd = end;
}
searchFrom = start + 1;
}

return [];
}

// ── Prompt building ──────────────────────────────────────────────────────────

export function buildBasePromptSections({
projectContext,
promptPath,
commitHelperPath,
customRulesPath,
aiRulesPath,
aiRulesLabel = "Follow them when applying changes.",
}) {
const sections = [];

if (projectContext) {
sections.push(`## Project Context\n\n${projectContext}`);
}

let basePrompt = readFileSync(promptPath, "utf-8");
if (commitHelperPath) {
basePrompt = basePrompt.replaceAll(
".review-hero/scripts/git-commit-fix.mjs",
commitHelperPath,
);
}
sections.push(basePrompt);

if (customRulesPath && existsSync(customRulesPath)) {
sections.push(readFileSync(customRulesPath, "utf-8"));
}

if (aiRulesPath) {
try {
const aiRules = readFileSync(aiRulesPath, "utf-8").trim();
if (aiRules) {
sections.push(
`## Repository AI Rules\n\nThis repository defines the following AI coding rules. ${aiRulesLabel}\n\n${aiRules}`,
);
}
} catch {
// No AI rules file or unreadable — skip
}
}

return sections;
}

// ── Commit helper ────────────────────────────────────────────────────────────

export function copyCommitHelper(prNumber) {
Expand Down
Loading