Files
devclaw-gitea/lib/task-managers/task-manager.ts
Lauren ten Hoor 09f6903ebb feat: include PR/MR URL in DEV completion notifications
Adds automatic PR/MR URL detection and inclusion in DEV completion
announcements to provide better visibility into completed work.

Changes:
1. TaskManager interface:
   - Added getMergedMRUrl() method to fetch PR/MR URL for an issue

2. GitHub/GitLab providers:
   - Implemented getMergedMRUrl() to find most recent merged PR/MR
   - Returns URL of PR/MR that references the issue number

3. task_complete tool:
   - Added optional prUrl parameter
   - Auto-detects PR/MR URL if not provided
   - Includes PR URL in announcement with 🔗 prefix
   - Format: 'PR: https://github.com/...'

4. Role templates (dev.md):
   - Updated to instruct workers to include prUrl in task_complete
   - Documents that prUrl is optional (auto-detected as fallback)

Example announcement:
 DEV done #101 — Added PR/MR URL to notifications
🔗 PR: https://github.com/user/repo/pull/102
. Moved to QA queue.

Addresses issue #101
2026-02-10 18:22:44 +08:00

93 lines
2.6 KiB
TypeScript

/**
* TaskManager — Abstract interface for issue tracker operations.
*
* GitHub (via gh CLI) and GitLab (via glab CLI) are the current implementations.
* Future providers: Jira (via API).
*
* All DevClaw tools operate through this interface, making it possible
* to swap issue trackers without changing tool logic.
*/
export const STATE_LABELS = [
"Planning",
"To Do",
"Doing",
"To Test",
"Testing",
"Done",
"To Improve",
"Refining",
] as const;
export type StateLabel = (typeof STATE_LABELS)[number];
export const LABEL_COLORS: Record<StateLabel, string> = {
Planning: "#6699cc",
"To Do": "#428bca",
Doing: "#f0ad4e",
"To Test": "#5bc0de",
Testing: "#9b59b6",
Done: "#5cb85c",
"To Improve": "#d9534f",
Refining: "#f39c12",
};
export type Issue = {
iid: number;
title: string;
description: string;
labels: string[];
state: string;
web_url: string;
};
export interface TaskManager {
/** Create a label if it doesn't exist (idempotent). */
ensureLabel(name: string, color: string): Promise<void>;
/** Create all 8 state labels (idempotent). */
ensureAllStateLabels(): Promise<void>;
/** Create a new issue. */
createIssue(title: string, description: string, label: StateLabel, assignees?: string[]): Promise<Issue>;
/** List issues with a specific state label. */
listIssuesByLabel(label: StateLabel): Promise<Issue[]>;
/** Fetch a single issue by ID. */
getIssue(issueId: number): Promise<Issue>;
/** Transition an issue from one state label to another (atomic unlabel + label). */
transitionLabel(issueId: number, from: StateLabel, to: StateLabel): Promise<void>;
/** Close an issue. */
closeIssue(issueId: number): Promise<void>;
/** Reopen an issue. */
reopenIssue(issueId: number): Promise<void>;
/** Check if an issue has a specific state label. */
hasStateLabel(issue: Issue, expected: StateLabel): boolean;
/** Get the current state label of an issue. */
getCurrentStateLabel(issue: Issue): StateLabel | null;
/** Check if any merged MR/PR exists for a specific issue. */
hasMergedMR(issueId: number): Promise<boolean>;
/** Get the URL of the most recently merged MR/PR for a specific issue. Returns null if not found. */
getMergedMRUrl(issueId: number): Promise<string | null>;
/** Add a comment to an issue. */
addComment(issueId: number, body: string): Promise<void>;
/** Verify the task manager is working (CLI available, auth valid, repo accessible). */
healthCheck(): Promise<boolean>;
}
/**
* Compatibility alias for backward compatibility.
* @deprecated Use TaskManager instead.
*/
export type IssueProvider = TaskManager;