fix: make text-mode progress output usable in CI#890
Conversation
| echo "line three of stdout" | ||
| exit 1 | ||
| """# | ||
| } |
There was a problem hiding this comment.
Deliberately failing CI step must not be merged
High Severity
The demo-fail step is a temporary debugging aid that unconditionally fails with exit 1. If this lands on the default branch, it will cause every CI run to fail on any commit that touches **/*.rs files. The PR description's test plan calls for removing it before merge, but it's still present.
Reviewed by Cursor Bugbot for commit 94f6568. Configure here.
There was a problem hiding this comment.
Code Review
This pull request introduces a temporary, intentionally failing linter step named 'demo-fail' to the hk.pkl configuration to capture and inspect CI failure output. Feedback suggests isolating this step using a specific profile to prevent it from disrupting local developer workflows by causing pre-commit or pre-push hooks to fail globally.
| // TEMP: deliberately failing step to capture the ugly clx failure output in CI. | ||
| // Remove once we've fixed the formatting in a follow-up. | ||
| ["demo-fail"] = new Step { | ||
| glob = "**/*.rs" | ||
| check = | ||
| #""" | ||
| echo "this step is intentionally failing so we can see what the output looks like" | ||
| echo "line two of stderr" 1>&2 | ||
| echo "line three of stdout" | ||
| exit 1 | ||
| """# | ||
| } |
There was a problem hiding this comment.
Adding a deliberately failing step to the global linters mapping will cause the pre-commit and pre-push hooks to fail for all developers working on this branch. This can be disruptive to local workflows.
Consider isolating this step using a specific profile so it only runs in the CI environment where you intend to capture the output. You can then trigger it in CI by passing the --profile flag.
// TEMP: deliberately failing step to capture the ugly clx failure output in CI.
// Remove once we've fixed the formatting in a follow-up.
["demo-fail"] = new Step {
profiles = List("ci-debug")
glob = "**/*.rs"
check =
#"""
echo "this step is intentionally failing so we can see what the output looks like"
echo "line two of stderr" 1>&2
echo "line three of stdout"
exit 1
"""#
}
Greptile SummaryThis PR improves CI/text-mode output readability by: (1) tracking failed steps in Confidence Score: 5/5Safe to merge once the demo-fail step and [patch.crates-io] branch pin are removed (both noted in existing threads). No P0 or P1 issues found. All logic changes are well-reasoned, well-commented, and backed by unit tests. The summary-display condition is correct, the token-splitter correctly handles multi-byte UTF-8, and the dual-render approach for display vs. execution is sound. No files require special attention beyond the pre-merge checklist items already tracked in existing review threads. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Hook run completes] --> B[clx::progress::stop]
B --> C{in_text_mode?}
C -->|No — UI mode| D[Enter output loop]
C -->|Yes| E{HK_SUMMARY_TEXT=1?}
E -->|Yes — force_summary| D
E -->|No| F{failed_steps not empty?}
F -->|No| G[Skip all summaries]
F -->|Yes| D
D --> H[For each step in output_by_step]
H --> I{in_text_mode && !force_summary?}
I -->|No| J[Print step summary]
I -->|Yes| K{step in failed_steps?}
K -->|Yes| J
K -->|No| L[Skip — already streamed live]
J --> M{More steps?}
L --> M
M -->|Yes| H
M -->|No| N[End]
G --> N
Reviews (7): Last reviewed commit: "fix(step): cap progress message length" | Re-trigger Greptile |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit eb79985. Configure here.
This is a temporary step that always exits 1, used to surface what hk check failures look like in GHA logs so we can fix the rendering in a follow-up commit on this PR. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two changes to make hk's CI/non-TTY output readable when a step fails:
clx fix (jdx/clx#fix-text-mode-rendering, patched in via Cargo):
- refresh_once() no longer emits UI-mode cursor escape sequences when
output is set to Text mode. set_status(Done|Failed|Warn) and stop()
both call refresh_once(), so previously every state change leaked
raw [9A[80D[0J into the log.
- render_text_mode() deduplicates consecutive identical job lines so
the same status doesn't get printed twice when callers update
several props in a row.
hk side:
- Track failing step names on HookContext (step_contexts are removed
as soon as each step finishes, so the existing status was already
gone by the time the summary ran).
- In text mode, always print the per-step output summary for failed
steps so the diagnostic is captured in full rather than truncated
one-line-at-a-time via the streaming `message` prop. Successful
steps stay quiet in text mode (their output already streamed);
HK_SUMMARY_TEXT=1 still forces every step to print.
The `demo-fail` step from the previous commit stays in for one more
CI run to capture the cleaned-up output; it'll be deleted before merge.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The per-job body_text template ran every message and ensembler_stdout line through clx's truncate_text filter, which clamps to (terminal_width - 20). In a non-TTY environment console::Term::stderr().size() returns 80 cols by default, so each line was being cut to ~60 chars with a trailing `…` — losing exactly the diagnostic detail you need to debug a CI failure. Drop the filter for body_text. UI-mode body still uses `flex` because the in-place renderer needs bounded widths; CI log viewers handle wrapping. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The per-job progress message embedded the fully-rendered run command —
which expands {{files}} into the literal list of matched paths. In
text mode (CI logs, piped stderr) a step matching 98 .rs files dumped
~4KB of file paths per status update; in UI mode the `flex` filter
hid it but the cost was still there.
Use the un-rendered template for display instead. The file count and
glob pattern shown right next to it already tell the reader what's
being processed; the actual list of paths adds no diagnostic value
in the progress line. The fully rendered command is still what we
hand to the shell for execution.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The progress message now embeds the un-rendered command template
(e.g. \`echo '{{files}}'\`) instead of expanding {{files}} into the
literal path list — paths still surface via streamed stdout / -v
trace. The git.bats merge-base test was asserting the rendered form;
update the three assertions to match the new contract while keeping
the streamed-stdout assertions unchanged.
Replaces the earlier "show un-rendered template" approach. The previous fix (a14e77e) traded one diagnostic detail (knowing what files actually got handed to the tool) for another (CI logs not filling with 4KB of paths). Better: render the command with {{files}} and {{workspace_files}} truncated to "first_file …" when there are multiple files. Steps matching one file still show that file inline, steps matching hundreds show the command shape plus one concrete example. Adds Context::for_display() that returns a clone with the file lists rewritten, plus split_quoted_tokens / truncate_quoted_list helpers that respect ShellType::quote-style escaping (so paths with spaces like 'a b.txt' don't get split mid-token). Step runner renders twice — display version for the progress message, full version for execution. Updates the git.bats merge-base assertions to expect the new form: 1 file → 'feature.txt', 2 files → 'feature.txt …'.
a4c77c2 to
06a6abd
Compare
clx 2.0.1 ships the text-mode rendering fixes from clx#86, so the [patch.crates-io] git-branch override is no longer needed. Drop it and bump the dependency. Also remove the deliberately-failing demo-fail step from hk.pkl — it served its purpose for capturing the before/after CI output and should not ship to main. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The per-job progress message embeds the rendered run command, which can be a multi-line shell script or a generated command with hundreds of inline args. With clx's text-mode escape-code suppression in place, an unbounded message would still flood CI logs on every prop update. Cap the formatted message at 2048 printable chars with a trailing `…`, ANSI-aware so escape sequences don't get split mid-cluster or counted toward the budget. The cap lives in hk because different consumers want different bounds — clx itself stays mode-agnostic.
### 🐛 Bug Fixes - **(hook)** do not stage fixes when fail_on_fix=true by [@jdx](https://github.com/jdx) in [#892](#892) - use site domain for plausible data-domain by [@jdx](https://github.com/jdx) in [#886](#886) - make text-mode progress output usable in CI by [@jdx](https://github.com/jdx) in [#890](#890) ### 📚 Documentation - prefix GitHub star count with ★ glyph by [@jdx](https://github.com/jdx) in [#883](#883) ### 🔍 Other Changes - **(release)** dedupe sponsor section in release notes by [@jdx](https://github.com/jdx) in [#881](#881) - switch analytics from gtm/goatcounter to plausible by [@jdx](https://github.com/jdx) in [#885](#885) - migrate to namespace.so runners by [@jdx](https://github.com/jdx) in [#891](#891) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk release bookkeeping: version bumps, regenerated docs, and lockfile dependency updates with no functional code changes in this PR. > > **Overview** > Bumps `hk` to **v1.44.3** and adds the corresponding `CHANGELOG.md` release entry. > > Regenerates versioned docs/CLI artifacts to reference `1.44.3` (package URLs and generated `commands.json`/`index.md`) and updates `Cargo.lock` with dependency resolution changes (notably `jni`, `rustls*`, `reqwest`, `wasm-bindgen`, and `thiserror` unification). > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit ab7b72e. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: mise-en-dev <123107610+mise-en-dev@users.noreply.github.com>


Summary
Cleans up hk's text-mode (CI / piped stderr) progress output. The previous behavior was unreadable in GitHub Actions logs: raw
[9A[80D[0Jcursor-control escapes leaked into the log, every status change duplicated, failure stderr was suppressed, and a step matching hundreds of files dumped ~4KB of paths into every progress line. After this PR a 14-step pre-commit run reads as a clean append-only stream with one full diagnostic block per failure.What changed
Bumped clx 2.0 → 2.0.1 (clx#86)
refresh_once()is now a no-op inProgressOutput::Textso terminal-state transitions andstop()don't leak UI escape codesrender_text_mode()dedupes consecutive identical job lines per job (multiple props updated in quick succession no longer print the same line N times)next_operation()resets the dedup cache so multi-operation transitions are never silently swallowedFailure summaries shown in text mode (src/hook.rs)
HookContext.failed_steps: Mutex<HashSet<String>>tracks failures so the end-of-run summary survives thestep_contexts.shift_removethat fires when each step finishesHK_SUMMARY_TEXT=1still forces every step's summary to printHK_SUMMARY_TEXTto reflect the new default behaviorBounded progress message rendering (src/step/runner.rs, src/tera.rs, src/step_job.rs)
Context::for_display()returns a tera context wherefiles/workspace_filesare rewritten tofirst_token …when more than one file matches. The runner renders twice — display version for the progress message, full version for executiontruncate_progress_message()caps the formatted progress message at 2048 printable chars with a trailing…, ANSI-aware so escape sequences don't get split mid-clustertruncate_textfilter fromstep_job.rsbody_text — clx's filter clamped to (term_width - 20) which is60chars in non-TTY environments, cutting exactly the diagnostic detail you need to debug a CI failureExamples —
dbgstep matching 98 .rs files in CI:Failed step in CI:
Test plan
cargo test— 149 pass (11 new acrosssrc/tera.rs::testsandsrc/step::runner::tests)mise run test:bats test/git.bats— 4 pass under both libgit2 and nolibgit2 (assertions updated forfirst_file …display)mise run test:bats test/output_summary.bats test/output_summary_no_duplicate.bats test/output_summary_check_first.bats— 11 passdemo-failscaffolding step — see runs 25166877825 (before) and 25168039915 (after)🤖 Generated with Claude Code