fix: replace domain-specific exit handler with generic signal handler registry (#299)

* fix: replace domain-specific exit handler with generic signal handler registry

Rewrite exitHandler.ts as a generic, domain-agnostic exit signal module
that exports onExitSignal(handler) returning a dispose function.

- subprocess.ts now registers via onExitSignal instead of direct
  process.on(SIGINT/SIGTERM) calls
- resolveTokens registers a signal handler that captures tokens by
  closure, fixing the race condition where the exit handler would
  read the wrong token after disposal
- Remove setupExitHandler and runCleanup — domain cleanup is handled
  by post.ts + await using

Co-authored-by: Cursor <cursoragent@cursor.com>

* tweaks

* simplify handler installation

* extract to util

* fix race in dispose

* wrap dispose body in try/finally to ensure disposingRef always settles

---------

Co-authored-by: Mateusz Burzyński <mateuszburzynski@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: pullfrog[bot] <226033991+pullfrog[bot]@users.noreply.github.com>
This commit is contained in:
pullfrog[bot]
2026-02-20 10:23:56 +00:00
committed by pullfrog[bot]
parent 70f1c47a28
commit ee100354da
10 changed files with 198 additions and 317 deletions
+29 -31
View File
@@ -41198,37 +41198,8 @@ var ReplyToReviewComment = type({
)
});
// utils/token.ts
var core3 = __toESM(require_core(), 1);
function getJobToken() {
const inputToken = core3.getInput("token");
if (inputToken) {
return inputToken;
}
const fallbackToken = process.env.GH_TOKEN || process.env.GITHUB_TOKEN;
if (fallbackToken) {
return fallbackToken;
}
throw new Error("token input is required");
}
// utils/exitHandler.ts
function buildErrorCommentBody(params) {
const workflowRunLink = params.runId ? `[workflow run logs](https://github.com/${params.owner}/${params.repo}/actions/runs/${params.runId})` : "workflow run logs";
const errorMessage = params.isCancellation ? `This run was cancelled \u{1F6D1}
The workflow was cancelled before completion. Please check the ${workflowRunLink} for details.` : `This run croaked \u{1F635}
The workflow encountered an error before any progress could be reported. Please check the ${workflowRunLink} for details.`;
const footer = buildPullfrogFooter({
triggeredBy: true,
workflowRun: params.runId ? { owner: params.owner, repo: params.repo, runId: params.runId } : void 0
});
return `${errorMessage}${footer}`;
}
// utils/payload.ts
var core4 = __toESM(require_core(), 1);
var core3 = __toESM(require_core(), 1);
// external.ts
var agentsManifest = {
@@ -41399,7 +41370,7 @@ var Inputs = type({
"cwd?": type.string.or("undefined")
});
function resolvePromptInput() {
const prompt = core4.getInput("prompt", { required: true });
const prompt = core3.getInput("prompt", { required: true });
let parsed2;
try {
parsed2 = JSON.parse(prompt);
@@ -41414,8 +41385,35 @@ function resolvePromptInput() {
return jsonPayload;
}
// utils/token.ts
var core4 = __toESM(require_core(), 1);
function getJobToken() {
const inputToken = core4.getInput("token");
if (inputToken) {
return inputToken;
}
const fallbackToken = process.env.GH_TOKEN || process.env.GITHUB_TOKEN;
if (fallbackToken) {
return fallbackToken;
}
throw new Error("token input is required");
}
// utils/postCleanup.ts
var SHOULD_CHECK_REASON = true;
function buildErrorCommentBody(params) {
const workflowRunLink = params.runId ? `[workflow run logs](https://github.com/${params.owner}/${params.repo}/actions/runs/${params.runId})` : "workflow run logs";
const errorMessage = params.isCancellation ? `This run was cancelled \u{1F6D1}
The workflow was cancelled before completion. Please check the ${workflowRunLink} for details.` : `This run croaked \u{1F635}
The workflow encountered an error before any progress could be reported. Please check the ${workflowRunLink} for details.`;
const footer = buildPullfrogFooter({
triggeredBy: true,
workflowRun: params.runId ? { owner: params.owner, repo: params.repo, runId: params.runId } : void 0
});
return `${errorMessage}${footer}`;
}
async function validateStuckProgressComment(promptInput, octokit, owner, repo) {
if (!promptInput?.progressCommentId) {
log.info("[post] no progressCommentId in prompt input, skipping cleanup");