feat: add human.selectText primitive + generator capture#63
Merged
Conversation
Element-scoped text-selection primitive: human.selectText(target) moves the cursor to the element (humanized) then selects its text via locator.selectText(); instant mode skips the motion. Wired across the surface — new 'selectText' KnownActionType (@humanjs/core), the codegen renders it (toPlaywright/toHumanJS), a human_selectText MCP tool, and the @humanjs/skill primitives table. The generator captures it too: a triple-click / select-all / whole-element drag emits a selectText step (multi-clicks no longer record as N clicks); free-form cross-element ranges stay uncaptured by design. Verified end-to-end (primitive selects text in both speed modes; capture records element-scoped only; the MCP tool lists).
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
So the generator's 0.1.0 changelog mentions the selectText capture (patch — the bump stays 0.1.0 from the pending initial-release minor).
…ank) The dependabot react-dom bump moved react-dom to 19.2.7 but left react at 19.2.6, and React 19 throws an incompatible-versions error at runtime when they differ — so the generator's React SPA crashed to a blank page (the static server, MIME types, and asset hashes were all correct). Bump react to ^19.2.7 across the workspace to match. Also add dashboard/** + vite.config.ts to the turbo build inputs so dashboard edits actually invalidate the build cache (they weren't tracked, risking a stale dist/dashboard).
…sture A drag-select fired a click event the recorder logged alongside (or instead of) the selection — e.g. a partial drag-select recorded only a junk click, and a full-element drag-select recorded a click plus the selectText. A click on non-interactive content while text is selected is part of a selection gesture, not a navigation click, so it's now skipped. Verified: full-element drag-select records selectText only; a partial selection records nothing; normal clicks (interactive or not, with no selection) still record.
A real text highlight is usually part of an element's text ("es una" in
"Esto es una prueba"), which the element-scoped primitive couldn't reproduce
— so the generator recorded nothing useful for partial selections.
selectText now takes an optional { text }: it finds that text inside the
element (whitespace-tolerant, mapped back to exact text-node offsets so a
range can span inline children) and selects just it, falling back to the whole
element when the text isn't found. Reproduced by the text itself, not by
coordinates — consistent with the by-what-you-see selector philosophy.
The generator captures it: highlighting an element's whole text records a
plain selectText; highlighting part records selectText(target, { text }) with
the exact substring. Mirrored in the human_selectText MCP tool (optional text
arg), the codegen, the skill table, and the API docs.
A triple-click forms a text selection but its first click (detail=1) fires before the selection exists, so it leaked as a stray click step ahead of the selectText. Defer a click on non-interactive content briefly: the second click of a multi-click (detail>=2) or the forming selectText retracts it, and any other recorded action flushes it first so order is preserved. A lone click on plain text still records after the short window. Also note select-text capture in the generator's initial-release changeset.
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.
Adds
human.selectText(target, { text })— humanized text selection, done as one combined unit (primitive + MCP + codegen + generator capture). The cursor moves to the element, then selects.Primitive
human.selectText(target)selects the element's whole text. Pass{ text }to select just a substring — HumanJS finds it inside the element (whitespace-tolerant, mapped back to exact text-node offsets so the range can span inline children like a<b>) and selects only that, falling back to the whole element if the text isn't found. Reproduced by the text itself, not coordinates — consistent with the by-what-you-see selector philosophy.speed: 'instant'skips the motion and still applies the selection.Wired across the surface
@humanjs/core— new'selectText'KnownActionType(plugins observe it).@humanjs/playwright— the primitive + codegen:toPlaywright/toHumanJSrenderawait human.selectText(...), with{ text }when the capture was partial.@humanjs/mcp—human_selectTexttool, with the optionaltextarg.@humanjs/skill— added to the primitives table.@humanjs/generator— captures the gesture: highlighting an element's whole text records a plainselectText(target); highlighting part of it recordsselectText(target, { text })with the exact substring.Capture-quality fixes (generator)
clickstep.selectText— a click on non-interactive content is deferred and retracted by the following multi-click /selectText(order preserved for everything else).Also riding in this PR (main-level fixes)
Bundled here rather than split into their own PR:
reacttoreact-dom19.2.7 — the generator dashboard rendered blank because React 19 throws on mismatchedreact/react-domversions (a dependabot bump had moved onlyreact-dom).dashboard/**+vite.config.tsso the bundled dashboard isn't served from a stale Turbo cache.Verified end-to-end
{ text }and a whole highlight records plain; replay selects exactly, spans inline nodes, and falls back to the whole element when the text is absent.selectTextonly (no stray click); plain-text and button clicks still record, in order.@humanjs/playwright233 tests,@humanjs/generator40 tests; typecheck / lint / build green.Release
Changeset:
@humanjs/playwright/@humanjs/core/@humanjs/mcpminor,@humanjs/skillpatch. The generator capture rides in its pending0.1.0(its initial-release changeset now lists "select text"). The react / turbo fixes need no changeset —apps/webis private, the generator'sreact/react-domare devDeps (the dashboard is pre-bundled, no runtime impact), andturbo.jsonis root config.README roadmap: the Visual generator (
@humanjs/generator) item is now checked off.