Add solve-issue committer after implement; replace develop-sense and develop-workflow script roles with createRole(hermesAdapter). Implement prompt no longer does git; publish prompt asks for meaningful PR titles. Refs #9 Made-with: Cursor
100 lines
2.9 KiB
TypeScript
100 lines
2.9 KiB
TypeScript
import { END } from "@uncaged/nerve-core";
|
|
import type { Moderator } from "@uncaged/nerve-core";
|
|
import type { ReadIssueMeta } from "./roles/read-issue/index.js";
|
|
import type { PrepareMeta } from "./roles/prepare/index.js";
|
|
import type { PlanMeta } from "./roles/plan/index.js";
|
|
import type { ImplementMeta } from "./roles/implement/index.js";
|
|
import type { CommitterMeta } from "./roles/committer/index.js";
|
|
import type { ReviewMeta } from "./roles/review/index.js";
|
|
import type { TestMeta } from "./roles/test/index.js";
|
|
import type { PublishMeta } from "./roles/publish/index.js";
|
|
|
|
export type WorkflowMeta = {
|
|
"read-issue": ReadIssueMeta;
|
|
prepare: PrepareMeta;
|
|
plan: PlanMeta;
|
|
implement: ImplementMeta;
|
|
committer: CommitterMeta;
|
|
review: ReviewMeta;
|
|
test: TestMeta;
|
|
publish: PublishMeta;
|
|
};
|
|
|
|
const MAX_IMPLEMENT_ROUNDS = 20;
|
|
const MAX_TOTAL_REJECTIONS = 10;
|
|
|
|
function implementRounds(steps: { role: string }[]): number {
|
|
return steps.filter((s) => s.role === "implement").length;
|
|
}
|
|
|
|
function totalRejections(steps: { role: string; meta: unknown }[]): number {
|
|
return steps.filter((s) => {
|
|
if (s.role === "review") return !(s.meta as Record<string, boolean>).approved;
|
|
if (s.role === "test") return !(s.meta as Record<string, boolean>).passed;
|
|
if (s.role === "committer") return !(s.meta as Record<string, boolean>).committed;
|
|
if (s.role === "publish") return !(s.meta as Record<string, boolean>).success;
|
|
return false;
|
|
}).length;
|
|
}
|
|
|
|
function canRetryImplement(steps: { role: string; meta: unknown }[]): boolean {
|
|
return implementRounds(steps) < MAX_IMPLEMENT_ROUNDS && totalRejections(steps) < MAX_TOTAL_REJECTIONS;
|
|
}
|
|
|
|
export const moderator: Moderator<WorkflowMeta> = (context) => {
|
|
if (context.steps.length === 0) {
|
|
return "read-issue";
|
|
}
|
|
|
|
const last = context.steps[context.steps.length - 1];
|
|
|
|
if (last.role === "read-issue") {
|
|
return last.meta.ready ? "prepare" : END;
|
|
}
|
|
|
|
if (last.role === "prepare") {
|
|
return last.meta.ready ? "plan" : END;
|
|
}
|
|
|
|
if (last.role === "plan") {
|
|
return last.meta.ready ? "implement" : END;
|
|
}
|
|
|
|
if (last.role === "implement") {
|
|
if (last.meta.done) {
|
|
return "committer";
|
|
}
|
|
return canRetryImplement(context.steps) ? "implement" : END;
|
|
}
|
|
|
|
if (last.role === "committer") {
|
|
if (last.meta.committed) {
|
|
return "review";
|
|
}
|
|
return canRetryImplement(context.steps) ? "implement" : END;
|
|
}
|
|
|
|
if (last.role === "review") {
|
|
if (last.meta.approved) {
|
|
return "test";
|
|
}
|
|
return canRetryImplement(context.steps) ? "implement" : END;
|
|
}
|
|
|
|
if (last.role === "test") {
|
|
if (last.meta.passed) {
|
|
return "publish";
|
|
}
|
|
return canRetryImplement(context.steps) ? "implement" : END;
|
|
}
|
|
|
|
if (last.role === "publish") {
|
|
if (last.meta.success) {
|
|
return END;
|
|
}
|
|
return canRetryImplement(context.steps) ? "implement" : END;
|
|
}
|
|
|
|
return END;
|
|
};
|