export default async function botHandler(app) {
app.log.info('Holon Bot is starting up!');
app.onAny(async (context) => {
const { name, payload } = context;
const action = payload.action ? `.${payload.action}` : '';
app.log.info(`Received event: ${name}${action}`);
});
app.on('push', async (context) => {
const { payload, repository } = context;
const { ref, pusher, head_commit } = payload;
if (!ref.startsWith('refs/heads/')) {
return;
}
const branch = ref.replace('refs/heads/', '');
const owner = repository.owner.login;
const repo = repository.name;
if (pusher.name === 'holonbot' || pusher.name === 'holonbot[bot]') {
app.log.info('Skipping push from holonbot itself to avoid loops');
return;
}
app.log.info(`Push to branch '${branch}' by ${pusher.name}`);
try {
const { data: pulls } = await context.octokit.rest.pulls.list({
owner,
repo,
state: 'open',
head: `${owner}:${branch}`,
per_page: 1
});
if (pulls.length === 0) {
app.log.info(`No open PR found for branch ${branch}`);
return;
}
const pr = pulls[0];
app.log.info(`Found PR #${pr.number} for branch ${branch}`);
if (head_commit && head_commit.message) {
const commitMsg = head_commit.message.toLowerCase();
const isHolonFix = commitMsg.includes('holon') ||
commitMsg.includes('automated fix') ||
commitMsg.includes('co-authored-by: claude');
if (!isHolonFix) {
app.log.info('Push does not appear to be a Holon fix commit');
return;
}
}
app.log.info(`Holon fix detected on PR #${pr.number}`);
} catch (error) {
app.log.error('Error processing push event:', error);
}
});
app.on('workflow_run.completed', async (context) => {
const { payload } = context;
const { workflow_run, repository, action } = payload;
const owner = repository.owner.login;
const repo = repository.name;
if (workflow_run.name !== 'Holonbot Fix Workflow') {
app.log.info(`Skipping non-Holon workflow: ${workflow_run.name}`);
return;
}
app.log.info(`Holonbot workflow ${action} for run #${workflow_run.id}`);
if (workflow_run.conclusion !== 'success') {
app.log.info(`Workflow run did not succeed: ${workflow_run.conclusion}`);
return;
}
try {
if (workflow_run.event !== 'issue_comment') {
app.log.info(`Workflow run was triggered by ${workflow_run.event}, not issue_comment`);
return;
}
const issueNumber = workflow_run.pull_requests?.[0]?.number;
if (!issueNumber) {
app.log.info('No PR number associated with this workflow run');
return;
}
app.log.info(`Found associated PR #${issueNumber}`);
const artifactName = `holon-fix-output-pr-${issueNumber}`;
const { data: artifacts } = await context.octokit.rest.actions.listWorkflowRunArtifacts({
owner,
repo,
run_id: workflow_run.id
});
const holonArtifact = artifacts.artifacts.find(a => a.name === artifactName);
if (!holonArtifact) {
app.log.warn(`Holon artifact not found: ${artifactName}`);
return;
}
app.log.info(`Found Holon artifact: ${holonArtifact.name} (${holonArtifact.size_in_bytes} bytes)`);
const { data: zipBuffer } = await context.octokit.rest.actions.downloadArtifact({
owner,
repo,
artifact_id: holonArtifact.id,
archive_format: 'zip'
});
app.log.info(`Downloaded artifact: ${zipBuffer.length} bytes`);
app.log.info('Holon output artifact found - processed by holon solve workflow');
} catch (error) {
app.log.error('Error processing workflow_run event:', error);
}
});
app.onError((error) => {
app.log.error('Error occurred in the app:', error);
});
app.log.info('Holon Bot is ready to receive events!');
}