yiyan-browser-agent 1.0.5 → 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/browser.js +19 -45
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yiyan-browser-agent",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "AI coding agent powered by Yiyan (文心一言) via browser automation — no API key needed",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/browser.js CHANGED
@@ -135,10 +135,14 @@ class YiyanBrowser {
135
135
 
136
136
  async _navigate(url) {
137
137
  try {
138
- // Wait for network idle instead of fixed timeout
138
+ // Wait for network idle, then extra wait for dynamic content
139
139
  await this.page.goto(url, { waitUntil: 'networkidle', timeout: 30_000 });
140
+ // Give React/Vue SPA time to render
141
+ await this.page.waitForTimeout(800);
140
142
  } catch (err) {
141
143
  logger.warn(`Navigation warning: ${err.message}`);
144
+ // Fallback: longer wait if networkidle fails
145
+ await this.page.waitForTimeout(2000);
142
146
  }
143
147
  }
144
148
 
@@ -149,8 +153,7 @@ class YiyanBrowser {
149
153
  const el = await this.page.waitForSelector(sel, { timeout: 2_000, state: 'visible' });
150
154
  if (el) {
151
155
  await el.click();
152
- // Smart wait for URL change or page update
153
- await this.page.waitForLoadState('domcontentloaded', { timeout: 3_000 }).catch(() => {});
156
+ await this.page.waitForTimeout(500);
154
157
  logger.dim('Started new chat session');
155
158
  return;
156
159
  }
@@ -165,8 +168,9 @@ class YiyanBrowser {
165
168
  // ── Login handling (optimized) ─────────────────────────────────────────────
166
169
 
167
170
  async _ensureLoggedIn() {
168
- // Smart wait for page to be interactive
171
+ // Wait for page to be fully interactive
169
172
  await this.page.waitForLoadState('domcontentloaded', { timeout: 5_000 }).catch(() => {});
173
+ await this.page.waitForTimeout(500);
170
174
 
171
175
  const needsLogin = await this.page.evaluate(() => {
172
176
  const url = window.location.href;
@@ -186,7 +190,6 @@ class YiyanBrowser {
186
190
  if (needsLogin) {
187
191
  this._printLoginBanner();
188
192
  await this._waitForEnter();
189
- // Wait for navigation after login
190
193
  await this.page.waitForNavigation({ waitUntil: 'networkidle', timeout: 30_000 }).catch(() => {});
191
194
  }
192
195
  }
@@ -225,51 +228,21 @@ class YiyanBrowser {
225
228
  });
226
229
  }
227
230
 
228
- // ── Sending Messages (optimized: paste instead of type) ────────────────────
231
+ // ── Sending Messages (stable: keyboard.type) ────────────────────────────────
229
232
 
230
233
  async sendMessage(text) {
231
234
  const { el } = await this._findInput();
232
235
 
233
- // Focus the element
234
- await el.focus();
236
+ // Focus and select all existing content
237
+ await el.click({ clickCount: 3, force: true });
238
+ await this.page.waitForTimeout(200);
235
239
 
236
- // Clear existing content
237
- await el.evaluate(e => {
238
- e.textContent = '';
239
- if (e.innerText) e.innerText = '';
240
- });
241
-
242
- // Use clipboard paste for instant input (much faster than typing)
243
- await this.page.evaluate(async (text) => {
244
- // Try modern clipboard API first
245
- try {
246
- await navigator.clipboard.writeText(text);
247
- document.execCommand('paste');
248
- return;
249
- } catch {}
250
-
251
- // Fallback: direct DOM manipulation with proper event dispatch
252
- const activeEl = document.activeElement;
253
- if (activeEl && activeEl.isContentEditable) {
254
- activeEl.textContent = text;
255
-
256
- // Dispatch input event so Yiyan recognizes the content
257
- const inputEvent = new InputEvent('input', {
258
- bubbles: true,
259
- cancelable: true,
260
- inputType: 'insertText',
261
- data: text,
262
- });
263
- activeEl.dispatchEvent(inputEvent);
264
-
265
- // Also dispatch change event for good measure
266
- const changeEvent = new Event('change', { bubbles: true });
267
- activeEl.dispatchEvent(changeEvent);
268
- }
269
- }, text);
240
+ // Clear by pressing Delete
241
+ await this.page.keyboard.press('Delete');
242
+ await this.page.waitForTimeout(100);
270
243
 
271
- // Small delay to let UI process the input
272
- await this.page.waitForTimeout(50);
244
+ // Type text character by character (stable, works reliably)
245
+ await this.page.keyboard.type(text, { delay: 30 });
273
246
 
274
247
  // Press Enter to send
275
248
  await this.page.keyboard.press('Enter');
@@ -278,7 +251,8 @@ class YiyanBrowser {
278
251
  async _findInput() {
279
252
  for (const sel of SEL.chatInput) {
280
253
  try {
281
- const el = await this.page.waitForSelector(sel, { timeout: 3_000, state: 'visible' });
254
+ // Increased timeout for initial page load
255
+ const el = await this.page.waitForSelector(sel, { timeout: 8_000, state: 'visible' });
282
256
  if (!el) continue;
283
257
  const tagName = await el.evaluate(e => e.tagName.toLowerCase());
284
258
  const isContentEditable = await el.evaluate(e => e.isContentEditable);