feat(cosh): concatenate hook systemMessages with [name] prefix#387
Merged
samchu-zsl merged 1 commit intoalibaba:mainfrom Apr 27, 2026
Merged
Conversation
- Replace last-write-wins with per-hook attribution in merge
- Prefix each message with [hookName] so users see all voices
- Fall back to command basename when hook name is missing
- Single-hook fast path keeps backward-compatible output
- Unified behavior for parallel and sequential hook execution
- Add 4 unit tests covering fast path, concat, basename, skip
|
Important Installation incomplete: to start using Gemini Code Assist, please ask the organization owner(s) to visit the Gemini Code Assist Admin Console and sign the Terms of Services. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Previously, when multiple hooks returned
systemMessagefor the same event(e.g.
PreToolUse),HookAggregator.mergeWithOrLogicused last-write-winssemantics — the final message was overwritten by whichever hook ran last,
even if that hook didn't trigger the
ask/blockdecision.This caused a confusing UX where hook A raised
askwith message "A", buta later allow-hook C silently replaced the message with "C", so the user
saw "C" in the confirmation dialog without any hint that A was the one
that actually triggered the prompt.
This PR changes the aggregation rule to concatenate every non-empty
systemMessageas[hookName] messageon separate lines, so users cansee exactly which hook contributed which message. The change applies
uniformly to both parallel and sequential hook execution since both
paths funnel into the same
aggregateResultsentry point.Related Issue
no-issue: internal UX polish for hook message attribution
Type of Change
Scope
cosh(copilot-shell)sec-core(agent-sec-core)skill(os-skills)sight(agentsight)tokenless(tokenless)Checklist
cosh: Lint passes, type check passes, and tests passsec-core(Rust):cargo clippy -- -D warningsandcargo fmt --checkpasssec-core(Python): Ruff format and pytest passskill: Skill directory structure is valid and shell scripts pass syntax checksight:cargo clippy -- -D warningsandcargo fmt --checkpasstokenless:cargo clippy -- -D warningsandcargo fmt --checkpasspackage-lock.json/Cargo.lock)Testing
Added 4 new unit tests under
mergeWithOrLogic - systemMessage concatenationin hookAggregator.test.ts:[name]prefix), preserving backward compatibility.
[rm-guard] rm detected\n[audit] logged;decision=askwins overallow.namefield: falls back to the command basename, e.g./usr/local/bin/guard.py --strict→[guard.py] ....systemMessage === undefinedor''do notcontribute to the concatenation.
Run:
Result: 28/28 passed (4 new + 24 existing).
Type check:
npx tsc --noEmitclean.Additional Notes
[name]prefix) to keep existingUX identical for the most common case.
aggregator is the single merge point;
hookRunnerdifferences don'taffect message attribution.
hookConfig.name→ basename of the firsttoken in
command→ fallback'hook'.