Skip to content
Closed
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 CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ checkpoint, and status-only commits are intentionally omitted.
commit lists no longer process entries that are omitted from Codex input.
- Thanks @stainlu for the repair prompt, GitHub pagination, lazy context
compaction, and review telemetry PRs.
- Cached the static review prompt and decision schema within each ClawSweeper
process instead of re-reading them during review planning and item prompts.

## 0.2.0 - 2026-05-03

Expand Down
19 changes: 13 additions & 6 deletions src/clawsweeper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,8 @@ const DEFAULT_CODEX_MODEL = "gpt-5.5";
const DEFAULT_REASONING_EFFORT = "high";
const DEFAULT_SERVICE_TIER = "";
const REVIEW_POLICY_VERSION = "2026-05-05-policy-v13";
const REVIEW_ITEM_PROMPT_PATH = join(ROOT, "prompts", "review-item.md");
const CLAWSWEEPER_DECISION_SCHEMA_PATH = join(ROOT, "schema", "clawsweeper-decision.schema.json");
const REVIEW_COMMENT_MARKER_PREFIX = "<!-- clawsweeper-review";
const REVIEW_START_STATUS_MARKER_PREFIX = "<!-- clawsweeper-review-status";
const AUTOMERGE_LABEL = "clawsweeper:automerge";
Expand Down Expand Up @@ -1069,6 +1071,9 @@ function sha256(text: string): string {
return createHash("sha256").update(text).digest("hex");
}

let reviewPromptTemplateCache: string | undefined;
let reviewDecisionSchemaCache: string | undefined;

function itemSnapshotHash(item: Item, context: ItemContext): string {
const snapshotItem = {
repo: item.repo,
Expand Down Expand Up @@ -3243,12 +3248,14 @@ function gitInfo(openclawDir: string): GitInfo {
return { mainSha, latestRelease };
}

function reviewPromptTemplate(): string {
return readFileSync(join(ROOT, "prompts", "review-item.md"), "utf8");
export function reviewPromptTemplate(): string {
reviewPromptTemplateCache ??= readFileSync(REVIEW_ITEM_PROMPT_PATH, "utf8");
return reviewPromptTemplateCache;
}

function reviewDecisionSchemaText(): string {
return readFileSync(join(ROOT, "schema", "clawsweeper-decision.schema.json"), "utf8");
export function reviewDecisionSchemaText(): string {
reviewDecisionSchemaCache ??= readFileSync(CLAWSWEEPER_DECISION_SCHEMA_PATH, "utf8");
return reviewDecisionSchemaCache;
}

function contextJsonForPrompt(context: ItemContext): string {
Expand Down Expand Up @@ -3465,7 +3472,7 @@ function runCodex(options: {
"-C",
options.openclawDir,
"--output-schema",
join(ROOT, "schema", "clawsweeper-decision.schema.json"),
CLAWSWEEPER_DECISION_SCHEMA_PATH,
"--output-last-message",
outputPath,
"--sandbox",
Expand Down Expand Up @@ -7735,7 +7742,7 @@ function statusCommand(args: Args): void {
}

function checkCommand(): void {
JSON.parse(readFileSync(join(ROOT, "schema", "clawsweeper-decision.schema.json"), "utf8"));
JSON.parse(reviewDecisionSchemaText());
if (!existsSync(join(ROOT, ".github", "workflows", "sweep.yml")))
throw new Error("Missing workflow");
console.log("ok");
Expand Down
10 changes: 10 additions & 0 deletions test/clawsweeper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ import {
reviewActionForDecision,
reviewPriority,
renderReviewCommentFromReport,
reviewDecisionSchemaText,
reviewPromptTelemetryForTest,
reviewPromptTemplate,
runtimeBudgetExceeded,
safeOutputTail,
sameAuthorCounterpartApplyReason,
Expand Down Expand Up @@ -213,6 +215,14 @@ test("compactMappedSlice maps every entry when no compaction is needed", () => {
assert.deepEqual(mapped, [1, 2, 3]);
});

test("review prompt assets match tracked files", () => {
assert.equal(reviewPromptTemplate(), readFileSync("prompts/review-item.md", "utf8"));
assert.deepEqual(
JSON.parse(reviewDecisionSchemaText()),
JSON.parse(readFileSync("schema/clawsweeper-decision.schema.json", "utf8")),
);
});

test("main CLI args ignore package-manager double dash separators", () => {
assert.deepEqual(parseClawsweeperArgs(["apply-decisions", "--", "--dry-run"]), {
_: ["apply-decisions"],
Expand Down
Loading