@adriandmitroca/relay 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,122 @@
1
+ import { runClaudeJson, type ClaudeOptions, type ClaudeStreamEvent } from "./claude.ts";
2
+ import { logger } from "../utils/logger.ts";
3
+
4
+ export interface TriageResult {
5
+ fixable: boolean;
6
+ confidence: number;
7
+ reason: string;
8
+ plan: string | null;
9
+ failed?: boolean;
10
+ failureReason?: string;
11
+ sessionId?: string;
12
+ durationMs: number;
13
+ inputTokens: number;
14
+ outputTokens: number;
15
+ costUsd?: number;
16
+ }
17
+
18
+ export async function triageIssue(
19
+ issueContext: string,
20
+ repoPath: string,
21
+ timeoutMs: number,
22
+ projectContext?: string,
23
+ model?: "sonnet" | "opus" | "haiku",
24
+ onEvent?: (event: ClaudeStreamEvent) => void,
25
+ logPath?: string,
26
+ ): Promise<TriageResult> {
27
+ const contextSection = projectContext ? `\nProject conventions and context:\n${projectContext}\n` : "";
28
+
29
+ const prompt = `You are triaging a task to decide if it can be automatically implemented by an AI coding agent.
30
+
31
+ Tasks can be anything: bug fixes, new features, refactors, improvements, chores, etc. Your job is to assess whether this task is well-defined enough and scoped appropriately for an AI agent to implement autonomously.
32
+ ${contextSection}
33
+ Analyze this task in the context of the codebase:
34
+
35
+ ${issueContext}
36
+
37
+ Steps:
38
+ 1. Understand what the task is asking for (bug fix, feature, refactor, etc.)
39
+ 2. For bugs: use the stacktrace (if available) to find the exact file(s) and line(s) where the error originates
40
+ 3. For features/improvements: identify the relevant files and understand the existing patterns
41
+ 4. Read the relevant code to understand what needs to change
42
+ 5. Check if tests exist for the affected area
43
+ 6. Decide if this is implementable and plan the implementation
44
+
45
+ Respond with ONLY a JSON object:
46
+ {
47
+ "fixable": true/false,
48
+ "confidence": 0.0-1.0,
49
+ "reason": "Brief explanation of what needs to be done and why this is/isn't implementable",
50
+ "plan": "If fixable: numbered steps, each specifying the exact file path, function/line, and what change to make. Include test file if one needs to be added or updated. Be concrete — e.g. 'In src/auth/login.ts line 42, add null check before accessing user.profile'. Otherwise null."
51
+ }
52
+
53
+ IS implementable (common patterns):
54
+ - Bug fixes: null checks, error handling, type errors, off-by-one, wrong comparisons
55
+ - Runtime errors from Sentry — if the stacktrace points to code in this repo, it's likely fixable
56
+ - New features with clear requirements that follow existing patterns in the codebase
57
+ - Refactors with well-defined scope (rename, extract, move, simplify)
58
+ - Adding/updating tests for existing functionality
59
+ - UI changes with clear descriptions (add button, change layout, update text)
60
+ - Adding validation, logging, or error handling
61
+ - Performance improvements with obvious targets
62
+
63
+ NOT implementable:
64
+ - The stacktrace points entirely to third-party code with no app code involved
65
+ - Requires infrastructure, deployment, or config changes outside the repo
66
+ - Needs product/design decisions or clarification from humans — the task description is too vague
67
+ - Would be a large architectural refactor touching many unrelated systems
68
+ - Requires access to external services, APIs, or credentials not in the repo
69
+
70
+ Important: An error that "shouldn't land on Sentry" IS fixable — the fix is to add proper error handling so it doesn't propagate. Missing error handling is a code bug.`;
71
+
72
+ const opts: ClaudeOptions = {
73
+ cwd: repoPath,
74
+ timeoutMs,
75
+ allowedTools: ["Read", "Grep", "Glob"],
76
+ model,
77
+ onEvent,
78
+ logPath,
79
+ };
80
+
81
+ const result = await runClaudeJson<TriageResult>(prompt, opts);
82
+
83
+ if (!result.success || !result.data) {
84
+ logger.warn("Triage failed", { error: result.error });
85
+ const failureReason = result.error?.includes("Timed out") ? "triage:timeout" : "triage:claude_failed";
86
+ return {
87
+ fixable: false,
88
+ confidence: 0,
89
+ reason: `Triage failed: ${result.error ?? "unknown error"}`,
90
+ plan: null,
91
+ failed: true,
92
+ failureReason,
93
+ durationMs: result.durationMs,
94
+ inputTokens: result.inputTokens,
95
+ outputTokens: result.outputTokens,
96
+ costUsd: result.costUsd,
97
+ };
98
+ }
99
+
100
+ const data = result.data;
101
+ logger.info("Triage complete", {
102
+ fixable: data.fixable,
103
+ confidence: data.confidence,
104
+ reason: data.reason,
105
+ sessionId: result.sessionId,
106
+ durationMs: result.durationMs,
107
+ inputTokens: result.inputTokens,
108
+ outputTokens: result.outputTokens,
109
+ });
110
+
111
+ return {
112
+ fixable: !!data.fixable,
113
+ confidence: typeof data.confidence === "number" ? data.confidence : 0,
114
+ reason: data.reason ?? "No reason given",
115
+ plan: data.plan ?? null,
116
+ sessionId: result.sessionId,
117
+ durationMs: result.durationMs,
118
+ inputTokens: result.inputTokens,
119
+ outputTokens: result.outputTokens,
120
+ costUsd: result.costUsd,
121
+ };
122
+ }