add magenta log prefixes for delegated subagents (#387)

When delegate() runs multiple subagents in parallel, their logs
interleave without visual distinction. Use AsyncLocalStorage to
automatically prefix every log line inside runSubagent() with the
task label in magenta (e.g. [frontend-review]).

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Colin McDonnell
2026-02-25 05:53:18 +00:00
committed by pullfrog[bot]
co-authored by Cursor
parent d5ab3706db
commit 1ed3da8273
5 changed files with 207 additions and 118 deletions
+66 -45
View File
@@ -135589,6 +135589,7 @@ var Effort = type.enumerated("mini", "auto", "max");
// utils/log.ts // utils/log.ts
var core = __toESM(require_core(), 1); var core = __toESM(require_core(), 1);
var import_table = __toESM(require_src(), 1); var import_table = __toESM(require_src(), 1);
import { AsyncLocalStorage } from "node:async_hooks";
// utils/globals.ts // utils/globals.ts
import { existsSync } from "node:fs"; import { existsSync } from "node:fs";
@@ -135597,6 +135598,23 @@ var isGitHubActions = !!process.env.GITHUB_ACTIONS;
var isInsideDocker = existsSync("/.dockerenv"); var isInsideDocker = existsSync("/.dockerenv");
// utils/log.ts // utils/log.ts
var logContext = new AsyncLocalStorage();
var MAGENTA = "\x1B[35m";
var RESET = "\x1B[0m";
function withLogPrefix(prefix, fn2) {
return logContext.run({ prefix }, fn2);
}
function prefixLines(message) {
const ctx = logContext.getStore();
if (!ctx) return message;
const colored = `${MAGENTA}${ctx.prefix}${RESET} `;
return message.split("\n").map((line) => `${colored}${line}`).join("\n");
}
function prefixPlain(name) {
const ctx = logContext.getStore();
if (!ctx) return name;
return `${ctx.prefix} ${name}`;
}
var isRunnerDebugEnabled = () => core.isDebug(); var isRunnerDebugEnabled = () => core.isDebug();
var isLocalDebugEnabled = () => process.env.LOG_LEVEL === "debug" || process.env.ACTIONS_STEP_DEBUG === "true"; var isLocalDebugEnabled = () => process.env.LOG_LEVEL === "debug" || process.env.ACTIONS_STEP_DEBUG === "true";
var isDebugEnabled = () => isLocalDebugEnabled() || isRunnerDebugEnabled(); var isDebugEnabled = () => isLocalDebugEnabled() || isRunnerDebugEnabled();
@@ -135612,10 +135630,11 @@ ${arg.stack}`;
}).join(" "); }).join(" ");
} }
function startGroup2(name) { function startGroup2(name) {
const prefixed = prefixPlain(name);
if (isGitHubActions) { if (isGitHubActions) {
core.startGroup(name); core.startGroup(prefixed);
} else { } else {
console.group(name); console.group(prefixed);
} }
} }
function endGroup2() { function endGroup2() {
@@ -135688,7 +135707,7 @@ function boxString(text, options) {
} }
function box(text, options) { function box(text, options) {
const boxContent = boxString(text, options); const boxContent = boxString(text, options);
core.info(boxContent); core.info(prefixLines(boxContent));
} }
async function writeSummary(text) { async function writeSummary(text) {
if (!isGitHubActions) return; if (!isGitHubActions) return;
@@ -135708,42 +135727,42 @@ function printTable(rows, options) {
); );
const formatted = (0, import_table.table)(tableData); const formatted = (0, import_table.table)(tableData);
if (title) { if (title) {
core.info(` core.info(prefixLines(`
${title}`); ${title}`));
} }
core.info(` core.info(prefixLines(`
${formatted} ${formatted}
`); `));
} }
function separator(length = 50) { function separator(length = 50) {
const separatorText = "\u2500".repeat(length); const separatorText = "\u2500".repeat(length);
core.info(separatorText); core.info(prefixLines(separatorText));
} }
var log = { var log = {
/** Print info message */ /** Print info message */
info: (...args2) => { info: (...args2) => {
core.info(`${ts()}${formatArgs(args2)}`); core.info(prefixLines(`${ts()}${formatArgs(args2)}`));
}, },
/** Print a warning message. Use only for warnings that should be displayed in the job summary. */ /** Print a warning message. Use only for warnings that should be displayed in the job summary. */
warning: (...args2) => { warning: (...args2) => {
core.warning(`${ts()}${formatArgs(args2)}`); core.warning(prefixLines(`${ts()}${formatArgs(args2)}`));
}, },
/** Print an error message. Use only for errors that should be displayed in the job summary. */ /** Print an error message. Use only for errors that should be displayed in the job summary. */
error: (...args2) => { error: (...args2) => {
core.error(`${ts()}${formatArgs(args2)}`); core.error(prefixLines(`${ts()}${formatArgs(args2)}`));
}, },
/** Print success message */ /** Print success message */
success: (...args2) => { success: (...args2) => {
core.info(`${ts()}\xBB ${formatArgs(args2)}`); core.info(prefixLines(`${ts()}\xBB ${formatArgs(args2)}`));
}, },
/** Print debug message (only when debug mode is enabled) */ /** Print debug message (only when debug mode is enabled) */
debug: (...args2) => { debug: (...args2) => {
if (isRunnerDebugEnabled()) { if (isRunnerDebugEnabled()) {
core.debug(formatArgs(args2)); core.debug(prefixLines(formatArgs(args2)));
return; return;
} }
if (isLocalDebugEnabled()) { if (isLocalDebugEnabled()) {
core.info(`${ts()}[DEBUG] ${formatArgs(args2)}`); core.info(prefixLines(`${ts()}[DEBUG] ${formatArgs(args2)}`));
} }
}, },
/** Print a formatted box with text */ /** Print a formatted box with text */
@@ -136443,41 +136462,43 @@ ${params.instructions}`;
}; };
} }
async function runSubagent(params) { async function runSubagent(params) {
params.subagent.keepAliveInterval = setInterval(markActivity, 3e4); return withLogPrefix(`[${params.subagent.label}]`, async () => {
const mcpServer = await startSubagentMcpServer({ params.subagent.keepAliveInterval = setInterval(markActivity, 3e4);
ctx: params.ctx, const mcpServer = await startSubagentMcpServer({
subagentId: params.subagent.id
});
const subagentTmpdir = join(params.ctx.tmpdir, params.subagent.id);
mkdirSync(subagentTmpdir, { recursive: true });
try {
const subagentPayload = { ...params.ctx.payload, effort: params.effort };
const subagentInstructions = buildSubagentInstructions({
ctx: params.ctx, ctx: params.ctx,
label: params.subagent.label, subagentId: params.subagent.id
instructions: params.instructions
}); });
const result = await params.ctx.agent.run({ const subagentTmpdir = join(params.ctx.tmpdir, params.subagent.id);
payload: subagentPayload, mkdirSync(subagentTmpdir, { recursive: true });
mcpServerUrl: mcpServer.url,
tmpdir: subagentTmpdir,
instructions: subagentInstructions
});
params.subagent.usage = result.usage;
writeFileSync(params.subagent.stdoutFilePath, result.output ?? "", "utf-8");
completeSubagent({ ctx: params.ctx, subagent: params.subagent, success: result.success });
return { success: result.success, error: result.error };
} catch (err) {
const errorMessage = err instanceof Error ? err.message : String(err);
try { try {
writeFileSync(params.subagent.stdoutFilePath, "", "utf-8"); const subagentPayload = { ...params.ctx.payload, effort: params.effort };
} catch { const subagentInstructions = buildSubagentInstructions({
ctx: params.ctx,
label: params.subagent.label,
instructions: params.instructions
});
const result = await params.ctx.agent.run({
payload: subagentPayload,
mcpServerUrl: mcpServer.url,
tmpdir: subagentTmpdir,
instructions: subagentInstructions
});
params.subagent.usage = result.usage;
writeFileSync(params.subagent.stdoutFilePath, result.output ?? "", "utf-8");
completeSubagent({ ctx: params.ctx, subagent: params.subagent, success: result.success });
return { success: result.success, error: result.error };
} catch (err) {
const errorMessage = err instanceof Error ? err.message : String(err);
try {
writeFileSync(params.subagent.stdoutFilePath, "", "utf-8");
} catch {
}
completeSubagent({ ctx: params.ctx, subagent: params.subagent, success: false });
return { success: false, error: errorMessage };
} finally {
await mcpServer.stop();
} }
completeSubagent({ ctx: params.ctx, subagent: params.subagent, success: false }); });
return { success: false, error: errorMessage };
} finally {
await mcpServer.stop();
}
} }
// mcp/askQuestion.ts // mcp/askQuestion.ts
+30 -14
View File
@@ -25507,6 +25507,7 @@ var core3 = __toESM(require_core(), 1);
// utils/log.ts // utils/log.ts
var core = __toESM(require_core(), 1); var core = __toESM(require_core(), 1);
var import_table = __toESM(require_src(), 1); var import_table = __toESM(require_src(), 1);
import { AsyncLocalStorage } from "node:async_hooks";
// utils/globals.ts // utils/globals.ts
import { existsSync } from "node:fs"; import { existsSync } from "node:fs";
@@ -25515,6 +25516,20 @@ var isGitHubActions = !!process.env.GITHUB_ACTIONS;
var isInsideDocker = existsSync("/.dockerenv"); var isInsideDocker = existsSync("/.dockerenv");
// utils/log.ts // utils/log.ts
var logContext = new AsyncLocalStorage();
var MAGENTA = "\x1B[35m";
var RESET = "\x1B[0m";
function prefixLines(message) {
const ctx = logContext.getStore();
if (!ctx) return message;
const colored = `${MAGENTA}${ctx.prefix}${RESET} `;
return message.split("\n").map((line) => `${colored}${line}`).join("\n");
}
function prefixPlain(name) {
const ctx = logContext.getStore();
if (!ctx) return name;
return `${ctx.prefix} ${name}`;
}
var isRunnerDebugEnabled = () => core.isDebug(); var isRunnerDebugEnabled = () => core.isDebug();
var isLocalDebugEnabled = () => process.env.LOG_LEVEL === "debug" || process.env.ACTIONS_STEP_DEBUG === "true"; var isLocalDebugEnabled = () => process.env.LOG_LEVEL === "debug" || process.env.ACTIONS_STEP_DEBUG === "true";
var isDebugEnabled = () => isLocalDebugEnabled() || isRunnerDebugEnabled(); var isDebugEnabled = () => isLocalDebugEnabled() || isRunnerDebugEnabled();
@@ -25530,10 +25545,11 @@ ${arg.stack}`;
}).join(" "); }).join(" ");
} }
function startGroup2(name) { function startGroup2(name) {
const prefixed = prefixPlain(name);
if (isGitHubActions) { if (isGitHubActions) {
core.startGroup(name); core.startGroup(prefixed);
} else { } else {
console.group(name); console.group(prefixed);
} }
} }
function endGroup2() { function endGroup2() {
@@ -25606,7 +25622,7 @@ function boxString(text, options) {
} }
function box(text, options) { function box(text, options) {
const boxContent = boxString(text, options); const boxContent = boxString(text, options);
core.info(boxContent); core.info(prefixLines(boxContent));
} }
function printTable(rows, options) { function printTable(rows, options) {
const { title } = options || {}; const { title } = options || {};
@@ -25620,42 +25636,42 @@ function printTable(rows, options) {
); );
const formatted = (0, import_table.table)(tableData); const formatted = (0, import_table.table)(tableData);
if (title) { if (title) {
core.info(` core.info(prefixLines(`
${title}`); ${title}`));
} }
core.info(` core.info(prefixLines(`
${formatted} ${formatted}
`); `));
} }
function separator(length = 50) { function separator(length = 50) {
const separatorText = "\u2500".repeat(length); const separatorText = "\u2500".repeat(length);
core.info(separatorText); core.info(prefixLines(separatorText));
} }
var log = { var log = {
/** Print info message */ /** Print info message */
info: (...args) => { info: (...args) => {
core.info(`${ts()}${formatArgs(args)}`); core.info(prefixLines(`${ts()}${formatArgs(args)}`));
}, },
/** Print a warning message. Use only for warnings that should be displayed in the job summary. */ /** Print a warning message. Use only for warnings that should be displayed in the job summary. */
warning: (...args) => { warning: (...args) => {
core.warning(`${ts()}${formatArgs(args)}`); core.warning(prefixLines(`${ts()}${formatArgs(args)}`));
}, },
/** Print an error message. Use only for errors that should be displayed in the job summary. */ /** Print an error message. Use only for errors that should be displayed in the job summary. */
error: (...args) => { error: (...args) => {
core.error(`${ts()}${formatArgs(args)}`); core.error(prefixLines(`${ts()}${formatArgs(args)}`));
}, },
/** Print success message */ /** Print success message */
success: (...args) => { success: (...args) => {
core.info(`${ts()}\xBB ${formatArgs(args)}`); core.info(prefixLines(`${ts()}\xBB ${formatArgs(args)}`));
}, },
/** Print debug message (only when debug mode is enabled) */ /** Print debug message (only when debug mode is enabled) */
debug: (...args) => { debug: (...args) => {
if (isRunnerDebugEnabled()) { if (isRunnerDebugEnabled()) {
core.debug(formatArgs(args)); core.debug(prefixLines(formatArgs(args)));
return; return;
} }
if (isLocalDebugEnabled()) { if (isLocalDebugEnabled()) {
core.info(`${ts()}[DEBUG] ${formatArgs(args)}`); core.info(prefixLines(`${ts()}[DEBUG] ${formatArgs(args)}`));
} }
}, },
/** Print a formatted box with text */ /** Print a formatted box with text */
+36 -33
View File
@@ -6,6 +6,7 @@ import type { Effort } from "../external.ts";
import { ghPullfrogMcpName } from "../external.ts"; import { ghPullfrogMcpName } from "../external.ts";
import { markActivity } from "../utils/activity.ts"; import { markActivity } from "../utils/activity.ts";
import type { ResolvedInstructions } from "../utils/instructions.ts"; import type { ResolvedInstructions } from "../utils/instructions.ts";
import { withLogPrefix } from "../utils/log.ts";
import { type SubagentState, startSubagentMcpServer, type ToolContext } from "./server.ts"; import { type SubagentState, startSubagentMcpServer, type ToolContext } from "./server.ts";
type CreateSubagentParams = { type CreateSubagentParams = {
@@ -132,41 +133,43 @@ type RunSubagentResult = {
}; };
export async function runSubagent(params: RunSubagentParams): Promise<RunSubagentResult> { export async function runSubagent(params: RunSubagentParams): Promise<RunSubagentResult> {
params.subagent.keepAliveInterval = setInterval(markActivity, 30_000); return withLogPrefix(`[${params.subagent.label}]`, async () => {
const mcpServer = await startSubagentMcpServer({ params.subagent.keepAliveInterval = setInterval(markActivity, 30_000);
ctx: params.ctx, const mcpServer = await startSubagentMcpServer({
subagentId: params.subagent.id,
});
// each subagent gets its own tmpdir so parallel agents don't clobber config files
const subagentTmpdir = join(params.ctx.tmpdir, params.subagent.id);
mkdirSync(subagentTmpdir, { recursive: true });
try {
const subagentPayload = { ...params.ctx.payload, effort: params.effort };
const subagentInstructions = buildSubagentInstructions({
ctx: params.ctx, ctx: params.ctx,
label: params.subagent.label, subagentId: params.subagent.id,
instructions: params.instructions,
}); });
const result = await params.ctx.agent.run({ // each subagent gets its own tmpdir so parallel agents don't clobber config files
payload: subagentPayload, const subagentTmpdir = join(params.ctx.tmpdir, params.subagent.id);
mcpServerUrl: mcpServer.url, mkdirSync(subagentTmpdir, { recursive: true });
tmpdir: subagentTmpdir,
instructions: subagentInstructions,
});
params.subagent.usage = result.usage;
writeFileSync(params.subagent.stdoutFilePath, result.output ?? "", "utf-8");
completeSubagent({ ctx: params.ctx, subagent: params.subagent, success: result.success });
return { success: result.success, error: result.error };
} catch (err) {
const errorMessage = err instanceof Error ? err.message : String(err);
try { try {
writeFileSync(params.subagent.stdoutFilePath, "", "utf-8"); const subagentPayload = { ...params.ctx.payload, effort: params.effort };
} catch { const subagentInstructions = buildSubagentInstructions({
// best-effort ctx: params.ctx,
label: params.subagent.label,
instructions: params.instructions,
});
const result = await params.ctx.agent.run({
payload: subagentPayload,
mcpServerUrl: mcpServer.url,
tmpdir: subagentTmpdir,
instructions: subagentInstructions,
});
params.subagent.usage = result.usage;
writeFileSync(params.subagent.stdoutFilePath, result.output ?? "", "utf-8");
completeSubagent({ ctx: params.ctx, subagent: params.subagent, success: result.success });
return { success: result.success, error: result.error };
} catch (err) {
const errorMessage = err instanceof Error ? err.message : String(err);
try {
writeFileSync(params.subagent.stdoutFilePath, "", "utf-8");
} catch {
// best-effort
}
completeSubagent({ ctx: params.ctx, subagent: params.subagent, success: false });
return { success: false, error: errorMessage };
} finally {
await mcpServer.stop();
} }
completeSubagent({ ctx: params.ctx, subagent: params.subagent, success: false }); });
return { success: false, error: errorMessage };
} finally {
await mcpServer.stop();
}
} }
+30 -14
View File
@@ -28846,6 +28846,7 @@ var require_semver2 = __commonJS({
// utils/log.ts // utils/log.ts
var core = __toESM(require_core(), 1); var core = __toESM(require_core(), 1);
var import_table = __toESM(require_src(), 1); var import_table = __toESM(require_src(), 1);
import { AsyncLocalStorage } from "node:async_hooks";
// utils/globals.ts // utils/globals.ts
import { existsSync } from "node:fs"; import { existsSync } from "node:fs";
@@ -28854,6 +28855,20 @@ var isGitHubActions = !!process.env.GITHUB_ACTIONS;
var isInsideDocker = existsSync("/.dockerenv"); var isInsideDocker = existsSync("/.dockerenv");
// utils/log.ts // utils/log.ts
var logContext = new AsyncLocalStorage();
var MAGENTA = "\x1B[35m";
var RESET = "\x1B[0m";
function prefixLines(message) {
const ctx = logContext.getStore();
if (!ctx) return message;
const colored = `${MAGENTA}${ctx.prefix}${RESET} `;
return message.split("\n").map((line) => `${colored}${line}`).join("\n");
}
function prefixPlain(name) {
const ctx = logContext.getStore();
if (!ctx) return name;
return `${ctx.prefix} ${name}`;
}
var isRunnerDebugEnabled = () => core.isDebug(); var isRunnerDebugEnabled = () => core.isDebug();
var isLocalDebugEnabled = () => process.env.LOG_LEVEL === "debug" || process.env.ACTIONS_STEP_DEBUG === "true"; var isLocalDebugEnabled = () => process.env.LOG_LEVEL === "debug" || process.env.ACTIONS_STEP_DEBUG === "true";
var isDebugEnabled = () => isLocalDebugEnabled() || isRunnerDebugEnabled(); var isDebugEnabled = () => isLocalDebugEnabled() || isRunnerDebugEnabled();
@@ -28869,10 +28884,11 @@ ${arg.stack}`;
}).join(" "); }).join(" ");
} }
function startGroup2(name) { function startGroup2(name) {
const prefixed = prefixPlain(name);
if (isGitHubActions) { if (isGitHubActions) {
core.startGroup(name); core.startGroup(prefixed);
} else { } else {
console.group(name); console.group(prefixed);
} }
} }
function endGroup2() { function endGroup2() {
@@ -28945,7 +28961,7 @@ function boxString(text, options) {
} }
function box(text, options) { function box(text, options) {
const boxContent = boxString(text, options); const boxContent = boxString(text, options);
core.info(boxContent); core.info(prefixLines(boxContent));
} }
function printTable(rows, options) { function printTable(rows, options) {
const { title } = options || {}; const { title } = options || {};
@@ -28959,42 +28975,42 @@ function printTable(rows, options) {
); );
const formatted = (0, import_table.table)(tableData); const formatted = (0, import_table.table)(tableData);
if (title) { if (title) {
core.info(` core.info(prefixLines(`
${title}`); ${title}`));
} }
core.info(` core.info(prefixLines(`
${formatted} ${formatted}
`); `));
} }
function separator(length = 50) { function separator(length = 50) {
const separatorText = "\u2500".repeat(length); const separatorText = "\u2500".repeat(length);
core.info(separatorText); core.info(prefixLines(separatorText));
} }
var log = { var log = {
/** Print info message */ /** Print info message */
info: (...args2) => { info: (...args2) => {
core.info(`${ts()}${formatArgs(args2)}`); core.info(prefixLines(`${ts()}${formatArgs(args2)}`));
}, },
/** Print a warning message. Use only for warnings that should be displayed in the job summary. */ /** Print a warning message. Use only for warnings that should be displayed in the job summary. */
warning: (...args2) => { warning: (...args2) => {
core.warning(`${ts()}${formatArgs(args2)}`); core.warning(prefixLines(`${ts()}${formatArgs(args2)}`));
}, },
/** Print an error message. Use only for errors that should be displayed in the job summary. */ /** Print an error message. Use only for errors that should be displayed in the job summary. */
error: (...args2) => { error: (...args2) => {
core.error(`${ts()}${formatArgs(args2)}`); core.error(prefixLines(`${ts()}${formatArgs(args2)}`));
}, },
/** Print success message */ /** Print success message */
success: (...args2) => { success: (...args2) => {
core.info(`${ts()}\xBB ${formatArgs(args2)}`); core.info(prefixLines(`${ts()}\xBB ${formatArgs(args2)}`));
}, },
/** Print debug message (only when debug mode is enabled) */ /** Print debug message (only when debug mode is enabled) */
debug: (...args2) => { debug: (...args2) => {
if (isRunnerDebugEnabled()) { if (isRunnerDebugEnabled()) {
core.debug(formatArgs(args2)); core.debug(prefixLines(formatArgs(args2)));
return; return;
} }
if (isLocalDebugEnabled()) { if (isLocalDebugEnabled()) {
core.info(`${ts()}[DEBUG] ${formatArgs(args2)}`); core.info(prefixLines(`${ts()}[DEBUG] ${formatArgs(args2)}`));
} }
}, },
/** Print a formatted box with text */ /** Print a formatted box with text */
+45 -12
View File
@@ -2,11 +2,43 @@
* Logging utilities that work well in both local and GitHub Actions environments * Logging utilities that work well in both local and GitHub Actions environments
*/ */
import { AsyncLocalStorage } from "node:async_hooks";
import * as core from "@actions/core"; import * as core from "@actions/core";
import { table } from "table"; import { table } from "table";
import type { AgentUsage } from "../agents/shared.ts"; import type { AgentUsage } from "../agents/shared.ts";
import { isGitHubActions, isInsideDocker } from "./globals.ts"; import { isGitHubActions, isInsideDocker } from "./globals.ts";
// --- subagent log prefix via AsyncLocalStorage ---
type LogContext = { prefix: string };
const logContext = new AsyncLocalStorage<LogContext>();
const MAGENTA = "\x1b[35m";
const RESET = "\x1b[0m";
/** run `fn` with every log line prefixed by `prefix` (e.g. "[task-label]") in magenta */
export function withLogPrefix<T>(prefix: string, fn: () => Promise<T>): Promise<T> {
return logContext.run({ prefix }, fn);
}
function prefixLines(message: string): string {
const ctx = logContext.getStore();
if (!ctx) return message;
const colored = `${MAGENTA}${ctx.prefix}${RESET} `;
return message
.split("\n")
.map((line) => `${colored}${line}`)
.join("\n");
}
/** plain-text prefix (no ANSI) for GitHub Actions group names */
function prefixPlain(name: string): string {
const ctx = logContext.getStore();
if (!ctx) return name;
return `${ctx.prefix} ${name}`;
}
const isRunnerDebugEnabled = () => core.isDebug(); const isRunnerDebugEnabled = () => core.isDebug();
const isLocalDebugEnabled = () => const isLocalDebugEnabled = () =>
@@ -36,10 +68,11 @@ function formatArgs(args: unknown[]): string {
* Start a collapsed group (GitHub Actions) or regular group (local) * Start a collapsed group (GitHub Actions) or regular group (local)
*/ */
function startGroup(name: string): void { function startGroup(name: string): void {
const prefixed = prefixPlain(name);
if (isGitHubActions) { if (isGitHubActions) {
core.startGroup(name); core.startGroup(prefixed);
} else { } else {
console.group(name); console.group(prefixed);
} }
} }
@@ -153,7 +186,7 @@ function box(
} }
): void { ): void {
const boxContent = boxString(text, options); const boxContent = boxString(text, options);
core.info(boxContent); core.info(prefixLines(boxContent));
} }
/** /**
@@ -200,9 +233,9 @@ function printTable(
const formatted = table(tableData); const formatted = table(tableData);
if (title) { if (title) {
core.info(`\n${title}`); core.info(prefixLines(`\n${title}`));
} }
core.info(`\n${formatted}\n`); core.info(prefixLines(`\n${formatted}\n`));
} }
/** /**
@@ -210,7 +243,7 @@ function printTable(
*/ */
function separator(length: number = 50): void { function separator(length: number = 50): void {
const separatorText = "─".repeat(length); const separatorText = "─".repeat(length);
core.info(separatorText); core.info(prefixLines(separatorText));
} }
/** /**
@@ -219,32 +252,32 @@ function separator(length: number = 50): void {
export const log = { export const log = {
/** Print info message */ /** Print info message */
info: (...args: unknown[]): void => { info: (...args: unknown[]): void => {
core.info(`${ts()}${formatArgs(args)}`); core.info(prefixLines(`${ts()}${formatArgs(args)}`));
}, },
/** Print a warning message. Use only for warnings that should be displayed in the job summary. */ /** Print a warning message. Use only for warnings that should be displayed in the job summary. */
warning: (...args: unknown[]): void => { warning: (...args: unknown[]): void => {
core.warning(`${ts()}${formatArgs(args)}`); core.warning(prefixLines(`${ts()}${formatArgs(args)}`));
}, },
/** Print an error message. Use only for errors that should be displayed in the job summary. */ /** Print an error message. Use only for errors that should be displayed in the job summary. */
error: (...args: unknown[]): void => { error: (...args: unknown[]): void => {
core.error(`${ts()}${formatArgs(args)}`); core.error(prefixLines(`${ts()}${formatArgs(args)}`));
}, },
/** Print success message */ /** Print success message */
success: (...args: unknown[]): void => { success: (...args: unknown[]): void => {
core.info(`${ts()}» ${formatArgs(args)}`); core.info(prefixLines(`${ts()}» ${formatArgs(args)}`));
}, },
/** Print debug message (only when debug mode is enabled) */ /** Print debug message (only when debug mode is enabled) */
debug: (...args: unknown[]): void => { debug: (...args: unknown[]): void => {
if (isRunnerDebugEnabled()) { if (isRunnerDebugEnabled()) {
core.debug(formatArgs(args)); core.debug(prefixLines(formatArgs(args)));
return; return;
} }
if (isLocalDebugEnabled()) { if (isLocalDebugEnabled()) {
core.info(`${ts()}[DEBUG] ${formatArgs(args)}`); core.info(prefixLines(`${ts()}[DEBUG] ${formatArgs(args)}`));
} }
}, },