in scripts-ts/src/selectTicketForAnalysis.ts [25:191]
async function main(): Promise<void> {
const projectDir = process.argv[2] || ".";
// Priority 1: Check for tickets with pending clarification (owner may have answered)
console.log("Checking for tickets with pending clarification...");
const pendingQuery = "State: Open tag: claude-pending-clarification Area: -{Remote Dev} Area: -Gateway";
const pendingTickets = await getTicketsByQuery(pendingQuery);
let selectedTicketId: string;
let hasPendingClarification = false;
if (pendingTickets.length > 0) {
// Select first pending ticket (prioritize getting answers)
selectedTicketId = pendingTickets[0];
hasPendingClarification = true;
console.log(`Found ${pendingTickets.length} tickets with pending clarification`);
console.log(`Selected pending ticket: ${selectedTicketId}`);
} else {
// Priority 2: Select random from unanalyzed tickets
console.log("No pending clarification tickets, searching for unanalyzed tickets...");
const query = "State: Open tag: -claude-analyzed Area: -{Remote Dev} Area: -Gateway";
const tickets = await getTicketsByQuery(query);
console.log(`Found ${tickets.length} unanalyzed open tickets`);
if (tickets.length === 0) {
console.log("No unanalyzed tickets found");
writeGitHubOutput("ticket_id", "");
writeGitHubOutput("ticket_summary", "");
writeGitHubOutput("has_pending_clarification", "false");
return;
}
// Pick a random ticket
selectedTicketId = tickets[Math.floor(Math.random() * tickets.length)];
console.log(`Selected random ticket: ${selectedTicketId}`);
}
const randomTicketId = selectedTicketId;
// Fetch ticket details, comments, and attachments
const details = await getTicketDetails(randomTicketId);
const comments = await getTicketComments(randomTicketId);
const attachments = await getTicketAttachments(randomTicketId);
console.log(`Ticket summary: ${details.summary}`);
console.log(`Ticket state: ${details.state}`);
console.log(`Found ${comments.length} comments`);
console.log(`Found ${attachments.length} attachments`);
// Format comments section
let commentsSection = "";
if (comments.length > 0) {
commentsSection = "\n## Comments\n\n";
for (const comment of comments) {
commentsSection += `### ${comment.author} (${comment.created})\n\n${comment.text}\n\n---\n\n`;
}
}
// Download image attachments and format attachments section
let attachmentsSection = "";
if (attachments.length > 0) {
const attachmentsDir = join(projectDir, "attachments");
// Create attachments directory if needed
if (!existsSync(attachmentsDir)) {
mkdirSync(attachmentsDir, { recursive: true });
}
attachmentsSection = "\n## Attachments\n\n";
for (const attachment of attachments) {
const mimeInfo = attachment.mimeType ? ` (${attachment.mimeType})` : "";
const isImage = attachment.mimeType?.startsWith("image/") ?? false;
if (isImage) {
// Download image attachment locally
const localPath = join(attachmentsDir, attachment.name);
const relativePath = `./attachments/${attachment.name}`;
const downloaded = await downloadAttachment(attachment.url, localPath);
if (downloaded) {
attachmentsSection += `- [${attachment.name}](${relativePath})${mimeInfo} - **LOCAL FILE: Use Read tool to view**\n`;
} else {
attachmentsSection += `- [${attachment.name}](${attachment.url})${mimeInfo} (download failed)\n`;
}
} else {
// Non-image attachments: keep as URL
attachmentsSection += `- [${attachment.name}](${attachment.url})${mimeInfo}\n`;
}
}
}
// Write ticket details to file for Claude to read
const ticketDetailsPath = `${projectDir}/ticket_details.md`;
const ticketDetailsContent = `# YouTrack Ticket: ${details.id}
## Summary
${details.summary}
## Description
${details.description ?? "No description provided"}
## Current State
${details.state}
## Created
${details.created}
## URL
https://youtrack.jetbrains.com/issue/${details.id}
${commentsSection}${attachmentsSection}`;
writeFileSync(ticketDetailsPath, ticketDetailsContent);
console.log(`Wrote ticket details to ${ticketDetailsPath}`);
// Write initial analysis state JSON for multi-step workflow
const analysisStatePath = `${projectDir}/analysis_state.json`;
const analysisState = {
ticket_id: details.id,
ticket_summary: details.summary,
has_pending_clarification: hasPendingClarification,
ticket_type: null,
triage_result: null,
triage_reason: null,
triage_attention_reason: null,
check_answer: {
status: "pending",
attention_reason: null
},
planning: {
status: "pending",
plan: null,
questions: null,
attention_reason: null
},
implementation: {
status: "pending",
changed_files: [],
test_files: [],
notes: null,
attention_reason: null
},
review: {
status: "pending",
notes: null,
attention_reason: null
},
changelog: {
status: "pending",
attention_reason: null
},
pr: {
url: null,
branch: null,
attention_reason: null
},
final_result: null
};
writeFileSync(analysisStatePath, JSON.stringify(analysisState, null, 2));
console.log(`Wrote analysis state to ${analysisStatePath}`);
// Write GitHub Actions outputs
writeGitHubOutput("ticket_id", details.id);
writeGitHubOutput("ticket_summary", details.summary);
writeGitHubOutput("has_pending_clarification", hasPendingClarification.toString());
}