Skip to content

Commit cd1ea52

Browse files
colinhackscursoragent
authored andcommitted
fix node24 PATH propagation and improve action logging (#381)
Add node24 binary directory to PATH in action entry point so spawned processes (pnpm, npm, etc.) resolve to the correct node version instead of the runner's default v20. Improve delegate task result logging with success/failure status and summaries. Use collapsible log groups for dependency install output instead of raw streaming. Co-authored-by: Cursor <[email protected]>
1 parent 4f1e4a2 commit cd1ea52

5 files changed

Lines changed: 61 additions & 25 deletions

File tree

entry

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -56274,7 +56274,7 @@ var require_snapshot_recorder = __commonJS({
5627456274
"node_modules/.pnpm/[email protected]/node_modules/undici/lib/mock/snapshot-recorder.js"(exports, module) {
5627556275
"use strict";
5627656276
var { writeFile, readFile, mkdir } = __require("node:fs/promises");
56277-
var { dirname: dirname2, resolve: resolve3 } = __require("node:path");
56277+
var { dirname: dirname3, resolve: resolve3 } = __require("node:path");
5627856278
var { setTimeout: setTimeout2, clearTimeout: clearTimeout2 } = __require("node:timers");
5627956279
var { InvalidArgumentError, UndiciError } = require_errors4();
5628056280
var { hashId, isUrlExcludedFactory, normalizeHeaders, createHeaderFilters } = require_snapshot_utils();
@@ -56498,7 +56498,7 @@ var require_snapshot_recorder = __commonJS({
5649856498
throw new InvalidArgumentError("Snapshot path is required");
5649956499
}
5650056500
const resolvedPath = resolve3(path3);
56501-
await mkdir(dirname2(resolvedPath), { recursive: true });
56501+
await mkdir(dirname3(resolvedPath), { recursive: true });
5650256502
const data = Array.from(this.#snapshots.entries()).map(([hash2, snapshot2]) => ({
5650356503
hash: hash2,
5650456504
snapshot: snapshot2
@@ -97612,6 +97612,7 @@ var require_semver2 = __commonJS({
9761297612

9761397613
// entry.ts
9761497614
var core5 = __toESM(require_core(), 1);
97615+
import { dirname as dirname2 } from "node:path";
9761597616

9761697617
// node_modules/.pnpm/@[email protected]/node_modules/@ark/util/out/arrays.js
9761797618
var liftArray = (data) => Array.isArray(data) ? data : [data];
@@ -141626,7 +141627,10 @@ function DelegateTool(ctx) {
141626141627
if (!ctx.toolState.selectedMode) {
141627141628
log.info(`\xBB warning: delegating without calling select_mode first (mode=${mode})`);
141628141629
}
141629-
log.info(`\xBB delegating ${params.tasks.length} task(s) in parallel (mode=${mode})`);
141630+
const n = params.tasks.length;
141631+
log.info(
141632+
`\xBB delegating ${n} task${n === 1 ? "" : "s"}${n > 1 ? " in parallel" : ""} (mode=${mode})`
141633+
);
141630141634
const taskEntries = params.tasks.map((task) => {
141631141635
const effort = task.effort ?? "auto";
141632141636
const subagent = createSubagentState({ ctx, mode, label: task.label });
@@ -141646,10 +141650,12 @@ function DelegateTool(ctx) {
141646141650
const results = taskEntries.map((entry, i) => {
141647141651
const outcome = settled[i];
141648141652
const error49 = outcome.status === "rejected" ? String(outcome.reason) : outcome.value.error;
141649-
log.debug(
141650-
`\xBB task "${entry.task.label}" result: output=${entry.subagent.output !== void 0}, status=${entry.subagent.status}`
141653+
const result = buildTaskResult(entry.task.label, entry.effort, entry.subagent, error49);
141654+
log.info(
141655+
`\xBB task "${entry.task.label}" ${result.success ? "succeeded" : "failed"}:
141656+
${result.summary}`
141651141657
);
141652-
return buildTaskResult(entry.task.label, entry.effort, entry.subagent, error49);
141658+
return result;
141653141659
});
141654141660
const succeeded = results.filter((r) => r.success).length;
141655141661
log.info(`\xBB delegation completed: ${succeeded}/${results.length} succeeded (mode=${mode})`);
@@ -142071,12 +142077,15 @@ var installNodeDependencies = {
142071142077
const result = await spawn({
142072142078
cmd: resolved.command,
142073142079
args: resolved.args,
142074-
env: { PATH: process.env.PATH || "", HOME: process.env.HOME || "" },
142075-
onStdout: (chunk) => process.stdout.write(chunk),
142076-
onStderr: (chunk) => process.stderr.write(chunk)
142080+
env: { PATH: process.env.PATH || "", HOME: process.env.HOME || "" }
142077142081
});
142082+
const output = [result.stdout, result.stderr].filter(Boolean).join("\n").trim();
142083+
if (output) {
142084+
log.startGroup(`${fullCommand} output`);
142085+
log.info(output);
142086+
log.endGroup();
142087+
}
142078142088
if (result.exitCode !== 0) {
142079-
const output = [result.stdout, result.stderr].filter(Boolean).join("\n").trim();
142080142089
const errorMessage = output || `exited with code ${result.exitCode}`;
142081142090
return {
142082142091
language: "node",
@@ -142213,20 +142222,26 @@ var installPythonDependencies = {
142213142222
}
142214142223
}
142215142224
const [cmd, ...args2] = config3.installCmd;
142216-
log.info(`\xBB running: ${cmd} ${args2.join(" ")}`);
142225+
const fullCommand = `${cmd} ${args2.join(" ")}`;
142226+
log.info(`\xBB running: ${fullCommand}`);
142217142227
const result = await spawn({
142218142228
cmd,
142219142229
args: args2,
142220-
env: { PATH: process.env.PATH || "", HOME: process.env.HOME || "" },
142221-
onStderr: (chunk) => process.stderr.write(chunk)
142230+
env: { PATH: process.env.PATH || "", HOME: process.env.HOME || "" }
142222142231
});
142232+
const output = [result.stdout, result.stderr].filter(Boolean).join("\n").trim();
142233+
if (output) {
142234+
log.startGroup(`${fullCommand} output`);
142235+
log.info(output);
142236+
log.endGroup();
142237+
}
142223142238
if (result.exitCode !== 0) {
142224142239
return {
142225142240
language: "python",
142226142241
packageManager: config3.tool,
142227142242
configFile: config3.file,
142228142243
dependenciesInstalled: false,
142229-
issues: [result.stderr || `${cmd} exited with code ${result.exitCode}`]
142244+
issues: [output || `${cmd} exited with code ${result.exitCode}`]
142230142245
};
142231142246
}
142232142247
return {
@@ -147697,6 +147712,7 @@ ${instructions.user}` : null,
147697147712
}
147698147713

147699147714
// entry.ts
147715+
process.env.PATH = `${dirname2(process.execPath)}:${process.env.PATH}`;
147700147716
async function run() {
147701147717
try {
147702147718
const result = await main();

entry.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,15 @@
44
* entry point for pullfrog/pullfrog - unified action
55
*/
66

7+
import { dirname } from "node:path";
78
import * as core from "@actions/core";
89
import { main } from "./main.ts";
910

11+
// GitHub Actions runs the action entry point with the node24 binary specified
12+
// in action.yml, but doesn't add that binary's directory to PATH. Without this,
13+
// spawned processes (pnpm, npm, etc.) resolve to the runner's default node (v20).
14+
process.env.PATH = `${dirname(process.execPath)}:${process.env.PATH}`;
15+
1016
async function run(): Promise<void> {
1117
try {
1218
const result = await main();

mcp/delegate.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,10 @@ export function DelegateTool(ctx: ToolContext) {
7777
}
7878

7979
// matched by delegate test validators — update tests if changed
80-
log.info(`» delegating ${params.tasks.length} task(s) in parallel (mode=${mode})`);
80+
const n = params.tasks.length;
81+
log.info(
82+
`» delegating ${n} task${n === 1 ? "" : "s"}${n > 1 ? " in parallel" : ""} (mode=${mode})`
83+
);
8184

8285
const taskEntries = params.tasks.map((task) => {
8386
const effort = task.effort ?? "auto";
@@ -100,10 +103,11 @@ export function DelegateTool(ctx: ToolContext) {
100103
const results: DelegateTaskResult[] = taskEntries.map((entry, i) => {
101104
const outcome = settled[i];
102105
const error = outcome.status === "rejected" ? String(outcome.reason) : outcome.value.error;
103-
log.debug(
104-
`» task "${entry.task.label}" result: output=${entry.subagent.output !== undefined}, status=${entry.subagent.status}`
106+
const result = buildTaskResult(entry.task.label, entry.effort, entry.subagent, error);
107+
log.info(
108+
`» task "${entry.task.label}" ${result.success ? "succeeded" : "failed"}:\n${result.summary}`
105109
);
106-
return buildTaskResult(entry.task.label, entry.effort, entry.subagent, error);
110+
return result;
107111
});
108112

109113
const succeeded = results.filter((r) => r.success).length;

prep/installNodeDependencies.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -159,13 +159,16 @@ export const installNodeDependencies: PrepDefinition = {
159159
cmd: resolved.command,
160160
args: resolved.args,
161161
env: { PATH: process.env.PATH || "", HOME: process.env.HOME || "" },
162-
onStdout: (chunk) => process.stdout.write(chunk),
163-
onStderr: (chunk) => process.stderr.write(chunk),
164162
});
165163

164+
const output = [result.stdout, result.stderr].filter(Boolean).join("\n").trim();
165+
if (output) {
166+
log.startGroup(`${fullCommand} output`);
167+
log.info(output);
168+
log.endGroup();
169+
}
170+
166171
if (result.exitCode !== 0) {
167-
// combine stdout and stderr for better error context (pnpm often outputs errors to stdout)
168-
const output = [result.stdout, result.stderr].filter(Boolean).join("\n").trim();
169172
const errorMessage = output || `exited with code ${result.exitCode}`;
170173
return {
171174
language: "node",

prep/installPythonDependencies.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,21 +162,28 @@ export const installPythonDependencies: PrepDefinition = {
162162

163163
// run the install command
164164
const [cmd, ...args] = config.installCmd;
165-
log.info(`» running: ${cmd} ${args.join(" ")}`);
165+
const fullCommand = `${cmd} ${args.join(" ")}`;
166+
log.info(`» running: ${fullCommand}`);
166167
const result = await spawn({
167168
cmd,
168169
args,
169170
env: { PATH: process.env.PATH || "", HOME: process.env.HOME || "" },
170-
onStderr: (chunk) => process.stderr.write(chunk),
171171
});
172172

173+
const output = [result.stdout, result.stderr].filter(Boolean).join("\n").trim();
174+
if (output) {
175+
log.startGroup(`${fullCommand} output`);
176+
log.info(output);
177+
log.endGroup();
178+
}
179+
173180
if (result.exitCode !== 0) {
174181
return {
175182
language: "python",
176183
packageManager: config.tool,
177184
configFile: config.file,
178185
dependenciesInstalled: false,
179-
issues: [result.stderr || `${cmd} exited with code ${result.exitCode}`],
186+
issues: [output || `${cmd} exited with code ${result.exitCode}`],
180187
};
181188
}
182189

0 commit comments

Comments
 (0)