fix: terminate failed scans in Temporal and surface the reason when following (#429)

* fix(cli): skip splash screen off a TTY (e.g. CI)

* fix: terminate failed scans in Temporal and surface the reason when following

* fix(cli): indent embedded newlines within failure-error segments

* fix(worker): omit the Agent Breakdown section when no agents completed

* fix(cli): don't reprint the failure reason when the log already showed it

* fix(worker): indent embedded newlines within the workflow.log error block
This commit is contained in:
ezl-keygraph
2026-08-24 20:04:47 +05:30
committed by GitHub
parent 53118c6203
commit b13788d8ef
10 changed files with 261 additions and 81 deletions
+31
View File
@@ -0,0 +1,31 @@
/**
* Rendering for the worker's '|'-delimited failure string.
*
* `formatWorkflowError` in the worker joins error segments — phase context, error type,
* message, and remediation hint — with '|' as a delimiter. These helpers turn that raw
* string into readable output for the CLI's own surfaces.
*/
/**
* Split the failure string into trimmed, non-empty lines. Segments are delimited by '|', and a
* segment's own embedded newlines (e.g. a multi-line validation message) become their own lines so
* each aligns with the rest of the block.
*/
export function parseFailureSegments(message: string): string[] {
return message
.split(/[|\n]/)
.map((segment) => segment.trim())
.filter((segment) => segment.length > 0);
}
/** Multi-line block: one segment per indented line (the caller prints the header). */
export function indentFailureSegments(message: string, indent = ' '): string {
return parseFailureSegments(message)
.map((segment) => `${indent}${segment}`)
.join('\n');
}
/** Single-line summary for compact contexts like the status footer. */
export function inlineFailureReason(message: string): string {
return parseFailureSegments(message).join(' — ');
}
+3 -1
View File
@@ -11,6 +11,7 @@ import { BOLD, DIM, GOLD, paint, RED, YELLOW } from '../colors.js';
import { commandPrefix } from '../mode.js';
import type { RunningAgent } from '../temporal-client.js';
import { agentError, deriveAgentStates, isTerminal, phaseGlyphState, type RunState, scanElapsedMs } from './derive.js';
import { inlineFailureReason } from './failure.js';
import { PIPELINE, type PipelineState } from './pipeline.js';
export interface RenderInput {
@@ -229,7 +230,8 @@ function footerLines(input: RenderInput, opts: RenderOptions): string[] {
const temporalValue = temporalDashboardUrl(input.workflowId);
if (isTerminal(input.temporalStatus)) {
const reason = input.failureMessage ?? input.state?.error ?? 'no result recorded';
const rawReason = input.failureMessage ?? input.state?.error;
const reason = rawReason ? inlineFailureReason(rawReason) : 'no result recorded';
return [
footerDivider(opts),
paint(