@alfe.ai/browser 0.1.0 → 0.2.1

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.
package/dist/index.d.cts CHANGED
@@ -125,16 +125,11 @@ interface BrowserSessionOptions {
125
125
  idleShutdownMs?: number;
126
126
  /** Extra Chrome args. */
127
127
  extraArgs?: string[];
128
- logger?: Logger;
129
- }
130
- interface BrowserSurfaceOptions extends BrowserSessionOptions {
131
- /**
132
- * Guard consulted before agent-driven or human navigation. Return false to
133
- * block (SSRF policy). Defaults to allow-all; Phase 11 wires the integration
134
- * SSRF allowlist here.
135
- */
128
+ /** Guard applied to every intercepted HTTP(S) page request. */
136
129
  isNavigationAllowed?: (url: string) => boolean;
130
+ logger?: Logger;
137
131
  }
132
+ type BrowserSurfaceOptions = BrowserSessionOptions;
138
133
  //#endregion
139
134
  //#region src/browser-session.d.ts
140
135
  declare class BrowserSession {
@@ -144,14 +139,24 @@ declare class BrowserSession {
144
139
  private launching;
145
140
  private holds;
146
141
  private idleTimer;
142
+ private generation;
143
+ private readonly preparedPages;
144
+ private readonly activePageListeners;
147
145
  private readonly log;
148
146
  private readonly idleMs;
149
147
  constructor(options: BrowserSessionOptions);
150
148
  /** Launch Chrome if not already running (idempotent, concurrent-safe). */
151
149
  ensureLaunched(): Promise<void>;
152
150
  private doLaunch;
151
+ /**
152
+ * Adopt `page` as the streamed active page iff it has a real navigable
153
+ * http(s) URL. Returns whether it was adopted. Guards against flipping the
154
+ * screencast to a transient `about:blank` throwaway target.
155
+ */
156
+ private adoptIfNavigable;
153
157
  /** The current active page, launching Chrome first if needed. */
154
158
  getActivePage(): Promise<Page>;
159
+ onActivePageChange(listener: (page: Page) => void | Promise<void>): () => void;
155
160
  /** Prevent idle shutdown while a viewer or op is active. */
156
161
  addHold(): void;
157
162
  /** Release a hold; arm idle shutdown when the last one is released. */
@@ -161,6 +166,9 @@ declare class BrowserSession {
161
166
  private armIdleTimer;
162
167
  private clearIdleTimer;
163
168
  shutdown(): Promise<void>;
169
+ private setActivePage;
170
+ private preparePage;
171
+ private isLaunchCurrent;
164
172
  }
165
173
  //#endregion
166
174
  //#region src/automation.d.ts
@@ -172,6 +180,7 @@ declare class BrowserAutomation {
172
180
  private readonly session;
173
181
  private readonly turn;
174
182
  private readonly isNavigationAllowed;
183
+ private operationTail;
175
184
  constructor(session: BrowserSession, turn: TurnController, isNavigationAllowed: (url: string) => boolean);
176
185
  navigate(url: string): Promise<NavigateResult>;
177
186
  click(selector: string): Promise<void>;
@@ -186,6 +195,9 @@ declare class BrowserAutomation {
186
195
  screenshot(): Promise<string>;
187
196
  /** Evaluate an expression in the page context via CDP (no eval on our side). */
188
197
  evaluate(expression: string): Promise<unknown>;
198
+ /** Wait until all agent operations that were already queued have settled. */
199
+ waitUntilIdle(): Promise<void>;
200
+ private run;
189
201
  }
190
202
  //#endregion
191
203
  //#region src/browser-surface.d.ts
@@ -207,26 +219,53 @@ declare class BrowserSurface implements SurfaceHandler {
207
219
  private readonly viewers;
208
220
  private viewport;
209
221
  private handoff;
222
+ private controllerSessionId;
223
+ private pendingControllerSessionId;
224
+ private streamGeneration;
225
+ private streamQueue;
226
+ private closed;
227
+ private readonly removePageListener;
210
228
  private readonly log;
211
229
  constructor(options: BrowserSurfaceOptions, sendFrame: (buf: Buffer) => void);
212
230
  openSession(sessionId: number, open: SessionOpenPayload): Promise<void>;
213
231
  handleFrame(frame: RemoteFrame): void;
214
232
  closeSession(sessionId: number): void;
215
233
  /**
216
- * Agent tool entry point: hand control to the human and block until they
217
- * release it (RELEASE_CONTROL) or `timeoutMs` elapses. Resolves with the
218
- * final page URL/title so the agent resumes on the same live page.
234
+ * Agent tool entry point: PARK the agent and wait for a human to take over
235
+ * and hand back (RELEASE_CONTROL / viewer teardown after a claim) or for
236
+ * `timeoutMs` to elapse. Resolves with the final page URL/title so the agent
237
+ * resumes on the same live page.
238
+ *
239
+ * Crucially this does NOT grant the human turn up front. The turn is granted
240
+ * only when a human ACTUALLY takes control — i.e. when the controlling
241
+ * (`canControl:true`) viewer sends a `TAKEOVER_REQUEST` frame (see
242
+ * `handleFrame` → `grantHuman()`). Granting at tool-call time made the session
243
+ * "human in control" before anyone had claimed, so a read-only viewer's
244
+ * teardown would fire `releaseToAgent()` and complete the session out from
245
+ * under the user (mislabeled 409 on the real claim; agent only resuming when
246
+ * the tab closed).
219
247
  */
220
248
  requestHandoff(timeoutMs: number): Promise<HandoffResult>;
249
+ /**
250
+ * Keep the shared Chrome alive across an awaiting-human window. Delegates to
251
+ * the session's hold counter (which also backs per-viewer holds). Idempotent
252
+ * and leak-safe when paired with {@link removeHold} in a `finally`.
253
+ */
254
+ addHold(): void;
255
+ /** Release a hold taken by {@link addHold}. */
256
+ removeHold(): void;
221
257
  shutdown(): Promise<void>;
222
258
  private releaseToAgent;
223
- private ensureStreaming;
259
+ private restartStreaming;
260
+ private enqueueStreamCleanup;
261
+ private shouldStream;
224
262
  private applyResize;
225
263
  private broadcastFrame;
226
264
  private broadcast;
227
265
  private broadcastState;
228
266
  private sendState;
229
267
  private currentPageInfo;
268
+ private sendFrameSafe;
230
269
  }
231
270
  //#endregion
232
271
  export { BrowserAutomation, BrowserSession, type BrowserSessionOptions, BrowserSurface, type BrowserSurfaceOptions, type HandoffResult, type Logger, type NavigateResult };
package/dist/index.d.ts CHANGED
@@ -125,16 +125,11 @@ interface BrowserSessionOptions {
125
125
  idleShutdownMs?: number;
126
126
  /** Extra Chrome args. */
127
127
  extraArgs?: string[];
128
- logger?: Logger;
129
- }
130
- interface BrowserSurfaceOptions extends BrowserSessionOptions {
131
- /**
132
- * Guard consulted before agent-driven or human navigation. Return false to
133
- * block (SSRF policy). Defaults to allow-all; Phase 11 wires the integration
134
- * SSRF allowlist here.
135
- */
128
+ /** Guard applied to every intercepted HTTP(S) page request. */
136
129
  isNavigationAllowed?: (url: string) => boolean;
130
+ logger?: Logger;
137
131
  }
132
+ type BrowserSurfaceOptions = BrowserSessionOptions;
138
133
  //#endregion
139
134
  //#region src/browser-session.d.ts
140
135
  declare class BrowserSession {
@@ -144,14 +139,24 @@ declare class BrowserSession {
144
139
  private launching;
145
140
  private holds;
146
141
  private idleTimer;
142
+ private generation;
143
+ private readonly preparedPages;
144
+ private readonly activePageListeners;
147
145
  private readonly log;
148
146
  private readonly idleMs;
149
147
  constructor(options: BrowserSessionOptions);
150
148
  /** Launch Chrome if not already running (idempotent, concurrent-safe). */
151
149
  ensureLaunched(): Promise<void>;
152
150
  private doLaunch;
151
+ /**
152
+ * Adopt `page` as the streamed active page iff it has a real navigable
153
+ * http(s) URL. Returns whether it was adopted. Guards against flipping the
154
+ * screencast to a transient `about:blank` throwaway target.
155
+ */
156
+ private adoptIfNavigable;
153
157
  /** The current active page, launching Chrome first if needed. */
154
158
  getActivePage(): Promise<Page>;
159
+ onActivePageChange(listener: (page: Page) => void | Promise<void>): () => void;
155
160
  /** Prevent idle shutdown while a viewer or op is active. */
156
161
  addHold(): void;
157
162
  /** Release a hold; arm idle shutdown when the last one is released. */
@@ -161,6 +166,9 @@ declare class BrowserSession {
161
166
  private armIdleTimer;
162
167
  private clearIdleTimer;
163
168
  shutdown(): Promise<void>;
169
+ private setActivePage;
170
+ private preparePage;
171
+ private isLaunchCurrent;
164
172
  }
165
173
  //#endregion
166
174
  //#region src/automation.d.ts
@@ -172,6 +180,7 @@ declare class BrowserAutomation {
172
180
  private readonly session;
173
181
  private readonly turn;
174
182
  private readonly isNavigationAllowed;
183
+ private operationTail;
175
184
  constructor(session: BrowserSession, turn: TurnController, isNavigationAllowed: (url: string) => boolean);
176
185
  navigate(url: string): Promise<NavigateResult>;
177
186
  click(selector: string): Promise<void>;
@@ -186,6 +195,9 @@ declare class BrowserAutomation {
186
195
  screenshot(): Promise<string>;
187
196
  /** Evaluate an expression in the page context via CDP (no eval on our side). */
188
197
  evaluate(expression: string): Promise<unknown>;
198
+ /** Wait until all agent operations that were already queued have settled. */
199
+ waitUntilIdle(): Promise<void>;
200
+ private run;
189
201
  }
190
202
  //#endregion
191
203
  //#region src/browser-surface.d.ts
@@ -207,26 +219,53 @@ declare class BrowserSurface implements SurfaceHandler {
207
219
  private readonly viewers;
208
220
  private viewport;
209
221
  private handoff;
222
+ private controllerSessionId;
223
+ private pendingControllerSessionId;
224
+ private streamGeneration;
225
+ private streamQueue;
226
+ private closed;
227
+ private readonly removePageListener;
210
228
  private readonly log;
211
229
  constructor(options: BrowserSurfaceOptions, sendFrame: (buf: Buffer) => void);
212
230
  openSession(sessionId: number, open: SessionOpenPayload): Promise<void>;
213
231
  handleFrame(frame: RemoteFrame): void;
214
232
  closeSession(sessionId: number): void;
215
233
  /**
216
- * Agent tool entry point: hand control to the human and block until they
217
- * release it (RELEASE_CONTROL) or `timeoutMs` elapses. Resolves with the
218
- * final page URL/title so the agent resumes on the same live page.
234
+ * Agent tool entry point: PARK the agent and wait for a human to take over
235
+ * and hand back (RELEASE_CONTROL / viewer teardown after a claim) or for
236
+ * `timeoutMs` to elapse. Resolves with the final page URL/title so the agent
237
+ * resumes on the same live page.
238
+ *
239
+ * Crucially this does NOT grant the human turn up front. The turn is granted
240
+ * only when a human ACTUALLY takes control — i.e. when the controlling
241
+ * (`canControl:true`) viewer sends a `TAKEOVER_REQUEST` frame (see
242
+ * `handleFrame` → `grantHuman()`). Granting at tool-call time made the session
243
+ * "human in control" before anyone had claimed, so a read-only viewer's
244
+ * teardown would fire `releaseToAgent()` and complete the session out from
245
+ * under the user (mislabeled 409 on the real claim; agent only resuming when
246
+ * the tab closed).
219
247
  */
220
248
  requestHandoff(timeoutMs: number): Promise<HandoffResult>;
249
+ /**
250
+ * Keep the shared Chrome alive across an awaiting-human window. Delegates to
251
+ * the session's hold counter (which also backs per-viewer holds). Idempotent
252
+ * and leak-safe when paired with {@link removeHold} in a `finally`.
253
+ */
254
+ addHold(): void;
255
+ /** Release a hold taken by {@link addHold}. */
256
+ removeHold(): void;
221
257
  shutdown(): Promise<void>;
222
258
  private releaseToAgent;
223
- private ensureStreaming;
259
+ private restartStreaming;
260
+ private enqueueStreamCleanup;
261
+ private shouldStream;
224
262
  private applyResize;
225
263
  private broadcastFrame;
226
264
  private broadcast;
227
265
  private broadcastState;
228
266
  private sendState;
229
267
  private currentPageInfo;
268
+ private sendFrameSafe;
230
269
  }
231
270
  //#endregion
232
271
  export { BrowserAutomation, BrowserSession, type BrowserSessionOptions, BrowserSurface, type BrowserSurfaceOptions, type HandoffResult, type Logger, type NavigateResult };