@q-agent/agent 0.1.9 → 0.1.10

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.
@@ -856,10 +856,33 @@ async function processExplorationJob(cfg, session) {
856
856
  args.push(storageState);
857
857
  const child = (0, child_process_1.spawn)((0, paths_1.nodeBin)(), args, { cwd: nm, env: nodePathEnv(nm) });
858
858
  activeChild = child;
859
+ // Capture the driver's stderr so a launch failure (missing browser, bad
860
+ // Playwright resolution, …) is visible instead of a silent "complete".
861
+ let driverStderr = "";
862
+ child.stderr?.on("data", (d) => {
863
+ driverStderr += String(d);
864
+ });
859
865
  const driver = makeExploreDriver(child);
860
866
  try {
861
- // Wait for the driver's readiness signal before the first observe.
862
- await driver.ready();
867
+ // Wait for the driver's readiness signal before the first observe. If the
868
+ // driver died before signalling ready, finalize with a clear driver-error
869
+ // (carrying its stderr) rather than letting the loop break silently.
870
+ const ready = await driver.ready();
871
+ if (!ready || ready.ok === false) {
872
+ const error = (ready && ready.error) || "driver failed to start";
873
+ const detail = driverStderr.trim();
874
+ await api
875
+ .postExploreFinalize(cfg, session.sessionId, {
876
+ discovered: { routes: [], selectors: [] },
877
+ log: [{ phase: "driver", error, stderr: detail || undefined }],
878
+ stopReason: "driver-error",
879
+ stepsTaken: 0,
880
+ })
881
+ .catch((err) => console.error("postExploreFinalize failed:", err));
882
+ (0, bus_1.emit)("explore-complete", { sessionId: session.sessionId, stopReason: "driver-error", error });
883
+ console.error(`Exploration ${session.sessionId} driver-error: ${error}${detail ? ` — ${detail}` : ""}`);
884
+ return;
885
+ }
863
886
  await runExplorationLoop(cfg, session, driver, api, bus_1.emit);
864
887
  }
865
888
  finally {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@q-agent/agent",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "Q-Agent Local Agent — claims execution jobs from the Q-Agent server and runs Playwright locally, so manual login/MFA happens on the user's own machine and session credentials never leave it.",
5
5
  "license": "UNLICENSED",
6
6
  "bin": {
@@ -18,7 +18,7 @@
18
18
  //
19
19
  // Protocol (one JSON object per line, each way):
20
20
  // {"cmd":"observe"}
21
- // -> {"ok":true,"url":..,"path":..,"a11y":<accessibility.snapshot()>,
21
+ // -> {"ok":true,"url":..,"path":..,"a11y":<ariaSnapshot() role+name tree>,
22
22
  // "elements":[<distilled interactive DOM>]}
23
23
  // {"cmd":"act","action":"goto|click|fill|expectVisible","args":{...}}
24
24
  // -> {"ok":bool,"error":str|null,"changed":bool}
@@ -121,7 +121,11 @@ async function doAct(action, args) {
121
121
  }
122
122
 
123
123
  async function doObserve() {
124
- const a11y = await page.accessibility.snapshot();
124
+ // Playwright removed page.accessibility; the supported role+name tree is
125
+ // locator.ariaSnapshot() (a compact YAML string, ideal for the model and
126
+ // maps directly to getByRole). Best-effort — never fail observe on it.
127
+ let a11y = '';
128
+ try { a11y = await page.locator('body').ariaSnapshot(); } catch { a11y = ''; }
125
129
  const elements = await page.evaluate(DISTILL);
126
130
  const url = page.url();
127
131
  let path = '';
@@ -161,6 +165,12 @@ async function handle(line) {
161
165
  const context = await browser.newContext(contextOpts);
162
166
  page = await context.newPage();
163
167
 
168
+ // Land on the app before the first observe so step 1 sees the real page,
169
+ // not about:blank. Best-effort — the model can still goto elsewhere.
170
+ if (baseURL) {
171
+ try { await page.goto(baseURL, { waitUntil: 'domcontentloaded' }); } catch {}
172
+ }
173
+
164
174
  // Serialize commands: one line in -> one response out, in order.
165
175
  const rl = readline.createInterface({ input: process.stdin });
166
176
  let chain = Promise.resolve();