Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions core/src/sites/xhs/knowledge.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ artifacts, and return a compact bundle. They differ only in where they enter:
Both flows keep opening notes by clicking their cards. Their card/note URLs
carry the xsec token needed for a later `get_notes` call.

On the homepage, the visible AI-search submit button may not be mounted until
after text is entered. Homepage feed cards are not proof that a search ran: a
successful search must transition to a `/search_result*` page with the requested
keyword. The runtime re-locates the post-typing submit control if Enter is ignored.

While reading any result set, keep track of what each author is: the subject's
own official account (the gym/brand/venue/organizer itself), semi-official
voices (its staff or coaches), aggregator/curator accounts, or ordinary users.
Expand Down
15 changes: 11 additions & 4 deletions core/src/sites/xhs/page.rs
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ impl<'a> XhsPageRuntime<'a> {

sleep_ms(150).await;
self.page.press_key("Enter").await?;
let state = self
let mut state = self
.wait_for_search_transition(query, wait_seconds.max(SEARCH_TRANSITION_TIMEOUT_S))
.await?;
if search_transition_ok(&state, query) {
Expand All @@ -386,12 +386,19 @@ impl<'a> XhsPageRuntime<'a> {
}));
}

if let Some(submit) = loc.get("submit") {
// Typing opens the homepage suggestion panel and can re-render (or
// only then mount) the submit affordance. Do not reuse `loc.submit`,
// which was measured while the input was still empty: the stale/null
// coordinate was the cause of intermittent searches that visibly had
// the requested keyword but stayed on /explore. Re-read the live DOM
// after Enter has failed, then click the current control.
let current_loc = self.expect_object("searchInput", None).await?;
if let Some(submit) = current_loc.get("submit") {
let x = number(submit, "x");
let y = number(submit, "y");
if x > 0.0 && y > 0.0 {
self.page.click(x, y).await?;
let state = self
state = self
.wait_for_search_transition(
query,
wait_seconds.max(SEARCH_TRANSITION_TIMEOUT_S),
Expand All @@ -400,7 +407,7 @@ impl<'a> XhsPageRuntime<'a> {
if search_transition_ok(&state, query) {
return Ok(json!({
"ok": true,
"strategy": "click_search_button",
"strategy": "click_refreshed_search_button",
"state": state,
"url": self.current_url().await?,
}));
Expand Down
10 changes: 5 additions & 5 deletions core/src/sites/xhs/page_scripts.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,11 +177,11 @@ const SocaiXhsPageScripts = (() => {
}

// Selectors for the search-submit affordance, tried in priority order.
// The 2026-05 chat composer has explicit class names; legacy UIs used a
// <form> with type=submit or an .icon-search SVG sibling. We don't try
// to score arbitrary clickable elements anymore — if none of these
// match, Rust falls back to pressing Enter, which works in practice.
// The current single-line composer mounts `.single-line-search-btn` only
// after text is entered. Older chat-composer and legacy controls stay as
// fallbacks. We don't try to score arbitrary clickable elements anymore.
const SEARCH_SUBMIT_SELECTORS = [
'.single-line-search-btn',
'.bottom-box-right-submit-button',
'.submit-button-wrapper',
'button[type="submit"]',
Expand All @@ -194,7 +194,7 @@ const SocaiXhsPageScripts = (() => {
const input = findSearchInput();
if (!input) return { ok: false, error: 'search_input_not_found' };
const root = input.closest(
'form, header, .search-input, .search-container, .search-bar, .search-box, .wendian-wrapper'
'form, header, .textarea-container, .search-input, .search-container, .search-bar, .search-box, .wendian-wrapper'
) || document;

let submit = null;
Expand Down
Loading