Paste directives into the composer - #74651
Merged
Merged
Conversation
…atch typed The composer chips a `/command` when it's picked or accepted from the popover. Text that arrives whole — a paste, a restored draft, an undo step — never passes through that path, so nothing recognizes the commands in it. Extract that recognition into a scanner that answers on the same terms the typed path uses: no-arg commands only, no paths, built-ins as invocations while skills may also be named mid-prose, and a trailing token still-typed unless the caller says the text is inert.
`appendComposerContents` — the one builder every paste goes through — only ever chipped `@kind:value` refs. Slash commands had a single leading-token special case in `renderComposerContents`, which paste doesn't call, so a pasted `/clean` landed as dead text while the same text typed by hand became a pill. Both directive kinds now hydrate from one ordered span walk, with `@` refs winning a tie so a slash inside a quoted ref value stays part of that value. Paste additionally scans as inert text: a command ending the paste is complete rather than half-typed, and the insertion point's own token boundary decides the leading token, so `foo` + `/clean` stays `foo/clean`. `textBeforeCaret`'s chip-atomic serialization moves to rich-editor as `serializeTextBefore` — the paste path needs the same "a chip edge is a token boundary" reading that trigger detection does.
Two repaint sites hand the editor text that is finished rather than mid-keystroke: the main composer's programmatic draft writes (restore, insert, history recall) and the inline edit composer opening a sent message. Both now render with `trailingCommitted`, so a command ending that text chips instead of reading as a half-typed token — the edit composer in particular showed plain text for a message the transcript had just rendered with a pill. Regression tests cover the paste path: a command ending the paste, one named mid-prose beside a ref, a path left alone, a paste landing against a word, and one landing after an existing chip.
OutThisLife
force-pushed
the
bb/composer-paste-directives
branch
from
July 30, 2026 07:01
916f7b6 to
422ecfe
Compare
Contributor
૮ >ﻌ< ა ci reviewran on 422ecfe ℹ️ InfoDesktop E2E visual evidence · View test artifacts · View job1 visual diff. inline evidence is publishing... |
OutThisLife
enabled auto-merge
July 30, 2026 07:10
randlee
pushed a commit
to randlee/hermes-agent
that referenced
this pull request
Aug 11, 2026
…aste-directives Paste directives into the composer
33hodl
pushed a commit
to 33hodl/hermes-agent
that referenced
this pull request
Aug 12, 2026
…aste-directives Paste directives into the composer
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.
A
/commandor@reftyped into the composer chips as it's committed. The same text pasted did not:appendComposerContents— the one builder every paste goes through — recognized@kind:valuerefs and nothing else. Slash commands had a single leading-token special case inrenderComposerContents, which paste never calls, so pasting/cleandropped a dead token into the composer while typing it produced a pill.Both directive kinds now hydrate from one ordered span walk, in the main composer and the inline edit composer alike.
Paste is scanned as inert text rather than live keystrokes, which changes two answers:
/worstill stays editable — that token belongs to the popover).foo+ a pasted/cleanisfoo/clean, not a command. A chip edge counts as a boundary, matching how trigger detection reads the line.Recognition answers on exactly the terms the typed path uses, or hydration would invent pills the popover would never have committed: no-arg commands only (
/goal ship itkeeps its prose tail), paths left alone (/usr/local/bin), and built-ins as invocations only —/newacts on the app, so it means nothing dropped mid-sentence, while a skill reads as "handle this part with X".Two repaint sites also hand the editor finished text — the main composer's programmatic draft writes and the edit composer opening a sent message — and now hydrate commands too. The edit composer was showing plain text for a message the transcript had rendered with a pill a moment earlier.