mirror of
https://github.com/github/spec-kit.git
synced 2026-08-03 06:26:30 +08:00
fix(workflows): escape the step-progress line so step ids render (and / stops failing the run) (#3783)
`workflow run` and `workflow resume` both print the step-progress line as
`f" ▸ [{sid}] {label} …"`. Rich parses the bracketed step id as a style tag,
which produces three failures on main:
1. The id is SILENTLY SWALLOWED on every run -- the only identifying content on
the line. `id: greet` prints " ▸ shell …"; "[greet]" is absent.
2. An id that forms a closing tag FAILS THE WHOLE RUN. `validate_workflow`
places no charset restriction on step ids, so `id: "/"` is a valid workflow;
the callback then raises MarkupError, which propagates into execute()'s
handler -> run persisted as `failed` with empty `step_results`, the step
never executed, exit 1 with a Rich internals error.
3. An id that is a real style (`bold`, `red`) is applied as FORMATTING to the
rest of the line.
The unescaped `label` (from `step_config["command"]`) compounds it.
Escape the literal bracket with `\[` and escape both interpolated values, at
both sites. This mirrors the `\[<type>]` step-graph precedent already in this
file (workflow_info). Escaping only the values is NOT sufficient -- the
f-string's own brackets are what Rich consumes.
Verified through the real CLI: ids `greet`/`bold`/`a]b` now render verbatim, and
`id: "/"` goes from a failed run to `Status: completed`.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1054,7 +1054,18 @@ def workflow_run(
|
||||
load_custom_steps(project_root)
|
||||
engine = WorkflowEngine(project_root)
|
||||
if not json_output:
|
||||
engine.on_step_start = lambda sid, label: console.print(f" \u25b8 [{sid}] {label} \u2026")
|
||||
# Escape the literal bracket (\[) so Rich renders `[<step id>]` instead
|
||||
# of parsing it as a style tag named after the step id -- which it
|
||||
# silently swallows (losing the only identifying content on the line),
|
||||
# applies as formatting when the id happens to be a real style such as
|
||||
# `bold`, or raises MarkupError when the id forms a closing tag (`/`),
|
||||
# failing the whole run. Escape the interpolated values too, since both
|
||||
# come from workflow YAML. Mirrors the `\[<type>]` step-graph precedent
|
||||
# in workflow_info below.
|
||||
engine.on_step_start = lambda sid, label: console.print(
|
||||
f" \u25b8 \\[{_escape_markup(str(sid))}] "
|
||||
f"{_escape_markup(str(label))} \u2026"
|
||||
)
|
||||
|
||||
err = _error_console(json_output)
|
||||
|
||||
@@ -1176,7 +1187,18 @@ def workflow_resume(
|
||||
load_custom_steps(project_root)
|
||||
engine = WorkflowEngine(project_root)
|
||||
if not json_output:
|
||||
engine.on_step_start = lambda sid, label: console.print(f" \u25b8 [{sid}] {label} \u2026")
|
||||
# Escape the literal bracket (\[) so Rich renders `[<step id>]` instead
|
||||
# of parsing it as a style tag named after the step id -- which it
|
||||
# silently swallows (losing the only identifying content on the line),
|
||||
# applies as formatting when the id happens to be a real style such as
|
||||
# `bold`, or raises MarkupError when the id forms a closing tag (`/`),
|
||||
# failing the whole run. Escape the interpolated values too, since both
|
||||
# come from workflow YAML. Mirrors the `\[<type>]` step-graph precedent
|
||||
# in workflow_info below.
|
||||
engine.on_step_start = lambda sid, label: console.print(
|
||||
f" \u25b8 \\[{_escape_markup(str(sid))}] "
|
||||
f"{_escape_markup(str(label))} \u2026"
|
||||
)
|
||||
|
||||
inputs = _parse_input_values(input_values, json_output=json_output)
|
||||
err = _error_console(json_output)
|
||||
|
||||
Reference in New Issue
Block a user