feat: enhance review process and role management

- Refactor reviewPass function to identify states with review checks instead of specific review types.
- Introduce review policies (HUMAN, AGENT, AUTO) to control PR review processes based on developer levels.
- Update projectTick to handle review policies and step routing labels for reviewers and testers.
- Add detailed reviewer instructions to templates for clarity on review responsibilities.
- Implement role:level label management, allowing dynamic creation of labels based on project configuration.
- Enhance task_update tool to support state and level updates, ensuring at least one parameter is provided.
- Update work_finish tool to include reviewer actions (approve, reject) in task completion.
- Modify work_start tool to utilize role-level detection for better level assignment.
- Add tests for new functionalities, including review routing and level detection from labels.
This commit is contained in:
Lauren ten Hoor
2026-02-16 18:09:53 +08:00
parent 1464fa82d2
commit d87b9f68a2
25 changed files with 1134 additions and 294 deletions

View File

@@ -191,6 +191,7 @@ export async function createTestHarness(opts?: HarnessOptions): Promise<TestHarn
developer: emptyWorkerState(["junior", "medior", "senior"]),
tester: emptyWorkerState(["junior", "medior", "senior"]),
architect: emptyWorkerState(["junior", "senior"]),
reviewer: emptyWorkerState(["junior", "senior"]),
};
// Apply worker overrides
@@ -264,6 +265,7 @@ export async function createTestHarness(opts?: HarnessOptions): Promise<TestHarn
hookCallback = cb;
},
logger: {
debug() {},
info() {},
warn() {},
error() {},

View File

@@ -37,12 +37,15 @@ export type ProviderCall =
method: "transitionLabel";
args: { issueId: number; from: StateLabel; to: StateLabel };
}
| { method: "addLabel"; args: { issueId: number; label: string } }
| { method: "removeLabels"; args: { issueId: number; labels: string[] } }
| { method: "closeIssue"; args: { issueId: number } }
| { method: "reopenIssue"; args: { issueId: number } }
| { method: "hasMergedMR"; args: { issueId: number } }
| { method: "getMergedMRUrl"; args: { issueId: number } }
| { method: "getPrStatus"; args: { issueId: number } }
| { method: "mergePr"; args: { issueId: number } }
| { method: "getPrDiff"; args: { issueId: number } }
| { method: "addComment"; args: { issueId: number; body: string } }
| { method: "healthCheck"; args: {} };
@@ -63,6 +66,8 @@ export class TestProvider implements IssueProvider {
mergedMrUrls = new Map<number, string>();
/** Issue IDs where mergePr should fail (simulates merge conflicts). */
mergePrFailures = new Set<number>();
/** PR diffs per issue (for reviewer tests). */
prDiffs = new Map<number, string>();
/** All calls, in order. */
calls: ProviderCall[] = [];
@@ -118,6 +123,7 @@ export class TestProvider implements IssueProvider {
this.prStatuses.clear();
this.mergedMrUrls.clear();
this.mergePrFailures.clear();
this.prDiffs.clear();
this.calls = [];
this.nextIssueId = 1;
}
@@ -193,6 +199,22 @@ export class TestProvider implements IssueProvider {
issue.labels.push(to);
}
async addLabel(issueId: number, label: string): Promise<void> {
this.calls.push({ method: "addLabel", args: { issueId, label } });
const issue = this.issues.get(issueId);
if (issue && !issue.labels.includes(label)) {
issue.labels.push(label);
}
}
async removeLabels(issueId: number, labels: string[]): Promise<void> {
this.calls.push({ method: "removeLabels", args: { issueId, labels } });
const issue = this.issues.get(issueId);
if (issue) {
issue.labels = issue.labels.filter((l) => !labels.includes(l));
}
}
async closeIssue(issueId: number): Promise<void> {
this.calls.push({ method: "closeIssue", args: { issueId } });
const issue = this.issues.get(issueId);
@@ -241,6 +263,11 @@ export class TestProvider implements IssueProvider {
}
}
async getPrDiff(issueId: number): Promise<string | null> {
this.calls.push({ method: "getPrDiff", args: { issueId } });
return this.prDiffs.get(issueId) ?? null;
}
async addComment(issueId: number, body: string): Promise<void> {
this.calls.push({ method: "addComment", args: { issueId, body } });
const existing = this.comments.get(issueId) ?? [];