diff --git a/entry b/entry index 4079762..264c92e 100755 --- a/entry +++ b/entry @@ -56274,7 +56274,7 @@ var require_snapshot_recorder = __commonJS({ "node_modules/.pnpm/undici@7.16.0/node_modules/undici/lib/mock/snapshot-recorder.js"(exports, module) { "use strict"; var { writeFile, readFile, mkdir } = __require("node:fs/promises"); - var { dirname: dirname2, resolve: resolve3 } = __require("node:path"); + var { dirname: dirname3, resolve: resolve3 } = __require("node:path"); var { setTimeout: setTimeout2, clearTimeout: clearTimeout2 } = __require("node:timers"); var { InvalidArgumentError, UndiciError } = require_errors4(); var { hashId, isUrlExcludedFactory, normalizeHeaders, createHeaderFilters } = require_snapshot_utils(); @@ -56498,7 +56498,7 @@ var require_snapshot_recorder = __commonJS({ throw new InvalidArgumentError("Snapshot path is required"); } const resolvedPath = resolve3(path3); - await mkdir(dirname2(resolvedPath), { recursive: true }); + await mkdir(dirname3(resolvedPath), { recursive: true }); const data = Array.from(this.#snapshots.entries()).map(([hash2, snapshot2]) => ({ hash: hash2, snapshot: snapshot2 @@ -97612,6 +97612,7 @@ var require_semver2 = __commonJS({ // entry.ts var core5 = __toESM(require_core(), 1); +import { dirname as dirname2 } from "node:path"; // node_modules/.pnpm/@ark+util@0.56.0/node_modules/@ark/util/out/arrays.js var liftArray = (data) => Array.isArray(data) ? data : [data]; @@ -141626,7 +141627,10 @@ function DelegateTool(ctx) { if (!ctx.toolState.selectedMode) { log.info(`\xBB warning: delegating without calling select_mode first (mode=${mode})`); } - log.info(`\xBB delegating ${params.tasks.length} task(s) in parallel (mode=${mode})`); + const n = params.tasks.length; + log.info( + `\xBB delegating ${n} task${n === 1 ? "" : "s"}${n > 1 ? " in parallel" : ""} (mode=${mode})` + ); const taskEntries = params.tasks.map((task) => { const effort = task.effort ?? "auto"; const subagent = createSubagentState({ ctx, mode, label: task.label }); @@ -141646,10 +141650,12 @@ function DelegateTool(ctx) { const results = taskEntries.map((entry, i) => { const outcome = settled[i]; const error49 = outcome.status === "rejected" ? String(outcome.reason) : outcome.value.error; - log.debug( - `\xBB task "${entry.task.label}" result: output=${entry.subagent.output !== void 0}, status=${entry.subagent.status}` + const result = buildTaskResult(entry.task.label, entry.effort, entry.subagent, error49); + log.info( + `\xBB task "${entry.task.label}" ${result.success ? "succeeded" : "failed"}: +${result.summary}` ); - return buildTaskResult(entry.task.label, entry.effort, entry.subagent, error49); + return result; }); const succeeded = results.filter((r) => r.success).length; log.info(`\xBB delegation completed: ${succeeded}/${results.length} succeeded (mode=${mode})`); @@ -142071,12 +142077,15 @@ var installNodeDependencies = { const result = await spawn({ cmd: resolved.command, args: resolved.args, - env: { PATH: process.env.PATH || "", HOME: process.env.HOME || "" }, - onStdout: (chunk) => process.stdout.write(chunk), - onStderr: (chunk) => process.stderr.write(chunk) + env: { PATH: process.env.PATH || "", HOME: process.env.HOME || "" } }); + const output = [result.stdout, result.stderr].filter(Boolean).join("\n").trim(); + if (output) { + log.startGroup(`${fullCommand} output`); + log.info(output); + log.endGroup(); + } if (result.exitCode !== 0) { - const output = [result.stdout, result.stderr].filter(Boolean).join("\n").trim(); const errorMessage = output || `exited with code ${result.exitCode}`; return { language: "node", @@ -142213,20 +142222,26 @@ var installPythonDependencies = { } } const [cmd, ...args2] = config3.installCmd; - log.info(`\xBB running: ${cmd} ${args2.join(" ")}`); + const fullCommand = `${cmd} ${args2.join(" ")}`; + log.info(`\xBB running: ${fullCommand}`); const result = await spawn({ cmd, args: args2, - env: { PATH: process.env.PATH || "", HOME: process.env.HOME || "" }, - onStderr: (chunk) => process.stderr.write(chunk) + env: { PATH: process.env.PATH || "", HOME: process.env.HOME || "" } }); + const output = [result.stdout, result.stderr].filter(Boolean).join("\n").trim(); + if (output) { + log.startGroup(`${fullCommand} output`); + log.info(output); + log.endGroup(); + } if (result.exitCode !== 0) { return { language: "python", packageManager: config3.tool, configFile: config3.file, dependenciesInstalled: false, - issues: [result.stderr || `${cmd} exited with code ${result.exitCode}`] + issues: [output || `${cmd} exited with code ${result.exitCode}`] }; } return { @@ -147697,6 +147712,7 @@ ${instructions.user}` : null, } // entry.ts +process.env.PATH = `${dirname2(process.execPath)}:${process.env.PATH}`; async function run() { try { const result = await main(); diff --git a/entry.ts b/entry.ts index ef89d70..a89ae37 100644 --- a/entry.ts +++ b/entry.ts @@ -4,9 +4,15 @@ * entry point for pullfrog/pullfrog - unified action */ +import { dirname } from "node:path"; import * as core from "@actions/core"; import { main } from "./main.ts"; +// GitHub Actions runs the action entry point with the node24 binary specified +// in action.yml, but doesn't add that binary's directory to PATH. Without this, +// spawned processes (pnpm, npm, etc.) resolve to the runner's default node (v20). +process.env.PATH = `${dirname(process.execPath)}:${process.env.PATH}`; + async function run(): Promise { try { const result = await main(); diff --git a/mcp/delegate.ts b/mcp/delegate.ts index 6371e85..b725b78 100644 --- a/mcp/delegate.ts +++ b/mcp/delegate.ts @@ -77,7 +77,10 @@ export function DelegateTool(ctx: ToolContext) { } // matched by delegate test validators — update tests if changed - log.info(`» delegating ${params.tasks.length} task(s) in parallel (mode=${mode})`); + const n = params.tasks.length; + log.info( + `» delegating ${n} task${n === 1 ? "" : "s"}${n > 1 ? " in parallel" : ""} (mode=${mode})` + ); const taskEntries = params.tasks.map((task) => { const effort = task.effort ?? "auto"; @@ -100,10 +103,11 @@ export function DelegateTool(ctx: ToolContext) { const results: DelegateTaskResult[] = taskEntries.map((entry, i) => { const outcome = settled[i]; const error = outcome.status === "rejected" ? String(outcome.reason) : outcome.value.error; - log.debug( - `» task "${entry.task.label}" result: output=${entry.subagent.output !== undefined}, status=${entry.subagent.status}` + const result = buildTaskResult(entry.task.label, entry.effort, entry.subagent, error); + log.info( + `» task "${entry.task.label}" ${result.success ? "succeeded" : "failed"}:\n${result.summary}` ); - return buildTaskResult(entry.task.label, entry.effort, entry.subagent, error); + return result; }); const succeeded = results.filter((r) => r.success).length; diff --git a/prep/installNodeDependencies.ts b/prep/installNodeDependencies.ts index 15f1e21..d315217 100644 --- a/prep/installNodeDependencies.ts +++ b/prep/installNodeDependencies.ts @@ -159,13 +159,16 @@ export const installNodeDependencies: PrepDefinition = { cmd: resolved.command, args: resolved.args, env: { PATH: process.env.PATH || "", HOME: process.env.HOME || "" }, - onStdout: (chunk) => process.stdout.write(chunk), - onStderr: (chunk) => process.stderr.write(chunk), }); + const output = [result.stdout, result.stderr].filter(Boolean).join("\n").trim(); + if (output) { + log.startGroup(`${fullCommand} output`); + log.info(output); + log.endGroup(); + } + if (result.exitCode !== 0) { - // combine stdout and stderr for better error context (pnpm often outputs errors to stdout) - const output = [result.stdout, result.stderr].filter(Boolean).join("\n").trim(); const errorMessage = output || `exited with code ${result.exitCode}`; return { language: "node", diff --git a/prep/installPythonDependencies.ts b/prep/installPythonDependencies.ts index 0892115..b8dcc57 100644 --- a/prep/installPythonDependencies.ts +++ b/prep/installPythonDependencies.ts @@ -162,21 +162,28 @@ export const installPythonDependencies: PrepDefinition = { // run the install command const [cmd, ...args] = config.installCmd; - log.info(`» running: ${cmd} ${args.join(" ")}`); + const fullCommand = `${cmd} ${args.join(" ")}`; + log.info(`» running: ${fullCommand}`); const result = await spawn({ cmd, args, env: { PATH: process.env.PATH || "", HOME: process.env.HOME || "" }, - onStderr: (chunk) => process.stderr.write(chunk), }); + const output = [result.stdout, result.stderr].filter(Boolean).join("\n").trim(); + if (output) { + log.startGroup(`${fullCommand} output`); + log.info(output); + log.endGroup(); + } + if (result.exitCode !== 0) { return { language: "python", packageManager: config.tool, configFile: config.file, dependenciesInstalled: false, - issues: [result.stderr || `${cmd} exited with code ${result.exitCode}`], + issues: [output || `${cmd} exited with code ${result.exitCode}`], }; }